如何运行
- 安装依赖
pip install keras
pip install pygame
pip install scikit-image
pip install h5py
作者使用的是theano
训练的,训练好的模型文件要使用theano
作为Keras
的后端才能调用,在配置文件~/.keras/keras.json
中(没有可创建)确认/修改backend
为theano
(如果没有安装tensorflow
[Keras
的另一可选后端]好像就不用管了),配置文件样式下文中卷积神经网络小节的补充里有。
要使用theano
,我们还需要安装OpenBLAS。直接下载源码并解压,cd
进目录,然后
sudo apt-get install gfortran
make FC=gfortran
sudo make PREFIX=/usr/local install
- 下载源码并运行
git clone https://github.com/yanpanlau/Keras-FlappyBird.git
cd Keras-FlappyBird
python qlearn.py -m "Run"
我下载时目录中game/wrapped_flappy_bird.py文件的第144行,FPSCLOCK.tick(FPS)
语句处缩进有点问题,删去现有缩进,打8个空格就好了,没问题就不用管了。
- vmware虚拟机Ubuntu16.04+python3+只使用CPU+theano运行:
- 如果想重新训练神经网络,删除**
model.h5
**文件然后运行命令qlearn.py -m "Train"
。
源码分析
- 游戏输入及返回图像
import wrapped_flappy_bird as game
x_t1_colored, r_t, terminal = game_state.frame_step(a_t)
直接使用flappybird python版本的接口。
输入为a_t((1, 0)
代表不跳,(0,1)
代表跳)。
返回值为下一帧图像x_t1_colored和奖励reward(+0.1
表示存活,+1
表示通过管道,-1
表示死亡),奖励被控制在[-1,+1]
来提高稳定性。terminal 是一个布尔值表示游戏是否结束。
奖励函数在game/wrapped_flappy_bird.py
中的
def frame_step(self, input_actions)
方法中修改。
为什么直接将游戏图像输入处理呢?我一开始没转过弯,其实图像中包含了全部的信息(声音信息在多数游戏里只是辅助,不影响游戏),而人在玩游戏时也是接受输入的图像信息,然后决策输出相应的操作指令。这里其实就是在模拟人的反馈过程,将这一过程描述为一个非线性函数,而该非线性函数我们将使用卷积神经网络来表达,大体上卷积实现了对图像特征的提取,神经网络实现了从特征到操作指令的转换。
- 图像预处理
要素:
1. 将图片转换为灰阶
2. 裁剪图片尺寸到80x80像素
3. 每次堆积4帧,一起馈入神经网络。相当于一次输入一张'四通道'的图像。
(为什么要将4帧堆在一起?这是一种方法,为了让模型能推断出小鸟的速度信息。)
x_t1 = skimage.color.rgb2gray(x_t1_colored)
x_t1 = skimage.transform.resize(x_t1,(80,80))
x_t1 = skimage.exposure.rescale_intensity(x_t1, out_range=(0, 255)) # 调整亮度
#
x_t1 = x_t1.reshape(1, 1, x_t1.shape[0], x_t1.shape[1])
s_t1 = np.append(x_t1, s_t[:, :3, :, :], axis=1)
# axis=1 意味着在第二维上添加
x_t1是一个(1x1x80x80) 的单帧,s_t1是4帧的叠加,形状为(1x4x80x80)。输入设计为 (1x4x80x80)而不是(4x80x80)是为了Keras考虑。
补充
rescale_intensity
- 卷积神经网络
现在,将预处理后的图像输入神经网络。
def buildmodel():
print("开始建模")
model = Sequential()
model.add(Convolution2D(32, 8, 8, subsample=(4,4),init=lambda shape, name: normal(shape, scale=0.01, name=name), border_mode='same', dim_ordering='th', input_shape=(img_channels,img_rows,img_cols)))
model.add(Activation('relu'))
model.add(Convolution2D(64, 4, 4, subsample=(2,2),init=lambda shape, name: normal(shape, scale=0.01, name=name), border_mode='same', dim_ordering='th'))
mod