在 PyTorch 中重新参数化模型

问题描述 投票:0回答:1

我正在尝试优化使用 PyTorch 库实现的简单模型的参数。出于优化的目的,我想使用与模型类指定的参数不同的表示形式。我特别想将我的参数表示为单个向量(而不是像本例中那样的两个向量)。

我可以使用

model.parameters()
中的
Iterable
parameters_to_vector
(这是一个
torch.nn.utils.convert_parameters
)转换为所需的向量表示。但是,当我尝试将此向量标记为叶子(使用
detach
requires_grad_
),并使用它用
vector_to_parameters
填充模型对象的原始参数时,看起来计算图并未生成知道正在发生什么。

#!/usr/bin/python3
import torch
import torch.nn as nn
from torch.nn.utils.convert_parameters import *

class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.linear = nn.Linear(10, 1)

    def forward(self, x):
        return self.linear(x)

model = SimpleModel()

for name, param in model.named_parameters():
    print(name, param.size())
# this prints:
## linear.weight torch.Size([1, 10])
## linear.bias torch.Size([1])

loss_function = nn.MSELoss()

vparams = parameters_to_vector(model.parameters()).detach().clone().requires_grad_(True)

# populate model.parameters() from vparams
vector_to_parameters(vparams, model.parameters())

input_data = torch.randn(1, 10)
output = model(input_data)
target = torch.randn(1, 1)

loss = loss_function(output, target)
# loss.backward()  ## if we do this, then vparams.grad is None

## this one works, but we wanted to use vparams:
# vgrads = torch.autograd.grad(loss, model.linear.weight)[0]   

## this gives an error:
vgrads = torch.autograd.grad(loss, vparams)[0]
## "One of the differentiated Tensors appears to not have been used in the graph."

我还尝试手动执行矢量切片,但这并不能解决错误。例如:

model.linear.weight.data.copy_(vparams[0:10].view_as(model.linear.weight.data))

model.linear.weight = nn.Parameter(vparams[0:10].view_as(model.linear.weight.data))

我对 PyTorch 有点陌生,但我读过 PyTorch 可以通过切片计算梯度,所以看来我正在尝试的应该是可能的。

我是否遗漏了 PyTorch 模型使用的

torch.nn.Parameter
类的某些内容?该类的成员是否需要成为计算图中的“叶子”?这是一个较小的示例,省略了
nn.Module
子类,只是尝试从“切片”创建
nn.Parameter
对象:

import torch
import torch.nn as nn

a = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)

#b = nn.Parameter(a[1]) # "RuntimeError: One of the differentiated Tensors appears to not have been used in the graph."
#b = torch.Tensor(a[1]) # "IndexError: slice() cannot be applied to a 0-dim tensor."
b = a[1] # works

g = torch.autograd.grad(b, a)[0]

从错误消息来看,PyTorch 似乎无法通过

nn.Parameter
初始化进行区分。有办法解决这个问题吗?

提前致谢。

python tensorflow deep-learning pytorch
1个回答
0
投票

我认为您误解了

vector_to_parameters
的工作原理。看源码:

def vector_to_parameters(vec: torch.Tensor, parameters: Iterable[torch.Tensor]) -> None:
    r"""Convert one vector to the parameters

    Args:
        vec (Tensor): a single vector represents the parameters of a model.
        parameters (Iterable[Tensor]): an iterator of Tensors that are the
            parameters of a model.
    """
    # Ensure vec of type Tensor
    if not isinstance(vec, torch.Tensor):
        raise TypeError('expected torch.Tensor, but got: {}'
                        .format(torch.typename(vec)))
    # Flag for the device where the parameter is located
    param_device = None

    # Pointer for slicing the vector for each parameter
    pointer = 0
    for param in parameters:
        # Ensure the parameters are located in the same device
        param_device = _check_param_device(param, param_device)

        # The length of the parameter
        num_param = param.numel()
        # Slice the vector, reshape it, and replace the old data of the parameter
        param.data = vec[pointer:pointer + num_param].view_as(param).data

        # Increment the pointer
        pointer += num_param

vector_to_parameters
vec
中的值分配给
parameters
中的参数。这会更新
data
中的
parameters
值,但
vec
和更新后的参数之间没有自动梯度链接。

当您进行前向传递时,您使用模型状态字典中的参数,并且梯度流回这些参数。

例如,当您运行以下代码时,您会得到在

model.linear.weight.grad
处填充的渐变,因为这是计算的叶参数。
vparams
不参与计算,因此没有返回到
vparams
的梯度链。

vector_to_parameters(vparams, model.parameters())

input_data = torch.randn(1, 10)
output = model(input_data)
target = torch.randn(1, 1)

loss = loss_function(output, target)
loss.backward()

print(model.linear.weight.grad)
© www.soinside.com 2019 - 2024. All rights reserved.