前言

继续学习霹雳大神的神经网络讲解视频

更新不易,希望大家可以去看原视频支持up主霹雳吧啦Wz

GoogLeNet网络详解
使用pytorch搭建GoogLeNet网络

本博文记载的是基于Pytorch框架的GoogLeNet网络

GoogLeNet网络结构详解与模型的搭建

简单介绍GoogLeNet网络

GoogLeNet网络在2014年被谷歌团队提出 LeNet大写是为了致敬LeNet

网络亮点:

  • 引入了Inception结构(融合不同尺度的特征信息)
  • 使用1 x 1的卷积核进行降维以及映射处理
  • 添加两个辅助分类器帮助训练

// AlexNet和VGG都只有一个输出层 GoogLeNet有三个输出层(其中有两个辅助分类层)

  • 丢弃全连接测层,使用平均池化层(大大减少模型参数)

模型结构


结构分析

input
卷积层
最大下采样层
LocalRespNorm层
卷积层
卷积层
LocalRespNorm层
最大下采样层

Inception层(3a)

lnception(3b)

最大池化层
Inception(4a)

黄色部分是辅助分类器1


softmax激活函数进行输出

Inception模型

初始的版本


将上一层的输出同时输入到四个分支中进行处理 处理之后将我们得到的这四个分支的特征矩阵按照深度进行拼接 得到我们的输出特征矩阵

注意:每个分支得到的特征矩阵的高和宽必须相同 否则无法沿深度方向进行拼接

优化后的版本


Inception结构加上一个降维的功能
用到了三个1 x 1的卷积层 进行降维

1x1的卷积核如何起到降维的作用呢?


这样子使用1x1的卷积核 目的是为了减少特征矩阵的深度,从而减少我们的参数个数 ,也就减少了我们的计算量

辅助分类器

两个辅助分类器的结构一样

**第一层是我们的平均下采样操作,池化核大小是5*5 ,步距是等于3 **
第一个辅助分类器是来自于我们的inception4a的输出
inception4a的输出矩阵的大小是14x14x512

第二个辅助分类器是来自于我们的inception4d的输出
inception4d的输出矩阵的大小是14x14x528

两个分类器的输出矩阵高度与宽度相同 但是深度不一样

计算一下AveragePool的输出
根据out(size)=in(size)- F(size)+2 P / S+1
可以计算得到out = (14 -5 )/ 3 + 1 = 4
而平均下采样层又不会改变输入矩阵的深度
所以第一个输出分类器AveragePool层的输出是4x4x512
所以第二个输出分类器AveragePool层的输出是4x4x528

采用128个卷积核大小为1*1的卷积层进行卷积处理,目的是为了降低维度,并且使用的是ReLU激活函数

采用节点个数为1024的全连接层,同样使用ReLU激活函数

全连接层与全连接层之间使用dropout函数,以70%的比例,随机失活神经元

采用节点个数为1000的全连接层,这里的节点个数是对应我们的类别个数!!!

通过softmax函数得到我们的概率分布

理解参数


表格数据从上到下 一一对应GoogLeNet的每一层结构的数据
LocalRespNorm层起到的作用不大 可以舍弃掉
辅助分类器的参数前面有详细讲解
池化层的参数表示是类似5x5+2(V) 表示的是5x5的大小 2的步长
而卷积层参数表示是5x5+2(S) 表示的是5x5的大小 2的步长
注意最后avg pool与全连接层直接还有一个dropout函数 是以40%的概率随机失活神经元

inception结构的对应 如下图所示

model.py代码解读

创建GoogLeNet网络之前先创建几个模板文件

首先是我们的BasicConv2d
因为我们在构建我们的卷积层的时候通常是将我们的卷积和我们的ReLU激活函数绑定在一起
所以创建一个常用的class BasicConv2d

定义BasicConv2d


class BasicConv2d(nn.Module):#继承于nn.Moduledef __init__(self, in_channels, out_channels, **kwargs):#参数有输出特征层的深度 输出矩阵特征层的深度 super(BasicConv2d, self).__init__()self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)#定义卷积层 #输入特征矩阵深度就是我in_channels,卷积核的个数就是我们输出特征矩阵的深度self.relu = nn.ReLU(inplace=True)#定义ReLU激活函数def forward(self, x):#定义一个正向传播过程x = self.conv(x)x = self.relu(x)return x

定义Inception结构

class Inception(nn.Module):#继承自nn.Moduledef __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):#参数分析:输入特征矩阵的深度,ch1x1代表#1x1 ch3x3red代表#3x3 reduce   #ch5x5red代表#5x5 reduce   ch5x5代表#5x5  pool_pro代表pool projsuper(Inception, self).__init__()self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)#分支1   使用BasicConv2d模板(我们输入特征矩阵的深度,采用卷积核的个数,卷积核大小,步距是1是默认的)self.branch2 = nn.Sequential(BasicConv2d(in_channels, ch3x3red, kernel_size=1),BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小)#分支2使用nn.Sequential函数#使用BasicConv2d(输入特征矩阵的深度,采用卷积核的个数,卷积核大小是1x1,步距是1是默认的)#使用BasicConv2d模板(输入特征矩阵的深度这时候就是ch3x3red是上一层输出矩阵的深度,采用卷积核的个数,卷积核大小为3x3,步距是1是默认的)#为了保证每个分支所输出的高度和宽度相同,所以必须设置padding为1#output_size=(input_size-3+2*1)/1+1=input_sizeself.branch3 = nn.Sequential(BasicConv2d(in_channels, ch5x5red, kernel_size=1),BasicConv2d(ch5x5red, ch5x5, kernel_size=5, padding=2)   # 保证输出大小等于输入大小)#分支3 使用nn.Sequential函数#使用BasicConv2d(输入特征矩阵的深度,采用卷积核的个数,卷积核大小是1x1,步距是1是默认的)#使用BasicConv2d模板(输入特征矩阵的深度这时候就是ch5x5red是上一层输出矩阵的深度,采用卷积核的个数,卷积核大小为5x5,步距是1是默认的)#为了保证每个分支所输出的高度和宽度相同,所以必须设置padding为2#output_size=(input_size-5+2*2)/1+1=input_sizeself.branch4 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=1, padding=1),BasicConv2d(in_channels, pool_proj, kernel_size=1))#分支4 使用nn.Sequential函数#使用nn.MaxPool2d(卷积核大小为3x3,步距是1,padding是1)#为了保证每个分支所输出的高度和宽度相同,stride设置为1,设置padding为1#使用BasicConv2d模板(输入矩阵的深度,采用卷积核的个数是pool_proj,卷积核大小为1x1)   def forward(self, x): #定义正向传播过程#将我们的特征矩阵分别输入到branch1、branch2.。。。 分别得到这四个分支所对应的输出branch1 = self.branch1(x)branch2 = self.branch2(x)branch3 = self.branch3(x)branch4 = self.branch4(x)outputs = [branch1, branch2, branch3, branch4] #将我们的的输出放入一个列表当中return torch.cat(outputs, 1)#使用一个torch.cat函数对我们的四个分支的输出进行合并,第一个参数是输出特征的列表,需要合并的一个维度,我们序呀在需要在深度方向上进行合并 #tensor的参数是(batch,channel,高度,宽度)

定义辅助分类器


class InceptionAux(nn.Module):#定义自nn.Module这个父类def __init__(self, in_channels, num_classes): #输入特征矩阵的深度 需要进行分类的类别个数super(InceptionAux, self).__init__()self.averagePool = nn.AvgPool2d(kernel_size=5, stride=3)  # output[batch, 512, 4, 4]/output[batch, 528, 4, 4]/#定义一个平均池化下采样层nn.AvgPool2d 池化和大小为5x5 步长为3self.conv = BasicConv2d(in_channels, 128, kernel_size=1)  # output[batch, 128, 4, 4]#定义第二个卷积层BasicConv2d  输入特征矩阵深度就是我们输入的in_channels,卷积核个数是128,卷积核大小为1x1 output batch不会改变 128是卷积核个数也是输出矩阵的深度128 4x4是输出的大小 是不会改变的 因为使用的卷积核大小是1x1的self.fc1 = nn.Linear(2048, 1024) #全连接层1 是输入节点个数是上面输出特征矩阵展平之后的一维向量 128x4x4=2048  输出的节点个数是1024self.fc2 = nn.Linear(1024, num_classes)#输入节点个数是1024 输出节点个数是我们需要分类的类别个数def forward(self, x):#定义一个正向传播过程# aux1: N x 512 x 14 x 14, aux2: N x 528 x 14 x 14#辅助分类器1输入的特征矩阵的维度 辅助分类器2输入的特征矩阵的维度x = self.averagePool(x)# aux1: N x 512 x 4 x 4, aux2: N x 528 x 4 x 4#通过辅助分类器1 和辅助分类器2x = self.conv(x)# N x 128 x 4 x 4x = torch.flatten(x, 1)#将我们的特征矩阵进行展平处理,从channel维度开始展平x = F.dropout(x, 0.5, training=self.training)#随即失活函数 以0.5的概率进行失活,原论文中0.7效果不好改成0。5,x是输入特征矩阵#当我们实例化一个模型model后,可以通过model.train()和model.eval()来操控模型的状态#在model.train()模式下self.training=True,在model.eval()模式下self.training=False# N x 2048x = F.relu(self.fc1(x), inplace=True)#将我们的全连接层通过relu激活函数x = F.dropout(x, 0.5, training=self.training)#通过一个dropout函数0.5比例随机失活# N x 1024x = self.fc2(x)#全连接层2# N x num_classesreturn x

定义我们的GoogLeNet网络

import torch.nn as nn
import torch
import torch.nn.functional as Fclass GoogLeNet(nn.Module):def __init__(self, num_classes=1000, aux_logits=True, init_weights=False):#分类类别个数是1000 是否使用辅助分类器 是否对我们的权重进行初始化super(GoogLeNet, self).__init__()self.aux_logits = aux_logits#是否使用辅助分类器的布尔变量传入到我们的类变量中self.conv1 = BasicConv2d(3, 64, kernel_size=7, stride=2, padding=3)#卷积层 输入特征矩阵深度是3x3 是RGB图像 卷积核个数64 卷积核大小7x7,stride是2,padding是3# padding=3这样做是为了将特征矩阵缩减为原来的一半#(224 - 7 + 2*3)/ 2 + 1 =112.5 pytorch默认向下取整,就是112self.maxpool1 = nn.MaxPool2d(3, stride=2, ceil_mode=True)#池化核大小为3x3 ceil_mode=True是指向上取整#此次没有使用localResNorm层self.conv2 = BasicConv2d(64, 64, kernel_size=1)#输入特征矩阵深度就是上一层输出特侦矩阵深度 卷积核大小为64是表中数据给出的self.conv3 = BasicConv2d(64, 192, kernel_size=3, padding=1)#此次没有使用localResNorm层self.maxpool2 = nn.MaxPool2d(3, stride=2, ceil_mode=True)self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)#使用已经定义好的inception类#输入特征矩阵的深度,ch1x1代表#1x1 ch3x3red代表#3x3 reduce   #ch5x5red代表#5x5 reduce   ch5x5代表#5x5  pool_pro代表pool proj self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)self.maxpool3 = nn.MaxPool2d(3, stride=2, ceil_mode=True)#每一个inception层的输入特征矩阵深度可以在表格数据中观察出来#也可以通过上一层inception的四个分支的特征矩阵深度加起来得到self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)self.maxpool4 = nn.MaxPool2d(3, stride=2, ceil_mode=True)self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)if self.aux_logits: #如果使用辅助分类器的话,这个是我们刚刚传入的布尔参数self.aux1 = InceptionAux(512, num_classes) #输入特侦矩阵的深度(inception4a的输出)self.aux2 = InceptionAux(528, num_classes) #输入特侦矩阵的深度(inception4d的输出)self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  #自适应的平均池化下采样操作 参数所需要输出特征矩阵的高和宽 #好处:无论输入的特征矩阵的高和宽是多少 最后的输出都可以固定为1x1self.dropout = nn.Dropout(0.4) self.fc = nn.Linear(1024, num_classes)#输入的是展平后的向量节点个数是1024,输出节点个数是num_classesif init_weights:#如果有初始化权重参数就是用 这里的详解在AlexNet模型笔记中self._initialize_weights()def forward(self, x): #定义下采样层# N x 3 x 224 x 224x = self.conv1(x)# N x 64 x 112 x 112x = self.maxpool1(x)# N x 64 x 56 x 56x = self.conv2(x)# N x 64 x 56 x 56x = self.conv3(x)# N x 192 x 56 x 56x = self.maxpool2(x)# N x 192 x 28 x 28x = self.inception3a(x)# N x 256 x 28 x 28x = self.inception3b(x)# N x 480 x 28 x 28x = self.maxpool3(x)# N x 480 x 14 x 14x = self.inception4a(x)# N x 512 x 14 x 14if self.training and self.aux_logits:    # eval model lose this layer#第一个参数是判断我们的当前处于的训练状态是否在训练状态 然后是是否使用辅助分类器aux1 = self.aux1(x)x = self.inception4b(x)# N x 512 x 14 x 14x = self.inception4c(x)# N x 512 x 14 x 14x = self.inception4d(x)# N x 528 x 14 x 14if self.training and self.aux_logits:    # eval model lose this layer#第一个参数是判断我们的当前处于的训练状态是否在训练状态 然后是是否使用辅助分类器aux2 = self.aux2(x)x = self.inception4e(x)# N x 832 x 14 x 14x = self.maxpool4(x)# N x 832 x 7 x 7x = self.inception5a(x)# N x 832 x 7 x 7x = self.inception5b(x)# N x 1024 x 7 x 7x = self.avgpool(x)# N x 1024 x 1 x 1x = torch.flatten(x, 1)# N x 1024x = self.dropout(x)x = self.fc(x)# N x 1000 (num_classes)if self.training and self.aux_logits:   # eval model lose this layerreturn x, aux2, aux1#返回三个值 一个是我们的主输出值 辅助分类器2的值 辅助分类器1的值return xdef _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.normal_(m.weight, 0, 0.01)nn.init.constant_(m.bias, 0)

train.py

与AlexNet基本相同 只有两点不同

import torch
import torch.nn as nn
from torchvision import transforms, datasets
import torchvision
import json
import matplotlib.pyplot as plt
import os
import torch.optim as optim
from model import GoogLeNetdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)data_transform = {"train": transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),"val": transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path
image_path = data_root + "/data_set/flower_data/"  # flower data set pathtrain_dataset = datasets.ImageFolder(root=image_path + "train",transform=data_transform["train"])
train_num = len(train_dataset)# {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
flower_list = train_dataset.class_to_idx
cla_dict = dict((val, key) for key, val in flower_list.items())
# write dict into json file
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:json_file.write(json_str)batch_size = 32
train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size, shuffle=True,num_workers=0)validate_dataset = datasets.ImageFolder(root=image_path + "val",transform=data_transform["val"])
val_num = len(validate_dataset)
validate_loader = torch.utils.data.DataLoader(validate_dataset,batch_size=batch_size, shuffle=False,num_workers=0)# test_data_iter = iter(validate_loader)
# test_image, test_label = test_data_iter.next()# net = torchvision.models.googlenet(num_classes=5)
# model_dict = net.state_dict()
# pretrain_model = torch.load("googlenet.pth")
# del_list = ["aux1.fc2.weight", "aux1.fc2.bias",
#             "aux2.fc2.weight", "aux2.fc2.bias",
#             "fc.weight", "fc.bias"]
# pretrain_dict = {k: v for k, v in pretrain_model.items() if k not in del_list}
# model_dict.update(pretrain_dict)
# net.load_state_dict(model_dict)
net = GoogLeNet(num_classes=5, aux_logits=True, init_weights=True)
net.to(device)
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.0003)best_acc = 0.0
save_path = './googleNet.pth'
for epoch in range(30):# trainnet.train()running_loss = 0.0for step, data in enumerate(train_loader, start=0):images, labels = dataoptimizer.zero_grad()logits, aux_logits2, aux_logits1 = net(images.to(device))loss0 = loss_function(logits, labels.to(device))loss1 = loss_function(aux_logits1, labels.to(device))loss2 = loss_function(aux_logits2, labels.to(device))loss = loss0 + loss1 * 0.3 + loss2 * 0.3loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()# print train processrate = (step + 1) / len(train_loader)a = "*" * int(rate * 50)b = "." * int((1 - rate) * 50)print("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss), end="")print()# validatenet.eval()acc = 0.0  # accumulate accurate number / epochwith torch.no_grad():for val_data in validate_loader:val_images, val_labels = val_dataoutputs = net(val_images.to(device))  # eval model only have last output layerpredict_y = torch.max(outputs, dim=1)[1]acc += (predict_y == val_labels.to(device)).sum().item()val_accurate = acc / val_numif val_accurate > best_acc:best_acc = val_accuratetorch.save(net.state_dict(), save_path)print('[epoch %d] train_loss: %.3f  test_accuracy: %.3f' %(epoch + 1, running_loss / step, val_accurate))print('Finished Training')

与AlexNet不同的两点

1.在定义我们的模型部分

net = GoogLeNet(num_classes=5, aux_logits=True, init_weights=True)
#采用辅助分类器

2.在我们的损失函数部分

  logits, aux_logits2, aux_logits1 = net(images.to(device)) #将我们的一批数据 训练图像传入到我们的网络当中,会得到三个输出#一个主输出,两个辅助分类器的输出loss0 = loss_function(logits, labels.to(device))#loss_function函数将我们的主输出与真实标签的之间的一个损失loss1 = loss_function(aux_logits1, labels.to(device))#loss_function函数将我们的辅助分类器1与真实标签的之间的一个损失loss2 = loss_function(aux_logits2, labels.to(device))#loss_function函数将我们的辅助分类器2与真实标签的之间的一个损失loss = loss0 + loss1 * 0.3 + loss2 * 0.3#原论文中就是以0.3的权重配置到损失当中loss.backward() #将损失进行一个反向传播optimizer.step()#通过我们的优化器更新我们的模型参数
#之前网络当中只有一个输出 现在采用了两个辅助分类器 ,所以一共有三个输出

3.注意的点net.train()和net.eval()
当我们的网络在train的过程中 training参数值就是True 返回一个主输出和两个辅助输出
当我们的网络在eval的过程中 training参数值就是False 只返一个主输出 因为验证环节不需要辅助分类器的结果 所以可以使用这个参数屏蔽这两个辅助分类器的结果 可以减少参数运算量

predict.py

大致与AlexNet模型的predict.py部分类似

import torch
from model import GoogLeNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import jsondata_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# load image
img = Image.open("../tulip.jpg")
plt.imshow(img)
# [N, C, H, W]
img = data_transform(img)
# expand batch dimension
img = torch.unsqueeze(img, dim=0)# read class_indict
try:json_file = open('./class_indices.json', 'r')class_indict = json.load(json_file)
except Exception as e:print(e)exit(-1)# create model
model = GoogLeNet(num_classes=5, aux_logits=False)
# load model weights
model_weight_path = "./googleNet.pth"
missing_keys, unexpected_keys = model.load_state_dict(torch.load(model_weight_path), strict=False)
model.eval()
with torch.no_grad():# predict classoutput = torch.squeeze(model(img))predict = torch.softmax(output, dim=0)predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)])
plt.show()

注意的点
载入模型的部分不需要构建辅助分类器 aux_logits=False

# create model
model = GoogLeNet(num_classes=5, aux_logits=False)

但是我们保存模型的时候,已经将我们的参数保存在我们的模型当中,所以我们要将我们的strict参数设为False,默认为True

strict=True就意味着会精准匹配我们当前模型和我们所需载入的权重模型的一个结构

因为我们现在的所搭建的GoogLeNet是没有辅助分类器的,所以和我们保存的模型结构是缺一些层结构

missing_keys, unexpected_keys = model.load_state_dict(torch.load(model_weight_path), strict=False)
#在unexpe_keys会有一系列层 这些层都是属于那些辅助分类器的

一位深度学习小萌新的学渣笔记(四)GoogLeNet网络介绍及代码详解相关推荐

  1. 失落城堡 获取服务器信息,【萌新攻略】失落城堡基础信息及技巧详解

    图片是微信截图的,看不清其实也没关系.我懒得在图上画一二三了,那么自定一个说法,天赋页分六列三大行,每大行都有上下分行,不要纠结太多,看得懂就行了. 第一列第二列 第二列分别解锁出门武器,宝箱,药水, ...

  2. 《机器学习实战》第二章学习笔记:K-近邻算法(代码详解)

    <机器学习实战>数据资料以及总代码可以去GitHub中下载: GitHub代码地址:https://github.com/yangshangqi/Machine-Learning-in-A ...

  3. 一位微信小程序萌新的学渣笔记(三)基础语法之常见组件

    文章目录 常见组件 view text image swiper navigator rich-text 富文本标签 button icon radio checkbox 自定义组件 创建自定义组件 ...

  4. 深度学习_目标检测_YOLOv1,v2,v3,v4,v5,v6,v7全系列详解(持续更新)

    [Make YOLO Great Again]栏目专注于从更实战,更深刻的角度解析YOLOv1-v7这个CV领域举足轻重的算法系列,并给出其在业务侧,竞赛侧以及研究侧的延伸思考.欢迎大家一起交流学习

  5. 《动手学深度学习》(PyTorch版)避坑总结 - 1 【d2lzh_pytorch模块导入方法详解及提示错误的解决方法】

    目录 运行环境 问题对应的章节 问题描述 解决方法 第一步:下载好包 第二步:转移d2lzh_pytorch文件夹 第三步:验证utils.py文件能否正常运行 第四步:在程序中导入d2lzh_pyt ...

  6. 【深度学习】利用tensorflow2.0卷积神经网络进行卫星图片分类实例操作详解

    本文的应用场景是对于卫星图片数据的分类,图片总共1400张,分为airplane和lake两类,也就是一个二分类的问题,所有的图片已经分别放置在2_class文件夹下的两个子文件夹中.下面将从这个实例 ...

  7. 来自某位小萌新的Web安全学习--day1

    标题草草介绍一哈哈: 哈喽!大家好!这里是网安一名小萌新发来的报道.19级网络空间安全本科生.现在的时间应该是2021-7-14日,正是大二升到大三的暑假阶段.由于前两年种种原因导致我个人的学习方向有 ...

  8. 小萌新准备参加五一建模大赛纪实

    小萌新准备参加五一数学建模大赛纪实 2020.4.20 2020.4.21 2020.4.22 2020.4.28 2020.5.1 本萌新在对数学建模一无所知的情况下,被邀请一起参加数学建模比赛,虽 ...

  9. 浙江杭电计算机系的秦嘉珩,迎新季丨@2019级杭电小萌新,你们的最美辅导员上线啦!...

    原标题:迎新季丨@2019级杭电小萌新,你们的最美辅导员上线啦! 2019级小萌新们 欢迎大家加入杭州电子科技大学 在即将开启的四年大学生活中 有这样一位亲切的老师 陪你军训,与你谈心,为你保驾护航 ...

最新文章

  1. 更新elementui图标不显示_超简单elementui主题及变量修改方案
  2. 数组名和数组名取地址的区别
  3. 【数字信号处理】线性时不变系统 LTI “ 输入 “ 与 “ 输出 “ 之间的关系 ( 线性卷积起点定理 | 左边序列概念 | 推理 )
  4. app mvc框架_Google App Engine上的Spring MVC和REST
  5. mongoose换成mysql_如何将MongoDB数据库的数据迁移到MySQL数据库中
  6. 基本算法——康托展开与逆康托展开
  7. Web前端实现锁屏/解锁功能
  8. securecrt修改mysql密码_在CentOS下Mysql5.5的密码修改
  9. ECSHOP全球国际通用配送快递插件,DHL、FEDEX、TNT、UPS配送快递插件
  10. 网站百度快速排名软件系统
  11. 用devc++表白_表白墙第42期|别人深夜买醉,我只想买你的心
  12. 11g OCM 考试感悟
  13. 读书笔记2014第6本:《The Hunger Games》
  14. Mysql出现问题:ERROR 1062 (23000): Duplicate entry ‘‘ for key ‘PRIMARY‘解决方案
  15. 高校BBS最HOT的100个笑话(不看保证后悔终身)
  16. 怎么把html设置桌面壁纸,win7系统怎么把桌面更换成自己喜欢的桌面背景?
  17. CentOS8服务器时间同步
  18. Python 的 libpng warning: iCCP: cHRM chunk does not match sRGB 报错处理
  19. 程序员生存定律-六个程序员的故事(2) .
  20. 如何自定义设置虚拟机的的IP地址

热门文章

  1. 计算机保密检查工作计划,局保密工作计划方案
  2. 手机端也能免费查看CAD图纸啦!
  3. 压缩包打开密码有什么方法破解
  4. 数据库范式判断及分解技巧
  5. 学Python有什么用?看完这些你肯定明白
  6. 总账:日记账导入流程(文档 ID 1591640.1)
  7. 光纤耦合装置的公差分析
  8. EMQX 实现 阿里云一机一密 认证
  9. k8s使用Harbor仓库
  10. 图像语义分割和目标检测(上)