【摘要】 pytorch init、forward和__call__方法 __init__主要用来做参数初始化用 forward是表示一个前向传播,构建网络层的先后运算步骤 在pytorch在nn.Module中,实现了__call__方法,而在__call__方法中调用了forward函数forward函数为什么可以直接被调用?nn.Module把__call__方法实现为类对象的…
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
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(model.state_dict(),path)
model_state_dic = torch.load(path)
model.load_state_dic(model_state_dic)