pytorch相关用法
文章目录
设置随机种子,复现模型结果
当我们想复现模型结果的时候,需要将所有的种子全部固定下来,可以实现多次运行结果一致。
def set_rand_seed(seed=1):
print("Random Seed: ", seed)
random.seed(seed)
np.random.seed(seed)
# CPU随机种子
torch.manual_seed(seed)
# GPU随机种子
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
# 直接禁用cudnn(结果可复现)
# torch.backends.cudnn.enabled = False
# 选择默认的优化方式
torch.backends.cudnn.benchmark = False
# 保证每次返回得的卷积算法是确定的
torch.backends.cudnn.deterministic = True
参考:https://blog.csdn.net/sinat_40624829/article/details/111309037
ModelCheckpoint(回调函数)
回调函数的作用,在每个epoch后保存模型到filepath
keras.callbacks.ModelCheckpoint(filepath,
monitor='val_loss',
verbose=0,
save_best_only=False,
save_weights_only=False,
mode='auto',
period=1)
filename:字符串,保存模型的路径,filepath可以是格式化的字符串,里面的占位符将会被epoch值和传入on_epoch_end的logs关键字所填入。
例如:
filepath = “weights_{epoch:03d}-{val_loss:.4f}.h5”
则会生成对应epoch和验证集loss的多个文件。
monitor:需要监视的值,通常为:val_acc 或 val_loss 或 acc 或 loss
verbose:信息展示模式,0或1。为1表示输出epoch模型保存信息,默认为0表示不输出该信息,信息形如:
Epoch 00001: val_acc improved from -inf to 0.49240, saving model to /xxx/checkpoint/model_001-0.3902.h5
save_best_only:当设置为True时,将只保存在验证集上性能最好的模型
mode:‘auto’,‘min’,‘max’之一,在save_best_only=True时决定性能最佳模型的评判准则,例如,当监测值为val_acc时,模式应为max,当检测值为val_loss时,模式应为min。在auto模式下,评价准则由被监测值的名字自动推断。
save_weights_only:若设置为True,则只保存模型权重,否则将保存整个模型(包括模型结构,配置信息等)
period:CheckPoint之间的间隔的epoch数
参考:https://blog.csdn.net/qq_28949847/article/details/109067395
pytorch init、forward和__call__方法
- __init__主要用来做参数初始化用
- forward是表示一个前向传播,构建网络层的先后运算步骤
- 在pytorch在nn.Module中,实现了__call__方法,而在__call__方法中调用了forward函数
forward函数为什么可以直接被调用?
nn.Module把__call__方法实现为类对象的forward函数,所以任意继承了nn.Module的类对象都可以这样简写来调用forward函数。
.item()
用于将一个零维张量转换成浮点数
如果是只有一个元素的 tensor,使用.item()可以将里面的 value 变成python数值
model.train()与model.eval()
model.train()
如果有BatchNormalization:BN层用每一批数据的均值和方差
Dropout:随机取一部分网络连接来训练更新参数
model.eval()
BatchNormalization:BN用全部训练数据的均值和方差
Dropout:利用到了所有的网络连接
反向传播与参数更新
model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=1e-4)
for epoch in range(1, epochs):
for i, (inputs, labels) in enumerate(train_loader):
output= model(inputs)
loss = criterion(output, labels)
# compute gradient and do SGD step
optimizer.zero_grad()
loss.backward()
optimizer.step()
- optimizer.zero_grad():将梯度归零(如果不将梯度清零的话,梯度会与上一个batch的数据相关,因此该函数要写在反向传播和梯度下降之前。)
- loss.backward():反向传播计算得到每个参数的梯度值
- optimizer.step():执行参数更新
根据pytorch中backward() 函数的计算,当网络参量进行反馈时,梯度是累积计算而不是被替换,但在处理每一个batch时并不需要与其他batch的梯度混合起来累积计算,因此需要对每个batch调用一遍zero_grad()将参数梯度置0。
NLP 数据集加载
torch.utils.data.Dataset和torch.utils.data.DataLoader:
https://blog.csdn.net/qq_36653505/article/details/83351808
RNN中的pack和pad
需要注意的是,在进行pack和pad的操作时,需要将batch中的数据长度按照递减进行排序。进行该操作的原因是一方面可以减少无谓的运算(PAD不参与计算),另一方面经过该操作后得到的PAD对应的值都为0,从而不会对句子产生影响。
分两种情况,一种是没有使用0填充的不等长tensor,直接使用torch.nn.utils.rnn.pack_sequence即可;另一种是已经使用0填充过的tensor,使用torch.nn.utils.rnn.pack_padded_sequence即可,输入的时候需要传入句子的长度seq_lengths。
https://zhuanlan.zhihu.com/p/93048452
https://www.cnblogs.com/sbj123456789/p/9834018.html
.contiguous().view()
contiguous:view只能用在contiguous的variable上。
如果在view之前用了transpose, permute等,需要用contiguous()来返回一个contiguous copy。
有些tensor并不是占用一整块内存,而是由不同的数据块组成,而tensor的view()操作依赖于内存是整块的,这时只需要执行contiguous()这个函数,把tensor变成在内存中连续分布的形式。
view()和reshape()的区别
相同点都是进行纬度变换,不同点应该是有两方面:view()方法只适用于满足连续性条件的tensor,并且该操作不会开辟新的内存空间,因此为了满足连续性条件常常会使用.contiguous().view();
reshape则不需要依赖目标 tensor 是否在内存中是连续的,可以认为a.reshape = a.view() + a.contiguous().view()
即:在满足tensor连续性条件时,a.reshape返回的结果与a.view()相同,否则返回的结果与a.contiguous().view()相同。
device转换
torch.cunda.is_available()
device = torch.device('cuda')
x = x.to(device)
# 如果数据是在 cuda 上得到的,需要先转为cpu(),再转为numpy()
y.to('cpu').data.numpy()
y.cpu().data.numpy()
np.pad()
# (1,2)表示在一维数组array前面填充1位,最后面填充2位
# constant_values=(0,2) 表示前面填充0,后面填充2
ndarray=np.pad(array,(1,2),'constant', constant_values=(0,2))
numpy和tensor常用转换
# 平方
np.square()
.pow(2)
# 线性变换
dot()
mm()
# relu
np.maximum(0,h)
h.clamp(min=0)
# 转置
.T
.t()
# 复制
.copy()
.clone()
pytorch维度转换
https://blog.csdn.net/husthy/article/details/101649012
unsqueeze()、squeeze()、expand()、repeat()、view()、和cat()函数的总结
unsqueeze():在指定位置增加维度(加[ ])
squeeze():压缩维度(把维度为1的维去掉,去掉[ ])
ps:只能压缩维度为1的维;其他大小的维不起作用。
expand():对指定的维度进行数值的复制。只能改变维大小为1的维,否则就会报错。不改变的维可以传入-1或者原来的数值。
repeat():沿着指定的维度,对原来的tensor进行数据复制。这个函数和expand()还是有点区别的。expand()只能对维度为1的维进行扩大,而repeat()对所有的维度可以随意操作。
view():类似reshape的功能。
cat():将两个或者多个tensor沿指定维度拼接起来。
batch_split
batch_split来进行时间换空间(梯度累加)
设定大的batch_size会使训练更稳定一些,也会收敛的更快,但通常我们的显卡可能达不到要求,如何进行平衡?设置小的batch_size,同时设置batch_split,来对多个batch积攒backward,积攒到一定程度,再进行参数更新,也就是对batch_split个batch一起进行参数更新。
这样子积累这么多步之后,只反向传播更新一次,loss相当于做一个平均叠加,梯度也就相当于平均叠加。
backward会释放计算图,如果你一起backward,所有的计算图都还在内存里,会爆。
多GPU使用单GPU计算
os.environ[‘CUDA_VISIBLE_DEVICES’] = args.gpu需要写在所有访问GPU代码的前面(如import torch),也可以在执行代码的时候在python前加CUDA_VISIBLE_DEVICES=‘0’
模型保存与加载
# 保存整个网络
torch.save(net, PATH)
# 加载整个网络
model_dict=torch.load(PATH)
#--------------------------------------------------
# 保存网络中的参数, 速度快,占空间少
torch.save(net.state_dict(),PATH)
#加载网络参数的方法:(注意需要先定义好model,再加载参数)
model_dict=model.load_state_dict(torch.load(PATH))