在之前的文章中,我們做了如下工作:
- 如何設計一個類flappy-bird小遊戲:【python實戰】使用pygame寫一個flappy-bird類小遊戲 | 設計思路+項目結構+代碼詳解|新手向
- DFS 算法是怎麼回事,我是怎麼應用於該小遊戲的:【深度優先搜索】一個實例+兩張動圖徹底理解DFS|DFS與BFS的區別|用DFS自動控制我們的小遊戲
- BFS 算法是怎麼回事,我是怎麼應用於該小遊戲的:【廣度優先搜索】一個實例+兩張動圖徹底理解BFS|思路+代碼詳解|用DFS自動控制我們的小遊戲
- 強化學習爲什麼有用?其基本原理:無需公式或代碼,用生活實例談談AI自動控制技術“強化學習”算法框架
本節開始,我們將討論如何用深度強化學習實現小遊戲的自動控制。
構造一個簡單的卷積神經網絡,實現 DQN
本文涉及的 .py
文件有:
DQN_train/gym_warpper.py
DQN_train/dqn_train.py
requirements
tianshou
pytorch > 1.40
gym
openCV
封裝交互環境
強化學習算法有效,很大程度上取決於獎勵機制設計的是否合理。
事件 | 獎勵 |
---|---|
動作後碰撞障礙物、牆壁 | -1 |
動作後無事發生 | 0.1 |
動作後得分 | 1 |
封裝代碼在 gym_wrapper.py 中,使用類 AmazingBrickEnv
。
強化學習機制與神經網絡的構建
我設計的機制爲:
- 每 2 幀進行一次動作決策;
- 狀態的描述變量爲 2 幀的圖像。
對於每幀的圖像處理如下。
# 首先把圖像轉換成 RGB 矩陣
pygame.surfarray.array3d(pygame.display.get_surface())
# 使用 openCV 將 RGB 矩陣矩陣轉換成 100*100 的灰度0-1矩陣
x_t = cv2.cvtColor(cv2.resize(obs, (100, 100)), cv2.COLOR_BGR2GRAY)
最後使用 np.stack()
將兩幀數據合併,我們就得到了一個 2 通道的圖像矩陣數據。
卷積神經網絡的構建
class Net(nn.Module):
def __init__(self):
super().__init__()
# nn.Conv2d(通道數, 輸出通道數, 卷積核大小, 步長)
self.conv1 = nn.Conv2d(2, 32, 8, 4, padding=1)
self.conv2 = nn.Conv2d(32, 64, 4, 2, padding=1)
self.conv3 = nn.Conv2d(64, 64, 3, 1, padding=1)
self.fc1 = nn.Linear(64, 64)
self.fc2 = nn.Linear(64, 3)
def forward(self, obs, state=None, info={}):
if not isinstance(obs, torch.Tensor):
obs = torch.tensor(obs, dtype=torch.float)
# turn NHWC to NCHW
obs = obs.permute(0, 3, 1, 2)
x = F.max_pool2d(F.relu(self.conv1(obs)), 2)
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = F.max_pool2d(F.relu(self.conv3(x)), 2)
x = x.view(-1, 64)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x, state
神經網絡解構如上述代碼。
卷積訓練過程如上圖右。
DQN 構建
import os.path as osp
import sys
dirname = osp.dirname(__file__)
path = osp.join(dirname, '..')
sys.path.append(path)
from amazing_brick.game.wrapped_amazing_brick import GameState
from amazing_brick.game.amazing_brick_utils import CONST
from DQN_train.gym_wrapper import AmazingBrickEnv
# 使用了清華開源深度強化學習框架
import tianshou as ts
import torch, numpy as np
from torch import nn
import torch.nn.functional as F
train_env = AmazingBrickEnv(fps=1000)
test_env = AmazingBrickEnv(fps=1000)
state_shape = (80, 80, 4)
action_shape = 1
net = Net()
optim = torch.optim.Adam(net.parameters(), lr=1e-3)
policy = ts.policy.DQNPolicy(net, optim,
discount_factor=0.9, estimation_step=3,
use_target_network=True, target_update_freq=320)
train_collector = ts.data.Collector(policy, train_env, ts.data.ReplayBuffer(size=200))
test_collector = ts.data.Collector(policy, test_env)
result = ts.trainer.offpolicy_trainer(
policy, train_collector, test_collector,
max_epoch=10, step_per_epoch=1000, collect_per_step=10,
episode_per_test=100, batch_size=64,
train_fn=lambda e: policy.set_eps(0.1),
test_fn=lambda e: policy.set_eps(0.05), writer=None)
print(f'Finished training! Use {result["duration"]}')
由於我還沒有開始系統學習 NNs ,不瞭解 CNNs ,因此不是很信任自己建立的這個網絡,沒有投入資源與時間訓練。
下兩節(也是本項目的最後兩節),我們將探討線性網絡解決這個控制問題的,其中將涉及到簡單的建模與獎勵機制設計討論,會很有趣。