奇客谷
2
3
转换成张量 torch.tensor
运算torch.mm(matrix1,matrix2)
并行torch.CUDA
网络torch.nn
优化器torch.optim
辅助模块torch.utils
存储载入
动态图:
pytorch使用动态计算图,在计算过程中构建图(结点是运算符)。
前向构建图的时候同时构建反向计算图,输出张量绑定反向梯度函数,到了最终损失函数后,开始沿着反向图,调用反向梯度函数。权重张量绑定梯度张量,优化器这个工具人来进行优化更新权重张量。
三个主人公和工具人:
+表示绑定
工具人 优化器:
LMS (online 更新) ⇒ SGD(考虑单次批次梯度信息) ⇒ Momentum(不够,再考虑之前的批次信息)⇒ AdaGrad(考虑过去所有的梯度平方和,用NLMS类似手法)⇒ RMSProp(用指数记忆过去平方梯度信息,再类似NLMS) ⇒ Adam(结合RMSProp和Momentum)
SGD, Momentum, AdaGrad, Rmsprop, Adam
SGD : 批次随机梯度下降
Momentum: w t + 1 = w t − m t \bold w_{t+1} = \bold w_t - \bold m_t wt+1=wt−mt
m t = γ . m t − 1 + α d L d w t \bold m_t = \gamma.\bold m_{t-1} + \alpha\frac{dL}{d \bold w_t} mt=γ.mt−1+αdwtdL
AdaGrad: 类似于NLMS, 记忆梯度平方
G t = ∑ i = 1 t ( d L d w i ) 2 \bold{G_t }= \sum_{i=1}^{t}(\frac{dL}{d\bold w_i})^2 Gt=i=1∑t(dwidL)2
w t + 1 = w t − α d L d w t G t + ϵ \bold w_{t+1} = \bold w_t - \frac{\alpha \frac{dL}{d\bold w_t}}{\sqrt{\bold G_{\bold t}+\epsilon}} wt+1=wt−Gt+ϵαdwtdL
RMSprop: 不用全部记忆,用移动指数平均。
用 v t v_t vt代替AdaGrad中的 G t G_t Gt
v t = γ v t − 1 + ( 1 − γ ) ( d L d w i ) 2 \bold{v_t} = \gamma \bold{v_{t-1}}+(1-\gamma)(\frac{dL}{d\bold w_i})^2 vt=γvt−1+(1−γ)(dwidL)2
w t + 1 = w t − α d L d w t v t + ϵ \bold w_{t+1} = \bold w_t - \frac{\alpha \frac{dL}{d\bold w_t}}{\sqrt{\bold v_{\bold t}+\epsilon}} wt+1=wt−vt+ϵαdwtdL
Adam:结合动量和速度
计算图举例
神经网络记录计算图, 结点为运算操作(operator),边为张量。(记忆:树结构,父节点是+号)
静态图(static graph):以前的TensorFlow ,caffe
动态图: Pytorch
静态图:先引擎构建图并且可以进行优化,然后不在过程中更改。然后进行正向,反向传播。缺点在于不灵活,不能在传播过程中debug。
静态图:
动态图:
每个输出张量
绑定一个反向传播的梯度计算函数,当计算图到达最终损失函数张量
的时候,直接调用这个张量的反向传播函数,并不断地递归反向传播函数。(记忆:前向绑定梯度,遇最终损失函数,反向传播调用梯度)动态计算图:
让我们理一理:
+表示绑定
优化器+权重张量
输出张量+反向梯度函数
优化器 ---->权重张量<------ (梯度张量)
torch模块包含了本身常使用的激活函数,torch.sigmoid, torch.relu, torch.tanh以及矩阵的乘法torch.mm,张量元素的选择torch.select。
torch.Tensor 模块
任何方法后缀带了_的函数都是直接修改本身数据,即in-place方法。
torch.Storage 负责torch.Tensor的底层数据存储
torch.sparse
稀疏表达
torch.CUDA
GPU有关
torch.nn
非常重要!!!
一般用来继承它。
import torch.nn as nn
nn.Linear
nn.Conv1d
nn.Conv2d
nn.Conv3d
torch.nn.MSELoss
torch.nn.CrossEntropyLoss
torch.nn.functional
激活函数和池化函数
torch.nn.init
神经网络初始化
torch.nn.init.uniform_
torch.nn.init.normal_
torch.optim
优化器 update weight tensor
torch.optim.SGD
torch.optim.AdaGrad
torch.optim.RMSprop
torch.optim.Adam
torch.optim.lr_scheduler #学习率衰减子模块
torch.optim.lr_scheduler.StepLR #阶梯下降
torch.optim.lr_scheduler.CosineAnnealingLR #余弦退火
torch.autograd
torch.autograd.backward
torch.onnx
ONNX格式存在是为了方便不同框架之间的模型交换。
torch.utils.bottleneck
检查模块运行时间,找到导致性能瓶颈的模块。
torch.utils.checkpoint
节约内存
时间换空间内存,丢弃中间数据,只记录计算过程。
torch.utils.data
引入了Dataset 和 DataLoader,得到shuffle 和 sample 后的迷你小批次数据集。
torch.utils.tensorboard
数据可视化工具,可视化中间张量,损失函数,张量权重的直方图,一节中间文本,视频,图像。
张量的使用和Numpy中的ndarrays很类似, 区别在于张量可以在GPU或其它专用硬件上运行, 这样可以得到更快的加速效果。
张量如何存储?
(记忆:最里面的,最深层的的,最后的维度,最先储存)
k维度张量,维度为 ( n 1 , n 2 , . . . , n k ) (n_1, n_2,...,n_k) (n1,n2,...,nk)
存储顺序是一般从 n k n_k nk开始,:
先填满 n k , n k − 1 , n k − 1 , . . . , n 1 n_k, n_{k-1}, n_{k-1}, ..., n_1 nk,nk−1,nk−1,...,n1,
一个元素张量中的下标为 ( i 1 , i 2 , i 3 , . . . , i k ) (i_1, i_2, i_3, ..., i_k) (i1,i2,i3,...,ik), 那么它在内存中是第 ( i k ) + ( i k − 1 ∗ n k ) + . . . + ( i 1 ∗ ( n 2 ∗ n 3 . . . ∗ n k ) ) (i_k)+(i_{k-1}*n_k) +...+ (i_1*(n_2*n_3...*n_k)) (ik)+(ik−1∗nk)+...+(i1∗(n2∗n3...∗nk))
张量的初始化
PyTorch教程
import torch
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
import numpy as np
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
x_ones = torch.ones_like(x_data) # 保留 x_data 的属性
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float) # 重写 x_data 的数据类型int -> float
print(f"Random Tensor: \n {x_rand} \n")
shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")
张量类型转换
import torch
torch.tensor(a, dtype = torch.float32) #或者
torch.tensor(a).to(torch.float32)
torch.tensor(a, device = 'cuda:3')
GPU->CPU
设备之间的转移可以用to、xx.cpu()
torch.ones_like(a, device="cuda:4")**.cpu()**
torch.ones_like(a, device = 'cuda:4').**to**('cuda:0')
view +contiguous == reshape
t = torch.tensor(a)
t.view(-1,3)
view函数不改变底层数据存储,只改变维度步长信息。
如果需要复制数据,需要调用contiguous()。
张量拼接与分割
拼接不会增加维度
但是stack会增加维度
t1 = torch.rand(3,4)
#Returns a tensor filled with random numbers from a uniform distribution
t2 = torch.rand(3,4)
t3 = torch.rand(3,4)
t.cat([t1,t2,t3, t4], -1)
#3*(4+4+4)
t.stack([t1 ,t2, t3], -1)
#3*4*3
t = torch.randn(3,4)
t.unsqueeze(-1).shape
# 3*4*1
t = torch.rand(1,3,4,1)
torch.squeeze()
#压缩所有为1 的维度
简单模型初始化化要把 tensor张量变成Parameter才能被optim优化器访问到!
Pytorch优化器直接接收模型的参数生成器作为函数的参数。
self.weight = nn.Parameter( torch.rand(n_dim,1) )
model.named_parameters()
model.parameters()
张量绑定的梯度张量不清空的话,会一直逐渐积累,因此要在反向传播之前optim.zero_grad()
import torch
from torch import nn
learning_rate = 0.01
model = LinearModel(..) # 初始化模型
criterion = nn.MSELoss() # 初始化损失函数criterion
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for step in range(..):
predict = model(x) # 预测
loss = criterion(preict, target) # 损失函数
optimizer.zero_grad()#优化器清空之前反向传播的梯度
loss.backward() #损失函数反向传播
optimizer.step()# 优化器进行梯度下降优化
DataLoader(dataset, batch_size =1, shuffle = False, sampler = None, batch_sampler =None, num_workers =0, collate_fn = None, pin_memory = False, drop_last = False, timeout =0, worker_init_fn = None)
import torch
torch.save()
model.state_dict()
model.load_state_dict(t)
save_info = {#保存的信息
"iter_num": iter_num, #迭代步数
"optimizer": optimizer.state_dict(), #优化器状态字典
"model": model.state_dict() # 模型状态字典
}
torch.save(save_info, save_path)
save_info = torch.load(save_info)
optimizer.load_state_dict(save_indo["optimizer"])
model.load_state_dict(save_indo["model"])