何为梯度 grad
记录loss
对参数的偏导,用于更新参数,模型训练的时候,默认为参数创建,可以使用tensor.requires_grad
查询张量是否带梯度
1 | import torch |
grad
有什么用
可以利用torch
的自动求导特性,得到loss
关于次参数的导数,并利用此导数进行参数更新
具体而言,模型的一个epoch
有这么五步
如果模型的设计是,参数是每个
step
更新,那每个step
都有这么几步
向前传播,
forward
,即使用模型,传入feature
,得到模型输出pred
1
pred = model(feature)
计算
loss
,这里的loss_func
为自己定义的函数,比如常见的L1 loss
1
loss = loss_func(pred, target)
向后传播,
backward
,即对模型各个参数计算对应的grad
1
loss.backward()
更新模型参数,根据自己定义的优化器
optimizer
策略,进行参数更新1
optimizer.step()
将模型所有参数的
grad
重置为01
optimizer.zero_grad()
清空单个张量的grad
当张量被初始化时,是没有梯度,是不用清空的,此时grad
为None
1 | import torch |
一旦基于此tensor
的计算的值进行了backward
,也就是依据计算图计算了各个参数的grad,此tensor
附带的grad
就不是None
了
1 | import torch |
梯度在每次backward
是不会被覆盖的,而是累计,所以需要手动清空,这里的清空是指将梯度设置为0;需要注意的是如果grad
是None
,是不能被清空的
1 | if tensor_demo.grad is not None: |
将grad
转为 feature importance
对feature
添加grad
,进行backward
后,基于grad
计算feature importance
读取模型参数,使用模型预测
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import torch
model = DailyNet.load_from_checkpoint(
Path("epoch04.ckpt"),
)
# 如果模型中有dropout等层,需要进行处理,否则后续操作有随机性
model._gru_block._gru.dropout = 0.0
# 可以将参数的梯度去掉, 并不影响featuer的grad计算
# for param in model.parameters():
# param.detach_()
# NOTE 需要给feature添加grad
input_feature = input_feature.requires_grad_(True)
preds = model(input_feature).cpu()计算
loss
,并backward
loss_func
为自定义的损失函数,target
为真实值1
2
3
4
5
6
7
8
9if input_feature.requires_grad:
if input_feature.grad is not None:
input_feature.grad.zero_()
else:
raise KeyError("input_feature requires grad")
loss = loss_func(preds, target)
loss.backward()根据
grad
计算feature importance
1
2grad = input_feature.grad
grad.abs().sum(axis=(0, 1)) / grad.abs().sum()