pytorch相关用法

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))

版权声明:本文为dzysunshine原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。