PyTorch框架搭建
- PyTorch是动态图计算,TensorFlow1.0还是静态图计算。
- 静态图计算是我们在编程的时候需要先构图(即将我们的网络环境搭建好),才能在后端运行我们的网络。
- Tensorflow的可视化是通过Tensorboard来完成的,而pytorch的可视化得需要其他第三方的工具。
- TnesorFlow的部署是通过TF serving来部署,而PyTorch模型的部署就比较麻烦了,可能需要Python的服务,如Flask
- 动态图是编好程序就可以运行,而静态图,我们想打印一个tensor时,我们要先把这个tensor定义好,然后我们如果想要打印这个tensor具体的值的话,需要去后台执行session,然后得到结果。这样的好处是:允许编译器进行优化。但是坏处是:代码编程复杂,不方便调试。
PyTorch 基础知识
PyTorch的基本概念
- Tensor : 张量。当维度过高时,就没办法用矩阵和向量来描述,所以用张量来描述。张量可以描述任意维度的物体,如H*W*C 3维的特征图。如矩阵是2阶的张量。
- Variable(autograd):模型的参数一开始未知就是变量
- nn.Module: 封装了解决计算机视觉任务会用到的一些网络结构。torch.nn是专门为神经网络设计的模块化接口。nn构建于autograd之上,可以用来定义和运行神经网络。
nn.Module是nn中十分重要的类,包含网络各层的定义及forward方法。 - 一个3阶的张量,表达了在图像中的特征图。
Tensor和机器学习的关系
- 我们将样本表达为Tensor,使用Tensor来描述样本。语音数据使用向量来描述,也就是一个一阶张量。图像数据使用矩阵来描述,也就是一个二阶张量。
- 模型包含了有参数模型和无参数模型。参数和最后的标签也是变量,所以也是用tensor来描述的。
- 因此tensor可以描述我们机器学习中的样本和模型。
- Tensor的类型,创建,属性,运算,操作,numpy的相互转换
- Tensor的类型:dtype,和语言的数据类型类似,只不过加了一个 torch.float32
- Tensor的创建(类比于numpy):
* 采用直接初始化的方法 / 指定shape的方法 (类比numpy来记忆)
a = torch.Tensor([[1,2],[3,4]])
b = torch.Tensor(2,3)
c = torch.eye(2,2) #对角线为1
d = torch.zeros(2,2)
e = torch.zeros_like(b) #和b大小一样,但是全0
##ones_like eyes_like
g = torch.normal(mean=0.0, std= torch.rand(5)) # 正态分布 通常用于参数初始化和随机生成值
h = torch.Tensor(2,2).uniform_(-1,1) #均匀分布
i = torch.arange(0,10,1) #tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
j = torch.linspace(2,10,3). #拿到等间隔的3个数
- 将样本打乱,可以将样本本身打乱,也可以将样本的索引打乱
k = torch.randperm(10) #tensor([1, 4, 2, 6, 7, 5, 3, 8, 9, 0]). 数据类型是longTensor
Tensor的属性
- 每一个Tensor都有torch.dtype / torch.device / torch.layout三种属性
- torch.device标识了torch.Tensor对象在创建之后所存储在的设备名称
(cpu / gpu: cuda: 0,1,2) - torch.layout标识了torch.Tensor内存布局的对象(稀疏的张量在内存中存储的是Tensor所对应的非0元素的坐标)
定义稠密的张量:
torch.tensor( [1,2,3],dtype=torch.float32, device=torch.device('cpu') )
定义稀疏的张量:
## Coordinate(COO) 格式的稀疏矩阵
torch.spares_coo_tensor(indices, values, size=None,*, dtype=None, requires_grad=False)
##indices: 此参数是指定非零元素所在的位置,也就是行和列,所以此参数应该是一个二维的数组。第一维指定了所有非零数所在的行数,第二维指定了所有非零元素所在的列数。例如indices=[[1, 4, 6], [3, 6, 7]]表示我们稀疏矩阵中(1, 3),(4, 6), (6, 7)几个位置是非零的数所在的位置。
##values:此参数指定了非零元素的值,所以此矩阵长度应该和上面的indices一样长。例如``values=[1, 4, 5]表示上面的三个位置非零数分别为1, 4, 5。
##size:指定了稀疏矩阵的大小,例如size=[10, 10]表示矩阵大小为10 × 10
##dtype:指定返回tensor中数据的类型,如果不指定,那么采取values中数据的类型。
##device:指定创建的tensor在cpu还是cuda上。
##requires_grad:指定创建的tensor需不需要梯度信息,默认为False
- 稀疏张量的作用:1.稀疏和低秩两个重要的标准。低秩其实是描述了数据本身之间的关联性。稀疏可以使我们的模型变得非常简单。如果有参数的模型中,这些参数中零的个数比较多的话,我们就可以将我们的模型进行简化。将数据稀疏化,也可以减少在内存中的开销。
#将稀疏的张量转成稠密的张量
i = torch.tensor([[0,1,2],[0,1,2]]) #这里要写成一个元组,自己总忘记
v = torch.tensor([1,2,3])
b = torch.sparse_coo_tensor(i,v,(4,4) ,dtype=torch.float32,device=dev).to_dense()
#tensor([[1, 0, 0, 0],
# [0, 2, 0, 0],
# [0, 0, 3, 0],
# [0, 0, 0, 0]])
- 为什么有的数据要放到cpu上有的要放到cuda上运行:在进行图像处理时,我们要对我们的数据进行合理的分配。在进行数据读取和数据预处理的时候,将其优先的放在cpu上跑。对于参数的计算,反向传播之类的优先放在gpu上跑。
- 资源的合理调度,也可能很大程度上节省训练时间。
Tensor的算术运算
- 加减乘除 / 矩阵运算 / 幂运算 / 对数运算 等
- 带下划线的方法会修改调用函数的那个变量的值
- 四则运算中的乘法和矩阵乘法要区分:
#四则运算中的是哈达玛积(element wise, 对应元素相乘)
c = a * b
a.mul(b)
#矩阵乘法 (不存在下划线形式,因为可能最终乘的结果维度和原来的维度不一样了)
a = torch.ones(2,1)
b = torch.ones(1,2)
torch.mm(a,b)
torch.matmul(a,b)
a @ b
a.matmul / mm(b)
- e的n次方
b = torch.exp(a)
Pytorch中的in-place操作
- “就地”操作,即不允许使用临时变量,也称为原位操作 如add_ sub_等
- Pytorch中的广播机制:张量参数可以自动扩展为相同大小
- 要满足的条件:每个张量至少有一个维度 & 满足右对齐
- 如 torch.rand(2,1,1) + torch.rand(3) 这里就是(2,1,1)对 (1,1,3)这里满足右对齐,就是每一位上要么相等要么有一个为1。相加之后维度为(2,1,3)
- 广播机制可以简化操作
- Tensor的取整/取余运算(floor 向下取整 / ceil 向上取整/ round 四舍五入 / trunc 只取整数/ frac 只取小数 / %)
Tensor的比较运算
- 除了第二个之外,剩下的返回的True和False长度和原来tensor中成员长度是相等的。因为是逐个比较,所以对每一个比较都有返回的结果。
- 前两个主要是用于机器学习loss排序用的 topk中largest控制是升序还是降序
- 这里的张量里面也是一堆True / False
- torch.isnan()是用来判断输入的张量是否为空的函数,当输入为空是,返回True。
Tensor的三角函数
- 在机器学习中使用最多的是余弦。计算两个向量的距离:欧氏距离 / 余弦距离(如果两个向量很相似的话,这两个向量之间的夹角就会非常小 在人脸识别网络中,如AM-Softmax loss都是基于余弦距离的loss)
- 余弦距离是我们现在解决相似性问题常用的距离。
- 描述摆放位置倾斜的物体的时候可以用其四个角的坐标来描述,也可以用一个矩形+一个
θ
\theta
θ角来描述
- 绝对值函数就是L1 loss 抛物线函数就是L2 loss
- 分段函数可以用作分类问题。本身无法进行求导,所以有了sigmoid函数
- 称sigmoid函数是sign函数的一种连续化逼近,其也是激活函数,通常用于二分类任务中
Pytorch中统计学相关的函数
- 直方图例子:一张图片,其每个像素点像素值取值都为[0,255],则将该张图片的所有像素值频数统计起来,可以将每个像素值作为一类画一个直方条。
- 在传统的机器学习算法中,我们进行特征描述时,通常使用的手段就是直方图的形式。
- 使用直方图的话,一张图片就可能产生256维向量/16维向量(合并)。当图片转换角度的时候,其统计出来的直方图的维度向量也不变。(对旋转是鲁棒的)
- 对图片除了颜色直方图之外,还有LBP sift gabor HOG
Tensor中的torch.distributions 分布函数(很重要)
- distributions包含可参数化的概率分布和采样函数
- 通过KL Divergence度量两个分布之间的相似性
- 通过Transforms完成分布和分布之间的转换,Constraint来完成对分布的约束
- Tensor中的随机抽样
# 定义随机种子
torch.manual_seed(seed)
# 定义随机数满足的分布
torch.normal()
- Tensor中的范数运算 (有点难!!!)
- 0 / 1 / 2 / p范数 / 核范数(针对低秩问题求解)
torch.dist(input, other, p = 2) #计算p范数
torch.norm() #计算2范数
核范数
核范数||W||*是指矩阵奇异值的和,Nuclear Norm。
作用:约束低秩
图像的特点是:图像经常呈现一种区域性,而这种区域性呈现在图像矩阵上就表示为数据与数据之间的相关性。所以对于图像而言,其通常是低秩的。
低秩约束是我们在构造损失函数时经常会用到的一个约束项。
低秩矩阵
概念
当矩阵的秩较小时(r <<n,m)就可以认为该矩阵为低秩矩阵。在图像处理中,图像灰度矩阵是低秩矩阵,那么就意味着该图像的行列相关性大即很多行或列向量是线性相关的,信息冗余高。
作用
可用于图像恢复,利用低秩矩阵的冗余信息,可以对缺失的数据进行恢复,此问题叫做“低秩矩阵重构”,即:假设恢复出来的矩阵是低秩的,利用已有的矩阵元素会付出矩阵中的缺失元素,可应用在图像的修复,协同过滤等领域。
在深度学习中,卷积核的参数过多,经常是低秩的,即存在较大的冗余信息,此时我们可以对卷积核进行低秩分解,将的卷积核分解为一个的和一个的核,这样就可以降低参数量,提高精度,防止过拟合。
范数在机器学习中的用法
- 定义loss(向量与向量间的距离)
- 参数约束(0范数:指在当前向量中非零元素的个数 1范数:元素绝对值的和) 为什么说通过对范数的约束,我们可以完成对模型参数的约束呢?在模型优化中有一个结构约束,其指我们当前的这个模型越简单,我们越不容易过拟合。模型越简单其中一个原因就是元素个数少,或其中0元素的个数多。正则项也是对参数的约束。