1.autograd
1)计算图是一个DAG有向无环图。
正向传播:autograd包含两个步骤,首先计算tensor结果,维护操作的.grad_fn。
反向传播:显示的调用backward函数后,包含三个步骤:首先用.grad_fn计算梯度值;然后所有requires_grad属性为True的结点的梯度(即结点的.grad属性)被累积更新;最终利用链式法则,反向传播。
2)backward(gradient,retain_graph)
(1)gradient:
对于标量结点,参数可选,此时参数被默认为torch.Tensor([1])。
对于非标量结点,则必需要gradient。且gradient尺寸需要和输出尺寸相同,
import torch
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
loss.backward()
(2)retain_graph:一个计算图只能调用一次backward函数。如果需要对同一张图多次调用,则需要backward(retain_graph=True).并且多次调用的梯度会累计。
3)取消gradient tracking
为了固定网络参数或加速计算省去后向传播,所以会不记录部分tensor梯度。
通过以下两种方式设置。用z_det=z.detach()定义的tensor或with torch.no_grad() 语句被包裹的结点。
z=torch.matmul(x,a)+b
z_det=z.detach()
with torch.no_grad():
z_det2=torch.matmul(x,a)+b
4)查看梯度和grad_fn
(1)结点梯度:print(x.grad)
(2)梯度函数:如果是直接创建tensor,则.grad_fn=None.如果是y=x+x,则.grad_fn=AddBackward
2.optimization
1) hyperparam
number of epochs:迭代模型的次数
batch size:每次迭代需要的样本数
learning rate:每个epoch更新模型的程度。值越小,模型学习速度越慢。值越大,模型容易出现不可预测的行为。
2)optimization loop
training loop:在训练集上迭代,目标是使模型收敛
validation loop:在验证集上迭代,验证模型效果。
3)优化器
优化算法被封装在优化器对象中。在初始化优化器时,我们把需要优化的模型参数、超参数作为初始化时的参数传给优化器。
optimizer=torch.optim.SGD(model.parameters(),lr=learning_rate)
在每个批次之间,为了防止模型梯度叠加,使用optimizer.zero_grad()清零梯度
在使用loss.backward()更新梯度后,使用optim.step()使用梯度更新模型参数
4)training loop和validation loop的实现
def train_loop(dataloader,model,optimizer,loss_fn)
model.train()
size=len(dataloader.dataset)
for batch,(X,y) in enumerate(dataloader):
pred=model(X)
loss=loss_fn(pred,y)
loss.backward()
optim.step()
optim.zero_grad()
if batch%100==0:
loss,current=loss.item(),(batch+1)*len(X)
print(f"train loss:{loss:>7f} [{current position:>5d}/{size:5d}]"))
#每个loss是在每个batch上计算,test_loop中loss需要求和因为需要求多个loss的平均,但train_loop是每100个batch才打印
#因为loss_fn的返回值是一个标量,pred才是和输出相同维度的。
def test_loop(dataloader,model,loss_fn)
model.eval()
test_loss,correct=0,0 #因为test_loop函数被多次调用,且两个变量累加。所以需要清零。
size=len(dataloader.dataset)
num_batches=len(dataloader)
with torch.no_grad(): #节约资源不用再计算梯度
for (X,y) in dataloader:
pred=model(X)
loss=loss_fn(pred,y)
test_loss+=loss.item()
correct+=(pred.argmax(1)==y).type(torch.float).sum().item()
#一个样本的预测标签为每一行中的最大值,即pred.argmax(1),列为种类、行为为一个batch中的样本。
correct/=size
test_loss/=num_batches #在多个batch上的平均
print(f"correctness:"crrect/batch_size,"train loss:"loss)
epochs=10
loss_fn=nn.CrossEntropyLoss()
for i in range(epochs):
print(f"Epoch"i+1"-------------")
train_loop(training_dataloader,model,optimizer,loss_fn)
test_loop(testing_dataloader,model,loss_fn)
print("done")
3. save and load model
1)只是用于推理:只保存模型权重
#save model weights
torch.save(model.state_dict(),'model_weight.pth')
#load model weights
model.load_state_dict(torch.load('model_weights.pth'))
#pytorch load save函数可以保存任何文件,保存的时候只保存了state_dict,则取出的时候也调用load_state_dict
2)需要继续训练模型:保存整个模型
state = {
'epoch': epoch,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
...
}
#save model including optimizer,epoch,score
torch.save(state,filepath)
#load model including optimizer,epoch,score
model=torch.load(state,filepath)
------------
1.model.tran() model.eval()作用
由于之前model = NeuralNetwork(),因此model是自定义类NeuralNetwork的实例。而NeuralNetwork是nn.Module的子类。nn.Module中包含属性.train();.eval()
表示模型在不同的状态下。在model.train()下模型会根据不同批的结果,更新梯度。但在model.eval()下不会,会关闭BN,dropout。具体解释dropout参照deep learning 7.12:deeplearningbook.org/contents/regularization.html, 解释BN参照deep learning 8.1.3:deeplearningbook.org/contents/optimization.html
2.model(X)
等价于调用__call__(),该函数调用model.forward(X)+hooks。
3.optimizer.zero_grad()
为什么清零模型梯度需要通过调用optimizer的属性呢?当把模型所有参数都在定义优化器时,给了同一个优化器,则optimizer.zero_grad()效果等于model.zero_grad().除非一个模型使用了多个优化器优化。
4.dataloader类
将dataset和决定如何从数据集中获取样本的sampler结合在一起。
.num_workers定义cpu加载数据需要子进程的数量。会尽可能均匀的将batch_size个样本平均分配给num_workers。num_workers数量越大,对内存消耗越大,模型能使用的内存越少;num_workers数量太小时,Gpu必须等待cpu加载数据。结合IO、内存使用情况。所以num_worker数量需要结合batch_size数量选择,最好和训练速度匹配。当num_workers数量为0时,只由主进程加载数据。
.dataset:获取定义dataloader的数据集。
5.为什么要设计batch和epoch
epoch数量是神经网络在整个数据集上训练的次数。
batch是把整个数据集分块的块数。batch的存在是由于一次把整个数据集太大,不能整个输入给模型。
7 tensor.type(dtype)
tensor的数据类型的强制转换。torch.float,torch.double等