GoogLeNet——网络实战

news2024/11/19 22:38:00

文章目录

  • 摘要🐇
  • 1 项目结构🐇
  • 2 划分训练集和测试集🐇
  • 3 计算mean和Standard🐇
    • 3.1 标准化的作用🐇
    • 3.2 归一化的作用🐇
  • 4 训练🐇
    • 4.1 导入项目使用的库🐇
    • 4.2 设置随机因子🐇
    • 4.3 设置全局参数🐇
    • 4.4 图像预处理与增强🐇
    • 4.5 读取数据🐇
    • 4.6 设置Loss🐇
    • 4.7 设置模型🐇
      • 4.7.1 如何确定改哪层?🐇
    • 4.8 设置优化器和学习率调整算法🐇
    • 4.9 训练函数
    • 4.10 验证函数🐇
    • 4.11 训练、验证、保存模型🐇
    • 4.12 继续训练🐇
  • 4.13 结果展示🐇
  • 5 测试🐇
  • 总结🐇

🐇🐇🐇🐇🐇🐇
🐇 欢迎阅读 【AI浩】 的博客🐇
👍 阅读完毕,可以动动小手赞一下👍
🌻 发现错误,直接评论区中指正吧🌻
📆 这是一篇讲解GoogLeNet实战的文章📆
💯专栏目录: 经典主干网络精讲与实战💯

摘要🐇

GoogLeNet作为2014年ILSVRC在分类任务上的冠军,以6.65%的错误率力压VGGNet等模型,在分类的准确率上面相比过去两届冠军ZFNet和AlexNet都有很大的提升。在前面的文章我介绍了GoogLeNet的网络结构和数据集的制作,这篇文章我将和大家一起完成GoogLeNet模型的实战。
在这里插入图片描述

数据集选用第三篇 制作数据集制作的数据集,模型用Pytorh自带的GoogLeNet。在这篇文章中,我尽量的简化代码,只保留最基本的逻辑,让每一个初学者能够看明白。通过这篇文章你能学到:
1、如何训练模型?
2、如何推理?
3、如何读取数据集、处理数据集?
4、如何使用余弦退火调整学习率?
5、如何保存权重文件和整个模型文件?
6、如何使用评价指标,如ACC、ReCall等指标评价模型。
7、如何使用matplotlib.pyplot绘制acc和loss曲线图?
在这里插入图片描述

1 项目结构🐇

GoogLeNet_Demo
├─trainvals
│  ├─双子座
│  ├─双鱼座
│  ├─处女座
│  ├─天秤座
│  ├─天蝎座
│  ├─射手座
│  ├─山羊座
│  ├─巨蟹座
│  ├─水瓶座
│  ├─狮子座
│  ├─白羊座
│  └─金牛座
├─test
├─makedata.py
├─mean_std.py
├─train.py
└─test.py

trainvals:数据集,接下来我们将其划分为训练集和验证集。
test:测试集
makedata.py:划分数据集的方法
mean_std.py:计算mean和std的值。
ema.py:EMA脚本
train.py:训练GoogLeNet模型
在这里插入图片描述

2 划分训练集和测试集🐇

import glob
import os
import shutil
from sklearn.model_selection import train_test_split

image_list=glob.glob('trainvals/*/*.*')
print(image_list)
file_dir='data'
if os.path.exists(file_dir):
    print('true')
    shutil.rmtree(file_dir)#删除再建立
    os.makedirs(file_dir)
else:
    os.makedirs(file_dir)
trainval_files, val_files = train_test_split(image_list, test_size=0.2, random_state=42)
train_dir='train'
val_dir='val'
train_root=os.path.join(file_dir,train_dir)
val_root=os.path.join(file_dir,val_dir)
for file in trainval_files:
    file_class=file.replace("\\","/").split('/')[-2]
    file_name=file.replace("\\","/").split('/')[-1]
    file_class=os.path.join(train_root,file_class)
    if not os.path.isdir(file_class):
        os.makedirs(file_class)
    shutil.copy(file, file_class + '/' + file_name)

for file in val_files:
    file_class=file.replace("\\","/").split('/')[-2]
    file_name=file.replace("\\","/").split('/')[-1]
    file_class=os.path.join(val_root,file_class)
    if not os.path.isdir(file_class):
        os.makedirs(file_class)
    shutil.copy(file, file_class + '/' + file_name)

核心思路:

  • 1、将所有的图片读取到list中。
  • 2、sklearn.model_selection的train_test_split方法将list切分。这一步需要安装sklearn这个库,安装命令:pip install sklearn
  • 3、保存切分结果。

运行结果:
在这里插入图片描述
如上结果,我们就将训练集和测试集划分好了。

3 计算mean和Standard🐇

使用深度学习进行图像分类或者图像检测时,首先需要对图像进行数据预处理,常见的对图像的预处理有两种办法,一种标准化处理,另一种是归一化处理。

3.1 标准化的作用🐇

图像标准化是将数据通过去均值实现中心化的处理,根据凸优化理论与数据概率分布相关知识,数据中心化符合数据分布规律,更容易取得训练之后的泛化效果。

3.2 归一化的作用🐇

归一化不改变图像信息,只是把像素从0-255变成0~1的范围,加快训练网络的收敛性,使得所有样本的输入信号其均值接近于0或与其均方差相比很小。

总之,为了使模型更加快速的收敛和具有更好的泛化性,我们需要计算出mean和std的值,新建mean_std.py,插入代码:

from torchvision.datasets import ImageFolder
import torch
from torchvision import transforms

def get_mean_and_std(train_data):
    train_loader = torch.utils.data.DataLoader(
        train_data, batch_size=1, shuffle=False, num_workers=0,
        pin_memory=True)
    mean = torch.zeros(3)
    std = torch.zeros(3)
    for X, _ in train_loader:
        for d in range(3):
            mean[d] += X[:, d, :, :].mean()
            std[d] += X[:, d, :, :].std()
    mean.div_(len(train_data))
    std.div_(len(train_data))
    return list(mean.numpy()), list(std.numpy())

if __name__ == '__main__':
    train_dataset = ImageFolder(root=r'data1', transform=transforms.ToTensor())
    print(get_mean_and_std(train_dataset))

运行结果:

([0.48214436, 0.42969334, 0.33318862], [0.2642221, 0.23746745, 0.21696019])

生成两个list,一个list是mean的结果,一个list是std的结果。
在这里插入图片描述

4 训练🐇

新建train.py脚本。

4.1 导入项目使用的库🐇

import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
from torchvision.models import googlenet
import os
from torchvision import datasets
import json
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")

4.2 设置随机因子🐇

设置随机因子后,再次训练时,图像的加载顺序不会改变,能够更好的复现训练结果。代码如下:

def seed_everything(seed=42):
    os.environ['PYHTONHASHSEED'] = str(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.backends.cudnn.deterministic = True

4.3 设置全局参数🐇


if __name__ == '__main__':
    #创建保存模型的文件夹
    file_dir = 'checkpoints/googlenet'
    if os.path.exists(file_dir):
        print('true')
        os.makedirs(file_dir,exist_ok=True)
    else:
        os.makedirs(file_dir)
    # 设置全局参数
    model_lr = 1e-4
    BATCH_SIZE = 16
    EPOCHS = 1000
    DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    classes = 12
    resume = None
    Best_ACC = 0 #记录最高得分
    SEED=42
    seed_everything(42)
    start_epoch=1

设置存放权重文件的文件夹,如果文件夹存在删除再建立。

接下来,设置全局参数,比如:学习率、BatchSize、epoch等参数,判断环境中是否存在GPU,如果没有则使用CPU。
注:建议使用GPU,CPU太慢了。

参数的详细解释:

model_lr:学习率,根据实际情况做调整。

BATCH_SIZE:batchsize,根据显卡的大小设置。

EPOCHS:epoch的个数,一般300够用。

classes:类别个数。

resume:再次训练的模型路径,如果不为None,则表示加载resume指向的模型继续训练。

Best_ACC:记录最高ACC得分。

start_epoch:开始的epoch,默认是1,如果重新训练时,需要给start_epoch重新赋值。

SEED:随机因子,数值可以随意设定,但是设置后,不要随意更改,更改后,图片加载的顺序会改变,影响测试结果。

在这里插入图片描述

4.4 图像预处理与增强🐇

   # 数据预处理7
    transform = transforms.Compose([
        transforms.RandomRotation(10),
        transforms.GaussianBlur(kernel_size=(5,5),sigma=(0.1, 3.0)),
        transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5),
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.44127703, 0.4712498, 0.43714803], std= [0.18507297, 0.18050247, 0.16784933])

    ])
    transform_test = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.44127703, 0.4712498, 0.43714803], std= [0.18507297, 0.18050247, 0.16784933])
    ])

数据处理和增强比较简单,加入了随机10度的旋转、高斯模糊、色彩饱和度明亮度的变化等比较常用的增强手段,做了Resize、归一化和标准化处理。

这里注意下Resize的大小,由于选用的GoogLeNet模型输入是224×224的大小,所以要Resize为224×224。
在这里插入图片描述

4.5 读取数据🐇

   # 读取数据
    dataset_train = datasets.ImageFolder('data/train', transform=transform)
    dataset_test = datasets.ImageFolder("data/val", transform=transform_test)
    with open('class.txt', 'w') as file:
        file.write(str(dataset_train.class_to_idx))
    with open('class.json', 'w', encoding='utf-8') as file:
        file.write(json.dumps(dataset_train.class_to_idx))
    # 导入数据
    train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE,pin_memory=True, shuffle=True)
    test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE,pin_memory=True, shuffle=False)

  • 使用pytorch默认读取数据的方式,然后将dataset_train.class_to_idx打印出来,预测的时候要用到。

  • 对于train_loader和test_loader ,pin_memory设置为True,可以加快运行速度,训练需要将shuffle设置为True,用于将图片加载的顺序打乱,验证时不用将图片的顺序打乱。

  • 将dataset_train.class_to_idx保存到txt文件或者json文件中。

class_to_idx的结果:

{'双子座': 0, '双鱼座': 1, '处女座': 2, '天秤座': 3, '天蝎座': 4, '射手座': 5, '山羊座': 6, '巨蟹座': 7, '水瓶座': 8, '狮子座': 9, '白羊座': 10, '金牛座': 11}

4.6 设置Loss🐇

  # 实例化模型并且移动到GPU
    criterion_val = torch.nn.CrossEntropyLoss()

设置loss函数,loss函数设置为交叉熵。

在这里插入图片描述

4.7 设置模型🐇

    # 设置模型
    model_ft = googlenet(pretrained=True,aux_logits=True)
    print(model_ft)
    num_ftrs=model_ft.fc.in_features
    model_ft.fc =nn.Linear(num_ftrs,classes)
    num_ftrs_aux1 = model_ft.aux1.fc2.in_features
    model_ft.aux1.fc2 = nn.Linear(num_ftrs_aux1, classes)
    num_ftrs_aux2=model_ft.aux2.fc2.in_features
    model_ft.aux2.fc2 = nn.Linear(num_ftrs_aux2, classes)

    if resume:
        model = torch.load(resume)
        model_ft.load_state_dict(model['state_dict'])
        Best_ACC = model['Best_ACC']
        start_epoch = model['epoch'] + 1
    model_ft.to(DEVICE)
    print(model_ft)
  • 设置模型为googlenet,pretrained设置为true,表示加载预训练模型,aux_logits设置为True,则表示启用辅助分类器。 将model_ft.fc 这个全连接层的输出修改为classes,将model_ft.aux1.fc2和 model_ft.aux2.fc2这两个辅助分类器的输出也改为classes。执行print(model_ft),查看是否修改成功,如下图所示:
    在这里插入图片描述
  • 如果resume为True,则加载模型接着resume指向的模型接着训练,使用模型里的Best_ACC初始化Best_ACC,使用epoch参数初始化start_epoch。
    在这里插入图片描述

4.7.1 如何确定改哪层?🐇

很多人有这样的疑问,不同的模型,最后一层全连接都不相同,我们如何找到最后一层的全连接层?我通过这篇文章揭晓一下:

 model_ft = alexnet(pretrained=True)
 print(model_ft)

首先,我们声明模型的对象后,使用print直接打印模型,然后寻找最后一层:
在这里插入图片描述
通过上图可以看到,最后一层的全连接在classifier这个Sequential下面,index为6的位置。
所以,我们先将这个层的in_features取出来,代码如下:

num_ftrs=model_ft.classifier[6].in_features

然后,给他重新赋个全连接,代码如下:

model_ft.classifier[6]=nn.Linear(num_ftrs,classes)

4.8 设置优化器和学习率调整算法🐇

   # 选择简单暴力的Adam优化器,学习率调低
   optimizer = optim.AdamW(model_ft.parameters(),lr=model_lr)
   cosine_schedule = optim.lr_scheduler.CosineAnnealingLR(optimizer=optimizer, T_max=20, eta_min=1e-6)
  • 优化器设置为adamW。
  • 学习率调整策略选择为余弦退火。

4.9 训练函数

# 定义训练过程
def train(model, device, train_loader, optimizer, epoch):
    model.train()
    sum_loss = 0
    correct=0 #预测正确的数量
    total_num = len(train_loader.dataset)
    print(total_num, len(train_loader))
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device,non_blocking=True), target.to(device,non_blocking=True)
        output, aux1, aux2 = model(data)
        loss_out = criterion(output, target)
        loss_aux = criterion(aux2, target)
        loss = loss_out * 0.7 + loss_aux * 0.3
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        print_loss = loss.data.item()
        _, pred = torch.max(output.data, 1)
        correct += torch.sum(pred == target)
        sum_loss += print_loss
        if (batch_idx + 1) % 10 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
                       100. * (batch_idx + 1) / len(train_loader), loss.item()))
    ave_loss = sum_loss / len(train_loader)
    correct = correct.data.item()
    acc = correct / total_num
    print('epoch:{},loss:{}'.format(epoch, ave_loss))
    return ave_loss,acc

训练的主要步骤:

1、 model.train()切换成训练模型。启用 BatchNormalization 和 Dropout。初始化sum_loss 为0,计算训练集图片的数量赋给total_num。correct设置为0

2、进入循环,将data和target放入device上,non_blocking设置为True。如果pin_memory=True的话,将数据放入GPU的时候,也应该把non_blocking打开,这样就只把数据放入GPU而不取出,访问时间会大大减少。
如果pin_memory=False时,则将non_blocking设置为False。

3、data输入model,输出预测结果,然后再计算loss。这里注意,我们除了计算output的loss,还要计算一个辅助分类器的loss,根据论文描述选择其中一个辅助分类器,按照7:3的比例配置loss。

4、 optimizer.zero_grad() 梯度清零,把loss关于weight的导数变成0。

5、反向传播求梯度。

6、获取loss,并赋值给print_loss 。

7、torch.sum(pred == target)计算当前Batch内,预测正确的数量,然后累加到correct 。

8、sum_loss 累加print_loss ,求得总的loss。所以,单个epoch的loss就是总的sum_loss 除以train_loader的长度。

等待一个epoch训练完成后,计算平均loss。然后将其打印出来。并返回loss和acc。

4.10 验证函数🐇

验证过程增加了对预测数据和Label数据的保存,所以,需要定义两个list保存,然后将其返回!

# 验证过程
def val(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    total_num = len(test_loader.dataset)
    print(total_num, len(test_loader))
    val_list = []
    pred_list = []
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device, non_blocking=True), target.to(device, non_blocking=True)
            for t in target:
                val_list.append(t.data.item())
            output = model(data)
            loss = criterion(output, target)
            _, pred = torch.max(output.data, 1)
            for p in pred:
                pred_list.append(p.data.item())
            correct += torch.sum(pred == target)
            print_loss = loss.data.item()
            test_loss += print_loss
        correct = correct.data.item()
        acc = correct / total_num
        avgloss = test_loss / len(test_loader)
        print('\nVal set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
            avgloss, correct, len(test_loader.dataset), 100 * acc))
    return val_list, pred_list,avgloss,acc

验证的过程和训练的过程大致相似,主要步骤:

1、model.eval(),切换验证模型,不启用 BatchNormalization 和 Dropout。

2、定义参数:
test_loss : 测试的loss
correct :统计正确类别的数量。
total_num:验证集图片的总数。
val_list :保存验证集的Label数据。
pred_list :保存预测的Label数据。

3、torch.no_grad():反向传播时就不会自动求导了。

4、进入循环,迭代test_loader:

将label保存到val_list。

将data和target放入device上,non_blocking设置为True。

遍历target,将Label保存到val_list 。

将data输入到model中,求出预测值,然后输入到loss函数中,求出loss。在验证集中,不用求辅助分类器的loss。

调用torch.max函数,将预测值转为对应的label。

遍历pred,将预测的Label保存到pred_list。

correct += torch.sum(pred == target),计算出识别对的数量,并累加到correct 变量上。

5、acc = correct / total_num,计算出acc。 avgloss = test_loss / len(test_loader)计算loss。 最后返回val_list, pred_list,loss,acc

在这里插入图片描述

4.11 训练、验证、保存模型🐇

   # 训练
    log_dir = {}
    train_loss_list, val_loss_list, train_acc_list, val_acc_list, epoch_list = [], [], [], [], []
    for epoch in range(start_epoch, EPOCHS + 1):
        epoch_list.append(epoch)
        train_loss, train_acc=train(model_ft, DEVICE, train_loader, optimizer, epoch)
        train_loss_list.append(train_loss)
        train_acc_list.append(train_acc)
        log_dir['train_acc'] = train_acc_list
        log_dir['train_loss'] = train_loss_list

        val_list, pred_list, val_loss, val_acc =val(model_ft, DEVICE, test_loader)
        val_loss_list.append(val_loss)
        val_acc_list.append(val_acc)
        log_dir['val_acc'] = val_acc_list
        log_dir['val_loss'] = val_loss_list
        log_dir['best_acc'] = Best_ACC

        if val_acc>=Best_ACC:
            Best_ACC=val_acc
            torch.save(model_ft, file_dir + "/" + 'best.pth')
        state = {
            'epoch': epoch,
            'state_dict': model_ft.state_dict(),
            'Best_ACC': Best_ACC
        }
        torch.save(state, file_dir + "/" + 'model_' + str(epoch) + '_' + str(round(val_acc, 3)) + '.pth')
        fig = plt.figure(1)
        plt.plot(epoch_list, train_loss_list, 'r-', label=u'Train Loss')
        # 显示图例
        plt.plot(epoch_list, val_loss_list, 'b-', label=u'Val Loss')
        plt.legend(["Train Loss", "Val Loss"], loc="upper right")
        plt.xlabel(u'epoch')
        plt.ylabel(u'loss')
        plt.title('Model Loss ')
        plt.savefig(file_dir + "/loss.png")
        plt.close(1)
        fig2 = plt.figure(2)
        plt.plot(epoch_list, train_acc_list, 'r-', label=u'Train Acc')
        plt.plot(epoch_list, val_acc_list, 'b-', label=u'Val Acc')
        plt.legend(["Train Acc", "Val Acc"], loc="lower right")
        plt.title("Model Acc")
        plt.ylabel("acc")
        plt.xlabel("epoch")
        plt.savefig(file_dir + "/acc.png")
        plt.close(2)

循环调用train函数和val函数,train函数返回train_loss, train_acc,val函数返回val_list, pred_list, val_loss, val_acc。loss和acc用于绘制曲线。
将val_list, pred_list和dataset_train.class_to_idx传入模型,计算模型指标。
判断acc是否大于Best_ACC,如果大于则保存模型,这里保存的是整个模型。
接下来是保存每个epoch的模型,新建state ,字典的参数:

  • epoch:当前的epoch。
  • state_dict:权重参数。 model_ft.state_dict(),只保存模型的权重参数。
  • Best_ACC:Best_ACC的数值。
    然后,调用 torch.save保存模型。

最后使用plt.plot绘制loss和acc曲线图
在这里插入图片描述

4.12 继续训练🐇

将resume设置为模型的路径即可开启继续训练。如下:
在这里插入图片描述

 resume = 'checkpoints/GoogLeNet/model_430_0.92.pth'

然后点击train.py,就可以继续训练了。如下图:
在这里插入图片描述

4.13 结果展示🐇

loss曲线图:
在这里插入图片描述

acc曲线图:
在这里插入图片描述

5 测试🐇

测试,我们采用一种通用的方式。测试集存放的目录如下图:

GoogLeNet_demo
├─test
│  ├─白羊座_2.jpg.jpg
│  ├─处女座_136.jpg
│  ├─金牛座_142.jpg
│  ├ ......
└─test.py

代码如下:

import torch.utils.data.distributed
import torchvision.transforms as transforms
from PIL import Image
from torch.autograd import Variable
import os

classes = ('双子座', '双鱼座', '处女座', '天秤座',
           '天蝎座', '射手座', '山羊座',
           '巨蟹座', '水瓶座', '狮子座', '白羊座', '金牛座')
transform_test = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.51819474, 0.5250407, 0.4945761], std=[0.24228974, 0.24347611, 0.2530049])
])

DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model=torch.load('checkpoints/googlenet/best.pth')
model.eval()
model.to(DEVICE)

path = 'test/'
testList = os.listdir(path)
for file in testList:
    img = Image.open(path + file).convert('RGB')
    img = transform_test(img)
    img.unsqueeze_(0)
    img = Variable(img).to(DEVICE)
    out = model(img)
    # Predict
    _, pred = torch.max(out.data, 1)
    print('Image Name:{},predict:{}'.format(file, classes[pred.data.item()]))

测试的主要逻辑:

1、定义类别,这个类别的顺序和训练时的类别顺序对应,一定不要改变顺序!!!!

2、定义transforms,transforms和验证集的transforms一样即可,别做数据增强。

3、 加载model,并将模型放在DEVICE里,

4、循环 读取图片并预测图片的类别,在这里注意,读取图片用PIL库的Image。不要用cv2,transforms不支持。循环里面的主要逻辑:

  • 使用Image.open读取图片,将其转为RGB格式。
  • 使用transform_test对图片做归一化和标椎化。
  • img.unsqueeze_(0) 增加一个维度,由(3,224,224)变为(1,3,224,224)
  • Variable(img).to(DEVICE):将数据放入DEVICE中。
  • model(img):执行预测。
  • _, pred = torch.max(out.data, 1):获取预测值的最大下角标。

运行结果:

在这里插入图片描述

总结🐇

到这里,这篇文章就写完了,通过这篇文章,你能学到:
1、如何训练模型?
2、如何推理?
3、如何读取数据集、处理数据集?
4、如何使用余弦退火调整学习率?
5、如何保存权重文件和整个模型文件?
6、如何使用评价指标,如ACC、ReCall等指标评价模型。
7、如何使用matplotlib.pyplot绘制acc和loss曲线图?
有没有发现,我们的实战代码正在逐渐的丰富起来。我打算通过这种逐步增加难度的方式,让大家更容易接受!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/191471.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java单例模式演示与理解

目录单例模式1、饿汉式2、懒汉式3、DSL懒汉式(双重锁懒汉模式)静态内部类懒汉式单例模式的如何破坏4、使用枚举类单例模式 为什么使用单例模式? 单例模式确保一个类在内存中只会有同一个实例对象存在。不管声明获取实例对象多少次都是内存中…

2023年网络安全八大预测!

随着创新技术的不断兴起,以及网络犯罪的日益专业化,网络安全攻击风险仍在持续增长。可以预见,2023年的网络安全形势依然严峻,需要国家不断完善网络安全政策和法规,网络安全企业积极创新网络安全防护技术。瑞数信息作为…

Allegro如何导出和导入器件模型Signal_Model操作指导

Allegro如何导出和导入器件模型Signal_Model操作指导 在用Allegro做PCB设计的时候,通常需要给器件加上Signal_Model,在做等长的时候用到的非常频繁。 Allegro除了可以给器件添加模型,还支持从一块加好模型的BRD导入到另外一块BRD中, 如下图,需要把R7002的Signal_Model导入…

剪报浏览器:可以自己设计网页的浏览器

总的功能就是一句话“不同网站的精华内容裁剪下来,合并到一处浏览”把自己关注的网页版块从不同网站上裁剪下来放在一个页面里,一次刷新就可以看到不同网站的最新内容,而不用逐个打开网站去看,提高了上网的效率。关键特征汇聚浏览…

排序算法(带动图)

0、算法概述0.1 算法分类十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。非比较类排序:不通过比较来决定元素间的相对…

【数据结构初阶】第七篇——二叉树的顺序结构及实现(堆的向下,向上调整算法)

二叉树的顺序结构 堆的概念及结构 堆的向下调整算法 堆的向上调整算法 堆的实现 初始化堆 销毁堆 打印堆 堆的插入 堆的删除 获取堆顶的数据 获取堆的数据个数 堆的判空 建堆的时间复杂度 二叉树的顺序结构 普通二叉树是不适合用数组来存储的,因为可能会导致大量…

为nginx配置好看的错误提示页面

前言 nginx默认错误页面确实有些丑哈,leeader让我换一个样式 ,我就来喽! 为nginx配置好看的错误提示页面前言1 找异常页原始页2 win上替换3 再linux服务器上替换4 不生效解决办法样式显示不正确6 错误页源码1 找异常页 原始页 nginx默认错误…

2个月快速通过PMP证书的经验

01 PMP证书是什么? 指的是项目管理专业人士资格认证。它是由美国项目管理协会(Project Management Institute(简称PMI))发起的,严格评估项目管理人员知识技能是否具有高品质的资格认证考试。其目的是为了给项目管理人员提供统一的…

初学者的Metasploit教程 - 从基础到高级

Metasploit是使用最广泛的渗透测试工具之一,是一个非常强大的多合一工具,用于执行渗透测试的不同步骤。 文章目录前言安装Metasploit在 Linux 上安装 Metasploit了解 Metasploit 的版本并更新渗透测试的基础知识1. 信息收集/侦察2. 漏洞分析3.渗透4. 渗透…

OSCP_VULHUB_Hack the Kioptrix Level-1.2

文章目录前言渗透方法论(方法一)渗透方法论(方法二)第一种sqlmap扫描&提取数据库和用户凭证ssh登录使用 SUID 位和 SUDO 二进制文件利用目标第二种方法searchsploit LotusCMS前言 Kioptrix 的 CTF 挑战:Level1.2 …

Linux搭建Hyperledger Fabric区块链框架 - Hyperledger Fabric 概念

企业选型的区块链底层技术 Hyperledger Fabric 概念 2015年,Linux基金会启动了Hyperledger项目,目标是发展跨行业的区块链技术。 Hyperledger Fabric是Hyperledger中的一个区块链项目,包含一个账本,使用智能合约并且是一个通过所…

上海亚商投顾:三大指数均涨约1% 两市近4300股飘红

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。市场情绪三大指数早盘冲高回落,午后又震荡走强,深成指、创业板指均涨超1.2%。人工智能概念掀涨停潮&a…

Pytorch实战笔记(3)——BERT实现情感分析

本文展示的是使用 Pytorch 构建一个 BERT 来实现情感分析。本文的架构是第一章详细介绍 BERT,其中包括 Self-attention,Transformer 的 Encoder,BERT 的输入与输出,以及 BERT 的预训练和微调方式;第二章是核心代码部分…

机器视觉_HALCON_HDevelop用户指南_4.HDevelop开发程序

文章目录四、HDevelop编程4.1. 新建一个新程序4.2. 输入一个算子4.3. 指定参数4.4. 获取帮助4.5. 添加其他程序4.6. 理解图像显示4.7. 检查变量4.8. 利用灰度直方图改进阈值4.9. 编辑代码行4.10. 重新执行程序4.11. 保存程序4.12. 选择特征区域4.13. 打开图形窗口4.14. 循环遍历…

Swig工具在win10上使用

SWIG 是一种软件开发工具,它将 C 和 C 编写的程序与各种高级编程语言连接起来。这里我们用它来将 C/C 转换成 Java。 一、Swig安装 1、下载 官网:SWIG官网下载 源码链接 GitHub:https://github.com/swig/swig.git 这两个地址可能会出现无…

STM32单片机智能蓝牙APP加油站火灾预警安防防控报警监控系统MQ2DHT11

实践制作DIY- GC0122-智能蓝牙APP加油站火灾预警 一、功能说明: 基于STM32单片机设计-智能蓝牙APP加油站火灾预警 功能介绍: 基于STM32F103C系列最小系统,MQ-2烟雾传感器,火焰传感器(不能直视阳光会受到阳光干扰&…

Cesium 渐变长方体实现-Shader

position获取: 1.1 在cesium中,可通过vec4 p = czm_computePosition();获取 模型坐标中相对于眼睛的位置矩阵 1.2 vec4 eyePosition = czm_modelViewRelativeToEye * p; // position in eye coordinates 获取eyePosition 1.3 v_positionEC = czm_inverseModelView * eyePo…

Python流程控制详解

和其它编程语言一样,Python流程控制可分为 3 大结构:顺序结构、选择(分支)结构和循环结构。 Python对缩进的要求(重点) Python 是一门非常独特的编程语言,它通过缩进来识别代码块,…

ConditionalOnBean详解及ConditionalOn××总结

ConditionalOnBean详解 为什么学习ConditionalOnBean 在学习 Springboot 自动装配的时候遇到 Bean 装配和 Bean 配置需要条件判断的场景时,查阅了相关内容了解到 Conditional 和 ConditionalOnBean 注解,深入学习之后受益匪浅。 ConditionalOnBean测试…

后量子 KEM 方案:Newhope

参考文献: Lyubashevsky V, Peikert C, Regev O. On ideal lattices and learning with errors over rings[J]. Journal of the ACM (JACM), 2013, 60(6): 1-35.Lyubashevsky V, Peikert C, Regev O. A toolkit for ring-LWE cryptography[C]//Advances in Cryptol…