首页 > 解决方案 > 将 .npz 模型从 ChainerRL 转换为 Keras 模型,或替代方法?

问题描述

我有一个 DQN 强化学习模型,它是使用 ChainerRL 在 Ms Pacman Atari 游戏环境中的内置 DQN 实验进行训练的,我们将此文件称为 model.npz。我有一些用 Keras 编写的分析软件,它使用 Keras 网络并将模型加载到该网络中。

我无法让从 ChainerRL 导出的 .npz 与 Keras 网络配合得很好。

我已经想出了如何从 .npz 文件中加载权重。我想我想出了如何确保 Keras 模型在内核大小、步幅和激活方面与 Chainer RL 模型相匹配。

这是调用在 ChainerRL 中构建网络的函数的代码:

return links.Sequence(
        links.NatureDQNHead(),
        L.Linear(512, n_actions),
        DiscreteActionValue)

被此调用并构建 Chainer DQN 网络的代码是:

class NatureDQNHead(chainer.ChainList):
"""DQN's head (Nature version)"""

def __init__(self, n_input_channels=4, n_output_channels=512,
             activation=F.relu, bias=0.1):
    self.n_input_channels = n_input_channels
    self.activation = activation
    self.n_output_channels = n_output_channels

    layers = [
        #L.Convolution2D(n_input_channels, out_channel=32, ksize=8, stride=4, pad=0, nobias=False, initialW=None, initial_bias=bias, *, dilate=1, groups=1),
        L.Convolution2D(n_input_channels, 32, 8, stride=4,
                        initial_bias=bias),
        #L.Convolution2D(n_input_channels=32, out_channel=64, ksize=4, stride=2, pad=0, nobias=False, initialW=None, initial_bias=bias, *, dilate=1, groups=1),
        L.Convolution2D(32, 64, 4, stride=2, initial_bias=bias),
        #L.Convolution2D(n_input_channels=64, out_channel=64, ksize=3, stride=1, pad=0, nobias=False, initialW=None, initial_bias=bias, *, dilate=1, groups=1),
        L.Convolution2D(64, 64, 3, stride=1, initial_bias=bias),
        #L.Convolution2D(in_size=3136, out_size=n_output_channels, nobias=False, initialW=None, initial_bias=bias),
        L.Linear(3136, n_output_channels, initial_bias=bias),
    ]

    super(NatureDQNHead, self).__init__(*layers)

def __call__(self, state):
    h = state
    for layer in self:
        h = self.activation(layer(h))
    return h

所以我写了下面的 Keras 代码来在 Keras 中构建一个等价的网络:

# Keras Model
hidden = 512
#bias initializer to match the chainerRL one
initial_bias = tf.keras.initializers.Constant(0.1)

#matches default "channels_last" data format for Keras layers
inputs = Input(shape=(84, 84, 4))

#First call to Conv2D including all defaults for easy reference
x = Conv2D(filters=32, kernel_size=(8, 8), strides=4, padding='valid', data_format=None, dilation_rate=(1, 1), activation='relu', use_bias=True, kernel_initializer='glorot_uniform', bias_initializer=initial_bias, kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, name='deepq/q_func/convnet/Conv')(inputs)
x1 = Conv2D(filters=64, kernel_size=(4, 4), strides=2, activation='relu', padding='valid', bias_initializer=initial_bias, name='deepq/q_func/convnet/Conv_1')(x)
x2 = Conv2D(filters=64, kernel_size=(3, 3), strides=1, activation='relu', padding='valid', bias_initializer=initial_bias, name='deepq/q_func/convnet/Conv_2')(x1)
#Flatten for move to linear layers
conv_out = Flatten()(x2)

action_out = Dense(hidden, activation='relu', name='deepq/q_func/action_value/fully_connected')(conv_out)
action_scores = Dense(units = 9, name='deepq/q_func/action_value/fully_connected_1', activation='linear', use_bias=True, kernel_initializer="glorot_uniform", bias_initializer=initial_bias, kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None,)(action_out)  # num_actions in {4, .., 18}

#Now create model using the above-defined layers
modelArchitecture = Model(inputs, action_scores)

我检查了 Keras 模型的初始权重的结构,发现它们如下:

然后,我检查了我尝试导入的 .npz 模型中的权重,发现它们如下:

因此,我使用 numpy.reshape 从 model.npz 的第 0 层重塑权重,并将它们应用到 Keras 网络的第 1 层。我对第 1 层的 model.npz 权重做了同样的事情,并将它们应用到 Keras 网络的第 2 层。然后,我从 model.npz 的第 2 层重塑权重,并将它们应用到 Keras 网络的第 3 层。我从 model.npz 转置了第 3 层的权重,并将它们应用到 Keras 模型的第 5 层。最后,我将 model.npz 第 4 层的权重转置并应用到 Keras 模型的第 6 层。

我将模型保存为 .H5 格式,然后尝试在 Ms Pacman Atari 环境中的评估代码上运行它,并制作了一个视频。当我这样做时,Pacman 会沿着完全相同的短路径,正面朝墙撞上,然后继续尝试穿过墙,直到被鬼杀死。

因此,我在 Chainer DQN 网络和 Keras DQN 网络之间的转换似乎做错了什么。我不确定他们是否以不同的顺序处理颜色或其他什么?

我还尝试将 ChainerRL model.npz 文件导出到 ONNX,但出现了几个错误,以至于如果不重写大量 ChainerRL 代码库,似乎不可能。

任何帮助,将不胜感激。

标签: python-3.xkerasneural-networkreinforcement-learningchainer

解决方案


我是 ChainerRL 的作者。我没有使用 Keras 的经验,但显然 Chainer 和 Keras 之间的权重参数格式似乎不同。您应该检查每个深度学习框架的权重参数的每个维度的含义。在Chainer中,您可以在文档(https://docs.chainer.org/en/stable/reference/generated/chainer.functions.convolution_2d.html#chainer.functions.convolution_2dConvolution2D )中找到,存储权重参数作为(c_O,c_I,h_K,w_K)。

一旦你找到了每个维度的含义,我想你需要的总是numpy.transpose,而不是numpy.reshape重新排序维度以匹配 Keras 的顺序。


推荐阅读