実現したいこと
ポケモンのalphazero(モンテカルロ、deeplearning、強化学習)を作っています。エラーを解決してバトルを学習してもらいたいです。
発生している問題・分からないこと
ループが止まらない。HPが0なのに続いている。
winner = battle.get_winner()
がうまく機能していないと思っている。
エラーメッセージ
error
1(コメントに記載,print文の実行結果もあり)
該当のソースコード
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 sei_policies=[] 27 28 for a in policies[0]: 29 sei_policies.append(a) 30 31 # 価値の取得 32 value=y[1][0] 33 34 return sei_policies, value 35 36# ノードのリストを試行回数のリストに変換 37def nodes_to_scores(nodes): 38 scores = [] 39 for c in nodes: 40 scores.append(c.n) 41 return scores 42 43# モンテカルロ木探索のスコアの取得 44#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つの状態 45def pv_mcts_scores(model, state, temperature,winner=None): #stateに8つの状態 46# モンテカルロ木探索のノードの定義 47 class Node: 48 player1=[ 49 p.Jolteon([m.BodySlam(),m.DoubleKick(),m.PinMissle(),m.Thunderbolt()]) 50 ] 51 52 player2=[ 53 p.Rhydon([m.Earthquake(), m.RockSlide(), m.Surf(), m.BodySlam()]) 54 ] 55 56 # ノードの初期化 57 def __init__(self, state, p,winner): 58 self.state = state # 状態 59 self.p = p # 方策 60 self.w = 0 # 累計価値 61 self.n = 0 # 試行回数 62 self.winner=winner 63 self.child_nodes = None # 子ノード群 64 (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 65 self.turn=0 66 67 # 局面の価値の計算 68 def evaluate(self): #Battle が入る 69 # ゲーム終了時 70 if self.winner is not None: 71 # 勝敗結果で価値を取得 72 #print("hplen",len(self.p1_nokorihp)) 73 battle=Battle(player1,player2) 74 value = 0 if self.winner == player1 else -1 75 76 # 累計価値と試行回数の更新 77 self.w += value 78 self.n += 1 79 return value 80 81 # 子ノードが存在しない時 82 if not self.child_nodes: 83 # ニューラルネットワークの推論で方策と価値を取得 84 policies, value = predict(model, self.state) 85 86 print("policies",policies) 87 print("value",value) 88 89 # 累計価値と試行回数の更新 90 self.w += value 91 self.n += 1 92 93 94 # 子ノードの展開 95 self.child_nodes = [] 96 a=[6,7,8,9] 97 for action, policy in zip(a, policies): 98 battle=Battle(player1,player2) 99 zyoutai=battle.forward_step(self.p1_nokorihp,self.p2_nokorihp,action) 100 winner = battle.get_winner() 101 self.child_nodes.append(Node(zyoutai, policy,winner)) 102 103 104 return value 105 106 # 子ノードが存在する時 107 else: 108 # アーク評価値が最大の子ノードの評価で価値を取得 109 value = self.next_child_node().evaluate() 110 111 # 累計価値と試行回数の更新 112 self.w += value 113 self.n += 1 114 return value 115 116 # アーク評価値が最大の子ノードを取得 117 def next_child_node(self): 118 # アーク評価値の計算 119 C_PUCT = 1.0 120 t = sum(nodes_to_scores(self.child_nodes)) 121 pucb_values = [] 122 print("前 child_nodes",len(self.child_nodes)) 123 for child_node in self.child_nodes: 124 print("child_node.p",child_node.p) 125 pucb_values.append((-child_node.w / child_node.n if child_node.n else 0.0) + 126 C_PUCT * child_node.p * sqrt(t) / (1 + child_node.n)) 127 self.turn+=1 128 129 # アーク評価値が最大の子ノードを返す 130 print("pucb_values",pucb_values) 131 print("argmax",np.argmax(pucb_values)) 132 print("turn",self.turn) 133 print("len(pucb_values)",len(pucb_values)) 134 index=np.argmax(pucb_values) 135 a = index.item() 136 print("index",type(index)) 137 print("index",index) 138 print("len(self.child_nodes)",len(self.child_nodes)) 139 print("self.child_nodes",self.child_nodes) 140 return self.child_nodes[a] 141 142 # 現在の局面のノードの作成 143 root_node = Node(state, 0,winner) 144 145 # 複数回の評価の実行 146 for _ in range(PV_EVALUATE_COUNT): 147 root_node.evaluate() 148 149 # 合法手の確率分布 150 scores = nodes_to_scores(root_node.child_nodes) 151 if temperature == 0: # 最大値のみ1 152 action = np.argmax(scores) 153 scores = np.zeros(len(scores)) 154 scores[action] = 1 155 else: # ボルツマン分布でバラつき付加 156 scores = boltzman(scores, temperature) 157 return scores 158 159# モンテカルロ木探索で行動選択 160def pv_mcts_action(model, temperature=0): 161 def pv_mcts_action(state): 162 scores = pv_mcts_scores(model, state, temperature,winner) 163 rng=np.random.default_rng() 164 return rng.choice([0,1,2,3], p=scores) 165 return pv_mcts_action 166 167# ボルツマン分布 168def boltzman(xs, temperature): 169 xs = [x ** (1 / temperature) for x in xs] 170 return [x / sum(xs) for x in xs] 171 172import moves as m 173import pokedex as p 174from damage import calculate_damage 175 176# 動作確認 177if __name__ == '__main__': 178 # モデルの読み込み 179 path = sorted(Path('./model').glob('*.h5'))[-1] 180 model = load_model(str(path)) 181 winner=None 182 # 状態の生成 183 player1=[ 184 p.Jolteon([m.BodySlam(),m.DoubleKick(),m.PinMissle(),m.Thunderbolt()]) 185 ] 186 187 player2=[ 188 p.Rhydon([m.Earthquake(), m.RockSlide(), m.Surf(), m.BodySlam()]) 189 ] 190 191 battle=Battle(player1,player2) 192 193 # モンテカルロ木探索で行動取得を行う関数の生成 194 action1 = pv_mcts_action(model, 1.0) 195 196 result=None 197 while True: 198 if result is not None: 199 if winner is not None: 200 print("バトルは終了しました") 201 break 202 else: 203 result=battle.forward_step(action=next_action) 204 next_action=action1(result) 205 else: 206 if winner is not None: 207 print("バトルは終了しました") 208 break 209 #1番目(resultない) 210 #result= battle.forward_step() 211 if player1[0].spe > player2[0].spe: 212 c1=1 213 c2=0 214 c1hp=player1[0].actual_hp 215 c2hp=player2[0].actual_hp 216 else: 217 c1=0 218 c2=1 219 c1hp=player2[0].actual_hp 220 c2hp=player1[0].actual_hp 221 result=((c1,-1,-1,c1hp),(c2,-1,-1,c2hp)) 222 next_action=action1(result) 223 winner = battle.get_winner() 224 #ゲーム終了時 225 if winner is not None or battle.turn > 500: 226 break
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
コードとエラーを見て、winner = battle.get_winner()
がうまく機能していないと思いました。
補足
参考 AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門
macM1
jupyter notebook
https://teratail.com/help/avoid-asking#question
https://teratail.com/help/question-tips#questionTips11
https://teratail.com/help/question-tips#questionTips35
https://teratail.com/help/question-tips
は読みましたか?
読んだ結果を本文に反映ください。解決のヒントを探れるかもしれません。
エラーメッセージ
WARNING:tensorflow:No training configuration found in the save file, so the model was *not* compiled. Compile it manually.
1/1 [==============================] - 0s 106ms/step
policies [1.0365372e-36, 1.4505721e-18, 1.0, 1.6264764e-22]
value [1.]
battle実行されました
0
3
モンテカルロ 6
c1 (Jolteon(271), BodySlam, [Jolteon(271)])
サンダース が技のしかかりをつかった!
こうかはいまひとつ... 0.5
サイドン が19をうけた
❤️ サイドン 残りHP 332
サイドン技のしかかりを使った!
サンダースが135を受けた
⭐️ サンダース 残りHP 136
battle実行されました
1
1
モンテカルロ 7
c1 (Jolteon(136), DoubleKick, [Jolteon(136)])
サンダース が技にどげりをつかった!
こうかはばつぐんだ! 2
サイドン が60をうけた
❤️ サイドン 残りHP 272
サイドン技いわなだれを使った!
サンダースが136を受けた
⭐️ サンダース 残りHP 0
battle実行されました
2
2
モンテカルロ 8
c1 (Jolteon(0), PinMissle, [Jolteon(0)])
サンダース が技ミサイルばりをつかった!
サイドン が20をうけた
❤️ サイドン 残りHP 252
サイドン技なみのりを使った!
サンダースが0を受けた
⭐️ サンダース 残りHP 0
battle実行されました
3
1
モンテカルロ 9
c1 (Jolteon(0), Thunderbolt, [Jolteon(0)])
サンダース が技10万ボルトをつかった!
こうかはいまひとつ... 0
サイドン が0をうけた
❤️ サイドン 残りHP 252
サイドン技いわなだれを使った!
急所に当たりました!
こうかはばつぐんだ! 1.5
サンダースが0を受けた
⭐️ サンダース 残りHP 0
前 child_nodes 4
child_node.p 1.0365372e-36
child_node.p 1.4505721e-18
child_node.p 1.0
child_node.p 1.6264764e-22
pucb_values [0.0, 0.0, 0.0, 0.0]
argmax 0
turn 4
len(pucb_values) 4
index <class 'numpy.int64'>
index 0
len(self.child_nodes) 4
self.child_nodes [<__main__.pv_mcts_scores.<locals>.Node object at 0x303043a50>, <__main__.pv_mcts_scores.<locals>.Node object at 0x303650c10>, <__main__.pv_mcts_scores.<locals>.Node object at 0x30369fe50>, <__main__.pv_mcts_scores.<locals>.Node object at 0x3036d2110>]
1/1 [==============================] - 0s 8ms/step
policies [4.088272e-31, 1.0, 1.9188026e-18, 1.2690159e-25]
value [1.]
battle実行されました
0
2
モンテカルロ 6
c1 (Jolteon(0), BodySlam, [Jolteon(0)])
サンダース が技のしかかりをつかった!
こうかはいまひとつ... 0.5
サイドン が21をうけた
❤️ サイドン 残りHP 231
サイドン技なみのりを使った!
サンダースが0を受けた
⭐️ サンダース 残りHP 0
battle実行されました
1
1
モンテカルロ 7
c1 (Jolteon(0), DoubleKick, [Jolteon(0)])
サンダース が技にどげりをつかった!
こうかはばつぐんだ! 2
サイドン が62をうけた
❤️ サイドン 残りHP 169
サイドン技いわなだれを使った!
サンダースが0を受けた
⭐️ サンダース 残りHP 0
battle実行されました
2
2
モンテカルロ 8
c1 (Jolteon(0), PinMissle, [Jolteon(0)])
サンダース が技ミサイルばりをつかった!
サイドン が20をうけた
❤️ サイドン 残りHP 149
サイドン技なみのりを使った!
サンダースが0を受けた
⭐️ サンダース 残りHP 0
battle実行されました
3
1
モンテカルロ 9
c1 (Jolteon(0), Thunderbolt, [Jolteon(0)])
サンダース が技10万ボルトをつかった!
こうかはいまひとつ... 0
サイドン が0をうけた
❤️ サイドン 残りHP 149
サイドン技いわなだれを使った!
技は外れました!
サンダースが0を受けた
⭐️ サンダース 残りHP 0
前 child_nodes 4
child_node.p 1.0365372e-36
child_node.p 1.4505721e-18
child_node.p 1.0
child_node.p 1.6264764e-22
pucb_values [array([-1.], dtype=float32), 1.4505721497113927e-18, 1.0, 1.6264764436105582e-22]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[8], line 48
46 c2hp=player1[0].actual_hp
47 result=((c1,-1,-1,c1hp),(c2,-1,-1,c2hp))
---> 48 next_action=action1(result)
49 winner = battle.get_winner()
50 #ゲーム終了時
Cell In[5], line 120, in pv_mcts_action.<locals>.pv_mcts_action(state)
119 def pv_mcts_action(state):
--> 120 scores = pv_mcts_scores(model, state, temperature,winner)
121 rng=np.random.default_rng()
122 return rng.choice([0,1,2,3], p=scores)
Cell In[5], line 105, in pv_mcts_scores(model, state, temperature, winner)
103 # 複数回の評価の実行
104 for _ in range(PV_EVALUATE_COUNT):
--> 105 root_node.evaluate()
107 # 合法手の確率分布
108 scores = nodes_to_scores(root_node.child_nodes)
Cell In[5], line 67, in pv_mcts_scores.<locals>.Node.evaluate(self)
62 return value
64 # 子ノードが存在する時
65 else:
66 # アーク評価値が最大の子ノードの評価で価値を取得
---> 67 value = self.next_child_node().evaluate()
69 # 累計価値と試行回数の更新
70 self.w += value
Cell In[5], line 89, in pv_mcts_scores.<locals>.Node.next_child_node(self)
87 # アーク評価値が最大の子ノードを返す
88 print("pucb_values",pucb_values)
---> 89 print("argmax",np.argmax(pucb_values))
90 print("turn",self.turn)
91 print("len(pucb_values)",len(pucb_values))
File ~/.pyenv/versions/anaconda3-2023.09-0/lib/python3.11/site-packages/numpy/core/fromnumeric.py:1229, in argmax(a, axis, out, keepdims)
1142 """
1143 Returns the indices of the maximum values along an axis.
1144
(...)
1226 (2, 1, 4)
1227 """
1228 kwds = {'keepdims': keepdims} if keepdims is not np._NoValue else {}
-> 1229 return _wrapfunc(a, 'argmax', axis=axis, out=out, **kwds)
File ~/.pyenv/versions/anaconda3-2023.09-0/lib/python3.11/site-packages/numpy/core/fromnumeric.py:56, in _wrapfunc(obj, method, *args, **kwds)
54 bound = getattr(obj, method, None)
55 if bound is None:
---> 56 return _wrapit(obj, method, *args, **kwds)
58 try:
59 return bound(*args, **kwds)
File ~/.pyenv/versions/anaconda3-2023.09-0/lib/python3.11/site-packages/numpy/core/fromnumeric.py:45, in _wrapit(obj, method, *args, **kwds)
43 except AttributeError:
44 wrap = None
---> 45 result = getattr(asarray(obj), method)(*args, **kwds)
46 if wrap:
47 if not isinstance(result, mu.ndarray):
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (4,) + inhomogeneous part.
文字数が上限に達したのでこちらに追記します。クラスbattle、インデントがなくなってしまい申し訳ないです。
import moves as m
import pokedex as p
from damage import calculate_damage
from random import randint
def choose_action(self) :#ランダム攻撃
return randint(6,9)
#raise NotImplementedError
def get_spe_ordered_pokemon(c1, c2) :
if c1[0].spe > c2[0].spe:
return (c1, c2)
if c1[0].spe < c2[0].spe:
return (c2, c1)
return (c1, c2) if random() > 0.5 else (c2, c1)
def get_available_pokemons(pokemons):
return [p for p in pokemons if p.actual_hp > 0]
def is_dead(pokemons):
return len(get_available_pokemons(pokemons)) == 0
def is_move(action) -> bool:
return action >= 6
class Battle:
def __init__(self,player1,player2):
self.player1=player1
self.player2=player2
self.turn = 0
def forward_step(self,hp1=None,hp2=None,action=None):
print("battle実行されました")
self.turn += 1
if action is not None:
action1=action
else:
#1回目の時
if(action == -1):
action1 = choose_action(self.player2)
action2 = choose_action(self.player1)
#result=(action1,action2,player1_took_damage,player2_took_damage)
active_pokemon1=self.player1[0]
active_pokemon2=self.player2[0]
print(action1 - 6)
print(action2 - 6)
print("モンテカルロ",action)
if is_move(action1) and is_move(action2):
# to handle both player choose a move
c1, c2 = get_spe_ordered_pokemon(
(active_pokemon1, active_pokemon1.actual_moves[action1 - 6], self.player1),
(active_pokemon2, active_pokemon2.actual_moves[action2 - 6], self.player2),
)
print("c1",c1)
#print(f"{c1[2]}'の {c1[0]} が技{c1[1]}をつかった!")
print(f"{c1[0].name_ja} が技{c1[1].name_ja}をつかった!")
damage = calculate_damage(c1[0], c2[0], c1[1])
took_damage1=damage
if hp1 is not None and c1 == self.player1:
c1[0].actual_hp=hp1
c2[0].actual_hp=hp2
elif hp1 is not None and c1 == self.player2:
c2[0].actual_hp=hp1
c1[0].actual_hp=hp2
c2[0].actual_hp -= damage
#print(f"{c2[2]}の {c2[0]} が{damage}をうけた")
print(f"{c2[0].name_ja} が{damage}をうけた")
print("❤️",c2[0].name_ja,"残りHP",c2[0].actual_hp)
if c2[0].actual_hp > 0:
print(f"{c2[0].name_ja}技{c2[1].name_ja}を使った!")
damage = calculate_damage(c2[0], c1[0], c2[1])
took_damage2=damage
c1[0].actual_hp -= damage
print(f"{c1[0].name_ja}が{damage}を受けた")
print("⭐️",c1[0].name_ja,"残りHP",c1[0].actual_hp)
if c1 == self.player1:
return ((0,action1,took_damage1,c1[0].actual_hp),(1,action2,took_damage2,c2[0].actual_hp))
else:
return ((0,action2,took_damage2,c2[0].actual_hp),(1,action1,took_damage1,c1[0].actual_hp))
def get_winner(self):
if is_dead(self.player1):
return self.player2
if is_dead(self.player2):
return self.player1
def validate(self):
for pokemons in (self.player1,self.player2):
if len([p for p in pokemons if len(p.actual_moves) == 0]) > 0:
raise ValueError("Pokemon must have at least one move")
def run(self):
self.validate()
while True:
self.forward_step()
winner = self.get_winner()
if winner is not None:
print(f"{winner} won the battle!")
return winner
if self.turn > 500:
raise Exception("Battle is too long")
def run1(self,hp1=None,hp2=None):
self.validate()
action=self.forward_step(self,hp1=hp1,hp2=hp2)
winner = self.get_winner()
if action is not None:
reward = 0
if winner == self.player1:
print("優勝はlearner")
reward = 1
return reward
elif winner == self.player2:
print("優勝はopponent")
reward = -1
return reward
elif battle.turn > 500:
print("ターンが長い")
reward = -0.1
return reward
else:
print("バトル中")
エラーが発生しているのは np.argmax(pucb_values) です。
pucb_values [array([-1.], dtype=float32), 1.4505721497113927e-18, 1.0, 1.6264764436105582e-22]
:
Cell In[5], line 89, in pv_mcts_scores.<locals>.Node.next_child_node(self)
87 # アーク評価値が最大の子ノードを返す
88 print("pucb_values",pucb_values)
---> 89 print("argmax",np.argmax(pucb_values))
実際に動作確認をしてみると、同じエラーが発生します。
>>> import numpy as np
>>> x = [np.array([-1.]), 1.4505721497113927e-18, 1.0, 1.6264764436105582e-22]
>>> x
[array([-1.]), 1.4505721497113927e-18, 1.0, 1.6264764436105582e-22]
>>> np.argmax(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
:
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (4,) + inhomogeneous part.
本来、pucb_values は以下の様に float 値を要素とするリストになるはずなのですが、上記の様に先頭の要素が numpy.ndarray になっています。
pucb_values [0.0, 0.0, 0.0, 0.0]
原因はおそらく、predict() 関数の戻り値の一つである value がスカラー値ではなく numpy.ndarray になっているからでしょう。
WARNING:tensorflow:No training configuration found in the save file, so the model was *not* compiled. Compile it manually.
1/1 [==============================] - 0s 106ms/step
policies [1.0365372e-36, 1.4505721e-18, 1.0, 1.6264764e-22]
value [1.] ### <== [1.] ではなく 1.0 になるはず
battle実行されました
0
3
あなたの回答
tips
プレビュー