【问题标题】:将 PyTorch 代码转换为具有嵌套层的神经网络的 Keras 代码
【发布时间】:2022-01-22 06:12:18
【问题描述】:

我正在尝试将 NBeats 从 PyTorch 重新创建到 Keras。我正在处理此页面上列出的源代码:https://github.com/ElementAI/N-BEATS/blob/master/models/nbeats.py。这是我试图模拟的示例 PyTorch 代码:

PYTORCH 代码:

class NBeatsBlock(t.nn.Module):
    def __init__(self,
                 input_size,
                 theta_size: int,
                 basis_function: t.nn.Module,
                 layers: int,
                 layer_size: int):
        super().__init__()
        self.layers = t.nn.ModuleList([t.nn.Linear(in_features=input_size, out_features=layer_size)] +
                                      [t.nn.Linear(in_features=layer_size, out_features=layer_size)
                                       for _ in range(layers - 1)])
        self.basis_parameters = t.nn.Linear(in_features=layer_size, out_features=theta_size)
        self.basis_function = basis_function

    def forward(self, x: t.Tensor) -> Tuple[t.Tensor, t.Tensor]:
        block_input = x
        for layer in self.layers:
            block_input = t.relu(layer(block_input))
        basis_parameters = self.basis_parameters(block_input)
        return self.basis_function(basis_parameters)


class NBeats(t.nn.Module):
    def __init__(self, blocks: t.nn.ModuleList):
        super().__init__()
        self.blocks = blocks

    def forward(self, x: t.Tensor, input_mask: t.Tensor) -> t.Tensor:
        residuals = x.flip(dims=(1,))
        input_mask = input_mask.flip(dims=(1,))
        forecast = x[:, -1:]
        for i, block in enumerate(self.blocks):
            backcast, block_forecast = block(residuals)
            residuals = (residuals - backcast) * input_mask
            forecast = forecast + block_forecast
        return forecast

class GenericBasis(t.nn.Module):
    def __init__(self, backcast_size: int, forecast_size: int):
        super().__init__()
        self.backcast_size = backcast_size
        self.forecast_size = forecast_size

    def forward(self, theta: t.Tensor):
        return theta[:, :self.backcast_size], theta[:, -self.forecast_size:]

这是我的 Keras 实现:

KERAS 代码:

class NBeatsBlock(keras.layers.Layer):
    def __init__(self, 
                 theta_size: int,
                 basis_function: keras.layers.Layer,
                 layer_size: int = 4):
        super(NBeatsBlock, self).__init__()
        self.layers_          = [keras.layers.Dense(layer_size, activation = 'relu') 
                                    for i in range(layer_size)]
        self.basis_parameters = keras.layers.Dense(theta_size)
        self.basis_function   = basis_function
        
    def call(self, inputs):
        x = self.layers_[0](inputs)
        for layer in self.layers_[1:]:
            x = layer(x)
        x = self.basis_parameters(x)
        return self.basis_function(x)
    
class NBeats(keras.layers.Layer):
    def __init__(self, 
                 blocksize: int,
                 theta_size: int,
                 basis_function: keras.layers.Layer):
        super(NBeats, self).__init__()
        self.blocks = [NBeatsBlock(theta_size =  theta_size, basis_function =  basis_function) for i in range(blocksize)]
        
    def call(self, inputs):
        residuals = K.reverse(inputs, axes = 0)
        forecast  = inputs[:, -1:]
        for block in self.blocks:
            backcast, block_forecast = block(residuals)
            residuals                = residuals - backcast
            forecast                 = forecast + block_forecast
        return forecast
    
class GenericBasis(keras.layers.Layer):
    def __init__(self, backcast_size: int, forecast_size: int):
        super().__init__()
        self.backcast_size = backcast_size
        self.forecast_size = forecast_size
        
    def call(self, inputs):
        return inputs[:, :self.backcast_size], inputs[:, -self.forecast_size:]

这看起来和我很相似,并且 keras 代码也允许我用它构建一个实际的模型:

inputs       = Input(shape = (1, ))

nbeats       = NBeats(blocksize = 4, theta_size = 7, basis_function = GenericBasis(7, 7))(inputs)
out          = keras.layers.Dense(7)(nbeats)

model        = Model(inputs, out)

但是,当我检查模型摘要时,内部NBeatsBlock 层似乎不存在:

同样,当我绘制模型时,我看不到在 NBeats 块内创建的内部 Dense 层的痕迹:

我不需要有人对我的所有代码进行故障排除,我最关心的是为什么 NBeatsBlock 层都没有出现在我的 NBeats 层中,我认为这意味着我做错了什么,虽然我不确定为什么。

【问题讨论】:

    标签: tensorflow keras deep-learning pytorch


    【解决方案1】:

    这是打印模型摘要的一种可能解决方法,但可能不是通用解决方案。第一个带有tf.keras.Model 类的子类如下:

    class NBeatsBlock(tf.keras.Model):
       ...
    
    class NBeats(tf.keras.Model):
       ...
    
    class GenericBasis(tf.keras.Model):
       ...
    

    现在,在打印模型摘要期间,请执行以下操作

    NBeats(blocksize = 1 ...)
    ...
    model        = Model(inputs, out)
    model.summary(expand_nested=True) < --- TRUE
    
    _________________________________________________________________
     Layer (type)                Output Shape              Param #   
    =================================================================
     input_42 (InputLayer)       [(None, 1)]               0         
                                                                     
     NBeats (NBeats)             (None, 7)                 103       
    |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
    | NBeatsBlock (NBeatsBlock)  multiple                 103       |
    ||¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||
    || dense_728 (Dense)       multiple                  8         ||
    ||                                                             ||
    || dense_729 (Dense)       multiple                  20        ||
    ||                                                             ||
    || dense_730 (Dense)       multiple                  20        ||
    ||                                                             ||
    || dense_731 (Dense)       multiple                  20        ||
    ||                                                             ||
    || dense_732 (Dense)       multiple                  35        ||
    ||                                                             ||
    || generic_basis_45 (GenericBa  multiple             0         ||
    || sis)                                                        ||
    |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
     dense_733 (Dense)           (None, 7)                 56        
                                                                     
    =================================================================
    Total params: 159
    Trainable params: 159
    Non-trainable params: 0
    

    但有一个问题,一些嵌套层的输出形状未显示。现在,plot_model 也不起作用了。

    # output: same as yours - issue remains
    utils.plot_model(model,
                     expand_nested=True, show_layer_activations=True)
    

    我认为,与这两个函数(summaryplot_model)相关的代码没有问题。应该是known issue 的API。我认为你应该打开一个issue 详细信息。

    【讨论】:

      猜你喜欢
      • 2019-12-07
      • 2020-07-31
      • 2017-05-24
      • 2019-08-18
      • 2021-10-11
      • 2019-09-02
      • 2019-06-05
      • 2013-05-17
      • 2017-05-10
      相关资源
      最近更新 更多