将Keras代码转换为PyTorch代码时出现的问题(整形)

时间:2019-04-11 15:29:11

标签: machine-learning keras deep-learning pytorch

我有一些需要转换为Pytorch的keras代码。我是pytorch的新手,我无法像在keras中一样将头放在如何接受输入上。我在此上花费了许多时间,非常感谢您提供任何提示或帮助。

这是我正在处理的keras代码。输入形状为(5000,1)

    def build(input_shape, classes):
        model = Sequential()

        filter_num = ['None',32,64,128,256]
        kernel_size = ['None',8,8,8,8]
        conv_stride_size = ['None',1,1,1,1]
        pool_stride_size = ['None',4,4,4,4]
        pool_size = ['None',8,8,8,8]


        # Block1
        model.add(Conv1D(filters=filter_num[1], kernel_size=kernel_size[1], input_shape=input_shape,
                         strides=conv_stride_size[1], padding='same',
                         name='block1_conv1'))
        model.add(BatchNormalization(axis=-1))
        model.add(ELU(alpha=1.0, name='block1_adv_act1'))
        model.add(Conv1D(filters=filter_num[1], kernel_size=kernel_size[1],
                         strides=conv_stride_size[1], padding='same',
                         name='block1_conv2'))
        model.add(BatchNormalization(axis=-1))
        model.add(ELU(alpha=1.0, name='block1_adv_act2'))
        model.add(MaxPooling1D(pool_size=pool_size[1], strides=pool_stride_size[1],
                               padding='same', name='block1_pool'))
        model.add(Dropout(0.1, name='block1_dropout'))



        # Block 2
        model.add(Conv1D(filters=filter_num[2], kernel_size=kernel_size[2],
                         strides=conv_stride_size[2], padding='same',
                         name='block2_conv1'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block2_act1'))

        model.add(Conv1D(filters=filter_num[2], kernel_size=kernel_size[2],
                         strides=conv_stride_size[2], padding='same',
                         name='block2_conv2'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block2_act2'))
        model.add(MaxPooling1D(pool_size=pool_size[2], strides=pool_stride_size[3],
                               padding='same', name='block2_pool'))
        model.add(Dropout(0.1, name='block2_dropout'))



        # Block 3
        model.add(Conv1D(filters=filter_num[3], kernel_size=kernel_size[3],
                         strides=conv_stride_size[3], padding='same',
                         name='block3_conv1'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block3_act1'))
        model.add(Conv1D(filters=filter_num[3], kernel_size=kernel_size[3],
                         strides=conv_stride_size[3], padding='same',
                         name='block3_conv2'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block3_act2'))
        model.add(MaxPooling1D(pool_size=pool_size[3], strides=pool_stride_size[3],
                               padding='same', name='block3_pool'))
        model.add(Dropout(0.1, name='block3_dropout'))



        # Block 4
        model.add(Conv1D(filters=filter_num[4], kernel_size=kernel_size[4],
                         strides=conv_stride_size[4], padding='same',
                         name='block4_conv1'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block4_act1'))
        model.add(Conv1D(filters=filter_num[4], kernel_size=kernel_size[4],
                         strides=conv_stride_size[4], padding='same',
                         name='block4_conv2'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='block4_act2'))
        model.add(MaxPooling1D(pool_size=pool_size[4], strides=pool_stride_size[4],
                               padding='same', name='block4_pool'))
        model.add(Dropout(0.1, name='block4_dropout'))




        # FC #1
        model.add(Flatten(name='flatten'))
        model.add(Dense(512, kernel_initializer=glorot_uniform(seed=0), name='fc1'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='fc1_act'))

        model.add(Dropout(0.7, name='fc1_dropout'))


        #FC #2
        model.add(Dense(512, kernel_initializer=glorot_uniform(seed=0), name='fc2'))
        model.add(BatchNormalization())
        model.add(Activation('relu', name='fc2_act'))

        model.add(Dropout(0.5, name='fc2_dropout'))


        # Classification
        model.add(Dense(classes, kernel_initializer=glorot_uniform(seed=0), name='fc3'))
        model.add(Activation('softmax', name="softmax"))
        return model

这是来自keras代码的model.summary()的结果

Layer (type)                 Output Shape              Param #   
=================================================================
block1_conv1 (Conv1D)        (None, 5000, 32)          288       
_________________________________________________________________
batch_normalization_1 (Batch (None, 5000, 32)          128       
_________________________________________________________________
block1_adv_act1 (ELU)        (None, 5000, 32)          0         
_________________________________________________________________
block1_conv2 (Conv1D)        (None, 5000, 32)          8224      
_________________________________________________________________
batch_normalization_2 (Batch (None, 5000, 32)          128       
_________________________________________________________________
block1_adv_act2 (ELU)        (None, 5000, 32)          0         
_________________________________________________________________
block1_pool (MaxPooling1D)   (None, 1250, 32)          0         
_________________________________________________________________
block1_dropout (Dropout)     (None, 1250, 32)          0         
_________________________________________________________________
block2_conv1 (Conv1D)        (None, 1250, 64)          16448     
_________________________________________________________________
batch_normalization_3 (Batch (None, 1250, 64)          256       
_________________________________________________________________
block2_act1 (Activation)     (None, 1250, 64)          0         
_________________________________________________________________
block2_conv2 (Conv1D)        (None, 1250, 64)          32832     
_________________________________________________________________
batch_normalization_4 (Batch (None, 1250, 64)          256       
_________________________________________________________________
block2_act2 (Activation)     (None, 1250, 64)          0         
_________________________________________________________________
block2_pool (MaxPooling1D)   (None, 313, 64)           0         
_________________________________________________________________
block2_dropout (Dropout)     (None, 313, 64)           0         
_________________________________________________________________
block3_conv1 (Conv1D)        (None, 313, 128)          65664     
_________________________________________________________________
batch_normalization_5 (Batch (None, 313, 128)          512       
_________________________________________________________________
block3_act1 (Activation)     (None, 313, 128)          0         
_________________________________________________________________
block3_conv2 (Conv1D)        (None, 313, 128)          131200    
_________________________________________________________________
batch_normalization_6 (Batch (None, 313, 128)          512       
_________________________________________________________________
block3_act2 (Activation)     (None, 313, 128)          0         
_________________________________________________________________
block3_pool (MaxPooling1D)   (None, 79, 128)           0         
_________________________________________________________________
block3_dropout (Dropout)     (None, 79, 128)           0         
_________________________________________________________________
block4_conv1 (Conv1D)        (None, 79, 256)           262400    
_________________________________________________________________
batch_normalization_7 (Batch (None, 79, 256)           1024      
_________________________________________________________________
block4_act1 (Activation)     (None, 79, 256)           0         
_________________________________________________________________
block4_conv2 (Conv1D)        (None, 79, 256)           524544    
_________________________________________________________________
batch_normalization_8 (Batch (None, 79, 256)           1024      
_________________________________________________________________
block4_act2 (Activation)     (None, 79, 256)           0         
_________________________________________________________________
block4_pool (MaxPooling1D)   (None, 20, 256)           0         
_________________________________________________________________
block4_dropout (Dropout)     (None, 20, 256)           0         
_________________________________________________________________
flatten (Flatten)            (None, 5120)              0         
_________________________________________________________________
fc1 (Dense)                  (None, 512)               2621952   
_________________________________________________________________
batch_normalization_9 (Batch (None, 512)               2048      
_________________________________________________________________
fc1_act (Activation)         (None, 512)               0         
_________________________________________________________________
fc1_dropout (Dropout)        (None, 512)               0         
_________________________________________________________________
fc2 (Dense)                  (None, 512)               262656    
_________________________________________________________________
batch_normalization_10 (Batc (None, 512)               2048      
_________________________________________________________________
fc2_act (Activation)         (None, 512)               0         
_________________________________________________________________
fc2_dropout (Dropout)        (None, 512)               0         
_________________________________________________________________
fc3 (Dense)                  (None, 101)               51813     
_________________________________________________________________
softmax (Activation)         (None, 101)               0         
=================================================================
Total params: 3,985,957
Trainable params: 3,981,989
Non-trainable params: 3,968

这是我用火炬制成的东西

class model(torch.nn.Module):
    def __init__(self, input_channels, kernel_size, stride, pool_kernel, pool_stride, dropout_p, dropout_inplace=False):
        super(model, self).__init__()
        self.encoder = nn.Sequential(
            BasicBlock1(input_channels, kernel_size, stride, pool_kernel, pool_stride, dropout_p),
            BasicBlock(input_channels//4, kernel_size, stride, pool_kernel, pool_stride, dropout_p),
            BasicBlock(input_channels//16, kernel_size, stride, pool_kernel, pool_stride, dropout_p),
            BasicBlock(input_channels//16//4, kernel_size, stride, pool_kernel, pool_stride, dropout_p)
        )


        self.decoder = nn.Sequential(
            nn.Linear(5120, 512),
            nn.BatchNorm1d(512),
            nn.ReLU(),
            nn.Dropout(p=dropout_p, inplace=dropout_inplace),
            nn.Linear(512, 512),
            nn.BatchNorm1d(512),
            nn.ReLU(),
            nn.Dropout(p=dropout_p, inplace=dropout_inplace),
            nn.Linear(512, 101),
            nn.Softmax(dim=101)
        )
    def forward(self, x):
        x = self.encoder(x)

        x = x.view(x.size(0), -1)  # flatten

        x = self.decoder(x)
        return x


def BasicBlock(input_channels, kernel_size, stride, pool_kernel, pool_stride, dropout_p, dropout_inplace=False):
    return nn.Sequential(
        nn.Conv1d(in_channels=input_channels, out_channels=input_channels, kernel_size=kernel_size, stride=stride,
                  padding=get_pad_size(input_channels, input_channels, kernel_size)),
        nn.BatchNorm1d(32),
        nn.ReLU(),
        nn.Conv1d(in_channels=input_channels, out_channels=input_channels, kernel_size=kernel_size, stride=stride,
                  padding=get_pad_size(input_channels, input_channels, kernel_size)),
        nn.BatchNorm1d(32),
        nn.ReLU(),
        nn.MaxPool1d(kernel_size=pool_kernel, stride=pool_stride,
                     padding=get_pad_size(input_channels, input_channels/4, kernel_size)),
        nn.Dropout(p=dropout_p, inplace=dropout_inplace)
    )


def BasicBlock1(input_channels, kernel_size, stride, pool_kernel, pool_stride, dropout_p, dropout_inplace=False):
    return nn.Sequential(
        nn.Conv1d(in_channels=1, out_channels=input_channels, kernel_size=kernel_size, stride=stride,
                  padding=get_pad_size(input_channels, input_channels, kernel_size)),
        nn.BatchNorm1d(32),
        nn.ReLU(),
        nn.Conv1d(in_channels=input_channels, out_channels=input_channels, kernel_size=kernel_size, stride=stride,
                  padding=get_pad_size(input_channels, input_channels, kernel_size)),
        nn.BatchNorm1d(32),
        nn.ReLU(),
        nn.MaxPool1d(kernel_size=pool_kernel, stride=pool_stride,
                     padding=get_pad_size(input_channels, input_channels/4, kernel_size)),
        nn.Dropout(p=dropout_p, inplace=dropout_inplace)
    )


def get_pad_size(input_shape, output_shape, kernel_size, stride=1, dilation=1):
    """
    Gets the right padded needed to maintain same shape in the conv layers
    BEWARE: works only on odd size kernel size
    :param input_shape: the input shape to the conv layer
    :param output_shape: the desired output shape of the conv layer
    :param kernel_size: the size of the kernel window, has to be odd
    :param stride: Stride of the convolution
    :param dilation: Spacing between kernel elements
    :return: the appropriate pad size for the needed configuration
    :Author: Aneesh
    """

    if kernel_size % 2 == 0:
        raise ValueError(
            "Kernel size has to be odd for this function to work properly. Current Value is %d." % kernel_size)

    return (int((output_shape * stride - stride + kernel_size - input_shape + (kernel_size - 1) * (dilation - 1)) / 2))

最后这是我的pytorch模型创建的模型摘要

model(
  (encoder): Sequential(
    (0): Sequential(
      (0): Conv1d(1, 5000, kernel_size=(7,), stride=(1,), padding=(3,))
      (1): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU()
      (3): Conv1d(5000, 5000, kernel_size=(7,), stride=(1,), padding=(3,))
      (4): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (5): ReLU()
      (6): MaxPool1d(kernel_size=8, stride=4, padding=-1872, dilation=1, ceil_mode=False)
      (7): Dropout(p=0.1)
    )
    (1): Sequential(
      (0): Conv1d(1250, 1250, kernel_size=(7,), stride=(1,), padding=(3,))
      (1): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU()
      (3): Conv1d(1250, 1250, kernel_size=(7,), stride=(1,), padding=(3,))
      (4): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (5): ReLU()
      (6): MaxPool1d(kernel_size=8, stride=4, padding=-465, dilation=1, ceil_mode=False)
      (7): Dropout(p=0.1)
    )
    (2): Sequential(
      (0): Conv1d(312, 312, kernel_size=(7,), stride=(1,), padding=(3,))
      (1): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU()
      (3): Conv1d(312, 312, kernel_size=(7,), stride=(1,), padding=(3,))
      (4): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (5): ReLU()
      (6): MaxPool1d(kernel_size=8, stride=4, padding=-114, dilation=1, ceil_mode=False)
      (7): Dropout(p=0.1)
    )
    (3): Sequential(
      (0): Conv1d(78, 78, kernel_size=(7,), stride=(1,), padding=(3,))
      (1): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU()
      (3): Conv1d(78, 78, kernel_size=(7,), stride=(1,), padding=(3,))
      (4): BatchNorm1d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (5): ReLU()
      (6): MaxPool1d(kernel_size=8, stride=4, padding=-26, dilation=1, ceil_mode=False)
      (7): Dropout(p=0.1)
    )
  )
  (decoder): Sequential(
    (0): Linear(in_features=5120, out_features=512, bias=True)
    (1): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
    (3): Dropout(p=0.1)
    (4): Linear(in_features=512, out_features=512, bias=True)
    (5): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (6): ReLU()
    (7): Dropout(p=0.1)
    (8): Linear(in_features=512, out_features=101, bias=True)
    (9): Softmax()
  )
)

1 个答案:

答案 0 :(得分:0)

我认为您的根本问题是将in_channelsout_channels与Keras形状混淆。让我们以第一个卷积层为例。在Keras中,您可以:

Conv1D(filters=32, kernel_size=8, input_shape=(5000,1), strides=1, padding='same')

等效的PyTorch应该是(像您一样将内核大小更改为7,我们稍后会再讨论):

nn.Conv1d(in_channels=1, out_channels=32, kernel_size=7, stride=1, padding=3) # different kernel size

请注意,您无需给出pytorch输入序列的形状。现在,让我们看看它与您所做的比较:

nn.Conv1d(in_channels=1, out_channels=5000, kernel_size=7, stride=1, padding=0) # note padding

您刚刚创建了一个庞大的网络。正确的实现会产生[b, 32, 5000]的输出,其中b是批处理大小,而您的输出是[b, 5000, 5000]

希望此示例可帮助您纠正其余的实现。

最后,关于在pytorch中复制same填充的一些说明。即使内核大小相同,要保留输入的大小,也需要非对称填充。我认为创建图层时可能不可用。我看到您改为将内核大小更改为7,但是实际上可以使用原始内核大小8来完成。您可以在forward()函数中使用padding创建所需的非对称填充。

layer = nn.Conv1d(in_channels=1, out_channels=32, kernel_size=8, stride=1, padding=0) # layer without padding
x = torch.empty(1, 1, 5000).normal_()  # random input

# forward run
x_padded = torch.nn.functional.pad(x, (3,4))
y = layer(x_padded).shape
print(y.shape)  # torch.Size([1, 32, 5000])