第七课目录

  • 图像分类基础
    • 卷积神经网络
    • Pooling layer
    • BatchNormalization
      • BatchNormalization与归一化
      • torch.nn.BatchNorm2d
  • MNIST图像分类
    • 加载MNIST并进行标准化
    • 模型定义
    • 使用dataloader
    • 训练与测试
  • FashionMNIST图像分类
    • 初步认识FashionMNIST
    • 完成图像分类任务

图像分类基础

图像分类应该属于计算机视觉的基本任务,在计算机视觉中,广泛使用卷积神经网络捕捉特征;CNN在第六课中已经进行过描述,但在这里,还是再复习一下;

卷积神经网络

parameters:
in_channels (int) – 输入张量的通道数
out_channels (int) – 输出张量的通道数
kernel_size (int or tuple) – kernel的尺寸
stride (int or tuple, optional) – 卷积的步长,默认为1
padding (int or tuple, optional) – Zero-padding added to both sides of the input.Default:0shape:
Input:[N,C_in,H_in,W_in]
Output:[N,C_out,H_out,W_out]

其中,HHH和WWW的计算满足:
Hout=Hin+2padding[0]−kernel[0]stride[0]+1H_{out}=\frac{H_{in}+2padding[0]-kernel[0]}{stride[0]}+1Hout​=stride[0]Hin​+2padding[0]−kernel[0]​+1
Wout=Win+2padding[1]−kernel[1]stride[1]+1W_{out}=\frac{W_{in}+2padding[1]-kernel[1]}{stride[1]}+1Wout​=stride[1]Win​+2padding[1]−kernel[1]​+1
一个卷积层包含多个filter,每个filter的kernel数量等于输入张量的通道数,输出张量的通道数量就是filter的个数,一个filter中的各个kernel是不同的;
可以理解为不同的filter提取不同的局部特征,filter内的kernel不同是为了获取输入张量上不同通道的局部信息,最后加和得到该filter对应的局部特征相似度;
卷积的过程如下:

输入张量(红色)中kernel_size大小的区域被卷积后成为输出张量(蓝色)的一个向量,容易看出,卷积层有5个filter,每个filter有3个kernel;
通过上图容易发现,卷积神经网络其实相当于不同的全连接网络组成一组滤波器(全连接网络不附带激活函数),作用在输入张量的局部特征上,这些局部特征计算得到的张量再组合成为新的张量:

上图中,int(height)×int(width)int(height)\times int(width)int(height)×int(width)就是上一层输入张量(蓝色)的局部特征个数,int(depth)int(depth)int(depth)就是全连接网络的个数,每个全连接网络的输出为1个值(最后一层只有一个神经元);

Pooling layer

计算机视觉任务中,Pooling layer一般就是Pool2d,用于对局部特征求最大或者求平均,比如这是一个MaxPool2d:

容易发现,Pool2d和Conv2d很相似,只是不改变通道数,因为pooling操作的对象是通道维度后的张量;
HHH和WWW的计算同样满足:
Hout=Hin+2padding[0]−kernel[0]stride[0]+1H_{out}=\frac{H_{in}+2padding[0]-kernel[0]}{stride[0]}+1Hout​=stride[0]Hin​+2padding[0]−kernel[0]​+1
Wout=Win+2padding[1]−kernel[1]stride[1]+1W_{out}=\frac{W_{in}+2padding[1]-kernel[1]}{stride[1]}+1Wout​=stride[1]Win​+2padding[1]−kernel[1]​+1

BatchNormalization

在计算机视觉任务中,常常会用到BatchNormalization,即对一个batch的数据进行标准化;
首先要对一个batch的数据求平均和方差,均值和方差按批次的维度(轴)计算;
假设现在获得一个mini-batch的张量(m,∗)(m,*)(m,∗)为:
{x1,x2,...,xm}\left \{ x_{1},x_{2},...,x_{m} \right \}{x1​,x2​,...,xm​}
*代表任意的size,比如(channel,height,width)(channel,height,width)(channel,height,width),这个batch共mmm个张量,xix_{i}xi​就是一个张量(channel,height,width)(channel,height,width)(channel,height,width)简写为(c,h,w)(c,h,w)(c,h,w);
计算均值有:
μ=1m∑i=1mxi\mu =\frac{1}{m}\sum_{i=1}^{m}x_{i}μ=m1​i=1∑m​xi​
均值μ\muμ的形状为(c,h,w)(c,h,w)(c,h,w);
方差(variance)为:
σ2=1m∑i=1m(xi−μ)2\sigma ^{2}=\frac{1}{m}\sum_{i=1}^{m}(x_{i}-\mu )^{2}σ2=m1​i=1∑m​(xi​−μ)2
方差σ2\sigma^{2}σ2的形状为(c,h,w)(c,h,w)(c,h,w);
现在可以对数据进行标准化为:
xi^=xi−μσ2+ε\widehat{x_{i}}=\frac{x_{i}-\mu }{\sqrt{\sigma ^{2}+\varepsilon }}xi​​=σ2+ε​xi​−μ​
注意到ε\varepsilonε,这是一个很小的数,一般取1e-5,目的是为了防止σ=0\sigma=0σ=0时除法出错;标准化后的数据被收缩到以0为中心,以1为标准差的正态分布上,这是有利于训练的,因为当数据分布变得简单与相似,模型的参数也就不需要很复杂;所以BatchNormalization一定程度上可以避免过拟合;
每当网络使用到一层BatchNormalization时,可能会需要学习两个参数γ,β\gamma ,\betaγ,β,这两个参数是两个向量(每个向量有channle个元素),得到张量为:
{y1,y2,...,ym}\left \{ y_{1},y_{2},...,y_{m} \right \}{y1​,y2​,...,ym​}
即:
{yi=BNγ,β(xi)=γxi^+β}\left \{ y_{i}=BN_{\gamma ,\beta}(x_{i})=\gamma \widehat{x_{i}}+\beta \right \}{yi​=BNγ,β​(xi​)=γxi​​+β}
理论上可以直接使用标准化后的张量xi^\widehat{x_{i}}xi​​作为yiy_{i}yi​,但进行适当的特征缩放与平移后,张量的值会变得有利于网络的计算;

BatchNormalization与归一化

BatchNormalization与归一化是两个不同的操作,回顾BatchNormalization,它会先沿着batch轴方向计算均值(c,h,w)(c,h,w)(c,h,w)和方差(c,h,w)(c,h,w)(c,h,w),再利用均值和方差对这个batch的数据进行标准化,最后对这组数据进行尺度缩放与平移(基于两个向量γ,β\gamma ,\betaγ,β);
两个待学习参数的向量展开表示为:
γ={γ1,γ2,...,γc}\gamma=\left \{\gamma _{1},\gamma_{2},...,\gamma_{c} \right \}γ={γ1​,γ2​,...,γc​}
β={β1,β2,...,βc}\beta=\left \{\beta _{1},\beta_{2},...,\beta_{c} \right \}β={β1​,β2​,...,βc​}
归一化一般是指不同特征之间分别进行尺度缩放,比如数据有2个特征f1f_{1}f1​:数值在0到2000,和f2f_{2}f2​ :数值在0到5,为了便于计算,会使用f1/2000f_{1}/2000f1​/2000和f2/5f_{2}/5f2​/5作为新的两个特征(两个特征值都在0到1之间)

torch.nn.BatchNorm2d

在pytorch中,一般会使用BatchNorm2d去完成计算机视觉的模型,BatchNorm2d常用到两个参数:

torch.nn.BatchNorm2d(num_features, eps=1e-05)num_features 输入张量的通道数
eps 为了除法的数值稳定(避免直接除以0方差出错),默认1e-5

注意,训练时,均值和方差是沿着batch轴计算的,但在测试时,均值和方差会沿着整个训练数据集得出,然后再标准化;所以,BatchNorm2d还有两个对象,一个保存不同通道的均值,一个保存不同通道的方差;
为了节省显存,不管是训练还是测试,均值和方差都会从理论上的(c,h,w)(c,h,w)(c,h,w)再平均到(c)(c)(c),即每个通道的二维均值张量和二维方差张量会计算平均,变成一个通道只有一个均值和方差:

import torch
import torch.nn as nn# 3通道
bn=nn.BatchNorm2d(num_features=3)
print(bn.state_dict())x=torch.randn(2,3,4,4)
y=bn(x)
print(bn.state_dict())
"""
OrderedDict([('weight', tensor([0.1341, 0.3598, 0.5994])), ('bias', tensor([0., 0., 0.])), ('running_mean', tensor([0., 0., 0.])), ('running_var', tensor([1., 1., 1.]))])
OrderedDict([('weight', tensor([0.1341, 0.3598, 0.5994])), ('bias', tensor([0., 0., 0.])), ('running_mean', tensor([ 0.0171, -0.0172,  0.0395])), ('running_var', tensor([0.9901, 1.0059, 1.0156]))])
"""

MNIST图像分类

MNIST数据集包含一组 60000 个示例的训练集和 10000 个示例的测试集。它是NIST提供的较大集的子集。数字图像已做了大小规范化,以固定大小的图像居中。
对于想要尝试实际数据学习技术和模式识别方法,同时在预处理和格式化上花费最少时间的人,它是一个很好的数据集:MNIST地址

加载MNIST并进行标准化

首先导入pytorch:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optimUSE_CUDA=torch.cuda.is_available()
BATCH_SIZE=32device=torch.device("cuda" if USE_CUDA else "cpu")

在之前的自然语言处理任务中,常会用到torchtext处理数据;类似的,在计算机视觉任务里,也必不可少的出现了为pytorch定制的数据处理工具torchvision:

# 适用于pytorch处理CV数据的库:torchvision
import torchvision
# transforms用于对图像提供基本处理
from torchvision import datasets,transforms

获取数据集并加载训练数据:

# 加载数据集mnist
mnistdata=datasets.MNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=True,#如果路径下没有,就从官网下载)
mnistdata
"""
Dataset MNISTNumber of datapoints: 60000Split: trainRoot Location: ./DataSetTransforms (if any): NoneTarget Transforms (if any): None
"""# mnistdata[i]有两个对象,第一个代表图片本身,第二个代表图片所属类别
mnistdata[0]
#(<PIL.Image.Image image mode=L size=28x28 at 0x7EFE825DD198>, 5)


需要注意,现在的mnist像素值在0到255,我也可以计算整个训练集"所有像素"的均值和方差(仅为1个值,不要和BatchNormalization中的计算混淆):

# 标准化输入图片前,需要知道均值和方差
import numpy as np# data为图片组成的列表
data=[np.array(d[0]).reshape(1,28,28) for d in mnistdata]print(len(data))
print(np.mean(data))
print(np.std(data))#需要注意,现在的mnist像素值在0到255
"""
60000
33.318421449829934
78.56748998339798
"""

如果在加载同时,使用transforms有:

# 实验需要transform对图片做处理,所以重新加载数据集(导入同时进行处理)
mnistdata=datasets.MNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=False,#即使没有数据集也不下载# Compose可以将不同的transforms操作组合起来transform=transforms.Compose([transforms.ToTensor(),#将图像转为张量]))print(mnistdata[0][0])
"""
容易看出,使用了transforms后,数据自动归一化了,即要想让值正确被标准化,就不能使用之前得到的均值和标准差:
33.318421449829934
78.56748998339798
而应该使用归一化后的均值和标准差进行标准化
"""

容易看出,使用了transforms后,数据自动归一化了,即要想让值正确被标准化,就不能使用之前得到的均值和标准差:
33.318421449829934
78.56748998339798


注意这里可以用"整个数据集所有像素"的均值和方差进行标准化是因为图像是单通道的


而应该使用归一化后的均值和标准差进行标准化:

#查看归一化后的均值和方差
data=[d[0].data.cpu().numpy() for d in mnistdata]print(len(data))
print(np.mean(data))
print(np.std(data))
"""
60000
0.13066062
0.30810776
"""

重新加载进行标准化处理的数据集:

# 重新加载进行标准化处理的数据集
mnistdata=datasets.MNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=False,#即使没有数据集也不下载# Compose可以将不同的transforms操作组合起来transform=transforms.Compose([transforms.ToTensor(),#将图像转为张量# 标准化 Normalize(mean, std, inplace=False)# Given mean: ``(M1,...,Mn)`` and std: ``(S1,..,Sn)`` for ``n`` channelstransforms.Normalize((0.1307,),(0.3081,))]))print(mnistdata[0][0].size())#验证一下标准化的结果
data=[d[0].data.cpu().numpy() for d in mnistdata]print(len(data))
print(np.mean(data))
print(np.std(data))"""
torch.Size([1, 28, 28])
60000
-0.00012829367
1.0000249
"""

模型定义

模型定义如下:

"""
Conv2d
parameters:
in_channels (int) – 输入张量的通道数
out_channels (int) – 输出张量的通道数
kernel_size (int or tuple) – kernel的尺寸
stride (int or tuple, optional) – 卷积的步长,默认为1
padding (int or tuple, optional) – Zero-padding added to both sides of the input.Default:0shape:
Input:[N,C_in,H_in,W_in]
Output:[N,C_out,H_out,W_out]out[i]=(in[i]+2*p[i]-kernel[i])/stride[i]+1
"""#定义模型
class CNN(nn.Module):def __init__(self):super().__init__()self.conv1=nn.Conv2d(1,20,5,1)self.conv2=nn.Conv2d(20,50,5,1)self.fc1=nn.Linear(4*4*50,500)self.fc2=nn.Linear(500,10)def forward(self,x):# x: [batch_size,1,28,28]x=F.relu(self.conv1(x)) # [batch_size,20,28-5+1=24,24] x=F.max_pool2d(x,kernel_size=2,stride=2)   # [batch_size,20,(24-2)/2+1=12,12]x=F.relu(self.conv2(x)) #[batch_size,50,12-5+1=8,8]x=F.max_pool2d(x,kernel_size=2,stride=2) #[batch_size,50,(8-2)/2+1=4,4]x=x.view(-1,4*4*50) # flatten [batch_size,4*4*50]x=F.relu(self.fc1(x)) # [batch_size,500]x=self.fc2(x) # [batch_size,10]# log_softmax不改变shapereturn F.log_softmax(x,dim=1) #在列轴方向操作 [batch_size,10]

log_softmax回顾pytorch记事本,log_softmax的输入输出张量shape相同,其本质就是对每个元素都计算log_softmax:
LogSoftmax(xi)=log(exp(xi)∑jexp(xj))LogSoftmax(x_{i})=log(\frac{exp(x_{i})}{\sum_{j}exp(x_{j})})LogSoftmax(xi​)=log(∑j​exp(xj​)exp(xi​)​)

使用dataloader

使用dataloader构造train_dataloader:

#使用dataloader构造train_dataloader
train_dataloader=torch.utils.data.DataLoader(mnistdata,batch_size=BATCH_SIZE,shuffle=True, #每个epoch打乱一次num_workers=1,pin_memory=True, # 提前把值布置到GPU上,某种程度上可以加速训练)

同理,构造test_dataloader:

# 同理,构造test_dataloader
test_dataloader=torch.utils.data.DataLoader(datasets.MNIST("./DataSet",train=False, #从test.pt获取数据download=False,                      transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])),batch_size=BATCH_SIZE,shuffle=True,num_workers=1,pin_memory=True,
)

训练与测试

实例化模型,并选择优化方法为结合动量更新的SGD:

LEARNING_RATE=1e-2
MOMENTUM=0.5model=CNN().to(device)optimizer=optim.SGD(model.parameters(),lr=LEARNING_RATE,momentum=MOMENTUM)

损失函数使用NLL loss,同样回顾pytorch记事本,定义训练与测试函数:

def train(model,device,train_dataloader,optimizer,epoch):model.train()for i,(data,target) in enumerate(train_dataloader):# target从0到9data,target=data.to(device),target.to(device)pred=model.forward(data) # [batch_size,10],而且每个元素已经是log(softmax)过# NLLloss :负对数似然损失loss=F.nll_loss(pred,target,reduction='mean')loss.backward()optimizer.step()model.zero_grad()if i%100==0:print("train epoch:{},iter:{},loss:{}".format(epoch,i,loss.item()))def test(model,device,test_dataloader):total_loss=0.0correct=0.0model.eval()with torch.no_grad():for i,(data,target) in enumerate(test_dataloader):# target的元素值从0到9# data为[batch_size,1,28,28] target [batch_size]data,target=data.to(device),target.to(device)pred=model.forward(data) # [batch_size,10],而且每个元素已经是log(softmax)过# NLLloss :负对数似然损失loss=F.nll_loss(pred,target,reduction='sum')total_loss+=loss.item()#索引到最大值的位置pred=pred.argmax(dim=1) # [batch_size]# 比较统计出分类正确的个数# x.view_as(other) 把x的size view至other的size # x.eq(y)->Tensor x与y逐个元素比较,相等为1,不等为0,所以返回张量的size和x或y的size一样correct+=pred.eq(target.view_as(pred)).sum().item()# test_dataloader.dataset有10000个数据total_loss/=len(test_dataloader.dataset)correct/=len(test_dataloader.dataset)print("test loss:{},accuracy:{}%".format(total_loss,correct*100))model.train()

训练并保存模型:

NUM_EPOCHS=2for epoch in range(NUM_EPOCHS):train(model,device,train_dataloader,optimizer,epoch)test(model,device,test_dataloader)torch.save(model.state_dict(),"mnistcnn.pth")

训练过程为:

train epoch:0,iter:0,loss:2.3189268112182617
train epoch:0,iter:100,loss:0.6662697792053223
train epoch:0,iter:200,loss:0.2979623079299927
train epoch:0,iter:300,loss:0.09481921792030334
train epoch:0,iter:400,loss:0.30337268114089966
train epoch:0,iter:500,loss:0.18740123510360718
train epoch:0,iter:600,loss:0.11033137142658234
train epoch:0,iter:700,loss:0.07353109121322632
train epoch:0,iter:800,loss:0.033268675208091736
train epoch:0,iter:900,loss:0.08645057678222656
train epoch:0,iter:1000,loss:0.11677625775337219
train epoch:0,iter:1100,loss:0.1111474335193634
train epoch:0,iter:1200,loss:0.2825027108192444
train epoch:0,iter:1300,loss:0.028150692582130432
train epoch:0,iter:1400,loss:0.00713057816028595
train epoch:0,iter:1500,loss:0.038987040519714355
train epoch:0,iter:1600,loss:0.048560887575149536
train epoch:0,iter:1700,loss:0.009530067443847656
train epoch:0,iter:1800,loss:0.04192616045475006
test loss:0.059446940588951114,accuracy:98.17%
train epoch:1,iter:0,loss:0.0873970091342926
train epoch:1,iter:100,loss:0.008814126253128052
train epoch:1,iter:200,loss:0.035313352942466736
train epoch:1,iter:300,loss:0.026842668652534485
train epoch:1,iter:400,loss:0.029370427131652832
train epoch:1,iter:500,loss:0.013188257813453674
train epoch:1,iter:600,loss:0.019715994596481323
train epoch:1,iter:700,loss:0.05217146873474121
train epoch:1,iter:800,loss:0.08963392674922943
train epoch:1,iter:900,loss:0.062028124928474426
train epoch:1,iter:1000,loss:0.05624012649059296
train epoch:1,iter:1100,loss:0.04770314693450928
train epoch:1,iter:1200,loss:0.016552984714508057
train epoch:1,iter:1300,loss:0.08976559340953827
train epoch:1,iter:1400,loss:0.04011422395706177
train epoch:1,iter:1500,loss:0.0032268762588500977
train epoch:1,iter:1600,loss:0.03296753764152527
train epoch:1,iter:1700,loss:0.005710721015930176
train epoch:1,iter:1800,loss:0.06353166699409485
test loss:0.04207099027633667,accuracy:98.68%

FashionMNIST图像分类

随着研究的深入,即使是纯正的算法实验,mnist已经不能满足难度,所以出现了fashion mnist:数据集地址

初步认识FashionMNIST

由于torchvision下的datasets提供了fashionMNIST的处理方法,所以只需要把之前的MNIST实验数据集改成FashionMNIST即可:

# 把MNIST改成FashionMNIST就行
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim# 适用于pytorch处理CV数据的库:torchvision
import torchvision
# transforms用于对图像提供基本处理
from torchvision import datasets,transformstorchvision.__version__# 加载数据集mnist
fashionmnistdata=datasets.FashionMNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=True,#如果路径下没有,就从官网下载)fashionmnistdata
"""
Dataset FashionMNISTNumber of datapoints: 60000Split: trainRoot Location: ./DataSetTransforms (if any): NoneTarget Transforms (if any): None
"""fashionmnistdata[9][0]

看到一只高跟鞋:

完成图像分类任务

根据MNIST分类的处理流程,可以复用代码去处理FashionMNIST:

# 把MNIST改成FashionMNIST就行
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np# 适用于pytorch处理CV数据的库:torchvision
import torchvision
# transforms用于对图像提供基本处理
from torchvision import datasets,transformsUSE_CUDA=torch.cuda.is_available()
BATCH_SIZE=32
device=torch.device("cuda" if USE_CUDA else "cpu")# 实验需要transform对图片做处理,所以重新加载数据集(导入同时进行处理)
mnistdata=datasets.FashionMNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=False,#即使没有数据集也不下载# Compose可以将不同的transforms操作组合起来transform=transforms.Compose([transforms.ToTensor(),#将图像转为张量]))#查看归一化后的均值和方差
data=[d[0].data.cpu().numpy() for d in mnistdata]print(len(data))
print(np.mean(data))
print(np.std(data))
"""
60000
0.2860402
0.3530239
"""# 重新加载进行标准化处理的数据集
mnistdata=datasets.FashionMNIST("./DataSet",train=True, #train为True,返回的数据为processed/training.pt#mnist的训练数据共6万张图片download=False,#即使没有数据集也不下载# Compose可以将不同的transforms操作组合起来transform=transforms.Compose([transforms.ToTensor(),#将图像转为张量# 标准化 Normalize(mean, std, inplace=False)# Given mean: ``(M1,...,Mn)`` and std: ``(S1,..,Sn)`` for ``n`` channelstransforms.Normalize((0.2860,),(0.3530,))]))print(mnistdata[0][0].size())
#验证一下标准化的结果
data=[d[0].data.cpu().numpy() for d in mnistdata]
print(len(data))
print(np.mean(data))
print(np.std(data))
"""
torch.Size([1, 28, 28])
60000
0.00011496393
1.0000685
"""#定义模型
class CNN(nn.Module):def __init__(self):super().__init__()self.conv1=nn.Conv2d(1,20,5,1)self.conv2=nn.Conv2d(20,50,5,1)self.fc1=nn.Linear(4*4*50,500)self.fc2=nn.Linear(500,10)def forward(self,x):# x: [batch_size,1,28,28]x=F.relu(self.conv1(x)) # [batch_size,20,28-5+1=24,24] x=F.max_pool2d(x,kernel_size=2,stride=2)   # [batch_size,20,(24-2)/2+1=12,12]x=F.relu(self.conv2(x)) #[batch_size,50,12-5+1=8,8]x=F.max_pool2d(x,kernel_size=2,stride=2) #[batch_size,50,(8-2)/2+1=4,4]x=x.view(-1,4*4*50) # flatten [batch_size,4*4*50]x=F.relu(self.fc1(x)) # [batch_size,500]x=self.fc2(x) # [batch_size,10]# log_softmax不改变shapereturn F.log_softmax(x,dim=1) #在列轴方向操作 [batch_size,10] USE_CUDA=torch.cuda.is_available()
BATCH_SIZE=32
device=torch.device("cuda" if USE_CUDA else "cpu")#使用dataloader构造train_dataloader
train_dataloader=torch.utils.data.DataLoader(mnistdata,batch_size=BATCH_SIZE,shuffle=True, #每个epoch打乱一次num_workers=1,pin_memory=True, # 提前把值布置到GPU上,某种程度上可以加速训练)
# 同理,构造test_dataloader
test_dataloader=torch.utils.data.DataLoader(datasets.FashionMNIST("./DataSet",train=False, #从test.pt获取数据download=False,                      transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.2860,),(0.3530,))])),batch_size=BATCH_SIZE,shuffle=True,num_workers=1,pin_memory=True,
)LEARNING_RATE=1e-2
MOMENTUM=0.5
model=CNN().to(device)
optimizer=optim.SGD(model.parameters(),lr=LEARNING_RATE,momentum=MOMENTUM)def train(model,device,train_dataloader,optimizer,epoch):model.train()for i,(data,target) in enumerate(train_dataloader):# target从0到9data,target=data.to(device),target.to(device)       pred=model.forward(data) # [batch_size,10],而且每个元素已经是log(softmax)过       # NLLloss :负对数似然损失loss=F.nll_loss(pred,target,reduction='mean')       loss.backward()       optimizer.step()       model.zero_grad()if i%100==0:print("train epoch:{},iter:{},loss:{}".format(epoch,i,loss.item()))def test(model,device,test_dataloader):total_loss=0.0correct=0.0model.eval()with torch.no_grad():for i,(data,target) in enumerate(test_dataloader):# target的元素值从0到9# data为[batch_size,1,28,28] target [batch_size]data,target=data.to(device),target.to(device)pred=model.forward(data) # [batch_size,10],而且每个元素已经是log(softmax)过# NLLloss :负对数似然损失loss=F.nll_loss(pred,target,reduction='sum')total_loss+=loss.item()#索引到最大值的位置pred=pred.argmax(dim=1) # [batch_size]# 比较统计出分类正确的个数# x.view_as(other) 把x的size view至other的size # x.eq(y)->Tensor x与y逐个元素比较,相等为1,不等为0,所以返回张量的size和x或y的size一样correct+=pred.eq(target.view_as(pred)).sum().item()            # test_dataloader.dataset有10000个数据total_loss/=len(test_dataloader.dataset)correct/=len(test_dataloader.dataset)    print("test loss:{},accuracy:{}%".format(total_loss,correct*100))model.train()NUM_EPOCHS=2
for epoch in range(NUM_EPOCHS):train(model,device,train_dataloader,optimizer,epoch)test(model,device,test_dataloader)
torch.save(model.state_dict(),"fashionmnistcnn.pth")

明显看出,同样的模型,同样的输入数据标准化方法,FashionMNIST的效果不如MNIST上的效果好,这也反映了FashionMNIST确实是一个训练快速且考验模型的优秀数据集:

train epoch:0,iter:0,loss:2.300595998764038
train epoch:0,iter:100,loss:0.9157668352127075
train epoch:0,iter:200,loss:0.9919059872627258
train epoch:0,iter:300,loss:0.4668219983577728
train epoch:0,iter:400,loss:0.6859469413757324
train epoch:0,iter:500,loss:0.5600563287734985
train epoch:0,iter:600,loss:0.4927268624305725
train epoch:0,iter:700,loss:0.31422850489616394
train epoch:0,iter:800,loss:0.6181213855743408
train epoch:0,iter:900,loss:0.5355464220046997
train epoch:0,iter:1000,loss:0.42539727687835693
train epoch:0,iter:1100,loss:0.6514754891395569
train epoch:0,iter:1200,loss:0.3070918619632721
train epoch:0,iter:1300,loss:0.5045261383056641
train epoch:0,iter:1400,loss:0.4136778712272644
train epoch:0,iter:1500,loss:0.4964996576309204
train epoch:0,iter:1600,loss:0.4898112714290619
train epoch:0,iter:1700,loss:0.4621049463748932
train epoch:0,iter:1800,loss:0.2887163460254669
test loss:0.4504015432357788,accuracy:83.8%
train epoch:1,iter:0,loss:0.65262371301651
train epoch:1,iter:100,loss:0.6052740216255188
train epoch:1,iter:200,loss:0.420048326253891
train epoch:1,iter:300,loss:0.3331279158592224
train epoch:1,iter:400,loss:0.5645015239715576
train epoch:1,iter:500,loss:0.5631495714187622
train epoch:1,iter:600,loss:0.39666175842285156
train epoch:1,iter:700,loss:0.40362614393234253
train epoch:1,iter:800,loss:0.3553037941455841
train epoch:1,iter:900,loss:0.4407092034816742
train epoch:1,iter:1000,loss:0.28769898414611816
train epoch:1,iter:1100,loss:0.3469170033931732
train epoch:1,iter:1200,loss:0.34690746665000916
train epoch:1,iter:1300,loss:0.27406278252601624
train epoch:1,iter:1400,loss:0.6393352746963501
train epoch:1,iter:1500,loss:0.29725462198257446
train epoch:1,iter:1600,loss:0.18399234116077423
train epoch:1,iter:1700,loss:0.3601799011230469
train epoch:1,iter:1800,loss:0.49094414710998535
test loss:0.37649406254291534,accuracy:86.38%

第七课.简单的图像分类(一)相关推荐

  1. 第八课.简单的图像分类(二)

    目录 常见的卷积神经网络架构 卷积网络的平移不变性 卷积网络的识别原理简述 卷积神经网络的缺陷 CNN的迁移学习 迁移学习简介 数据集 使用dataloader生成batch 设置超参数 使用data ...

  2. 初二计算机简单动画,浙教版八年级下册信息技术:第七课《简单的动画补间动画》教案...

    ID:10051834 分类: 全国 , 2019 资源大小:219KB 资料简介: 第七课<简单的动画补间动画> 课题 第六课  简单的动画补间动画 目标 1.通过设置舞台背景和角色,学 ...

  3. Coursera公开课笔记: 斯坦福大学机器学习第七课“正则化(Regularization)”

     Coursera公开课笔记: 斯坦福大学机器学习第七课"正则化(Regularization)" +13投票 斯坦福大学机器学习第七课"正则化"学习笔记, ...

  4. 《幸福就在你身边》第七课、工作着,快乐着【哈佛大学幸福课精华】

    一.开心工作 愚人向远方寻找快乐,智者则在身旁培养快乐. 泰戈尔在<人生的亲证>中写道:"我们的工作日不是我们的欢乐日--因此,我们要求节日,我们在自己的工作中不能找到节日,所以 ...

  5. Asp.Net Web API 2第七课——Web API异常处理

    Asp.Net Web API 2第七课--Web API异常处理 原文:Asp.Net Web API 2第七课--Web API异常处理 前言 阅读本文之前,您也可以到Asp.Net Web AP ...

  6. 【Cocos游戏实战】功夫小子第七课之游戏主功能场景逻辑功能和暂停功能场景的分析和实现...

    CSDN的markdown编辑器是吃屎了么! !.什么玩意.!写了一半写不了东西还全没了,搞个毛线! 本节课的视频教程地址是:第七课在此  假设本教程有帮助到您,希望您能点击进去观看一下,并且如今注冊 ...

  7. 第七课:每年白捡几百块,你要不要

    第七课:每年白捡几百块,你要不要 理财就是理生活.欢迎来到长投学堂小白理财训练营. 多数人有这么一大特点:爱装逼.人人都能听懂的东西,撑不起面子,就不叫高逼格. 举个例子,有一次我去一个饭店吃饭,饭店 ...

  8. Python学习,第七课(灵活使用Frame,让布局更舒适)

    Python学习第七课(让界面布局舒适,是一个长久的工作) 一入布局深似海,加一减一都很难 基础知识 尝试布局 尝试好布局,感受下元素带来的不同 改造主程序,细节还是要优化 细节优化,细枝末节的参数 ...

  9. 北大AI公开课第七课--AI赋能 智赢未来by科大讯飞胡郁

    今天来打卡英语流利说第三天,希望自己可以坚持下去,说实话,一直以来我都挺喜欢英语的,然后从大一开始,也在网易公开课上听了很多世界名校的计算机专业课.金融.心理学方面的课,感觉对于语感的培养还是很不错的 ...

最新文章

  1. python能做软件吗-python能够做软件的自动化测试吗?
  2. android apk反编译工具下载,Android apk反编译工具下载与使用
  3. 服务器线程数一直增加,.NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长...
  4. PHP 设计模式 笔记与总结(3)SPL 标准库
  5. Ubuntu 磁盘自动挂载解决
  6. eclipse安装教程2020版(解决官网下载的安装包打开无响应的问题)
  7. IXI数据预处理 + Linux + freesurfer
  8. 使用ul li 实现图片的左右滚动
  9. 环卫工人的福音,电动扫地车。
  10. PC微信3.7.0将本地文件从MsgAttach文件夹转移回原先的File文件夹
  11. 食物链(带权并查集)
  12. 超市积分管理系统(论文+源码)
  13. 论文FirmAFL固件模糊测试工具——复现之路
  14. 软件测试压力测试例子,第一个web压力测试例子 - 稻香老农 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  15. U8到货拒收单API接口示例(参照采购到货)
  16. endnote把参考文献控制插入到想要的地方
  17. 神器 logging,你真的了解吗?
  18. PDMan使用问题记录
  19. Python解决数学难题:囚徒存活的概率 ‘‘‘
  20. 达梦数据库项目 SpringBoot + jpa + DM8

热门文章

  1. GIT_忽略文件和属性文件配置
  2. 修正版 | QPS过万,Redis大量连接超时怎么解决?
  3. 百亿级数据分表后怎么分页查询?
  4. 深入理解 Spring Cloud 核心组件与底层原理!
  5. JAVA面试解析(有赞二面)
  6. 来翻翻百度的老底:当年你是怎么赢的谷歌?
  7. Scrum敏捷看板工具leangoo-销售流程管理
  8. JSP中EL表达式失效的问题
  9. Control~Kalman filter
  10. 利用PCA进行数据降维