神经网络

模块 pyro.nn 提供了在深度概率编程背景下有用的神经网络模块的实现。

Pyro模块

Pyro 包含一个类 PyroModule,它是 torch.nn.Module 的子类,其属性可以通过 Pyro 效果进行修改。要 创建一个支持 poutine 的属性,可以使用 PyroParam 结构或 PyroSample 结构:

my_module = PyroModule()
my_module.x = PyroParam(torch.tensor(1.), constraint=constraints.positive)
my_module.y = PyroSample(dist.Normal(0, 1))
class PyroParam(init_value: Optional[Union[torch.Tensor, Callable[[], torch.Tensor]]] = None, constraint: torch.distributions.constraints.Constraint = Real(), event_dim: Optional[int] = None)[source]

基础类:tuple

声明一个由Pyro管理的可学习属性,类似于pyro.param

这可以用于设置PyroModule实例的属性:

assert isinstance(my_module, PyroModule)
my_module.x = PyroParam(torch.zeros(4))                   # eager
my_module.y = PyroParam(lambda: torch.randn(4))           # lazy
my_module.z = PyroParam(torch.ones(4),                    # eager
                        constraint=constraints.positive,
                        event_dim=1)

或者实验性地作为延迟初始化属性的装饰器:

class MyModule(PyroModule):
    @PyroParam
    def x(self):
        return torch.zeros(4)

    @PyroParam
    def y(self):
        return torch.randn(4)

    @PyroParam(constraint=constraints.real, event_dim=1)
    def z(self):
        return torch.ones(4)

    def forward(self):
        return self.x + self.y + self.z  # accessed like a @property
Parameters
  • init_value (torch.Tensor返回 torch.Tensor 的可调用对象None) – 可以是一个用于急切初始化的张量,一个用于延迟初始化的可调用对象,或者 None 用作装饰器。

  • 约束 (Constraint) – torch 约束,默认为 constraints.real

  • event_dim (int) – (可选)与批处理无关的最右侧维度的数量。此维度左侧的维度将被视为批处理维度;如果参数语句位于子采样的plate中,则参数的相应批处理维度将相应地进行子采样。如果未指定,所有维度将被视为事件维度,并且不会执行子采样。

init_value: Optional[Union[torch.Tensor, Callable[[], torch.Tensor]]]

字段编号 0 的别名

constraint: torch.distributions.constraints.Constraint

字段编号1的别名

event_dim: Optional[int]

字段编号2的别名

class PyroSample(prior: Union[TorchDistributionMixin, Callable[[PyroModule], TorchDistributionMixin]])[source]

基础类:object

声明一个由Pyro管理的随机属性,类似于pyro.sample

这可以用于设置PyroModule实例的属性:

assert isinstance(my_module, PyroModule)
my_module.x = PyroSample(Normal(0, 1))                    # independent
my_module.y = PyroSample(lambda self: Normal(self.x, 1))  # dependent

或者实验性地作为延迟初始化方法的装饰器:

class MyModule(PyroModule):
    @PyroSample
    def x(self):
        return Normal(0, 1)       # independent

    @PyroSample
    def y(self):
        return Normal(self.x, 1)  # dependent

    def forward(self):
        return self.y             # accessed like a @property
Parameters

prior – 输入PyroModule实例self并返回一个分布对象的分布对象或函数。

prior: Union[TorchDistributionMixin, Callable[[PyroModule], TorchDistributionMixin]]
class PyroModule(name: str = '')[source]

基础类: torch.nn.modules.module.Module

torch.nn.Module 的子类,其属性可以通过 Pyro 效果进行修改。属性可以使用助手 PyroParamPyroSample 进行设置,方法可以通过 pyro_method() 进行装饰。

参数

要创建一个由Pyro管理的参数属性,可以使用torch.nn.Parameter(用于无约束参数)或PyroParam(用于有约束参数)来设置该属性。读取该属性时,将触发pyro.param语句。例如:

# Create Pyro-managed parameter attributes.
my_module = PyroModule()
my_module.loc = nn.Parameter(torch.tensor(0.))
my_module.scale = PyroParam(torch.tensor(1.),
                            constraint=constraints.positive)
# Read the attributes.
loc = my_module.loc  # Triggers a pyro.param statement.
scale = my_module.scale  # Triggers another pyro.param statement.

请注意,与普通的torch.nn.Module不同,PyroModule不应通过pyro.module语句进行注册。PyroModule可以包含其他PyroModule和普通的torch.nn.Module。访问PyroModule的普通torch.nn.Module属性会触发pyro.module语句。如果在一个Pyro模型或指南中出现多个PyroModule,它们应该包含在该模型的单个根PyroModule中。

PyroModule 在每次 setattrgetattrdelattr 事件时,根据属性的嵌套名称与参数存储同步数据:

  • 设置 mod.x = x_init 会尝试从参数存储中读取 x。如果在参数存储中找到值,则该值会被复制到 mod 中,并且 x_init 会被忽略;否则,x_init 会被复制到 mod 和参数存储中。

  • 读取 mod.x 尝试从参数存储中读取 x。如果在参数存储中找到值,则该值被复制到 mod 中;否则,mod 的值被复制到参数存储中。最后,mod 和参数存储就返回的单一值达成一致。

  • 删除 del mod.x 会从 mod 和参数存储中移除一个值。

注意,两个同名的PyroModule都会与全局参数存储同步,因此包含相同的数据。当创建一个PyroModule,然后删除它,再创建一个同名的模块时,后者将从参数存储中填充前者的数据。为了避免这种持久性,可以在删除PyroModule之前调用pyro.clear_param_store()clear()

PyroModule 可以直接使用 torch.save() / torch.load() 进行保存和加载,或者间接使用参数存储的 save() / load()。请注意,torch.load() 会被参数存储中的任何值覆盖,因此在加载之前最好先 pyro.clear_param_store()

示例

要创建一个由Pyro管理的随机属性,使用PyroSample辅助工具设置该属性,并指定一个先验分布。读取该属性将触发一个pyro.sample语句。例如:

# Create Pyro-managed random attributes.
my_module.x = PyroSample(dist.Normal(0, 1))
my_module.y = PyroSample(lambda self: dist.Normal(self.loc, self.scale))

# Sample the attributes.
x = my_module.x  # Triggers a pyro.sample statement.
y = my_module.y  # Triggers one pyro.sample + two pyro.param statements.

采样在每次调用.__call__()或由pyro_method()装饰的方法中被缓存。由于采样语句在Pyro跟踪中只能出现一次,您应确保对采样属性的跟踪访问被包装在.__call__()或由pyro_method()装饰的方法的单个调用中。

要使现有模块具有概率性,您可以创建一个子类并使用PyroSample覆盖一些参数:

class RandomLinear(nn.Linear, PyroModule):  # used as a mixin
    def __init__(self, in_features, out_features):
        super().__init__(in_features, out_features)
        self.weight = PyroSample(
            lambda self: dist.Normal(0, 1)
                             .expand([self.out_features,
                                      self.in_features])
                             .to_event(2))

混合类

PyroModule 可以用作混合类,并支持动态创建混合类的简单语法,例如以下内容是等价的:

# Version 1. create a named mixin class
class PyroLinear(nn.Linear, PyroModule):
    pass

m.linear = PyroLinear(m, n)

# Version 2. create a dynamic mixin class
m.linear = PyroModule[nn.Linear](m, n)

这种表示法可以递归地用于创建贝叶斯模块,例如:

model = PyroModule[nn.Sequential](
    PyroModule[nn.Linear](28 * 28, 100),
    PyroModule[nn.Sigmoid](),
    PyroModule[nn.Linear](100, 100),
    PyroModule[nn.Sigmoid](),
    PyroModule[nn.Linear](100, 10),
)
assert isinstance(model, nn.Sequential)
assert isinstance(model, PyroModule)

# Now we can be Bayesian about weights in the first layer.
model[0].weight = PyroSample(
    prior=dist.Normal(0, 1).expand([28 * 28, 100]).to_event(2))
guide = AutoDiagonalNormal(model)

请注意,PyroModule[...] 不会递归地将 PyroModule 混入到输入的 Module 的子模块中;因此我们需要 将上述 nn.Sequential 的每个子模块进行包装。

Parameters

name (str) – 可选的根 PyroModule 名称。这在另一个 PyroModule 的子 PyroModule 中会被忽略。

add_module(name: str, module: Optional[torch.nn.modules.module.Module]) None[源代码]

向当前模块添加一个子模块。

named_pyro_params(prefix: str = '', recurse: bool = True) Iterator[Tuple[str, torch.nn.parameter.Parameter]][来源]

返回一个遍历PyroModule参数的迭代器,同时生成参数的名称和参数本身。

Parameters
  • prefix (str) – 要添加到所有参数名称前的前缀。

  • recurse (bool) – 如果为True,则生成此模块及其所有子模块的参数。否则,仅生成直接属于此模块的参数。

Returns

一个生成器,它生成包含名称和参数的元组

training: bool
pyro_method(fn: Callable[[pyro.nn.module._PyroModule, pyro.nn.module._P], pyro.nn.module._T]) Callable[[pyro.nn.module._PyroModule, pyro.nn.module._P], pyro.nn.module._T][source]

用于PyroModule顶层方法的装饰器,以启用pyro效果并缓存pyro.sample语句。

这应该应用于所有读取Pyro管理属性的公共方法,但对于.forward()则不需要。

clear(mod: pyro.nn.module.PyroModule) None[source]

PyroModule和参数存储中移除数据。

Parameters

mod (PyroModule) – 要清除的模块。

to_pyro_module_(m: torch.nn.modules.module.Module, recurse: bool = True) None[source]

将一个普通的torch.nn.Module实例转换为PyroModule 原地

这对于向第三方模块添加Pyro效果非常有用:无需修改任何第三方代码。例如:

model = nn.Sequential(
    nn.Linear(28 * 28, 100),
    nn.Sigmoid(),
    nn.Linear(100, 100),
    nn.Sigmoid(),
    nn.Linear(100, 10),
)
to_pyro_module_(model)
assert isinstance(model, PyroModule[nn.Sequential])
assert isinstance(model[0], PyroModule[nn.Linear])

# Now we can attempt to be fully Bayesian:
for m in model.modules():
    for name, value in list(m.named_parameters(recurse=False)):
        setattr(m, name, PyroSample(prior=dist.Normal(0, 1)
                                              .expand(value.shape)
                                              .to_event(value.dim())))
guide = AutoDiagonalNormal(model)
Parameters
  • m (torch.nn.Module) – 一个模块实例。

  • recurse (bool) – 是否将子模块转换为 PyroModules

class PyroModuleList(modules)[source]

基础类:torch.nn.modules.container.ModuleList, pyro.nn.module.PyroModule

自回归神经网络

class AutoRegressiveNN(input_dim: int, hidden_dims: List[int], param_dims: List[int] = [1, 1], permutation: Optional[torch.LongTensor] = None, skip_connections: bool = False, nonlinearity: torch.nn.modules.module.Module = ReLU())[source]

基础类:pyro.nn.auto_reg_nn.ConditionalAutoRegressiveNN

一个类似MADE的自回归神经网络的实现。

示例用法:

>>> x = torch.randn(100, 10)
>>> arn = AutoRegressiveNN(10, [50], param_dims=[1])
>>> p = arn(x)  # 1 parameters of size (100, 10)
>>> arn = AutoRegressiveNN(10, [50], param_dims=[1, 1])
>>> m, s = arn(x) # 2 parameters of size (100, 10)
>>> arn = AutoRegressiveNN(10, [50], param_dims=[1, 5, 3])
>>> a, b, c = arn(x) # 3 parameters of sizes, (100, 1, 10), (100, 5, 10), (100, 3, 10)
Parameters
  • input_dim (int) – 输入变量的维度

  • hidden_dims (list[int]) – 每层隐藏单元的维度

  • param_dims (list[int]) – 将输出形状转换为维度为 (p_n, input_dim) 的参数,当 p_n > 1 时,以及维度为 (input_dim) 的参数,当 p_n == 1 时。默认值为 [1, 1],即输出两个维度为 (input_dim) 的参数,这对于逆自回归流非常有用。

  • permutation (torch.LongTensor) – 一个可选的排列,应用于输入并控制自回归分解的顺序。特别是对于恒等排列,自回归结构使得雅可比矩阵是上三角的。默认情况下,这是随机选择的。

  • skip_connections (bool) – 是否添加从输入到输出的跳跃连接。

  • 非线性 (torch.nn.module) – 在前馈网络中使用的非线性函数,例如 torch.nn.ReLU()。请注意,最终网络输出不应用非线性函数,因此输出是一个无界的实数。

参考:

MADE: 用于分布估计的掩码自编码器 [arXiv:1502.03509] Mathieu Germain, Karol Gregor, Iain Murray, Hugo Larochelle

forward(x: torch.Tensor) Union[Sequence[torch.Tensor], torch.Tensor][source]
training: bool

DenseNN

class DenseNN(input_dim: int, hidden_dims: List[int], param_dims: List[int] = [1, 1], nonlinearity: torch.nn.modules.module.Module = ReLU())[source]

基础类:pyro.nn.dense_nn.ConditionalDenseNN

一个简单的密集前馈网络的实现,用于例如一些条件流,如 pyro.distributions.transforms.ConditionalPlanarFlow 和其他不需要自回归网络的无条件流,如 pyro.distributions.transforms.AffineCoupling

示例用法:

>>> input_dim = 10
>>> context_dim = 5
>>> z = torch.rand(100, context_dim)
>>> nn = DenseNN(context_dim, [50], param_dims=[1, input_dim, input_dim])
>>> a, b, c = nn(z)  # parameters of size (100, 1), (100, 10), (100, 10)
Parameters
  • input_dim (int) – 输入的维度

  • hidden_dims (list[int]) – 每层隐藏单元的维度

  • param_dims (list[int]) – 将输出形状转换为维度为 (p_n,) 的参数,当 p_n > 1 时,当 p_n == 1 时维度为 ()。默认值为 [1, 1],即输出两个维度为 () 的参数。

  • 非线性 (torch.nn.module) – 在前馈网络中使用的非线性函数,例如 torch.nn.ReLU()。请注意,最终网络输出不应用非线性函数,因此输出是一个无界的实数。

forward(x: torch.Tensor) Union[Sequence[torch.Tensor], torch.Tensor][source]
training: bool

条件自回归神经网络

class ConditionalAutoRegressiveNN(input_dim: int, context_dim: int, hidden_dims: List[int], param_dims: List[int] = [1, 1], permutation: Optional[torch.LongTensor] = None, skip_connections: bool = False, nonlinearity: torch.nn.modules.module.Module = ReLU())[source]

基础类: torch.nn.modules.module.Module

一个类似MADE的自回归神经网络的实现,可以输入额外的上下文变量。 (有关条件MADE架构如何工作的解释,请参见参考文献[2]第3.3节。)

示例用法:

>>> x = torch.randn(100, 10)
>>> y = torch.randn(100, 5)
>>> arn = ConditionalAutoRegressiveNN(10, 5, [50], param_dims=[1])
>>> p = arn(x, context=y)  # 1 parameters of size (100, 10)
>>> arn = ConditionalAutoRegressiveNN(10, 5, [50], param_dims=[1, 1])
>>> m, s = arn(x, context=y) # 2 parameters of size (100, 10)
>>> arn = ConditionalAutoRegressiveNN(10, 5, [50], param_dims=[1, 5, 3])
>>> a, b, c = arn(x, context=y) # 3 parameters of sizes, (100, 1, 10), (100, 5, 10), (100, 3, 10)
Parameters
  • input_dim (int) – 输入变量的维度

  • context_dim (int) – 上下文变量的维度

  • hidden_dims (list[int]) – 每层隐藏单元的维度

  • param_dims (list[int]) – 将输出形状转换为维度为 (p_n, input_dim) 的参数,当 p_n > 1 时,以及维度为 (input_dim) 的参数,当 p_n == 1 时。默认值为 [1, 1],即输出两个维度为 (input_dim) 的参数,这对于逆自回归流非常有用。

  • permutation (torch.LongTensor) – 一个可选的排列,应用于输入并控制自回归分解的顺序。特别是对于恒等排列,自回归结构使得雅可比矩阵是上三角的。默认情况下,这是随机选择的。

  • skip_connections (bool) – 是否添加从输入到输出的跳跃连接。

  • 非线性 (torch.nn.module) – 在前馈网络中使用的非线性函数,例如 torch.nn.ReLU()。请注意,最终网络输出不应用非线性函数,因此输出是一个无界的实数。

参考:

1. MADE: 用于分布估计的掩码自编码器 [arXiv:1502.03509] Mathieu Germain, Karol Gregor, Iain Murray, Hugo Larochelle

2. 图形模型中顺序蒙特卡洛的推理网络 [arXiv:1602.06701] 布鲁克斯·佩奇, 弗兰克·伍德

forward(x: torch.Tensor, context: Optional[torch.Tensor] = None) Union[Sequence[torch.Tensor], torch.Tensor][source]
get_permutation() torch.LongTensor[source]

获取应用于输入的排列(默认情况下这是随机选择的)

training: bool

条件密集神经网络

class ConditionalDenseNN(input_dim: int, context_dim: int, hidden_dims: List[int], param_dims: List[int] = [1, 1], nonlinearity: torch.nn.modules.module.Module = ReLU())[source]

基础类: torch.nn.modules.module.Module

一个简单的密集前馈网络的实现,该网络接受一个上下文变量,用于例如某些条件流,如pyro.distributions.transforms.ConditionalAffineCoupling

示例用法:

>>> input_dim = 10
>>> context_dim = 5
>>> x = torch.rand(100, input_dim)
>>> z = torch.rand(100, context_dim)
>>> nn = ConditionalDenseNN(input_dim, context_dim, [50], param_dims=[1, input_dim, input_dim])
>>> a, b, c = nn(x, context=z)  # parameters of size (100, 1), (100, 10), (100, 10)
Parameters
  • input_dim (int) – 输入的维度

  • context_dim (int) – 上下文变量的维度

  • hidden_dims (list[int]) – 每层隐藏单元的维度

  • param_dims (list[int]) – 将输出形状转换为维度为 (p_n,) 的参数,当 p_n > 1 时,当 p_n == 1 时维度为 ()。默认值为 [1, 1],即输出两个维度为 () 的参数。

  • 非线性 (torch.nn.Module) – 在前馈网络中使用的非线性函数,例如 torch.nn.ReLU()。请注意,最终的网络输出不会应用非线性函数,因此输出是一个无界的实数。

forward(x: torch.Tensor, context: torch.Tensor) Union[Sequence[torch.Tensor], torch.Tensor][source]
training: bool