首先有个
网络定义
随意定义了,根据自己的情况
python
class ANN(nn.Module):
def __init__(self):
super(ANN, self).__init__()
self.fc1 = nn.Linear(10000, 1)
# self.fc1.bias.data.fill_(0)
def forward(self, data):
x = self.fc1(data)
return x
求hessian
autograd这个方法求梯度的时候分子是scalar ,分母是vector的时候,也即scalar对vector求导,得到的梯度向量和vector一样,而对于vector对vector求导,autograd没法求,只能求scalar对vector求导,所以需要循环。
python
def getHessian(grads, model, loss_fn, dat, tar ,device):
loss = loss_fn(model(dat), tar)
grads_fn = torch.autograd.grad(loss, model.parameters(), retain_graph=True, create_graph=True) # 记录一阶梯度的grad_fn
# 这部分是更新一阶梯度的值,因为其实我要计算的一阶梯度的值是grads
for source, target in zip(grads, grads_fn):
target.data.copy_(source)
hessian_params = []
#第k个梯度
for k in range(len(grads_fn)):
# 第i个参数
for param in model.parameters():
hess_params = []
# 第k个梯度的地i行参数
for i in range(grads_fn[k].size(0)):
# 判断是w还是b
if len(grads_fn[k].size()) == 2:
# w
for j in range(grads_fn[k].size(1)):
hess = torch.autograd.grad(grads_fn[k][i][j], param, retain_graph=True, allow_unused= True)
hess_params.append(hess[0].cpu().detach().numpy() if hess[0] is not None else None)
else:
# b
hess = torch.autograd.grad(grads_fn[k][i], param, retain_graph=True, allow_unused=True)
hess_params.append(hess[0].cpu().detach().numpy() if hess[0] is not None else None)
hessian_params.append(np.array(hess_params))
return hessian_params
关于backward和autograd
autograd只计算梯度不反向传播更新model的参数,因为这部分是torch中的优化器进行的,backward()也计算梯度,但获得具体一阶梯度信息需要用这个命令
grad_list = [p.grad.clone() for p in net.parameters()]
而这样得到的一阶梯度是不含grad_fn的,再进行求导的时候报错,虽然我也尝试loss.backward(retain_graph=True)用了这里的参数,但仍然无法解决问题,所以还是用了autograd。但在模型更新的时候两者使用并不冲突
python
net = ANN()
opt = optim.SGD(net.parameters(), lr=1e-4)
net.load_state_dict(model_state_dict)
net.to(device)
opt.load_state_dict(optimizer_state_dict)
opt.zero_grad()
pred = net(inputs)
loss = loss_fn(pred, targets)
grads = torch.autograd.grad(loss, net.parameters(), retain_graph=True, create_graph=True) # 计算一阶梯度
loss.backward(retain_graph=True)
opt.step()
·········
······
#之后进行hessian矩阵的计算就可以
参考
[2] 【矩阵的导数运算】标量向量方程对向量求导_分母布局_分子布局 此系列三个视频
[3] 常用矩阵微分公式_老子今晚不加班的博客-CSDN博客 这里提到的链接,里面也有提到[4]的链接
[4] Matrix calculus - Wikipedia这里面总结的很好