当前位置:   article > 正文

[Pytorch入门] 土堆课程笔记_pytransform3d 帮助

pytransform3d 帮助

目录

P1-4 准备工作:

1 pytorch环境配置及安装

2 jupter安装

3 使用对比

4 python 函数两大法宝

P5  加载数据

5.1 dataset与 dataloader

5.2 dataset:

P6  dataset实战

6.1 读取单张图片:

6.2 完整代码:

6.3 补充(class类)

6.3.1  class实例化

 6.3.2  class调用

 6.3.3 calss中的__call__

6.3.4 rename填充数据集

6.4 rename填充数据集

P7-8  tensorboard的使用 

7.1 tensorboard的安装:

7.2 tensorboard使用 

7.3 完整代码 

7.4 一些使用tensorboard的tips:

P9   Transform的使用(一)

P10  Transform的使用(二)

P12   常见的Transforms(一)

12.1  __call__

12.2 transforms的使用

12.3 Normolize使用

12.4 我有疑问Image.open和cv2.imread打开不一致

 P13   常见的Transforms(二)

13.1 Resize()

13.2 Compose()

13.3 RandomCrop()

P14 Torchvision中Dataset的使用

P15 Torchvision中DataLoader的使用

P16  nn.Module的使用

P17 浅说卷积

P18  Conv Layers 卷积层

P23 损失函数与反向传播

23.1 损失函数

23.1.1  torch.nn.L1Loss

23.1.2  torch.nn.MSELoss 均方误差

23.1.3 torch.nn.CrossEntropyLoss 交叉熵

23.2 反向传播

P24  优化器

P25 现有模型修改(vgg16为例)

25.1 vgg16

25.2 imagene

P26 模型的保存与加载

26.1 模型的保存

26.2  数据的加载:

26.2.1 以方法一加载: 

26.1.1 方法一存在缺陷:

26.2.2  以方法二加载

P27 完整的训练套路(一)

27.1 训练套路总结

27.2 modoel文件:

 27.3 train文件夹:

P28  完整的训练套路(二)

28.1  准确率

28.1.1 预测正确率代码(argmax使用)

 28.2 完整的代码:

P29  完整的训练套路(三)

P29 用GPU训练(一)

29.1 .cuda()

29.2 time计时器

29.3 完整代码:

P30 用gpu训练(二)

P31 完整的验证套路

31.1 完整的训练步骤:

31.2 注意点:

31.3 完整的代码

P32  如何看开源项目


P1-4 准备工作:

1 pytorch环境配置及安装

非常非常推荐这个博主@炮哥带你学,也是我的师兄开学时推荐给我的。

(20条消息) 利用Anaconda安装pytorch和paddle深度学习环境+pycharm安装---免额外安装CUDA和cudnn(适合小白的保姆级教学)_安装paddlepaddle 依赖_炮哥带你学的博客-CSDN博客

建议:不要安装太新版本的cuda和python,可能会出现许许多多稀奇古怪的问题,非常让人火大,选择之前的版本可以少很多烦恼,而且极为顺畅。

cuda11.7+python3.8真的很好用~ 

老老实实一步步配基本没什么太大问题网络问题可能会丢包。多百度多csdn,丢了什么就pip install。如果遇到实在解决不了的就卸载重装。。。

2 jupter安装

根据上面的博主,会自动安装jupter,配置好环境用就行了(very easy)。

3 使用对比

pycharm的控制台:以每一行为块执行,哪里出错,从错的地方开始写,从错的地方开始执行。阅读性不佳。也可以以任意块开始执行(shift+enter输入下一行代码,回车运行)。可以看到每个变量的各个属性,缺点是出现错误不利于代码阅读。

jupyter:以任意行为块运行,可以自己操控。哪一块错误,只要修改某一块,前面正确的部分不受影响,便于阅读。使用时需要配置环境(但是很简单)。

4 python 函数两大法宝

  • dir() 函数:能让我们知道工具箱以及工具箱中的分隔区有什么东西(打开,看见)
  • help() 函数:帮助知道每个工具是如何使用的,工具的使用方法(说明书)

 可以看到torch工具包里还有哪些工具,想看torch下这么多工具包下的某个工具包还有什么工具包,可以执行点操作,如看看AVG这个包下面还有没有别的工具包,就输入dir(torch.AVG)即可。

 看每个工具具体如何使用,调用help()

​ 

一般更常用的方法就是遇到看不懂的函数名,按ctrl+函数名,就会进入python内置的说明文档。

输出的前后都带有双下划线__,这是一种规范,说明这个变量不容许篡改,即它不再是一个分隔区,而是一个确确实实的函数(相当于工具,可以用help()函数) 

 P5 加载数据

5.1 dataset与 dataloader

dataset:提供一种方式去获取其数据及其label(标签),并完成编号

  • 如何获取每一个数据及其label
  • 告诉我们有多少个数据

dataloader:为后面的网络提供不同的数据形式(batch_size会一个批次抓取多个数据)

下面以蚂蚁蜜蜂数据集为例:这是网址,直接下载就行

https://download.pytorch.org/tutorial/hymenoptera_data.zip

根据文件名很容易看到里面的数据。

5.2 dataset:

还有一种写法:

Dataset?? 

​ 

P6 dataset实战

6.1 读取单张图片:

绝对引用: 

  1. from PIL import Image # PIL相当于python官方图像处理库,非常适合于图像归档以及图像的批处理任务
  2. # 用 PIL显示图片
  3. img_path ="E:\\pycharm\\project\\project_test\\test_0306\hymenoptera_data\\train\\ants_image\\0013035.jpg"
  4. img = Image.open(img_path)
  5. img.show()

相对引用:

  1. from PIL import Image # PIL相当于python官方图像处理库,非常适合于图像归档以及图像的批处理任务
  2. # 用 PIL显示图片
  3. img_path ="hymenoptera_data/train/ants_image/0013035.jpg"
  4. img = Image.open(img_path)
  5. img.show()

输出为:

 6.2 完整代码:

代码写的挺清楚的,也从cv2和pil两种方式展示了图片

  1. from torch.utils.data import Dataset # 从torch.的工具区(utils)中的data区获取数据集
  2. from PIL import Image # PIL相当于python官方图像处理库,非常适合于图像归档以及图像的批处理任务
  3. import cv2
  4. import os
  5. # 用 PIL显示图片
  6. img_path ="E:\\pycharm\\project\\project_test\\test_0306\hymenoptera_data\\train\\ants_image\\0013035.jpg"
  7. # img = Image.open(img_path)
  8. # img.show()
  9. # 用cv2显示图片,
  10. img = cv2.imread(img_path) # Image.open(img_path)
  11. def cv2_show_cv_image(image): # 使用cv2显示cv2打开的图片
  12. cv2.namedWindow('image', 0) # 命名一个窗口
  13. cv2.resizeWindow('image', 600, 500) # 将窗口大小进行调整,这两部主要是为了防止图片过大,屏幕显示不下
  14. cv2.imshow('image', img) # 显示图片
  15. cv2.waitKey(0) # 等待,按任意键跳过,如果没有这个,窗口会是一闪而过
  16. cv2.destroyWindow('image') # 这个和下一句都是关闭窗口,只不过这是关闭指定窗口
  17. # cv2.destroyAllWindows() # 关闭此时cv2所有打开的窗口
  18. # cv2.imwrite('cat.png', image) # cv2保存图片
  19. # 获取当前目录
  20. current_path = os.getcwd()
  21. print(current_path)
  22. # 将所有数据放进列表,通过指针获取
  23. dir_path ="hymenoptera_data/train/ants_image" # 这里是相对引用
  24. img_path_list = os.listdir(dir_path) # dir文件夹,listdir就是将文件夹下的所有东西变成列表
  25. img_path_list[1]
  26. class Mydata (Dataset): # 是类不是模块
  27. def __init__(self,root_dir,label_dir): # 理解成文件夹就行
  28. # 变量前面加了self,那么在任何实例方法(非staticmethod和calssmethod)
  29. # 就都可以访问这个变量了,如果没有加self,只有在当前函数内部才能访问这个变量
  30. # 因为python里没有变量声明,最好确保所有带self前缀的变量是在__init__中首次出现
  31. self.root_dir = root_dir # 函数中一个变量不能传递给另外一个变量,加self,相当于指定了一个类中的全局变量,可以给后面的变量使用
  32. self.label_dir = label_dir
  33. self.path = os.path.join(self.root_dir,self.label_dir)
  34. self.listdir = os.listdir(self.path)
  35. self.img_path = os.listdir(self.path) # 图片下所有的地址都以指针的形式保存
  36. def __getitem__(self, idx): # idx:索引,指针吧我觉得,根据索引去获取每一个图片
  37. img_name =self.img_path[idx]
  38. img_item_path =os.path.join(self.root_dir,self.label_dir,img_name) # join(path, *paths)实例化的加指针
  39. img = Image.open(img_item_path)
  40. # img.show()
  41. label = self.label_dir
  42. return img,label
  43. def __len__(self):
  44. return len(self.img_path) # 长度就是文件夹列表的长度
  45. root_dir = "hymenoptera_data/train"
  46. ants_label_dir = "ants_image"
  47. bees_label_dir = "bees_image"
  48. ants_dataset = Mydata(root_dir,ants_label_dir)
  49. bees_dataset = Mydata(root_dir,bees_label_dir)
  50. train_dataset = ants_dataset + bees_dataset
  51. len(train_dataset) # 把两个数据集拼接起来,数据长度就是两个之和
  52. print(len(train_dataset))
  53. img,label = train_dataset[220] # 根据数组地址,从两个数据集里找,通过修改数组元素可以找到不同的数据
  54. img.show()

6.3 补充(class类)

6.3.1  class实例化

  1. class student:
  2. name = None
  3. age = None
  4. contourpy = "中国"
  5. stu_1 = student()
  6. stu_1.name = "xixi"
  7. stu_1.age = 18
  8. print(stu_1.name)
  9. print(stu_1.age)
  10. print(stu_1.contourpy)

 6.3.2  class调用

  1. class student:
  2. name = None
  3. age = None
  4. def say_hi(self):
  5. print(f"我是{self.name},很高兴认识你")
  6. def say_hello(self,msg):
  7. print(f"我是{self.name},{msg}")
  8. std1 = student() # 实例化
  9. std1.name = "xixi"
  10. std1.say_hi()
  11. std1.say_hello("加一") # 因为self不用管,就相当于hello里只有一个参数,传进去就行了

 6.3.3 calss中的__call__

  1. class Person:
  2. def __call__(self,name):
  3. print("__call"+name)
  4. def hello(self,name):
  5. print("hello"+name)
  6. # Python中那些能够在后面加()来调用执行的对象,被称为可调用对象。可调用对象包括自定义函数、Python内置函数、实例对象和实例方法等。
  7. # call()方法是Python中一个很特殊的方法。凡是可调用对象,都可以通过调用__call__()方法来调用该对象。
  8. # 如果类中定义了__call__()方法,那么该类的实例对象也将成为可调用对象。该对象被调用时,将执行__call__()方法中的代码。
  9. person = Person() # 实例化
  10. person("haha") # 内置__call__ 可以直接对象名+属性,参数
  11. person.hello("xixi") #

6.3.4 rename填充数据集

  1. # 填充数据集
  2. import os
  3. root_dir ="hymenoptera_data/train"
  4. target_dir = "ants_image"
  5. img_path = os.listdir(os.path.join(root_dir,target_dir)) # 把"hymenoptera_data/train/ants_image"
  6. """
  7. os.listdir(path)
  8. os.listdir的返回值是一个列表,列表里面存储该path下面的子目录的名称
  9. """
  10. print(img_path)
  11. # label读取的就是:把"ants_image"分为两份,然后把间隔的第一份当作label
  12. label = target_dir.split('_')[0] # 以_作为分隔符分隔数据,[0]读取第0位分割出来的东西
  13. print(label)
  14. out_dir = "ants_label"
  15. for i in img_path:
  16. file_name = i.split('.jpg')[0]
  17. with open (os.path.join(root_dir,out_dir,"{}.txt".format(file_name)),'w') as f:
  18. f.write(label)
  19. """
  20. with open(r'filename.txt') as f:
  21. for l in f:
  22. l = json.loads(l) #文件的读操作
  23. with open('Hello.txt', 'w') as f:
  24. f.write('hello world') #文件的写操作,w以写方式打开
  25. """

6.4 rename填充数据集

  1. # 填充数据集
  2. import os
  3. root_dir ="E:\\pycharm\\project\\project_test\\test_0306\\hymenoptera_data\\train"
  4. target_dir = "ants_image"
  5. img_path = os.listdir(os.path.join(root_dir, target_dir)) # 把"hymenoptera_data/train/ants_image"
  6. """
  7. os.listdir(path)
  8. os.listdir的返回值是一个列表,列表里面存储该path下面的子目录的名称
  9. """
  10. # print(img_path)
  11. # label读取的就是:把"ants_image"分为两份,然后把间隔的第一份当作label
  12. label = target_dir.split('_')[0] # 以_作为分隔符分隔数据,[0]读取第0位分割出来的东西
  13. print(label)
  14. out_dir = "ants_label"
  15. for i in img_path:
  16. file_name = i.split('.jpg')[0]
  17. with open(os.path.join(root_dir, out_dir, "{}.txt".format(file_name)), 'w') as f:
  18. f.write(label)
  19. """
  20. with open(r'filename.txt') as f:
  21. for l in f:
  22. l = json.loads(l) #文件的读操作
  23. with open('Hello.txt', 'w') as f:
  24. f.write('hello world') #文件的写操作,w以写方式打开
  25. """

 

P7-8 tensorboard的使用 

用tensorboard的时候命名文件里不要出现中文,不要出现空格!!!

7.1 tensorboard的安装:

在终端里

pip install tensorboard

7.2 tensorboard使用 

SummaryWriter:就相当于文件夹,把自己想存的东西放进去。
writer.add_image():读取图片,第一个参数为标题,第二个是y轴,第三个是x轴
writer.add_scalar():绘制折线图,第一个参数为标题,第二个是y轴,第三个是x轴

7.3 完整代码 

  1. from torch.utils.tensorboard import SummaryWriter
  2. writer = SummaryWriter("xixi")
  3. writer.add_image()
  4. """
  5. add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):
  6. Args:
  7. tag (string): Data identifier # 图像的title
  8. img_tensor (torch.Tensor, numpy.array, or string/blobname): # 图像的类型:字符串、torch.Tensor, numpy.array
  9. global_step (int): Global step value to record # 训练的步骤
  10. walltime (float): Optional override default walltime (time.time()) # 这个一般不是很常用
  11. seconds after epoch of event
  12. dataformats='CHW'
  13. """
  14. # 读取图片,用tensorboard打印显示
  15. import numpy as np
  16. from torch.utils.tensorboard import SummaryWriter
  17. img_path = "hymenoptera_data/train/ants_image/67270775_e9fdf77e9d.jpg"
  18. # from PIL import Image
  19. # img_PIL = Image.open(img_path)
  20. # print(type(img_PIL))
  21. import cv2
  22. img_cv2 = cv2.imread(img_path)
  23. print(type(img_cv2))
  24. print(img_cv2.shape)
  25. # import numpy as np
  26. # img_np = np.array(img_path)
  27. # print(type(img_np))
  28. writer = SummaryWriter("xixi")
  29. writer.add_image("data_read", img_cv2, 2, dataformats='HWC') # 要求的数据格式是HWC,通道数在最后面!
  30. # y = 2x
  31. # 用tensorboard绘制曲线图
  32. for i in range(100):
  33. writer.add_scalar("y=2x", 3*i, i) # 第一个参数是标题,第二个是y轴,第三个是x轴
  34. # 画出的图像会回环是因为他会有一个拟合的操作,
  35. # 解决:①把对应的logs下的所有文件都删掉再重新开始 ②创建一个新文件,SummaryWriter(”新文件夹“)
  36. """
  37. def add_scalar(self, tag, scalar_value, global_step=None)
  38. Args:
  39. tag (string): Data identifier 图表标题
  40. scalar_value (float or string/blobname): Value to save y轴
  41. global_step (int): Global step value to record x轴
  42. """
  43. writer.close()

运行后左边会出现一个xixi的文件夹 (每运行一次就会产生一个文件)

运行后打开终端,输入: tensorboard --logdir=xixi

点击弹出来的网址

PS E:\pycharm\tudui_test\test_0306> tensorboard --logdir=xixi
TensorFlow installation not found - running with reduced feature set.
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
TensorBoard 2.10.0 at http://localhost:6006/ (Press CTRL+C to quit) 

7.4 一些使用tensorboard的tips:

 ①不改变标题只修改里面的参数,就会在原图表里直接绘制,就是说会有回环或者重叠,解决:

  1. 把对应的logs下的所有文件都删掉再重新开始
  2. 创建一个新文件,SummaryWriter(”新文件夹“)

②tensorboard为了加速只需要在tensorboard 可视化命令时参加参数--samples_per_plugin这里面的–samples_per_plugin=images=10000000就是显示1000000张图片出来,所以这个值尽可能大一点就好。

P9 Transform的使用(一)

Transform相当于一个工具箱,按住ctrl点击,可以看到官方解释说明

一个个class相当于具体的工具,点结构会看到各种工具,如下

 工具就可以使用上述的所有

 9.1 transforms.ToTensor

通过transforms.ToTensor去看两个问题
 1、transform该如何使用(python)
 2、为什么需要tensor数据

transform该如何使用(python):

  1. from torchvision import transforms
  2. from PIL import Image
  3. # 通过transforms.ToTensor去看两个问题
  4. # 1、transform该如何使用(python)
  5. # 2、为什么需要tensor数据集
  6. # 绝对路径:E:\pycharm\tudui_test\test_0306\hymenoptera_data
  7. # 相对路径:hymenoptera_data/train/ants_image/0013035.jpg
  8. img_path = "hymenoptera_data/train/ants_image/0013035.jpg" # 不用绝对路径是因为他有转义字符,需要双斜杠转化
  9. # 用PIL读取
  10. img = Image.open(img_path)
  11. print(img) # <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=768x512 at 0x1883790A760>
  12. # 1、transform该如何使用(python)
  13. trans_tensor = transforms.ToTensor()(img)
  14. print(trans_tensor)
  15. # transform的使用
  16. # ToTensor()是工具箱里的一个工具,加参数需要重新加括号~
  17. # Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor(HWC)->(CHW)
  18. """
  19. tensor([[[0.3137, 0.3137, 0.3137, ..., 0.3176, 0.3098, 0.2980],
  20. [0.3176, 0.3176, 0.3176, ..., 0.3176, 0.3098, 0.2980],
  21. [0.3216, 0.3216, 0.3216, ..., 0.3137, 0.3098, 0.3020],
  22. """

P10 Transform的使用(二)

tensor里包装了神经网络所需要的一些参数,把代码复制进控制台或者debug。

可以看到右边的一些参数

 尝试一下cv2

 在终端里安装 pip install opencv-python

 !!注意一下,imread是无法读取包含中文的路径的,用绝对路径的小伙伴注意一下

 P12   常见的Transforms(一)

12.1  __call__

Python中那些能够在后面加()来调用执行的对象,被称为可调用对象。可调用对象包括自定义函数、Python内置函数、实例对象和实例方法等。

call()方法是Python中一个很特殊的方法。凡是可调用对象,都可以通过调用__call__()方法来调用该对象,如果类中定义了__call__()方法,那么该类的实例对象也将成为可调用对象。该对象被调用时,将执行__call__()方法中的代码。
  1. class Person:
  2. def __call__(self,name):
  3. print("__call"+name)
  4. def hello(self,name):
  5. print("hello"+name)
  6. __call__()方法中的代码。
  7. person = Person() # 实例化
  8. person("haha") # 内置__call__ 可以直接对象名+属性,参数
  9. person.hello("xixi") #

 12.2 transforms的使用

  1. import cv2
  2. from PIL import Image
  3. from torch.utils.tensorboard import SummaryWriter
  4. from torchvision import transforms
  5. img_path = "images/5a59b02cf81e017531d1701aa6b2e66.jpg"
  6. img = Image.open(img_path)
  7. # print(img)
  8. # print(type(img)) # numpy.ndarray
  9. writer = SummaryWriter("transforms_use")
  10. # ToTensor的使用
  11. trans_totensor = transforms.ToTensor()(img)
  12. # print(type(trans_totensor)) # <class 'torch.Tensor'>
  13. writer.add_image("transforms_use",trans_totensor)
  14. writer.close()

!! img = cv2.imread(img_path)   读取的图片与原图不一致,下面输出的tensor数据也不一样

12.3 Normolize使用

  1. import cv2
  2. from PIL import Image
  3. from torch.utils.tensorboard import SummaryWriter
  4. from torchvision import transforms
  5. img_path = "images/5a59b02cf81e017531d1701aa6b2e66.jpg"
  6. img = Image.open(img_path)
  7. # img.show()
  8. print(img.mode)
  9. # print(img)
  10. # print(type(img)) # numpy.ndarray
  11. writer = SummaryWriter("use_transforms")
  12. # ToTensor的使用
  13. trans_totensor = transforms.ToTensor()(img)
  14. # print(type(trans_totensor)) # <class 'torch.Tensor'>
  15. writer.add_image("transforms_use",trans_totensor)
  16. # Normalize归一化的使用
  17. print(trans_totensor[0],[0],[0]) # 输出图像第一层的第一行第一列
  18. trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) # 图片是三通道的,每个维度都要定义均值和方差
  19. img_norm = trans_norm(trans_totensor) # Normalize a tensor image with mean and standard deviation.
  20. print(img_norm[0],[0],[0])
  21. writer.add_image("img_norm",img_norm,2)
  22. writer.close()

 看他的输出,如果transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]),均值和标准差在每个通道上都设为0.5,用数学公式看就相当于output = input*2-1,

 tensorboard的结果:

 12.4 我有疑问Image.open和cv2.imread打开不一致

img = Image.open(img_path)

img = cv2.imread(img_path)

使用PIL/Pillow的Image.open()和OpenCV的cv2.imread()打开同一张图片时,得到的图像可能会有微妙的差异。这主要有以下几个原因:

  1. 默认颜色空间不同:Image.open()默认读取RGB颜色空间的图片,cv2.imread()默认读取BGR颜色空间的图片。这会导致颜色通道的顺序不同。
  2. 默认像素值范围不同:Image.open()默认图片的像素值范围是0-255,cv2.imread()默认范围是0-255。这可能会导致像素值映射不同。
  3. 色彩模式不同:Image.open()读取的图片模式可以是RGB、RGBA、L等,cv2.imread()读取的图片只有BGR一个模式。这会导致色彩表示不同。
  4. 图像数据存储不同:Image.open()读取的图像数据存储为numpy数组,cv2.imread()读取的图像数据存储为OpenCV mat对象。尽管底层都是数组,但接口不同。
  5. 图像处理手段不同:Image.open()基于PIL/Pillow,cv2.imread()基于OpenCV。两者的图像处理函数和方法都不同。

 P13   常见的Transforms(二)

13.1 Resize()

 我的一个小报错~

UserWarning: The default value of the antialias parameter of all the resizing transforms (Resize(), RandomResizedCrop(), etc.) will change from None to True in v0.17, in order to be consistent across the PIL and Tensor backends.  To suppress this warning, directly pass antialias=True (recommended, future default), antialias=None (current default, which means False for Tensors and True for PIL), or antialias=False (only works on Tensors - PIL will still use antialiasing).  This also applies if you are using the inference transforms from the models weights: update the call to weights.transforms(antialias=True).
warnings.warn(

按照报错的提示,在resize后加上  antialias=True,就不会有UserWarning

  1. from torch.utils.tensorboard import SummaryWriter
  2. from torchvision import transforms
  3. import cv2 as cv
  4. from PIL import Image
  5. writer = SummaryWriter("img_resize")
  6. img_path = "images/5a59b02cf81e017531d1701aa6b2e66.jpg"
  7. img = Image.open(img_path)
  8. print(type(img)) # <class 'numpy.ndarray'>
  9. # resize()的使用
  10. img_tensor = transforms.ToTensor()(img) # Resize 要求图像格式为tensor
  11. print(type(img_tensor)) # <class 'torch.Tensor'>
  12. print(img.size) # 获取图像尺寸
  13. trans_resize = transforms.Resize((512,512),antialias=True) # 剪裁图像尺寸为512*512
  14. img_resize = trans_resize(img) # 讲指定图像剪裁为指定大小
  15. print(type(img_resize)) # <class 'torch.Tensor'>
  16. print(img_resize.size)

 

 更改参数会得到不同的结果:

 

 

 13.2 Compose()

compose()相当于一个transforms缝合的操作:

  1. from torch.utils.tensorboard import SummaryWriter
  2. from torchvision import transforms
  3. import cv2 as cv
  4. from PIL import Image
  5. writer = SummaryWriter("img_resize")
  6. img_path = "images/5a59b02cf81e017531d1701aa6b2e66.jpg"
  7. img = Image.open(img_path)
  8. print(type(img)) # <class 'numpy.ndarray'>
  9. # resize()的使用
  10. img_tensor = transforms.ToTensor()(img) # Resize 要求图像格式为tensor
  11. print(type(img_tensor)) # <class 'torch.Tensor'>
  12. print(img.size) # 获取图像尺寸
  13. trans_resize = transforms.Resize(512,antialias=True) # 剪裁图像尺寸为512*512
  14. img_resize = trans_resize(img) # 讲指定图像剪裁为指定大小
  15. print(type(img_resize)) # <class 'torch.Tensor'>
  16. print(img_resize.size) # (512, 512)
  17. # compose()使用 就是把很多transform的操作组合在一起执行,然后放在一个列表[]里就行
  18. trans_resize_2 = transforms.Resize(224) #Resize里只有一个参数:将短边缩放致x,长宽比保持不变
  19. # 里面的参数是列表[],数据类型是transforms 两个参数的数据类型要匹配起来
  20. # trans_resize_2输出的数据类型要和transforms.ToTensor()输入的数据类型保持一致
  21. trans_com = transforms.Compose([trans_resize_2,transforms.ToTensor()])
  22. trans_resize_2 = trans_com(img) # 传入图片
  23. print(trans_resize_2)
  24. writer.add_image("trans_compose",trans_resize_2,5)
  25. # writer.add_image("trans_compose",trans_resize_2,1)
  26. writer.close()

13.3 RandomCrop()

  1. from PIL import Image
  2. from torch.utils.tensorboard import SummaryWriter
  3. from torchvision import transforms
  4. writer = SummaryWriter("randomcrop")
  5. img_path = "images/5a59b02cf81e017531d1701aa6b2e66.jpg"
  6. img = Image.open(img_path)
  7. # randomcrop
  8. trans_randomcrop = transforms.RandomCrop(512) # 长宽都是512
  9. img_randamcrop = transforms.Compose([trans_randomcrop,transforms.ToTensor()])
  10. for i in range(10):
  11. img_rancrop = img_randamcrop(img)
  12. writer.add_image("randomcrop",img_rancrop,i) # 依次写入表名称
  13. writer.close() # 关闭时写入内存,否则它每隔120s写入一次

 !! 关注输入和输出数据类型

!!  多看官方文档

!! 关注方法需要什么参数(不知道返回值是什么数据类型的时候,print一下~)

P14 Torchvision中Dataset的使用

Datasets — Torchvision 0.15 documentation (pytorch.org)

里面有很多分类好的数据集,每个数据集都有详细的讲解

以cifar10为例:

这个数据集比较小,32*32,所以分辨率不是很高

 第一次下载的话可能会比较慢,可以运行复制下面框里的链接用迅雷下载。

  1. import torchvision
  2. from torch.utils.tensorboard import SummaryWriter
  3. from torchvision import transforms
  4. # 数据集里的每个数据都变成tensor
  5. # 更改数据集里的数据类型的时候记得一定一定改torchvision.datasets.CIFAR10(transform=dataset_transform)
  6. dataset_transform = transforms.Compose([torchvision.transforms.ToTensor()])
  7. # train=True则为训练集,train=True则为测试集,download=True从官网下载
  8. # 如果要使用官网的一些数据集,download常年设置为true
  9. train_set = torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,download=True)
  10. test_set = torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,download=False)
  11. # test_set[0]对应class里的第一个类别airplane
  12. print(test_set[0]) # (<PIL.Image.Image image mode=RGB size=32x32 at 0x2930708C7C0>, 6) 6:target
  13. print(test_set.classes) # ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
  14. img,target = test_set[0]
  15. print(img) # <PIL.Image.Image image mode=RGB size=32x32 at 0x29E418F3220>
  16. print(target) # 6
  17. print(test_set.classes[target]) # class是个列表,通过下标可以找到对应的标签类别frog
  18. img.show()
  19. print(test_set[0]) # (<PIL.Image.Image image mode=RGB size=32x32 at 0x29E433D3B80>, 6)

 用tensorboard可视化一下,完整代码如下:

!!img必须是tensor数据类型
  1. import torchvision
  2. from torch.utils.tensorboard import SummaryWriter
  3. from torchvision import transforms
  4. # 数据集里的每个数据都变成tensor
  5. # 更改数据集里的数据类型的时候记得一定一定改torchvision.datasets.CIFAR10(transform=dataset_transform)
  6. dataset_transform = transforms.Compose([torchvision.transforms.ToTensor()])
  7. # train=True则为训练集,train=True则为测试集,download=True从官网下载
  8. # 如果要使用官网的一些数据集,download常年设置为true
  9. train_set = torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,transform=dataset_transform,download=True)
  10. test_set = torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,transform=dataset_transform,download=False)
  11. writer = SummaryWriter("test_set")
  12. for i in range(10):
  13. img,target = test_set[i]
  14. writer.add_image("test_set",img,i) # i是步长,img必须是tensor数据类型
  15. # 读取的是test_set列表里对应下标的图片
  16. writer.close()

P15 Torchvision中DataLoader的使用

dataset就相当于一摞牌,dataloader就相当于如何抓取牌
# batch_size 是每次抓牌抓几张
# shuffle 每一轮结束后还要不要洗牌
# num_workers 多进程还是单进程加载数据,一般设置为0,因为可能windows下大于0的话可能会报错
# drop_last 100张牌每次取三张,最后一张牌要不要丢弃,True为不要,False为要

 

  1. import torchvision
  2. from torch.utils.data import DataLoader
  3. from torch.utils.tensorboard import SummaryWriter
  4. trans_tensor = torchvision.transforms.ToTensor()
  5. # 测试集的train=False
  6. test_data = torchvision.datasets.CIFAR10("dataset_CIFAR10",train=False,transform=trans_tensor)
  7. test_loader = DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0,drop_last=True)
  8. # CIFAR10 -> return img target
  9. # 测试数据集第一章图片及target
  10. img,target = test_data[0]
  11. print(img.shape)
  12. print(target)
  13. print(test_data.classes[target])
  14. writer = SummaryWriter("dataloader1")
  15. for epoch in range(2):
  16. step = 0 # 每一轮执行下面的子循环读取一遍数据集,shuffle=True数据就会打乱重新读
  17. for data in test_loader:
  18. imgs,targets = data
  19. # print(imgs.shape) # torch.Size([4, 3, 32, 32]) 4层,每个都是32*32有三个通道的图片
  20. # print(targets) # tensor([1, 1, 6, 5]) 这四个图片对应的target依次是1,1,6,5
  21. # writer.add_images 要+s
  22. writer.add_images("epoch:{}".format(epoch),imgs,step) # 因为已经转为tesor数据类型了,batch_size随机抓取的就在一个tensor张量里放着
  23. step = step + 1
  24. writer.close()

 P16  nn.Module的使用

 

  1. import torch
  2. from torch import nn
  3. class Haha(nn.Module):
  4. def __init__(self):
  5. super().__init__()
  6. def forward(self,input):
  7. output = input+1
  8. return output
  9. haha = Haha()
  10. x = torch.tensor(1.0)
  11. output = haha(x)
  12. print(output)

P17 浅说卷积

Torch.nn   neural network

包括Conv2d,MaxPool2d,ReLU, Linear 等等,后面会逐步介绍。

Containers: 相当于一个容器,给神经网络定义了一些骨架,给里面添加不同的内容就能组成神经网络

 Containers下面也有非常多模块,

Module:所有神经网络基本的类,基本上自己写的所有的类都需要继承它(nn.Module),相当于一个模板,你只需要修改里面的部分内容就好了,刚学习的话就需要debug看它具体每一步走到哪。

Sequential:就是可以整合所有的conv,maxpool2d放在一起,然后整体调用,和compose()的用法差不多。

练习代码~

  1. import torch
  2. import torch.nn.functional as F
  3. # 将数据类型转为tensor,然后两个中括号连着就是二维
  4. input = torch.tensor([[1,2,0,3,1],
  5. [0,1,2,3,1],
  6. [1,2,1,0,0],
  7. [5,2,3,1,1],
  8. [2,1,0,1,1]])
  9. kernel = torch.tensor([[1,2,1],
  10. [0,1,0],
  11. [2,1,0]])
  12. print(input.shape) # torch.Size([5, 5])
  13. print(kernel.shape) # torch.Size([3, 3])
  14. input1 = torch.reshape(input,(1,1,5,5)) # (1,1,5,5) -> (barch_size,channel,H,w)
  15. kernel1 = torch.reshape(kernel,(1,1,3,3)) # (1,1,5,5) -> (barch_size,channel,H,w)
  16. print(input1.shape) # torch.Size([1, 1, 5, 5])
  17. print(kernel1.shape) # torch.Size([1, 1, 3, 3])
  18. # 输出
  19. output1 = F.conv2d(input1,kernel1,stride=1)
  20. print(output1) # 因为input是4维,输出的也是4维
  21. print(output1.shape) # torch.Size([1, 1, 3, 3])
  22. print(output1.size) # <built-in method size of Tensor object at 0x000001BDE1B1AD10>
  23. output2 = F.conv2d(input1,kernel1,stride=2)
  24. print(output2) # 因为input是4维,输出的也是4维
  25. output3 = F.conv2d(input1,kernel1,stride=1,padding=1) # padding 可以避免边缘的数据只计算一次
  26. print(output3)

 输出:

  1. torch.Size([5, 5])
  2. torch.Size([3, 3])
  3. torch.Size([1, 1, 5, 5])
  4. torch.Size([1, 1, 3, 3])
  5. tensor([[[[10, 12, 12],
  6. [18, 16, 16],
  7. [13, 9, 3]]]])
  8. torch.Size([1, 1, 3, 3])
  9. <built-in method size of Tensor object at 0x000001E9FFD6D040>
  10. tensor([[[[10, 12],
  11. [13, 3]]]])
  12. tensor([[[[ 1, 3, 4, 10, 8],
  13. [ 5, 10, 12, 12, 6],
  14. [ 7, 18, 16, 16, 8],
  15. [11, 13, 9, 3, 4],
  16. [14, 13, 9, 7, 4]]]])
torch.Size括号中有几个数字就是几维      
torch.Size([1, 1, 3, 3])
tensor([[[[10, 12, 12],
          [18, 16, 16],
          [13,  9,  3]]]])
第一层(最外层)中括号里面包含了1个中括号(以逗号进行分割),这就是([1, 1, 3, 3])中的1
第二层中括号里面包含了三个中括号(以逗号进行分割),这就是([1, 1, 3, 3])中的1
第三层中括号里面包含了三个中括号(以逗号进行分割),这就是([1, 1, 3, 3])中的3
第四层中括号里面包含了三个数(以逗号进行分割),这就是([1, 1, 3, 3])中的3

P18  Conv Layers 卷积层

torch.nn.function   相当于汽车轮子齿轮的运转(更细致一点)

torch.nn                齿轮封装好,提供了一个方向盘

 这个公式还挺重要,后面出现有的网络结构,需要自己算stride和padding。。

N 代表batch_size,每次取多少张数据

minibatch:从训练数据里选出一批数据

padding:可以避免input图片边缘的数据只计算一次,padding_mode = 'zero'

kernel_size = 3: 卷积核大小是3*3

代码来咯!

  1. import torchvision.transforms
  2. from PIL.Image import Image
  3. from torch.nn import Conv2d
  4. from torch import nn
  5. from torch.utils import tensorboard
  6. from torch.utils.data import DataLoader
  7. from torch.utils.tensorboard import SummaryWriter
  8. from torchvision.transforms import transforms
  9. import torch
  10. dataset = torchvision.datasets.CIFAR10("..\CIFAR10",train=False,transform=torchvision.transforms.ToTensor(),download=True)
  11. dataloader = DataLoader(dataset,batch_size=64)
  12. class Haha(nn.Module): # 自定义类的名称不要和torch里的方法同名
  13. def __init__(self):
  14. super(Haha, self).__init__()
  15. self.conv2 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1)
  16. def forward(self,x):
  17. x = self.conv2(x)
  18. return x
  19. conv2 = Haha()
  20. print(conv2)
  21. # 神经网络里的每个图片
  22. writer = SummaryWriter("conv2d")
  23. step = 0
  24. for data in dataloader:
  25. imgs,targets = data #totensor
  26. output = conv2(imgs) # 前面已经实例化过了,直接用就行,不要再用类名称了
  27. print(imgs.shape)
  28. print(output.shape) # torch.Size([64, 6, 30, 30]) 6个通道不知道在tensorboard里怎么显示
  29. output = torch.reshape(output, (-1, 3, 30, 30)) # 不知道batch_size是什么就写-1,会根据后面的值自己计算, 通道数变少相当于平铺了,batch_size变多了
  30. writer.add_images("conv2_output", output, step)
  31. step += 1
  32. writer.close()
  33. # 通道数可以根据官方文档里的公式推导出来
  34. # 长宽不变,通道数变多可能kernel_num 变多了

输出:

  1. Haha(
  2. (conv2): Conv2d(3, 6, kernel_size=(3, 3), stride=(1, 1))
  3. )
  4. torch.Size([64, 3, 32, 32])
  5. torch.Size([64, 6, 30, 30])
  6. torch.Size([64, 3, 32, 32])
  7. torch.Size([64, 6, 30, 30])
  8. torch.Size([64, 3, 32, 32])
  9. torch.Size([64, 6, 30, 30])

P23 损失函数与反向传播

23.1 损失函数

23.1.1  torch.nn.L1Loss

损失函数当然越小越好

① 计算实际输出与目标输出的差距

② 为我们更新提供一定的依据(反向传播)

torch.nn.L1Loss

输入x:1,2,3       目标y:1,2,5

L1Loss:\frac{1-1+2-2+5-3}{3}​=0.667(保留三位小数)

23.1.2  torch.nn.MSELoss 均方误差

 

公式很好懂,shape也没啥子要注意的地方

23.1.3 torch.nn.CrossEntropyLoss 交叉熵

官网的公式太难懂了。。。

信息量:一个时间发生的可能性越小,信息量就越大

熵:信息量的期望值(所有取值二点信息量的期望)

      一个随机变量的取值越不确定,熵越大,反之越小。

交叉熵: 两个概率分布之间的距离 = 通过概率分布q来表达gail分布p的困难程度

       p为正确答案,q代表的是预测值,交叉熵越小,2个概率分布越接近 

这部分一般要先经过softmax一下,使神经网络的输出变为一个概率分布,再使用交叉熵来计算预测的概率分布和真实值概率分布之间的距离。

 上图来自B站up主霹雳吧啦Wz图像处理篇课件~

这三部分的代码如下:

  1. import torch
  2. from torch.nn import L1Loss, MSELoss, CrossEntropyLoss
  3. inputs = torch.tensor([1, 2, 3], dtype=torch.float32) # input里的数据类型都是int,不含long,会报错
  4. targets = torch.tensor([1, 2, 5], dtype=torch.float32)
  5. inputs = torch.reshape(inputs, (1, 1, 1, 3))
  6. targets = torch.reshape(targets, (1, 1, 1, 3))
  7. # loss = L1Loss(reduction='sum') # 就是把每个部分的误差加起来 tensor(2.)
  8. loss = L1Loss(reduction='mean') # 每部分误差的平均数,和默认不写是一样的 tensor(0.6667)
  9. r = loss(inputs, targets)
  10. print(r)
  11. # 均方误差
  12. loss_mseloss = MSELoss() # 就是给每一项的差值平方和/总个数
  13. result = loss_mseloss(inputs, targets) # tensor(1.3333)
  14. print(result)
  15. # 交叉熵
  16. x = torch.tensor([0.1, 0.2, 0.3])
  17. y = torch.tensor([1]) # 这里必须是tensor数据类型
  18. x = torch.reshape(x, (1, 3))
  19. loss_cross = CrossEntropyLoss()
  20. result2 = loss_cross(x, y)
  21. print(result2) # tensor(1.1019)

输出:

  1. tensor(0.6667)
  2. tensor(1.3333)
  3. tensor(1.1019)

23.2 反向传播

反向传播:尝试如何调整参数才会导致最终的Loss变小。

从loss开始推到参数,和网络的顺序相反,所以是反向传播。

梯度就是求导,比如在某个点让他沿着梯度方向下降,就会达到loss最小值。

  1. import torch
  2. import torchvision
  3. from torch import nn
  4. from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear, CrossEntropyLoss
  5. from torch.utils.data import DataLoader
  6. from torch.utils.tensorboard import SummaryWriter
  7. dataset = torchvision.datasets.CIFAR10("cifar10",train=False,download=True,
  8. transform=torchvision.transforms.ToTensor())
  9. dataloader = DataLoader(dataset, batch_size=1)
  10. class Haha(nn.Module):
  11. def __init__(self) -> None:
  12. super().__init__()
  13. self.model = Sequential(
  14. Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
  15. MaxPool2d(2),
  16. Conv2d(in_channels=32,out_channels=32,kernel_size=5,stride=1,padding=2),
  17. MaxPool2d(2),
  18. Conv2d(in_channels=32,out_channels=64,kernel_size=5,stride=1,padding=2),
  19. MaxPool2d(2),
  20. Flatten(),
  21. Linear(1024,64),
  22. Linear(64,10)
  23. )
  24. def forward(self,x):
  25. x = self.model(x)
  26. return x
  27. # 计算实际输出和目标之间的差距
  28. haha = Haha()
  29. loss = CrossEntropyLoss()
  30. for data in dataloader:
  31. imgs, targets = data
  32. # print(imgs)
  33. # print(targets)
  34. outputs = haha(imgs) # 先把这个东西放进模型里跑一趟啊,不跑哪来的损失函数
  35. result = loss(outputs,targets)
  36. result.backward() # 反向传播,运行这一行之前,grad = None,运行了之后就会有数值
  37. print(result) # tensor(2.3552, grad_fn=<NllLossBackward0>)某一步的结果

 输出部分结果为:

  1. tensor(2.1898, grad_fn=<NllLossBackward0>)
  2. tensor(2.3114, grad_fn=<NllLossBackward0>)
  3. tensor(2.3232, grad_fn=<NllLossBackward0>)
  4. tensor(2.3348, grad_fn=<NllLossBackward0>)
  5. tensor(2.4124, grad_fn=<NllLossBackward0>)
  6. tensor(2.4264, grad_fn=<NllLossBackward0>)
  7. tensor(2.3046, grad_fn=<NllLossBackward0>)
  8. tensor(2.4234, grad_fn=<NllLossBackward0>)


p24  优化器

根据损失梯度进行参数调整,达到降低loss的目的,整体思想就是input数据进模型里跑一趟,输出output,通过上节的损失函数计算损失梯度,loss.backward()进行反向传播,optim.step()每个参数进行调优,循环里每次的梯度都不相关,所以每一次调节都要清零optim.zero_grad()

如果只训练一轮,就是说数据集里所有的数据都只看了一次,通常需要训练上千上万轮,初学阶段仅以20轮为例,将每一轮所有损失和相加,可以看到loss在降低。

选择合适的优化器,只需要设置模型参数和学习率即可,后面的先采用默认值,若训练模型有需要再自行设置,学习率lr设置太大不稳定,太小训练速度又很慢,所以一般训练刚开始设置大一点,后面再调小。

  1. import torch
  2. import torchvision
  3. from torch import nn
  4. from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear, CrossEntropyLoss
  5. from torch.optim import optimizer
  6. from torch.utils.data import DataLoader
  7. from torch.utils.tensorboard import SummaryWriter
  8. dataset = torchvision.datasets.CIFAR10("cifar10",train=False,download=True,
  9. transform=torchvision.transforms.ToTensor())
  10. dataloader = DataLoader(dataset, batch_size=64)
  11. class Haha(nn.Module):
  12. def __init__(self) -> None:
  13. super().__init__()
  14. self.model = Sequential(
  15. Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
  16. MaxPool2d(2),
  17. Conv2d(in_channels=32,out_channels=32,kernel_size=5,stride=1,padding=2),
  18. MaxPool2d(2),
  19. Conv2d(in_channels=32,out_channels=64,kernel_size=5,stride=1,padding=2),
  20. MaxPool2d(2),
  21. Flatten(),
  22. Linear(1024,64),
  23. Linear(64,10)
  24. )
  25. def forward(self,x):
  26. x = self.model(x)
  27. return x
  28. haha = Haha()
  29. loss_cross = CrossEntropyLoss()
  30. # 选择合适的优化器,并设置模型参数和学习率(lr)
  31. # 学习速率不能设置的太大(训练过程会很不稳定),也不能设置的太小(模型训练会比较慢)
  32. # 一般训练过程刚开始lr会设置的比较大,后面会设置的比较小。
  33. optim = torch.optim.SGD(haha.parameters(), lr=0.01) # 其他的参数先用默认的
  34. for epoch in range(20):
  35. running_loss = 0.0 # 整体误差求和
  36. for data in dataloader: # 所有的数据只看了一次,所以要进行多轮训练
  37. imgs, targets = data # 依次读取数据
  38. output = haha(imgs) # 把读取的数据放进自己的模型里跑一趟
  39. result_loss = loss_cross(output, targets) # 获得损失函数
  40. optim.zero_grad() # 网络模型中每个可以调节参数的对应梯度设为0
  41. result_loss.backward() # 优化器要对其中的参数进行优化,需要每个参数的梯度,所以要用反向传播
  42. optim.step() # 每个参数进行调优,且循环里每次的梯度都不相关,所以每一次调节都要清零
  43. running_loss =running_loss + result_loss
  44. print(running_loss) # 每一轮学习过程中,整体误差的总和

输出:

  1. Files already downloaded and verified
  2. tensor(360.8012, grad_fn=<AddBackward0>)
  3. tensor(357.8290, grad_fn=<AddBackward0>)
  4. tensor(347.7727, grad_fn=<AddBackward0>)
  5. tensor(322.9131, grad_fn=<AddBackward0>)
  6. tensor(311.0620, grad_fn=<AddBackward0>)
  7. tensor(301.3166, grad_fn=<AddBackward0>)
  8. tensor(291.4036, grad_fn=<AddBackward0>)
  9. tensor(283.9122, grad_fn=<AddBackward0>)
  10. tensor(276.8408, grad_fn=<AddBackward0>)
  11. tensor(270.4795, grad_fn=<AddBackward0>)
  12. tensor(264.6440, grad_fn=<AddBackward0>)
  13. tensor(259.1889, grad_fn=<AddBackward0>)
  14. tensor(254.0679, grad_fn=<AddBackward0>)
  15. tensor(249.3576, grad_fn=<AddBackward0>)
  16. tensor(245.0429, grad_fn=<AddBackward0>)
  17. tensor(241.1004, grad_fn=<AddBackward0>)
  18. tensor(237.3984, grad_fn=<AddBackward0>)
  19. tensor(233.8950, grad_fn=<AddBackward0>)
  20. tensor(230.5357, grad_fn=<AddBackward0>)
  21. tensor(227.2878, grad_fn=<AddBackward0>)

可以打断点观察module -> weight data和grad的变化:

刚开始data从dataloader里取值,grad = 0,经过一次result_loss.backward(),会计算出新的梯度值grad,每次经过一个新的循环,data重新取值,optim.zero_grad()将梯度置为0,再重新计算grad值。

P25 现有模型修改(vgg16为例)

25.1 vgg16

pretrained:是否与训练,pretrained=true,网络模型的参数在数据集上已经训练好了,pretrained=flase,使用的就是初始化的参数。

progress:是否在运行的框下面显示进度条,progress=true显示,progress=flase不显示

25.2 imagenet

 有15000张图片,然后分为1000个类别

本来想和之前一样,用cifar10验证一下相关的数据集,但是用之前的方法已经无法在pytorch里直接下载了,太大了,有需要的可以去官网直接下载放在相关文件路径下面。

这几个参数也比较熟悉了

root:文件存放路径

spilt:spilt = ‘train’ 为训练集

transform :把数据集里的数据转为tensor类型

target_transform: 把目标的数据转为ensor数据类型

loader:在给定路径下加载数据

  1. import torchvision
  2. from torch import nn
  3. # dataset = torchvision.datasets.imagenet("imagenet",split='train' ) 已经非公开了,需要自己下载
  4. # pretain就是是否预训练
  5. vgg16_false = torchvision.models.vgg16(pretrained=False) # 加载网络模型,就像之前写的cifar10的那个代码,其中的参数就是默认的,不用下载
  6. vgg16_true = torchvision.models.vgg16(pretrained=True) # 就要去下载比如卷积层,池化层的参数,在imgenet里训练好的
  7. print("okk")
  8. vgg16_true.add_module('new_linear',nn.Linear(1000,10)) # 加在vgg_16的框架下
  9. vgg16_true.classifier.add_module('new_linear',nn.Linear(1000,10)) # 加在vgg_16.classifier下面
  10. print(vgg16_true)
  11. vgg16_false.classifier[6] = nn.Linear(in_features=4096,out_features=10) # 可以直接修改某一层的输入和输出
  12. print(vgg16_false)

输出:

  1. okk
  2. VGG(
  3. (features): Sequential(
  4. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  5. (1): ReLU(inplace=True)
  6. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  7. (3): ReLU(inplace=True)
  8. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  9. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  10. (6): ReLU(inplace=True)
  11. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  12. (8): ReLU(inplace=True)
  13. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  14. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  15. (11): ReLU(inplace=True)
  16. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  17. (13): ReLU(inplace=True)
  18. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  19. (15): ReLU(inplace=True)
  20. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  21. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  22. (18): ReLU(inplace=True)
  23. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  24. (20): ReLU(inplace=True)
  25. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  26. (22): ReLU(inplace=True)
  27. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  28. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  29. (25): ReLU(inplace=True)
  30. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  31. (27): ReLU(inplace=True)
  32. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  33. (29): ReLU(inplace=True)
  34. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  35. )
  36. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  37. (classifier): Sequential(
  38. (0): Linear(in_features=25088, out_features=4096, bias=True)
  39. (1): ReLU(inplace=True)
  40. (2): Dropout(p=0.5, inplace=False)
  41. (3): Linear(in_features=4096, out_features=4096, bias=True)
  42. (4): ReLU(inplace=True)
  43. (5): Dropout(p=0.5, inplace=False)
  44. (6): Linear(in_features=4096, out_features=1000, bias=True)
  45. )
  46. )
  47. VGG(
  48. (features): Sequential(
  49. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  50. (1): ReLU(inplace=True)
  51. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  52. (3): ReLU(inplace=True)
  53. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  54. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  55. (6): ReLU(inplace=True)
  56. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  57. (8): ReLU(inplace=True)
  58. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  59. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  60. (11): ReLU(inplace=True)
  61. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  62. (13): ReLU(inplace=True)
  63. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  64. (15): ReLU(inplace=True)
  65. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  66. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  67. (18): ReLU(inplace=True)
  68. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  69. (20): ReLU(inplace=True)
  70. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  71. (22): ReLU(inplace=True)
  72. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  73. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  74. (25): ReLU(inplace=True)
  75. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  76. (27): ReLU(inplace=True)
  77. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  78. (29): ReLU(inplace=True)
  79. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  80. )
  81. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  82. (classifier): Sequential(
  83. (0): Linear(in_features=25088, out_features=4096, bias=True)
  84. (1): ReLU(inplace=True)
  85. (2): Dropout(p=0.5, inplace=False)
  86. (3): Linear(in_features=4096, out_features=4096, bias=True)
  87. (4): ReLU(inplace=True)
  88. (5): Dropout(p=0.5, inplace=False)
  89. (6): Linear(in_features=4096, out_features=1000, bias=True)
  90. (new_linear): Linear(in_features=1000, out_features=10, bias=True)
  91. )
  92. (new_linear): Linear(in_features=1000, out_features=10, bias=True)
  93. )
  94. VGG(
  95. (features): Sequential(
  96. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  97. (1): ReLU(inplace=True)
  98. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  99. (3): ReLU(inplace=True)
  100. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  101. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  102. (6): ReLU(inplace=True)
  103. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  104. (8): ReLU(inplace=True)
  105. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  106. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  107. (11): ReLU(inplace=True)
  108. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  109. (13): ReLU(inplace=True)
  110. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  111. (15): ReLU(inplace=True)
  112. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  113. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  114. (18): ReLU(inplace=True)
  115. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  116. (20): ReLU(inplace=True)
  117. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  118. (22): ReLU(inplace=True)
  119. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  120. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  121. (25): ReLU(inplace=True)
  122. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  123. (27): ReLU(inplace=True)
  124. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  125. (29): ReLU(inplace=True)
  126. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  127. )
  128. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  129. (classifier): Sequential(
  130. (0): Linear(in_features=25088, out_features=4096, bias=True)
  131. (1): ReLU(inplace=True)
  132. (2): Dropout(p=0.5, inplace=False)
  133. (3): Linear(in_features=4096, out_features=4096, bias=True)
  134. (4): ReLU(inplace=True)
  135. (5): Dropout(p=0.5, inplace=False)
  136. (6): Linear(in_features=4096, out_features=10, bias=True)
  137. )
  138. )
  139. 进程已结束,退出代码0

P26 模型的保存与加载

26.1 模型的保存

方法一:保存模型的结构和参数

  1. import torch
  2. import torchvision
  3. vgg16 = torchvision.models.vgg16(pretrained=False) # 获取网络模型
  4. # 保存方式1 保存模型结构+参数
  5. torch.save(vgg16,"vgg16_method1.pth")

方法二:以字典的形式只保存了模型的参数

  1. import torch
  2. import torchvision
  3. # 保存方式2,模型参数(官方推荐,空间会稍微小一点)
  4. torch.save(vgg16.state_dict(),"vgg16_method2.pth") # 保存为一种字典形式

不管是那种方法,左边文件会以命名方式保存

26.2  数据的加载:

26.2.1 以方法一加载: 

  1. import torch
  2. import torchvision
  3. # 保存方式1 -> 模型加载1
  4. model = torch.load("vgg16_method1.pth")
  5. print(model)

输出:

  1. VGG(
  2. (features): Sequential(
  3. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  4. (1): ReLU(inplace=True)
  5. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  6. (3): ReLU(inplace=True)
  7. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  8. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  9. (6): ReLU(inplace=True)
  10. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  11. (8): ReLU(inplace=True)
  12. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  13. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  14. (11): ReLU(inplace=True)
  15. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  16. (13): ReLU(inplace=True)
  17. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  18. (15): ReLU(inplace=True)
  19. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  20. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  21. (18): ReLU(inplace=True)
  22. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  23. (20): ReLU(inplace=True)
  24. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  25. (22): ReLU(inplace=True)
  26. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  27. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  28. (25): ReLU(inplace=True)
  29. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  30. (27): ReLU(inplace=True)
  31. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  32. (29): ReLU(inplace=True)
  33. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  34. )
  35. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  36. (classifier): Sequential(
  37. (0): Linear(in_features=25088, out_features=4096, bias=True)
  38. (1): ReLU(inplace=True)
  39. (2): Dropout(p=0.5, inplace=False)
  40. (3): Linear(in_features=4096, out_features=4096, bias=True)
  41. (4): ReLU(inplace=True)
  42. (5): Dropout(p=0.5, inplace=False)
  43. (6): Linear(in_features=4096, out_features=1000, bias=True)
  44. )
  45. )

26.1.1 方法一存在缺陷:

如果不是网络现有的模型,是自己写的模型的话,加载模型所在目录就会出现报错:

自己的模型及保存文件格式为:

  1. import torch
  2. from torch import nn
  3. from torch.nn import Conv2d
  4. class Haha(nn.Module):
  5. def __init__(self) -> None:
  6. super().__init__()
  7. self.conv1 = Conv2d(in_channels=3,out_channels=32,kernel_size=5)
  8. def forward(self, x):
  9. x = self.conv1(x)
  10. return x
  11. haha = Haha()
  12. torch.save(haha, "haha.pth") # haha.pth为保存路径

新建python文件:

  1. import torch
  2. model = torch.load("haha.pth")
  3. print(model)

会出现报错

解决方法为:

  • 把自己写的网络模型class类在加载页面再复制一次

  1. import torch
  2. from torch import nn
  3. from torch.nn import Conv2d
  4. class Haha(nn.Module):
  5. def __init__(self) -> None:
  6. super().__init__()
  7. self.conv1 = Conv2d(in_channels=3,out_channels=32,kernel_size=5)
  8. def forward(self, x):
  9. x = self.conv1(x)
  10. return x
  11. model = torch.load("haha.pth")
  12. print(model)

  • from model_save import *
    
  1. from model_save import *
  2. model = torch.load("haha.pth")
  3. print(model)

输出结果如上

26.2.2  以方法二加载

  1. import torch
  2. import torchvision
  3. # 保存方式2 -> 模型加载2
  4. model = torch.load("vgg16_method2.pth")
  5. print(model)

输出的还是字典形式:

  1. OrderedDict([('features.0.weight', tensor([[[[-0.0323, 0.0177, 0.0042],
  2. [-0.0171, -0.0156, 0.0780],
  3. [-0.0617, 0.0712, -0.0670]],
  4. [[ 0.0193, -0.0177, 0.0217],
  5. [ 0.0202, 0.0395, -0.0228],
  6. [ 0.0152, -0.0815, 0.0166]],
  7. [[ 0.0769, -0.0474, 0.0711],
  8. [ 0.0329, -0.0049, -0.0085],
  9. [ 0.0684, -0.0518, 0.0332]]],

把保存为字典型的恢复为网络模型:

  1. import torch
  2. import torchvision
  3. # 保存方式2 -> 模型加载2
  4. vgg16 = torchvision.models.vgg16(pretrained=False) # 打开模型
  5. vgg16.load_state_dict(torch.load("vgg16_method2.pth")) # 加载vgg16原来的状态
  6. # model = torch.load("vgg16_method2.pth") # 获得的就是字典形式
  7. print(vgg16)

输出的结果为:

  1. VGG(
  2. (features): Sequential(
  3. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  4. (1): ReLU(inplace=True)
  5. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  6. (3): ReLU(inplace=True)
  7. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  8. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  9. (6): ReLU(inplace=True)
  10. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  11. (8): ReLU(inplace=True)
  12. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  13. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  14. (11): ReLU(inplace=True)
  15. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  16. (13): ReLU(inplace=True)
  17. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  18. (15): ReLU(inplace=True)
  19. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  20. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  21. (18): ReLU(inplace=True)
  22. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  23. (20): ReLU(inplace=True)
  24. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  25. (22): ReLU(inplace=True)
  26. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  27. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  28. (25): ReLU(inplace=True)
  29. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  30. (27): ReLU(inplace=True)
  31. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  32. (29): ReLU(inplace=True)
  33. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  34. )
  35. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  36. (classifier): Sequential(
  37. (0): Linear(in_features=25088, out_features=4096, bias=True)
  38. (1): ReLU(inplace=True)
  39. (2): Dropout(p=0.5, inplace=False)
  40. (3): Linear(in_features=4096, out_features=4096, bias=True)
  41. (4): ReLU(inplace=True)
  42. (5): Dropout(p=0.5, inplace=False)
  43. (6): Linear(in_features=4096, out_features=1000, bias=True)
  44. )
  45. )
  46. 进程已结束,退出代码0

P 27 完整的训练套路(一)

27.1 训练套路总结

  1. 创建dataset数据集,分为训练集和测试集
  2. 用dataloader进行数据加载
  3. 用len()查看数据集长度,比如cifar10 训练集和测试集各有多少张图片
  4. 自己写的模型model  model文件和train文件要在同一个目录下,from model import *
  5. 写损失函数  loss
  6. 选择合适的优化器
  7. 设置网络训练参数
  8. 调用haha.train()让网络进入训练状态(传数据,过模型得到output,loss,梯度置零,反向传播,打印~)
  9. 测试步骤开始haha.eval()   with torch.no_grad()测试不需要对梯度进行调整,也不需要进行优化(取数据,过模型,得误差,得准确率)
  10. 展示效果(tensorboard     print      torch.save()

采用cifar 10模型

27.2 modoel文件:

  1. import torch
  2. from torch import nn
  3. class Haha(nn.Module):
  4. def __init__(self) -> None:
  5. super().__init__()
  6. self.model = nn.Sequential(
  7. nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
  8. nn.MaxPool2d(2),
  9. nn.Conv2d(in_channels=32,out_channels=32,kernel_size=5,stride=1,padding=2),
  10. nn.MaxPool2d(2),
  11. nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),
  12. nn.MaxPool2d(2),
  13. nn.Flatten(),
  14. nn.Linear(64*4*4, 64),
  15. nn.Linear(64, 10)
  16. )
  17. def forward(self, x):
  18. x = self.model(x)
  19. return x
  20. # 验证自己的模型是否正确
  21. if __name__ == '__main__':
  22. haha = Haha()
  23. input = torch.ones((64, 3, 32, 32))
  24. output = haha(input)
  25. print(output.shape)

 27.3 train文件夹:

  1. import torch
  2. import torchvision
  3. from torch import nn
  4. from torch.utils.data import DataLoader
  5. from model import *
  6. # 选择gpu跑数据
  7. device = torch.device("cuda")
  8. print(device)
  9. # 准备数据集
  10. dataset_train = torchvision.datasets.CIFAR10("cifar10",train=True,download=True,transform=torchvision.transforms.ToTensor())
  11. dataset_test = torchvision.datasets.CIFAR10("cifar10",train=False,download=True,transform=torchvision.transforms.ToTensor())
  12. dataloader = DataLoader(dataset_train, batch_size=64)
  13. # 查看数据长度
  14. train_len = len(dataset_train)
  15. test_len = len(dataset_test)
  16. print("训练集的长度为:{}".format(train_len))
  17. print("测试集的长度为:{}".format(test_len))
  18. # 创建模型:
  19. haha = Haha()
  20. haha = haha.to(device)
  21. # 损失函数
  22. loss = nn.CrossEntropyLoss()
  23. loss = loss.to(device)
  24. # 优化器
  25. optim = torch.optim.SGD(haha.parameters(), lr=1e-2)
  26. # 参数准备:
  27. epoch = 20
  28. # 反向传播
  29. for i in range(epoch):
  30. print("-----第{}轮训练开始-----".format(i+1))
  31. running_loss = 0.0
  32. for data in dataloader:
  33. imgs, targets = data
  34. imgs = imgs.to(device)
  35. targets = targets.to(device)
  36. outputs = haha(imgs)
  37. result_loss = loss(outputs, targets)
  38. # 优化器优化模型
  39. optim.zero_grad()
  40. result_loss.backward()
  41. optim.step()
  42. running_loss = running_loss + result_loss
  43. print(running_loss)

输出结果为:

  1. cuda
  2. Files already downloaded and verified
  3. Files already downloaded and verified
  4. 训练集的长度为:50000
  5. 测试集的长度为:10000
  6. -----第1轮训练开始-----
  7. tensor(1700.0593, device='cuda:0', grad_fn=<AddBackward0>)
  8. -----第2轮训练开始-----
  9. tensor(1440.8804, device='cuda:0', grad_fn=<AddBackward0>)
  10. -----第3轮训练开始-----
  11. tensor(1288.2825, device='cuda:0', grad_fn=<AddBackward0>)
  12. -----第4轮训练开始-----
  13. tensor(1199.8562, device='cuda:0', grad_fn=<AddBackward0>)
  14. -----第5轮训练开始-----
  15. tensor(1141.1815, device='cuda:0', grad_fn=<AddBackward0>)
  16. -----第6轮训练开始-----
  17. tensor(1089.9484, device='cuda:0', grad_fn=<AddBackward0>)
  18. -----第7轮训练开始-----
  19. tensor(1041.3491, device='cuda:0', grad_fn=<AddBackward0>)
  20. -----第8轮训练开始-----
  21. tensor(995.0281, device='cuda:0', grad_fn=<AddBackward0>)
  22. -----第9轮训练开始-----
  23. tensor(950.4661, device='cuda:0', grad_fn=<AddBackward0>)
  24. -----第10轮训练开始-----
  25. tensor(908.3196, device='cuda:0', grad_fn=<AddBackward0>)
  26. -----第11轮训练开始-----
  27. tensor(870.1450, device='cuda:0', grad_fn=<AddBackward0>)
  28. -----第12轮训练开始-----
  29. tensor(836.3250, device='cuda:0', grad_fn=<AddBackward0>)
  30. -----第13轮训练开始-----
  31. tensor(806.3509, device='cuda:0', grad_fn=<AddBackward0>)
  32. -----第14轮训练开始-----
  33. tensor(779.3769, device='cuda:0', grad_fn=<AddBackward0>)
  34. -----第15轮训练开始-----
  35. tensor(754.8840, device='cuda:0', grad_fn=<AddBackward0>)
  36. -----第16轮训练开始-----
  37. tensor(731.9321, device='cuda:0', grad_fn=<AddBackward0>)
  38. -----第17轮训练开始-----
  39. tensor(710.3835, device='cuda:0', grad_fn=<AddBackward0>)
  40. -----第18轮训练开始-----
  41. tensor(690.2420, device='cuda:0', grad_fn=<AddBackward0>)
  42. -----第19轮训练开始-----
  43. tensor(671.0947, device='cuda:0', grad_fn=<AddBackward0>)
  44. -----第20轮训练开始-----
  45. tensor(652.6206, device='cuda:0', grad_fn=<AddBackward0>)
  46. 进程已结束,退出代码0

P28  完整的训练套路(二)

28.1  准确率

准确率 = 所有预测对的图片/测试集图片总个数

具体的实现思路需要调用一下argmax函数

argmax()是可以获取输出的outpu最大概率类别所在的位置

28.1.1 预测正确率代码(argmax使用)

  1. import torch
  2. # 就相当于输入两张图片,outputs输出预测第一章图片是0类别的概率是0.1,是1类别的概率是0.2
  3. pic_sum = 2
  4. outputs = torch.tensor([[0.1, 0.2],
  5. [0.3, 0.4]])
  6. print(outputs.argmax(1)) # argmax(0)横向看,argmax(1)纵向看,tensor([1, 1]) 说明output输出的两个都是1类别
  7. predict = outputs.argmax(1)
  8. targets = torch.tensor([0, 1]) # 给定目标种类,第一个是0类别, 第二个是1类别
  9. accuracy = (predict == targets).sum() # 预测正确的个数有多少
  10. print(accuracy)
  11. print("准确率为:{}".format(accuracy/pic_sum)) # 准确率= 正确预测个数/总图片个数

 28.2 完整的代码:

我的cpu跑不动,借用了一下后面用gpu训练的部分内容

  1. import torch
  2. import torchvision
  3. from torch import nn
  4. from torch.utils.data import DataLoader
  5. from torch.utils.tensorboard import SummaryWriter
  6. from model import *
  7. # 使用cuda训练数据
  8. device = torch.device("cuda")
  9. print(device)
  10. # 准备数据集
  11. dataset_train = torchvision.datasets.CIFAR10("cifar10",train=True,download=True,transform=torchvision.transforms.ToTensor())
  12. dataset_test = torchvision.datasets.CIFAR10("cifar10",train=False,download=True,transform=torchvision.transforms.ToTensor())
  13. dataloader_train = DataLoader(dataset_train, batch_size=64)
  14. dataloader_test = DataLoader(dataset_test, batch_size=64)
  15. # 查看数据长度
  16. train_len = len(dataset_train)
  17. test_len = len(dataset_test)
  18. print("训练集的长度为:{}".format(train_len))
  19. print("测试集的长度为:{}".format(test_len))
  20. # 创建模型:
  21. haha = Haha()
  22. haha = haha.to(device)
  23. # 损失函数
  24. loss = nn.CrossEntropyLoss()
  25. loss = loss.to(device)
  26. # 优化器
  27. optim = torch.optim.SGD(haha.parameters(), lr=1e-2)
  28. # 用tensorboard画图咯
  29. writer = SummaryWriter("logs_train")
  30. # 训练开始
  31. # 参数准备:
  32. epoch = 20
  33. global_step = 1
  34. for i in range(epoch):
  35. print("-----第{}轮训练开始-----".format(i+1))
  36. step = 1
  37. # 计算损失函数
  38. for data in dataloader_train:
  39. imgs, targets = data
  40. imgs = imgs.to(device)
  41. targets = targets.to(device)
  42. outputs = haha(imgs)
  43. result_loss = loss(outputs, targets)
  44. # 优化器优化模型
  45. optim.zero_grad()
  46. result_loss.backward()
  47. optim.step()
  48. # 训练轮数逢百打印
  49. if step % 100 == 0:
  50. print("训练次数:{}次,损失为:{},".format(step, result_loss.item())) # item()
  51. writer.add_scalar("train_result_loss", result_loss,step)
  52. step += 1
  53. # 测试步骤开始
  54. running_loss = 0
  55. total_accuracy_test = 0
  56. with torch.no_grad(): # 新增的tensor没有梯度,使带梯度的tensor能够进行原地运算。
  57. for data in dataloader_test:
  58. imgs, targets = data
  59. imgs = imgs.to(device)
  60. targets = targets.to(device)
  61. outputs = haha(imgs)
  62. result_loss = loss(outputs, targets) # 该loss为部分数据在网络模型上的损失,为tensor数据类型
  63. # 求整体测试数据集上的误差
  64. running_loss = running_loss + result_loss.item() # result_loss为tensor数据类型,running_loss为
  65. # 求整体测试集上的正确率
  66. accuracy = (outputs.argmax(1) == targets).sum()
  67. total_accuracy_test = total_accuracy_test + accuracy
  68. print("第{}轮 总损失为:{}".format(global_step, running_loss))
  69. writer.add_scalar("train_running_loss", running_loss, global_step)
  70. print("第{}轮 准确率为:{}".format(global_step, total_accuracy_test/test_len))
  71. writer.add_scalar("total_accuracy", total_accuracy_test, global_step)
  72. global_step += 1
  73. # 保存每一轮的模型
  74. model = torch.save(haha,"haha_train_moedl{}.pth".format(i+1))
  75. print("第{}轮的模型已保存".format(i+1))
  76. writer.close()

输出保存模型在左侧目录显示为:

  1. cuda
  2. Files already downloaded and verified
  3. Files already downloaded and verified
  4. 训练集的长度为:50000
  5. 测试集的长度为:10000
  6. -----第1轮训练开始-----
  7. 训练次数:100次,损失为:2.2931113243103027
  8. 训练次数:200次,损失为:2.284919500350952
  9. 训练次数:300次,损失为:2.2788472175598145
  10. 训练次数:400次,损失为:2.2056031227111816
  11. 训练次数:500次,损失为:2.0810277462005615
  12. 训练次数:600次,损失为:2.0361318588256836
  13. 训练次数:700次,损失为:2.022759437561035
  14. 1轮 总损失为:317.60839223861694
  15. 1轮 准确率为:0.27410000562667847
  16. 1轮的模型已保存
  17. -----第2轮训练开始-----
  18. 训练次数:100次,损失为:2.0008018016815186
  19. 训练次数:200次,损失为:1.9731968641281128
  20. 训练次数:300次,损失为:1.9332154989242554
  21. 训练次数:400次,损失为:1.8408057689666748
  22. 训练次数:500次,损失为:1.8841831684112549
  23. 训练次数:600次,损失为:1.8792617321014404
  24. 训练次数:700次,损失为:1.8609519004821777
  25. 2轮 总损失为:300.46228551864624
  26. 2轮 准确率为:0.3188000023365021
  27. 2轮的模型已保存
  28. -----第3轮训练开始-----
  29. 训练次数:100次,损失为:1.7655715942382812
  30. 训练次数:200次,损失为:1.760992407798767
  31. 训练次数:300次,损失为:1.7241920232772827
  32. 训练次数:400次,损失为:1.6210854053497314
  33. 训练次数:500次,损失为:1.7465519905090332
  34. 训练次数:600次,损失为:1.7013258934020996
  35. 训练次数:700次,损失为:1.7307485342025757
  36. 3轮 总损失为:267.0808128118515
  37. 3轮 准确率为:0.3837999999523163
  38. 3轮的模型已保存
  39. -----第4轮训练开始-----
  40. 训练次数:100次,损失为:1.5298057794570923
  41. 训练次数:200次,损失为:1.604145884513855
  42. 训练次数:300次,损失为:1.5831634998321533
  43. 训练次数:400次,损失为:1.4993634223937988
  44. 训练次数:500次,损失为:1.5525864362716675
  45. 训练次数:600次,损失为:1.5678906440734863
  46. 训练次数:700次,损失为:1.6980340480804443
  47. 4轮 总损失为:267.1874620914459
  48. 4轮 准确率为:0.3865000009536743
  49. 4轮的模型已保存
  50. -----第5轮训练开始-----
  51. 训练次数:100次,损失为:1.3614977598190308
  52. 训练次数:200次,损失为:1.4923309087753296
  53. 训练次数:300次,损失为:1.501603126525879
  54. 训练次数:400次,损失为:1.4064840078353882
  55. 训练次数:500次,损失为:1.4037704467773438
  56. 训练次数:600次,损失为:1.4647917747497559
  57. 训练次数:700次,损失为:1.6546450853347778
  58. 5轮 总损失为:254.799556016922
  59. 5轮 准确率为:0.4179999828338623
  60. 5轮的模型已保存
  61. -----第6轮训练开始-----
  62. 训练次数:100次,损失为:1.2472984790802002
  63. 训练次数:200次,损失为:1.3790236711502075
  64. 训练次数:300次,损失为:1.4547381401062012
  65. 训练次数:400次,损失为:1.3174049854278564
  66. 训练次数:500次,损失为:1.2885082960128784
  67. 训练次数:600次,损失为:1.3783830404281616
  68. 训练次数:700次,损失为:1.5873558521270752
  69. 6轮 总损失为:241.37652945518494
  70. 6轮 准确率为:0.44200000166893005
  71. 6轮的模型已保存
  72. -----第7轮训练开始-----
  73. 训练次数:100次,损失为:1.1562687158584595
  74. 训练次数:200次,损失为:1.2875163555145264
  75. 训练次数:300次,损失为:1.4133583307266235
  76. 训练次数:400次,损失为:1.254225492477417
  77. 训练次数:500次,损失为:1.1896222829818726
  78. 训练次数:600次,损失为:1.3112317323684692
  79. 训练次数:700次,损失为:1.5086911916732788
  80. 7轮 总损失为:230.23083698749542
  81. 7轮 准确率为:0.4754999876022339
  82. 7轮的模型已保存
  83. -----第8轮训练开始-----
  84. 训练次数:100次,损失为:1.086610198020935
  85. 训练次数:200次,损失为:1.2097818851470947
  86. 训练次数:300次,损失为:1.3678902387619019
  87. 训练次数:400次,损失为:1.2088969945907593
  88. 训练次数:500次,损失为:1.1163411140441895
  89. 训练次数:600次,损失为:1.247499942779541
  90. 训练次数:700次,损失为:1.4252394437789917
  91. 8轮 总损失为:218.35910069942474
  92. 8轮 准确率为:0.5044999718666077
  93. 8轮的模型已保存
  94. -----第9轮训练开始-----
  95. 训练次数:100次,损失为:1.037935733795166
  96. 训练次数:200次,损失为:1.141263484954834
  97. 训练次数:300次,损失为:1.3190100193023682
  98. 训练次数:400次,损失为:1.1700167655944824
  99. 训练次数:500次,损失为:1.0646848678588867
  100. 训练次数:600次,损失为:1.1844598054885864
  101. 训练次数:700次,损失为:1.3446803092956543
  102. 9轮 总损失为:209.00663626194
  103. 9轮 准确率为:0.527999997138977
  104. 9轮的模型已保存
  105. -----第10轮训练开始-----
  106. 训练次数:100次,损失为:0.9983921647071838
  107. 训练次数:200次,损失为:1.0837466716766357
  108. 训练次数:300次,损失为:1.2751736640930176
  109. 训练次数:400次,损失为:1.1298927068710327
  110. 训练次数:500次,损失为:1.0229113101959229
  111. 训练次数:600次,损失为:1.1295039653778076
  112. 训练次数:700次,损失为:1.2733806371688843
  113. 10轮 总损失为:200.50266510248184
  114. 10轮 准确率为:0.5493999719619751
  115. 10轮的模型已保存
  116. -----第11轮训练开始-----
  117. 训练次数:100次,损失为:0.966463565826416
  118. 训练次数:200次,损失为:1.0211725234985352
  119. 训练次数:300次,损失为:1.2367210388183594
  120. 训练次数:400次,损失为:1.088995099067688
  121. 训练次数:500次,损失为:0.9786638021469116
  122. 训练次数:600次,损失为:1.0866005420684814
  123. 训练次数:700次,损失为:1.2103657722473145
  124. 11轮 总损失为:194.7027866244316
  125. 11轮 准确率为:0.5641999840736389
  126. 11轮的模型已保存
  127. -----第12轮训练开始-----
  128. 训练次数:100次,损失为:0.9357775449752808
  129. 训练次数:200次,损失为:0.9653837084770203
  130. 训练次数:300次,损失为:1.2010201215744019
  131. 训练次数:400次,损失为:1.0523639917373657
  132. 训练次数:500次,损失为:0.9388719797134399
  133. 训练次数:600次,损失为:1.045914888381958
  134. 训练次数:700次,损失为:1.1654292345046997
  135. 12轮 总损失为:191.47566080093384
  136. 12轮 准确率为:0.5737999677658081
  137. 12轮的模型已保存
  138. -----第13轮训练开始-----
  139. 训练次数:100次,损失为:0.9041438102722168
  140. 训练次数:200次,损失为:0.9161452054977417
  141. 训练次数:300次,损失为:1.1599822044372559
  142. 训练次数:400次,损失为:1.013271450996399
  143. 训练次数:500次,损失为:0.9019820094108582
  144. 训练次数:600次,损失为:1.0087833404541016
  145. 训练次数:700次,损失为:1.125746726989746
  146. 13轮 总损失为:187.77414095401764
  147. 13轮 准确率为:0.5839999914169312
  148. 13轮的模型已保存
  149. -----第14轮训练开始-----
  150. 训练次数:100次,损失为:0.8752296566963196
  151. 训练次数:200次,损失为:0.8772607445716858
  152. 训练次数:300次,损失为:1.1191498041152954
  153. 训练次数:400次,损失为:0.9737100005149841
  154. 训练次数:500次,损失为:0.8703413009643555
  155. 训练次数:600次,损失为:0.9731168746948242
  156. 训练次数:700次,损失为:1.0966637134552002
  157. 14轮 总损失为:185.168947160244
  158. 14轮 准确率为:0.5892999768257141
  159. 14轮的模型已保存
  160. -----第15轮训练开始-----
  161. 训练次数:100次,损失为:0.849646806716919
  162. 训练次数:200次,损失为:0.8409485816955566
  163. 训练次数:300次,损失为:1.0751159191131592
  164. 训练次数:400次,损失为:0.9429139494895935
  165. 训练次数:500次,损失为:0.8454231023788452
  166. 训练次数:600次,损失为:0.937741219997406
  167. 训练次数:700次,损失为:1.0663700103759766
  168. 15轮 总损失为:182.5419823527336
  169. 15轮 准确率为:0.5976999998092651
  170. 15轮的模型已保存
  171. -----第16轮训练开始-----
  172. 训练次数:100次,损失为:0.8328421115875244
  173. 训练次数:200次,损失为:0.8099387288093567
  174. 训练次数:300次,损失为:1.0304874181747437
  175. 训练次数:400次,损失为:0.9107857346534729
  176. 训练次数:500次,损失为:0.8217724561691284
  177. 训练次数:600次,损失为:0.9004014134407043
  178. 训练次数:700次,损失为:1.0346449613571167
  179. 16轮 总损失为:179.81149476766586
  180. 16轮 准确率为:0.6050999760627747
  181. 16轮的模型已保存
  182. -----第17轮训练开始-----
  183. 训练次数:100次,损失为:0.8141376376152039
  184. 训练次数:200次,损失为:0.7860156893730164
  185. 训练次数:300次,损失为:0.9776766300201416
  186. 训练次数:400次,损失为:0.8795670866966248
  187. 训练次数:500次,损失为:0.803113579750061
  188. 训练次数:600次,损失为:0.8628700971603394
  189. 训练次数:700次,损失为:1.0075130462646484
  190. 17轮 总损失为:177.66287940740585
  191. 17轮 准确率为:0.6111999750137329
  192. 17轮的模型已保存
  193. -----第18轮训练开始-----
  194. 训练次数:100次,损失为:0.8004648089408875
  195. 训练次数:200次,损失为:0.7675616145133972
  196. 训练次数:300次,损失为:0.9339349865913391
  197. 训练次数:400次,损失为:0.8534804582595825
  198. 训练次数:500次,损失为:0.7856743931770325
  199. 训练次数:600次,损失为:0.8288229703903198
  200. 训练次数:700次,损失为:0.9895642399787903
  201. 18轮 总损失为:175.08234637975693
  202. 18轮 准确率为:0.6191999912261963
  203. 18轮的模型已保存
  204. -----第19轮训练开始-----
  205. 训练次数:100次,损失为:0.7893921732902527
  206. 训练次数:200次,损失为:0.7497053742408752
  207. 训练次数:300次,损失为:0.8933553099632263
  208. 训练次数:400次,损失为:0.8314535021781921
  209. 训练次数:500次,损失为:0.763375997543335
  210. 训练次数:600次,损失为:0.7902735471725464
  211. 训练次数:700次,损失为:0.9701849818229675
  212. 19轮 总损失为:173.36062556505203
  213. 19轮 准确率为:0.6258999705314636
  214. 19轮的模型已保存
  215. -----第20轮训练开始-----
  216. 训练次数:100次,损失为:0.7721090912818909
  217. 训练次数:200次,损失为:0.7328221797943115
  218. 训练次数:300次,损失为:0.8560763597488403
  219. 训练次数:400次,损失为:0.8105795383453369
  220. 训练次数:500次,损失为:0.7467403411865234
  221. 训练次数:600次,损失为:0.7569105625152588
  222. 训练次数:700次,损失为:0.9446259140968323
  223. 20轮 总损失为:172.8064525127411
  224. 20轮 准确率为:0.6273999810218811
  225. 20轮的模型已保存
  226. 进程已结束,退出代码0

tensorboard:

 因为我设置的每一轮epoch都默认从0开始到700多轮,所有从上面可以看出轮数增加,总体的损失率是越来越小的。

P29  完整的训练套路(三)

在训练步骤开始之前设置haha.train(),在测试步骤前设置haha.eval()

这两个方法调用的时候就会设置模型进入相应的状态(如训练状态和测试状态),只会对网络层中的特定层起作用,如dropout和batch_norm。起控制某些层的作用,训练时和测试时是不一样的。

dropout:是使指定概率的权重随机失活,作用是加快训练速度,防止过拟合

batch_norm:就是把因为层数太多,数据分布逐渐离散,把这些值强行拉回到非线性函数敏感的区域,避免梯度消失,加快训练速度。

就是在训练套路(二)的代码里各加了一行:

 

 P29 用GPU训练(一)

29.1 .cuda()

主要采用.cuda(),根据上面创建的train文件,复制全部代码,只需要做部分改动

可以

  • 加在自己创建的网络模型后面;haha = haha.cuda()
  • 损失函数后面;loss = loss.cuda()
  • 数据后面;imgs = imgs.cuda()   targets = targets.cuda()

只要用cuda,就要在前面加一行命令判断一下自己有没有gpu,然后剩下的代码再缩进写:

if torch.cuda.is_available():

    haha = haha.cuda()    # haha是我自己的模型

29.2 time计时器

可以在用time包输出自己训练一轮所需要的时间

  1. import time # 计时器的包
  2. start_time = time.time()
  3. end_time = time.time()
  4. print("训练一轮所需时间:{}".format(end_time - start_time)

如果电脑上没有gpu,可以放在google.colab上新建笔记本去跑(需要谷歌账号,每个月可以有30h试用)

29.3 完整代码:

  1. import torch
  2. import torchvision
  3. from torch import nn
  4. from torch.utils.data import DataLoader
  5. from torch.utils.tensorboard import SummaryWriter
  6. from model import *
  7. import time
  8. # # 使用cuda训练数据
  9. # device = torch.device("cuda")
  10. # print(device)
  11. # 准备数据集
  12. dataset_train = torchvision.datasets.CIFAR10("cifar10",train=True,download=True,transform=torchvision.transforms.ToTensor())
  13. dataset_test = torchvision.datasets.CIFAR10("cifar10",train=False,download=True,transform=torchvision.transforms.ToTensor())
  14. dataloader_train = DataLoader(dataset_train, batch_size=64)
  15. dataloader_test = DataLoader(dataset_test, batch_size=64)
  16. # 查看数据长度
  17. train_len = len(dataset_train)
  18. test_len = len(dataset_test)
  19. print("训练集的长度为:{}".format(train_len))
  20. print("测试集的长度为:{}".format(test_len))
  21. # 创建模型:
  22. class Haha(nn.Module):
  23. def __init__(self) -> None:
  24. super().__init__()
  25. self.model = nn.Sequential(
  26. nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
  27. nn.MaxPool2d(2),
  28. nn.Conv2d(in_channels=32,out_channels=32,kernel_size=5,stride=1,padding=2),
  29. nn.MaxPool2d(2),
  30. nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),
  31. nn.MaxPool2d(2),
  32. nn.Flatten(),
  33. nn.Linear(64*4*4, 64),
  34. nn.Linear(64, 10)
  35. )
  36. def forward(self, x):
  37. x = self.model(x)
  38. return x
  39. haha = Haha()
  40. if torch.cuda.is_available():
  41. haha = haha.cuda()
  42. # 损失函数
  43. loss = nn.CrossEntropyLoss()
  44. loss = loss.cuda()
  45. # 优化器
  46. optim = torch.optim.SGD(haha.parameters(), lr=1e-2)
  47. # 用tensorboard画图咯
  48. writer = SummaryWriter("logs_train")
  49. # 训练开始
  50. # 参数准备:
  51. epoch = 20
  52. global_step = 1
  53. for i in range(epoch):
  54. print("-----第{}轮训练开始-----".format(i+1))
  55. step = 1
  56. # 训练步骤开始
  57. start_time = time.time()
  58. haha.train()
  59. for data in dataloader_train:
  60. imgs, targets = data
  61. imgs = imgs.cuda()
  62. targets = targets.cuda()
  63. outputs = haha(imgs)
  64. result_loss = loss(outputs, targets)
  65. # 优化器优化模型
  66. optim.zero_grad()
  67. result_loss.backward()
  68. optim.step()
  69. # 训练轮数逢百打印
  70. if step % 100 == 0:
  71. print("训练次数:{}次,损失为:{},".format(step, result_loss.item())) # item()
  72. writer.add_scalar("train_result_loss", result_loss,step)
  73. step += 1
  74. # 测试步骤开始
  75. haha.eval()
  76. running_loss = 0
  77. total_accuracy_test = 0
  78. with torch.no_grad(): # 新增的tensor没有梯度,使带梯度的tensor能够进行原地运算。
  79. for data in dataloader_test:
  80. imgs, targets = data
  81. imgs = imgs.cuda()
  82. targets = targets.cuda()
  83. outputs = haha(imgs)
  84. result_loss = loss(outputs, targets) # 该loss为部分数据在网络模型上的损失,为tensor数据类型
  85. # 求整体测试数据集上的误差
  86. running_loss = running_loss + result_loss.item() # result_loss为tensor数据类型,running_loss为
  87. # 求整体测试集上的正确率
  88. accuracy = (outputs.argmax(1) == targets).sum()
  89. total_accuracy_test = total_accuracy_test + accuracy
  90. print("第{}轮 总损失为:{}".format(global_step, running_loss))
  91. writer.add_scalar("train_running_loss", running_loss, global_step)
  92. print("第{}轮 准确率为:{}".format(global_step, total_accuracy_test/test_len))
  93. writer.add_scalar("total_accuracy", total_accuracy_test, global_step)
  94. # 保存每一轮的模型
  95. # model = torch.save(haha,"haha_train_moedl{}.pth".format(i+1))
  96. print("第{}轮的模型已保存".format(i+1))
  97. endtime = time.time()
  98. print("训练第{}轮的时间为:{}".format(global_step,endtime - start_time))
  99. global_step += 1
  100. writer.close()

输出 本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】

推荐阅读
相关标签