深度学习之CNN

目录

我们为什么要用CNN,或者说究竟是因为什么我们要用CNN

卷积操作的实现原理

 补充知识

torch.nn.Conv2d()

注意

torch.nn.functional.conv2d()

torch.nn.functional.conv2d()和torch.nn.Conv2d()区别

关于padding填充

torch.nn.BatchNorm2d(out_channel)

sklearn.metrics

回归指标

回归方差(反应自变量与因变量之间的相关程度)

平均绝对误差

方差

中值绝对误差

R平方值

分类指标

 精度sklearn.metrics.accuracy_score

ROC曲线下的面积auc

根据预测得分计算平均精度(AP)average_precision_score

brier损失函数brier_score_loss()

混淆矩阵confusion_matrix()

fi_score()

对数损耗

查准率precision_score()

recall_score()

roc_auc_score()

roc_curve()

交叉熵函数Cross-Entropy的补充

卷积后的大小计算

代码示例 

代码运行结果

池化计算 

代码示例 

 代码运行结果

 卷积实战之猫狗分类数据集

导入操作库

 使用类创建数据集(猫狗分类)

利用DataLoader加载数据集

搭建CNN神经网络

反向传播并且输出准确率

图像显示 

完整源码 

运行结果

总结 

VGG16

vgg16的网络结构

代码

ResNet18 

代码


我们为什么要用CNN,或者说究竟是因为什么我们要用CNN

CNN,就是我们的卷积神经网络,在了解它之前,我们首先回忆一下我们的BP神经网络。关于BP神将网络我们可以看这篇博客:深度学习之感知机,激活函数,梯度消失,BP神经网络-CSDN博客

我们知道在我们训练图片识别种类的BP神经网络中,我们首先要做的就是将图片进行展平,每个像素点就相当于一个输入层神经元,而后面和隐藏层之间的关系就是我们的全连接层。

就是这个样子,这样做的缺点很明显:

1.参数开销过大,运行时间过长。

2.如果在隐藏层层数不够甚至只有一层的情况下,并且我们训练分类的训练集的有效部份都在图片同一个位置,那我们训练出来的这个模型就不能用于有效部份在图片其他位置的识别,或者说,我们训练出来的模型里面只有一部分的参数是有用的,其他的参数是没用的。

例如我们用如下这样的图片训练的模型,标签为‘横折’。

 这样的模型是无法识别下面的图片的。

参数的有效是因为图片的有效部份才有效的,这是我们BP神经网络的一个缺点。

于是有人设想,(比如就上面的图片示例),我们有没有什么方法可以将中间是有效部分的图片所学到的规律,或者说所训练的参数,也可以在其他的位置有效?答案是有,让不同位置共享同样的权重即可,而这也就是卷积操作的核心思想,也是为什么我们要用CNN卷积神经网络。

权重的共享是其和BP神经网络根本的区别。

卷积操作的实现原理

(该图片及上述图片来自网络,侵权必删。)

上图就是卷积操作的核心,权重共享的实现原理。 

下面就是卷积操作的基础知识的详细介绍了。

卷积神经网络(CNN)基础知识整理 (qq.com)

链接里面的文章里面提到的步幅stride,我认为解释成每次移动的长度更好一些,为1是就是每次移动一位,从第一列到第二列......,从第一行到第二行......,为2就是每次移动两位,从第一列到第三列......,中间隔着一列,从第一行到第二行......,中间隔着一行。

w就是输入尺寸,k是过滤器尺寸,p是填充的大小,s是步幅。

 补充知识

torch.nn.Conv2d()

dilation = 2

蓝色部份就是 我们要进行卷积操作的数据。

groups参数

进行分组卷积的组数,这个不常用一般就是默认值,默认值为一。

官方文档:

当groups等于1时就是普通的卷积操作。

import torch
import torch.nn as nn
N,C_in,H,W,C_out =  10,4,16,16,6
x = torch.randn(N,C_in,H,W).float()
conv = nn.Conv2d(C_in,C_out,kernel_size=3,stride=3,padding=1)
y = conv(x)
print(y.size())
'''torch.Size([10, 6, 6, 6])'''

 当groups=2时,就相当于把我们的输入的数据分成两份子数据了,每份数据的通道数就跟上面的计算公式一样,都和原来的数据相比除了个2,我们的卷积核也是,这样的话,我们卷积核就相当于被拆分成了两份或者说两层,这两份对应着拆分的两份数据,最后的到结果,进行拼接,就是我们的输出结果。

import torch
import torch.nn as nn
N,C_in,H,W,C_out =  10,4,16,16,6
x = torch.randn(N,C_in,H,W).float()
conv = nn.Conv2d(C_in,C_out,kernel_size=3,stride=3,padding=1)
conv_group = nn.Conv2d(C_in,C_out,kernel_size=3,stride=3,padding=1,groups = 2)
y = conv(x)
y_group = conv_group(x)
print(y.size())
print(y_group.size())
'''torch.Size([10, 6, 6, 6])'''
'''torch.Size([10, 6, 6, 6])'''

其余的类似。

dilation 参数

  这个参数决定了是否采用空洞卷积默认为1(不采用)。该参数解释起来有些麻烦,直接看样例吧。

dilation=1时的卷积:

dilation=2

注意

Padding即所谓的图像填充,后面的int型常数代表填充的多少(行数、列数),默认为0。需要注意的是这里的填充包括图像的上下左右,以padding = 1为例,若原始图像大小为32x32,那么padding后的图像大小就变成了34x34,而不是33x33。

padding_mode :即padding的模式,默认采用零填充

这些参数的默认值:

padding_mode = ‘zeros’

bias = True

groups = 1

dilation = 1

padding = 0

具体详情可以看这篇博客Pytorch的nn.Conv2d()参数详解_nn.conv2d参数-CSDN博客

torch.nn.functional.conv2d()

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) → Tensor

它里面的各种参数

返回值:一个Tensor变量

作用:在输入图像input中使用filters做卷积运算

参数的具体意义:

input:图像的大小(minibatch,in_channels,H,W),批次大小,通道数,图像的高,图像的宽

是一个四维tensor

filters:代表卷积核的大小(out_channels,in_channe/groups,H,W),是一个四维tensor

bias:代表每一个channel通道的bias偏置,是一个维数等于out_channels的tensor

stride:是一个数或者一个二元组(SH,SW),代表纵向和横向的步长

padding:是一个数或者一个二元组(PH,PW ),代表纵向和横向的填充值

dilation:和上文torch.nn.Conv2d()中的一样。

groups是一个数,代表分组卷积时分的组数,特别的当groups = in_channel时,就是在做深度卷积(depth-wise conv)(暂时先不提了)

torch.nn.functional.conv2d()和torch.nn.Conv2d()区别

PyTorch 27.2D卷积,nn.Conv2d和F.conv2d - 知乎 (zhihu.com)

关于padding填充

下面关于这部分的内容来源于这篇博客:

卷积的三种模式full, same, valid以及padding的same, valid - 知乎 (zhihu.com)

三种方式:

1. full mode

2。 same mode

当filter的中心(K)与image的边角重合时,开始做卷积运算。

并且卷积之后输出的feature map尺寸保持不变(相对于输入图片)。当然,same模式不代表完全输入输出尺寸一样,也跟卷积核的步长有关系。

same模式也是最常见的模式,因为这种模式可以在前向传播的过程中让特征图的大小保持不变,调参师不需要精准计算其尺寸变化(因为尺寸根本就没变化)。

3.valid

         当filter全部在image里面的时候,进行卷积运算,可见filter的移动范围较same更小了。

(注:filter就是过滤器也就是我们的卷积核) 

torch.nn.BatchNorm2d(out_channel)

sklearn.metrics

这个库内置了许多评价模型性能的功能模块,或者说各种评价指标

下面简单介绍一下:(图片来源网络,侵权必删)

回归指标

(y_true:真实的标签, y_pred:预测的结果)

回归方差(反应自变量与因变量之间的相关程度)

explained_variance_score(y_true, y_pred, sample_weight=None,multioutput=‘uniform_average’) 

平均绝对误差

mean_absolute_error(y_true,y_pred,sample_weight=None,multioutput=‘uniform_average’):

方差

mean_squared_error(y_true, y_pred, sample_weight=None, multioutput=‘uniform_average’)

中值绝对误差

median_absolute_error(y_true, y_pred) 

R平方值

r2_score(y_true, y_pred,sample_weight=None,multioutput=‘uniform_average’) 

分类指标

 精度sklearn.metrics.accuracy_score

sklearn.metrics.accuracy_score(y_true, y_pred, normalize=True, sample_weight=None)

normalize:默认值为True,返回正确分类的比例;如果为False,返回正确分类的样本数

(常用)


ROC曲线下的面积auc

auc(x, y, reorder=False) (较大的AUC代表了较好的performance,这个自己查吧,这里就不多解释了)

根据预测得分计算平均精度(AP)average_precision_score

average_precision_score(y_true, y_score, average=‘macro’, sample_weight=None)

brier损失函数brier_score_loss()

brier_score_loss(y_true, y_prob, sample_weight=None, pos_label=None)

这个就是一个loss函数,它的值越小越好,他就是一个损失函数

官方文档:

sklearn.metrics.brier_score_loss() scikit-learn官方教程 _w3cschool

混淆矩阵confusion_matrix()

confusion_matrix(y_true, y_pred, labels=None, sample_weight=None)

(通过计算混淆矩阵来评估分类的准确性 返回混淆矩阵)

fi_score()

f1_score(y_true, y_pred, labels=None, pos_label=1, average=‘binary’, sample_weight=None): F1值
  F1 = 2 * (precision * recall) / (precision + recall) precision(查准率)=TP/(TP+FP) recall(查全率)=TP/(TP+FN)

(返回对精确率与召回率进行平均的一个结果)

召回率 =提取出的正确信息条数 /样本中的信息条数。通俗地说,就是所有准确的条目有多少被检索出来了。一般用recall表示,有时候也称之为查全率。

对数损耗

log_loss(y_true, y_pred, eps=1e-15, normalize=True, sample_weight=None, labels=None)

对数损耗,又称逻辑损耗或交叉熵损耗

查准率precision_score()

precision_score(y_true, y_pred, labels=None, pos_label=1, average=‘binary’,)

查准率或者精度; precision(查准率)=TP/(TP+FP)

recall_score()

klearn.metrics.recall_score(y_true, y_pred, labels=None, pos_label=1,average='binary', sample_weight=None)

roc_auc_score()

roc_auc_score(y_true, y_score, average=‘macro’, sample_weight=None):计算ROC曲线下的面积就是AUC的值,the larger the better

roc_curve()

roc_curve(y_true, y_score, pos_label=None, sample_weight=None, drop_intermediate=True);计算ROC曲线的横纵坐标值,TPR,FPR
  TPR = TP/(TP+FN) = recall(真正例率,敏感度) FPR = FP/(FP+TN)(假正例率,1-特异性

 我们知识简单介绍一下,记一下常用的就好,若想仔细了解可以自行查阅。

交叉熵函数Cross-Entropy的补充

推荐看这篇文章一文搞懂熵(Entropy),交叉熵(Cross-Entropy) - 知乎 (zhihu.com)

在猫和狗分类的博客中我们提到了他,但是只是简易的介绍了一下,这里做一下补充。

首先看一下上面推荐的博客。

核心思想,我们计算的是一个混乱程度,我们假设我们的分类是正确的,那么根据交叉熵公式,其混乱程度应该是最小的,所以我们应该不断训练这个函数然后求他的最小值。(这些上面推荐的博客里面都有解释)

公式:

我们的交叉熵函数,传入的label值可以是独热编码也可以是一个数,这个数表示的是一个下标,在我们的猫狗分类中,最后的神经元是两个,所以我们可以传[0,1],[1,0]这样独热编码的形式,也可以直接传入下表,表示该下标对应的概率是1.

卷积后的大小计算

例子:

代码示例 

print('------------------------------单通道卷积核及步长stride----------------------------------------')
import torch
import torch.nn.functional as F
#输入
input=torch.tensor([[1,1,1,0,0],[0,1,1,1,0],[0,0,1,1,1],[0,0,1,1,0],[0,1,1,0,0]])
#卷积核
kernel=torch.tensor([[1,0,1],[0,1,0],[1,0,1]])
print(input.shape)
print(kernel.shape)
#修改尺寸,可以让我们进行后面的操作,修改尺寸为:批次大小,通道数,hight,weight
input=torch.reshape(input,(1,1,5,5))
#卷积核的个数,卷积核的通道数,卷积核的h,卷积核的w
kernel=torch.reshape(kernel,(1,1,3,3))
#
print(input.shape)
print(kernel.shape)
#步长stride=1
output1=F.conv2d(input,kernel,stride=1)
print(output1)
#stride=2
output2=F.conv2d(input,kernel,stride=2)
print(output2)
print('padding操作--------------------------------------------')
output3=F.conv2d(input,kernel,stride=3,padding=2)
print(output3)
output4=F.conv2d(input,kernel,stride=1,padding=1)#默认填充零
print(output4)
output5=F.conv2d(input,kernel,stride=1,padding='same')#same时系统会自动给我们填充判定,vail类型时我们自己进行填充判定
print(output5)

代码运行结果

D:\Anaconda3\envs\pytorch\python.exe D:\learn_pytorch\学习过程\第五周的代码\代码一.py 
------------------------------单通道卷积核及步长stride----------------------------------------
torch.Size([5, 5])
torch.Size([3, 3])
torch.Size([1, 1, 5, 5])
torch.Size([1, 1, 3, 3])
tensor([[[[4, 3, 4],[2, 4, 3],[2, 3, 4]]]])
tensor([[[[4, 4],[2, 4]]]])
padding操作--------------------------------------------
tensor([[[[1, 1, 0],[0, 4, 0],[0, 1, 0]]]])
tensor([[[[2, 2, 3, 1, 1],[1, 4, 3, 4, 1],[1, 2, 4, 3, 3],[1, 2, 3, 4, 1],[0, 2, 2, 1, 1]]]])
tensor([[[[2, 2, 3, 1, 1],[1, 4, 3, 4, 1],[1, 2, 4, 3, 3],[1, 2, 3, 4, 1],[0, 2, 2, 1, 1]]]])进程已结束,退出代码0

池化计算 

主要有两种池化方式,Max pooling/ avg pooling,通常情况下,池化区域是2*2大小,池化之后,4*4的图片,会变成2*2大小。

示例:

代码示例 

print('------------------------------池化层操作----------------------------------------')
import torch
import torch.nn.functional as F
#输入
input=torch.tensor([[1,1,1,0,0],[0,1,1,1,0],[0,0,1,1,1],[0,0,1,1,0],[0,1,1,0,0]],dtype=torch.float32)
#卷积核
maxsp=torch.nn.MaxPool2d(kernel_size=2)
avp=torch.nn.AvgPool2d(kernel_size=2)
input=torch.reshape(input,(1,1,5,5))
output1=maxsp(input)
print(output1)
print('---------------------------')
output2=avp(input)
print(output2)

 代码运行结果

D:\Anaconda3\envs\pytorch\python.exe D:\learn_pytorch\学习过程\第五周的代码\代码二.py 
------------------------------池化层操作----------------------------------------
tensor([[[[1., 1.],[0., 1.]]]])
---------------------------
tensor([[[[0.7500, 0.7500],[0.0000, 1.0000]]]])进程已结束,退出代码0

(注意:关于池化和卷积原理的详细可以看这篇文章:(我的图片也是来自这里:卷积神经网络(CNN)基础知识整理 (qq.com))) 

 卷积实战之猫狗分类数据集

关于猫狗分类数据集的内容,在在我的这篇博客中阐述过:BP实战之猫狗分类数据集-CSDN博客,这里就不说明了,并且创建数据集的操作在这篇博客也提到过,可以说是一模一样,下面也不多加阐述。

导入操作库

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from sklearn.metrics import accuracy_score
print('猫狗分类数据集---------------------')
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
from PIL import Image
import os

 使用类创建数据集(猫狗分类)

#使用类创建自己的猫狗分类数据集
class catanddog(Dataset):def __init__(self,rootpath,label_dir):self.rootpath=rootpathself.label_dir=label_dirself.path=os.path.join(rootpath,label_dir)self.imge_all=os.listdir(self.path)self.transform=transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])def __getitem__(self, item):imge_name=self.imge_all[item]imge=Image.open(os.path.join(self.path,imge_name))imge=self.transform(imge)if self.label_dir=='Cat':target=0else:target=1if imge.shape[0]!=3:print(self.imge_all[item],target)os.remove(os.path.join(self.path,imge_name))return imge,targetdef __len__(self):return len(self.imge_all)
rootpath='D:\learn_pytorch\数据集\PetImages_test'
test_rootpath='D:\learn_pytorch\数据集\PetImages_test\Test'
cat='Cat'#标签对应0
dog='Dog'#标签对应1
catdatasets=catanddog(rootpath,cat)#猫的数据集
#print(len(catdatasets))#12500
dogdatasets=catanddog(rootpath,dog)#狗的数据集
testcat=catanddog(test_rootpath,cat)
testdog=catanddog(test_rootpath,dog)
traindata=catdatasets+dogdatasets
testdata=testcat+testdog

注意: 我们为了演示方便,这次另外制作了新的文件夹作为数据集,其中训练集dog1170张,cat1116张,测试集猫狗各39张。

利用DataLoader加载数据集

trainload=DataLoader(dataset=traindata,shuffle=True,batch_size=64)
testLoad=DataLoader(dataset=testdata,shuffle=False,batch_size=39*2)

搭建CNN神经网络

class CNNNetwork(torch.nn.Module):def __init__(self):super(CNNNetwork,self).__init__()#我们的每张图片都是224*224*3个像素点#第一个隐藏层self.cnn1=torch.nn.Conv2d(in_channels=3,out_channels=3,kernel_size=3)#激活函数,这里选择Reluself.relu1=torch.nn.ReLU()#池化层,最大池化self.max1=torch.nn.MaxPool2d(kernel_size=2)#第二个隐藏层self.cnn2=torch.nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3)#激活函数,这里选择Reluself.relu2=torch.nn.ReLU()#池化层,最大池化self.max2=torch.nn.MaxPool2d(kernel_size=2)# #第三个隐藏层:# self.cnn3=torch.nn.Conv2d(in_channels=6,out_channels=12,kernel_size=3)# #激活函数,这里选择Relu# self.relu3=torch.nn.ReLU()# #池化层,最大池化# self.max3=torch.nn.MaxPool2d(kernel_size=2)#输出层self.linear4=torch.nn.Linear(6*54*54,2)# 激活函数self.softmax=torch.nn.LogSoftmax()#前向传播def forward(self,x):#前向传播x=self.cnn1(x)x=self.relu1(x)x=self.max1(x)#--------------------x=self.cnn2(x)x=self.relu2(x)x=self.max2(x)#------------------------# x=self.cnn3(x)# x=self.relu3(x)# x=self.max3(x)#------------------------# print('----------------')# print(x.shape)# print('----------------')x=torch.reshape(x,(x.shape[0],-1))x=self.linear4(x)x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想#上面的这些都可以这几使用x=self.model(x)来代替,为什么能用它,我的理解是,我们继承的class moudle 然后对立面写好的模型框架进行定义,而这个方法就是可以直接调用我们定义好的神经网络return x

和我们bp网络的思路差不多,前向传播只不过用了卷积层,我们要清楚一件事就是,一般而言,我们卷积玩要进行激活函数的操作,位的就是引入非线性的操作,但是如果随着卷积层的深度加深引入的过多的话,有可能会出现梯度消失的现象。

反向传播并且输出准确率

#建立我们的神经网络对象
model=CNNNetwork()
# #定义损失函数
critimizer=torch.nn.NLLLoss()
#定义优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.001,momentum=0.9)
epochs=6
#每轮抽取次数的和
a=0
loss_=[]
a_=[]
font = font_manager.FontProperties(fname="C:\\Users\\ASUS\\Desktop\\Fonts\\STZHONGS.TTF")
# #开始预测
example=enumerate(testLoad)#从测试集里面随机抽64份并且记录下来里面的内容和下标
batch_index,(imagess,labelss)=next(example)
# bath_index=0
# imagess=0
# labelss=0
# for i,j in example:
#     bath_index=i
#     print(j)# (imagess, labelss)=j
score_=[]
for i in range(epochs):# 损失值参数sumloss = 0for imges,labels in trainload:a+=1#前向传播# print('imges.shape:',imges.shape)output=model(imges)#反向传播loss=critimizer(output,labels)loss.backward()#参数更新optimizer.step()#梯度清零optimizer.zero_grad()#损失累加sumloss+=loss.item()loss_.append(sumloss)a_.append(a)print(f"第{i+1}轮的损失:{sumloss},抽取次数和:{a}")print('正确率---------------------')labelss_ = labelss.numpy()pre_ = []for i in range(39 * 2):sample_ = torch.unsqueeze(imagess[i], dim=0)  # 升维度加1# print(a.shape)pre = model(sample_)  # 预测# 第一张图片对应的pre得格式:# 接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0pro = list(pre.detach().numpy()[0])pre_label = pro.index(max(pro))pre_.append(pre_label)# print(pre_label)pre_ = np.array(pre_)sore = accuracy_score(labelss_, pre_)score_.append(sore)print('准确率:', sore)

图像显示 

#预测画图------------------------
fig=plt.figure()
for i in range(16):# print(imagess[i])# print(imagess[i].shape)a=torch.unsqueeze(imagess[i],dim=0)    #升维度加1# print('a.shape:',a.shape)pre=model(a)#预测#第一张图片对应的pre得格式:#接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0# print(pre)pro = list(pre.detach().numpy()[0])pre_label=pro.index(max(pro))# print(pre_label)dict_={0:'猫',1:"狗"}#图像显示img=torch.squeeze(a)        #去掉维度中的一个‘1’,大小变成3*224*224 需要转换img_=img.permute(1,-1 , 0)                   #224*224*3这个我们的图像才可以显示imge=img_.numpy()# print(img_.shape)# print(img_)plt.subplot(4,4,i+1)plt.tight_layout()plt.imshow(imge,cmap='gray',interpolation='none')plt.title(f"预测值:{dict_[pre_label]}",fontproperties=font, fontsize=9)plt.xticks([])plt.yticks([])
plt.show()

完整源码 

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from sklearn.metrics import accuracy_score
print('猫狗分类数据集---------------------')
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
from PIL import Image
import os
#使用类创建自己的猫狗分类数据集
class catanddog(Dataset):def __init__(self,rootpath,label_dir):self.rootpath=rootpathself.label_dir=label_dirself.path=os.path.join(rootpath,label_dir)self.imge_all=os.listdir(self.path)self.transform=transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])def __getitem__(self, item):imge_name=self.imge_all[item]imge=Image.open(os.path.join(self.path,imge_name))imge=self.transform(imge)if self.label_dir=='Cat':target=0else:target=1if imge.shape[0]!=3:print(self.imge_all[item],target)os.remove(os.path.join(self.path,imge_name))return imge,targetdef __len__(self):return len(self.imge_all)
rootpath='D:\learn_pytorch\数据集\PetImages_test'
test_rootpath='D:\learn_pytorch\数据集\PetImages_test\Test'
cat='Cat'#标签对应0
dog='Dog'#标签对应1
catdatasets=catanddog(rootpath,cat)#猫的数据集
#print(len(catdatasets))#12500
dogdatasets=catanddog(rootpath,dog)#狗的数据集
testcat=catanddog(test_rootpath,cat)
testdog=catanddog(test_rootpath,dog)
traindata=catdatasets+dogdatasets
testdata=testcat+testdog
# print(traindata[12500])
# print(testdata[0])
# for x , y in testdata:
#     print(x,y)
#     pass
# 利用DataLoader加载数据集
trainload=DataLoader(dataset=traindata,shuffle=True,batch_size=64)
testLoad=DataLoader(dataset=testdata,shuffle=False,batch_size=39*2)#搭建CNN神经网络
class CNNNetwork(torch.nn.Module):def __init__(self):super(CNNNetwork,self).__init__()#我们的每张图片都是224*224*3个像素点#第一个隐藏层self.cnn1=torch.nn.Conv2d(in_channels=3,out_channels=3,kernel_size=3)#激活函数,这里选择Reluself.relu1=torch.nn.ReLU()#池化层,最大池化self.max1=torch.nn.MaxPool2d(kernel_size=2)#第二个隐藏层self.cnn2=torch.nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3)#激活函数,这里选择Reluself.relu2=torch.nn.ReLU()#池化层,最大池化self.max2=torch.nn.MaxPool2d(kernel_size=2)# #第三个隐藏层:# self.cnn3=torch.nn.Conv2d(in_channels=6,out_channels=12,kernel_size=3)# #激活函数,这里选择Relu# self.relu3=torch.nn.ReLU()# #池化层,最大池化# self.max3=torch.nn.MaxPool2d(kernel_size=2)#输出层self.linear4=torch.nn.Linear(6*54*54,2)# 激活函数self.softmax=torch.nn.LogSoftmax()#前向传播def forward(self,x):#前向传播x=self.cnn1(x)x=self.relu1(x)x=self.max1(x)#--------------------x=self.cnn2(x)x=self.relu2(x)x=self.max2(x)#------------------------# x=self.cnn3(x)# x=self.relu3(x)# x=self.max3(x)#------------------------# print('----------------')# print(x.shape)# print('----------------')x=torch.reshape(x,(x.shape[0],-1))x=self.linear4(x)x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想#上面的这些都可以这几使用x=self.model(x)来代替,为什么能用它,我的理解是,我们继承的class moudle 然后对立面写好的模型框架进行定义,而这个方法就是可以直接调用我们定义好的神经网络return x
#建立我们的神经网络对象
model=CNNNetwork()
# #定义损失函数
critimizer=torch.nn.NLLLoss()
#定义优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.001,momentum=0.9)
epochs=6
#每轮抽取次数的和
a=0
loss_=[]
a_=[]
font = font_manager.FontProperties(fname="C:\\Users\\ASUS\\Desktop\\Fonts\\STZHONGS.TTF")
# #开始预测
example=enumerate(testLoad)#从测试集里面随机抽64份并且记录下来里面的内容和下标
batch_index,(imagess,labelss)=next(example)
# bath_index=0
# imagess=0
# labelss=0
# for i,j in example:
#     bath_index=i
#     print(j)# (imagess, labelss)=j
score_=[]
for i in range(epochs):# 损失值参数sumloss = 0for imges,labels in trainload:a+=1#前向传播# print('imges.shape:',imges.shape)output=model(imges)#反向传播loss=critimizer(output,labels)loss.backward()#参数更新optimizer.step()#梯度清零optimizer.zero_grad()#损失累加sumloss+=loss.item()loss_.append(sumloss)a_.append(a)print(f"第{i+1}轮的损失:{sumloss},抽取次数和:{a}")print('正确率---------------------')labelss_ = labelss.numpy()pre_ = []for i in range(39 * 2):sample_ = torch.unsqueeze(imagess[i], dim=0)  # 升维度加1# print(a.shape)pre = model(sample_)  # 预测# 第一张图片对应的pre得格式:# 接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0pro = list(pre.detach().numpy()[0])pre_label = pro.index(max(pro))pre_.append(pre_label)# print(pre_label)pre_ = np.array(pre_)sore = accuracy_score(labelss_, pre_)score_.append(sore)print('准确率:', sore)plt.figure()
plt.plot(a_, score_)
plt.title('准确率随着抽取总次数得变化情况:', fontproperties=font, fontsize=18)
plt.xlabel('抽取总次数', fontproperties=font, fontsize=18)
plt.ylabel('准确率', fontproperties=font, fontsize=18)
plt.legend(prop=font)
plt.show()plt.figure()
plt.plot(a_,loss_)
plt.title('损失值随着抽取总次数得变化情况:',fontproperties=font, fontsize=18)
plt.show()
#预测画图------------------------
fig=plt.figure()
for i in range(16):# print(imagess[i])# print(imagess[i].shape)a=torch.unsqueeze(imagess[i],dim=0)    #升维度加1# print('a.shape:',a.shape)pre=model(a)#预测#第一张图片对应的pre得格式:#接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0# print(pre)pro = list(pre.detach().numpy()[0])pre_label=pro.index(max(pro))# print(pre_label)dict_={0:'猫',1:"狗"}#图像显示img=torch.squeeze(a)        #去掉维度中的一个‘1’,大小变成3*224*224 需要转换img_=img.permute(1,-1 , 0)                   #224*224*3这个我们的图像才可以显示imge=img_.numpy()# print(img_.shape)# print(img_)plt.subplot(4,4,i+1)plt.tight_layout()plt.imshow(imge,cmap='gray',interpolation='none')plt.title(f"预测值:{dict_[pre_label]}",fontproperties=font, fontsize=9)plt.xticks([])plt.yticks([])
plt.show()

运行结果

D:\Anaconda3\envs\pytorch\python.exe D:\learn_pytorch\学习过程\第五周的代码\代码三.py 
D:\Anaconda3\envs\pytorch\lib\site-packages\scipy\__init__.py:132: UserWarning: A NumPy version >=1.21.6 and <1.28.0 is required for this version of SciPy (detected version 1.21.5)warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
猫狗分类数据集---------------------
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第1轮的损失:24.896146833896637,抽取次数和:36
正确率---------------------
准确率: 0.4230769230769231
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第2轮的损失:24.687452137470245,抽取次数和:72
正确率---------------------
准确率: 0.44871794871794873
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第3轮的损失:24.54122930765152,抽取次数和:108
正确率---------------------
准确率: 0.5641025641025641
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第4轮的损失:24.266421258449554,抽取次数和:144
正确率---------------------
准确率: 0.5
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第5轮的损失:24.06421685218811,抽取次数和:180
正确率---------------------
准确率: 0.5641025641025641
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
第6轮的损失:23.939453184604645,抽取次数和:216
正确率---------------------
准确率: 0.5512820512820513
No artists with labels found to put in legend.  Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
D:\learn_pytorch\学习过程\第五周的代码\代码三.py:101: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想进程已结束,退出代码0

 

总结 

本次示例并没有进行优化,优化方式可以从以下几种方面考虑。

1.卷积层的深度,一般而言,卷积模型的准确度会随着深度的增加而增加,但是会出现“退化现象”。

2.卷积层相关参数的设置。

3.池化方式

4.全连接层的层数

VGG16

我们简单的展示一下vgg16

vgg16的网络结构

代码

print('-------------------------------VGG16-------------------------------')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from sklearn.metrics import accuracy_score
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
from PIL import Image
import os
class VGG16(torch.nn.Module):def __init__(self):super(VGG16,self).__init__()#定义网络模块self.conv1=torch.nn.Conv2d(3,64,kernel_size=1,stride=1,padding=1)self.relu1=torch.nn.ReLU(inplace=True)#inplace = False 时,不会修改输入对象的值,而是返回一个新创建的对象,nn.ReLU()函数默认inplace 默认是Falseself.conv2 = torch.nn.Conv2d(64,64,kernel_size=3,stride=1,padding=1)self.relu2 = torch.nn.ReLU(inplace=True)self.max_pooling_1=torch.nn.MaxPool2d(kernel_size=2,stride=2)self.conv3 = torch.nn.Conv2d(64,128,kernel_size=3,stride=1,padding=1)self.relu3 = torch.nn.ReLU(inplace=True)self.conv4 = torch.nn.Conv2d(128,128,kernel_size=3,stride=1,padding=1)self.relu4= torch.nn.ReLU(inplace=True)self.max_pooling_2 = torch.nn.MaxPool2d(kernel_size=2,stride=2)self.conv5 = torch.nn.Conv2d(128,256,kernel_size=3,stride=1,padding=1)self.relu5 = torch.nn.ReLU(inplace=True)self.conv6 = torch.nn.Conv2d(256,256,kernel_size=3,stride=1,padding=1)self.relu6 = torch.nn.ReLU(inplace=True)self.conv7 = torch.nn.Conv2d(256,256,kernel_size=3,stride=1,padding=1)self.relu7 = torch.nn.ReLU(inplace=True)self.max_pooling_3 = torch.nn.MaxPool2d(kernel_size=2,stride=2)self.conv8 = torch.nn.Conv2d(256,512,kernel_size=3,stride=1,padding=1)self.relu8 = torch.nn.ReLU(inplace=True)self.conv9 = torch.nn.Conv2d(512,512,kernel_size=3,stride=1,padding=1)self.relu9 = torch.nn.ReLU(inplace=True)self.conv10 = torch.nn.Conv2d(512,512,kernel_size=3,stride=1,padding=1)self.relu10 = torch.nn.ReLU(inplace=True)self.max_pooling_4= torch.nn.MaxPool2d(kernel_size=2,stride=2)self.conv11= torch.nn.Conv2d(512,512,kernel_size=3,stride=1,padding=1)self.relu11 = torch.nn.ReLU(inplace=True)self.conv12 = torch.nn.Conv2d(512,512,kernel_size=3,stride=1,padding=1)self.relu12 = torch.nn.ReLU(inplace=True)self.conv13 = torch.nn.Conv2d(512,512,kernel_size=3,stride=1,padding=1)self.relu13 = torch.nn.ReLU(inplace=True)self.max_pooling_5= torch.nn.MaxPool2d(kernel_size=2,stride=2)#全部连接层self.f1=torch.nn.Linear(512*7*7,4096)self.relu14=torch.nn.ReLU(inplace=True)self.f2=torch.nn.Linear(4096,4096)self.relu15=torch.nn.ReLU(inplace=True)self.dropout=torch.nn.Dropout()#是一种常用的正则化方法,通过随机将部分神经元的输出置为0来减少过拟合,默认惩罚因子p=0.5# self.f3=torch.nn.Linear(4096,1000)self.f3 = torch.nn.Linear(4096, 2)#为了猫狗数据集简单的修改def forward(self,x):x=self.conv1(x)x=self.relu1(x)x = self.conv2(x)x=self.relu2(x)x = self.max_pooling_1(x)x = self.conv3(x)x = self.relu3(x)x = self.conv4(x)x = self.relu4(x)x = self.max_pooling_2(x)x = self.conv5(x)x = self.relu5(x)x = self.conv6(x)x = self.relu6(x)x = self.conv7(x)x = self.relu7(x)x = self.max_pooling_3(x)x = self.conv8(x)x = self.relu8(x)x = self.conv9(x)x = self.relu9(x)x = self.conv10(x)x = self.relu10(x)x = self.max_pooling_4(x)x = self.conv11(x)x = self.relu11(x)x = self.conv12(x)x = self.relu12(x)x = self.conv13(x)x = self.relu13(x)x = self.max_pooling_5(x)x=x.view(-1,512*7*7)x=self.f1(x)x=self.relu14(x)x = self.f2(x)x = self.relu15(x)x = self.f3(x)return x

单独建立该模块,模块调用

print('----------------------VGG16------------------测试')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from sklearn.metrics import accuracy_score
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
from PIL import Image
import os
from VGG16 import VGG16
#使用类创建自己的猫狗分类数据集
class catanddog(Dataset):def __init__(self,rootpath,label_dir):self.rootpath=rootpathself.label_dir=label_dirself.path=os.path.join(rootpath,label_dir)self.imge_all=os.listdir(self.path)self.transform=transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])def __getitem__(self, item):imge_name=self.imge_all[item]imge=Image.open(os.path.join(self.path,imge_name))imge=self.transform(imge)if self.label_dir=='Cat':target=0else:target=1if imge.shape[0]!=3:print(self.imge_all[item],target)os.remove(os.path.join(self.path,imge_name))return imge,targetdef __len__(self):return len(self.imge_all)
rootpath='D:\learn_pytorch\数据集\PetImages_test'
test_rootpath='D:\learn_pytorch\数据集\PetImages_test\Test'
cat='Cat'#标签对应0
dog='Dog'#标签对应1
catdatasets=catanddog(rootpath,cat)#猫的数据集
#print(len(catdatasets))#12500
dogdatasets=catanddog(rootpath,dog)#狗的数据集
testcat=catanddog(test_rootpath,cat)
testdog=catanddog(test_rootpath,dog)
traindata=catdatasets+dogdatasets
testdata=testcat+testdog
# print(traindata[12500])
# print(testdata[0])
# for x , y in testdata:
#     print(x,y)
#     pass
# 利用DataLoader加载数据集
trainload=DataLoader(dataset=traindata,shuffle=True,batch_size=64)
testLoad=DataLoader(dataset=testdata,shuffle=False,batch_size=39*2)#搭建CNN神经网络
# class CNNNetwork(torch.nn.Module):
#     def __init__(self):
#         super(CNNNetwork,self).__init__()
#         #我们的每张图片都是224*224*3个像素点
#         #第一个隐藏层
#         self.cnn1=torch.nn.Conv2d(in_channels=3,out_channels=3,kernel_size=3)
#         #激活函数,这里选择Relu
#         self.relu1=torch.nn.ReLU()
#         #池化层,最大池化
#         self.max1=torch.nn.MaxPool2d(kernel_size=2)
#         #第二个隐藏层
#         self.cnn2=torch.nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3)
#         #激活函数,这里选择Relu
#         self.relu2=torch.nn.ReLU()
#         #池化层,最大池化
#         self.max2=torch.nn.MaxPool2d(kernel_size=2)
#         # #第三个隐藏层:
#         # self.cnn3=torch.nn.Conv2d(in_channels=6,out_channels=12,kernel_size=3)
#         # #激活函数,这里选择Relu
#         # self.relu3=torch.nn.ReLU()
#         # #池化层,最大池化
#         # self.max3=torch.nn.MaxPool2d(kernel_size=2)
#         #输出层
#         self.linear4=torch.nn.Linear(6*54*54,2)
#         # 激活函数
#         self.softmax=torch.nn.LogSoftmax()
#     #前向传播
#     def forward(self,x):
#         #前向传播
#         x=self.cnn1(x)
#         x=self.relu1(x)
#         x=self.max1(x)
#         #--------------------
#         x=self.cnn2(x)
#         x=self.relu2(x)
#         x=self.max2(x)
#         #------------------------
#         # x=self.cnn3(x)
#         # x=self.relu3(x)
#         # x=self.max3(x)
#         #------------------------
#         # print('----------------')
#         # print(x.shape)
#         # print('----------------')
#         x=torch.reshape(x,(x.shape[0],-1))
#         x=self.linear4(x)
#         x=self.softmax(x)#最后输出的数值我们需要利用到独热编码的思想
#         #上面的这些都可以这几使用x=self.model(x)来代替,为什么能用它,我的理解是,我们继承的class moudle 然后对立面写好的模型框架进行定义,而这个方法就是可以直接调用我们定义好的神经网络
#         return x
#建立我们的神经网络对象
model=VGG16()
# #定义损失函数
critimizer=torch.nn.CrossEntropyLoss()
#定义优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.001,momentum=0.9)
epochs=6
#每轮抽取次数的和
a=0
loss_=[]
a_=[]
font = font_manager.FontProperties(fname="C:\\Users\\ASUS\\Desktop\\Fonts\\STZHONGS.TTF")
# #开始预测
example=enumerate(testLoad)#从测试集里面随机抽64份并且记录下来里面的内容和下标
batch_index,(imagess,labelss)=next(example)
# bath_index=0
# imagess=0
# labelss=0
# for i,j in example:
#     bath_index=i
#     print(j)# (imagess, labelss)=j
score_=[]
for i in range(epochs):# 损失值参数sumloss = 0for imges,labels in trainload:a+=1#前向传播# print('imges.shape:',imges.shape)output=model(imges)#反向传播loss=critimizer(output,labels)loss.backward()#参数更新optimizer.step()#梯度清零optimizer.zero_grad()#损失累加sumloss+=loss.item()loss_.append(sumloss)a_.append(a)print(f"第{i+1}轮的损失:{sumloss},抽取次数和:{a}")print('正确率---------------------')labelss_ = labelss.numpy()pre_ = []for i in range(39 * 2):sample_ = torch.unsqueeze(imagess[i], dim=0)  # 升维度加1# print(a.shape)pre = model(sample_)  # 预测# 第一张图片对应的pre得格式:# 接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0pro = list(pre.detach().numpy()[0])pre_label = pro.index(max(pro))pre_.append(pre_label)# print(pre_label)pre_ = np.array(pre_)sore = accuracy_score(labelss_, pre_)score_.append(sore)print('准确率:', sore)plt.figure()
plt.plot(a_, score_)
plt.title('准确率随着抽取总次数得变化情况:', fontproperties=font, fontsize=18)
plt.xlabel('抽取总次数', fontproperties=font, fontsize=18)
plt.ylabel('准确率', fontproperties=font, fontsize=18)
plt.legend(prop=font)
plt.show()plt.figure()
plt.plot(a_,loss_)
plt.title('损失值随着抽取总次数得变化情况:',fontproperties=font, fontsize=18)
plt.show()
#预测画图------------------------
fig=plt.figure()
for i in range(16):# print(imagess[i])# print(imagess[i].shape)a=torch.unsqueeze(imagess[i],dim=0)    #升维度加1# print('a.shape:',a.shape)pre=model(a)#预测#第一张图片对应的pre得格式:#接下来我们要用到独热编码的思想,我们取最大的数,也就是最高的概率对应得下标,就相当于这个最高概率对应得独热编码里面的1,其他是0# print(pre)pro = list(pre.detach().numpy()[0])pre_label=pro.index(max(pro))# print(pre_label)dict_={0:'猫',1:"狗"}#图像显示img=torch.squeeze(a)        #去掉维度中的一个‘1’,大小变成3*224*224 需要转换img_=img.permute(1,-1 , 0)                   #224*224*3这个我们的图像才可以显示imge=img_.numpy()# print(img_.shape)# print(img_)plt.subplot(4,4,i+1)plt.tight_layout()plt.imshow(imge,cmap='gray',interpolation='none')plt.title(f"预测值:{dict_[pre_label]}",fontproperties=font, fontsize=9)plt.xticks([])plt.yticks([])
plt.show()

ResNet18 

推荐看这篇博客。

ResNet-18超详细介绍!!!!_resnet18-CSDN博客

代码

print('-------------------------------ResNet18-------------------------------')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from sklearn.metrics import accuracy_score
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
from PIL import Image
import torch.nn.functional  as F
import os
class CommonBlock(torch.nn.Module):def __init__(self,in_channel,out_channel,stride):super(CommonBlock,self).__init__()self.conv1=torch.nn.Conv2d(in_channel,out_channel,kernel_size=3,stride=stride,bias=False)self.bn1=torch.nn.BatchNorm2d(out_channel)#添加BatchNorm2d进行数据的归一化处理,这使得数据在进行Relu之前不会因为数据过大而导致网络性能的不稳定self.conv2 = torch.nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride,bias=False)self.bn2=torch.nn.BatchNorm2d(out_channel)def forward(self,x):identity=xx=F.relu(self.bn1(self.conv1(x)),inplace=True)x=self.bn2(self.conv2(x))x+=identityreturn F.relu(x,inplace=True)class SpecialBlock(torch.nn.Module):def __init__(self, in_channel, out_channel, stride):super(SpecialBlock, self).__init__()self.change_channel=torch.nn.Sequential(torch.nn.Conv2d(in_channel,out_channel,kernel_size=1,stride=stride[0],padding=0,bias=False),torch.nn.BatchNorm2d(out_channel))self.conv1 = torch.nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride[0],padding=1,bias=False)self.bn1 = torch.nn.BatchNorm2d(out_channel)  # 添加BatchNorm2d进行数据的归一化处理,这使得数据在进行Relu之前不会因为数据过大而导致网络性能的不稳定self.conv2 = torch.nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride[1],padding=1,bias=False)self.bn2 = torch.nn.BatchNorm2d(out_channel)def forward(self, x):identity = self.change_channel(x)x = F.relu(self.bn1(self.conv1(x)), inplace=True)x = self.bn2(self.conv2(x))x += identityreturn F.relu(x, inplace=True)class ResNet18(torch.nn.Module):def __init__(self,classes_num):super(ResNet18).__init__()#定义网络模块self.prepare=torch.nn.Sequential(torch.nn.Conv2d(3,64,7,2,3),torch.nn.BatchNorm2d(64),#Batch Normanlization简称BN,也就是数据归一化torch.nn.ReLU(inplace=True),torch.nn.MaxPool2d(3,2,1))self.layer1=torch.nn.Sequential(CommonBlock(64,64,1),CommonBlock(64,64,1))self.layer2=torch.nn.Sequential(SpecialBlock(64,128,[2,1]),CommonBlock(128,128,1))self.layer3 = torch.nn.Sequential(SpecialBlock(128, 256, [2, 1]),CommonBlock(256, 256, 1))self.layer4 = torch.nn.Sequential(SpecialBlock(256, 512, [2, 1]),CommonBlock(512, 512, 1))self.pool=torch.nn.AdaptiveAvgPool2d(output_size=(1,1))self.fc=torch.nn.Sequential(# torch.nn.Dropout(p=0.5),# torch.nn.Linear(512,256),# torch.nn.ReLU(inplace=True),# torch.nn.Dropout(p=0.25),torch.nn.Linear(256,classes_num))def forward(self,x):x=self.prepare(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x=self.pool(x)x=x.reshape(x.shape[0],-1)x=self.fc(x)return x

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

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

相关文章

Fannel和Calico

一 1、路由器下面每一个端口都是一个vlan,隔离了广播包 192.168.1.0和192.168.2.0他们属于不同的vlan,没有三层交换机或者路由器,他们通不了信 不在同一个vlan,也就是子网,包就会走向网关(也就是路由器那里,路由器有路由表。查看目的地192.168.2.0在b口,从b口出去vlan…

互联网技术知识点总览——算法和数据结构

简介 本文对算法和数据结构的知识点整体框架进行梳理和分享如下&#xff1a;

Ubuntu无法安装向日癸15.2.0.63062_amd64.deb最新版

Ubuntu安装向日葵远程控制 安装包下载 安装方式 方式一&#xff1a;运行安装包安装 方式二&#xff1a;终端命令安装 通过以下教程可以快速的安装向日葵远程控制&#xff0c;本教程适用于Ubuntu18.04/20.04/22.04 安装包下载 进入向日葵远程控制下载官网下载向日葵远程控制Lin…

黑马程序员Linux简单入门学习笔记

Linux介绍 内核提供系统最核心的功能&#xff0c;如: 调度CPU、调度内存、调度文件系统、调度网络通讯、调度等系统级应用程序&#xff0c;可以理解为出厂自带程序&#xff0c;可供用户快速上手操作系统&#xff0c;如:文件管理器、任务管理器、图片查看、音乐播放等 目录结构 …

深度学习--CNN卷积神经网络(附图)

框架 让我们先看一下CNN的框架 卷积层中后是ReLu激活函数 &#xff0c;然后是深化池&#xff0c;之后是全连接&#xff0c;最后进行Softmax进行归一化。 所以&#xff0c;我们先逐一了解一下它们各个部分 全连接层 全连接层也称感知机&#xff0c;BP神经网络 全连接层&…

seatable部署之后network error【seatable】

这里写自定义目录标题 问题汇总 问题汇总 seatable服务部署后&#xff0c;组件显示正常运行&#xff0c;创建表单&#xff0c;显示Network error 点击错误信息&#xff0c;查看其跳转至另一个页面

AI大模型探索之路-实战篇1:基于OpenAI智能翻译助手实战落地

文章目录 前言一、需求规格描述二、系统架构设计三、技术实施方案四、核心功能说明五、开源技术选型六、代码实现细节1.图形用户界面&#xff08;GUI&#xff09;的开发2.大型模型调用的模块化封装3.文档解析翻译结果处理 总结 前言 在全球化的浪潮中&#xff0c;语言翻译需求…

节点加密技术:保障数据传输安全的新利器

随着信息技术的快速发展&#xff0c;网络数据的安全传输问题日益凸显。节点加密技术作为一种新兴的加密手段&#xff0c;正逐渐成为保障数据传输安全的重要工具。本文将探讨节点加密技术的原理、应用及其优势&#xff0c;并分析其未来的发展趋势。 节点加密技术的原理 节点加密…

(OSKS)代币:狂热的Meme币投资者指南

你那位对加密货币几乎一窍不通的朋友却是富豪。为什么&#xff1f;因为他们买了一枚硬币&#xff0c;上面有一只戴着帽子的狗。 帽子一直戴着&#xff0c;所以价格一直在上涨。该Meme币即将成为拉斯维加斯球体的主流&#xff0c;这要归功于社区筹集了 650,000 美元的酷炫资金来…

Redis集合[持续更新]

Redis&#xff08;全称&#xff1a;Remote Dictionary Server 远程字典服务&#xff09;是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库&#xff0c;并提供多种语言的 API。 数据结构 1. string 字符串 字符串类型是 Redis 最…

Unity实现动态数字变化

最近的项目需要动态显示数字&#xff0c;所以使用Text组件&#xff0c;将数字进行变化操作过程记录下来。 一、UI准备 1、新建一个Text组件 2、新建C#脚本 3、将Text挂载到脚本上 二、函数说明 1、NumberChange 方法 NumberChange 方法接收四个参数&#xff1a;初始数字 in…

项目管理-项目范围管理

目录 一、概述 二、范围计划的编制 2.1 项目中包含的范围 2.1.1 产品范围 2.1.2 工作范围 2.1.3 总结 2.2 范围计划编制的成果 2.2.1 范围管理计划 2.2.1.1 概述 2.2.1.2 内容 三、创建工作分解结构 3.1 概述 3.2 WBS目的和用途 3.3 WBS分层结构 3.3.1 分层结构图…

【云计算】云数据中心网络(六):私网连接

《云网络》系列&#xff0c;共包含以下文章&#xff1a; 云网络是未来的网络基础设施云网络产品体系概述云数据中心网络&#xff08;一&#xff09;&#xff1a;VPC云数据中心网络&#xff08;二&#xff09;&#xff1a;弹性公网 IP云数据中心网络&#xff08;三&#xff09;…

网络安全产品---扛DDOS产品

DDOS攻击 what 分布式拒绝服务攻击&#xff08;Distributed Denial of Service attack&#xff09; how 攻击者通过控制大量的网络设备&#xff08;傀儡机&#xff09;&#xff0c;向攻击目标&#xff08;例如网站、Web服务器、网络设备等&#xff09;发出海量的、但并不是…

SQLite R*Tree 模块(三十三)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite FTS3 和 FTS4 扩展(三十二) 下一篇:SQLite轻量级会话扩展&#xff08;三十四&#xff09; 1. 概述 R-Tree 是一个特殊的 专为执行范围查询而设计的索引。R-树最常见的是 用于地理空间系统&#xff0c;其中…

前端三剑客 HTML+CSS+JavaScript ① 基础入门

光永远会照亮你 —— 24.4.18 一、C/S架构和B/S架构 C:Client&#xff08;客户端&#xff09; B:Browser&#xff08;浏览器&#xff09; S:Server&#xff08;服务器&#xff09; C/S 架构&#xff1a; B/S 架构&#xff1a; 大型专业应用、安全性要求较高的应用&#xff0c;还…

binary tree Leetcode 二叉树算法题

144.二叉树的前序遍历 前序遍历是&#xff1a;根-左-右 所以记录序列的的时候放在最前面 递归 class Solution {List<Integer> ans new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {if(root null) return ans;ans.add(root…

【HCIP】OSPF的高级特性

OSPF的高级特性1 --- 不规则区域 一、OSPF不规则区域类型 产生原因&#xff1a;区域划分不合理&#xff0c;导致的问题 1、非骨干区域无法和骨干区域保持连通 2、骨干区域被分割 造成后果&#xff1a;非骨干区域没和骨干区域相连&#xff0c;导致ABR将不会帮忙转发区域间的路由…

【数据结构练习题】堆——top-k问题

♥♥♥♥♥个人主页♥♥♥♥♥ ♥♥♥♥♥数据结构练习题总结专栏♥♥♥♥♥ ♥♥♥♥♥上一章&#xff1a;【数据结构练习题】二叉树(1)——1.相同的树2.另一颗树的子树3.翻转二叉树4.平衡二叉树5.对称二叉树♥♥♥♥♥ 文章目录 1.top-k问题1.1问题描述1.2思路分析1.3绘图分析…

理光打印机设置扫描文件到共享文件夹教程(线上和现场)

在线设置。 1.点击用户工具/计数器按钮。 2.点击系统设置。 3.点击端口设置&#xff0c;点击机器IPV4地址。 4.获得打印机IP地址。 5.回到共享电脑&#xff0c;新建一个账户或者使用当前账户&#xff0c;为了隐私安全起见&#xff0c;最好设置密码。 6.关闭防火墙。 7.启用…