资讯详情

PyTorch深度学习-跟着小土堆学习

目录

  • 学习视频链接
  • 一些问题
  • P4:Python/PyTorch学习两个法宝函数-dir()、help()
  • P5:PyCharm及Jupyter使用及对比
  • P6:PyTorch初步了解加载数据
  • P7:Dataset类代码实战
  • P8:TensorBoard使用(1)
  • P9:TensorBoard使用(二)
  • P10-11:Transeforms使用(一)(二)
  • P12-13:常见的transforms(一)(二)
  • P14:torchvision使用中数据集
  • P15:DataLoader的使用
  • P16:神经网络的基本骨架-nn.Module的使用
  • P17:土堆说卷积操作(可选)torch.nn.functional.conv2d
  • P18.神经网络-卷积层 torch.nn.Conv2d
  • P19:使用神经网络-最大池化 torch.nn.MaxPool2d
  • P20:神经网络-非线性激活
  • P21.介绍神经网络-线形层及其他层
  • P22:神经网络-搭建小实战和Sequential的使用
  • P23:损失函数和反向传播
  • P24:优化器(1)
  • P25:使用和修改现有网络模型
  • P26:自定义网络模型的保存和读取
  • P27:完整的模型训练套路(一)~(四)

学习视频链接

学习不是一天的工作,我的大脑转得很慢,只是慢慢学习!

先从第一个【小土堆】的视频中学习!

  • PyTorch深度学习快速入门教程(绝对通俗易懂!)小土堆
  • 《PyTorch深度学习实践完成集-刘二大人

【小土堆】给出的信息:(2021-5-31)

个人微信官方账号:土堆碎念

请自带各种资料。 代码:https://github.com/xiaotudui/PyTorch-Tutorial 蚂蚁蜜蜂/练习数据集:链接: https://pan.baidu.com/s/1jZoTmoFzaTLWh4lKBHVbEA 密码: 5suq 课程资源:https://pan.baidu.com/s/1CvTIjuXT4tMonG0WltF-vQ?pwd=jnnp 提取码:jnnp


有用的链接:

  • cv2、plt 、PIL显示图像
  • 解决 OpenCV cv2.imread()、cv2.imwrite()函数不能读取或写入以中文命名的图像文件和包含中文路径的图像文件
  • 图像的三个表示格式的每个维度:
    • tensor:tensor.shape -> torch.Size([C, H, W]) # 在训练过程中,通常会在0维上扩展一个维度batchsize,即torch.Size([batchsize, C, H, W])
    • numpy.ndarray:ndarray.shape -> (H, W, C) # 通常使用这种格式cv2.imread(img_path)读取或使用np.array(PIL.Image)转换得到的。
    • PIL.Image:Image.size -> (W, H) # 注意这个用法size而不是shape,而且只有两个元素tuple,分别表示宽度W、高H。(而不似tensor、numpy有三个元素,先表示高H,再表示的宽W)

一些问题

  1. tensorboard中的x轴是step还是epoch?这是自己设定的吗?

P4:Python/PyTorch学习两个法宝函数-dir()、help()

dir() 打开工具箱(例如函数PyTorch,进一步打开某些分区)

help() 查看工具包中某个工具函数的用法(说明书)

(1) 查看torch工具包有哪些分区?

dir(torch) # ['AVG', 'AggregationType', 'AnyType', 'Argument', 'ArgumentSpec', 'BFloat16Storage', 'BFloat16Tensor',...] 

(2) 查看torch.cuda分区有哪些?

dir(torch.cuda) # ['Any', 'BFloat16Storage', 'BFloat16Tensor', 'BoolStorage', 'BoolTensor', 'ByteStorage', ...] 

(3) 查看torch.cuda.is_available()分隔区有哪些?

dir(torch.cuda.is_available()) # 去除函数后面的(),效果相同 # ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', ...] 

发现前后都有两条下划线:__这意味着规定能改变,也就是说torch.cuda.is_available它不再是一个分区,而是一个函数,因此可以调用help()查看函数的基本功能。

help(torch.cuda.is_available)  # 注意以后跟不上()  # 打印结果,该函数会返回一个bool值 # Help on function is_available in module torch.cuda: # is_available() -> bool # Returns a bool indicating if CUDA is currently available. 

P5:PyCharm及Jupyter使用及对比

打开cmd,然后依次键入以下两行命令,然后将cmd中出现的URL粘贴进浏览器打开即可:

activate yolov5
jupyter notebook

---------------------------------------------------------------------------

oh!从这里开始就在编写另外一个博客了:关于使用Jupyter的几个tips

继续学习!!!

---------------------------------------------------------------------------

P6:PyTorch加载数据初认识

P7:Dataset类代码实战

如果是小白的话,真的很建议去看看这个视频!UP主用了PyCharm + Python Console配合着来看结果的生成的,非常棒!

  1. 手写加载数据集的类:MyData。主要是要重写__init__()__getitem__()__len()__这3个类。
  2. get到一个小技巧,可以直接用+对两个Data类进行拼接(可用于数据集不足时,直接将两个数据集这样加起来一起使用)
  3. new_path = os.path.join(path1,path2,...)将所有路径联合起来,返回一个整合路径(str)
  4. file_name_list = os.listdir(path)读取path路径中的所有文件名称,返回一个名称列表(list)

:

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

# 构造一个子文件夹数据集类MyData
class MyData(Dataset):
    def __init__(self, root_dir, label_dir):    # root_dir是指整个数据集的根目录,label_dir是指具体某一个类的子目录
        # 在init初始化函数中,定义一些类中的全局变量,即跟在self.后的变量们
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.path = os.path.join(self.root_dir, self.label_dir)
        self.img_list = os.listdir(self.path)

    def __getitem__(self, index):   # 传入下标获取元素
        img_name = self.img_list[index]
        img_item_path = os.path.join(self.path, img_name)
        img = Image.open(img_item_path)
        label = self.label_dir
        return img, label[:-6]	# 返回的是一个元组
        # 这里进行了截取,因为我不想要label_dir最后面的'_image'这6个元素

    def __len__(self):
        return len(self.img_list)

# --------------实例化ants_data和bees_data------------- #
root_dir = 'dataset/train'
ants_dir = 'ants_image'
bees_dir = 'bees_image'
ants_data = MyData(root_dir, ants_dir)
bees_data = MyData(root_dir, bees_dir)
# ---------------------------------------------------- #

# -------------返回一个元组,分别赋值给img和label------- #
img, label = ants_data[0]
# ----------------------------------------------------- #

# ---因为是元组,所以可用[0]、[1]直接提取出img、label---- #
print(label == ants_data[0][1])		# true
# ----------------------------------------------------- #

# ----------将ants_data和bees_data相加起来使用---------- #
y = ants_data + bees_data
len_ants = len(ants_data)	# 124
len_bees = len(bees_data)	# 121
len_y = len(y)				# 245
print(len_y == len_ants+len_bees)	# True
print(y[123][1])			# ants
print(y[124][1])			# bees

P8:TensorBoard的使用(一)

之前写过一篇文章,可能会有点帮助:tensorboard初体验

  1. 调用from torch.utils.tensorboard import SummaryWriter(摘要编写器)

Writes entries directly to event files in the log_dir to be consumed by TensorBoard. The SummaryWriter class provides a high-level API to create an event file in a given directory and add summaries and events to it. The class updates the file contents asynchronously. This allows a training program to call methods to add data to the file directly from the training loop, without slowing down training. 将条目直接写入log_dir中的事件文件,供TensorBoard使用。 “SummaryWriter”类提供了一个高级API,用于在给定目录中创建事件文件,并向其中添加摘要和事件。该类异步更新文件内容。这允许训练程序调用方法直接从训练循环中向文件添加数据,而不会降低训练速度。

如果调用SummaryWriter类没有传入log_dir参数的话,会默认在当前目录下新建一个runs文件夹用于存放训练过程中的event事件文件。(SummaryWriter的其他参数一般用不到)

(1) 使用名称runs创建SummaryWriter()。

writer = SummaryWriter()
# folder location: runs/May04_22-14-54_s-MacBook-Pro.local/

(2) 使用名称my_experiment创建SummaryWriter()。

writer = SummaryWriter("my_experiment")
# folder location: my_experiment

(3) 创建一个的SummaryWriter()。

writer = SummaryWriter(comment="LR_0.1_BATCH_16")
# folder location: runs/May04_22-14-54_s-MacBook-Pro.localLR_0.1_BATCH_16/
  1. 主要会用到两种方法: writer.add_image(tag, tensor, step) # 添加图像(模型图像,观察训练结果) writer.add_scalar(tag, tensor, step) # 添加标量(就是一些数据的变化曲线,比如loss) writer.add_graph(model, input) # 查看模型计算图(在P22有使用到)

(1) writer.add_image() # 添加图像(模型图像,观察训练结果)

def add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):

     Note that this requires the ``pillow`` package.

     Args:
         tag (string): Data identifier	# 数据标识符(就是图标的title)
         img_tensor (torch.Tensor, numpy.array, or string/blobname): Image data	# 图像数据(指明传入的数据类型只能是torch.Tensor,numpy.array,string)
         global_step (int): Global step value to record	# 要训练多少步(就是x轴)
         walltime (float): Optional override default walltime (time.time())
           seconds after epoch of event
           
     Shape:
         img_tensor: Default is :math:`(3, H, W)`. You can use ``torchvision.utils.make_grid()`` to
         convert a batch of tensor into 3xHxW format or call ``add_images`` and let us do the job.
         Tensor with :math:`(1, H, W)`, :math:`(H, W)`, :math:`(H, W, 3)` is also suitable as long as
         corresponding ``dataformats`` argument is passed, e.g. ``CHW``, ``HWC``, ``HW``.

     Examples::
         from torch.utils.tensorboard import SummaryWriter
         import numpy as np
         img = np.zeros((3, 100, 100))
         img[0] = np.arange(0, 10000).reshape(100, 100) / 10000
         img[1] = 1 - np.arange(0, 10000).reshape(100, 100) / 10000

         img_HWC = np.zeros((100, 100, 3))
         img_HWC[:, :, 0] = np.arange(0, 10000).reshape(100, 100) / 10000
         img_HWC[:, :, 1] = 1 - np.arange(0, 10000).reshape(100, 100) / 10000

         writer = SummaryWriter()
         writer.add_image('my_image', img, 0)

         # If you have non-default dimension setting, set the dataformats argument.
         writer.add_image('my_image_HWC', img_HWC, 0, dataformats='HWC')
         writer.close()

     Expected result:

     .. image:: _static/img/tensorboard/add_image.png
        :scale: 50 %

(2) writer.add_scalar() # 添加标量(就是一些数据的变化曲线,比如loss)

def add_scalar(self, tag, scalar_value, global_step=None, walltime=None):

    Args:
        tag (string): Data identifier	# 数据标识符(就是图标的title)
        scalar_value (float or string/blobname): Value to save	# 要保存的数值(就是y轴)
        global_step (int): Global step value to record	# 要训练多少步(就是x轴)
        walltime (float): Optional override default walltime (time.time())
          with seconds after epoch of event
          
	Examples::
        from torch.utils.tensorboard import SummaryWriter
        writer = SummaryWriter()
        x = range(100)
        for i in x:
            writer.add_scalar('y=2x', i * 2, i)
        writer.close()
        
    Expected result:
	.. image:: _static/img/tensorboard/add_scalar.png
	    :scale: 50 %
  1. 最后还需要关闭:writer.close()
  2. 打开tensorboard观察图表的方式:在pycharm的终端Terminal中键入tensorboard --logdir=logs --port=6007(最后指定端口的操作是可选的,这里指定端口是为了避免:当前有多人在使用同一个服务器的默认端口进行训练而造成的拥塞) 注意: 1)当前面3步运行完之后,再通过第4步指定event文件的存放路径,将event文件们显示进行观察。 2)如果同一logdir下存放了多个相同tag的event文件,则绘图时会发生混乱。:将此logdir下的文件全部删除,然后重新运行。构建子文件夹,也就是说创建新的SummaryWriter(‘新文件夹’)

本节例子只使用到了writer.scalar()

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('logs')  # 实例化一个SummaryWriter为writer,并指定event的保存路径为logs
for i in range(10):
    writer.add_scalar('y=2x', 2 * i, i)
writer.close()  # 最后还需要将这个writer关闭

P9:TensorBoard的使用(二)

  1. 运用writer.add_image()。由上节 可知,add_image能处理的图像数据类型是:torch.Tensor、numpy.array、String。 (而在 中运用的 PIL.Image 读取的数据类型是PIL.JpegImagePlugin.JpegImageFile,所以需要转换成 numpy.array 才可放进 add_image 中使用。本节课直接采用的

  2. 利用numpy.array() 将 PIL 转为 numpy.ndarray

from PIL import Image
image_path = 'dataset/train/ants_image/0013035.jpg'
img = Image.open(image_path)
print(type(img))	# <class 'PIL.JpegImagePlugin.JpegImageFile'>

import numpy as np
img_array = np.array(img)	
print(type(img_array))	# <class 'numpy.ndarray'>
  1. 又是一个重点,由 可知,img_tensor的shape是有要求的!

img_tensor: Default is :math:(3, H, W). You can use torchvision.utils.make_grid() to convert a batch of tensor into 3xHxW format or call add_images and let us do the job. Tensor with :math:(1, H, W), :math:(H, W), :math:(H, W, 3) is also suitable as long as corresponding dataformats argument is passed, e.g. CHW, HWC, HW.

  • img_tensor的默认shape是(3, H, W)
  • 如果要使用其他的shape,则需要通过dataformats来指明一下,即:dataformats=‘CHW’、dataformats=‘HWC’、dataformats=‘HW’

通过将PIL转换为numpy后,虽然满足了img_tensor的数据类型要求,但是没有满足img_tensor的默认shape要求。

因为转换后的numpy的shape是(H,W,C),也就是说channel=3在最后一维,所以还需要在add_image()中添加参数dataformats=(H,W,C)(或者手动调整一下维度,代码为img_array = img_array.transepose(2, 0, 1),然后就不用添加dataformats参数了)。

print(img_array.shape)	# (512, 768, 3)

opencv是按照BGR读取的图像,记得转换为RGB:cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

整体代码为:

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

writer = SummaryWriter('logs_3')  # 实例化一个SummaryWriter为writer,并指定event的保存路径为logs

image_path1 = 'dataset/train/ants_image/0013035.jpg'
image_path2 = 'dataset/train/bees_image/16838648_415acd9e3f.jpg'

img = Image.open(image_path2)	# image_path1
img_array = np.array(img)
print(type(img))  # <class 'PIL.JpegImagePlugin.JpegImageFile'>
print(type(img_array))  # <class 'numpy.ndarray'>
print(img_array.shape)

# 这里的add_image中的tag为'test_image'没有变化,所以在tensorboard中可通过拖动滑块来展示这两张图像
# writer.add_image('test_image', img_array, 1, dataformats='HWC')
writer.add_image('test_image', img_array, 2, dataformats='HWC')

for i in range(10):	# 这个add_scalar暂时没有管它,虽然tag没有变,但是因为每次写入的数据都是y=3x所以曲线没有显示混乱
    writer.add_scalar('y=3x', 3 * i, i)

writer.close()  # 最后还需要将这个writer关闭

(1)同一个tag显示多张图像(拖动滑条)

(2)多个tag显示

P10-11:Transeforms的使用(一)(二)

  1. torchvision中的transeforms,主要是对图像进行变换(预处理)。from torchvision import transforms

  1. transeforms中常用的就是以下几种方法:(Alt+7可唤出左侧的Structure结构)

“Compose”, “ToTensor”, “PILToTensor”, “ConvertImageDtype”, “ToPILImage”, “Normalize”, “Resize”, “Scale”,“CenterCrop”

  • Compose: Composes several transforms together. Args:list of transforms to compose.将几个变换组合在一起。参数:[Transform对象列表],例如transforms.Compose([transforms.CenterCrop(10),transforms.ToTensor(),…])
  • ToTensor: Convert a PIL Image or numpy.ndarray to tensor.
  • ToPILImage: Convert a tensor or an ndarray to PIL Image.
  • Normalize(torch.nn.Module): Normalize a tensor image with mean and standard deviation.This transform does not support PIL Image.用平均值和标准偏差归一化张量图像。此转换不支持PIL图像。(为n个维度给定mean:(mean[1],…,mean[n])和std:(std[1],…,std[n]),此转换将对每个channel进行归一化)
  • Resize(torch.nn.Module): Resize the input image (PIL Image or Tensor) to the given size.Return PIL Image or Tensor: Rescaled image.将输入的图像(PIL Image or Tensor)的大小缩放到指定的size尺寸。size (sequence or int),当是sequence时则调整到指定的(h, w);当是int时,就将原图的min(h,w)调整到size大小,然后另一条边进行等比例缩放。
  • RandomCrop(torch.nn.Module): Crop the given image (PIL Image or Tensor) at a random location.在随机位置裁剪给定的size大小的图像(size的输入要求跟Resize一样)。
  1. python的用法 -> tensor数据类型

通过transforms.ToTensor去看两个问题: (1)transforms该如何使用(python) (2)为什么我们需要Tensor数据类型:因为在tensor中封装了许多训练神经网络中会用到的参数,例如requires_grad等。

也可以用 ToTensor() 将 numpy.ndarray 转为tensor(用读入的数据类型是numpy.ndarray)

import numpy as np
from torchvision import transforms
from PIL import Image

image_path = 'dataset/train/ants_image/0013035.jpg'
image = Image.open(image_path)

# 1.transforms该如何使用(python)
tensor_trans = transforms.ToTensor()	# ToTensor()中不带参数
tensor_img = tensor_trans(image)		# 不能直接写成transforms.ToTensor(image)

print(np.array(image).shape)	# (512, 768, 3)
print(tensor_img.shape)			# torch.Size([3, 512, 768]),通道数变到第0维了

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

image_path = 'dataset/train/ants_image/0013035.jpg'
image = Image.open(image_path)

# 1.transforms该如何使用(python)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(image)

print(np.array(image).shape)
print(tensor_img.shape)

# 写入tensorboard
writer = SummaryWriter('logs')
writer.add_image('tag', tensor_img, 1)
writer.close()

P12-13:常见的transforms(一)(二)

这张图挺棒的!因为图像的数据类型在不同场景往往不同,很容易出错,需要转换为特定格式才能使用!

  1. 了解python中某个类的内置函数__call__的用法(用__表示是内置函数)

参考链接:详解Python的__call__()方法

  • __call__()方法的作用:。调用该实例对象就是执行__call__()方法中的代码。
  • 可以通过内置函数callable来判断是否是可调用对象。例如判断p是否为可调用对象:print(callable(p))返回 True 或 False。

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

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


person = Person()               # 实例化一个对象person
person('zhangsan')              # 像调用函数一样调用person对象
person.__call__('zhangshan_2')  # 也可像调用类函数调用
person.hello('wangwu')          # 调用类函数person

# __call__ Hello zhangsan
# __call__ Hello zhangshan_2
# hello wangwu
  1. 例子ToTensor、Normalize、Resize、Compose
  • Compose: Composes several transforms together. Args:list of transforms to compose.将几个变换组合在一起。参数:[Transform对象列表],例如transforms.Compose([transforms.CenterCrop(10),transforms.ToTensor(),…]) 注意:Compose的参数列表是会按照参数的顺序来对图像进行操作的,相当于list[0]的输出会作为list[1]的输入,以此类推,要注意每种transforms函数的输入数据格式要求,有些是要求为tensor,有些是PIL。
  • ToTensor: Convert a PIL Image or numpy.ndarray to tensor.
  • ToPILImage: Convert a tensor or an ndarray to PIL Image.
  • Normalize(torch.nn.Module): Normalize a tensor image with mean and standard deviation.This transform does not support PIL Image.用平均值和标准偏差归一化张量图像。此转换不支持PIL图像。(为n个维度给定mean:(mean[1],…,mean[n])和std:(std[1],…,std[n]),此转换将对每个channel进行归一化)
  • Resize(torch.nn.Module): Resize the input image (PIL Image or Tensor) to the given size.Return PIL Image or Tensor: Rescaled image.将输入的图像(PIL Image or Tensor)的大小缩放到指定的size尺寸。size (sequence or int),当是sequence时则调整到指定的(h, w);当是int时,就将原图的min(h,w)调整到size大小,然后另一条边进行等比例缩放。
  • RandomCrop(torch.nn.Module): Crop the given image (PIL Image or Tensor) at a random location.在随机位置裁剪给定的size大小的图像(size的输入要求跟Resize一样)。

  1. Ctrl+点击进去):主要关注它的输入和输出是什么数据格式、所需的输入参数、作用是什么。
  2. :不清楚到变量image某一步的时候值或类型是什么的时候,可以打上断点,用Debug,然后在Debug的console执行type(image)、image.shape等操作进行查看。(可看下我的这篇文章:PyCharm的Debug和中断方法)

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

image_path = 'images/cat2.jpg'
image = Image.open(image_path)

writer = SummaryWriter('logs_2')

# 1.Totensor
trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(image)
writer.add_image('ToTensor', img_tensor)  # 这里只传入了tag和image_tensor,没有写入第3个参数global_step,则会默认是第0步

# 2.Normalize 可以改变色调
trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
img_norm = trans_norm(img_tensor)
writer.add_image('Normalize', img_norm)

trans_norm = transforms.Normalize([1, 3, 5], [3, 2, 1])
img_norm_2 = trans_norm(img_tensor)
writer.add_image('Normalize', img_norm_2, 1)

trans_norm = transforms.Normalize([2, 0.5, 3], [5, 2.6, 1.5])
img_norm_3 = trans_norm(img_tensor)
writer.add_image('Normalize', img_norm_3, 2)

# 3.Resize 将PIL或者tensor缩放为指定大小然后输出PIL或者tensor
w, h = image.size   # PIL.Image的size先表示的宽再表示的高

trans_resize = transforms.Resize(min(w, h) // 2)    # 缩放为原来的1/2
img_resize = trans_resize(image)  # 对PIL进行缩放
writer.add_image('Resize', trans_totensor(img_resize
        标签: 7p8pin连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台