张量简介和创建

Tensor概念

张量是什么?是一个多维数组,它是标量、向量、矩阵的高维拓展。

Tensor与Variable

Variable是torch.autograd种的数据类型,主要用于封装Tensor,进行自动求导,具有5个属性:

  • data:被包装的Tensor
  • grad:data的梯度
  • grad_fn:创建Tensor的Function,是自动求导的关键
  • requires_grad:指示是否需要梯度
  • is_leaf:指示是否是叶子结点(张量)

PyTorch 0.4.0版开始,Varibable并入Tensor,Tensor具有8个属性,除了上面5个还有:

  • dtype:张量的数据类型,如torch.FloatTensortorch.cuda.FloatTensor

  • shape:张量的形状,如(64,3,224,224)

  • device:张量所在设备,GPU/CPU,是加速的关键

张量的创建

  1. 直接创建

    torch.tensor()从data创建tensor

    data:数据,可以是list,numpy

    dtype:数据类型,默认与data的一致

    device:所在设备,cuda/cpu

    requires_grad:是否需要梯度

    pin_memory:是否存于锁页内存

    torch.from_numpy(ndarray)

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

  2. 依据数值创建

    torch.zeros()

    size:张量的性质,如(3, 3)、(3, 224, 224)

    out:输出的张量

    layout:内存中布局形式,有 strided, sparse_coo等

    device:所在设备 gpu/cpu

    requires_grad:是否需要梯度

    torch.ones_like(), torch.full(), torch.full_like()

    torch.arange(start, stop, step)区间为[start, stop)

    torch.linspace(start, stop, step)区间为[start, stop]

    torch.logspace()

    start:数列的起始值

    stop:数列结束值

    steps:数列长度

    base:对数函数的底,默认为10

    torch.eye():创建单位对角矩阵

  3. 依据概率分别创建

    torch.narmal(mean, std, out=None):生成正态分布(高斯分布)

    mean:均值 std:标准差

    torch.randn(), torch.randn_like():标准整体分布

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

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

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

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

张量操作

张量拼接与切分

1.torch.cat(tensors, dim=0, oout=None):将张量按维度 dim 进行拼接,不会扩张维度

tensors:张量序列

dim:要拼接的维度

2.torch.stack(tensors, dim=0, oout=None):在新创建的维度 dim 上进行拼接,会扩张维度

tensors:张量序列

dim:要拼接的维度

cat 和 .stack的区别在于 cat会增加现有维度的值,可以理解为续接,stack会新加增加一个维度,可以理解为叠加

1.torch.chunk(input, chunks, dim=0):将张量按维度 dim 进行平均切分,返回值是张量列表

注意事项:若不能整除,最后一份张量小于其他张量

input:要切分的张量

chunks:要切分的份数

dim:要切分的维度

2.torch.split(tensor, split_size_or_sections, dim=0):将张量按维度dim进行切分

tensor:要切分的张量

split_size_or_sections:为int时,表示每一份的长度,为list时,按list元素切分

dim:要切分的维度

张量的索引

1.torch.index_select(input, dim, index, out=None):在维度dim上,按index索引数据

input:要索引的张量

dim:要索引的维度

index:要索引数据的序号

2.torch.masked_select(input, mask, out=None):按mask中的True进行索引

返回值是一维向量

input:要索引的张量

mask:与input同形状的布尔类型张量

张量变化

1.torch.reshape(input, shape):功能变换张量形状

注意事项:当张量在内存中是连续的,新张量与input共享数据内存

input:要变换的张量

shape:新张量的形状

2.torch.transpose(input, dim0, dim1):变换张量的两个维度

input:要变换的张量

dim0:要交换的维度

dim1:要交换的维度

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

4.torch.squeeze(input, dim, out=None):压缩长度为1的维度(轴)

dim:若为None,移除所有长度为1的轴;若指定维度,当且仅当该轴长度为1时,可以被移除

5.torch.unsqueeze(input, dim, out=None):依据dim扩展维度。

dim:扩展的维度

张量的数学运算

加减乘除

torch.add()
torch.addcdiv()
torch.addcmul()
torch.sub()
torch.div()
torch.mul()

torch.add(input, alpha=1, other,, out=None):逐元素计算 input + alpha*other

input:第一个张量

alpha:乘项因子

other:第二个张量

torch.addcmul(input, value=1, tensor1, tensor2, out=None)

 out i= input i+ value  tensor 1i tensor 2i\text { out }_{i}=\text { input }_{i}+\text { value } * \frac{\text{ tensor }1_{i}}{\text{ tensor }2_{i}}

torch.addcdiv()

 out i=inputi+valuetensor1itensor2i\text { out }_{i}=\text {input}_{i}+\text {value} * \text {tensor1}_{i} * \text {tensor} 2_{i}

对数,指数,幂函数

torch.log(input, out=None)
torch.log10(input, out=None)
torch.log2(input, out=None)
torch.exp(input, out=None)
torch.pow()

三角函数

torch.abs(input, output=None)
torch.acos(input, output=None)
torch.cosh(input, output=None)
torch.cos(input, output=None)
torch.asin(input, output=None)
torch.atan(input, output=None)
torch.atan2(input, output=None)

线性回归-例程

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

求解步骤:

  1. 确定模型:Model y=ωx+by=\omega x+b
  2. 选择损失函数 MSE:1mi=1m(yiy^i)2\frac{1}{m} \sum_{i=1}^{m}\left(y_{i}-\hat{y}_{i}\right)^{2}
  3. 求解梯度并更新ω,b\omega, bω=ωLRω.grad\omega = \omega - LR * \omega .grad b=bLRω.gradb=b-LR * \omega .grad

计算图与动态图机制

计算图

计算图是用来描述运算的有向无环图。计算图有两个主要元素:结点(Node)和边(Edge)

结点表示数据,如向量、矩阵、张量

边表示运算,如加减乘除卷积等

用计算图表示:

y=(x+ω)(ω+1)a=x+ωb=ω+1y=ab\begin{aligned} y &=(x+\omega) *(\omega+1) \\ a &=x+\omega \\ b &=\omega+1 \\ y &=a * b \end{aligned}

yyω\omega求导过程

yw=yaaw+ybbw=b1+a1=b+a=(w+1)+(x+w)=2w+x+1=21+2+1=5\begin{aligned} \frac{\partial y}{\partial w} &=\frac{\partial y}{\partial a} \frac{\partial a}{\partial w}+\frac{\partial y}{\partial b} \frac{\partial b}{\partial w} \\ &=b*1+a * 1 \\ &=b+a \\ &=(w+1)+(x+w) \\ &=2 * w+x+1 \\ &=2 * 1+2+1=5 \end{aligned}

过程:在计算图中找到所有yyω\omega的路径,把路径上的导数求和即可。

叶子结点:用户创建的结点称为叶子结点,比如xxω\omega

grad_fun:记录创建该张量时所用的方法(函数)

y.grad_fn = <MulBackward0>

a.grad_fn = <AddBackward0>

b.grad_fn = <AddBackward0>

动态图

动态图:运算与搭建同时进行

静态图:先搭建图,后运算

autograd-自动求导系统

autograd

torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False)

功能:自动求取梯度

  • tensors:用于求导的张量,如loss
  • retain_graph:保存计算图
  • create_graph:创建导数计算图,用于高阶求导
  • grad_tensors:多梯度权重

torch.autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False)

功能:求取梯度

autograd注意事项:

  1. 梯度不自动清零
  2. 依赖于叶子结点的结点,requires_grad默认为True
  3. 叶子结点不可执行in-place(原位操作/原地操作,即在原始数据内存中操作该数据)

Dataloader与DataSet

torch.utils.data.DataLoader

功能:构建可迭代的数据装载器

  • Dataset:DataSet类,决定数据从哪读取以及如何读取
  • batchsize:批大小
  • num_works:是否多进程读取数据
  • shuffle:每个epoch是否乱序
  • drop_list:当样本数不能被batchsize整除时,是否舍弃最后一批数据

Epoch:所有训练样本都已经输入到模型中,称为一个Epoch

Iteration:一批样本输入到模型中,称之为一个Iteration

Batchsize:批大小,决定一个Epoch有多少个Iteration

class DataSet(object):
def __getitem__(self, index):
raise NotImplementedError

def __add__(self, other):
return COncatDataSet([self, other])

torch.utils.data.Dataset

功能:Dataset抽象类,所有自定义的Dataset需要继承它,并且重写__getitem__(),getitem:接收一个索引,返回一个样本。

transforms图像增强

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

torchvision.datasets::常用的数据集的dataset实现,MNIST,CIFAR-10,IMageNet等

torch vision.model:常用的模型预训练,AlexNet,VGG,ResNet,GoogleNet等

torchvision:计算机视觉工具包

transforms

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

  • 数据中心化
  • 数据标准化
  • 缩放
  • 裁剪
  • 旋转
  • 翻转
  • 填充
  • 噪声添加
  • 灰度变换
  • 线性变换
  • 仿射变换
  • 亮度、饱和度以及对比度变换

transforms.Normalize功能:逐channel的对图像进行标准化

output = (input - mean)/ std

mean:各通道的均值

std:各通道的标准差

inplace:是否原地操作

图像增强:

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

裁剪transforms-crop

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

    size:所学裁剪图片的尺寸

  2. transforms.RandomCrop(size, padding=None, pad_if_needed=Flase, fill=0, padding_mode='constant'):从图片中随机裁剪出尺寸为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:镜像填充,最后一个像素不镜像,eg: [1,2,3,4] -> [3,2,|1,2,3,4,|4,3,2]; symmetric:镜像填充,最后一个像素镜像,eg:[1,2,3,4] -> [2,1,|1,2,3,4,|4,3]

    • fill:constant时,设置填充的像素值

  3. transforms.RandomResizeCrop(size, scale=(0.08, 1.0),ratio=(3/4,3/4),interpolation) :随机大小,长宽比裁剪图片

    • size:所需裁剪图片尺寸
    • scale:随机裁剪面积比例,默认(0.08,1)
    • ratio:随机长宽比,默认(3/4,4/3)
    • interpolation:插值方法 PIL.Image.NEAREST PIL.Image.BILINEAR PIL.Image.BICUBIC
  4. transforms.FiveCrop(size) transforms.TenCrop(size, vertical_flip=False) :在图像的上下左右以及中心裁剪出尺寸为size的5张图片,TenCrop对这5张图片进行水平或垂直镜像获得10张图片

    • size:所需裁剪图片尺寸
    • vertical_flip:是否垂直翻转

翻转、旋转

  1. RandomHorizontalFlip(p=0.5) RandomVerticalFlip(p=0.5):伊概率水平(左右)或垂直(上下)翻转图片;
    • p:翻转概率
  2. RandomRotation(degress, resample=False, expand=False, center=None) :随机旋转图片
    • degrees:旋转角度;当为a时,在(-a,a)之间选择旋转角度;当为(a,b)时,在(a,b)之间选择旋转角度
    • resample:重采样方法
    • expand:是否扩大图片,以保持原图信息
    • center:旋转点设置,默认中心旋转

图像变换

  1. Pad(padding, fill=0, padding_mode='constant'):对图片边缘进行填充

    • padding:设置填充大小,当为a时,上下左右均填充a个像素,当为(a,b)时,上下填充b个像素,左右填充a个像素;当为(a,b,c,d)时左上右下分别填充a,b,c,d
    • padding_mode :填充模式,4种模式,constant,edge,reflect和symmetric
    • fill:constant时,设置填充的像素值
  2. ColorJitter(brightness=0,contrast=0, saturation=0, hue=0) :调整亮度、对比度、饱和度和色相

    • brightness:亮度调整因子,当为a时,从[max(0, 1-a), 1+a]中随机选择,当为 (a,b)时,从 [a,b]中选择
    • congtrast:对比度参数,同brightness
    • saturation:饱和度参数,同brightness
    • hue:色相参数,当为a时,从 [-a, a]中选择参数,注: 0 <= a <= 0.5 ;当为 (a,b)时,从[a, b]中选择参数,注:-0.5 <= a <=b <=0.5
  3. Grayscale(num_output_channels, p=0.1) RandomGrayscale(num_output_channels) :依概率将图片转换为灰度图

    • num _output_channels :输出通道数,只能设1或3
    • p:概率值,图像被转化为灰度图的概率
  4. RandomAffine(degress, translate=None, scale=None, shear=None, resample=False, fillcolor=0)

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

    • degress:旋转角度设置
    • translate:平移区间设置,如(a,b)a设置宽(width)b设置高(height);图像在宽维度平移的区间为 -img_width * a < dx < img_widt * a
    • scale:缩放比例(以面积为单位)
    • fill_color:填充颜色设置
    • shear:错切角度设置,有水平错切和垂直错切。若为a,则仅在x轴错切,错切角度在(-a,a)之间,若为(a,b)则a设置x轴角度,b设置y轴角度,若为(a,b,c,d)则a,b设置x轴角度,c,d设置y轴角度
    • resample:重采样方式,有NEAREST,BILINEAR,BUCUBIC
  5. RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False)

    对图像进行随机遮挡

    • p:概率值,执行该操作的概率
    • scale:遮挡区域的面积
    • ratio:遮挡区域长宽比
    • value:设置遮挡区域的像素值 (R,G,B)或(Gray)
  6. transforms.Lambda(lambda) :用户自定义的lambda方法

    • lambd:lambda匿名函数 lambda [arg1 [arg2, …, argn]]: expression

transforms 操作

  1. transforms.RandomChoice([transforms1, transforms2, transform3]):从一系列transforms方法中随机挑选一个
  2. transforms.RandomApply([transforms1, transforms2, transform3], p=0.5) :依据概率执行一组transfroms操作
  3. transforms.RandomOrder([transforms1, transforms2, transform3]):对一组transforms操作打乱顺序

自定义transforms

自定义transforms要素:

  • 仅接收一个参数,返回一个参数
  • 注意上下游的输出与输入

通过类实现多参数传入:

class YourTransfroms(object):
def __init__(self,...):
...
def __call__(self, img):
...
return img

椒盐噪声又称为脉冲噪声,是一种随机出现的白点或者黑点,白点称为盐噪声,黑色为椒噪声

信噪比是衡量噪声的比例,图像中为图像像素的占比。

数据增强实战应用

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

空间位置:平移

色彩:灰度图,色彩抖动

形状:仿射变换

上下文场景:遮挡,填充

网络模型创建与nn.Module属性

网络模型创建步骤

nn.Module

nn.Module

  • parameters:存储管理nn.Parameter类
  • modules:存储管理nn.Module类
  • buffers:存储管理缓冲属性,如BN层中的running_mean
  • ***_hooks:存储管理钩子函数
self._paremeters = OrderedDict()
self._buffers = OrderedDict()
self._backward_hooks = OrderedDict()
self._forward_hooks = OrderedDict()
self._forward_pre_hooks = OrderedDict()
self._state_dict_hooks = OrderedDict()
self._load_state_dict_pre_hooks = OrderedDict()
self._modules = OrderedDict()

nn.Module总结:

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

模型容器

容器之Sequential

nn.Sequential是nn.Module的容器,用于按顺序包装一组网络层。

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

容器之ModuleList

ModuleList用于包装一组网络层,以迭代方式调用网络层。主要方法:

  • append():在ModuleList后面添加网络层

  • extend():拼接两个ModuleList

  • insert():指定在ModuleList中位置插入网络层

容器之ModuleDict

ModuleDict用于包装一组网络层,以索引方式调用网络层。主要方法:

  • clear(): 清空ModuleDict
  • items(): 返回可迭代的键值对(key-value pairs)
  • keys(): 返回字典的键(key)
  • values(): 返回字典的值(value)
  • pop(): 返回一对键值,并从字典中删除

容器总结

3种构建Module的方法

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

AlexNet

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

  • 采用ReLu:替换饱和激活函数,减轻梯度消失
  • 采用LRN(Local Response Normalizetion):对数据归一化,减轻梯度消失
  • Dropout:提高全连接层的鲁棒性,增加网络的泛化能力
  • Data Augmentation:TenCrop,色彩修改

卷积层

1d/2d/3d卷积

卷积运算:卷积核在输入信号(图像)上滑动,相应位置上进行乘加

卷积核:又称为滤波器,过滤器,可认为是某种模式,某种特征

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

卷积维度:一般情况下,卷积核在几个维度上滑动,就是几维卷积。

Conv2d

nn.Conv2d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros')

功能:对多个二维平面进行二维卷积

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

尺寸计算

简化版:outsize=insizekernelsizestride+1out_{size} = \frac{in_{size}-kernel_{size}}{stride} + 1

完整版:Hout=Hin+2× padding [0] dilation [0]×(kernelsize[0]1)1 stride [0]+1H_{o u t}=\left\lfloor\frac{H_{i n}+2 \times \text { padding }[0]-\text { dilation }[0] \times( kernel_{size}[0]-1)-1}{\text { stride }[0]}+1\right\rfloor

转置卷积

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

nn.ConvTranspose2d(in_channels,
out_channels,
kernek_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1,
padding_mode='zeros'
)

转置卷积实现上采样,参数与Conv2d类似。

尺寸计算:

简化版:outsize=( in size 1) stride + kernel sizeout_{size} =\left(\text { in }_{\text {size }}-1\right) * \text { stride }+\text { kernel }_{\text {size}}

完整版:Hout=(Hin1)× stride [0]2× padding [0]+ dilation [0]× (kernel sizef0 1)+ output-padding [0]+1\left.H_{\text {out}}=\left(H_{\text {in}}-1\right) \times \text { stride }[0]-2 \times \text { padding }[0]+\text { dilation }[0] \times \text { (kernel sizef0 }-1\right)+\text { output-padding }[0]+1

池化、线性、激活函数层

池化层 – Pooling Layer

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

收集:多变少。 总结:最大值/平均值

# 功能:对二维信号(图像)进行最大值池化
nn.MaxPool2d(kernel_size, stride=None,
padding=0, dilation=1,
return_indices=False,
ceil_mode=False)
  • kernel_size:池化核尺寸
  • stride:步长
  • padding:填充个数
  • dilation:池化核间隔大小
  • ceil_mode:尺寸向上取整
  • return_indices:记录池化像素索引
# 对图像进行平均池化
nn.AvgPool2d(kernek_size,
stride=None,
padding=0,
ceil_mode=False,
count_include_pad=True,
divisor_override=None)
  • kernel_size:池化核尺寸
  • stride:步长
  • padding:填充个数
  • ceil_mode:尺寸向上取整
  • count_include_pad:填充值用于计算
  • divisor_override:除法因子
# 对二维信号(图像)进行最大值池化上采样,反池化层
nn.MaxUnpool2d(kernel_size, # 池化核尺寸
stride=None, # 步长
padding=0) # 填充个数

forward(self, input, indices, out_size=None# forward 时要传入 indices 的值

线性层 – Linear Layer

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

nn.Linear(in_features, out_features, bias=True):对一维信号(向量)进行线性组合。

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

计算公式:y=xWT+biasy=xW^T+bias

激活函数层

激活函数对特征进行非线性变换,赋予多层神经网络具有深度的意义。

nn.Sigmoid

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

nn.tanh

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

nn.ReLu

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

nn.LeakyReLu negative_slope: 负半轴斜率

nn.PReLu init:可学习斜率

nn.RReLU lower:均匀分布下限,upper:均匀分布上限

权值初始化

梯度消失与爆炸

公式:

  1. E(XY)=E(X)E(Y){E}({X} * {Y})={E}({X}) * {E}({Y})
  2. D(X)=E(X2)[E(X)]2{D}({X})={E}\left({X}^{2}\right)-[{E}({X})]^{2}
  3. D(X+Y)=D(X)+D(Y){D}({X}+{Y})=D({X})+D({Y})

由1,2,3可以推出:

D(XY)=D(X)D(Y)+D(X)[E(Y)]2+D(Y)[E(X)]2{D}({X} * {Y})={D}({X}) * {D}({Y})+{D}({X}) *[E(Y)]^{2}+{D}({Y}) \star[E(X)]^{2}

E(X)=0,E(Y)=0E(X)=0, E(Y)=0,则

D(XY)=D(X)D(Y)D(X*Y)={D}({X}) * {D}({Y})

在神经网络中

H11=i=0nXiW1iD(H11)=i=0nD(Xi)D(W1i)=n(11)=nstd(H11)=D(H11)=n\begin{aligned} H_{11} &=\sum_{i=0}^{n} X_{i} * W_{1 i} \\ D\left(H_{11}\right)=& \sum_{i=0}^{n} D\left(X_{i}\right) * D\left(W_{1 i}\right) \\ =& n *(1 * 1) \\ =& n \\ s t d\left(H_{11}\right) &=\sqrt{D\left(H_{11}\right)}=\sqrt{n} \end{aligned}

若要保证梯度的尺度保持不变,则需要D(H11)=nD(X)D(W)=1D(H_{11}) = n * D(X) * D(W) = 1

D(W)=1nstd(W)=1nD(W)=\frac{1}{n} \Rightarrow {std}(W)=\sqrt{\frac{1}{n}}

加入激活函数后,会存在梯度消失的问题。

Xavier方法与Kaiming方法

Xavier初始化

方差一致性:保持数据尺度维持在恰当范围,通常方差为1

激活函数:饱和函数,如sigmoid,Tanh

参考文献《Understanding the difficulty of training deep feedforward neurtal networks》

Kaiming初始化

方差一致性:保持数据尺度维持在恰当范围,通常方差为1

激活函数:Relu及其变种

参考文献:《Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification》

常用初始化方法

十种初始化方法

  • Xavier均匀分布
  • Xavier正态分布
  • Kaiming均匀分布
  • Kaiming正太分布
  • 均匀分布
  • 正太分布
  • 常数分布
  • 正交矩阵初始化
  • 单位矩阵初始化
  • 稀疏矩阵初始化

nn.init.calculate_gain(nonlinearity, para=None):计算激活函数的方差变化尺度

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

损失函数

损失函数概念

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

损失函数(Loss Function):

 Loss =f(y,y)\text { Loss }=f\left(y^{\wedge}, y\right)

代价函数(Cost Function):

cost=1NiNf(yi,yi)\cos t=\frac{1}{N} \sum_{i}^{N} f\left(y_{i}^{\wedge}, y_{i}\right)

目标函数(Objective Function):

Obj=Cost+RegularizationObj = Cost + Regularization

1.交叉熵损失函数:

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

loss(x, class )= weight [ class ](x[ class ]+log(jexp(x[j])))\operatorname{loss}(x, \text { class })=\text { weight }[\text { class }]\left(-x[\text { class }]+\log \left(\sum_{j} \exp (x[j])\right)\right)

功能:nn.LogSoftmax()与nn.NLLLoss()结合,进行交叉熵计算。

  • weight:各类别的loss设置权值
  • ignore_index:忽略某个类别
  • reduction:计算模式,可为 none/sum/mean;none-逐个元素计算;sum-所有元素求和,返回标量值;mean-加权平均,返回标量

交叉熵 = 信息熵 + 相对熵

交叉熵:H(P,Q)=i=1NP(xi)logQ(xi)H(P, Q)=-\sum_{i=1}^{N} P\left(x_{i}\right) \log Q\left(x_{i}\right)

自信息:I(x)=log[p(x)]\mathrm{I}(x)=-\log [p(x)]

熵(信息熵):H(P)=Exp[I(x)]=iNP(xi)logP(xi)H(P)=E_{x \sim p}[I(x)]=-\sum_{i}^{N} P\left(x_{i}\right) \log P\left(x_{i}\right)

相对熵:

DKL(P,Q)=Exp[logP(x)Q(x)]=Exp[logP(x)logQ(x)]=l=1NP(xi)[logP(xi)logQ(xi)]=i=1NP(xi)logP(xi)i=1NP(xi)logQ(xi)=H(P,Q)H(P)\begin{aligned} D_{K L}(P, Q) &=E_{x \sim p}\left[\log \frac{P(x)}{Q(x)}\right] \\ &=E_{x \sim p}[\log P(x)-\log Q(x)] \\ &=\sum_{l=1}^{N} P\left(x_{i}\right)\left[\log P\left(x_{i}\right)-\log Q\left(x_{i}\right)\right] \\ &=\sum_{i=1}^{N} P\left(x_{i}\right) \log P\left(x_{i}\right)-\sum_{i=1}^{N} P\left(x_{i}\right) \log Q\left(x_{i}\right) \\ &=H(P, Q)-H(P) \end{aligned}

交叉熵:H(P,Q)=DKL(P,Q)+H(P)H(P,Q) = D_{KL}(P,Q) + H(P) ,其中 $P $ 是真实分布,QQ是模型输出的分布。优化交叉熵等价优化相对熵DKLD_{KL}

2.NLLLoss

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

(x,y)=L={l1,,lN}1,ln=wynxn,yn\ell(x, y)=L=\left\{l_{1}, \ldots, l_{N}\right\}^{1}, \quad l_{n}=-w_{y_{n}} x_{n, y_{n}}

功能:实现负对数似然函数中的负号功能

  • weight:各类别的loss设置权限
  • ignore_index:忽略某个类别
  • reduction:计算模式,可为none/sum/mean

3.二分类交叉熵

nn.BCELoss(weight=None,
size_average=None,
reduce=None,
reduction='mean')

ln=wn[ynlogxn+(1yn)log(1xn)]l_{n}=-w_{n}\left[y_{n} \cdot \log x_{n}+\left(1-y_{n}\right) \cdot \log \left(1-x_{n}\right)\right]

功能:二分类交叉熵,输入值取值在[0, 1]

  • weight:各类别的loss设置权限
  • ignore_index:忽略某个类别
  • reduction:计算模式,可为none/sum/mean

4.BCEWithLogitsLoss

nn.BCEWithLogitsLoss(weight=None,
size_average=None,
reduce=None,
reduction='mean',
pos_weight=None)

ln=wn[ynlogσ(xn)+(1yn)log(1σ(xn))]l_{n}=-w_{n}\left[y_{n} \cdot \log \sigma\left(x_{n}\right)+\left(1-y_{n}\right) \cdot \log \left(1-\sigma\left(x_{n}\right)\right)\right]

功能:结合Sigmoid与二分类交叉熵,注意:网络最后不加sigmoid函数

  • pos_weight:正样本的权值
  • weight:各类别的loss设置权值
  • ignore_index:忽略某个类别
  • reduction:计算模式,可为none/sum/mean

5.L1Loss

nn.L1Loss(size_average=None,
reduce=None,
reduction='mean')# 计算模式:none/sum/mean

ln=xnynl_{n}=\left|x_{n}-y_{n}\right|

功能:计算inputs与target之差的绝对值

6.MSELoss

nn.MSELoss(size_average=None,
reduce=None,
reduction='mean')# 计算模式:none/sum/mean

ln=(xnyn)2l_{n}=\left(x_{n}-y_{n}\right)^{2}

功能:计算inputs与target之差的平方

none-逐个元素计算

sum-所有元素求和,返回标量

mean-加权平均,返回标量

7.SmoothL1Loss

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

功能:平滑的L1Loss

loss(x,y)=1nizi\operatorname{loss}(x, y)=\frac{1}{n} \sum_{i} z_{i}

zi={0.5(xiyi)2, if xiyi<1xiyi0.5, otherwise z_{i}=\left\{\begin{array}{ll}{0.5\left(x_{i}-y_{i}\right)^{2},} & {\text { if }\left|x_{i}-y_{i}\right|<1} \\ {\left|x_{i}-y_{i}\right|-0.5,} & {\text { otherwise }}\end{array}\right.

8.PoissonNLLLoss

nn.PoissonNLLLoss(log_input=True,
full=False,
size_average=None,
eps=1e-08,
reduce=None,
reduction='mean')
"""
log_input = True时
loss(input, target) = exp(input) - target*input

log_input = False时
loss(input, target) = input - target*(input+eps)
"""

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

  • log_input:输入是否为对数形式,决定计算公式
  • full:计算所有loss,默认为False
  • eps:修正项,避免log(input)为Nan

9.KLDivLoss

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

功能:计算KLD(divergence)KL散度,相对熵。

注意事项:需提前将输入计算 log-probabilities,如通过nn.logsoftmax()

  • Watchman:batchsize维度求平均值

DKL(PQ)=Exp[logP(x)Q(x)]=Exp[logP(x)logQ(x)]=i=1NP(xi)(logP(xi)logQ(xi))\begin{aligned} D_{K L}(P \| Q)=E_{x-p}\left[\log \frac{P(x)}{Q(x)}\right] &=E_{x-p}[\log P(x)-\log Q(x)] \\ &=\sum_{i=1}^{N} \mathrm{P}\left(\mathrm{x}_{i}\right)\left(\log P\left(\mathrm{x}_{i}\right)-\log \mathrm{Q}\left(\mathrm{x}_{i}\right)\right) \end{aligned}

ln=yn(logynxn)l_{n}=y_{n} \cdot\left(\log y_{n}-x_{n}\right)

10.MarginRankingLoss

nn.MarginRankingLoss(margin=0.0,
size_average=None,
reduce=None,
reduction='mean'
)

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

  • margin:边界值,x1与x2之间的差异值。

loss(x,y)=max(0,y(x1x2)+margin)\operatorname{loss}(x, y)=\max (0,-y *(x 1-x 2)+\operatorname{margin})

11.MultiLableMarginLoss

nn.MultiLableMarginLoss(margin=0.0,
size_average=None,
reduce=None,
reduction='mean'
)

功能:多标签边界损失函数;

举例:四分类任务,样本x属于0类和3类,标签[0,3,-1,-1],不是[1,0,0,1]

loss(x,y)=ijmax(0,1(x[y[j]]x[i]))x. size(0)  where i=0 to x.size(0),j=0 to y.size(0),y[j]0, and iy[j] for all i and j\begin{array}{c}{\operatorname{loss}(x, y)=\sum_{i j} \frac{\max (0,1-(x[y[j]]-x[i]))}{x . \text { size(0) }}} \\ {\text { where } i=0 \text { to }{x.size(0), } j=0 \text { to } {y. size(0), } y[j] \geq 0, \text { and } i \neq y[j] \text { for all i and } j}\end{array}

12.SoftMarginLoss

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

功能:计算二分类的logistic损失

loss(x,y)=ilog(1+exp(y[i]x[i]))x. nelement ()\operatorname{loss}(x, y)=\sum_{i} \frac{\log (1+\exp (-y[i] * x[i]))}{x . \text { nelement } ()}

13.MultiLabelSoftMarginLoss

nn.MultiLabelSoftMarginLoss(
weight=None,
size_average=None,
reduce=None,
reduction='mean'
)

功能:SoftMarginLoss多标签版本

  • weight:各类别的loss设置权值
  • reduction:计算模式,none/sum/mean

loss(x,y)=1Ciy[i]log((1+exp(x[i]))1)+(1y[i])log(exp(x[i])(1+exp(x[i])))\operatorname{loss}(x, y)=-\frac{1}{C} * \sum_{i} y[i] * \log \left((1+\exp (-x[i]))^{-1}\right)+(1-y[i]) * \log \left(\frac{\exp (-x[i])}{(1+\exp (-x[i]))}\right)

14.MultiMarginLoss

nn.MultiLabelSoftMarginLoss(
p = 1,
margin=1.0,
weight=None,
size_average=None,
reduce=None,
reduction='mean'
)

功能:计算多分类的折页损失

  • P:可选1或2
  • weight:各类别的loss设置权值
  • margin:边界值

loss(x,y)=imax(0,marginx[y]+x[i]))pxsize(0)\operatorname{loss}(x, y)=\frac{\left.\sum_{i} \max (0, \operatorname{margin}-x[y]+x[i])\right)^{p}}{x \cdot \operatorname{size}(0)}

 where x{0,,x. size (0)1},y{0,,y. size (0)1},0y[j]x. size (0)1, and iy[j] for all i and j.\begin{array}{l}{\text { where } x \in\{0, \cdots, x . \text { size }(0)-1\}, y \in\{0, \cdots, y . \text { size }(0)-1\}, 0 \leq y[j] \leq x . \text { size }(0)-1, \text { and }} \\ {i \neq y[j] \text { for all } i \text { and } j .}\end{array}

15.TripletMarginLoss

nn.TripletMarginLoss(
margin=1.0,
p=2.0,
eps=1e-6,
swap=False,
weight=None,
size_average=None,
reduce=None,
reduction='mean'
)

功能:计算三元组损失,人脸验证中常用

  • P:范数的阶,默认为2
  • margin:边界值
  • reduction:计算模式

L(a,p,n)=max{d(ai,pi)d(ai,ni)+ margin ,0}d(xi,yi)=xiyip\begin{array}{c}{L(a, p, n)=\max \left\{d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\text { margin }, 0\right\}} \\ {d\left(x_{i}, y_{i}\right)=\left\|\mathbf{x}_{i}-\mathbf{y}_{i}\right\|_{p}}\end{array}

16.HingeEmbeddingLoss

nn.HingeEmbeddingLoss(
margin=1.0,
size_average=None,
reduce=None,
reduction='mean'
)

功能:计算两个输入的相似性,常用于非线性embedding和半监督学习。

注意:输入x应为两个输入之差的绝对值。

ln={xn, if yn=1max{0,Δxn}, if yn=1l_{n}=\left\{\begin{array}{ll}{x_{n},} & {\text { if } y_{n}=1} \\ {\max \left\{0, \Delta-x_{n}\right\},} & {\text { if } y_{n}=-1}\end{array}\right.

17.CosineEmbedding Loss

nn.CosineEmbedding.Loss(
margin=0.0,
size_average=None,
reduce=None,
reduction='mean'
)

功能:采用余弦相似度计算两个输入的相似性

loss(x,y)={1cos(x1,x2), if y=1max(0,cos(x1,x2) margin ), if y=1cos(θ)=ABAB=i=1nAi×Bii=1n(Ai)2×i=1n(Bi)2\begin{array}{rlr}{\operatorname{loss}(x, y)=\left\{\begin{array}{ll}{1-\cos \left(x_{1}, x_{2}\right),} & {\text { if } y=1} \\ {\max \left(0, \cos \left(x_{1}, x_{2}\right)-\text { margin }\right),} & {\text { if } y=-1}\end{array}\right.} \\ {\qquad \cos (\theta)=\frac{A \cdot B}{\|A\|\|B\|}=\frac{\sum_{i=1}^{n} A_{i} \times B_{i}}{\sqrt{\sum_{i=1}^{n}\left(A_{i}\right)^{2}} \times \sqrt{\sum_{i=1}^{n}\left(B_{i}\right)^{2}}}}\end{array}

margin:可取值[-1, 1]

18.CTCLoss

nn.CTCLoss(blank=0,
reduction='mean'),
zero_infinity=rFlase)

功能:计算CTC损失,解决时序类数据的分离

  • blank:blank label
  • zero_infinity:无穷大的值或梯度0
  • reduction::计算模式

优化器Optimizer

优化器

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

导数:函数在指定坐标轴上的变化率

方向导数:指定方向上的变化率

梯度:一个向量,方向为方向导数取得最大值的方向

class Optimizer(object):
def __init__(self, params, defaults):
self.defaults = defaults
self.state = defaultidict(dict)
self.param_groups = []

param_groups = [{'params': param_groups}]

基本属性:

  • defaults:优化器超参数
  • state:参数的缓存,如momentum的缓存
  • param_groups:管理的参数组,是一个list 字典中 key params存的模型中参数
  • _step_count:记录更新次数,学习率调整中使用

基本方法:

  • zero_grad():清空所管理参数的梯度 【pytorch特性:张量梯度不自动清零】
  • step() :执行一步更新
  • add_param_group():添加参数组
  • state_dict():获取优化器当前状态信息字典
  • load_state_dict():加载状态信息字典

随机梯度下降

学习率 learning rate

梯度下降:wi+1=wig(wi)w_{i+1} = w_i - g(w_i)

wi+1=wilrg(wi)w_{i+1} = w_i - lr * g(w_i)

学习率(learning rate)控制更新的步伐

动量 momentum

momentum(动量,冲量):结合当前梯度与上一次更新信息,用于当前更新

指数加权平均:vt=βvt1+(1β)θtv_t = \beta * v_{t-1} + (1 - \beta) * \theta_t

梯度下降:wi+1=wilrg(wi)w_{i+1} = w_i - lr * g(w_i)

pytorch中更新公式:

vi=mvi1+g(wi)v_i = m * v_{i-1} + g(w_i)

wi+1=wilrviw_{i+1} = w_i - lr * v_i

wi+1w_{i+1}:第i+1i+1次更新的参数

lrlr:学习率

viv_i:更新量

mm:momentum系数

g(wi)g(w_i)wiw_i的梯度

SGD

optim.SGD(params, lr=<object object>, momentum=0, dampening=0,weight_decay=0,
nesterov=False
)

params:管理的参数组

lr:初始学习率

momentum:动量系数,贝塔

weight_decay:L2正则化系数

nesterov:是否采用NAG

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

Pytorch的十种优化器

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

学习率的调整策略

为什么要调整学习率

学习率(learning rate)控制更新的步伐,前期学习率大,后期学习率小。

学习率的调整都是继承基类class_LRcheduler

属性:

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

方法:

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

Pytorch的六种学习率调整策略

  1. StepLR

    功能:等间隔调整学习率

    参数:step_size:调整间隔数

    ​ gamma:调整系数

    ​ 调整方式: lr=lrγlr = lr * \gamma

  2. MultiStepLR

    功能:按给定间隔调整学习率

    主要参数:milestones:设定调整时刻数

    ​ gamma:调整系数

    ​ 调整方式: lr=lrγlr = lr * \gamma

  3. ExponentialLR

    ​ 功能:按指数衰减调整学习率

    ​ 主要参数:gamma:指数的底

    调整方式: lr=lrγepochlr = lr * \gamma ^ {epoch}

  4. CosineAnnealingLR

    功能:余弦周期调整学习率

    主要参数:T_max:下降周期

    ​ eta_min:学习率下限

    调整方式:ηt=ηmin+12(ηmaxηmin)(1+cos(TcurTmaxπ))\eta_{t}=\eta_{\min }+\frac{1}{2}\left(\eta_{\max }-\eta_{\min }\right)\left(1+\cos \left(\frac{T_{\operatorname{cur}}}{T_{\max }} \pi\right)\right)

  5. ReduceLRonPlateau

    功能:监控指标,当指标不再变化则调整

    主要参数:mode:min/max两种模式

    ​ factor:调整系数

    ​ patience:耐心,接受几次不变化

    ​ cooldown:冷却时间,停止监控一段时间

    ​ verbose:是否打印日志

    ​ min_lr:学习率下限

    ​ eps:学习率衰减最小值

  6. LambdaLR

    功能:自定义调整策略

    主要参数:lr_lambda:function or list

学习率调整小结

  1. 有序调整:Step、MultiStep、Exponential和CosineAnnealing
  2. 自适应调整:ReduceLROnPleateau
  3. 自定义调整:Lambda

学习率初始化:

  1. 设置较小数:0.01、0.001、0.0001
  2. 搜索最大学习率:《Cyclical Learning Rates for Training Neural Networks》

可视化工具–TensorBoard

迭代训练可视化

TensorBoard:TensorFLow中强大的可视化工具

支持标量、图像、文本、音频、视频和Eembedding等多种数据可视化。

python脚本:记录可视化的数据

硬盘:event file

终端:tensorboard 读取event file

网页:现实可视化结果

SummaryWriter

  1. SummaryWriter

功能:提高创建event file的高级接口

主要属性:

  • log_dir:event file输出文件夹
  • commen:不指定log_dir是,文件夹后缀
  • filename_suffix:event file文件名后缀
  1. add_scalar() 功能:记录标量
  • tag:图像的标签名,图的唯一标识
  • scalar_value:要记录的标量
  • global_step:x轴

add_scalars()

  • main_tag:该图的标签
  • tag_scalar_dict:key是变量的tag,value是变量的值
  1. add_histogram()

功能:统计直方图与多分位数折线图

  • tag:图像的标签名,图的唯一标识
  • values:要统计的参数
  • global_step:y轴
  • bins:取直方图的bins
  1. add_image()

功能:记录图像

  • tag:图像的标签名,图的唯一标识
  • img_tensor:图像数据,注意尺度(需要0-255)
  • global_step:x轴
  • dataformats:数据形式,CHW,HWC,HW
  1. torchvision.utils.make_grid

功能:制作网格图像

  • tensor:图像数据,B*C*H*W形式
  • nrow:行数,列数自动计算
  • padding:图像间距(像素单位)
  • normalize:是否将像素值标准化
  • range:标准化范围
  • scale_each:是否单张图维度标准化
  • pad_value:padding的像素值
  1. add_graph()

功能:可视化模型计算图

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

功能:查看模型信息,便于调试

  • model:pytorch模型
  • input_size:模型输入size
  • batch_size:batch size
  • device:cuda或者cpu

Hook函数

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

  1. Tensor.register_hook

    功能:注册一个反向传播hook函数

    hook函数仅一个输入参数,为张量的梯度

    hook(grad)->Tensor or None

  2. Module.register_forward_hook

    功能:注册module的前向传播hook函数

    • module:当前网络层
    • input:当前网络层输入数据
    • output:当前网络层输出数据
  3. Module.register_forward_pre_hook

    功能:注册module前向传播前的hook函数

    • module:当前网络层
    • input:当前网络层输入数据
  4. Module.register_backward_hook

    功能:注册module反向传播的hook函数

    • module:当前网络层
    • grad_input:当前网络层输入梯度数据
    • grad_output:当前网络层输出梯度数据

类激活图

CAM:类激活图,class activation map 《Learning Deep Features for Discriminative Localization》

对特征图加权求和。

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

正则化

Regularization:正则化,减少方差的策略

误差可以分解为:偏差、方差和噪声值和,即误差 = 偏差 + 方差 + 噪声之和

偏差 度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力

方差 度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了数据扰动所造成的影响

噪声 则表达了在当前任务上任何学习算法所能达到的期望泛化误差的下界

过拟合就是高方差

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

目标函数(Objective Function)

Obj = Cost + Regularization Trem (目标函数是损失函数+正则项)

L1正则项:iNwi\sum_{i}^{N}|w_i|

L2正则项:iNwi2\sum_{i}^{N}|w_{i}^{2}|

L2 Regularization = weight decay(权值衰减)

Obj=Loss+λ2iNwi2Obj = Loss + \frac{\lambda}{2}*\sum_{i}^{N}w_i^2

若不加正则项

wi+1=wiobjwi=wiLosswiw_{i+1} = w_i - \frac{\partial obj}{\partial w_i} = w_i - \frac{\partial Loss}{\partial w_i}

加上正则项后:

wi+1=wiobjwi=wi(Losswi+λwi)=wi(1λ)(Losswi)w_{i+1} = w_i - \frac{\partial obj}{\partial w_i} = w_i - (\frac{\partial Loss}{\partial w_i} + \lambda * w_i) =w_i(1- \lambda)-(\frac{\partial Loss}{\partial w_i})

其中0<λ<10<\lambda<1

dropout

Dropout:随机失活

随机:dropout probability

失活:weight=0

数据尺度变化:测试时,所有权重乘以 1 - drop_prob

nn.Dropout

功能:Dropout层 参数:被舍弃的概率,失活概率

实现细节:训练时权重均乘以11p\frac{1}{1-p},即除以1p1-p

Batch Normalization

Batch Normalization:批标准化

批:一批数据,通常为mini-batch

标准化:0均值,1方差

优点:

  • 可以用更大学习率,加速模型收敛
  • 可以不用精心设计权值初始化
  • 可以不用dropout或较小的dropout
  • 可以不用L2或者较小的weight decay
  • 可以不用LRN(local response normalization)

《Batch Normalization:Accelerating Deep Network Training by Reducing Internal Covariate Shift》

计算方式:

Batch Normalization是为了解决Internal Covariate Shift(ICS,数据尺度/分布变化)

函数:_BatchNorm

  • nn.BatchNorm1d
  • nn.BatchNorm2d
  • nn.BatchNorm3d

参数:

  • num_features:一个样本特征数量(最重要)
  • eps:分母修正项
  • momentum:指数加权平均估计 当前mean/var
  • affine:是否需要affine transfrom
  • track_running_stats:是训练状态,还是测试状态

主要属性:

  • running_mean:均值
  • running_var:方差
  • weight:affine transform中的gamma
  • bias:affine transform中的beta

对每个特征维度(每一行)都要对4个参数进行计算

训练时:均值和方差采用指数加权平均

测试时:当前统计值

对数据要求:

  • n n.BatchNorm1d input = B *特征数 * 1d特征
  • n n.BatchNorm1d input = B *特征数 * 1d特征
  • n n.BatchNorm1d input = B *特征数 * 3d特征

为什么要Normalization

Internal Covariate Shift(ICS):数据尺度/分布异常,导致训练困难

常见的Normalization

  • Batch Normalization(BN)
  • Layer Normalization(LN)
  • Instance Normalization(IN)
  • Group Normalization(GN)

不同之处是均值和方差求取方式。

Layer Normalization

起因:BN不适用于变长的网络,如RNN

思路:逐层计算均值和方差

注意事项:

  1. 不再有 running_mean和running_var
  2. gamma和beta为逐元素的

nn.LayerNorm

主要参数:

  • normalized_shape:该层特征形状
  • eps:分母修正项
  • elementwise_affine:是否需要affine transform

Instance Normalization(IN)

起因:BN在图像生成(Image Generation)中不适用

思路:逐Instance(channel)计算均值和方差

nn.InstanceNorm

主要参数:

  • num_features:一个样本特征数量(最重要)
  • eps:分母修正项
  • momentum:指数加权平均估计当前mean/var
  • affine:是否需要affine transform
  • track_running_stats:是训练状态还是测试状态

Group Normalization

起因:小batch样本中,BN估计的值不准

思路:数据不够,通道来凑

注意事项:

  1. 不再有running_mean和running_var
  2. gamma和beta为逐通道的(channel)的

应用场景为大模型(小batch size)任务

nn.GroupNorm

主要参数:

  • num_groups:分组数
  • num_channels:通道数(特征数)
  • eps:分母修正项
  • affine:是否需要affine transform

Normalization 小结

BN,LN,IN,GN从学术化上解释差异:

  • BatchNorm:batch方向做归一化,算NHW的均值,对小batchsize效果不好;BN主要缺点是对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布
  • LayerNorm:channel方向做归一化,算CHW的均值,主要对RNN作用明显;
  • InstanceNorm:一个channel内做归一化,算H*W的均值,用在风格化迁移;因为在图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。
  • GroupNorm:将channel方向分group,然后每个group内做归一化,算(C//G)HW的均值;这样与batchsize无关,不受其约束。
  • SwitchableNorm是将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。

下图是四种Normalization方式的一个汇总。

  • 图中每一个正方体块表示一个数据(比如说这里一个正方体就是一个图像)
  • 每一个正方体中的C, H, W分别表示channel(通道个数), height(图像的高), weight(图像的宽)
  • 下图介绍了4中Norm的方式, 如Layer Norm中NHWC->N111表示是将后面的三个进行标准化, 不与batch有关.
  • 我们可以看到, 后面的LayerNorm, InstanceNorm和GroupNorm这三种方式都是和Batch是没有关系的

模型保持与加载

序列化与反序列化

torch.save

  • obj:对象
  • f:输出路径

torch.load

  • f:文件路径
  • map_location:指定存放位置,cpu or gpu

模型保持与加载

  1. 保存整个Module

torch.save(net, path)

  1. 保存模型参数(官方推荐)

state_dict = net.state_dict()

torch.save(state_dict, path)

断点续训练

checkpoint = {
"model_state_dict": net.state_dict(),
"optimizer_state_dict": optimizer.state_dict(),
"epoch": epoch
}

模型finetune

模型微调

Transfer Learning:机器学习分支,研究源域(source domain)的知识如何应用到目标域(target domain)

Model Finetune:模型的迁移学习

模型微调步骤

  1. 获取预训练模型参数
  2. 加载模型(load_state_dict)
  3. 修改输出层

模型微调训练方法(两种方法)

  1. 固定预训练的参数(requires_grad=Flase; or lr=0)
  2. Features Extractor较小学习率(params_group)

GPU使用

CPU与GPU

CPU(Central Processing Unit,中央处理器):主要包括控制器和运算器

GPU(Graphics Processing Unit,图形处理器):处理统一的,无依赖的大规模数据运算

数据迁移至GPU

data.to("cuda")

data.to("cpu)

to函数:转换数据类型/设备

tensor.to(*args, **kwargs)

module.to(*args, **kwargs)

区别:张量不执行inplace,模型执行inplace

torch.cuda常用方法

  • torch.cuda.device_count()计算当前可见可用GPU数
  • torch.cuda.get_device_name()获取GPU名称
  • torch.cuda.manual_seed()为当前GPU设置随机种子
  • torch.cuda.manual_seed_all()为所有可见可用的GPU设置随机种子
  • torch.cuda.set_device()设置主GPU为哪一个物理GPU(不推荐)

推荐os.environ,setdefault("CUDA_VISIBLE_DEVICES", "2, 3)

多GPU运算的分发并行机制

torch.nn.DataParallel

功能:包装模型,实现分发并行机制

主要参数:

  • module:需要包装分发的模型
  • device_ids:可分发的gpu,默认分发到所有可见可用的GPU
  • output_device:结果输出设备

查询当前GPU内存剩余

def get_gpu_memory():
import os
os.system('nvidia-smi -q -d Memory | grep -A4 GPU | grep Free > tmp.txt')
memory_gpu = [int(x.split()[2]) for x in open('tmp.txt', 'r').readlines()]
os.system('rm tmp.txt')
return memory_gpu

PyTorch常见错误

参考:PyTotch常见报错/坑汇总

常见应用

Image Classification 图像分类

图像分类

Interence代码基本步骤:

  1. 获取数据与模型

  2. 数据变换,如RGB --> 4D-Tensor

  3. 前向传播

  4. 输出保存预测结果

注意事项:

  • 确保model处于eval而非training
  • 设置torch.no_grad(),减少内存消耗
  • 数据预处理保持一致,RGB or BGR?

Image Segmentation 图像分割

图像分割:将图像每一个像素分类

分类:

  • 超像素分割:少量超像素代替大量像素,常用于图像预处理
  • 语义分割:逐像素分类,无法区分个体
  • 实例分割:对个体目标进行分割,像素级目标检测
  • 全景分割:语义分割结合实例分割

PyTorch-Hub:PyTorch模型库,有大量模型供开发者调用

  1. torch.hub.load('pytorch/vision', 'deeplabv3_resnet101', pretrained=True)

    model = torch.hub.load(github, model, *args, **kwargs)

    功能:加载模型

    主要参数:

    • github:str,项目名,eg:pytorch/vision, <repo_owner/repo_name[:tag_name]>
    • model:str,模型名
  2. torch.hub.list(github, force_reload=False)

  3. torch.hub.help(github, model, force_reload=False)

深度学习中的图像分割模型

  1. FCN:

    最主要贡献:利用全卷积完成pixelwise prediction

  2. UNet:

    最主要贡献:奠定Unet系列分割模型

​ 基本结构:编码器与解码器的特征融合

​ 总结:Unet总结

  1. DeepLab系列–V1

    ​ 主要特点:1. 孔洞卷积:借助孔洞卷积,增大感受野

    ​ 2. 采用CRF进行mask后处理

  2. DeepLab系列–V2

    ​ 主要特点:ASPP(Atrous spatial pyramid pooling)解决多尺度问题

  3. DeepLab系列–V3

    ​ 主要特点: 1. 孔洞卷积的串行

    ​ 2. ASPP的并行

  4. DeepLab系列–V3+

    ​ 主要特点: 在v3基础上加上了Encoder-Decoder的思想

综述文章:《Deep Semantic Segmentation of Natural and Medical Images: A Revice》2019

资源:1. Unet-family

​ 2. Pytorch_segmentation

Object Detection 目标检测

目标检测:判断图像中目标的位置

目标检测两要素:

  • 分类:分类向量[p0, …, pn]
  • 回归:回归边界框[x1, y1, x2, y2]

如何完成目标检测:

将3D张量映射到两个张量:

  1. 分类张量:shape为[N, c+1]
  2. 边界框张量:shape为[N, 4]

边界框数量N如何确定:

传统方法–滑动窗策略;缺点:重复计算量大,窗口大小难确定

利用卷积来减少重复计算,用卷积来实现滑动窗策略。

Faster RCNN --经典two stage 检测网络

Faster RCNN数据流:

  1. Feature Map:[256, h_f, w_f]
  2. 2 Softmax:[num_anchors, h_f, w_f]
  3. Regressors:[num_anchors*4, h_f, w_f]
  4. NMS Out:[n_proposals=2000, 4]
  5. ROI Layer:[512, 256, 7, 7]
  6. FC1, FC2:[512, 1024]
  7. c + 1 Softmax:[512, c+1]
  8. Regressors:[512, (c+1)*4]

代码结构

  1. torchvision.models.detection.fasterrcnn_resnet50_fpn():返回FasterRCNN实例

  2. class FasterRCNN(GeneralizedRCNN)

  3. class GeneralizedRCNN(nn.Module)

    forward():

    • features:features = self.backbone(images.tensors)
    • proposals:proposal_losses = self.rpn(images, features, targets)
    • detections:detector_losses = self.roi_heads(features,proposals, images.image_sizes, targets)

Faster RCNN 主要组件

  • backbone

  • rpn

  • filter_proposals(NMS)

  • roi_heads

生成对抗网络(GAN)

GAN:生成 对抗 网络 — 一种可以生成特定分布数据的模型

GAN网络结构

论文参考:

  • 《Recent Progress on Generative Adversarial Networks(GANs): A Survey》
  • 《How Generative Adversarial Networks and Its Variants Work: An Overview of GAN》
  • 《Generative Adversarial Networks: A Survey and Taxonomy》

GAN的训练

训练目的:

  1. 对于D:对真样本输出高概率
  2. 对于G:输出使D会给出高概率的数据

监督学习训练模式

利用损失函数计算标签与输出值的差异,从而可以逼近标签的值。

GAN训练模式

利用网络模型来代替损失函数,使输出值逼近训练数据,利用差异值更新G-network中的参数,逼近不是数值上的逼近,而是分布上的逼近。

训练步骤

Step1:训练D(判别器)

输入:真是数据加G生成的假数据

输出:二分类概率

Step2:训练G(生成器)

输入:随机噪声Z

输出:分类概率–D(G(z))

DCGAN 深度卷积对抗网络

参考文献:《Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks》

Discriminator:卷积结构的模型

Generator:卷积结构的模型

GAN应用

参考:gan-some-aoolications

  • 模特改变姿态
  • 《CycleGAN》
  • 《PixelDTGAN》
  • 《SRGAN》-超分辨率图片
  • 《Progressive GAN》
  • 《StackGAN》根据文字生成图片
  • 《Context Encoders》图片缺失填充
  • 《Pix2Pix》素描上色
  • 《IcGAN》

GAN推荐github:awesome-gan

循环神经网络RNN

RNN:循环神经网络

  • 处理不定长输入的模型
  • 常用于NLP及时间序列任务(输入数据具有前后关系)

RNN的网络结构

  • xt:时刻t的输入,shape = (1, 57)

  • st:时刻t的状态值,shape=(1, 128)

  • ot:时刻t的输出值,shape=(1, 18)

  • U:linear层的权重参数,shape=(128, 57)

  • W:linear层的权重参数,shape=(128, 128)

  • V:linear层的权重参数,shape=(57, 128)

    hidden state:隐藏层状态信息,记录过往时刻的信息

St=f(Uxt+WSt1).S_t = f(U_{x_t} + W_{S_{t-1}}).

Ot=softmax(VSt).O_t = softmax(V_{S_t}).

计算机如何实现不定长字符串分类向量的映射?

Chou(字符串) --> RNN --> Chinese(分类类别)

for循环分别对单个字符进行分类

for string in [C, h, o, u]:

	1. One-hot: string --> [0, 0, ...,1,...,0]
	2. y, h = model([0,0,...1,...0], h)