# パッケージのインポート from game import State, random_action, alpha_beta_action, mcts_action from pv_mcts import pv_mcts_action from tensorflow.keras.models import load_model from tensorflow.keras import backend as K from pathlib import Path import numpy as np
# パッケージのインポート from game import State from pv_mcts import pv_mcts_action from tensorflow.keras.models import load_model from tensorflow.keras import backend as K from pathlib import Path from shutil import copy import numpy as np
# パッケージのインポート from dual_network import DN_INPUT_SHAPE from tensorflow.keras.callbacks import LearningRateScheduler, LambdaCallback from tensorflow.keras.models import load_model from tensorflow.keras import backend as K from pathlib import Path import numpy as np import pickle
パラメータを定義します。RN_EPOCHSは学習回数を表します。
train_network.py
1 2
# パラメータの準備 RN_EPOCHS = 100# 学習回数
セルフデータ部で保存した学習データ(data/*.history)を読み込む関数を定義します。
train_network.py
1 2 3 4 5
# 学習データの読み込み defload_data(): history_path = sorted(Path('./data').glob('*.history'))[-1] with history_path.open(mode='rb') as f: return pickle.load(f)
# パッケージのインポート from game import State from pv_mcts import pv_mcts_scores from dual_network import DN_OUTPUT_SIZE from datetime import datetime from tensorflow.keras.models import load_model from tensorflow.keras import backend as K from pathlib import Path import numpy as np import pickle import os
# パッケージのインポート from game import State from dual_network import DN_INPUT_SHAPE from math import sqrt from tensorflow.keras.models import load_model from pathlib import Path import numpy as np
# 推論 defpredict(model, state): # 推論のための入力テ゛ータのシェイフ゜の変換 a, b, c = DN_INPUT_SHAPE x = np.array([state.pieces, state.enemy_pieces]) x = x.reshape(c, a, b).transpose(1, 2, 0).reshape(1, a, b, c)
# パッケージのインポート from tensorflow.keras.layers import Activation, Add, BatchNormalization, Conv2D, Dense, GlobalAveragePooling2D, Input from tensorflow.keras.models import Model from tensorflow.keras.regularizers import l2 from tensorflow.keras import backend as K import os
# 残差ブロックの作成 defresidual_block(): deff(x): sc = x x = conv(DN_FILTERS)(x) x = BatchNormalization()(x) x = Activation('relu')(x) x = conv(DN_FILTERS)(x) x = BatchNormalization()(x) x = Add()([x, sc]) x = Activation('relu')(x) return x return f
# 石の数の取得 defpiece_count(self, pieces): count = 0 for i in pieces: if i == 1: count += 1 return count
# 負けかどうか defis_lose(self): # 3並びかどうか defis_comp(x, y, dx, dy): for k inrange(3): if y < 0or2 < y or x < 0or2 < x or \ self.enemy_pieces[x+y*3] == 0: returnFalse x, y = x+dx, y+dy returnTrue
# 負けかどうか if is_comp(0, 0, 1, 1) or is_comp(0, 2, 1, -1): returnTrue for i inrange(3): if is_comp(0, i, 1, 0) or is_comp(i, 0, 0, 1): returnTrue returnFalse
# 評価 defevaluate(self): # ゲーム終了時 if self.state.is_done(): # 勝敗結果で価値を取得 value = -1if self.state.is_lose() else0# 負けは-1、引き分けは0
# 累計価値と試行回数の更新 self.w += value self.n += 1 return value
# 子ノードが存在しない時 ifnot self.child_nodes: # プレイアウトで価値を取得 value = playout(self.state)
# 累計価値と試行回数の更新 self.w += value self.n += 1
# 子ノードの展開 if self.n == 10: self.expand() return value
# 子ノードが存在する時 else: # UCB1が最大の子ノードの評価で価値を取得 value = -self.next_child_node().evaluate()
# 累計価値と試行回数の更新 self.w += value self.n += 1 return value
# 子ノードの展開 defexpand(self): legal_actions = self.state.legal_actions() self.child_nodes = [] for action in legal_actions: self.child_nodes.append(node(self.state.next(action)))
# UCB1が最大の子ノードを取得 defnext_child_node(self): # 試行回数nが0の子ノードを返す for child_node in self.child_nodes: if child_node.n == 0: return child_node
# UCB1の計算 t = 0 for c in self.child_nodes: t += c.n ucb1_values = [] for child_node in self.child_nodes: ucb1_values.append(-child_node.w/child_node.n+2*(2*math.log(t)/child_node.n)**0.5)
# ルートノードを100回評価 for _ inrange(100): root_node.evaluate()
# 試行回数の最大値を持つ行動を返す legal_actions = state.legal_actions() n_list = [] for c in root_node.child_nodes: n_list.append(c.n) return legal_actions[argmax(n_list)]
動作確認のためのコードを実装します。ランダムとランダムで対戦するコードです。
game.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# 動作確認 if __name__ == '__main__': # 状態の生成 state = State()
# ゲーム終了までのループ whileTrue: # ゲーム終了時 if state.is_done(): break
# 次の状態の取得 state = state.next(random_action(state))
# 石の数の取得 defpiece_count(self, pieces): count = 0 for i in pieces: if i == 1: count += 1 return count
# 負けかどうか defis_lose(self): # 3並びかどうか defis_comp(x, y, dx, dy): for k inrange(3): if y < 0or2 < y or x < 0or2 < x or \ self.enemy_pieces[x+y*3] == 0: returnFalse x, y = x+dx, y+dy returnTrue
# 負けかどうか if is_comp(0, 0, 1, 1) or is_comp(0, 2, 1, -1): returnTrue for i inrange(3): if is_comp(0, i, 1, 0) or is_comp(i, 0, 0, 1): returnTrue returnFalse
# 局面の価値の計算 defevaluate(self): # ゲーム終了時 if self.state.is_done(): # 勝敗結果で価値を取得 value = -1if self.state.is_lose() else0# 負けは-1、引き分けは0
# 累計価値と試行回数の更新 self.w += value self.n += 1 return value
# 子ノードが存在しない時 ifnot self.child_nodes: # プレイアウトで価値を取得 value = playout(self.state)
# 累計価値と試行回数の更新 self.w += value self.n += 1
# 子ノードの展開 if self.n == 10: self.expand() return value
# 子ノードが存在する時 else: # UCB1が最大の子ノードの評価で価値を取得 value = -self.next_child_node().evaluate()
# 累計価値と試行回数の更新 self.w += value self.n += 1 return value
# 子ノードの展開 defexpand(self): legal_actions = self.state.legal_actions() self.child_nodes = [] for action in legal_actions: self.child_nodes.append(Node(self.state.next(action)))
# UCB1が最大の子ノードの取得 defnext_child_node(self): # 試行回数が0の子ノードを返す for child_node in self.child_nodes: if child_node.n == 0: return child_node
# UCB1の計算 t = 0 for c in self.child_nodes: t += c.n ucb1_values = [] for child_node in self.child_nodes: ucb1_values.append(-child_node.w/child_node.n+(2*math.log(t)/child_node.n)**0.5)
# 100回のシミュレーションを実行 for _ inrange(100): root_node.evaluate()
# 試行回数の最大値を持つ行動を返す legal_actions = state.legal_actions() n_list = [] for c in root_node.child_nodes: n_list.append(c.n) return legal_actions[argmax(n_list)]
# 石の数の取得 defpiece_count(self, pieces): count = 0 for i in pieces: if i == 1: count += 1 return count
# 負けかどうか defis_lose(self): # 3並びかどうか defis_comp(x, y, dx, dy): for k inrange(3): if y < 0or2 < y or x < 0or2 < x or \ self.enemy_pieces[x+y*3] == 0: returnFalse x, y = x+dx, y+dy returnTrue
# 負けかどうか if is_comp(0, 0, 1, 1) or is_comp(0, 2, 1, -1): returnTrue for i inrange(3): if is_comp(0, i, 1, 0) or is_comp(i, 0, 0, 1): returnTrue returnFalse
# 石の数の取得 defpiece_count(self, pieces): count = 0 for i in pieces: if i == 1: count += 1 return count
# 負けかどうか defis_lose(self): # 3並びかどうか defis_comp(x, y, dx, dy): for k inrange(3): if y < 0or2 < y or x < 0or2 < x or \ self.enemy_pieces[x+y*3] == 0: returnFalse x, y = x+dx, y+dy returnTrue
# 負けかどうか if is_comp(0, 0, 1, 1) or is_comp(0, 2, 1, -1): returnTrue for i inrange(3): if is_comp(0, i, 1, 0) or is_comp(i, 0, 0, 1): returnTrue returnFalse