ぷよぷよプログラミングAI学習システムは、中高生の自己調整学習に向けて開発されました。
どうやって、Chromebookで、10分で、素敵な人工知能を作れるのでしょうか?
秘密は、3つ。
1 jupyter liteで、webクライアントがpythonコードを実行
2 超軽量な機械学習フレームワークdezeroを採用
3 ぷよぷよのstageとactionがコンパクト
Github&X
ぷよぷよプログラミングAI学習用まとめ
チュートリアルまとめ
Step10 Agent
10 Agentは特徴量抽出が大切。
Agentとbrain(model)の使い分けてです。
modelには、できる限り処理された情報のみを入れたほうが、効率よく学習が進みます。また、actionが存在するかどうかの処理や、actionが有効かどうかの処理などは、やめたほうがいい。また、データを管理して学習を効率よく進める部分なども、やめたほうがいい。そのような、入力と出力のルール化みたいところを、ラップでくるんで行うのがAgentです。
action = agent(state)
主に3つの機能を有するべきです。
- 入力データから特徴量を抽出する機能
- 出力データの形式を整える機能
- 学習を効率よく進める機能
10.1 コードを見ていきます。
import copy
import numpy as np
import dezero_emb as dezero
class DQNAgent:
def __init__(self):
self.epsilon = CFG_ML.initial_epsilon
self.action_size = 2
self.replay_buffer = ReplayBuffer(CFG_ML.buffer_size, CFG_ML.batch_size)
self.qnet = DQNet()
self.qnet_target = DQNet()
self.optimizer = dezero.optimizers.Adam(CFG_ML.lr)
self.optimizer.setup(self.qnet)
def __call__(self, board, puyo):
action_list = utils.create_action_list(board)
next_boards = []
next_reward =[]
action =(2, 1)
if len(action_list):
for action in action_list:
next_board, reward, done = utils.next_board(board, puyo, action)
if not done:
next_boards.append(next_board)
next_reward.append(reward)
next_boards = np.stack(next_boards)
predictions = self.eval2(next_boards)
next_reward =np.array(next_reward)[:, np.newaxis]
predictions += dezero.Variable(next_reward)
index = predictions.data.argmax()
action = action_list[index]
return action
def boardtostate(self, board):
cont_b = 2 ** np.arange(CFG.Width,dtype=np.int32)
b1 = np.zeros(CFG.Height * CFG.Width,dtype = np.int32).reshape(CFG.Height , CFG.Width)
b1[board == 1] = 1
b2 = np.zeros(CFG.Height * CFG.Width,dtype = np.int32).reshape(CFG.Height , CFG.Width)
b2[board == 2] = 1
b3 = np.zeros(CFG.Height * CFG.Width,dtype = np.int32).reshape(CFG.Height , CFG.Width)
b3[board == 3] = 1
b4 = np.zeros(CFG.Height * CFG.Width,dtype = np.int32).reshape(CFG.Height , CFG.Width)
b4[board == 4] = 1
board_list = np.concatenate([b1,b2,b3,b4])
state = board_list.dot(cont_b)
return state
def eval(self, board):
state = self.boardtostate(board)
return self.qnet_target(state)
def eval2(self, boards):
states = []
for i in range(boards.shape[0]):
state = self.boardtostate(boards[i])
states.append(state)
states = np.stack(states)
return self.qnet_target(states)
def update(self, board, action, reward, next_board, done):
state = self.boardtostate(board)
next_state = self.boardtostate(next_board)
self.replay_buffer.add(state, action, reward, next_state, done)
if not done:
return
if len(self.replay_buffer) < CFG_ML.batch_size:
return
state, action, reward, next_state, done = self.replay_buffer.get_batch()
qs = self.qnet(state)
next_qs = self.qnet_target(next_state)
reward =reward[:,np.newaxis]
done =done[:,np.newaxis]
target = reward + (1 - done) * CFG_ML.gamma * next_qs
self.qnet.cleargrads()
loss = dezero.F.mean_squared_error(qs, target)
loss.backward()
self.optimizer.update()
def sync_qnet(self):
self.qnet_target = copy.deepcopy(self.qnet)
def save_model(self,filename):
self.qnet.save_weights(filename)
def load_model(self,filename):
self.qnet.load_weights(filename)
self.qnet_target.load_weights(filename)
10.2 init
初期化には、agentが持つデータが定義されます。4つあります。
- replay_buffer
- DQNet : 訓練対象
- target_DQNet : 評価用
- optimizer : lossは関数を使うので、optimizerだけです。
2つのmodelの使い分けですが、評価用のmodelで計算したpredictionsを使って、訓練用のmodelを学習させます。訓練後に、sync_qnetで同期します。
10.3 board to state
- cont_bは、boardの横1行のデータを2進法でビット化するために使います。これで、12行6列の72個のデータを、12個に圧縮して特徴量にします。4色あるので、288個のデータが、48個になります。
- np.concatenate([b1,b2,b3,b4]) : 4色の2次元データを連結しています。
- board_list.dot(cont_b) : board_list と cont_b の行列積を計算します。
10.3 call
agent()のように呼び出されたときに、この関数が動きます。
- action_list から next_board を計算して next_statesを作ります。fallblockは、blockを落とす場所をすれば、必ず決まった挙動をするゲームなので、計算可能です。計算ができないゲームでは、この手法は使えません。
- next_statesから、Qを推測します(predictions)。predictionsにrewardを加えて、一番大きいものを選択します。
10.4 update
- データをreplay bufferに入れていきます。
- done(終了)で、バッチデータから学習をします。
- qnet.cleargrads : 累積しているgradを0にします。
- loss.backward : 逆伝播させます。
- optimizer.update : パラメータに反映させます。