image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

一、第一周:Pytorch基础概念

2. Pytorch的Tensor(张量)

Content

  1. Tensor概念
  2. Tensor创建一:直接创建
  3. Tensor创建二:依据数值创建
  4. Tensor创建三:依据概率创建

2.1 张量是什么(What is Tensor?)

张量是一个**多维数组**,它是标量、向量、矩阵的高维拓展。
image.png

2.2 Tensor与Variable

Variable是torch.autograd中的数据类型,主要用于封装Tensor,进行自动求导。
image.png
data:被封装的Tensor
grad:data的梯度
grad_fn:创建Tensor的Function,是自动求导的关键
requires_grad:指示是否需要梯度
is_leaf:指示是否是叶子结点(张量)

Pytorch0.4.0版开始,Variable并入Tensor
image.png
dtype:张量的数据类型,如torch.FloatTensor、torch.cuda.FloatTensor
image.png
shape:张量的形状,如(64,3,224,224)
device:张量所在设备,GPU/CPU,是加速的关键

2.3 张量的创建——(1)直接创建张量

1. torch.tensor()

torch.tensor()
功能:从data创建tensor

  • data:数据,可以是list,numpy
  • dtype:数据类型,默认与data的一致
  • device:所在设备,cuda/cpu
  • requires_grad:是否需要梯度
  • pin_memory:是否存于锁页内存
    1. torch.tensor(
    2. data,
    3. dtype=None,
    4. device=None,
    5. requires_grad=False,
    6. pin_memory=False)

2. torch.from_numpy(ndarray)

torch.from_numpy(ndarray)
功能:从numpy创建tensor
注意事项:从torch.from_numpy创建的tensor与原ndarray共享内存,当修改其中一个的数据,另一个也将会被修改。
image.png

2.4 张量的创建——(2)依据数值创建张量

1. torch.zeros()

torch.zeros()
功能:依size创建全0张量

  • size:张量的形状,如(3,3)、(3,244,244)
  • out:输出的张量
  • layout:内存中布局形式,有strided、sparse_coo等
  • device:所在设备,gpu/cpu
  • requires_grad:是否需要梯度
    1. torch.zeros(*size,
    2. out=None,
    3. dtype=None,
    4. layout=torch.strided,
    5. device=None,
    6. requires_grad=False)

2. torch.zeros_like()

torch.zeros_like()
功能:依input形状创建全0张量

  • input:创建于input同形状的全0张量
  • dtype:数据类型
  • layout:内存中布局形式
    1. torch.zeros_like(input,
    2. dtype=None,
    3. layout=None,
    4. device=None,
    5. requires_grad=False)

3. torch.ones()

4. torch.ones_like()

torch.ones()
torch.ones_like()
功能:依input形状创建全1张量

  • size:张量的形状,如(3,3)、(3,244,244)
  • input:创建于input同形状的全1张量
  • dtype:数据类型
  • layout:内存中布局形式,有strided、sparse_coo等
  • layout:内存中布局形式
  • device:所在设备,gpu/cpu
  • requires_grad:是否需要梯度
    1. torch.ones(*size,
    2. out=None,
    3. dtype=None,
    4. layout=torch.strided,
    5. device=None,
    6. requires_grad=False)
    1. torch.ones_like(input,
    2. dtype=None,
    3. layout=None,
    4. device=None,
    5. requires_grad=False)

5. torch.full()

6. torch.full_like()

torch.full()
torch.full_like()
功能:依据input形状创建全值张量

  • size:张量的形状,如(3,3)
  • full_value:张量的值
    1. torch.full(size,
    2. full_value,
    3. out=None,
    4. dtype=None,
    5. layout=torch.strided,
    6. device=None,
    7. requires_grad=False)

7. torch.arange()

torch.arange()
功能:创建等差的1维张量
注意事项:数值区间为[start,end)

  • start:数列起始值
  • end:数列”结束值”
  • step:数列公差,默认为1
    1. torch.arange(start=0,
    2. end,
    3. step=1,
    4. out=None,
    5. dtype=None,
    6. layout=torch.strided,
    7. device=None,
    8. requires_grad=False)

8. torch.linspace()

torch.linspace()
功能:创建均分的1维张量
注意事项:数值区间为[start,end]

  • start:数列起始值
  • end:数列结束值
  • steps:数列长度

步长为:(end-start)/(steps-1)

  1. torch.linspace(start,
  2. end,
  3. steps=100,
  4. out=None,
  5. dtype=None,
  6. layout=torch.strided,
  7. device=None,
  8. requires_grad=False)

9. torch.logspace()

torch.logspace()
功能:创建对数均分的1维张量
注意事项:数值区间为[start,end];长度为steps,底数为base

  • start:数列起始值
  • end:数列结束值
  • steps:数列长度
  • base:对数函数的底,默认为10
    1. torch.logspace(start,
    2. end,
    3. steps=100,
    4. base=10.0,
    5. out=None,
    6. dtype=None,
    7. layout=torch.strided,
    8. device=None,
    9. requires_grad=False)

10. torch.eye()

torch.eye()
功能:创建单位对角矩阵(2维张量)
注意事项:默认为方阵

  • n:矩阵函数
  • m:矩阵列数
    1. torch.linspace(n,
    2. m=None,
    3. out=None,
    4. dtype=None,
    5. layout=torch.strided,
    6. device=None,
    7. requires_grad=False)

2.5 张量的创建——(3)依概率分布创建张量

1. torch.normal()

torch.normal()
功能:生成正态分布(高斯分布)

  • mean:均值
  • std:标准差
    1. torch.normal(mean,
    2. std,
    3. out=None)
    四种模式:
    mean为标量,std为标量
    mean为标量,std为张量
    mean为张量,std为标量
    mean为张量,std为张量
    1. torch.normal(mean,
    2. std,
    3. size,
    4. out=None)

2. torch.randn()

3. torch.randn_like()

torch.randn()
torch.randn_like()
功能:生成标准正态分布

  • size:张量的形状
    1. torch.randn(*size,
    2. out=None,
    3. dtype=None,
    4. layout=torch.strided,
    5. device=None,
    6. requires_grad=False)

4. torch.rand()

5. torch.rand_like()

torch.rand()
torch.rand_like()
功能:在区间[0,1)上,生成均匀分布

  1. torch.rand(*size,
  2. out=None,
  3. dtype=None,
  4. layout=torch.strided,
  5. device=None,
  6. requires_grad=False)

6. torch.randint()

7. torch.randint_like()

torch.randint()
torch.randint_like()
功能:在区间[low,high)生成整数均匀分布

  • size:张量的形状
    1. torch.randint(low,
    2. high,
    3. size,
    4. out=None,
    5. dtype=None,
    6. layout=torch.strided,
    7. device=None,
    8. requires_grad=False)

8. torch.randperm()

torch.randperm()
功能:生成从0到n-1的随机排列

  • n:张量的长度
    1. torch.randperm(n,
    2. out=None,
    3. dtype=None,
    4. layout=torch.strided,
    5. device=None,
    6. requires_grad=False)

9. torch.bernoulli()

torch.bernoulli()
功能:以input为概率,生成伯努利分布(0-1分布,两点分布)

  • input:概率值
    1. torch.bernoulli(input,
    2. *,
    3. generator=None,
    4. out=None)

3. 张量操作与线性回归

Content

  1. 张量的操作:拼接、切分、索引和变换
  2. 张量的数学运算
  3. 线性回归

3.1 张量的拼接与切分

1. torch.cat()

torch.cat()
功能:将张量按维度dim进行拼接

  • tensors:张量序列
  • dim:要拼接的维度
    1. torch.cat(tensors,
    2. dim=0,
    3. out=None)
    ```python import torch

t = torch.ones((2, 3)) t0 = torch.cat([t, t], dim=0) t1 = torch.cat([t, t], dim=1)

print(‘t:\n{}\nt.shape:\n{}’.format(t,t.shape)) print(‘t0:\n{}\nt0.shape:\n{}’.format(t0,t0.shape)) print(‘t1:\n{}\nt1.shape:\n{}’.format(t1,t1.shape))

output: t: tensor([[1., 1., 1.], [1., 1., 1.]]) t.shape: torch.Size([2, 3]) t0: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) t0.shape: torch.Size([4, 3]) t1: tensor([[1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1.]]) t1.shape: torch.Size([2, 6])

  1. <a name="WMTJT"></a>
  2. #### 2. torch.stack()
  3. torch.stack()<br />功能:在新创建的维度dim上进行拼接
  4. - tensors:张量序列
  5. - dim:要拼接的维度
  6. ```python
  7. torch.stack(tensors,
  8. dim=0,
  9. out=None)
  1. # example2
  2. # torch.stack
  3. import torch
  4. t = torch.ones((2, 3))
  5. t0 = torch.stack([t, t], dim=2)
  6. t1 = torch.stack([t, t], dim=0)
  7. # 若dim指定的维度已经存在,则会创建一个新的维度,已存在的依次向后挪一个维度。
  8. print('t:\n{}\nt.shape:\n{}'.format(t, t.shape))
  9. print('t0:\n{}\nt0.shape:\n{}'.format(t0, t0.shape))
  10. print('t1:\n{}\nt1.shape:\n{}'.format(t1, t1.shape))
  11. ouput
  12. t:
  13. tensor([[1., 1., 1.],
  14. [1., 1., 1.]])
  15. t.shape:
  16. torch.Size([2, 3])
  17. t0:
  18. tensor([[[1., 1.],
  19. [1., 1.],
  20. [1., 1.]],
  21. [[1., 1.],
  22. [1., 1.],
  23. [1., 1.]]])
  24. t0.shape:
  25. torch.Size([2, 3, 2])
  26. t1:
  27. tensor([[[1., 1., 1.],
  28. [1., 1., 1.]],
  29. [[1., 1., 1.],
  30. [1., 1., 1.]]])
  31. t1.shape:
  32. torch.Size([2, 2, 3])

3. torch.chunk()

torch.chunk()
功能:将张量按维度dim进行平均切分
返回值:张量列表
注意事项:若不能整除,最后一个张量小于其他张量

  • input:要切分的张量
  • chunks:要切分的份数
  • dim:要切分的维度
    1. torch.chunk(input,
    2. chunks,
    3. dim=0)
    ```python

    example3

    torch.chunk

import torch

a = torch.ones((2, 5))

list_tensors = torch.chunk(a, dim=1, chunks=2) for idx, t in enumerate(list_tensors): print(‘第{}个张量:\n{}\nshape is:\n{}’.format(idx + 1, t, t.shape))

output: 第1个张量: tensor([[1., 1., 1.], [1., 1., 1.]]) shape is: torch.Size([2, 3]) 第2个张量: tensor([[1., 1.], [1., 1.]]) shape is: torch.Size([2, 2])

  1. <a name="MXTua"></a>
  2. #### 4. torch.split()
  3. torch.split()<br />功能:将张量按维度dim进行切分<br />返回值:张量列表
  4. - tensor:要切分的张量
  5. - split_size_or_sections:为int时,表示每一份长度;为list时,按list元素切分
  6. - dim:要切分的维度
  7. 注意事项:切分后,tensor指向切分完的最后一个张量
  8. ```python
  9. torch.split(tensor,
  10. split_size_or_sections,
  11. dim=0)
  1. # example4
  2. # torch.split
  3. import torch
  4. t = torch.ones((2, 5))
  5. list_tensors = torch.split(t, 2, dim=1)
  6. for idx, t in enumerate(list_tensors):
  7. print('第{}个张量:\n{}\nshape is:\n{}'.format(idx + 1, t, t.shape))
  8. print('t:\n',t)
  9. t = torch.ones((2, 5))
  10. list_tensors = torch.split(t, [2, 1, 2], dim=1)
  11. for idx, t in enumerate(list_tensors):
  12. print('第{}个张量:\n{}\nshape is:\n{}'.format(idx + 1, t, t.shape))
  13. output
  14. 1个张量:
  15. tensor([[1., 1.],
  16. [1., 1.]])
  17. shape is:
  18. torch.Size([2, 2])
  19. 2个张量:
  20. tensor([[1., 1.],
  21. [1., 1.]])
  22. shape is:
  23. torch.Size([2, 2])
  24. 3个张量:
  25. tensor([[1.],
  26. [1.]])
  27. shape is:
  28. torch.Size([2, 1])
  29. t:
  30. tensor([[1.],
  31. [1.]])
  32. 1个张量:
  33. tensor([[1., 1.],
  34. [1., 1.]])
  35. shape is:
  36. torch.Size([2, 2])
  37. 2个张量:
  38. tensor([[1.],
  39. [1.]])
  40. shape is:
  41. torch.Size([2, 1])
  42. 3个张量:
  43. tensor([[1., 1.],
  44. [1., 1.]])
  45. shape is:
  46. torch.Size([2, 2])

3.2 张量的索引

1. torch.index_select()

torch.index_select()
功能:在维度dim上,按index索引数据
返回值:依index索引数据拼接的张量

  • input:要索引的张量
  • dim:要索引的维度
  • index:要索引数据的序号
    1. torch.index_select(input,
    2. dim,
    3. index,
    4. out=None)
    ```python

    example5

    torch.index_select

import torch

t = torch.randint(0, 9, size=(3, 3)) idx = torch.tensor([0, 2], dtype=torch.long) t_select = torch.index_select(t, dim=0, index=idx) print(‘t:\n{}\nidx:\n{}\nt_select:\n{}’.format(t, idx, t_select))

output: t: tensor([[4, 4, 1], [5, 1, 8], [2, 1, 2]]) idx: tensor([0, 2]) t_select: tensor([[4, 4, 1], [2, 1, 2]])

  1. <a name="NN86p"></a>
  2. #### 2. torch.masked_select()
  3. torch.index_select()<br />功能:按mask中的True进行索引<br />返回值:一维张量
  4. - input:要索引的张量
  5. - mask:与input同形状的布尔类型张量
  6. ```python
  7. torch.masked_select(input,
  8. mask,
  9. out=None)

ge:>= gt:> le:<= lt:<

  1. # example6
  2. # torch.masked_select
  3. import torch
  4. t = torch.randint(0, 9, size=(3, 3))
  5. mask = t.ge(5)
  6. t_select = torch.masked_select(t, mask)
  7. print('t:\n{}\nmask:\n{}\nt_select:\n{}'.format(t, mask, t_select))
  8. output
  9. t:
  10. tensor([[5, 3, 1],
  11. [3, 8, 6],
  12. [1, 5, 4]])
  13. mask:
  14. tensor([[ True, False, False],
  15. [False, True, True],
  16. [False, True, False]])
  17. t_select:
  18. tensor([5, 8, 6, 5])

3.3 张量的变换

1. torch.reshape()

torch.reshape()
功能:变换张量的形状
注意事项:当张量在内存中是连续存在时,新张量与input共享内存

  • input:要变换的张量
  • shape:新张量的形状
    1. torch.reshape(input,
    2. shape)
    ```python

    example7

    torch.reshape

import torch

t = torch.randperm(8) t_reshape = torch.reshape(t, (-1, 4)) print(‘t:\n{}\nt_reshape:\n{}’.format(t, t_reshape))

print(‘t.data 内存地址:{}’.format(id(t.data))) print(‘t_reshape.data 内存地址:{}’.format(id(t_reshape.data))) t[0] = 1024 print(‘t:\n{}\nt_reshape:\n{}’.format(t, t_reshape))

output: t: tensor([5, 7, 0, 2, 6, 1, 4, 3]) t_reshape: tensor([[5, 7, 0, 2], [6, 1, 4, 3]]) t.data 内存地址:1749654845224 t_reshape.data 内存地址:1749654845224 t: tensor([1024, 7, 0, 2, 6, 1, 4, 3]) t_reshape: tensor([[1024, 7, 0, 2], [ 6, 1, 4, 3]])

  1. <a name="KRXRX"></a>
  2. #### 2. torch.transpose()
  3. torch.transpose()<br />功能:交换张量的两个维度
  4. - input:要交换维度的张量
  5. - dim0:要交换的维度
  6. - dim1:要交换的维度
  7. ```python
  8. torch.transpose(input,
  9. dim0,
  10. dim1)
  1. # example8
  2. # torch.transpose
  3. import torch
  4. t = torch.rand(2, 3, 4)
  5. t_transpose = torch.transpose(t, dim0=1, dim1=2)
  6. print('t:\n{}\nt_transpose:\n{}'.format(t, t_transpose))
  7. print('t.shape:\n{}\nt_transpose.shape:\n{}'.format(t.shape, t_transpose.shape))
  8. output
  9. t:
  10. tensor([[[0.9669, 0.3727, 0.8775, 0.5900],
  11. [0.1132, 0.6863, 0.9109, 0.8974],
  12. [0.5809, 0.0539, 0.7609, 0.3699]],
  13. [[0.9527, 0.2056, 0.6411, 0.6718],
  14. [0.6573, 0.9133, 0.6319, 0.2841],
  15. [0.5032, 0.6048, 0.4830, 0.4872]]])
  16. t_transpose:
  17. tensor([[[0.9669, 0.1132, 0.5809],
  18. [0.3727, 0.6863, 0.0539],
  19. [0.8775, 0.9109, 0.7609],
  20. [0.5900, 0.8974, 0.3699]],
  21. [[0.9527, 0.6573, 0.5032],
  22. [0.2056, 0.9133, 0.6048],
  23. [0.6411, 0.6319, 0.4830],
  24. [0.6718, 0.2841, 0.4872]]])
  25. t.shape:
  26. torch.Size([2, 3, 4])
  27. t_transpose.shape:
  28. torch.Size([2, 4, 3])

3. torch.t()

torch.t()
功能:2维张量转置,对矩阵而言,等价于 torch.transpose(input,0,1)

  1. torch.t(input)

4. torch.squeeze()

torch.squeeze()
功能:压缩长度为1的维度(轴)

  • dim:若为None,移除所有长度为1的轴;若指定维度,当且仅当该轴长度为1时,可以被移除。
    1. torch.squeeze(input,
    2. dim=None,
    3. out=None)
    ```python

    example9

    torch.squeeze

import torch

t = torch.rand((1, 2, 3, 1)) t_sq = torch.squeeze(t) t0 = torch.squeeze(t, dim=0) t1 = torch.squeeze(t, dim=1)

print(‘t.shape:\n{}\nt_sq.shape:\n{}’.format(t.shape, t_sq.shape)) print(‘t0.shape:\n{}\nt1.shape:\n{}’.format(t0.shape, t1.shape))

output: t.shape: torch.Size([1, 2, 3, 1]) t_sq.shape: torch.Size([2, 3]) t0.shape: torch.Size([2, 3, 1]) t1.shape: torch.Size([1, 2, 3, 1])

  1. <a name="eZVKM"></a>
  2. #### 5. torch.unsqueeze()
  3. torch.unsqueeze()<br />功能:依据dim扩展维度
  4. - dim:扩展的维度
  5. ```python
  6. torch.usqueeze(input,
  7. dim,
  8. out=None)

6. torch.flatten()

torch.flatten(input, start_dim=0, end_dim=-1)
功能:展平/推平一个连续范围的维度,输出类型为 Tensor

  • input: 一个 tensor,即要被“推平”的 Tensor。
  • start_dim: “推平”的起始维度。
  • end_dim: “推平”的结束维度。

首先如果按照 start_dim 和 end_dim 的默认值,那么这个函数会把 input 推平成一个 shape 为 [n] 的tensor,其中 n 即 input 中元素个数
当 start_dim = 1 而 end_dim = −1 时,它把第 1 个维度到最后一个维度全部推平合并了。而当 start_dim = 0 而 end_dim = 1 时,它把第 0 个维度到第 1 个维度全部推平合并了。

  1. import torch
  2. t = torch.tensor([[[1, 2, 2, 1],
  3. [3, 4, 4, 3],
  4. [1, 2, 3, 4]],
  5. [[5, 6, 6, 5],
  6. [7, 8, 8, 7],
  7. [5, 6, 7, 8]]])
  8. print('t:\n{}\nt.shape:\n{}'.format(t, t.shape))
  9. x = torch.flatten(t, start_dim=1)
  10. print('x:\n{}\nx.shape:\n{}'.format(x, x.shape))
  11. y = torch.flatten(t, start_dim=0, end_dim=1)
  12. print('y:\n{}\ny.shape:\n{}'.format(y, y.shape))
  13. output
  14. """
  15. t:
  16. tensor([[[1, 2, 2, 1],
  17. [3, 4, 4, 3],
  18. [1, 2, 3, 4]],
  19. [[5, 6, 6, 5],
  20. [7, 8, 8, 7],
  21. [5, 6, 7, 8]]])
  22. t.shape:
  23. torch.Size([2, 3, 4])
  24. x:
  25. tensor([[1, 2, 2, 1, 3, 4, 4, 3, 1, 2, 3, 4],
  26. [5, 6, 6, 5, 7, 8, 8, 7, 5, 6, 7, 8]])
  27. x.shape:
  28. torch.Size([2, 12])
  29. y:
  30. tensor([[1, 2, 2, 1],
  31. [3, 4, 4, 3],
  32. [1, 2, 3, 4],
  33. [5, 6, 6, 5],
  34. [7, 8, 8, 7],
  35. [5, 6, 7, 8]])
  36. y.shape:
  37. torch.Size([6, 4])
  38. """

3.4 张量的数学运算——加减乘除

1. torch.add()

torch.add()
功能:逐元素计算 input+alpha×other

  • input:第一个张量
  • alpha:乘项因子
  • other:第二个张量
    1. torch.add(input
    2. alpha=1,
    3. other,
    4. out=None)
    ```python

    example10

    torch.add

import torch

t0 = torch.randn((3, 3)) t1 = torch.ones_like(t0) t_add = torch.add(t0, 10, t1)

print(‘t0:\n{}\nt1:\n{}\nt_add:\n{}’.format(t0, t1, t_add))

output: t0: tensor([[-0.1253, -0.2573, -2.2917], [ 1.4232, 0.1650, -0.1312], [ 0.7477, 0.1264, -0.6293]]) t1: tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) t_add: tensor([[ 9.8747, 9.7427, 7.7083], [11.4232, 10.1650, 9.8688], [10.7477, 10.1264, 9.3707]])

  1. <a name="bhNjB"></a>
  2. #### 2. torch.addcdiv()
  3. torch.addcdiv()<br />功能:逐元素计算 input + value * tensor1 / tensor2
  4. torch.addcmul()<br />功能:input + value * tensor1 * tensor2
  5. ```python
  6. torch.addcmul(input,
  7. value=1,
  8. tensor1,
  9. tensor2,
  10. out=None)
  1. torch.sub()
  2. torch.div()
  3. torch.mul()

3.5 张量的数学运算——对指幂函数

  1. torch.log(input,out=None)
  2. torch.log10(input,out=None)
  3. torch.log2(input,out=None)
  4. torch.exp(input,out=None)
  5. torch.pow()

3.6 张量的数学运算——三角函数

  1. torch.abs(input,out=None)
  2. torch.acos(input,out=None)
  3. torch.cosh(input,out=None)
  4. torch.cos(input,out=None)
  5. torch.asin(input,out=None)
  6. torch.atan(input,out=None)
  7. torch.atan2(input,other,out=None)

3.7 线性回归

线性回归是分析一个变量与另外一(多)个变量之间关系的方法

因变量:y 自变量:x 关系:线性
y = wx + b

求解步骤:

  1. 确定模型 Model:y = wx + b
  2. 选择损失函数 MSE: Pytorch 框架训练营 - 图16

  3. 求解梯度并更新w,b w = LR w.grad b = b - LR b.grad (LR:学习率,步长)

线性回归模型示例:

  1. # -*- coding:utf-8 -*-
  2. """
  3. @file_name :lesson1.3-Linear_Regression
  4. @author :
  5. @data :2021-05-07
  6. @brief :一元线性回归
  7. """
  8. import torch
  9. from matplotlib import pyplot as plt
  10. torch.manual_seed(10)
  11. lr = 0.1 # 学习率
  12. # 创建训练数据
  13. x = torch.rand(20, 1) * 10 # x data (tensor),shape=(20,1)
  14. y = 2 * x + (5 + torch.randn(20, 1)) # y data (tensor),shape=(20,1)
  15. # 构建线性回归参数
  16. w = torch.randn((1), requires_grad=True)
  17. b = torch.zeros((1), requires_grad=True)
  18. for iteration in range(1000):
  19. # 前向传播
  20. wx = torch.mul(w, x)
  21. y_pred = torch.add(wx, b)
  22. # 计算 MSE loss
  23. loss = (0.5 * (y - y_pred) ** 2).mean()
  24. # 反向传播
  25. loss.backward()
  26. # 更新参数
  27. b.data.sub_(lr * b.grad)
  28. w.data.sub_(lr * w.grad)
  29. # 绘图
  30. if iteration % 20 == 0:
  31. plt.scatter(x.data.numpy(), y.data.numpy())
  32. plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5)
  33. plt.text(2, 20, 'Loss=%0.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
  34. plt.xlim(1.5, 10)
  35. plt.ylim(8, 28)
  36. plt.title('Iteration:{}\nw:{} b:{}'.format(iteration, w.data.numpy(), b.data.numpy()))
  37. plt.pause(0.5)
  38. if loss.data.numpy() < 1:
  39. break

4. 计算图与动态图机制

Content

  1. 计算图
  2. Pytorch的动态图机制

4.1 计算图

  • 计算图是用来描述运算的有向无环图
  • 计算图两个主要元素:结点Node边Edge
    • 结点表示数据,如向量/矩阵/张量
    • 边表示运算,如加/减/乘/除/卷积

用计算图表示:y = (x + w) * (w + 1)
image.png

计算图与梯度求导
y = (x + w) (w + 1)
a = x + w b = w + 1
y = a
b
Pytorch 框架训练营 - 图18
image.png
Pytorch 框架训练营 - 图20

叶子结点
叶子节点:用户创建的结点,如上述的 x 和 w 。
is_leaf:指示张量是否为叶子结点
非叶子节点梯度会被释放

grad_fn:记录创建该张量时所用的方法/函数
叶子结点:grad_fn = None
image.png

  1. # y.grad_fn = <MulBackward0>
  2. # a.grad_fn = <AddBackward0>
  3. # b.grad_fn = <AddBackward0>
  1. # example1
  2. # 计算图示例
  3. import torch
  4. w = torch.tensor([1., ], requires_grad=True)
  5. x = torch.tensor([2., ], requires_grad=True)
  6. a = torch.add(w, x)
  7. a.retain_grad() # 保存非叶子结点a的梯度
  8. b = torch.add(w, 1)
  9. y = torch.mul(a, b)
  10. y.backward()
  11. print(w.grad) # w=5
  12. # 查看叶子节点
  13. # print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf) # TTFFF
  14. print('w.is_leaf:', w.is_leaf)
  15. print('x.is_leaf:', x.is_leaf)
  16. print('a.is_leaf:', a.is_leaf)
  17. print('b.is_leaf:', b.is_leaf)
  18. print('y.is_leaf:', y.is_leaf)
  19. # 查看梯度
  20. # print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
  21. print('w.grad:', w.grad)
  22. print('x.grad:', x.grad)
  23. print('a.grad:', a.grad)
  24. print('b.grad:', b.grad)
  25. print('y.grad:', y.grad)
  26. # 查看 grad_fn
  27. # print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn) # NNAAM
  28. print('w.grad_fn:', w.grad_fn)
  29. print('x.grad_fn:', x.grad_fn)
  30. print('a.grad_fn:', a.grad_fn)
  31. print('b.grad_fn:', b.grad_fn)
  32. print('y.grad_fn:', y.grad_fn)
  33. output
  34. tensor([5.])
  35. w.is_leaf: True
  36. x.is_leaf: True
  37. a.is_leaf: False
  38. b.is_leaf: False
  39. y.is_leaf: False
  40. w.grad: tensor([5.])
  41. x.grad: tensor([2.])
  42. a.grad: tensor([2.])
  43. b.grad: None
  44. y.grad: None
  45. w.grad_fn: None
  46. x.grad_fn: None
  47. a.grad_fn: <AddBackward0 object at 0x000001974E7E15C8>
  48. b.grad_fn: <AddBackward0 object at 0x000001974E7E1608>
  49. y.grad_fn: <MulBackward0 object at 0x000001974E7E15C8>

4.2 动态图

动态图 VS. 静态图
根据计算图搭建方式,可将计算图分为动态图和静态图
image.png

5. 自动求导系统torch.autograd及逻辑回归实现

Content

  1. torch.autograd
  2. 逻辑回归

5.1 autograd——自动求导系统

1. torch.autograd.backward()

torch.autograd.backward()
功能:自动求取梯度

  • tensors:用于求导的张量,如loss
  • retain_graph:保存计算图
  • create_graph:创建导数计算图,用于高阶求导
  • grad_tensors:多梯度权值
  1. torch.autograd.backward(tensors,
  2. grad_tensors=None,
  3. retain_graph=None,
  4. create_graph=Flase)
  1. # example1
  2. # retain_graph
  3. import torch
  4. torch.manual_seed(10)
  5. w = torch.tensor([1.], requires_grad=True)
  6. x = torch.tensor([1.], requires_grad=True)
  7. a = torch.add(w, x)
  8. b = torch.add(w, 1)
  9. y = torch.mul(a, b)
  10. y.backward(retain_graph=True)
  11. print(w.grad)
  12. y.backward()
  13. print(w.grad)
  14. output
  15. tensor([4.])
  16. tensor([8.])
  1. # example2
  2. # grad_tensors
  3. import torch
  4. w = torch.tensor([1.], requires_grad=True)
  5. x = torch.tensor([2.], requires_grad=True)
  6. a = torch.add(w, x)
  7. b = torch.add(w, 1)
  8. y0 = torch.mul(a, b) # y0=(x + w)*(w + 1) dy0/dw=5
  9. y1 = torch.add(a, b) # y1=(x + w)+(w + 1) dy1/dw=2
  10. loss = torch.cat([y0, y1], dim=0)
  11. grad_tensors = torch.tensor([1., 2.])
  12. loss.backward(gradient=grad_tensors)
  13. # gradient 传入 torch.autograd.backward()中的grad_tensors
  14. print(w.grad)
  15. output
  16. tensor([9.])

2. torch.autograd.grad()

torch.autograd.grad()
功能:求取梯度

  • outputs:用于求导的张量,如loss
  • inputs:需要梯度的张量
  • create_graph=Flase:创建导数计算图,用于高阶求导
  • retain_graph=None:保存计算图
  • grad_tensors=None:多梯度权值
  1. torch.autograd.grad(outputs,
  2. inputs,
  3. grad_tensors=None,
  4. retain_graph=None,
  5. create_graph=Flase)
  1. # example3
  2. # torch.autograd.grad
  3. import torch
  4. x = torch.tensor([3.], requires_grad=True)
  5. y = torch.pow(x, 2)
  6. grad_1 = torch.autograd.grad(y, x, create_graph=True)
  7. print(grad_1)
  8. grad_2 = torch.autograd.grad(grad_1[0], x)
  9. print(grad_2)
  10. output
  11. (tensor([6.], grad_fn=<MulBackward0>),)
  12. (tensor([2.]),)

autograd小贴士:

  1. 梯度不自动清零,使用 w.grad.zero_() 操作清零

  2. 依赖于叶子结点的结点,requires_grad默认为True

  3. 叶子结点不可执行in-place

in-place:原位操作,在原有内存地址上进行操作

  1. # example3
  2. # tips-1
  3. import torch
  4. w = torch.tensor([1.], requires_grad=True)
  5. x = torch.tensor([2.], requires_grad=True)
  6. for i in range(3):
  7. a = torch.add(w, x)
  8. b = torch.add(w, 1)
  9. y = torch.mul(a, b)
  10. y.backward()
  11. print(w.grad)
  12. if i ==1:
  13. w.grad.zero_()
  14. output
  15. tensor([5.])
  16. tensor([10.])
  17. tensor([5.])
  1. # example4
  2. # tips-2
  3. import torch
  4. w = torch.tensor([1.], requires_grad=True)
  5. x = torch.tensor([2.], requires_grad=True)
  6. a = torch.add(w, x)
  7. b = torch.add(w, 1)
  8. y = torch.mul(a, b)
  9. print('a.requires_grad:',a.requires_grad)
  10. print('b.requires_grad:',b.requires_grad)
  11. print('y.requires_grad:',y.requires_grad)
  12. output
  13. a.requires_grad: True
  14. b.requires_grad: True
  15. y.requires_grad: True

5.2 逻辑回归

逻辑回归是线性的二分类模型
模型表达式:
Pytorch 框架训练营 - 图23
Pytorch 框架训练营 - 图24

f(x)称为Sigmoid函数,也称为Logistics函数。
image.png

Pytorch 框架训练营 - 图26

逻辑回归与线性回归
线性回归是分析自变量x因变量y(标量)之间关系的方法
逻辑回归是分析自变量x因变量y(概率)之间关系的方法
image.png

逻辑回归又称对数几率回归
Pytorch 框架训练营 - 图28

机器学习模型训练步骤:

  1. 数据:数据采集、数据清洗、数据划分、数据预处理
  2. 模型:线性模型/神经网络模型
  3. 损失函数:线性模型中采用的均方差损失函数、分类任务中的交叉熵
  4. 优化器:更新权值
  5. 迭代训练:反复迭代训练

逻辑回归模型示例:

  1. # -*- coding:utf-8 -*-
  2. """
  3. @file_name :lesson1.5-Logistic_Regression
  4. @author :
  5. @data :2021-05-09
  6. @brief :逻辑回归
  7. """
  8. import torch
  9. import torch.nn as nn
  10. import matplotlib.pyplot as plt
  11. import numpy as np
  12. # ========== step 1/5 生成数据 ==========
  13. sample_nums = 100
  14. mean_value = 1.7
  15. bias = 1
  16. n_data = torch.torch.ones(sample_nums, 2)
  17. x0 = torch.normal(mean_value * n_data, 1) + bias # 类别0 数据 shape=(100,2)
  18. y0 = torch.zeros(sample_nums) # 类别0 标签 shape=(100,1)
  19. x1 = torch.normal(-mean_value * n_data, 1) + bias # 类别1 数据 shape=(100,2)
  20. y1 = torch.ones(sample_nums) # 类别1 标签 shape=(100,1)
  21. train_x = torch.cat((x0, x1), 0)
  22. train_y = torch.cat((y0, y1), 0)
  23. # ========== step 2/5 选择数据 ==========
  24. class LR(nn.Module):
  25. def __init__(self):
  26. super(LR, self).__init__()
  27. self.features = nn.Linear(2, 1)
  28. self.sigmoid = nn.Sigmoid()
  29. def forward(self, x):
  30. x = self.features(x)
  31. x = self.sigmoid(x)
  32. return x
  33. lr_net = LR() # 实例化逻辑回归模型
  34. # ========== step 3/5 选择损失函数 ==========
  35. loss_fn = nn.BCELoss()
  36. # ========== step 4/5 选择优化器 ==========
  37. lr = 0.01 # 学习率
  38. optimizer = torch.optim.SGD(lr_net.parameters(), lr=lr, momentum=0.9)
  39. # ========== step 5/5 模型训练 ==========
  40. for iteration in range(1000):
  41. # 前向传播
  42. y_pred = lr_net(train_x)
  43. # 计算loss
  44. loss = loss_fn(y_pred.squeeze(), train_y)
  45. # 方向传播
  46. loss.backward()
  47. # 更新参数
  48. optimizer.step()
  49. # 绘图
  50. if iteration % 20 == 0:
  51. mask = y_pred.ge(0.5).float().squeeze() # 以0.5为阀值进行分类
  52. correct = (mask == train_y).sum() # 计算正确预测的样本个数
  53. acc = correct.item() / train_y.size(0) # 计算分类准确率
  54. plt.scatter(x0.data.numpy()[:, 0], x0.data.numpy()[:, 1], c='r', label='class0')
  55. plt.scatter(x1.data.numpy()[:, 0], x1.data.numpy()[:, 1], c='b', label='class1')
  56. w0, w1 = lr_net.features.weight[0]
  57. w0, w1 = float(w0.item()), float(w1.item())
  58. plot_b = float(lr_net.features.bias[0].item())
  59. plot_x = np.arange(-6, 6, 0.1)
  60. plot_y = (-w0 * plot_x - plot_b) / w1
  61. plt.xlim(-5, 7)
  62. plt.ylim(-7, 7)
  63. plt.plot(plot_x, plot_y)
  64. plt.text(-5, 5, 'Loss=%0.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
  65. plt.title('Iteration: {}\nw0:{:.2f} w1:{:.2f} b:{:.2f} accuracy:{:.2f}'.format(iteration, w0, w1, plot_b, acc))
  66. plt.legend()
  67. plt.show()
  68. plt.pause(0.5)
  69. if acc > 0.99:
  70. break

二、第二周:Pytorch数据处理

数据:

  • 数据收集:数据又原始样本和标签
  • 数据划分:数据会划分为训练集、验证集和测试集(train、valid、test)。
    1. - 训练集->训练模型;
    2. - 验证集->验证模型是否过拟合,也就是挑选模型,挑选那些还没有过拟合的模型;
    3. - 测试集->测试挑选出来的模型的性能
  • 数据读取:DataLoader
    1. - Sampler->生成索引
    2. - Dataset->根据索引去读取图片和标签
  • 数据预处理:transforms

image.png

6. 数据读取模块——DataSet与DataLoader

Content

  1. 人民币二分类
  2. DataLoader与Dataset

6.1 DataLoader与Dataset

1. torch.utils.data.DataLoader

torch.utils.data.DataLoader
功能:构建可迭代的数据装载器

  • dataset:Dataset类,决定数据从哪里读取
  • batch_size:批大小
  • num_workers:是否多进程读取数据
  • shuffle=False:每个epoch是否乱序
  • drop_last=False:当样本数不能被batchsize整除时,是否舍弃最后一批数据
  1. torch.utils.data.DataLoader()
  2. DataLoader(dataset,
  3. batch_size=1,
  4. shuffle=False,
  5. sampler=None,
  6. batch_sampler=None,
  7. num_workers=0,
  8. collate_fn=None,
  9. pin_memory=False,
  10. drop_last=False,
  11. timeout=0,
  12. worker_in it_fn=None,
  13. multiprocessing_context=None)

epoch:所有训练样本都已输入到模型中,称为1个epoch
iteration:一批样本输入到模型中,称为1个iteration
batchsize:批大小,决定了一个epoch有多少个iteration

例如:

  1. 样本总数:87batchsize8
  2. drop_last = True1 epoch = 10 iteration # 舍弃掉后七个样本
  3. drop_last = Flase1 epoch = 11 iteration

2. touch.utils.data.Dataset

touch.utils.data.Dataset
功能:Dataset抽象类,所有自定义的Dataset都需要继承它,并且复写 __getitem__()(接受一个索引,返回一个样本)

  1. torch.utils.data.Dataset()
  2. class Dataset(object):
  3. def __getitem__(self, index):
  4. # 接收一个索引,返回一个样本
  5. raise NotImplementedError
  6. def __add__(self, other):
  7. return ConcatDataset([self, other])

6.2 人民币二分类

数据读取:

  • 读哪些数据? Sampler输出Index
  • 从哪读数据? Dataset中的data_dir
  • 怎么读数据? Dataset中的getitem

image.png

7. 图像数据预处理模块——transforms

Content

  1. transforms运行机制
  2. 数据标准化——transforms.normalize

7.1 transforms运行机制

1. 计算机视觉工具包:torchvision

  • torchvision.transforms:常用的图像预处理方法

  • torchvision.datasets:常用数据集,如MNIST/CIFAR-10/ImageNet

  • torchvision.model:常用的模型预训练,如AlexNet/VGG/ResNet/GoogLeNet

2. 常用图像预处理方法:transforms

  • 数据中心化/标准化

  • 缩放/裁剪/旋转/翻转/填充/噪声添加

  • 灰度变换/线性变换/仿射变换/亮度、饱和度及对比度变换

image.png

7.2 数据标准化——transforms.Normalize

1. transform.Normalize

transform.Normalize
功能:逐channel(通道)的对图像进行标准化,加快模型的收敛速度
output = (input - mean) / std ==> 得到0均值1标准差的数据分布

  • mean:各通道的均值
  • std:各通道的标准差
  • inplace:是否原地操作
    1. # 对图像的每个通道进行标准化
    2. # output = (input - mean) / std
    3. transforms.Normalize(mean,
    4. std,
    5. inplace=False)

8. transforms图像增强(一)

Content

  1. 数据增强
  2. transforms——裁剪
  3. transforms——翻转和旋转

8.1 数据增强(Data Augmentation)

数据增强又称为数据增广、数据扩增,它是对训练集进行变换,使训练集更丰富,从而让模型更具泛化能力

原则:使得训练集与测试集更接近

  • 空间位置:平移
  • 色彩:灰度图,色彩抖动
  • 形状:仿射变换
  • 上下文场景:遮挡,填充

8.2 transforms——裁剪(Crop)

1. transforms.CenterCrop

transforms.CenterCrop
功能:从图像中心裁剪图片

  • size:所需裁剪图片尺寸(也就是裁剪后图片的尺寸)
    1. # 1. 从图像中心裁剪
    2. transforms.CenterCrop(size) # 所需裁剪图片尺寸

2. transforms.RandomCrop

transforms.RandomCrop
功能:从图片中随机裁剪出尺寸为size的图片

  • size:所需裁剪图片尺寸
  • padding:设置填充大小
    • 当为 a 时,上下左右均填充 a 个像素
    • 当为 (a,b) 时,上下填充 b 个像素,左右填充 a 个像素
    • 当为 (a,b,c,d) 时,左、上、右、下分别填充 a,b,c,d 个像素
  • pad_if_need:若图像小于设定的size,则填充
  • padding_mode:填充模式,有 4 种模式
    • constant:像素值由 fill 设定
    • edge:像素值由图像边缘像素决定
    • reflect:镜像填充,最后一个像素不镜像,例:[1,2,3,4] — [3,2,1,2,3,4,3,2]
    • symmetric:镜像填充,最后一个像素镜像,例:[1,2,3,4] — [2,1,1,2,3,4,4,3]
  • fill:constant时,设置填充的像素值
    1. transforms.RandomCrop(size, # 所需裁剪图片的尺寸
    2. padding=None, # 设置填充大小
    3. pad_if_needed=False, # 若图像小于设定size,则填充
    4. fill=0, # 填充模式为constant时,设置填充的像素值,如(R,G,B)/(Gray)
    5. padding_mode='constant') # 填充模式,共有4种

3. transforms.RandomResizedCrop

transforms.RandomResizedCrop
功能:随机大小。长宽比裁剪图片

  • size:所需裁剪图片的尺寸
  • scale=(0.08, 1.0):随机裁剪面积比例
  • ratio=(3/4, 4/3):随即长宽比
  • interpolation:插值方法,最近邻/双线性/双三次插值
    • PIL.Image.NEAREST 最近邻
    • PIL.Image.BILINEAR 双线性
    • PIL.Image.BICUBIC 双三次插值
      1. # 3. 随机大小、长宽比裁剪图片
      2. transforms.RandomResizedCrop(size, # 所需裁剪图片的尺寸
      3. scale=(0.08, 1.0), # 随机裁剪面积比例
      4. ratio=(3/4, 4/3) # 随机长宽比
      5. interpolation) # 插值方法,最近邻/双线性/双三次插值

4. transforms.FiveCrop

5. transforms.TenCrop

transforms.FiveCrop
transforms.TenCrop
功能:在图像的上下左右以及中心裁剪出尺寸为size的5张图片,transforms.TenCrop对这 5 张图片进行水平或者垂直镜像获得 10 张图片。

  • size:所需裁剪图片尺寸
  • vertical_flip:是否垂直翻转
    1. # 4. 从图像上下左右及中心裁剪出尺寸为size的5张图像
    2. transforms.FiveCrop(size) # 返回一个tuple
    1. # 5. 对上述5张图像进行水平或者垂直镜像获得10张图像
    2. transforms.TenCrop(size, # 所需裁剪图片尺寸
    3. vertical_flip=False) # 是否垂直翻转

8.3 transforms——翻转与旋转(Flip and Rotation)

1. RandomHorizontalFlip

2. RandomVerticalFlip

RandomHorizontalFlip
RandomVerticalFlip
功能:依概率水平(左右)或垂直(上下)翻转图片

  • p:翻转概率
    1. # 水平翻转
    2. transforms.RandomHorizontalFlip(p=0.5)
    1. # 垂直翻转
    2. transforms.RandomVerticalFlip(p=0.5)

3. transforms.RandomRotation

transforms.RandomRotation
功能:随机旋转图片

  • degrees:旋转角度
    • 当degrees=a时,在(-a, a)之间选择旋转角度
    • 当degrees=(a, b)时,在(a, b)之间选择旋转角度
  • resample=False:重采样方法
  • expand=False:是否扩大图片,以保持原图信息
  • center=None:旋转点设置,默认中心旋转
    1. # 2. 旋转
    2. transforms.RandomRotation(degrees, # 旋转角度
    3. resample=False, # 重采样方法
    4. expand=False, # 是否扩大图片,以保持原图信息
    5. center=None) # 旋转点设置,默认中心旋转

9. transforms图像增强(二)

Content

  1. transforms——图像变换
  2. transforms——transforms方法操作
  3. 自定义 transforms 方法

9.1 transforms——图像变换(Data Augmentation)

1. transforms.Pad

transforms.Pad
功能:对图片的边缘进行填充

  • padding:设置填充大小
    • 当padding=a时,上下左右均填充a个像素
    • 当padding=(a, b)时,上下填充b个像素,左右填充a个像素
    • 当padding=(a, b, c, d)时,左/上/右/下分别填充a/b/c/d个像素
  • padding_mode:填充模式,有 4 种模式,constant、edge、reflect、symmetric
  • fill:填充模式为constant时,设置填充的像素值,如(R,G,B)/(Gray)
    1. # 1. 填充图像边缘
    2. transforms.Pad(padding, # 设置填充大小
    3. # 当padding=a时,上下左右均填充a个像素
    4. # 当padding=(a, b)时,上下填充b个像素,左右填充a个像素
    5. # 当padding=(a, b, c, d)时,左/上/右/下分别填充a/b/c/d个像素
    6. fill=0, # 填充模式为constant时,设置填充的像素值,如(R,G,B)/(Gray)
    7. padding_mode='constant') # 填充模式,constant/edge/reflect/symmetric

2. transforms.ColorJitter

transforms.ColorJitter
功能:调整亮度、对比度、饱和度和色相

  • brightness:亮度调整因子
    • 当brightness=a时,在[max(0, 1-a), 1+a]之间选择
    • 当brightness=(a, b)时,在[a, b]之间选择
  • contrast:对比度参数,同brightness
  • saturation:饱和度参数,同brightness
  • hue=0:色相参数
    • 当hue=a时,在[-a, a]之间选择
    • 当hue=(a, b)时,在[a, b]之间选择
      1. # 2. 调整图像亮度/对比度/饱和度/色相
      2. transforms.ColorJitter(brightness=0, # 亮度调整因子
      3. # 当brightness=a时,在[max(0, 1-a), 1+a]之间选择
      4. # 当brightness=(a, b)时,在[a, b]之间选择
      5. contrast=0, # 对比度参数,同brightness
      6. saturation=0, # 饱和度参数,同brightness
      7. hue=0) # 色相参数
      8. # 当hue=a时,在[-a, a]之间选择
      9. # 当hue=(a, b)时,在[a, b]之间选择

3. transforms.Grayscale

4. transforms.RandomGrayscale

transforms.Grayscale
transforms.RandomGrayscale
功能:依概率将图片转换为灰度图

  • num_ouput_channels:输出通道数
  • p:概率值,图像被转换为灰度图的概率

注意事项:transforms.Grayscale 是 transforms.RandomGrayscale p = 1 时的特例

  1. # 3. 灰度图转换
  2. transforms.Grayscale(num_output_channels) # 输出通道数,1或3
  3. transforms.RandomGrayscale(num_output_channels,
  4. p=0.1) # 概率值

5. transforms.RandomAffine

transforms.RandomAffine
功能:对图像进行仿射变换,仿射变换是二维的线性变换,由五种基本原子变换构成,分别是旋转平移缩放错切翻转

  • degrees:设置旋转角度
  • translate:平移区间设置
    • 如 translate = (a, b) ,a 设置宽(width),b 设置高(height);
    • 图像在宽维度平移的区间为 -img_width a < dx < img_width a
    • 图像在高维度平移的区间为 -img_height b < dy < img_height b
  • scale:缩放比例(以面积为单位)
  • fillcolor:填充颜色设置
  • shear:错切角度设置,有水平错切和垂直错切
    • 当 shear = a 时,仅在 x 轴错切,错切角度在 (-a, a) 之间
    • 当 shear = (a, b) 时,则 x 轴在 (-a, a) 之间随机选择错切角度,y 轴在 (-b, b) 之间随机选择错切角度
    • 当shear=(a, b, c, d) 时,则 x 轴在 (a, b) 之间随机选择错切角度,y 轴在 (c, d) 之间随机选择错切角度
  • resample:重采样方式,NEAREST、BILINEAR、BICUBIC
    1. # 5. 仿射变换
    2. # 仿射变换是二维的线性变换,由五种基本原子变换构成,旋转/平移/缩放/错切/翻转
    3. transforms.RandomAffine(degrees, # 设置旋转角度
    4. translate=None, # 平移区间设置
    5. # 例:translate=(a, b),a为宽,b为高
    6. # 图像在宽维度平移的区间为 -img_width * a < dx < img_width * a
    7. # 图像在高维度平移的区间为 -img_height * b < dy < img_height * b
    8. scale=None, # 缩放比例
    9. shear=None, # 错切角度设置
    10. # 当shear=a时,仅在x轴错切,错切角度在(-a, a)之间
    11. # 当shear=(a, b)时,则a设置x轴角度,b设置y轴角度
    12. # 当shear=(a, b, c, d)时,则a、b设置x轴角度,c、d设置y轴角
    13. resample=False, # 重采样方式,NEAREST/BILINEAR/BICUBIC
    14. fillcolor=0) # 填充颜色设置

6. transforms.RandomErasing

transforms.RandomErasing
功能:对图像进行随机遮挡

  • p:概率值,执行该操作的概率
  • scale:遮挡区域面积
  • ratio=:遮挡区域长宽比
  • value:遮挡区域像素值,如(R,G,B)/(Gray)/‘random’(只要是字符串就会随机)
  • inplace

注意事项:transforms.RandomErasing 是对张量进行操作,所以执行 transforms.RandomErasing 之前,一般需要执行 transforms.ToTensor

  1. # 6. 随机遮挡
  2. transforms.ToTensor()
  3. transforms.RandomErasing(p=0.5, # 执行遮挡的概率
  4. scale=(0.02, 0.33), # 遮挡区域面积
  5. ratio=(0.3, 3.3) # 遮挡区域长宽比
  6. value=0, # 遮挡区域像素值,如(R,G,B)/(Gray)/'random'
  7. inplace=False)

7. transforms.ToTensor

transforms.ToTensor
功能:将 PILImage 或者 numpy 的 ndarray 转化成 Tensor ;把一个取值范围是 [0,255] 的 PIL.Image 转换成 Tensor ,shape 为 (H,W,C) 的 numpy.ndarray ,转换成形状为 [C,H,W] ,取值范围是 [0,1.0] 的 Tensor 。
对于 PILImage 转化的 Tensor ,其数据类型是 torch.FloatTensor 对于 ndarray 的数据类型没有限制,但转化成的 Tensor 的数据类型是由 ndarray 的数据类型决定的。

8. transforms.Lambda

transforms.Lambda
功能:用户自定义 lambda 方法

  • lambda:lambda 匿名函数
    • lambda[arg1 [,arg2,…,argn]] : expression
      1. # 8. 自定义lambda方法
      2. transforms.Lambda(lambd) # 匿名函数 lambda[arg1 [,arg2,...,argn]] : expression

9.2 transforms——transforms方法操作(Transforms Operation)

1. transforms.RandomChoice

transforms.RandomChoice
功能:从一系列 transforms 方法中随机挑选一个

  1. transforms.RandomChoice([transforms1, transforms2, transforms3])

2. transforms.RandomApply

transforms.RandomApply
功能:依概率执行一组 transforms 操作

  1. transforms.RandomApply([transforms1, transforms2, transforms3], p=0.5)

3. transforms.RandomOrder

transforms.RandomOrder
功能:对一组 transforms 操作打乱顺序

  1. transforms.RandomOrder([transforms1, transforms2, transforms3])

9.3 自定义 transforms 方法(User-Defined Transforms)

自定义 transforms 方法要素:

  1. 仅接受一个参数,返回一个参数
  2. 注意上下游的输出与输入
    1. class Compose(object):
    2. def __call__(self, img):
    3. for t in self.transform:
    4. img = t(img)
    5. return img

通过类实现多参数传入:

  1. # 通过类实现多参数传入
  2. class YoutTransforms(object):
  3. def __init__(self, ...):
  4. ...
  5. def __call__(self, img):
  6. ...
  7. return img

椒盐噪声
椒盐噪声又称为脉冲噪声,是一种随机出现的白点或者黑点,白点成为盐噪声,黑色成为椒噪声
信噪比(Signal-Noise Rate,SNR)是衡量噪声的比例,图像中为图像像素的占比

  1. class AddPepperNoise(object):
  2. def __init__(self, snr, p):
  3. self.snr = snr
  4. self.p = p
  5. def __call__(self, img):
  6. """
  7. 添加椒盐噪声具体实现过程
  8. """
  9. return img
  10. class Compose(object):
  11. def __call__(self,img):
  12. for t in self.transforms:
  13. img = t(img)
  14. return img

transforms 方法总结

image.png

image.png

image.png

第三周 模型模块

10. 模型创建与 nn.Module

Content

  1. 网络模型创建步骤
  2. nn.Module属性

10.1 网络模型创建步骤(Steps of Creating Module)

image.png

模型创建两要素:

  • 构建子模块(构建网络层) ==> init()
  • 拼接子模块(拼接网络层) ==> forward()

10.2 nn.Module属性

image.png

1. torch.nn

torch.nn:

  • nn.Parameter:张量子类,表示可学习参数,如weight/权重、bias/偏置
  • nn.Module:所有网络层基类,管理网络属性
  • nn.functional:函数具体实现,如卷积、池化、激活函数等
  • nn.init:参数初始化方法

2. nn.Module

nn.Module
功能:所有网络层基类,管理网络属性
nn.Module有 8 个属性,这个 8 个属性都是有序字典(OrderDict):

  • paramters:存储管理 nn.Parameter
  • modules:存储管理 nn.Module
  • buffers:存储管理缓冲属性,如 BN 层中 running_mean
  • *_hooks:存储管理钩子函数
    1. self._parameter = OrderDict()
    2. self._buffers = OrderDict()
    3. self._backward_hooks = OrderDict()
    4. self._forward_hooks = OrderDict()
    5. self._forward_pre_hooks = OrderDict()
    6. self._state_dict_hooks = OrderDict()
    7. self._load_state_pre_dict_hooks = OrderDict()
    8. self._modules = OrderDict()

3. nn.Module总结

nn.Module总结:

  • 一个module可以包含多个子module
  • 一个module相当于一个运算,必须实现 forward() 函数
  • 每个module都有 8 个有序字典(OrderDict)管理它的属性

11. 模型容器Containers与AlexNet构建

Content

  1. 模型容器(Containers)
  2. AlexNet构建

11.1 模型容器——Containers

1. Containers

Containers:

  • nn.Sequetial按顺序包装多个网络层
  • nn.ModuleList:像Python的 list 一样包装多个网络层
  • nn.ModuleDict:像Python的 dict 一样包装多个网络层

2. nn.Sequetial

nn.Sequetial
功能:nn.Sequetial 是 nn.module 的容器,用于按顺序包装一组网络层
特性:

  • 顺序性:各网络层之间严格按照顺序构建
  • 自带forward():自带的 forward 里,通过 for 循环依次执行前向传播运算

注意:nn.Sequetial 中也可以传入字典类型的参数,可以实现给各个网络层命名的效果

实例:
LeNet模块 = features子模块 + classifier子模块

  1. # Conv1-pool1-Conv2-pool2-fc1-fc2-fc3
  2. # ============================ Sequential
  3. class LeNetSequential(nn.Module):
  4. def __init__(self, classes):
  5. super(LeNetSequential, self).__init__()
  6. self.features = nn.Sequential(
  7. nn.Conv2d(3, 6, 5),
  8. nn.ReLU(),
  9. nn.MaxPool2d(kernel_size=2, stride=2),
  10. nn.Conv2d(6, 16, 5),
  11. nn.ReLU(),
  12. nn.MaxPool2d(kernel_size=2, stride=2), )
  13. self.classifier = nn.Sequential(
  14. nn.Linear(16 * 5 * 5, 120),
  15. nn.ReLU(),
  16. nn.Linear(120, 84),
  17. nn.ReLU(),
  18. nn.Linear(84, classes), )
  19. def forward(self, x):
  20. x = self.features(x)
  21. x = x.view(x.size()[0], -1)
  22. x = self.classifier(x)
  23. return x
  24. fake_img = torch.randn((4, 3, 32, 32), dtype=torch.float32)
  25. net = LeNetSequential(classes=2)
  26. output = net(fake_img)
  27. print(net)
  28. print(output)
  29. output
  30. LeNetSequential(
  31. (features): Sequential(
  32. (0): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  33. (1): ReLU()
  34. (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  35. (3): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  36. (4): ReLU()
  37. (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  38. )
  39. (classifier): Sequential(
  40. (0): Linear(in_features=400, out_features=120, bias=True)
  41. (1): ReLU()
  42. (2): Linear(in_features=120, out_features=84, bias=True)
  43. (3): ReLU()
  44. (4): Linear(in_features=84, out_features=2, bias=True)
  45. )
  46. )
  47. tensor([[ 0.0570, -0.0268],
  48. [ 0.0579, -0.0404],
  49. [ 0.0660, -0.0268],
  50. [ 0.0500, -0.0363]], grad_fn=<AddmmBackward>)

通过给 nn.Sequetial 传入字典类型的参数,以实现给各个网络层命名的效果

  1. # Conv1-pool1-Conv2-pool2-fc1-fc2-fc3
  2. # ============================ SequentialOrderDict
  3. class LeNetSequentialOrderDict(nn.Module):
  4. def __init__(self, classes):
  5. super(LeNetSequentialOrderDict, self).__init__()
  6. self.features = nn.Sequential(OrderedDict({
  7. 'conv1': nn.Conv2d(3, 6, 5),
  8. 'relu1': nn.ReLU(inplace=True),
  9. 'pool1': nn.MaxPool2d(kernel_size=2, stride=2),
  10. 'conv2': nn.Conv2d(6, 16, 5),
  11. 'relu2': nn.ReLU(inplace=True),
  12. 'pool2': nn.MaxPool2d(kernel_size=2, stride=2),
  13. }))
  14. self.classifier = nn.Sequential(OrderedDict({
  15. 'fc1': nn.Linear(16 * 5 * 5, 120),
  16. 'relu3': nn.ReLU(),
  17. 'fc2': nn.Linear(120, 84),
  18. 'relu4': nn.ReLU(inplace=True),
  19. 'fc3': nn.Linear(84, classes),
  20. }))
  21. def forward(self, x):
  22. x = self.features(x)
  23. x = x.view(x.size()[0], -1)
  24. x = self.classifier(x)
  25. return x
  26. fake_img = torch.randn((4, 3, 32, 32), dtype=torch.float32)
  27. net = LeNetSequentialOrderDict(classes=2)
  28. output = net(fake_img)
  29. print(net)
  30. print(output)
  31. output
  32. LeNetSequentialOrderDict(
  33. (features): Sequential(
  34. (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  35. (relu1): ReLU(inplace=True)
  36. (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  37. (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  38. (relu2): ReLU(inplace=True)
  39. (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  40. )
  41. (classifier): Sequential(
  42. (fc1): Linear(in_features=400, out_features=120, bias=True)
  43. (relu3): ReLU()
  44. (fc2): Linear(in_features=120, out_features=84, bias=True)
  45. (relu4): ReLU(inplace=True)
  46. (fc3): Linear(in_features=84, out_features=2, bias=True)
  47. )
  48. )
  49. tensor([[-0.1304, -0.0338],
  50. [-0.1102, -0.0299],
  51. [-0.0928, -0.0051],
  52. [-0.0988, -0.0417]], grad_fn=<AddmmBackward>)

3. nn.ModuleList

nn.ModuleList
功能:nn.ModuleList 是 nn.module 的容器,用于包装一组网络层,以迭代方式调用网络层
主要方法:

  • append():在 ModuleList 后面添加网络层
  • extend():拼接两个 ModuleList
  • insert():指定在 ModuleList 中位置插入网络层
  1. #20层全连接网络
  2. # ============================ ModuleList
  3. class ModuleList(nn.Module):
  4. def __init__(self):
  5. super(ModuleList, self).__init__()
  6. self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(20)])
  7. def forward(self, x):
  8. for i, linear in enumerate(self.linears):
  9. x = linear(x)
  10. return x
  11. net = ModuleList()
  12. print(net)
  13. fake_data = torch.ones((10, 10))
  14. output = net(fake_data)
  15. print(output)
  16. output
  17. """
  18. ModuleList(
  19. (linears): ModuleList(
  20. (0): Linear(in_features=10, out_features=10, bias=True)
  21. (1): Linear(in_features=10, out_features=10, bias=True)
  22. (2): Linear(in_features=10, out_features=10, bias=True)
  23. (3): Linear(in_features=10, out_features=10, bias=True)
  24. (4): Linear(in_features=10, out_features=10, bias=True)
  25. (5): Linear(in_features=10, out_features=10, bias=True)
  26. (6): Linear(in_features=10, out_features=10, bias=True)
  27. (7): Linear(in_features=10, out_features=10, bias=True)
  28. (8): Linear(in_features=10, out_features=10, bias=True)
  29. (9): Linear(in_features=10, out_features=10, bias=True)
  30. (10): Linear(in_features=10, out_features=10, bias=True)
  31. (11): Linear(in_features=10, out_features=10, bias=True)
  32. (12): Linear(in_features=10, out_features=10, bias=True)
  33. (13): Linear(in_features=10, out_features=10, bias=True)
  34. (14): Linear(in_features=10, out_features=10, bias=True)
  35. (15): Linear(in_features=10, out_features=10, bias=True)
  36. (16): Linear(in_features=10, out_features=10, bias=True)
  37. (17): Linear(in_features=10, out_features=10, bias=True)
  38. (18): Linear(in_features=10, out_features=10, bias=True)
  39. (19): Linear(in_features=10, out_features=10, bias=True)
  40. )
  41. )
  42. tensor([[ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  43. -0.1960, 0.2176],
  44. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  45. -0.1960, 0.2176],
  46. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  47. -0.1960, 0.2176],
  48. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  49. -0.1960, 0.2176],
  50. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  51. -0.1960, 0.2176],
  52. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  53. -0.1960, 0.2176],
  54. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  55. -0.1960, 0.2176],
  56. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  57. -0.1960, 0.2176],
  58. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  59. -0.1960, 0.2176],
  60. [ 0.1451, 0.1003, 0.0663, 0.1063, -0.2361, -0.1720, 0.1003, -0.1731,
  61. -0.1960, 0.2176]], grad_fn=<AddmmBackward>)
  62. """

4. nn.ModuleDict

nn.ModuleDict
功能:nn.ModuleDict 是 nn.module 的容器,用于包装一组网络层,以索引方式调用网络层
主要方法:

  • clear():清空ModuleDict
  • items():返回可迭代的键值对
  • keys():返回字典的键
  • values():返回字典的值
  • pop():返回一对键值,并从字典中删除
  1. # ============================ ModuleDict
  2. class ModuleDict(nn.Module):
  3. def __init__(self):
  4. super(ModuleDict, self).__init__()
  5. self.choices = nn.ModuleDict({
  6. 'conv': nn.Conv2d(10, 10, 3),
  7. 'pool': nn.MaxPool2d(3)
  8. })
  9. self.activations = nn.ModuleDict({
  10. 'relu': nn.ReLU(),
  11. 'prelu': nn.PReLU()
  12. })
  13. def forward(self, x, choice, act):
  14. x = self.choices[choice](x)
  15. x = self.activations[act](x)
  16. return x
  17. net = ModuleDict()
  18. fake_img = torch.randn((4, 10, 32, 32))
  19. output = net(fake_img, 'conv', 'relu')
  20. print(output)

5. 容器总结

Containers:

  • nn.Sequetial顺序性,各网络成之间严格按照顺序执行,常用语 block 构建
  • nn.ModuleList迭代性,常用于大量重复网络构建,通过 for 循环实现重复构建
  • nn.ModuleDict索引性,常用于可选择的网络层

11.2 AlexNet构建

AlexNet:2012 年以高出第二名 10 多个百分点的准确率获得 ImageNet 分类任务冠军,开创了卷积神经网络的新时代
AlexNet特点如下:

  1. 采用 ReLU:替换饱和激活函数(如,Sigmoid 函数),减轻梯度消失
  2. 采用 LRN(Local REsponse Normalization):对数据归一化,减轻梯度消失
  3. Dropout:提高全连接层的鲁棒性,增加网络的泛化能力
  4. Data Augmentation:TenCrop,色彩修改

12. nn中的网络层——卷积层

Content

  1. 1d/2d/3d 卷积
  2. 卷积 - nnConv2d()
  3. 转置卷积 - nn.ConvTranspose

12.1 1d/2d/3d Convolution

卷积运算:卷积核在输入信号(图像)上滑动,相应位置上进行乘加
卷积核:又称为滤波器、过滤器,可认为是某种模式、某种特征

卷积过程类似于用一个模板去图像上寻找与它相识的区域,与卷积核模式月相似,激活值越高,从而实现特征提取。

AlexNet卷积核可视化,发现卷积核学习到的是边缘、条纹色彩这一些细节模式

卷积维度:一般情况下,卷积核在几个维度上滑动,就是几维卷积;和卷积核的维度不一定一致,请勿混淆。
image.png

12.2 卷积 - nn.Conv2d()

nnConv2d()
功能:对多个二维信号进行二维卷积
主要参数:

  • in_channels:输入通道数
  • out_channels:输出通道数,等价于卷积核个数
  • kernel_size:卷积核尺寸
  • stride = 1:步长
  • padding = 0:填充个数,保持输入输出的尺寸一致
  • dilation = 1:空洞卷积大小
  • groups = 1:分组卷积设置
  • bias = True:偏置

尺寸计算:
简化版:不带 padding 和 dilation
Pytorch 框架训练营 - 图38

完整版:
Pytorch 框架训练营 - 图39

其中,Pytorch 框架训练营 - 图40 为输出尺寸;Pytorch 框架训练营 - 图41 为输入尺寸;Pytorch 框架训练营 - 图42 为内核尺寸;Pytorch 框架训练营 - 图43 为步长;Pytorch 框架训练营 - 图44 为填充个数;Pytorch 框架训练营 - 图45 为空洞卷积大小

12.3 转置卷积(Transpose Convlution)

转置卷积又称为反卷积(Deconvolution)和部分跨越卷积(Fractionally-strided Convolution),用于对图像进行上采样(UpSample)

为什么称为转置卷积?

正常卷积:
假设图像尺寸为:44 ,卷积核为:33 ,padding = 0 ,stride = 1 。
图像:Pytorch 框架训练营 - 图46

  • 16 ==> 4*4 = 16

卷积核:Pytorch 框架训练营 - 图47

  • 16 ==> 3*3=9,再根据前面的Pytorch 框架训练营 - 图48的形状补 0 得到 16
  • 4 ==> 输出特征图的尺寸得到的

输出:Pytorch 框架训练营 - 图49

转置卷积:
假设图像尺寸为:22,卷积核为:33,padding = 0,stride = 1
图像:Pytorch 框架训练营 - 图50

  • 4 ==> 2*2 = 4

卷积核:Pytorch 框架训练营 - 图51

  • 4 ==> 3*3 = 9,再剔除得到 4;因为能与图像相乘的最多只有 4 个
  • 16 ==> 根据输出特征图的尺寸计算得到

输出:Pytorch 框架训练营 - 图52

1. nn.ConvTranspose2d

nn.ConvTranspose2d
功能:装置卷积实现上采样
主要参数:

  • in_channels:输入通道数
  • out_channels:输出通道数,等价于卷积核个数
  • kernel_size:卷积核尺寸
  • stride=1:步长
  • padding=0:填充个数,保持输入输出的尺寸一致
  • groups=1:分组卷积设置
  • bias=True:偏置
  • output_padding=0,
  • dilation=1:空洞卷积大小
  • padding_mode=’zeros’
    1. # 转置卷积实现上采样
    2. nn.ConvTranspose2d(in_channels, # 输入通道数
    3. out_channels, # 输出通道数,等价于卷积核个数
    4. kernel_size, # 卷积核尺寸
    5. stride=1, # 步长
    6. padding=0, # 填充个数,保持输入输出的尺寸一致
    7. output_padding=0,
    8. groups=1, # 分组卷积设置
    9. bias=True, # 偏置
    10. dilation=1, # 空洞卷积大小
    11. padding_mode='zeros')

尺寸计算:
简化版:
Pytorch 框架训练营 - 图53

复杂版:
Pytorch 框架训练营 - 图54

13. nn中的网络层——池化层、线性层、激活函数层

Content

  1. 池化层——Pooling Layer
  2. 线性层——Linear Layer
  3. 激活函数层——Activation Layer

13.1 池化层(Pooling Layer)

池化运算:对信号进行“收集”并“总结”,类似水池收集水资源,因而得名池化层。

  • 收集:信号由多变少、尺寸由大变小
  • 总结:最大值/平均值

1. nn.MaxPool2d

nn.MaxPool2d
功能:对二维信号(图像)进行最大值池化
主要参数:

  • kernel_size:池化核尺寸
  • stride = None:步长,通常与kernel_size相同
  • padding = 0 :填充个数
  • dilation:池化核间隔大小
  • ceil_mode = False:尺寸向上/向下取整(尺寸计算中的除法操作是向上/向下取整,默认ceil_mode = False,向下取整。)
  • return_indices = False:记录池化像素索引
    1. # 1. 最大池化
    2. nn.MaxPool2d(kernel_size, # 池化核尺寸
    3. stride=None, # 步长,通常与kernel_size相同
    4. padding=0, # 填充个数
    5. dilation=1, # 池化核间隔大小
    6. return_indices=False, # 记录池化像素索引
    7. ceil_mode=False) # 尺寸向上取整

2. nn.AvgPool2d

nn.AvgPool2d
功能:对二维信号(图像)进行平均值池化
主要参数:

  • kernel_size:池化核尺寸
  • stride = None:步长,通常与kernel_size相同
  • padding = 0 :填充个数
  • ceil_mode = False:尺寸向上取整
  • count_include_pad = True:填充值用于计算
  • divisor_override = None :除法因子

注意事项:最大池化后的图片亮度大于平均池化的图片亮度

  1. # 2. 平均池化
  2. nn.AvgPool2d(kernel_size, # 池化核尺寸
  3. stride=None, # 步长,通常与kernel_size相同
  4. padding=0, # 填充个数
  5. ceil_mode=False, # 尺寸向上取整
  6. count_include_pad=True, # 填充值用于计算
  7. divisor_override=None) # 除法因子

3. nn.MaxUnpool2d

nn.MaxUnpool2d
功能:对二维信号(图像)进行最大值池化上采样
主要参数:

  • kernel_size:池化核尺寸
  • stride = None:步长,通常与kernel_size相同
  • padding = 0:填充个数
  1. # 3. 最大值反池化
  2. nn.MaxUnpool2d(kernel_size, # 池化核尺寸
  3. stride=None, # 步长,通常与kernel_size相同
  4. padding=0) # 填充个数
  5. # 在前向传播的过程中要添加反池化的索引值indices
  6. forward(self, input, indices, output_size=None)

13.2 线性层(Linear Layer)

线性层又称全连接层,其,每个神经元与上一层所有神经元相连实现对前一层的线性组合、线性变换。

image.png

Pytorch 框架训练营 - 图56Pytorch 框架训练营 - 图57

Pytorch 框架训练营 - 图58 = Pytorch 框架训练营 - 图59Pytorch 框架训练营 - 图60

Pytorch 框架训练营 - 图61Pytorch 框架训练营 - 图62

1. nn.Linear

nn.Linear
功能:对一维信号(向量)进行线性组合
主要参数:

  • in_features:输入结点数
  • out_features:输出结点数
  • bias :是否需要偏置

计算公式:Pytorch 框架训练营 - 图63

  1. # 对一维信号进行线性组合
  2. nn.Linear(in_features, # 输入结点数
  3. out_features, # 输出结点数
  4. bias=True) # 是否需要偏置

13.3 激活函数层

激活函数对特征进行非线性变换,赋予多层神经网络具有深度的意义
若无激活函数,多个线性层叠加等价于一个线性层

1. nn.Sigmoid

nn.Sigmoid
计算公式:Pytorch 框架训练营 - 图64

梯度公式:Pytorch 框架训练营 - 图65

特性:

  • 输出值在 (0,1) ,符合概率
  • 导数范围是 [0, 0.25] ,易导致梯度消失
  • 输出为非 0 均值,破坏数据分布

image.png

2. nn.tanh

nn.tanh
计算公式:Pytorch 框架训练营 - 图67

梯度公式:Pytorch 框架训练营 - 图68

特性:

  • 输出值在 (-1,1) ,数据符合0均值
  • 导数范围是 (0, 1) ,易导致梯度消失

image.png

3. nn.ReLU

nn.ReLU
计算公式:Pytorch 框架训练营 - 图70

梯度公式:Pytorch 框架训练营 - 图71

特性:

  • 输出值均为正数,负半轴导致死神经元
  • 导数是 1 ,缓解梯度消失,但易引发梯度爆炸

image.png

4. 改进的 nn.ReLU 激活函数

nn.LeakyReLU

  • negative_slope:负半轴斜率

nn.PReLU

  • init:可学习斜率

nn.RReLU

  • lower:均匀分布下限
  • upper:均匀分布上限

image.png

第四周

14. 权值初始化

Content

  1. 梯度消失与梯度爆炸
  2. Xavier 方法与 Kaiming 方法
  3. 常用初始化方法

14.1 梯度消失与梯度爆炸

1. 什么是梯度消失与梯度爆炸

image.png

Pytorch 框架训练营 - 图75

Pytorch 框架训练营 - 图76

Pytorch 框架训练营 - 图77 的梯度取决于上一层的输出 Pytorch 框架训练营 - 图78

梯度消失: Pytorch 框架训练营 - 图79
梯度爆炸: Pytorch 框架训练营 - 图80

2. 为什么会梯度消失与梯度爆炸

  1. Pytorch 框架训练营 - 图81
  2. Pytorch 框架训练营 - 图82
  3. Pytorch 框架训练营 - 图83

1.2.3 ==> Pytorch 框架训练营 - 图84
Pytorch 框架训练营 - 图85
Pytorch 框架训练营 - 图86

image.png
Pytorch 框架训练营 - 图88Pytorch 框架训练营 - 图89

由 ①② 可得:
Pytorch 框架训练营 - 图90
Pytorch 框架训练营 - 图91

3. 如何解决梯度消失与梯度爆炸

要解决梯度消失与梯度爆炸,就得使网络层的方差保持不变,这就得让网络层的方差为 1 。
Pytorch 框架训练营 - 图92
==>

==>

当然,这只能在没有激活函数的情况解决梯度消失与梯度爆炸。
在具有激活函数的情况下,还得通过其他方法解决梯度消失有梯度爆炸

14.2 Xavier 初始化

适用激活函数:饱和函数,如 Sigmoid、Tanh
方差一致性:保持数据尺度维持在恰当范围,通常方差为 1



由①②可得:

通常 Xavier 采用的是均匀分布:

故:

==>

14.3 Kaiming 初始化

适用激活函数:ReLU及其变种
方差一致性:保持数据尺度维持在恰当范围,通常方差为 1

ReLU变种:
(其中, a:负半轴的斜率;ReLU中负半轴斜率为 0 )

14.4 常用初始化方法

1. 常用的初始化方法

常用的初始化方法可以分为四大类:

  1. Xavier均匀分布
  2. Xavier标准正态分布

  3. Kaiming均匀分布

  4. Kaiming标准正态分布

  5. 均匀分布

  6. 正态分布
  7. 常数分布

  8. 正交矩阵初始化

  9. 单位矩阵初始化
  10. 稀疏矩阵初始化

2. nn.init.calculate_gain

nn.init.calculate_gain
主要功能:计算激活函数的方差变化尺度(输入数据的方差 / 经过激活函数之后输出数据的方差)
主要参数:

  • nonlinearity: 激活函数名称
  • param: 激活函数的参数,如 Leaky ReLU 的 negative_slop

15. 损失函数(一)

Content

  1. 损失函数概念
  2. 交叉熵损失函数
  3. NLL / BCE / BCEWithLogits Loss

15.1 损失函数概念

image.png
损失函数:衡量模型输出与真实标签的差异

损失函数(Loss Function):
计算一个样本:模型输出与真实标签的差异
代价函数(Cost Function):
计算整个训练集 的平均值
目标函数(Objective Function):
对模型进行的一些约束,以防止过拟合

  1. class _Loss(Module):
  2. def __init__(self, size_average=None, reduce=None, reduction='mean'):
  3. super(_Loss, self).__init__()
  4. if size_average is not None or reduce is not None:
  5. self.reduction = _Reduction.legacy_get_string(size_average, reduce)
  6. else:
  7. self.reduction = reduction

注意:
size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
所以不要再使用 size_average = None 与 reduce = None 这两个参数。

15.2 交叉熵损失函数

交叉熵

交叉熵 = 信息熵 + 相对熵

熵:
用来描述不确定性;熵越大,不确定性越大。
熵是自信息的期望
自信息: ( )

相对熵: ( P:真实的分布,Q:模型输出的分布 )
又称为 KL 散度,用来衡量两个分布之间的差异,也就是两个分布之间的距离;但是它不是一个距离的函数,它没有距离函数具有的对称性。

交叉熵:
衡量两个概率分布之间的关系,两个概率分布之间的相似度

相对熵:

交叉熵: ( P:真实的分布,Q:模型输出的分布 )

1. nn.CrossEntropyLoss

nn.CrossEntropyLoss
功能: nn.LogSoftmax() 与 nn.NLLLoss() 结合,进行交叉熵计算
主要参数:

  • weight=None:各类别 loss 设置的权值
  • ignore_index=-100:忽略某个类别
  • reduction=’mean’:计算模式,可为 none/sum/mean
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. # 计算交叉熵
      2. nn.CrossEntropyLoss(weight=None, # 各类别loss设置的权值
      3. ignore_index=-100, # 忽略某个类别
      4. reduction='mean') # 计算模式,如none/sum/mean
      5. # none:逐个元素计算
      6. # sum:所有元素求和,返回标题
      7. # mean:加权平均,返回标量
      计算公式:

15.3 NLL / BCE / BCEWithLogits Loss

2. nn.NLLoss

nn.NLLoss
功能:实现负对数似然函数中的负号功能
主要参数:

  • weigh t:各类别的 loss 设置权值
  • ignore_ind e x:忽略某个类别
  • reduction :计算模式,可为 none/sum /m e an
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. # 1. 实现负对数似然函数中的负号功能
      2. nn.NLLLoss(weight=None, # 各类别的loss设置权值
      3. ignore_index=-100, # 忽略某个类别
      4. reduction='mean') # 计算模式,如none/sum/
      计算公式:

3. nn.BCELoss

nn.BCELoss
功能:二分类交叉熵
注意事项:输入值取值在 [0,1]
主要参数:

  • weight:各类别的 loss 设置权值
  • ignore _index:忽略某个类别
  • reduction :计算模式,可为 none/sum /m e an
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. # 2. 二分类交叉熵
      2. # 注:输入值为[0,1],可配合sigmoid函数使用
      3. nn.BCELoss(weight=None, # 各类别loss设置的权值
      4. ignore_index=-100, # 忽略某个类别
      5. reduction='mean') # 计算模式,如none/sum/mean
      计算公式:

4. nn.BCEWithLogitsLoss

nn.BCEWithLogitsLoss
功能:结合 Sigmoid 与二分类交叉熵
注意事项:网络最后不加 Sigmoid 函数
主要参数:

  • pos_weight:正样本的权值
  • weight:各类别的 loss 设置权值
  • ignore _index:忽略某个类别
  • reduction:计算模式,可为 none/sum /mean
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. # 3. 结合Sigmoid与二分类交叉熵
      2. # 注:不需要额外加入Sigmoid函数
      3. nn.BCEWithLogitsLoss(weight=None, # 各类别loss设置的权值
      4. ignore_index=-100, # 忽略某个类别
      5. reduction='mean', # 计算模式,如none/sum/mean
      6. pos_weight=None) # 正样本的权值
      计算公式:

16. 损失函数(二)—— pytorch 中其余 14 中损失函数

Content

  1. nn.L1Loss
  2. nn.MSELoss
  3. nn.SmoothL1Loss
  4. nn.PoissonNLLLoss
  5. nn.KLDivLoss
  6. nn.MarginRankingLoss
  7. nn.MultiLabelMarginLoss
  8. nn.SoftMarginLoss
  9. nn.MultiLabelSoftMarginLoss
  10. nn.MultiMarginLoss
  11. nn.TripletMarginLoss
  12. nn.HingeEmbeddingLoss
  13. nn.CosineEmbeddingLoss
  14. nn.CTCLoss

16.1 回归中常用的两个损失函数

5. nn.L1Loss

nn.L1Loss
功能: 计算 inputs 与 target 之差的绝对值
主要参数:

  • reduction :计算模式,可为 none/sum/mean
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. nn.L1Loss(size_average=None,
      2. reduce=None,
      3. reduction='mean’)
      注意:
      size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
      所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

6. nn.MSELoss

nn.MSELoss
功能: 计算 inputs 与 target 之差的平方
主要参数:

  • reduction :计算模式,可为 none/sum/mean
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. nn.MSELoss(size_average=None,
      2. reduce=None,
      3. reduction='mean’)
      注意:
      size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
      所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

7. SmoothL1Loss

SmoothL1Loss
功能: 平滑的 L1Loss
主要参数:

  • reduction :计算模式,可为 none/sum/mean
  • none:逐个元素计算
  • sum:所有元素求和,返回标量
  • mean:加权平均,返回标量
  1. nn.SmoothL1Loss(size_average=None,
  2. reduce=None,
  3. reduction='mean’)

注意:
size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

image.png

8. PoissonNLLLoss

PoissonNLLLoss
功能:泊松分布的负对数似然损失函数
主要参数:

  • log_input :输入是否为对数形式,决定计算公式
  • full :计算所有 loss ,默认为 False
  • eps :修正项,避免 log(input) 为 nan
    1. nn.PoissonNLLLoss(log_input=True,
    2. full=False,
    3. size_average=None,
    4. eps=1e-08,
    5. reduce=None,
    6. reduction='mean')
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

9. nn.KLDivLoss

nn.KLDivLoss
功能:计算KLD(divergence),KL 散度,相对熵
注意事项:需提前将输入计算 log-probabilities ,如通过 nn.logsoftmax()
主要参数:

  • reduction :计算模式,可为 none/sum/mean/batchmean
    • batchmean:batchsize 维度求平均值
    • none:逐个元素计算
    • sum:所有元素求和,返回标量
    • mean:加权平均,返回标量
      1. nn.KLDivLoss(size_average=None,
      2. reduce=None,
      3. reduction='mean')
      注意:
      size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
      所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:
公式定义的计算公式:
P:真实标签分布,Q:模型输出分布

nn.KLDivLoss 函数的计算公式如下:

10. nn.MarginRankingLoss

nn.MarginRankingLoss
功能:计算两个向量之间的相似度,用于排序任务
特别说明:该方法计算两组数据之间的差异,返回一个 n*n 的 loss 矩阵
主要参数:

  • margin :边界值,x1 与 x2 之间的差异值
  • reduction :计算模式,可为 none/sum/mean
  1. nn.MarginRankingLoss(margin=0.0,
  2. size_average=None,
  3. reduce=None,
  4. reduction='mean')

注意:
size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

y = 1时, 希望x1比x2大,当 x1 > x2 时,不产生loss
y = -1时,希望x2比x1大,当 x2 > x1 时,不产生loss

11. nn.MultiLabelMarginLoss

nn.MultiLabelMarginLoss
功能:多标签边界损失函数
举例:四分类任务,样本 x 属于 0 类和 3 类,
标签:[0, 3, -1, -1] , 不是 [1, 0, 0, 1]
主要参数:

  • reduction :计算模式,可为 none/sum/mean
  1. nn.MultiLabelMarginLoss(size_average=None,
  2. reduce=None,
  3. reduction='mean')

注意:
size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:
x:模型输出值,y:真实标签。
举例:四分类任务,样本 x 属于 0 类和 3 类,标签 y:[0, 3, -1, -1] , 不是 [1, 0, 0, 1] ;
x 属于第几类,y 中就有几,随后用 -1 将 y 的长度补足到 x 的长度。

上述计算公式中 表示每个真实类别(标签所在)的神经元输出减去其他(非标签所在的)神经元的输出。
x[y[j]] 表示 样本x所属类的输出值,x[i] 表示不等于该类的输出值。

12. nn.SoftMarginLoss

nn.SoftMarginLoss
功能:计算二分类的 logistic 损失
主要参数:

  • reduction :计算模式,可为 none/sum/mean
    1. nn.SoftMarginLoss(size_average=None,
    2. reduce=None,
    3. reduction='mean')
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

13. nn.MultiLabelSoftMarginLoss

nn.MultiLabelSoftMarginLoss
功能:SoftMarginLoss 多标签版本
主要参数:

  • weight:各类别的 loss 设置权值
  • reduction :计算模式,可为 none/sum/mean
    1. nn.MultiLabelSoftMarginLoss(weight=None,
    2. size_average=None,
    3. reduce=None,
    4. reduction='mean')
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

14. nn.MultiMarginLoss

nn.MultiMarginLoss
功能:计算多分类的折页损失
主要参数:

  • p :可选 1 或 2
  • weight:各类别的 loss 设置权值
  • margin :边界值
  • reduction :计算模式,可为 none/sum/mean
    1. nn.MultiMarginLoss(p=1,
    2. margin=1.0,
    3. weight=None,
    4. size_average=None,
    5. reduce=None,
    6. reduction='mean')
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

15. nn.TripletMarginLoss

nn.TripletMarginLoss
功能:计算三元组损失,人脸验证中常用
主要参数:

  • p :范数的阶,默认为 2
  • margin :边界值
  • reduction :计算模式,可为 none/sum/mean

三元组:
image.png

  1. nn.TripletMarginLoss(margin=1.0,
  2. p=2.0,
  3. eps=1e-06,
  4. swap=False,
  5. size_average=None,
  6. reduce=None,
  7. reduction='mean')

注意:
size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

16. nn.HingeEmbeddingLoss

nn.HingeEmbeddingLoss
功能:计算两个输入的相似性,常用于非线性 embedding 和半监督学习
特别注意:输入 x 应为两个输入之差的绝对值
主要参数:

  • margin :边界值
  • reduction :计算模式,可为 none/sum/mean
    1. nn.HingeEmbeddingLoss(margin=1.0,
    2. size_average=None,
    3. reduce=None,
    4. reduction='mean’)
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

17. nn.CosineEmbeddingLoss

nn.CosineEmbeddingLoss
功能:采用余弦相似度计算两个输入的相似性;关注的是方向上的差异
主要参数:

  • margin :可取值 [-1, 1] , 推荐为 [0, 0.5]
  • reduction :计算模式,可为 none/sum/mean
    1. nn.CosineEmbeddingLoss(margin=0.0,
    2. size_average=None,
    3. reduce=None,
    4. reduction='mean')
    注意:
    size_average = None 与 reduce = None 这两个参数即将被舍弃,他们的功能在参数 reduction = ‘mean’ 中已经可以完全被实现了。
    所以不要再使用 size_average = None 与 reduce = None 这两个参数。

计算公式:

18. nn.CTCLoss

nn.CTCLoss
功能: 计算CTC损失,解决时序类数据的分类(Connectionist Temporal Classification)
主要参数:

  • blank :blank label
  • zero_infinity :无穷大的值或梯度置 0
  • reduction :计算模式,可为 none/sum/mean
    1. # 计算CTC损失,解决时序类数据的分类
    2. nn.CTCLoss(blank=0, # blank label
    3. reduction='mean', # 无穷大的值或梯度置0
    4. zero_infinity=False)

参考文献:
A. Graves et al.: Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks

损失函数总结

image.png

17. 优化器 Optimizer(一)

Content

  1. 什么是优化器
  2. optimizer 的属性
  3. optimizer 的方法

17.1 什么是优化器(Optimizer)

  • pytorch 的优化器:管理 更新 模型中可学习参数的值,使得模型输出更接近真实标签

image.png

  • 导数:函数在指定坐标轴上的变化率
  • 方向导数:函数在指定方向上的变化率
  • 梯度:向量,方向为方向导数取得最大值的方向

17.2 优化器的基本属性

基本属性:

  • defaults:优化器超参数
  • state:参数的缓存,如 momentum 的缓存
  • params_groups:管理的参数组
  • _step_count:记录更新次数,学习率调整中使用
    1. class Optimizer(object):
    2. def __init__(self, params, defaults):
    3. self.defaults = defaults # 优化器超参数
    4. self.state = defaultdict(dict) # 参数的缓存,如momentum的缓存
    5. self.param_grops = [] # 管理的参数组,包含字典元素的list
    6. # param_groups = [{'params': param_groups}]
    7. # _step_count:记录更新次数,学习率调整中使用
    8. ...

17.3 优化器的基本方法

基本方法:

1. zero_grad()

zero_grad():清空管理参数的梯度
注:pytorch中张量梯度不自动清零

  1. class Optimizer(object):
  2. def zero_grad(self):
  3. r"""Clears the gradients of all optimized :class:`torch.Tensor` s."""
  4. for group in self.param_groups:
  5. for p in group['params']:
  6. if p.grad is not None:
  7. p.grad.detach_()
  8. p.grad.zero_()

2. step()

step():执行一步更新

  1. class Optimizer(object):
  2. def __init__(self, params, defaults):
  3. self.defaults = defaults
  4. self.state = defaultdict(dict)
  5. self.param_groups = []
  6. def step(self, closure):
  7. r"""Performs a single optimization step (parameter update).
  8. Arguments:
  9. closure (callable): A closure that reevaluates the model and
  10. returns the loss. Optional for most optimizers.
  11. """
  12. raise NotImplementedError

3. add_param_group()

add_param_group():添加参数组

  1. class Optimizer(object):
  2. def add_param_group(self, param_group):
  3. for group in self.param_groups:
  4. param_set.update(set(group['params']))
  5. self.param_groups.append(param_group)

4. state_dict()

state_dict():获取优化器当前状态信息字典

  1. class Optimizer(object):
  2. def state_dict(self):
  3. return {
  4. 'state': packed_state,
  5. 'param_groups': param_groups,
  6. }

5. load_state_dict()

load_state_dict():加载状态信息字典

  1. class Optimizer(object):
  2. def state_dict(self):
  3. return {
  4. 'state': packed_state,
  5. 'param_groups': param_groups,
  6. }
  7. def load_state_dict(self, state_dict):

18. 常用的优化方法(优化器)

Content

  1. learning rate 学习率
  2. momentum 动量
  3. torch.optim.SGD
  4. Pytorch的十种优化器

18.1 learning rate 学习率

梯度下降:

例如:

image.png

梯度下降:

LR:学习率(learning rate)/步长,控制更新的步伐

18.2 momentum 动量

Momentum(动量,冲量):结合当前梯度与上一次更新信息,用于当前更新
指数加权平均:

例如:
image.png

梯度下降:

pytorch中更新公式:

例如:

18.3 torch.optim.SGD

optim.SGD
主要参数:

  • params:管理的参数组
  • lr:初始学习率
  • momentum:动量系数,贝塔
  • weight_decay:L2 正则化系数
  • nesterov:是否采用 NAG
    1. torch.optim.SGD(params, # 管理的参数组
    2. lr= < object object >, # 初始学习率
    3. momentum=0, # 动量系数beta
    4. dampening=0, # L2正则化系数
    5. weight_decay=0,
    6. nesterov=False) # 是否采用NAG

NAG参考文献:
《On the importance of initialization and momentum in deep learning》

18.4 Pytorch的十种优化器

pytorch中的十种优化器:

  1. optim.SGD:随机梯度下降法
  2. optim.Adagrad:自适应学习率梯度下降法
  3. optim.RMSprop:Adagrad 的改进
  4. optim.Adadelta:Adagrad 的改进
  5. optim.Adam:RMSprop 结合 Momentum
  6. optim.Adamax:Adam 增加学习率上限
  7. optim.SparseAdam:稀疏版的 Adam
  8. optim.ASGD:随机平均梯度下降
  9. optim.Rprop:弹性反向传播
  10. optim.LBFGS:BFGS 的改进

参考文献:

  1. optim.SGD: 《On the importance of initialization and momentum in deep learning 》
  2. optim.Adagrad: 《Adaptive Subgradient Methods for Online Learning and Stochastic Optimization》
  3. optim.RMSprop:http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf
  4. optim.Adadelta: 《 AN ADAPTIVE LEARNING RATE METHOD》
  5. optim.Adam: 《Adam: A Method for Stochastic Optimization》
  6. optim.Adamax: 《Adam: A Method for Stochastic Optimization》
  7. optim.SparseAdam
  8. optim.ASGD:《Accelerating Stochastic Gradient Descent using Predictive Variance Reduction》
  9. optim.Rprop:《Martin Riedmiller und Heinrich Braun》
  10. optim.LBFGS:BDGS 的改进

第五周

19. 学习率调整策略

Content

  1. 为什么要调整学习率?
  2. pytorch 的六种学习率调整策略
  3. 学习率调整小结

19.1 为什么要调整学习率?

梯度下降:

LR:学习率(learning rate)/步长,控制更新的步伐

  • 学习率大时,loss 下降得快,但到了一定程度不再下降
  • 学习率小时,loss 下降得多,但下降的速度慢
  • 在训练的过程中调整学习率,先大后小,可以使得训练的效率更高效果更好

19.2 基类——class _LRScheduler

1. class _LRScheduler 的主要属性

class _LRScheduler
主要属性:

  • optimizer:关联的优化器
  • last_epoch:记录 epoch 数
  • base_lrs:记录初始学习率

    1. class _LRScheduler(object):
    2. def __init__(self, optimizer, last_epoch=-1):

2. class _LRScheduler 的主要方法

class _LRScheduler
主要方法:

  • step():更新下一个 epoch 的学习率
  • get_lr():虚函数,计算下一个 epoch 的学习率

    1. class _LRScheduler(object):
    2. def __init__(self, optimizer, last_epoch=-1):
    3. def get_lr(self):
    4. raise NotImplementedError

19.3 pytorch 的六种学习率调整策略

1. StepLR

StepLR
功能:等间隔调整学习率
主要参数:

  • step_size:调整间隔数
  • gamma:调整系数

调整方式:

  1. # 1. StepLR
  2. # 等间隔调整学习率
  3. lr_scheduler.StepLR(optimizer,
  4. step_size, # 调整间隔数
  5. gamma=0.1, # 调整系数
  6. last_epoch=-1)

2. MultiStepLR

MultiStepLR
功能:按给定间隔调整学习率
主要参数:

  • milestones:设定调整时刻数
  • gamma:调整系数

调整方式:

  1. # 2. MultiStepLR
  2. # 按给定间隔调整学习率
  3. lr_scheduler.MultiStepLR(optimizer,
  4. milestones, # 设定调整时刻数,如[50,70,100]
  5. gamma=0.1, # 调整系数
  6. last_epoch=-1)

3. ExponentialLR

ExponentialLR
功能:按指数衰减调整学习率
主要参数:

  • gamma:指数的底

调整方式:

  1. # 3. ExponentialLR
  2. # 按指数衰减调整学习率
  3. lr_scheduler.ExponentialLR(optimizer,
  4. gamma=0.1, # 指数的底
  5. last_epoch=-1)

4. CosineAnnealingLR

CosineAnnealingLR
功能:余弦周期调整学习率
主要参数:

  • T_max:下降周期
  • eta_min:学习率下限

调整方式:

  1. # 4. CosineAnnealingLR
  2. # 余弦周期调整学习率
  3. lr_scheduler.CosineAnnealingLR(optimizer,
  4. T_max, # 下降周期
  5. eta_min=0, # 学习率下限
  6. last_epoch=-1)

5. ReduceLRonPlateau

ReduceLRonPlateau
功能:监控指标,当指标不再变化则调整学习率
主要参数:

  • mode:min/max 两种模式
    • mode = min:观察所要监控的指标下降,监控的指标不再下降就调整学习率;一般监控 loss
    • mode = max:观察所要监控的指标上升,监控的指标不再上升就调整学习率;一般监控分类准确率
  • factor:调整系数
  • patience:“耐心 ”,接受连续几次不变化
  • cooldown:“冷却时间”,停止监控一段时间
  • verbose:是否打印日志
  • min_lr:学习率下限
  • eps:学习率衰减最小值
  1. # 5. ReduceLRonPlateau
  2. # 监控指标,当指标不再变化时调整学习率
  3. # scheduler_lr.step(要监测的变量)
  4. lr_scheduler.ReduceLROnPlateau(optimizer,
  5. mode='min', # min/max两种模式
  6. factor=0.1, # 调整系数
  7. patience=10, # 接受参数不变化的迭代次数
  8. verbose=False, # 是否打印日志
  9. threshold=0.0001,
  10. threshold_mode='rel',
  11. cooldown=0, # 停止监控的迭代次数
  12. min_lr=0, # 学习率下限
  13. eps=1e-08) # 学习率衰减最小值

6. LambdaLR

LambdaLR
功能:自定义调整策略
主要参数:

  • lr_lambda:function or list
  1. # 6. LambdaLR
  2. # 自定义调整策略,可以对不同的参数组使用不同的参数调整策略
  3. lr_scheduler.LambdaLR(optimizer,
  4. lr_lambda, # 函数或元素为函数的列表
  5. last_epoch=-1)

19.4 学习率调整小结

学习率调整小结:

  1. 有序调整:Step、MultiStep、Exponential 和 CosineAnnealing

  2. 自适应调整:ReduceLROnPleateau

  3. 自定义调整:Lambda

19.5 学习率初始化

学习率初始化:

  1. 设置较小数:0.01、0.001、0.0001

  2. 搜索最大学习率: 《Cyclical Learning Rates for Training Neural Networks》

image.png
image.png

20. 可视化工具——TensorBoard

Content

  1. TensorBoard简介
  2. TensorBoard安装
  3. TensorBoard运行可视化

20.1 TensorBoard简介

image.png

1. TensorBoard简介

TensorBoard:TensorFlow 中强大的可视化工具
支持标量、图像、文本、音频、视频和 Eembedding 等多种数据可视化

image.png

2. 运行机制

image.png

20.2 TensorBoard安装

安装注意事项:
pip install tensorboard 的时候会报错:
ModuleNotFoundError: No module named ‘past’
通过 pip install future 解决

20.3 TensorBoard运行可视化

  1. tensorboard --logdir=./runs
  1. TensorFlow installation not found - running with reduced feature set.
  2. Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
  3. TensorBoard 2.5.0 at http://localhost:6006/ (Press CTRL+C to quit)

image.png

21. TensorBoard 使用(一)

Content

  1. SummaryWriter
  2. add_scalar and add_histogram
  3. 模型指标监控

image.pngimage.pngimage.png

image.png

21.1 SummaryWriter

SummaryWriter
功能:提供创建event file的高级接口
主要属性:

  • log_dir:event file 输出文件夹;默认 log_dir = None,表示在当前 .py 文件所在文件下创建一个 runs 文件夹
  • comment:不指定 log_dir 时,文件夹后缀
  • filename_suffix:event file 文件名后缀 ```python

提供创建event file的高级接口

class SummaryWriter(object): def init(self, log_dir=None, # event file 输出文件 comment=’’, # 不指定log_dir时,文件夹后缀 purge_step=None, max_queue=10, flush_secs=120, filename_suffix=’’) # event file文件名后缀

  1. <a name="Donud"></a>
  2. ### 21.2 add_scalar and add_histogram
  3. <a name="gfWcQ"></a>
  4. #### 1. add_scalar()
  5. add_scalar()<br />功能:记录标量
  6. 主要方法:
  7. - tag:图像的标签名,图的唯一标识
  8. - scalar_value:要记录的标量;可以理解为 y 轴
  9. - **global_step:x 轴**
  10. 注意事项:add_scalar() 只能记录一条曲线
  11. ```python
  12. # 1. add_scalar
  13. # 记录标量
  14. add_scalar(tag, # 图像的标签名,图的唯一标识
  15. scalar_value, # 要记录的标量
  16. global_step=None, # x轴
  17. walltime=None)

2. add_scalars()

add_scalars()
功能:记录标量;可以记录多条曲线
主要参数:

  • main_tag:该图的标签
  • tag_scalar_dict:key 是变量的 tag ,value 是变量的值
    1. # 1. add_scalars
    2. # 记录标量,可以记录多条曲线
    3. add_scalars(main_tag, # 该图的标签
    4. tag_scalar_dict, # key是变量的tag,value是变量的值
    5. global_step=None,
    6. walltime=None)

3. add_histogram()

add_histogram()
功能:统计直方图与多分位数折线图
主要参数:

  • tag:图像的标签名,图的唯一标识
  • values:要统计的参数
  • global_step:y 轴
  • bins:取直方图的 bins
  1. # 3. add_histogram
  2. # 统计直方图与多分位数折线图
  3. add_histogram(tag, # 图像的标签名,图的唯一标识
  4. values, # 要统计的参数
  5. global_step=None, # y轴
  6. bins='tensorflow', # 取直方图的bins
  7. walltime=None)

21.2 模型指标监控

22. TensorBoard 使用(二)——TensorBoaed 的图像可视化方法

Content

  1. add_image and torchvision.utils.make_grid
  2. AlexNet 卷积核与特征图可视化
  3. add_graph and torchsummary

image.pngimage.png

22.1 add_image and torchvision.utils.make_grid

4. add_image()

add_image()
功能:记录图像
主要参数:

  • tag:图像的标签名,图的唯一标识
  • img_tensor:图像数据,注意尺度
  • global_step:x 轴
  • dataformats:数据形式,CHW,HWC,HW
    1. # 4. add_image
    2. # 记录图像
    3. add_image(tag, # 图像的标签名,图的唯一标识
    4. img_tensor, # 图像数据,注意尺度
    5. global_step=None, # x轴
    6. walltime=None,
    7. dataformats='CHW') # 数据形式,CHW/HWC/HW

torchvision.utils.make_grid

torchvision.utils.make_grid
功能:制作网格图像
主要参数:

  • tensor:图像数据,BCH*W 形式
  • nrow:行数(列数自动计算)
  • padding:图像间距(像素单位)
  • normalize:是否将像素值标准化
  • range:标准化范围
  • scale_each:是否单张图维度标准化
  • pad_value:padding 的像素值
    1. # torchvision.utils.make_grid
    2. # 制作网格图像
    3. make_grid(tensor, # 图像数据,B*C*H*W形式
    4. nrow=8, # 行数(列数自动计算)
    5. padding=2, # 图像间距(像素单位)
    6. normalize=False, # 是否将像素值标准化
    7. range=None, # 标准化范围
    8. scale_each=False, # 是否单张图维度标准化
    9. pad_value=0) # padding的像素值

22.2 AlexNet 卷积核与特征图可视化

22.3 add_graph and torchsummary

5. add_graph()

add_graph()
功能:可视化模型计算图
主要参数:

  • model:模型,必须是 nn.Module
  • input_to_model:输出给模型的数据
  • verbose:是否打印计算图结构信息

注意事项:在 pytorch 1.2 版本中,add_graph() 有 bug

  1. # 5. add_graph
  2. # 可视化模型计算图
  3. add_graph(model, # 模型,必须是nn.Module
  4. input_to_model=None, # 输出给模型的数据
  5. verbose=False) # 是否打印计算图结构信息

torchsummary

torchsummary
功能:查看模型信息,便于调试
主要参数:

  • model:pytorch 模型
  • input_size:模型输入 size
  • batch_size:batch size
  • device:“cuda” or “cpu”
  1. # torchsummary
  2. # 查看模型信息,便于调试
  3. summary(model, # pytorch模型
  4. input_size, # 模型输入size
  5. batch_size=-1, # batch size
  6. device="cuda") # cuda/cpu

github: https://github.com/sksq96/pytorch-summary

23. Hook 函数与 CAM 可视化

Content

  1. Hook 函数概念
  2. Hook 函数与特征图提取
  3. CAM(Class Activation Map, 类激活图)

23.1 Hook函数概念

Hook函数机制:不改变主体,实现额外功能,像一个挂件

Hook函数:

  1. torch.Tensor.register_hook(hook)

  2. torch.nn.Module.register_forward_hook

  3. torch.nn.Module.register_forward_pre_hook
  4. torch.nn.Module.register_backward_hook

23.2 Hook 函数与特征图提取

1. torch.Tensor.register_hook(hook)

torch.Tensor.register_hook(hook)
功能:注册一个方向传播 hook 函数
hook 函数仅一个输入参数,为张量的梯度

  1. # 1.
  2. # 注册一个反向传播的hook函数
  3. # hook(grad) -> Tensor or None
  4. torch.Tensor.register_hook(hook)

记录梯度:

  1. # ----------------------------------- 2 tensor hook 2 -----------------------------------
  2. import torch
  3. w = torch.tensor([1.], requires_grad=True)
  4. x = torch.tensor([2.], requires_grad=True)
  5. a = torch.add(w, x)
  6. b = torch.add(w, 1)
  7. y = torch.mul(a, b)
  8. a_grad = list()
  9. def grad_hook(grad):
  10. a_grad.append(grad)
  11. handle = a.register_hook(grad_hook)
  12. y.backward()
  13. # 查看梯度
  14. print("gradient:", w.grad, x.grad, a.grad, b.grad, y.grad)
  15. print("a_grad[0]: ", a_grad[0])
  16. handle.remove()
  17. output
  18. """
  19. gradient: tensor([5.]) tensor([2.]) None None None
  20. a_grad[0]: tensor([2.])
  21. """

修改梯度:

  1. # ----------------------------------- 2 tensor hook 2 -----------------------------------
  2. import torch
  3. w = torch.tensor([1.], requires_grad=True)
  4. x = torch.tensor([2.], requires_grad=True)
  5. a = torch.add(w, x)
  6. b = torch.add(w, 1)
  7. y = torch.mul(a, b)
  8. a_grad = list()
  9. def grad_hook(grad):
  10. grad *= 2
  11. return grad * 3
  12. handle = w.register_hook(grad_hook)
  13. y.backward()
  14. # 查看梯度
  15. print("w.grad: ", w.grad)
  16. handle.remove()
  17. output
  18. """
  19. w.grad: tensor([30.])
  20. """

2. Module.register_forward_hook

Module.register_forward_hook
功能:注册 module 的前向传播 hook 函数;
参数:

  • module: 当前网络层
  • input:当前网络层输入数据
  • output:当前网络层输出数据
    1. # 2.
    2. # 注册module的前向传播hook函数
    3. # hook(module, input, output) -> None
    4. # module:当前网络层
    5. # input:当前网路层输入数据
    6. # output:当前网络层输出数据
    7. torch.nn.Module.register_forward_hook(hook)

通常使用 forward_hook 函数获得卷积输出的特征图
image.png

  1. # ----------------------------- 3 Module.register_forward_hook-----------------------------
  2. class Net(nn.Module):
  3. def __init__(self):
  4. super(Net, self).__init__()
  5. self.conv1 = nn.Conv2d(1, 2, 3)
  6. self.pool1 = nn.MaxPool2d(2, 2)
  7. def forward(self, x):
  8. x = self.conv1(x)
  9. x = self.pool1(x)
  10. return x
  11. def forward_hook(module, data_input, data_output):
  12. fmap_block.append(data_output)
  13. input_block.append(data_input)
  14. # 初始化网络
  15. net = Net()
  16. net.conv1.weight[0].detach().fill_(1)
  17. net.conv1.weight[1].detach().fill_(2)
  18. net.conv1.bias.data.detach().zero_()
  19. # 注册hook
  20. fmap_block = list()
  21. input_block = list()
  22. net.conv1.register_forward_hook(forward_hook)
  23. # inference
  24. fake_img = torch.ones((1, 1, 4, 4)) # batch size * channel * H * W
  25. output = net(fake_img)
  26. # 观察
  27. print("output shape: {}\noutput value: {}\n".format(output.shape, output))
  28. print("feature maps shape: {}\noutput value: {}\n".format(fmap_block[0].shape, fmap_block[0]))
  29. print("input shape: {}\ninput value: {}".format(input_block[0][0].shape, input_block[0]))
  30. output
  31. """
  32. output shape: torch.Size([1, 2, 1, 1])
  33. output value: tensor([[[[ 9.]],
  34. [[18.]]]], grad_fn=<MaxPool2DWithIndicesBackward>)
  35. feature maps shape: torch.Size([1, 2, 2, 2])
  36. output value: tensor([[[[ 9., 9.],
  37. [ 9., 9.]],
  38. [[18., 18.],
  39. [18., 18.]]]], grad_fn=<ThnnConv2DBackward>)
  40. input shape: torch.Size([1, 1, 4, 4])
  41. input value: (tensor([[[[1., 1., 1., 1.],
  42. [1., 1., 1., 1.],
  43. [1., 1., 1., 1.],
  44. [1., 1., 1., 1.]]]]),)
  45. """

3. Module.register_forward_pre_hook

Module.register_forward_pre_hook
功能:注册 module 前向传播的 hook函数
参数:

  • module: 当前网络层
  • input:当前网络层输入数据
    1. # 3.
    2. # 注册module前向传播前的hook函数
    3. # hook(module, input) -> None
    4. # module:当前网络层
    5. # input:当前网路层输入数据
    6. torch.nn.Module.register_forward_pre_hook(hook)
  1. # ------------------------------- 4 Module.register_pre_hook ------------------------------
  2. class Net(nn.Module):
  3. def __init__(self):
  4. super(Net, self).__init__()
  5. self.conv1 = nn.Conv2d(1, 2, 3)
  6. self.pool1 = nn.MaxPool2d(2, 2)
  7. def forward(self, x):
  8. x = self.conv1(x)
  9. x = self.pool1(x)
  10. return x
  11. def forward_pre_hook(module, data_input):
  12. print("forward_pre_hook input:{}".format(data_input))
  13. # 初始化网络
  14. net = Net()
  15. net.conv1.weight[0].detach().fill_(1)
  16. net.conv1.weight[1].detach().fill_(2)
  17. net.conv1.bias.data.detach().zero_()
  18. # 注册hook
  19. fmap_block = list()
  20. input_block = list()
  21. net.conv1.register_forward_pre_hook(forward_pre_hook)
  22. # inference
  23. fake_img = torch.ones((1, 1, 4, 4)) # batch size * channel * H * W
  24. output = net(fake_img)
  25. output
  26. """
  27. forward_pre_hook input:(tensor([[[[1., 1., 1., 1.],
  28. [1., 1., 1., 1.],
  29. [1., 1., 1., 1.],
  30. [1., 1., 1., 1.]]]]),)
  31. """

4. Module.register_backward_hook

Module.register_backward_hook
功能:注册 module 反向传播的 hook 函数
参数:

  • module: 当前网络层
  • grad_input:当前网络层输入梯度数据
  • grad_output:当前网络层输出梯度数据
  1. # 4.
  2. # 注册module反向传播的hook函数
  3. # hook(module, grad_input, grad_output) -> Tensor or None
  4. # module:当前网络层
  5. # grad_input:当前网络层输入梯度数据
  6. # grad_output:当前网络层输出梯度数据
  7. torch.nn.Module.register_backward_hook(hook)
  1. # ---------------------------- 5 Module.register_backward_hook ----------------------------
  2. class Net(nn.Module):
  3. def __init__(self):
  4. super(Net, self).__init__()
  5. self.conv1 = nn.Conv2d(1, 2, 3)
  6. self.pool1 = nn.MaxPool2d(2, 2)
  7. def forward(self, x):
  8. x = self.conv1(x)
  9. x = self.pool1(x)
  10. return x
  11. def backward_hook(module, grad_input, grad_output):
  12. print("backward hook input:{}".format(grad_input))
  13. print("backward hook output:{}".format(grad_output))
  14. # 初始化网络
  15. net = Net()
  16. net.conv1.weight[0].detach().fill_(1)
  17. net.conv1.weight[1].detach().fill_(2)
  18. net.conv1.bias.data.detach().zero_()
  19. # 注册hook
  20. fmap_block = list()
  21. input_block = list()
  22. net.conv1.register_backward_hook(backward_hook)
  23. # inference
  24. fake_img = torch.ones((1, 1, 4, 4)) # batch size * channel * H * W
  25. output = net(fake_img)
  26. loss_fnc = nn.L1Loss()
  27. target = torch.randn_like(output)
  28. loss = loss_fnc(target, output)
  29. loss.backward()
  30. output
  31. """
  32. backward hook input:(None, tensor([[[[0.5000, 0.5000, 0.5000],
  33. [0.5000, 0.5000, 0.5000],
  34. [0.5000, 0.5000, 0.5000]]],
  35. [[[0.5000, 0.5000, 0.5000],
  36. [0.5000, 0.5000, 0.5000],
  37. [0.5000, 0.5000, 0.5000]]]]), tensor([0.5000, 0.5000]))
  38. backward hook output:(tensor([[[[0.5000, 0.0000],
  39. [0.0000, 0.0000]],
  40. [[0.5000, 0.0000],
  41. [0.0000, 0.0000]]]]),)
  42. """

4. 特征图提取

23.3 CAM(Class Activation Map, 类激活图) and Grad-CAM

1. CAM

  • CAM:类激活图,Class Activation Map
  • Class Activation Map:在最后 Conv 层后、FC 层前增加 GAP 层,得到一组权重,与其对应特征图加权,得到 CAM

image.png

Grad-CAM:《Grad-CAM:Visual Explanations from Deep Networks via Gradient-based Localization》

2. Grad-CAM

  • Grad-CAM:CAM 的改进,使用梯度作为特征图权重

image.png
Grad-CAM:《Grad-CAM:Visual Explanations from Deep Networks via Gradient-based Localization》

3. CAM and Grad-CAM 实例

image.pngimage.png

分析与代码:https://zhuanlan.zhihu.com/p/75894080

第六周

24. L1 与 L2 正则化