実現したいこと
ポケモンのalphazero(モンテカルロ、deeplearning、強化学習)を作っています。エラーを解決してバトルを学習してもらいたいです。
発生している問題・分からないこと
child_nodesに存在しない引数が渡されてしまっている
。ループが止まらない(コメント追記)
エラーメッセージ
error
1(省略、文字数制限のためコメントに記載print文の実行結果など) 2--------------------------------------------------------------------------- 3IndexError Traceback (most recent call last) 4Cell In[18], line 44 5 42 c2hp=player1[0].actual_hp 6 43 result=((c1,-1,-1,c1hp),(c2,-1,-1,c2hp)) 7---> 44 next_action=action1(result) 8 45 winner = battle.get_winner() 9 46 #ゲーム終了時 10 11Cell In[16], line 120, in pv_mcts_action.<locals>.pv_mcts_action(state) 12 119 def pv_mcts_action(state): 13--> 120 scores = pv_mcts_scores(model, state, temperature,winner) 14 121 rng=np.random.default_rng() 15 122 return rng.choice([0,1,2,3], p=scores) 16 17Cell In[16], line 105, in pv_mcts_scores(model, state, temperature, winner) 18 103 # 複数回の評価の実行 19 104 for _ in range(PV_EVALUATE_COUNT): 20--> 105 root_node.evaluate() 21 107 # 合法手の確率分布 22 108 scores = nodes_to_scores(root_node.child_nodes) 23 24Cell In[16], line 67, in pv_mcts_scores.<locals>.Node.evaluate(self) 25 62 return value 26 64 # 子ノードが存在する時 27 65 else: 28 66 # アーク評価値が最大の子ノードの評価で価値を取得 29---> 67 value = self.next_child_node().evaluate() 30 69 # 累計価値と試行回数の更新 31 70 self.w += value 32 33Cell In[16], line 98, in pv_mcts_scores.<locals>.Node.next_child_node(self) 34 96 print("len(self.child_nodes)",len(self.child_nodes)) 35 97 print("self.child_nodes",self.child_nodes) 36---> 98 return self.child_nodes[a] 37 38IndexError: list index out of range
該当のソースコード
python
1from dual_network import DN_INPUT_SHAPE 2from math import sqrt 3from tensorflow.keras.models import load_model 4from pathlib import Path 5import numpy as np 6import battle 7from battle import Battle 8import pokedex as p 9import moves as m 10 11# パラメータの準備 12PV_EVALUATE_COUNT = 50 # 1推論あたりのシミュレーション回数(本家は1600) 13 14# 推論 15def predict(model, state): 16 # 推論のための入力データのシェイプの変換 17 x=np.array(state) 18 x=x.reshape(1,4,2) 19 20 # 推論 21 y=model.predict(x,batch_size=1) 22 23 # 方策の取得 24 policies=y[0][0:4] 25 26 # 価値の取得 27 value=y[1][0] 28 29 return policies, value 30 31# ノードのリストを試行回数のリストに変換 32def nodes_to_scores(nodes): 33 scores = [] 34 for c in nodes: 35 scores.append(c.n) 36 return scores 37 38# モンテカルロ木探索のスコアの取得 39#def pv_mcts_scores(model, p1_is,p1_mae_action,p1_took_damage,p1_nokorihp,p1_is,p2_mae_action,p2_took_damage,p2_nokorihp, temperature): #stateに8つの状態 40def pv_mcts_scores(model, state, temperature,winner=None): #stateに8つの状態 41# モンテカルロ木探索のノードの定義 42 class Node: 43 player1=[ 44 p.Jolteon([m.BodySlam(),m.DoubleKick(),m.PinMissle(),m.Thunderbolt()]) 45 ] 46 47 player2=[ 48 p.Rhydon([m.Earthquake(), m.RockSlide(), m.Surf(), m.BodySlam()]) 49 ] 50 51 # ノードの初期化 52 def __init__(self, state, p,winner): 53 self.state = state # 状態 54 self.p = p # 方策 55 self.w = 0 # 累計価値 56 self.n = 0 # 試行回数 57 self.winner=winner 58 self.child_nodes = None # 子ノード群 59 (self.p1_is,self.p1_mae_action,self.p1_took_damage,self.p1_nokorihp),(self.p1_is,self.p2_mae_action,self.p2_took_damage,self.p2_nokorihp)=state 60 self.turn=0 61 62 # 局面の価値の計算 63 def evaluate(self): #Battle が入る 64 # ゲーム終了時 65 if self.winner is not None: 66 # 勝敗結果で価値を取得 67 #print("hplen",len(self.p1_nokorihp)) 68 battle=Battle(player1,player2) 69 value = 0 if self.winner == player1 else -1 70 71 # 累計価値と試行回数の更新 72 self.w += value 73 self.n += 1 74 return value 75 76 # 子ノードが存在しない時 77 if not self.child_nodes: 78 # ニューラルネットワークの推論で方策と価値を取得 79 policies, value = predict(model, self.state) 80 81 print("policies",policies) 82 print("value",value) 83 84 # 累計価値と試行回数の更新 85 self.w += value 86 self.n += 1 87 88 89 # 子ノードの展開 90 self.child_nodes = [] 91 a=[6,7,8,9] 92 for action, policy in zip(a, policies): 93 battle=Battle(player1,player2) 94 zyoutai=battle.forward_step(self.p1_nokorihp,self.p2_nokorihp,action) 95 winner = battle.get_winner() 96 self.child_nodes.append(Node(zyoutai, policy,winner)) 97 98 99 return value 100 101 # 子ノードが存在する時 102 else: 103 # アーク評価値が最大の子ノードの評価で価値を取得 104 value = self.next_child_node().evaluate() 105 106 # 累計価値と試行回数の更新 107 self.w += value 108 self.n += 1 109 return value 110 111 # アーク評価値が最大の子ノードを取得 112 def next_child_node(self): 113 # アーク評価値の計算 114 C_PUCT = 1.0 115 t = sum(nodes_to_scores(self.child_nodes)) 116 pucb_values = [] 117 print("前 child_nodes",len(self.child_nodes)) 118 for child_node in self.child_nodes: 119 print("child_node.p",child_node.p) 120 pucb_values.append((-child_node.w / child_node.n if child_node.n else 0.0) + 121 C_PUCT * child_node.p * sqrt(t) / (1 + child_node.n)) 122 self.turn+=1 123 124 # アーク評価値が最大の子ノードを返す 125 print("argmax",np.argmax(pucb_values)) 126 print("turn",self.turn) 127 print("len(pucb_values)",len(pucb_values)) 128 print("pucb_values",pucb_values) 129 index=np.argmax(pucb_values) 130 a = index.item() 131 print("index",type(index)) 132 print("index",index) 133 print("len(self.child_nodes)",len(self.child_nodes)) 134 print("self.child_nodes",self.child_nodes) 135 return self.child_nodes[a] 136 137 # 現在の局面のノードの作成 138 root_node = Node(state, 0,winner) 139 140 # 複数回の評価の実行 141 for _ in range(PV_EVALUATE_COUNT): 142 root_node.evaluate() 143 144 # 合法手の確率分布 145 scores = nodes_to_scores(root_node.child_nodes) 146 if temperature == 0: # 最大値のみ1 147 action = np.argmax(scores) 148 scores = np.zeros(len(scores)) 149 scores[action] = 1 150 else: # ボルツマン分布でバラつき付加 151 scores = boltzman(scores, temperature) 152 return scores 153 154# モンテカルロ木探索で行動選択 155def pv_mcts_action(model, temperature=0): 156 def pv_mcts_action(state): 157 scores = pv_mcts_scores(model, state, temperature,winner) 158 rng=np.random.default_rng() 159 return rng.choice([0,1,2,3], p=scores) 160 return pv_mcts_action 161 162# ボルツマン分布 163def boltzman(xs, temperature): 164 xs = [x ** (1 / temperature) for x in xs] 165 return [x / sum(xs) for x in xs] 166 167 168import moves as m 169import pokedex as p 170from damage import calculate_damage 171 172# 動作確認 173if __name__ == '__main__': 174 # モデルの読み込み 175 path = sorted(Path('./model').glob('*.h5'))[-1] 176 model = load_model(str(path)) 177 winner=None 178 # 状態の生成 179 player1=[ 180 p.Jolteon([m.BodySlam(),m.DoubleKick(),m.PinMissle(),m.Thunderbolt()]) 181 ] 182 183 player2=[ 184 p.Rhydon([m.Earthquake(), m.RockSlide(), m.Surf(), m.BodySlam()]) 185 ] 186 187 battle=Battle(player1,player2) 188 189 # モンテカルロ木探索で行動取得を行う関数の生成 190 action1 = pv_mcts_action(model, 1.0) 191 192 result=None 193 while True: 194 if result is not None: 195 if winner is not None: 196 print("バトルは終了しました") 197 break 198 else: 199 result=battle.forward_step(action=next_action) 200 next_action=action1(result) 201 else: 202 #1番目(resultない) 203 #result= battle.forward_step() 204 if player1[0].spe > player2[0].spe: 205 c1=1 206 c2=0 207 c1hp=player1[0].actual_hp 208 c2hp=player2[0].actual_hp 209 else: 210 c1=0 211 c2=1 212 c1hp=player2[0].actual_hp 213 c2hp=player1[0].actual_hp 214 result=((c1,-1,-1,c1hp),(c2,-1,-1,c2hp)) 215 next_action=action1(result) 216 winner = battle.get_winner() 217 #ゲーム終了時 218 if winner is not None or battle.turn > 500: 219 break
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
print文を追加し、child_nodesに存在しない引数が渡されてしまっていることがわかりました。
補足
参考 AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門
macM1
jupyter notebook
質問の内容が違うことがわかったので新しく質問をしました。
https://teratail.com/questions/6grhjidtt878w4