python-3.x - 将 .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 模型的初始权重的结构,发现它们如下:
- 第 0 层:无权重
- 第 1 层:(8、8、4、32)
- 第 2 层:(4、4、32、64)
- 第 3 层:(4,4,64,64)
- 第 4 层:无权重
- 第 5 层:(3136,512)
- 第 6 层:(9,512)
然后,我检查了我尝试导入的 .npz 模型中的权重,发现它们如下:
- 第 0 层:(32,4,8,8)
- 第 1 层:(64,32,4,4)
- 第 2 层:(64,64,4,4)
- 第 3 层:(512,3136)
- 第 4 层:(9,512)
因此,我使用 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 代码库,似乎不可能。
任何帮助,将不胜感激。
解决方案
我是 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 的顺序。
推荐阅读
- java - 如何仅加载配置文件特定的属性文件并忽略默认的 application.properties?
- python - Python 多处理:如何测量工作人员中子进程的运行时间?
- firebase - 从 Observable 的动态数组中将 Observables 组合成单个 Observable?
- azure - 如何导出当前的 Azure 应用服务证书并导入到不同的订阅
- javascript - 如何应用正则表达式将字符串转换为驼峰式大小写并从字符串 Javascript 中删除所有特殊字符
- node.js - 创建或查询与联系人关联的 Dynamics 365 任务
- kubernetes - k8s集群中pod的外部IP是多少?
- python - 如何在 Django 中发出安全的 URL?
- python - 如何将嵌套列表中的元组转换为列表?
- javascript - 数组中的字符串不添加其他字符