python - 如何在不影响梯度的情况下更改 NN 权重?
问题描述
假设我有一个简单的 NN:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.nn.utils import parameters_to_vector
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.fc1 = nn.Linear(1, 2)
self.fc2 = nn.Linear(2, 3)
self.fc3 = nn.Linear(3, 1)
def forward(self, x):
x = self.fc1(x)
x = torch.relu(x)
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Model()
opt = optim.Adam(net.parameters())
还有一些功能
features = torch.rand((3,1))
我可以使用以下方法正常训练它:
for i in range(10):
opt.zero_grad()
out = net(features)
loss = torch.mean(torch.square(torch.tensor(5) - torch.sum(out)))
loss.backward()
opt.step()
但是,我有兴趣在批处理中的每个示例之后更新每一层的权重。也就是说,将实际权重值更新为每层不同的量。
我可以打印每一层的参数:
for i in range(1):
opt.zero_grad()
out = net(features)
print(parameters_to_vector(net.fc1.parameters()))
print(parameters_to_vector(net.fc2.parameters()))
print(parameters_to_vector(net.fc3.parameters()))
loss = torch.mean(torch.square(torch.tensor(5) - torch.sum(out)))
loss.backward()
opt.step()
如何在不影响梯度的情况下更改反向传播之前的权重值?
假设我希望根据以下功能更新图层权重:
def first_layer_update(weight):
return weight + 1e-3*weight
def second_layer_update(weight):
return 1e-2*weight
def third_layer_update(weight):
return weight - 1e-1*weight
解决方案
- 使用torch.no_grad
上下文管理器。
这允许您在张量上执行(就地或异地)操作,而无需 Autograd 跟踪这些更改。正如@user3474165解释的那样:
def first_layer_update(weight):
with torch.no_grad():
return weight + 1e-3*weight
def second_layer_update(weight):
with torch_no_grad():
return 1e-2*weight
def third_layer_update(weight):
with torch.no_grad():
return weight - 1e-1*weight
或者在调用函数时不使用上下文管理器更改函数:
with torch.no_grad():
first_layer_update(net.fc1.weight)
second_layer_update(net.fc2.weight)
third_layer_update(net.fc3.weight)
- 使用@torch.no_grad
装饰器。
一个变体是使用@torch.no_grad
装饰器:
@torch.no_grad()
def first_layer_update(weight):
return weight + 1e-3*weight
@torch.no_grad():
def second_layer_update(weight):
return 1e-2*weight
@torch.no_grad():
def third_layer_update(weight):
return weight - 1e-1*weight
并用: first_layer_update(net.fc1.weight)
, second_layer_update(net.fc2.weight)
, 等来调用它们...
- 变异torch.Tensor.data
。
使用上下文包装操作的另一种方法torch.no_grad
是使用它们的data
属性来改变权重。这意味着调用你的函数:
>>> first_layer_update(net.fc1.weight.data)
>>> second_layer_update(net.fc2.weight.data)
>>> third_layer_update(net.fc3.weight.data)
这将使用各自的更新策略改变三层的权重(而不是偏差)。
简而言之,如果你想改变 a 的所有参数,nn.Module
你可以这样做:
>>> with torch.no_grad():
... update_policy(parameters_to_vector(net.layer.parameters()))
或者
>>> update_policy(parameters_to_vector(net.layer.parameters().data))
推荐阅读
- powershell - 给定一个 IP 地址,我如何找到它也属于哪个 GCP Compute Engine 实例?
- c# - 如何将表达式传递到实体框架 LINQ 查询 OrderBy 子句
- javascript - 如何在 Sequelize .then 中执行 bcrypt.compare?
- bash - ssh 找不到 /usr/local/bin 路径
- python - pysftp 无法创建日志文件 - 权限被拒绝
- vue.js - 为什么我的 paypal 添加到购物车按钮可以与沙盒一起使用,而我的订阅按钮却不能?
- python - pandas - 多张大纸上的 read_excel 效率
- python - 如果其他特定列与变量匹配,则更新数据库列
- regex - 值不是有效的 XML 正则表达式
- java - 字符串频率搜索未找到所有单词