做了这么。。。。。终于到达这一步了。
GitHub上源代码
上一篇我们用简单的全连接神经网络实现了DQN玩儿了一个简单的游戏,今天我们要用一个复杂的神经网络来玩儿一个复杂的游戏,SpaceInvaders-v0,就玩这个游戏吧,看起来很棒的样子,随便选的。
在这个游戏中observaction是一个屏幕RGB的图片,shape是(210,160,3) = 100800个数据正好试一下卷积神经网络,action 6个中4是发送子弹 2、3分别是左右,reward就是你打没打死那个外星人所得到的奖励,就是图片上的分数,reward分别是5,10,15,20,25,30,每往上增加一层的外星人加5分,然后时不时的有一个紫色的外星人出现,打中他加200分,这里可以考虑做不做归一化处理,我这里先不做归一化处理直接使用它的reward。然后我看国外的论文中也有用opencv先做一个图像处理的,我这里也先不做了就用原图。
看来我还是太小看这个神经网络的训练,还有太高估我渣渣电脑的能力了,居然还想不做图像预处理直接跑。。。。。。根本跑不动啊。。。。我还是老老实实加opencv预处理吧,还有opencv比较熟悉。
所以使用这个教程安装opencv,在这个教程中我没有进入Windows的终端,而是进入anaconda prompt进行安装的,要不然找不到pip命令。
做灰度化处理后的效果:
加了opencv处理后还是很慢,但是比之前好多了
接下来还需要继续优化神经网络,让训练的速度变快。
真正遇到大数据做机器学习的时候就知道自己的电脑有多差了。。。。。。。可优化后的学习速度都需要1.1s左右,导致整个游戏完全没法看,所以我开了一个线程来控制是否学习,也就是说关闭学习的时候能从游戏界面中看出学习的成果,但还是太慢了。。。。。。。所以接下来可能在网上租一个服务器,或者去实验室用实验室的服务器来跑一跑看看效果。
接下来看看我搭的神经网络是什么样的,看起来很大的样子,其实说到底也就是四层,前两层是卷积神经网络,配备了pooling减少数据损失,然后加上两层全连接网络,本来这个地方是要放LSTM的,但是我的电脑更跑不动了。。。。。。所以先用全连接。等我找到好的服务器再修改。
这个是搭建两个神经网络的代码,Keras搭建的,真的超级方便。(详见注释)
def _build_net(self):
# ------------------ 建造估计层 ------------------
# 因为神经网络在这个地方只是用来输出不同动作对应的Q值,最后的决策是用Q表的选择来做的
# 所以其实这里的神经网络可以看做是一个线性的,也就是通过不同的输入有不同的输出,而不是确定类别的几个输出
# 这里我们先按照上一个例子造一个两层每层单个神经元的神经网络
self.model_eval = Sequential([
# 输入第一层是一个二维卷积层(100, 80, 1)
Convolution2D( # 就是Conv2D层
batch_input_shape=(None, self.observation_shape[0], self.observation_shape[1],
self.observation_shape[2]),
filters=15, # 多少个滤波器 卷积核的数目(即输出的维度)
kernel_size=5, # 卷积核的宽度和长度。如为单个整数,则表示在各个空间维度的相同长度。
strides=1, # 每次滑动大小
padding='same', # Padding 的方法也就是过滤后数据xy大小是否和之前的一样
data_format='channels_last', # 表示图像通道维的位置,这里rgb图像是最后一维表示通道
),
Activation('relu'),
# 输出(100, 80, 15)
# Pooling layer 1 (max pooling) output shape (50, 40, 15)
MaxPooling2D(
pool_size=2, # 池化窗口大小
strides=2, # 下采样因子
padding='same', # Padding method
data_format='channels_last',
),
# output(50, 40, 30)
Convolution2D(30, 5, strides=1, padding='same', data_format='channels_last'),
Activation('relu'),
# (10, 8, 30)
MaxPooling2D(5, 5, 'same', data_format='channels_first'),
# (10, 8, 30)
Flatten(),
# LSTM(
# units=1024,
# return_sequences=True, # True: output at all steps. False: output as last step.
# stateful=True, # True: the final state of batch1 is feed into the initial state of batch2
# ),
Dense(512),
Activation('relu'),
Dense(self.n_actions),
])
# 选择rms优化器,输入学习率参数
rmsprop = RMSprop(lr=self.lr, rho=0.9, epsilon=1e-08, decay=0.0)
self.model_eval.compile(loss='mse',
optimizer=rmsprop,
metrics=['accuracy'])
# ------------------ 构建目标神经网络 ------------------
# 目标神经网络的架构必须和估计神经网络一样,但是不需要计算损失函数
self.model_target = Sequential([
Convolution2D( # 就是Conv2D层
batch_input_shape=(None, self.observation_shape[0], self.observation_shape[1],
self.observation_shape[2]),
filters=15, # 多少个滤波器 卷积核的数目(即输出的维度)
kernel_size=5, # 卷积核的宽度和长度。如为单个整数,则表示在各个空间维度的相同长度。
strides=1, # 每次滑动大小
padding='same', # Padding 的方法也就是过滤后数据xy大小是否和之前的一样
data_format='channels_last', # 表示图像通道维的位置,这里rgb图像是最后一维表示通道
),
Activation('relu'),
# 输出(210, 160, 30)
# Pooling layer 1 (max pooling) output shape (105, 80, 30)
MaxPooling2D(
pool_size=2, # 池化窗口大小
strides=2, # 下采样因子
padding='same', # Padding method
data_format='channels_last',
),
# output(105, 80, 60)
Convolution2D(30, 5, strides=1, padding='same', data_format='channels_last'),
Activation('relu'),
# (21, 16, 60)
MaxPooling2D(5, 5, 'same', data_format='channels_first'),
# 21 * 16 * 60 = 20160
Flatten(),
# LSTM(
# units=1024,
# return_sequences=True, # True: output at all steps. False: output as last step.
# stateful=True, # True: the final state of batch1 is feed into the initial state of batch2
# ),
Dense(512),
Activation('relu'),
Dense(self.n_actions),
])
我准备用一下午时间跑一跑,看看会不会有效果。