Pytorch学习笔记

Pytorch学习笔记

  • 学习视频:[B站up主:我是土堆]
  • 一、help和dir指令
  • 二、Pytorch加载数据
  • 三、TensorBoard的使用
    • 1. add_scalar()的使用
    • 2. add_image()的使用
  • 四、Transforms的使用
    • 1. Transforms中的Compose类
    • 2. Transforms中的ToTensor类
    • 3. Transforms中的Normalize类
    • 4. Transforms中的Resize类
      • 4.1 结合前面的compose
    • 5. Transforms中的RandomCrop类
    • 6. python知识点: _ _ call_ _函数
    • 7. 总结知识点
  • 五、torchvision中的数据集使用
    • 1. 数据集的下载
    • 2. CIFAR-10 dataset的下载
      • 2.1 CIFAR-10数据集介绍
  • 六、DataLoader的使用
    • 1. dataset类和datalodar的关系
    • 2.Dataloader官方介绍
    • 3.代码实例
  • 七、神经网络的基本骨架-nn.Module的使用
    • 7.1 官方文档介绍
    • 7.2 代码实例
  • 八、卷积层(Convolution Layers)
    • 8.1 torch.nn.function.conv2d官方介绍
    • 8.2 代码实例
    • 8.3 torch.nn.Conv2d官方介绍
    • 8.4 代码实例
  • 九、最大池化的使用
    • 9.1 MaxPool2d官方介绍
    • 9.2 代码实例
    • 9.3 最大池化的直观感受
  • 十、非线性激活
    • 10.1 线性激活官方介绍
    • 10.2 代码实例
  • 十一、线性层介绍
  • 十二、搭建CIFAR-10网络模型
    • 12.1 不使用Sequential
    • 12.2 使用Sequential
    • 12.3 模型的可视化
  • 十三、损失函数与反向传播
    • 13.1 官方文档介绍
      • 13.1.1 L1Loss
      • 13.1.2 MSELoss
      • 13.1.3 CrossEntropyLoss
    • 13.2 为CIFAR-10网络模型添加损失函数
  • 十四、优化器
    • 14.1 官方文档介绍
    • 14.2 为CIFAR-10网络模型添加优化器
  • 十五、官网模型的加载(浅谈)
    • 15.1 官网介绍
    • 15.2 模型的使用与修改
  • 十六、网络模型的保存与读取
  • 十七、完整的模型训练套路
  • 十八、使用CPU训练
    • 18.1 第一种方式
    • 18.2 第二种方式
    • 18.3 测试时注意事项

学习视频:[B站up主:我是土堆]

一、help和dir指令

p y t o r c h pytorch pytorch可以看作一个工作箱,里面有很多的小格子装有不同的工具。
可以使用 d i r ( ) dir() dir()指令来查看这个工作箱里面有哪些分格区:
Pytorch学习笔记_第1张图片
想要继续探索这个工具箱第一个分格区装了哪些工具,继续使用 d i r ( ) dir() dir()指令:
Pytorch学习笔记_第2张图片
想知道这个分格区的第二个工具的作用,使用 h e l p ( ) help() help()指令:
Pytorch学习笔记_第3张图片

二、Pytorch加载数据

  • D a t a s e t 类 Dataset类 Dataset
    提供一种方式去获取数据及其label

  • D a t a l o a d e r 类 Dataloader类 Dataloader
    为网络提供不同的数据形式

以图片数据为例子:

  • 仅读取一张图片可以使用 P I L . I m a g e PIL.Image PIL.Image
from PIL import Image
#图片路径
img_path = 'data\\train\\ants\\0013035.jpg'
#读取图片
img = Image.open(img_path)
#打印图片尺寸
print('尺寸:',img.size)
#展示图片
img.show()
  • 获取多个文件,需要使用 o s os os
import os
#数据所处文件夹
dir_path = 'data\\train\\ants'
#获取文件夹下文件的名字存于list数组中
img_path_list = os.listdir(dir_path)# 第一个列表元素指向文件夹第一个文件的名字

一、接下来读取一些数据(图片),文件名为数据集的 l a b e l label label
这里有很多蚂蚁和蜜蜂的图片,蚂蚁图片的路径是 d a t a / t r a i n / a n t s data/train/ants data/train/ants,蜜蜂图片的路径是 d a t a / t r a i n / b e e data/train/bee data/train/bee;图片上一层就是该图片集的 l a b e l label label

获取蚂蚁数据集

from PIL import Image
import os
from torch.utils.data import Dataset


class MyData(Dataset):
    '''
    需要重写Dataset的函数
    '''
    def __init__(self,root_dir,label_dir):
        '''
        初始化函数
        root_dir:根路径 如:data\\train
        label_dir:label 如:ants
        '''
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.path = os.path.join(self.root_dir,self.label_dir)#文件路径:data\\train\\ants 这个函数会自动加 /
        self.img_path = os.listdir(self.path)#文件下的图片名:['img_1.jpg',img_2.jpg,……]
        
    def __getitem__(self, index):
        '''
        根据索引读取文件
        index:索引值
        '''
        img_name = self.img_path[index]#获取图片名字
        img_item_path = os.path.join(self.root_dir,self.label_dir,img_name)#拼接成指向一个图片的详细地址
        img = Image.open(img_item_path)#获取这一张图片
        label = self.label_dir#获取图片的标签
        return img,label
    
    def __len__(self):
        '''
        数据长度
        '''
        return len(self.img_path)

读取数据:

root_dir = 'data/train'
ants_label_dir = 'ants'
ants_data = MyData(root_dir,ants_label_dir)

#获取第2个数据
img,label = ants_data[1]
img.show()
print(label)#ants

展示的图片
Pytorch学习笔记_第4张图片

获取蜜蜂数据集

bees_label_dir = 'bees'
bees_data = MyData(root_dir,bees_label_dir)

#获取第2个数据
img,label = bees_data[1]
img.show()

Pytorch学习笔记_第5张图片

获取训练集数据(train文件夹下的ants数据集+bees数据集):

train_data = ants_data + bees_data#将两个数据拼接在一起
#len(ants_data)=124 ,len(bees_data)=121, len(train_data)=245

img1,label1 = train_data[1]
img1.show()
img2,label2 = train_data[124]
img2.show()

img1展示:
Pytorch学习笔记_第6张图片
img2展示:
Pytorch学习笔记_第7张图片
即按顺序拼接

二、读取 l a b e l label label和图片分开放的数据集:
这里有很多蚂蚁和蜜蜂的图片,蚂蚁图片的路径是 d a t a / t r a i n / a n t s i m g e data/train/ants_imge data/train/antsimge,蜜蜂图片的路径是 d a t a / t r a i n / b e e s _ i m g e data/train/bees \_imge data/train/bees_imge d a t a / t r a i n / data/train/ data/train/下还存在两个文件夹: a n t s _ l a b e l ants \_label ants_label b e e s _ l a b e l bees \_label bees_label,这两个文件夹里面放的是txt文档,文档与图片一一对应,保存图片的label。

train文件夹:
Pytorch学习笔记_第8张图片
ants_image文件夹下:
Pytorch学习笔记_第9张图片
ants_label文件夹下:
Pytorch学习笔记_第10张图片
txt文档
Pytorch学习笔记_第11张图片

在原先的MyData类上进行修改即可

from PIL import Image
import os
from torch.utils.data import Dataset

class MyData(Dataset):
    '''
    需要重写Dataset的函数
    '''
    def __init__(self,root_dir,target_dir,label_dir):
        '''
        初始化函数
        root_dir:根路径 如:data\\train
        target_dir:数据所在文件名 如:ants_image
        label_dir:标签所在文件名 如:ants_label
        '''
        self.root_dir = root_dir
        self.target_dir = target_dir
        
        self.img_path = os.path.join(self.root_dir,self.target_dir)#目标数据所在路径:data\\train\\ants_image
        self.img_name_list = os.listdir(self.img_path)#文件下的图片名:['img_1.jpg',img_2.jpg,……]
        
        self.label_path = os.path.join(self.root_dir,label_dir)#标签所在路径:data\\train\\ants_label
        #标签文件名与图片文件名只有后缀不一样,不用读取
    def __getitem__(self, index):
        '''
        根据索引读取文件
        index:索引值
        '''
        img_name = self.img_name_list[index]#获取图片名字
        img_item_path = os.path.join(self.root_dir,self.target_dir,img_name)#拼接成指向一个图片的详细地址
        img = Image.open(img_item_path)#获取这一张图片
        
        label_name = img_name.split('.')[0] + '.txt' #获取图片的标签文件名
        label_item_path = os.path.join(self.root_dir,label_dir,label_name)#拼接成指向一个图片label的详细地址
        with open(label_item_path,'r') as f:
            label = f.read()
        return img,label
    
    def __len__(self):
        '''
        数据长度
        '''
        return len(self.img_path)

读取文件:

root_dir='data\\train'
target_dir='ants_image'
label_dir='ants_label'

ants_data = MyData(root_dir,target_dir,label_dir)
img,label = ants_data[0]

三、TensorBoard的使用

T e n s o r B o a r d TensorBoard TensorBoard作用:
记录日志信息并通过 t e n s o r b o a r d tensorboard tensorboard可视化

1. add_scalar()的使用

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('logs')#写到logs文件夹下

for i in range(100):
    writer.add_scalar(tag='y=x',scalar_value=i,global_step=i)

writer.close()
'''
add_scalar(self, tag, scalar_value, global_step=None, walltime=None):
-tag:可视化图像标题
scalar_value:y轴
global_step:x轴
'''

改用端口:
在pytorch环境下输入:
tensorboard --logdir=日志文件所在绝对路径
在这里插入图片描述
可以看到端口号是6006
输入tensorboard --logdir=日志文件所在绝对路径 --port=6007
在这里插入图片描述
端口号变成6007

进入http://localhost:6007/后,可以看到绘制的图像:

Pytorch学习笔记_第12张图片

2. add_image()的使用

from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image

writer = SummaryWriter('log')
#图片路径地址
image_path = './image.jpg'
#读取图片
img_PIL = Image.open(image_path)
#转换为numpy.array类型
img_array = np.array(img_PIL)
#绘制
writer.add_image('test',img_array,1,dataformats='HWC')
writer.close()

a d d _ i m a g e ( s e l f , t a g , i m g _ t e n s o r , g l o b a l _ s t e p = N o n e , w a l l t i m e = N o n e , d a t a f o r m a t s = ′ C H W ′ ) add\_image(self, tag, img\_tensor, global\_step=None, walltime=None, dataformats='CHW') add_image(self,tag,img_tensor,global_step=None,walltime=None,dataformats=CHW)

  • i m g _ t e n s o r img\_tensor img_tensor i m a g e image image d a t a data data
    格式要求为 t o r c h . T e n s o r , n u m p y . a r r a y , o r   s t r i n g / b l o b n a m e torch.Tensor, numpy.array, or \ string/blobname torch.Tensor,numpy.array,or string/blobname

  • 默认的图片数据格式是 H W C HWC HWC

进入http://localhost:6007/后,可以看到绘制的图片:
Pytorch学习笔记_第13张图片

四、Transforms的使用

t o r c h v i s i o n torchvision torchvision p y t o r c h pytorch pytorch的一个图形库,主要用于构建计算机视觉模型。
t o r c h v i s i o n . t r a n s f o r m s torchvision.transforms torchvision.transforms用于图形的变换。

1. Transforms中的Compose类

C o m p o s e ( ) Compose() Compose()类主要作用是串联多个图片变换的操作。
如下面代码,将图片先进行中心裁剪再转为 T e n s o r Tensor Tensor

transforms.Compose([
    transforms.CenterCrop(10),
    transforms.ToTensor(),
    ])

C o m p o s e ( ) Compose() Compose()内放的是一个列表,列表里的元素是想要执行的 t r a n s f o r m s transforms transforms操作。

2. Transforms中的ToTensor类

作用是将类型为 P I L   I m a g e PIL\ Image PIL Image n u m p y . n d a r r a y numpy.ndarray numpy.ndarray 的数据转变成 t e n s o r tensor tensor类型。

T o T e n s o r ToTensor ToTensor的使用

from torchvision import transforms
from PIL import Image
from torch.utils.tensorboard import SummaryWriter

#创建tensorboard和读取PIL image
writer = SummaryWriter('logs')
img_path = './Zoro.png'
img = Image.open(img_path)

#实例化ToTensor类并进行调用
trans_totensor = transforms.ToTensor()#PIL格式转为tensor格式
img_tensor = trans_totensor(img)

#在tensorboard进行显示
writer.add_image('ToTensor',img_tensor)
writer.close()

结果:
Pytorch学习笔记_第14张图片

转换前的 P I L   I m a g e PIL\ Image PIL Image 或者 n u m p y . n d a r r a y numpy.ndarray numpy.ndarray ( H × W × C ) (H \times W \times C) (H×W×C)且范围在 [ 0 , 255 ] [0, 255] [0,255],转换后的 t e n s o r tensor tensor ( C × H × W ) (C \times H \times W) (C×H×W)且范围在 [ 0.0 , 1.0 ] [0.0, 1.0] [0.0,1.0]

T r a n s f o r m s Transforms Transforms中的 T o P I L I m a g e ToPILImage ToPILImage
( C × H × W ) (C \times H \times W) (C×H×W)的tensor或者 ( H × W × C ) (H \times W \times C) (H×W×C) n u m p y . n d a r r a y numpy.ndarray numpy.ndarray转换为 P I L   I m a g e PIL\ Image PIL Image

3. Transforms中的Normalize类

使用均值和方差对 t e n s o r tensor tensor图片进行归一化。

对于 n n n个通道,需要提供均值 m e a n mean mean ( M 1 , . . . , M n ) (M1,...,Mn) (M1,...,Mn)和标准差 s t d std std ( S 1 , . . , S n ) (S1,..,Sn) (S1,..,Sn),然后对每个通道进行归一化:
o u t p u t [ c h a n n e l ] = ( i n p u t [ c h a n n e l ] − m e a n [ c h a n n e l ] ) / s t d [ c h a n n e l ] output[channel] = (input[channel] - mean[channel]) / std[channel] output[channel]=(input[channel]mean[channel])/std[channel]

#归一化前
print(img_tensor[0][0][0])
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
#归一化后
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])

writer.add_image('Normalize',img_norm)

writer.close()

输出:

tensor(0.9647)
tensor(0.9294)
#(0.9647-0.5)/0.5 = 0.9294

展示结果:
Pytorch学习笔记_第15张图片

4. Transforms中的Resize类

作用:将输入的 P I L   I m a g e PIL\ Image PIL Image转换为所提供的尺寸 s i z e size size

输入和输出都是 P I L PIL PIL

s i z e size size可以是一个序列 ( h , w ) (h,w) (h,w);也可以是一个 i n t int int,当只有一个数字,使用最小的边进行匹配(整体缩放,缩放后最小边的尺寸就是这个 i n t int int)

#转换前
print(img.size)
trans_reszie = transforms.Resize((512,512))
img_resize = trans_reszie(img)
#转换后
print(img_resize.size)

输出:

#转换前
(1092, 712)
#转换后
(512, 512)

4.1 结合前面的compose

#定义transforms操作
trans_totensor = transforms.ToTensor()
trans_reszie = transforms.Resize(512)

#组合
trans_compose = transforms.Compose([trans_reszie,trans_totensor])

#上面的transforms列表中的第一个是trans_reszie,所以需要传入的类型是PIL;最后返回的结果是resize后的tensor

img_resize_totensor = trans_compose(img)

注意:
C o m p o s e Compose Compose中的参数顺序是 [ t r a n s t o t e n s o r , t r a n s r e s z i e ] [trans_totensor,trans_reszie] [transtotensortransreszie],会报错。因为 t r a n s _ r e s z i e trans\_reszie trans_reszie的输入需要的是PIL类型, t r a n s _ t o t e n s o r trans\_totensor trans_totensor输出是 t e n s o r tensor tensor类型

5. Transforms中的RandomCrop类

作用:对输入 P I L PIL PIL图片进行随机裁剪

初始化参数:

  • s i z e size size:裁剪后的尺寸。可以是数字序列: ( h , w ) (h,w) (h,w);或者是一个数字 i n t int int,只有一个数字裁剪后是正方形的。
  • pad_if_needed:是否需要进行填充
  • p a d d i n g padding padding:对图像边界进行填充的像素值。可以是数字序列: ( h , w ) (h,w) (h,w) ( l e f t , t o p , r i g h t , b o t t o m ) (left, top, right, bottom) (left,top,right,bottom);或者是一个数字 i n t int int
  • p a d _ i f _ n e e d e d pad\_if\_needed pad_if_needed:是否进行填充
  • f i l l fill fill:填充的数值
  • p a d d i n g m o d e padding_mode paddingmode:填充的模式。“ c o n s t a n t constant constant”:利用常值进行填充;“ e d g e edge edge”:利用图像边缘像素点进行填充;“ r e f l e c t reflect reflect”;“ s y m m e t r i c symmetric symmetric
tans_rcrop = transforms.RandomCrop(512)

trans_compose = transforms.Compose([tans_rcrop,trans_totensor])

img_rcrop = trans_compose(img)

writer.add_image('RandomCrop',img_rcrop,global_step=1)
writer.close()

展示结果:
Pytorch学习笔记_第16张图片

6. python知识点: _ _ call_ _函数

若A类中有   _   _ c a l l   _   _ \ \_ \ \_call\ \_ \ \_  _ _call _ _函数,可以使用 A ( 参数 ) A(参数) A(参数)调用   _   _ c a l l   _   _ \ \_ \ \_call\ \_ \ \_  _ _call _ _函数。

class Person:
    def __call__(self, name):
        print('call_',name)

    def hello(self,name):
        print('hello_',name)

person = Person()

#调用的是call函数,call函数的调用十分简便
person('张三')

#其他函数需要加 . 来进行调用
person.hello('李四')

输出结果:

call_ 张三
hello_ 李四

7. 总结知识点

  • 关注某个 c l a s s class class时,要先了解这个 c l a s s class class输入和输出
  • 多看官方文档
  • 关注方法需要什么参数;如   _   _ i n i t   _   _ \ \_ \ \_init\ \_ \ \_  _ _init _ _函数,在初始化时可以传入什么参数
  • 不知道返回值的时候,多用 p r i n t ( ) print() print() t y p e ( ) type() type() d e b u g debug debug

五、torchvision中的数据集使用

1. 数据集的下载

在官方网站可以找到很多的数据集和相关模型。
下图的 P y T o r c h PyTorch PyTorch是一个核心模块; t o r c h a u d i o torchaudio torchaudio是处理语言的一个模块; t o r c h t e x t torchtext torchtext是处理文本的一个模块; t o r c h v i s i o n torchvision torchvision是处理图像的一个模块。
Pytorch学习笔记_第17张图片
点击进入 t o r c h v i s i o n torchvision torchvision可以下载数据集或者训练好的模型和,如下图:
Pytorch学习笔记_第18张图片

2. CIFAR-10 dataset的下载

可以通过 t o r c h v i s i o n torchvision torchvision中的 d a t a s e t dataset dataset类对数据集进行下载。如我们要下载 C I F A R − 10 CIFAR-10 CIFAR10数据集,先在官方文档查看这个类方法的解释:

Pytorch学习笔记_第19张图片

  • r o o t ( s t r i n g ) root (string) root(string):数据集存放在文件夹;当 d o w n l o a d download download设置为 T r u e True True会自动下载到这个文件夹下
  • t r a i n ( b o o l ) train (bool) train(bool):是 T r u e True True则创建训练集数据,否则创建测试集。
  • $transform $:对图片的操作
  • $download : 是否进行下载。 :是否进行下载。 :是否进行下载。True$则下载。

下载代码如下,下载到 . / d a t a s e t ./dataset ./dataset文件夹下,并将数据集每张( P I L PIL PIL)图片转成 t e n s o r tensor tensor类型

import torchvision

dataset_transform = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

#训练集
train_set = torchvision.datasets.CIFAR10(root='./dataset',transform=dataset_transform,train=True,download=True)
#测试集
test_set = torchvision.datasets.CIFAR10(root='./dataset',transform=dataset_transform,train=False,download=True)

运行结果如下,会有一个链接。这样下载速度很慢,所以建议复制链接到迅雷去下载。若运行没有出现链接,可以去到 C I F A R 10 CIFAR10 CIFAR10类里去 u r l url url属性。

在这里插入图片描述
打印类别并获取第一个数据

#打印数据集类别,上面返回的target就是指classes的下标,即属于那一类
print(test_set.classes)  #['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']

img,target = test_set[0]
print(test_set.classes[target])  #cat

使用tensorboard进行展示
显示前 10 10 10张图片

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('p10')
for i in range(10):
    img,target = train_set[i]
    writer.add_image('CIFAR10',img,i)
writer.close()

展示结果:
Pytorch学习笔记_第20张图片

2.1 CIFAR-10数据集介绍

官方介绍
这个数据集有 60000 60000 60000万张 32 × 32 32\times32 32×32的彩色图片;总共有 10 10 10个类别,每个类别都有 6000 6000 6000张图片;数据集的 50000 50000 50000张作为训练集, 10000 10000 10000张作为测试集。
Pytorch学习笔记_第21张图片

六、DataLoader的使用

1. dataset类和datalodar的关系

d a t a s e t dataset dataset负责获取数据,如获得一副扑克牌; d a t a l o a d e r dataloader dataloader负责从 d a t a s e t dataset dataset中抽取数据,如怎么从一副扑克牌中抽取几张扑克。
如下图, d a t a l o a d e r dataloader dataloader负责抽取数据放入神经网络中,抓住牌的手可以看出需要获取数据的神经网络。
Pytorch学习笔记_第22张图片

2.Dataloader官方介绍

官方介绍链接
Pytorch学习笔记_第23张图片
参数:

  • d a t a s e t ( D a t a s e t ) dataset (Dataset) dataset(Dataset):之前定义的 D a t a s e t Dataset Dataset,作用是提供数据集的位置、长度等信息。
  • b a t c h _ s i z e ( i n t ) batch\_size (int) batch_size(int):每次抽取数据的大小
  • s h u f f l e ( b o o l ) shuffle (bool) shuffle(bool):每个 e p o c h epoch epoch是否打乱数据
  • n u m _ w o r k e r s ( i n t ) num\_workers (int) num_workers(int):线程数量。但在 w i n d o w window window环境下不太好使
  • d r o p _ l a s t ( b o o l ) drop\_last (bool) drop_last(bool):最后抽取的数据抽不成一个完整的 b a t c h _ s i z e batch\_size batch_size F a l s e False False的时候会保留这些数据, T r u e True True舍弃。

3.代码实例

import torchvision
from torch.utils.data import  DataLoader

#获取数据
import torchvision
from torch.utils.data import  DataLoader
from torch.utils.tensorboard import SummaryWriter

#获取数据
test_data = torchvision.datasets.CIFAR10(root='./dataset',transform=torchvision.transforms.ToTensor(),train=False,download=True)

#dataloder的使用
test_loader = DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0,drop_last=False)

writer = SummaryWriter('dataloder')
step = 0

for data in test_loader:
    imgs,targets = data
    
	#注意是images
    writer.add_images('dataloder',imgs,step)
    step+=1

writer.close()

因为这里 b a t c h s i z e batch_size batchsize=64,所以data都是 t o r c h . S i z e ( [ 64 , 3 , 32 , 32 ] ) torch.Size([64, 3, 32, 32]) torch.Size([64,3,32,32])

d a t a s e t dataset dataset取出数据, d a t a l o a d e r dataloader dataloader d a t a s e t dataset dataset中的数据每64个打包成一组。

展示结果:
Pytorch学习笔记_第24张图片

七、神经网络的基本骨架-nn.Module的使用

7.1 官方文档介绍

官方nn.Module文档
Pytorch学习笔记_第25张图片
t o r c h . n n torch.nn torch.nn包含了很多的神经网络模块,其中的 C o n t a i n e r s Containers Containers(容器)表示的是神经网络的基本骨架。

如其中的 M o d u l e Module Module,官方解释: B a s e   c l a s s   f o r   a l l   n e u r a l   n e t w o r k   m o d u l e s . Base\ class\ for\ all\ neural\ network\ modules. Base class for all neural network modules.
当我们使用 M o d u l e Module Module时,创建的类都要继承这个类,如下面的代码:

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
    	#调用父类的初始化,必须有
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

	#前向传播
    def forward(self, x):
    	#x-->conv1-->relu-->conv2-->relu-->output
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

7.2 代码实例

尝试一个 + 1 +1 +1功能的神经网络:

import torch
from torch import  nn
class Model(nn.Module):
    def __index__(self):
        super().__init__()

    def forward(self,input):
        output = input+1
        return output

model = Model()
x = torch.tensor(1.0)
output = model(x)
print(output) #tensor(2.)

八、卷积层(Convolution Layers)

t o r c h . n n torch.nn torch.nn t o r c h . n n . f u n c t i o n torch.nn.function torch.nn.function的封装。即一个现成的工具( t o r c h . n n torch.nn torch.nn)和零件( t o r c h . n n . f u n c t i o n torch.nn.function torch.nn.function)的关系。

8.1 torch.nn.function.conv2d官方介绍

本小节讨论 2 D 2D 2D的卷积,即函数 c o n v 2 d conv2d conv2d

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

参数:

  • i n p u t input input:输入的维度 ( m i n i b a t c h , i n _ c h a n n e l s , i H , i W ) (minibatch,in\_channels,iH,iW) (minibatch,in_channels,iH,iW)
  • w e i g h t weight weight:卷积核维度 ( out_channels , in_channels groups , k H , k W ) (\text{out\_channels} , \frac{\text{in\_channels}}{\text{groups}} , kH , kW) (out_channels,groupsin_channels,kH,kW)
  • s t r i d e stride stride:滑动的步数。一个数字或者一个数字序列 ( s H , s W ) (sH, sW) (sH,sW)
  • p a d d i n g padding padding:填充。可以是字符串{ ‘ v a l i d ’ ‘valid’ valid, ‘ s a m e ’ ‘same’ same},或者是一个数字,或者是数字序列 ( p a d H , p a d W ) (padH, padW) (padH,padW)

8.2 代码实例

本小节将实现下面的卷积操作
Pytorch学习笔记_第26张图片
代码

import torch
import torch.nn.functional  as F

input = torch.tensor([[1,2,0,3,1],
                      [0,1,2,3,1],
                      [1,2,1,0,0],
                      [5,2,3,1,1],
                      [2,1,0,1,1]])

kernel = torch.tensor([[1,2,1],
                       [0,1,0],
                       [2,1,0]])

input = torch.reshape(input,(1,1,5,5))#(1,1,5,5) -- (样本数,通道数,w,h)
kernel = torch.reshape(kernel,(1,1,3,3))#(1,1,3,3) -- (卷积核数目,通道数,w,h)

output = F.conv2d(input,kernel,stride=1)
print(output)

输出结果:

tensor([[[[10, 12, 12],
          [18, 16, 16],
          [13,  9,  3]]]])

8.3 torch.nn.Conv2d官方介绍

官方介绍
Pytorch学习笔记_第27张图片
参数:

  • i n _ c h a n n e l s ( i n t ) in\_channels (int) in_channels(int):输入图像的通道数
  • o u t _ c h a n n e l s ( i n t ) out\_channels (int) out_channels(int):输出图像的通道数
  • k e r n e l _ s i z e ( i n t   o r   t u p l e ) kernel\_size (int\ or\ tuple) kernel_size(int or tuple):卷积核尺寸
  • s t r i d e ( i n t   o r   t u p l e ) stride (int\ or\ tuple) stride(int or tuple):滑动步数
  • p a d d i n g ( i n t , t u p l e   o r   s t r ) padding (int, tuple\ or\ str) padding(int,tuple or str):填充方式
  • b i a s ( b o o l ) bias (bool) bias(bool):是否为输出结果添加偏置
  • d i l a t i o n ( i n t   o r   t u p l e ) dilation(int\ or\ tuple) dilation(int or tuple):间隔空隙。如下图中的卷积核覆盖是间隔着距离的
    Pytorch学习笔记_第28张图片

输入维度与输出维度

  • I n p u t : ( N , C i n ​ , H i n ​ , W i n ​ )   o r   ( C i n , H i n , W i n ) Input: (N,C_{in}​,H_{in​},W_{in}​)\ or\ (C_{in},H_{in},W_{in}) Input:(N,Cin,Hin,Win) or (Cin,Hin,Win)
  • O u t p u t : ( N , C o u t , H o u t , W o u t )   o r   ( C o u t , H o u t , W o u t ) Output:(N, C_{out}, H_{out}, W_{out})\ or\ (C_{out}, H_{out}, W_{out}) Output:(N,Cout,Hout,Wout) or (Cout,Hout,Wout)

Pytorch学习笔记_第29张图片

8.4 代码实例

import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from torch.utils.data import DataLoader
import torchvision

#获取数据
dataset = torchvision.datasets.CIFAR10('.\dataset',transform=torchvision.transforms.ToTensor(),train=False,download=True)

#抽取数据
dataloder = DataLoader(dataset=dataset,batch_size=64)

#定义卷积模型  x-->conv2d-->output
class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv2d = nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)

    def forward(self,x):
        output = self.conv2d(x)
        return output

#模型实例化
model = Model()

#使用tensorboard进行可视化
writer = SummaryWriter('./logs')
step = 0

#遍历数据集
for data in dataloder:
    
    imgs,targets = data

    #输入前[64,3,32,32]
    writer.add_images('input',imgs,step)
    
    #放入模型
    outputs = model(imgs)

    #输入后[64,6,30,30]  转换成[……,3,30,30]才能可视化
    outputs = torch.reshape(outputs,(-1,3,30,30))
    writer.add_images('output', outputs, step)

    step += 1

writer.close()

展示结果:
Pytorch学习笔记_第30张图片
Pytorch学习笔记_第31张图片

九、最大池化的使用

最大池化目的:
保留最大特征同时减小输入维度。

9.1 MaxPool2d官方介绍

在这里插入图片描述
参数:

  • k e r n e l _ s i z e kernel\_size kernel_size:窗口大小
  • s t r i d e stride stride:窗口移动步幅。默认值是 k e r n e l _ s i z e kernel\_size kernel_size
  • p a d d i n g padding padding:填充数值
  • c e i l _ m o d e ceil\_mode ceil_mode:如下图所示,区别在于池化核移动到边缘时,不能完全覆盖输入,是否依然要输出其最大值。 T r u e True True则输出, F a l s e False False不输出。
    Pytorch学习笔记_第32张图片

9.2 代码实例

我们要尝试下图的池化计算(注意 k e r n e l _ s i z e = 3 kernel\_size=3 kernel_size=3 s t r i d e stride stride也默认为 3 3 3)
Pytorch学习笔记_第33张图片

import torch
from torch import nn

input = torch.tensor([[1,2,0,3,1],
                      [0,1,2,3,1],
                      [1,2,1,0,0],
                      [5,2,3,1,1],
                      [2,1,0,1,1]],dtype=torch.float32)

input = torch.reshape(input,(1,1,5,5))#(1,1,5,5) -- (样本数,通道数,w,h)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.maxpool1 = nn.MaxPool2d(kernel_size=3,ceil_mode=True)

    def forward(self,x):
        output = self.maxpool1(x)
        return output

model = Model()
output = model(input)
print(output)
'''tensor([[[[2., 3.],
          [5., 1.]]]])'''

9.3 最大池化的直观感受

我们对CIFAR10数据集的测试集进行最大池化并可视化结果:

import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10('./dataset',train=False,transform=torchvision.transforms.ToTensor(),download=True)

dataloder = DataLoader(dataset,batch_size=64)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.maxpool1 = nn.MaxPool2d(kernel_size=3,ceil_mode=True)

    def forward(self,x):
        output = self.maxpool1(x)
        return output

model = Model()

writer = SummaryWriter('logs')
step = 0

for data in dataloder:
    imgs,targets = data

    writer.add_images('input',imgs,step)
    output = model(imgs)
    writer.add_images('output',output,step)

    step+=1

writer.close()

展示结果:
原始输入
Pytorch学习笔记_第34张图片
池化后输出:
Pytorch学习笔记_第35张图片

输出的结果变模糊了,有点类似视频的画质。保留图像的大部分特征并缩小图像维度。

十、非线性激活

非线性函数的目的是为了给网络引入一些非线性特折,非线性特征足够多才能够拟合出符合各种曲线线(各种特征)的模型。

10.1 线性激活官方介绍

官方文档
R e L U ReLU ReLU为例子

class
torch.nn.ReLU(inplace=False)

参数:

  • i n p l a c e inplace inplace:是否替换输入。
    R e L U ( i n p u t , i n p l a c e = T r u e ) ReLU(input,inplace=True) ReLU(input,inplace=True),这里的 i n p u t input input的值会随着函数的使用而改变,可以不用变量接收返回值。

数学公式:
R e L U ( x ) = ( x ) + = m a x ( 0 , x ) ReLU(x)=(x)+=max(0,x) ReLU(x)=(x)+=max(0,x)

输入输出维度:
在这里插入图片描述

图像:
Pytorch学习笔记_第36张图片

10.2 代码实例

import torch
from torch import nn

input = torch.tensor([[1,-0.5],
                      [-3,2]])

input = torch.reshape(input,(1,1,2,2))#(1,1,2,2) -- (样本数,通道数,w,h)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.relu1 = nn.ReLU()

    def forward(self,x):
        output = self.relu1(x)
        return output

model = Model()
output = model(input)
print(output)
'''
tensor([[[[1., 0.],
          [0., 2.]]]])
'''

十一、线性层介绍

官方链接
L I N E A R LINEAR LINEAR为例子

class
torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

参数:

  • i n _ f e a t u r e s in\_features in_features:输入特征数(前一层节点数)
  • o u t _ f e a t u r e s out\_features out_features:输出特征数(当前层节点数)
  • b i a s bias bias:是否添加偏置

l i n e a r linear linear就是计算 y = x A T + b y=xA^T+b y=xAT+b

经典的 L R LR LR算法的结构就是: x − > l i n n e a r − > S o f t m a x − > o u t p u t x->linnear->Softmax->output x>linnear>Softmax>output,即线性层的输出一般作为激活函数的输入。

十二、搭建CIFAR-10网络模型

神经网络结构示意图如下:

Pytorch学习笔记_第37张图片

12.1 不使用Sequential

import torch
from torch import nn
from torch.nn import Conv2d,MaxPool2d,Linear
from torch.nn.modules.flatten import Flatten


class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = Conv2d(3,32,5,padding=2)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, padding=2)
        self.maxpool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2)
        self.maxpool3 = MaxPool2d(2)
        self.faltten = Flatten()
        self.linear1 = Linear(1024,64)
        self.linear2 = Linear(64,10)

    def forward(self,x):
        x = self.conv1(x)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x= self.faltten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x

model = Model()

#检测网络输出
input = torch.ones([64,3,32,32])
output = model(input)
print(output.shape)#torch.Size([64, 10])

要点:

  • 对于 p a d d i n g 、 s t r i d e padding、stride paddingstride的确定可以使用公式进行计算
  • F l a t t e n ( ) Flatten() Flatten()的引用在 t o r c h . n n . m o d u l e s . f l a t t e n torch.nn.modules.flatten torch.nn.modules.flatten。【本人是 1.4.1 1.4.1 1.4.1版本的 p y t o r c h pytorch pytorch
  • 如果不知道下一层的应该使用什么维度的卷积层,可以在 f o r w a r d forward forward里面截断输出上一层的维度。
    例如:不知道第一层 F C FC FC输入是多少,可以在 f o r w a r d forward forward里面就前向传播到 f a l t t e n faltten faltten,查看它的输出维度就知道第一层 F C FC FC输入应该是 1024 1024 1024了。

12.2 使用Sequential

S e q u e n t i a l Sequential Sequential使代码更简洁和有序,代码如下:

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Linear, Sequential
from torch.nn.modules.flatten import Flatten


class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )


    def forward(self,x):
        x = self.model1(x)
        return x

model = Model()

#检测网络输出
input = torch.ones([64,3,32,32])
output = model(input)
print(output.shape)##torch.Size([64, 10])

12.3 模型的可视化

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('./logs')
writer.add_graph(model,input)
writer.close()

展示结构如下,双击查看详细结构
Pytorch学习笔记_第38张图片

十三、损失函数与反向传播

L o s s Loss Loss的作用:

  1. 计算实际输出与目标之间的差距
  2. 为更新输出提供一定的依据(反向传播)

13.1 官方文档介绍

文档链接

13.1.1 L1Loss

torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')

ℓ ( x , y ) = L = { l 1 ​ , … , l N } ​ ⊤ , l n ​ = ∣ x n ​ − y n ​ ∣ ℓ(x,y)=L=\{l_1​,…,l_N\}​^⊤,l_n​=∣x_n​−y_n​∣ (x,y)=L={l1,,lN},ln=∣xnyn
在这里插入图片描述

13.1.2 MSELoss

平方差

class
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')

ℓ ( x , y ) = L = { l 1 ​ , … , l N } ​ ⊤ , l n ​ = ( x n ​ − y n ​ ) 2 ℓ(x,y)=L=\{l_1​,…,l_N\}​^⊤,l_n​=(x_n​−y_n​)^2 (x,y)=L={l1,,lN},ln=(xnyn)2
在这里插入图片描述

13.1.3 CrossEntropyLoss

一般用于多分类问题, C C C表示分类个数

class
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

Pytorch学习笔记_第39张图片

  • x x x表示预测结果(多分类问题预测结果是数组)
  • c l a s s class class表示真实的分类
  • j j j的范围为 [ 0 , ( C − 1 ) ] [0,(C-1)] [0,(C1)]

13.2 为CIFAR-10网络模型添加损失函数

#获取数据
dataset = torchvision.datasets.CIFAR10('.\dataset',transform=torchvision.transforms.ToTensor(),train=False,download=True)

#抽取数据
dataloder = DataLoader(dataset=dataset,batch_size=64)

#定义模型
model = Model()
#定义损失函数
loss = nn.CrossEntropyLoss()

#一个mini_batch计算一次损失函数
for data in dataloder:
    imgs,targets = data
    output = model(imgs)
    res_loss = loss(output,targets)#损失函数值=loss(预测值,真实值)
    print(res_loss)

输出结果:

Files already downloaded and verified
tensor(2.3027, grad_fn=<NllLossBackward>)
tensor(2.3200, grad_fn=<NllLossBackward>)
tensor(2.2939, grad_fn=<NllLossBackward>)
tensor(2.3089, grad_fn=<NllLossBackward>)
tensor(2.3268, grad_fn=<NllLossBackward>)
…………不展示全部输出

添加反向传播

#一个mini_batch计算一次损失函数
for data in dataloder:
    imgs,targets = data
    output = model(imgs)
    res_loss = loss(output,targets)#损失函数值=loss(预测值,真实值)
    #反向传播
    res_loss.backward()

在运行 r e s _ l o s s . b a c k w a r d ( ) res\_loss.backward() res_loss.backward()之前, m o d e l model model里面的梯度 g r a d grad grad N o n e None None的,如下图:
在这里插入图片描述
在运行之后,梯度 g a r d gard gard就被附上了值,如下图:

在这里插入图片描述
之后采取优化算法使用这些值来优化模型。

十四、优化器

14.1 官方文档介绍

官方介绍
使用流程

  1. C o n s t r u c t i n g   i t Constructing\ it Constructing it(构建它):
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

参数:
m o d e l . p a r a m e t e r s ( ) model.parameters() model.parameters():模型参数
l r lr lr:学习率

  1. T a k i n g   a n   o p t i m i z a t i o n   s t e p Taking\ an\ optimization\ step Taking an optimization step(进行优化步骤):
for input, target in dataset:
    optimizer.zero_grad()#梯度归0
    output = model(input)
    loss = loss_fn(output, target)
    loss.backward()#计算梯度
    optimizer.step()#优化

14.2 为CIFAR-10网络模型添加优化器

如下面代码,在之前的基础上添加了外层 e p o c h epoch epoch迭代,一次迭代遍历一数据集。

优化器的添加要保证这三个的前后次序:
( 1 ) g r a d 清零 − − > ( 2 ) 反向传播计算 g r a d − − > ( 3 ) 优化算法根据 g r a d 执行梯度下降 (1)grad清零-->(2)反向传播计算grad-->(3)优化算法根据grad执行梯度下降 (1)grad清零>(2)反向传播计算grad>(3)优化算法根据grad执行梯度下降

#获取数据
dataset = torchvision.datasets.CIFAR10('.\dataset',transform=torchvision.transforms.ToTensor(),train=False,download=True)

#抽取数据
dataloder = DataLoader(dataset=dataset,batch_size=64)

#定义模型
model = Model()
#定义损失函数
loss = nn.CrossEntropyLoss()

#优化器
optim = torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(20):
    running_loss = 0.0
    for data in dataloder:
        optim.zero_grad()  # grad清零
        imgs, targets = data
        output = model(imgs)
        res_loss = loss(output, targets)  # 损失函数值=loss(预测值,真实值)
        res_loss.backward()  # 反向传播计算grad
        optim.step()  # 优化算法进行梯度下降
        running_loss += res_loss

十五、官网模型的加载(浅谈)

15.1 官网介绍

V G G 16 VGG16 VGG16为例子:

vgg = torchvision.models.vgg16(pretrained=False, progress=True, **kwargs)
  • p r e t r a i n e d pretrained pretrained:是否下载权重进行预训练
    当为 T r u e True True时,加载模型过程中会下载官网训练好的权重
  • p r o g r e s s progress progress:是否显示进度条

这个模型使用的 I m a g e N e t ImageNet ImageNet数据集很大,官网不提供下载,可以去浏览器搜索资源下载。

在官网查看模型函数介绍时,要选择正确的 t o r c h v i s i o n torchvision torchvision版本,不同版本函数之间存在一定的差异。

15.2 模型的使用与修改

下图是 V G G 16 VGG16 VGG16的结构图,最后一层的输出维度是 1000 1000 1000,是一个多分类问题。
Pytorch学习笔记_第40张图片
如何修改 V G G 16 VGG16 VGG16应用到 C I F A R − 10 CIFAR-10 CIFAR10这个数据集上呢?

  • 添加新的输出层,可以添加一个输出维度为 10 10 10 F C FC FC
import torchvision
from torch.nn import Linear

vgg16 = torchvision.models.vgg16(pretrained=False,progress=True)

vgg16.add_module('add_linear',Linear(1000,10))

print(vgg16)

输出结果:
看下图红框,网络结构的最后一层成功的添加了一层全连接层。
Pytorch学习笔记_第41张图片

若想把这个 F C FC FC层添加到 c l a s s i f i e r classifier classifier中去,将

vgg16.add_module('add_linear',Linear(1000,10))
  • 对原有输出层进行替换
vgg16.classifier[6]=Linear(4096,10)

Pytorch学习笔记_第42张图片

十六、网络模型的保存与读取

第一种方式
保存模型结构和参数

vgg16 = torchvision.models.vgg16(pretrained=False,progress=True)

#保存方式一
torch.save(vgg16,'vgg16_method1.pth')#(模型,文件名)
#会在文件夹下生成一个vgg16_method1.pth文件,包含模型结构和参数权重

#读取方式一
model = torch.load('vgg16_method1.pth')

第一种方式在保存和读取自己定义的模型时,会有陷阱:
在读取模型时会报错,所以需要把模型 c l a s s class class定义复制到读取的那个 . p y .py .py文件中。也可以从定义模型 c l a s s class class的那个类 i m p o r t import import进来。

第二种方式
保存模型参数(官方推荐)

#保存方式二
torch.save(vgg16.state_dict(),'vgg16_method2.pth')#(模型的状态字典,文件名)
#状态字典中保存了模型的参数权重,不包含网络结构

#读取方式二
vgg16 = torchvision.models.vgg16(pretrained=False,progress=True)#重建网络结构
vgg16.load_state_dict(torch.load('vgg16_method2.pth'))#加载参数字典

十七、完整的模型训练套路

一、加载数据集

#加载数据集
train_data = torchvision.datasets.CIFAR10('./dataset',train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10('./dataset',train=False,transform=torchvision.transforms.ToTensor(),download=True)

train_data_len = len(train_data)
test_data_len = len(test_data)

#打印数据长度
print("训练集数据长度{}".format(train_data_len))
print("训练集数据长度{}".format(test_data_len))

#抽取数据
train_loader = DataLoader(train_data,batch_size=64)
test_loader = DataLoader(test_data,batch_size=64)

二、搭建网络模型与测试

这个网络模型的搭建可以在一个新py文件中定义,需要时从这个 p y py py文件 i m p o r t import import即可

#搭建模型
class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self,x):
        x = self.model(x)
        return x

#测试模型输出维度
if __name__ == '__main__':
    model = Model()
    input = torch.ones((64,3,32,32))
    output = model(input)
    print(output.shape)

三、定义网络模型、损失函数、优化器与tensorboard的可视化

#创建网络模型
model = Model()

#添加tensorboard
writer = SummaryWriter('./logs')

#损失函数
loss_fn = nn.CrossEntropyLoss()

#优化器
learning_rate = 1e-2
optimizer = torch.optim.SGD(model.parameters(),lr=learning_rate)

#设置网络训练参数
#记录训练次数
total_train_step = 0
#记录测试次数
total_test_step = 0
#训练轮次
epochs = 10

for epoch in range(epochs):
    print("----第{}轮训练开始----".format(epoch+1))
    for data in train_loader:
        imgs,targets = data
        outputs = model(imgs)
        loss = loss_fn(outputs,targets)

        #优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step+=1
        if total_train_step%100 == 0:
            print("训练次数{},Loss:{}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss,total_train_step)

    #测试集步骤开始
    total_test_loss = 0
    total_accuracy = 0
    
    with torch.no_grad():#确保不进行优化,仅测试
        for data in test_loader:
            imgs,targets = data
            outputs = model(imgs)
            loss = loss_fn(outputs,targets)
            total_test_loss += loss.item()
            #正确率计算
            accuracy = (outputs.argmax(1)==targets).sum()
            total_accuracy += accuracy
    print("测试集整体上的正确率:{}".format(total_accuracy/test_data_len))
    print("测试集整体上的Loss:{}".format(total_test_loss))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_len, total_test_step)
    total_test_step +=1
    
    #模型保存
    #torch.save(model,"model_{}.pth".format(epoch))
writer.close()

完整代码
t r a i n . p y train.py train.py:

from torch.utils.data import DataLoader
import torchvision
from torch.utils.tensorboard import SummaryWriter

from model import *

#加载数据集
train_data = torchvision.datasets.CIFAR10('./dataset',train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10('./dataset',train=False,transform=torchvision.transforms.ToTensor(),download=True)

train_data_len = len(train_data)
test_data_len = len(test_data)

#打印数据长度
print("训练集数据长度{}".format(train_data_len))
print("训练集数据长度{}".format(test_data_len))

#抽取数据
train_loader = DataLoader(train_data,batch_size=64)
test_loader = DataLoader(test_data,batch_size=64)

#创建网络模型
model = Model()

#添加tensorboard
writer = SummaryWriter('./logs')

#损失函数
loss_fn = nn.CrossEntropyLoss()

#优化器
learning_rate = 1e-2
optimizer = torch.optim.SGD(model.parameters(),lr=learning_rate)

#设置网络训练参数
#记录训练次数
total_train_step = 0
#记录测试次数
total_test_step = 0
#训练轮次
epochs = 10

for epoch in range(epochs):
    print("----第{}轮训练开始----".format(epoch+1))
    for data in train_loader:
        imgs,targets = data
        outputs = model(imgs)
        loss = loss_fn(outputs,targets)

        #优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step+=1
        if total_train_step%100 == 0:
            print("训练次数{},Loss:{}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss,total_train_step)

    #测试集步骤开始
    total_test_loss = 0
    total_accuracy = 0
    #确保不进行优化,仅测试
    with torch.no_grad():
        for data in test_loader:
            imgs,targets = data
            outputs = model(imgs)
            loss = loss_fn(outputs,targets)
            total_test_loss += loss.item()
            accuracy = (outputs.argmax(1)==targets).sum()
            total_accuracy += accuracy.item()
    print("测试集整体上的正确率:{}".format(total_accuracy/test_data_len))
    print("测试集整体上的Loss:{}".format(total_test_loss))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_len, total_test_step)
    total_test_step +=1

    #模型保存
    #torch.save(model,"model_{}.pth".format(epoch))
writer.close()

m o d e l . p y model.py model.py

import torch
from torch import nn
from torch.nn import Sequential,Conv2d,MaxPool2d,Linear
from torch.nn.modules.flatten import Flatten

#搭建模型
class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self,x):
        x = self.model(x)
        return x

if __name__ == '__main__':
    model = Model()
    input = torch.ones((64,3,32,32))
    output = model(input)
    print(output.shape)

展示结果(没有训练完,太耗时间了,下节使用GPU加速会快很多):
Pytorch学习笔记_第43张图片

注意:

  • 关于 t r a i n ( m o d e = T r u e ) train(mode=True) train(mode=True) e v a l ( ) eval() eval():
    t r a i n ( ) train() train()表示开启训练,后续代码是进行训练集训练的。
    e v a l ( ) eval() eval()表示开启测试,后续代码是进行验证集训练的。
    但大部分情况下可以不用添加这两行代码,除非使用了 D r o p o u t , B a t c h N o r m Dropout,BatchNorm Dropout,BatchNorm

  • 当数字和 t e n s o r tensor tensor进行计算时,要使用 t e n s o r . i t e m tensor.item tensor.item进行计算

十八、使用CPU训练

18.1 第一种方式

网络模型、数据(输入、标注)、损失函数处加上 . c u d a ( ) .cuda() .cuda()

if torch.cuda.is_available()是为了在gpu和cpu环境下都能跑。

  • 第一处:网络模型
    在这里插入图片描述

  • 第二处:数据(输入、标注)
    Pytorch学习笔记_第44张图片
    Pytorch学习笔记_第45张图片

  • 第三处:损失函数处
    Pytorch学习笔记_第46张图片

使用GPU训练速度快了好多。
10个轮次的训练,测试集正确率能达到53%
Pytorch学习笔记_第47张图片

如果电脑上没有不能使用GPU加速,可以使用国外的 G o o g l e   c o l a b Google\ colab Google colab或者国内的天池实验室来代跑我们的代码。

18.2 第二种方式

使用 . t o ( d i v i c e ) .to(divice) .to(divice)

  • 先在开头定义训练的设备:
    在这里插入图片描述
    为了确保不能 G P U GPU GPU加速的情况下代码也能使用,可以替换成下面的代码:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

  • 第一处:网络模型
    可以不用赋值
    在这里插入图片描述

  • 第二处:数据(输入、标注)
    可以不用赋值
    Pytorch学习笔记_第48张图片
    Pytorch学习笔记_第49张图片

  • 第三处:损失函数处
    在这里插入图片描述

18.3 测试时注意事项

  • 使用GPU加速训练的模型,在预测新数据时,要将数据进行转换,如 i m g = i m g . c u d a ( ) img = img.cuda() img=img.cuda()

  • p n g png png格式是四个通道,除了RGB三通道外,还有一个透明的通道。因此应该使用 i m a g e = i m a g e . c o n v e r t ( ′ R G B ′ ) image = image.convert('RGB') image=image.convert(RGB)保留颜色通道。

  • 加载训练好的模型时,若 m a p _ l o c a t i o n map\_location map_location报错,应添加 m a p _ l o c a t i o n = t o r c h . d e v i c e ( ′ c p u ′ ) map\_location = torch.device('cpu') map_location=torch.device(cpu)【cpu或cuda】

model = torch.load("model_gpu.pth",map_location=torch.device('cpu'))

你可能感兴趣的:(深度学习框架学习,pytorch,学习,深度学习)