BCELoss(binary_crossentropy)二分类交叉熵损失函数,用于图片多标签分类,n张图片分m类,会得到n*m的矩阵,经过sigmoid把矩阵数值变换到0~1,然后通过如下公式计算得到:
不同分类问题用到的激活函数和损失函数有所不同:
分类问题名称 | 输出层使用卷积函数 | 对应的损失函数 |
---|---|---|
二分类 | sigmoid函数 | 二分类交叉熵损失函数 |
多分类 | softmax函数 | 多分类交叉熵损失函数 |
多标签分类 | sigmoid函数 | 二分类交叉熵损失函数 |
inplace=true
的意思是进行覆盖运算,如:
nn.ConvTranspose2d(in_features, out_features, 3, stride=2, padding=1, output_padding=1),
nn.InstanceNorm2d(out_features),
nn.ReLU(inplace=True)
即对从上步InstanceNorm2d得到的tensor直接进行修改,这样节约内存,不用多存储其他变量。
class torch.nn.Conv2d(in_channels, out_channels,
kernel_size, stride=1, padding=0,
dilation=1, groups=1, bias=True,
padding_mode='zeros', device=None,
dtype=None)
功能解释:对由多个输入平面组成的输入信号运用二维卷积。
参数解释:
in_channels
:指输入的四维张量[N, C, H, W]中的C,即输入图像通道数;
out_channels
:指卷积后期望的输出张量的通道数;
kernel_size
:卷积核的大小,一般写一个数,如3,代表卷积核大小是3×3,如果卷积核左右大小不一样,则写成元组的形式,如kernel_size=(3, 5);
stride=1
:步长,默认为1,卷积核在图像窗口上每次平移的间隔,也可以为一个元组;
padding=0
:填充操作,默认为0,填充包括上下左右,比如原始图像大小为30×30,padding=1,则填充后,图像大小为32×32;
dilation=1
:是否采用空洞卷积,默认为1(不采用),一般采用默认值,先不深究其意思;
groups=1
:决定是否采用分组卷积,默认为1(不分组);
bias=True
:默认为True,是否要添加偏置参数作为一个可学习参数;
padding_mode=’zeros‘
:padding的模式,默认采用零填充。
卷积操作的一般公式:
H o = ( H i − K + 2 P ) / S + 1 H_o=(H_i-K+2P)/S+1 Ho=(Hi−K+2P)/S+1
其中, H H H也可以替换为 W W W,表示输入/输出的高度和宽度。
逆卷积,与卷积参数类似。
class torch.nn.ConvTranspose2d(in_channels,
out_channels,kernel_size,
stride=1, padding=0,
output_padding=0, groups=1,
bias=True, dilation=1)
in_channels(int)
– 输入信号的通道数
out_channels(int)
– 卷积产生的通道数
kerner_size(int or tuple)
- 卷积核的大小
stride(int or tuple,optional)
- 卷积步长,即要将输入扩大的倍数。
padding(int or tuple, optional)
- 输入的每一条边补充0的层数,高宽都增加2*padding
output_padding(int or tuple, optional)
- 输出边补充0的层数,高宽都增加padding
groups(int, optional)
– 从输入通道到输出通道的阻塞连接数
bias(bool, optional)
- 如果bias=True,添加偏置
dilation(int or tuple, optional)
– 卷积核元素之间的间距
每条边的输出尺寸的公式如下:
H o u t p u t = ( H i n p u t − 1 ) S − 2 P + K + o u t p u t p a d d i n g H_{output}=(H_{input}-1)S-2P+K+outputpadding Houtput=(Hinput−1)S−2P+K+outputpadding
pytorch中对于一般的序贯模型,可以直接调用torch.nn.Sequential类实现,但是对于复杂的模型,比如多输入多输出、多分支模型、跨层连接模型等等,就需要自己来定义。
nn.Module是nn中的一个类,可以用来自定义自己的网络,基本步骤:
(1)自定义一个类,要继承nn.Module类,并一定实现两个函数。__init__构造函数和forward方法,forward是层的逻辑运算函数,也即前向计算函数。
(2)__init__中定义参数。比如Linear层的权重和偏置,Conv2d层的in_channels,out_channels等。
(3)forward函数中实现前向计算。一般是通过torch.nn.functional函数实现,也可以自己定义运算方式,表示__init__中各层的连接关系(顺序等)。
注意一些技巧:
(1)一般把网络中具有可学习参数的层(如全连接层、卷积层等)放在构造函数__init__中。
(2)一般把不具有可学习参数的层(如ReLU)可放在构造函数中,如果不放在__init__中,则在forward方法里面可以使用nn.functional来代替。
(3)forward方法是必须要重写的,它是实现模型的功能,实现各个层之间的连接关系的核心。
(4)一般情况下,我们定义的参数是可以求导的,但是自定义操作如不可导,需要实现backward函数。
参考了:
(1)pytorch教程之nn.Module类详解
(2)pytorch教程之nn.Module类详解——使用Module类来自定义网络层
nn.parameter()
是将普通的tensor转换为module的可训练的参数,会被加入到parameter()这个迭代器中,成为模型的一部分,会随着模型的训练而变化,而module的非parameter的普通tensor不会加入到parameter()的迭代器中。
nn.ReflectionPad2d(padding)
函数作用:利用输入边界的反射来填充输入张量。
这句话有两个重要的词,“边界”和“反射”,边界是指输入张量的边界,“反射”类似物理中的镜面反射,就是以“边界”为反射面,将输入中的某行某列反射到界外,达到填充的目的。
当padding是一个int型时(如k),表示上下左右都填充相同的k;当padding是一个元组时(如(Left,Right, Top, Bottom)),这时按照元组的要求的那样进行填充。
代码示例:
# padding为int型:填充为1
import torch
import torch.nn as nn
m = nn.ReflectionPad2d(1)
input = torch.arange(9, dtype=torch.float).reshape(1, 1, 3, 3)
print(input)
print(m(input))
输出结果:
可以看出以蓝色框为“反射面”,将输入的
( 1 4 7 ) \begin{pmatrix} 1&\\ 4&\\ 7&\\ \end{pmatrix} ⎝⎛147⎠⎞
反射到外边以完成填充。
# padding为int型:填充为2
import torch
import torch.nn as nn
m = nn.ReflectionPad2d(2)
input = torch.arange(9, dtype=torch.float).reshape(1, 1, 3, 3)
print(input)
print(m(input))
输出结果:
可以看出,上下左右还是以边界为“反射面”进行反射填充,只是四个角(绿色框),是以黄色区域为边界进行反射填充。
#当padding为元组时:(1,1,0,2)意思是左右分别填充为1,上边填充0,下边填充2.
import torch
import torch.nn as nn
m = nn.ReflectionPad2d((1,1,0,2))
input = torch.arange(9, dtype=torch.float).reshape(1,1,3,3)
print(input)
print(m(input))
输出结果:
参考了:
1、图解pytorch padding方法 ReflectionPad2d
[⭐推荐⭐]对UNet结合pytorch代码介绍的一篇很不错的博文:
Pytorch深度学习实战教程(二):UNet语义分割网络|Jack Cui
feature map是输入图像经过卷积核卷积运算后得到的结果,表征的是输入图像的一种特征。
层与层之间会有若干个卷积核(kernel),上一层的每个feature map跟卷积核做卷积运算得到下一层的feature map。
当每层有多个feature map时,这几个feature map表示从不同角度对图片进行描述,比如颜色深浅、形状边缘、直线形状等,这几个feature map是不同卷积核卷积得到的结果。
参考了:
1、Feature Map
2、CNN中的feature map
激活函数 R e L U ReLU ReLU是将小于0的c值都置为零,函数图如下:
ReLU的效果图如下:
但是使用 R e L U ReLU ReLU容易出现梯度消失的问题。
L e a k y R e L U Leaky ReLU LeakyReLU可以解决这个问题,其表达式如下:
f ( n ) = { α x , x <0 x , x ≥0 f(n)= \begin{cases} αx, & \text {$x$ <0} \\ x, & \text{$x$≥0 } \end{cases} f(n)={αx,x,x <0x≥0
其效果图如下:
在生成对抗网络GAN中使用的是 L e a k y R e L U Leaky ReLU LeakyReLU而不是 R e L U ReLU ReLU。
参考了:
1、为什么在生成对抗网络(GAN)中,隐藏层中使用leaky relu比relu要好?