update save and load
This commit is contained in:
@@ -81,12 +81,12 @@ class PolicyAgent(Agent):
|
|||||||
loss.backward()
|
loss.backward()
|
||||||
opt.step()
|
opt.step()
|
||||||
|
|
||||||
def save(self, path):
|
def save(self, file_path):
|
||||||
torch.save(self._model.state_dict(), path)
|
torch.save(self._model.state_dict(), file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path, encoder):
|
def load(cls, file_path, encoder):
|
||||||
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||||
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
||||||
model.load_state_dict(torch.load(path))
|
model.load_state_dict(torch.load(file_path))
|
||||||
return cls(model, encoder)
|
return cls(model, encoder)
|
||||||
|
|||||||
+4
-4
@@ -38,12 +38,12 @@ class DeepLearningAgent(Agent):
|
|||||||
return goboard.Move.play(point)
|
return goboard.Move.play(point)
|
||||||
return goboard.Move.pass_turn()
|
return goboard.Move.pass_turn()
|
||||||
|
|
||||||
def save(self, path):
|
def save(self, file_path):
|
||||||
torch.save(self.model.state_dict(), path)
|
torch.save(self.model.state_dict(), file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path, encoder):
|
def load(cls, file_path, encoder):
|
||||||
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||||
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
||||||
model.load_state_dict(torch.load(path))
|
model.load_state_dict(torch.load(file_path))
|
||||||
return cls(model, encoder)
|
return cls(model, encoder)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
""" reinforcement learning,在监督学习之后,进行自我对弈的强化学习的策略网络 """
|
||||||
import torch
|
import torch
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
""" supervised learning,采用监督学习的策略网络 """
|
||||||
from tugo.data_processing.parallel_processor import GoDataProcessor
|
from tugo.data_processing.parallel_processor import GoDataProcessor
|
||||||
from tugo.encoders.alphago import AlphaGoEncoder
|
from tugo.encoders.alphago import AlphaGoEncoder
|
||||||
from tugo.agents.predict import DeepLearningAgent
|
from tugo.agents.predict import DeepLearningAgent
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
""" AlphaGo 的价值网络部分,用于评估棋盘状态的价值,即估算当前的局面走某步棋后的胜率 """
|
||||||
|
# from tugo.models.alphago import alphago_model
|
||||||
|
from tugo.models.alphago import AlphaGoModel
|
||||||
|
from tugo.encoders.alphago import AlphaGoEncoder
|
||||||
|
from tugo.rl.value import ValueAgent
|
||||||
|
from tugo.rl.experience import ExperienceBuffer
|
||||||
|
|
||||||
|
# init_value
|
||||||
|
rows, cols = 19, 19
|
||||||
|
encoder = AlphaGoEncoder()
|
||||||
|
input_shape = (encoder.num_planes, rows, cols)
|
||||||
|
alphago_value_network = AlphaGoModel(input_shape)
|
||||||
|
|
||||||
|
alphago_value = ValueAgent(alphago_value_network, encoder)
|
||||||
|
|
||||||
|
# train_value
|
||||||
|
experience = ExperienceBuffer.load('checkpoints/alphago_rl_experience.h5')
|
||||||
|
|
||||||
|
alphago_value.train(experience)
|
||||||
|
|
||||||
|
alphago_value.save('checkpoints/alphago_value.h5')
|
||||||
@@ -93,14 +93,14 @@ class ACAgent(Agent):
|
|||||||
def diagnostics(self):
|
def diagnostics(self):
|
||||||
return {'value': self.last_state_value}
|
return {'value': self.last_state_value}
|
||||||
|
|
||||||
def save(self, path):
|
def save(self, file_path):
|
||||||
torch.save(self.model.state_dict(), path)
|
torch.save(self.model.state_dict(), file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path, encoder):
|
def load(cls, file_path, encoder):
|
||||||
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||||
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
model = AlphaGoModel(encoder.get_input_shape(), is_policy_net=True).to(device)
|
||||||
model.load_state_dict(torch.load(path))
|
model.load_state_dict(torch.load(file_path))
|
||||||
return cls(model, encoder)
|
return cls(model, encoder)
|
||||||
|
|
||||||
# def load_ac_agent(path, encoder):
|
# def load_ac_agent(path, encoder):
|
||||||
|
|||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
import torch
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from tugo import encoders
|
||||||
|
from tugo.game_logic import goboard
|
||||||
|
from tugo.agents import Agent
|
||||||
|
|
||||||
|
|
||||||
|
class ACAgent(Agent):
|
||||||
|
def __init__(self, model, encoder):
|
||||||
|
Agent.__init__(self)
|
||||||
|
self.model = model
|
||||||
|
self.encoder = encoder
|
||||||
|
self.collector = None
|
||||||
|
self.temperature = 1.0
|
||||||
|
|
||||||
|
self.last_state_value = 0
|
||||||
|
|
||||||
|
def set_temperature(self, temperature):
|
||||||
|
self.temperature = temperature
|
||||||
|
|
||||||
|
def set_collector(self, collector):
|
||||||
|
self.collector = collector
|
||||||
|
|
||||||
|
def select_move(self, game_state):
|
||||||
|
num_moves = self.encoder.board_width * self.encoder.board_height
|
||||||
|
|
||||||
|
board_tensor = self.encoder.encode(game_state)
|
||||||
|
x = torch.from_numpy(np.array([board_tensor])).float().to(self.model.device)
|
||||||
|
|
||||||
|
actions, values = self.model(x)
|
||||||
|
move_probs = actions[0].detach().cpu().numpy()
|
||||||
|
estimated_value = values[0][0].item()
|
||||||
|
self.last_state_value = float(estimated_value)
|
||||||
|
|
||||||
|
# Prevent move probs from getting stuck at 0 or 1.
|
||||||
|
move_probs = np.power(move_probs, 1.0 / self.temperature)
|
||||||
|
move_probs = move_probs / np.sum(move_probs)
|
||||||
|
eps = 1e-6
|
||||||
|
move_probs = np.clip(move_probs, eps, 1 - eps)
|
||||||
|
# Re-normalize to get another probability distribution.
|
||||||
|
move_probs = move_probs / np.sum(move_probs)
|
||||||
|
|
||||||
|
# Turn the probabilities into a ranked list of moves.
|
||||||
|
candidates = np.arange(num_moves)
|
||||||
|
ranked_moves = np.random.choice(
|
||||||
|
candidates, num_moves, replace=False, p=move_probs)
|
||||||
|
for point_idx in ranked_moves:
|
||||||
|
point = self.encoder.decode_point_index(point_idx)
|
||||||
|
true_move = goboard.Move.play(point)
|
||||||
|
if not game_state.is_valid_move(true_move):
|
||||||
|
true_move = goboard.Move.pass_turn()
|
||||||
|
if self.collector is not None:
|
||||||
|
self.collector.record_decision(
|
||||||
|
state=board_tensor,
|
||||||
|
action=point_idx,
|
||||||
|
estimated_value=estimated_value
|
||||||
|
)
|
||||||
|
return true_move
|
||||||
|
# No legal, non-self-destructive moves less.
|
||||||
|
return goboard.Move.pass_turn()
|
||||||
|
|
||||||
|
def train(self, experience, lr=0.1, batch_size=128):
|
||||||
|
optimizer = torch.optim.SGD(self.model.parameters(), lr=lr, clipvalue=0.2)
|
||||||
|
criterion = torch.nn.CrossEntropyLoss()
|
||||||
|
|
||||||
|
n = experience.states.shape[0]
|
||||||
|
num_moves = self.encoder.num_points()
|
||||||
|
policy_target = np.zeros((n, num_moves))
|
||||||
|
value_target = np.zeros((n,))
|
||||||
|
for i in range(n):
|
||||||
|
action = experience.actions[i]
|
||||||
|
reward = experience.rewards[i]
|
||||||
|
policy_target[i][action] = experience.advantages[i]
|
||||||
|
value_target[i] = reward
|
||||||
|
|
||||||
|
self.model.train()
|
||||||
|
optimizer.zero_grad()
|
||||||
|
policy_target_t = torch.from_numpy(policy_target).float().to(self.model.device)
|
||||||
|
value_target_t = torch.from_numpy(value_target).float().to(self.model.device)
|
||||||
|
states_t = torch.from_numpy(experience.states).float().to(self.model.device)
|
||||||
|
actions_pred, values_pred = self.model(states_t)
|
||||||
|
loss1 = criterion(actions_pred, policy_target_t)
|
||||||
|
loss2 = criterion(values_pred, value_target_t)
|
||||||
|
loss = loss1 + loss2
|
||||||
|
loss.backward()
|
||||||
|
optimizer.step()
|
||||||
|
|
||||||
|
def serialize(self, file_path):
|
||||||
|
torch.save({
|
||||||
|
'model_state_dict': self.model.state_dict(),
|
||||||
|
'encoder_name': self.encoder.name(),
|
||||||
|
'encoder_board_width': self.encoder.board_width,
|
||||||
|
'encoder_board_height': self.encoder.board_height,
|
||||||
|
}, file_path)
|
||||||
|
|
||||||
|
def diagnostics(self):
|
||||||
|
return {'value': self.last_state_value}
|
||||||
|
|
||||||
|
|
||||||
|
def load_passing_ac_agent(file_path):
|
||||||
|
checkpoint = torch.load(file_path)
|
||||||
|
model = TheModelClass() # TheModelClass should be replaced with your model class
|
||||||
|
model.load_state_dict(checkpoint['model_state_dict'])
|
||||||
|
encoder_name = checkpoint['encoder_name']
|
||||||
|
board_width = checkpoint['encoder_board_width']
|
||||||
|
board_height = checkpoint['encoder_board_height']
|
||||||
|
encoder = encoders.get_encoder_by_name(
|
||||||
|
encoder_name,
|
||||||
|
(board_width, board_height))
|
||||||
|
return ACAgent(model, encoder)
|
||||||
|
|||||||
+4
-4
@@ -43,13 +43,13 @@ class ExperienceBuffer:
|
|||||||
self.rewards = rewards
|
self.rewards = rewards
|
||||||
self.advantages = advantages
|
self.advantages = advantages
|
||||||
|
|
||||||
def save(self, filename):
|
def save(self, file_path):
|
||||||
with open(filename, 'wb') as f:
|
with open(file_path, 'wb') as f:
|
||||||
pickle.dump((self.states, self.actions, self.rewards, self.advantages), f)
|
pickle.dump((self.states, self.actions, self.rewards, self.advantages), f)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, filename):
|
def load(cls, file_path):
|
||||||
with open(filename, 'rb') as f:
|
with open(file_path, 'rb') as f:
|
||||||
states, actions, rewards, advantages = pickle.load(f)
|
states, actions, rewards, advantages = pickle.load(f)
|
||||||
return cls(
|
return cls(
|
||||||
states=states,
|
states=states,
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class QAgent(Agent):
|
|||||||
def diagnostics(self):
|
def diagnostics(self):
|
||||||
return {'value': self.last_move_value}
|
return {'value': self.last_move_value}
|
||||||
|
|
||||||
def save(self, filename):
|
def save(self, file_path):
|
||||||
torch.save({
|
torch.save({
|
||||||
'model': self.model.state_dict(),
|
'model': self.model.state_dict(),
|
||||||
'encoder': {
|
'encoder': {
|
||||||
@@ -121,11 +121,11 @@ class QAgent(Agent):
|
|||||||
'board_width': self.encoder.board_width,
|
'board_width': self.encoder.board_width,
|
||||||
'board_height': self.encoder.board_height,
|
'board_height': self.encoder.board_height,
|
||||||
}
|
}
|
||||||
}, filename)
|
}, file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, filename):
|
def load(cls, file_path):
|
||||||
checkpoint = torch.load(filename)
|
checkpoint = torch.load(file_path)
|
||||||
|
|
||||||
# Assuming `model` is a PyTorch model here and `encoder` is a DLGo encoder
|
# Assuming `model` is a PyTorch model here and `encoder` is a DLGo encoder
|
||||||
model = Model() # The Model class should be defined appropriately
|
model = Model() # The Model class should be defined appropriately
|
||||||
@@ -139,17 +139,17 @@ class QAgent(Agent):
|
|||||||
return cls(model, encoder)
|
return cls(model, encoder)
|
||||||
|
|
||||||
|
|
||||||
def load_q_agent(filename):
|
# def load_q_agent(file_path):
|
||||||
# 我假设 Model 类是预先定义好的 PyTorch 模型,你需要根据实际情况替换或实现这个模型。
|
# # 我假设 Model 类是预先定义好的 PyTorch 模型,你需要根据实际情况替换或实现这个模型。
|
||||||
checkpoint = torch.load(filename)
|
# checkpoint = torch.load(file_path)
|
||||||
|
#
|
||||||
# Assuming `model` is a PyTorch model here and `encoder` is a DLGo encoder
|
# # Assuming `model` is a PyTorch model here and `encoder` is a DLGo encoder
|
||||||
model = Model() # The Model class should be defined appropriately
|
# model = Model() # The Model class should be defined appropriately
|
||||||
model.load_state_dict(checkpoint['model'])
|
# model.load_state_dict(checkpoint['model'])
|
||||||
|
#
|
||||||
encoder_info = checkpoint['encoder']
|
# encoder_info = checkpoint['encoder']
|
||||||
encoder = encoders.get_encoder_by_name(
|
# encoder = encoders.get_encoder_by_name(
|
||||||
encoder_info['name'],
|
# encoder_info['name'],
|
||||||
(encoder_info['board_width'], encoder_info['board_height']))
|
# (encoder_info['board_width'], encoder_info['board_height']))
|
||||||
|
#
|
||||||
return QAgent(model, encoder)
|
# return QAgent(model, encoder)
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
from tugo import rl
|
||||||
|
from tugo.game_logic import scoring
|
||||||
|
from tugo.game_logic import goboard_fast as goboard
|
||||||
|
from tugo.game_logic.gotypes import Player
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
|
class GameRecord(namedtuple('GameRecord', 'moves winner margin')):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def simulate_game(black_player, white_player):
|
||||||
|
moves = []
|
||||||
|
game = goboard.GameState.new_game(19)
|
||||||
|
agents = {
|
||||||
|
Player.black: black_player,
|
||||||
|
Player.white: white_player,
|
||||||
|
}
|
||||||
|
while not game.is_over():
|
||||||
|
next_move = agents[game.next_player].select_move(game)
|
||||||
|
moves.append(next_move)
|
||||||
|
game = game.apply_move(next_move)
|
||||||
|
|
||||||
|
game_result = scoring.compute_game_result(game)
|
||||||
|
# print(game_result)
|
||||||
|
|
||||||
|
return GameRecord(
|
||||||
|
moves=moves,
|
||||||
|
winner=game_result.winner,
|
||||||
|
margin=game_result.winning_margin,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def experience_simulation(num_games, agent1, agent2):
|
||||||
|
collectors = [rl.ExperienceCollector() for _ in range(2)]
|
||||||
|
agents = [agent1, agent2]
|
||||||
|
|
||||||
|
color1 = Player.black
|
||||||
|
for i in range(num_games):
|
||||||
|
for collector, agent in zip(collectors, agents):
|
||||||
|
collector.begin_episode()
|
||||||
|
agent.set_collector(collector)
|
||||||
|
|
||||||
|
if color1 == Player.black:
|
||||||
|
black_player, white_player = agent1, agent2
|
||||||
|
else:
|
||||||
|
white_player, black_player = agent2, agent1
|
||||||
|
game_record = simulate_game(black_player, white_player)
|
||||||
|
|
||||||
|
winner_reward = 1 if game_record.winner == color1 else -1
|
||||||
|
for collector in collectors:
|
||||||
|
collector.complete_episode(reward=winner_reward)
|
||||||
|
winner_reward *= -1
|
||||||
|
|
||||||
|
color1 = color1.other
|
||||||
|
|
||||||
|
return rl.combine_experience(collectors)
|
||||||
|
|||||||
+10
-10
@@ -3,10 +3,10 @@ import torch.nn as nn
|
|||||||
import torch.optim as optim
|
import torch.optim as optim
|
||||||
from torch.distributions import Categorical
|
from torch.distributions import Categorical
|
||||||
|
|
||||||
from dlgo import encoders
|
from tugo import encoders
|
||||||
from dlgo import goboard
|
from tugo import goboard
|
||||||
from dlgo.agent import Agent
|
from tugo.agents import Agent
|
||||||
from dlgo.agent.helpers import is_point_an_eye
|
from tugo.agents.helpers import is_point_an_eye
|
||||||
|
|
||||||
|
|
||||||
class ValueAgent(Agent):
|
class ValueAgent(Agent):
|
||||||
@@ -109,7 +109,7 @@ class ValueAgent(Agent):
|
|||||||
def diagnostics(self):
|
def diagnostics(self):
|
||||||
return {'value': self.last_move_value}
|
return {'value': self.last_move_value}
|
||||||
|
|
||||||
def save(self, filename):
|
def save(self, file_path):
|
||||||
torch.save({
|
torch.save({
|
||||||
'model': self.model.state_dict(),
|
'model': self.model.state_dict(),
|
||||||
'encoder': {
|
'encoder': {
|
||||||
@@ -117,11 +117,11 @@ class ValueAgent(Agent):
|
|||||||
'board_width': self.encoder.board_width,
|
'board_width': self.encoder.board_width,
|
||||||
'board_height': self.encoder.board_height,
|
'board_height': self.encoder.board_height,
|
||||||
}
|
}
|
||||||
}, filename)
|
}, file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, filename):
|
def load(cls, file_path):
|
||||||
checkpoint = torch.load(filename)
|
checkpoint = torch.load(file_path)
|
||||||
|
|
||||||
model = Model() # The Model class should be defined appropriately
|
model = Model() # The Model class should be defined appropriately
|
||||||
model.load_state_dict(checkpoint['model'])
|
model.load_state_dict(checkpoint['model'])
|
||||||
@@ -134,9 +134,9 @@ class ValueAgent(Agent):
|
|||||||
return cls(model, encoder)
|
return cls(model, encoder)
|
||||||
|
|
||||||
|
|
||||||
def load_value_agent(filename):
|
def load_value_agent(file_path):
|
||||||
# 我假设 Model 类是预先定义好的 PyTorch 模型,你需要根据实际情况替换或实现这个模型。
|
# 我假设 Model 类是预先定义好的 PyTorch 模型,你需要根据实际情况替换或实现这个模型。
|
||||||
checkpoint = torch.load(filename)
|
checkpoint = torch.load(file_path)
|
||||||
|
|
||||||
model = Model() # The Model class should be defined appropriately
|
model = Model() # The Model class should be defined appropriately
|
||||||
model.load_state_dict(checkpoint['model'])
|
model.load_state_dict(checkpoint['model'])
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
充分利用PyTorch的能力并优化代码主要包括以下几个方面:
|
||||||
|
|
||||||
|
1. **使用GPU计算**: PyTorch支持使用GPU进行计算,这可以大大加速模型的训练和推理速度。您可以通过使用`.to(device)`方法将数据和模型发送到GPU,其中`device`是一个特定的设备指示器,如`device = torch.device("cuda:0")`。
|
||||||
|
|
||||||
|
2. **使用TorchScript**:TorchScript是一个静态图表示,提供了优化和序列化能力。通过将模型转换为TorchScript,可以提高模型的运行速度并优化内存使用。
|
||||||
|
|
||||||
|
3. **使用DataLoader**:PyTorch的`DataLoader`类可以自动进行数据分批,洗牌和多线程数据加载。这样可以使数据加载更高效,且易于管理。
|
||||||
|
|
||||||
|
4. **使用模型训练工具**:PyTorch提供了许多方便的模型训练工具,如学习率调度器(`torch.optim.lr_scheduler`)和模型保存/加载函数(`torch.save()`, `torch.load()`)。
|
||||||
|
|
||||||
|
5. **使用自动混合精度训练 (AMP)**:这是一个在PyTorch中进行混合精度训练的工具,可以提高训练速度并减少内存消耗。
|
||||||
|
|
||||||
|
6. **优化网络结构**:对于神经网络,合理的网络结构和参数设置也能够极大地提高训练和推断的速度,例如使用Batch Normalization,更合适的激活函数等。
|
||||||
|
|
||||||
|
以上提及的优化方法需要根据具体模型和需求来进行修改和设置。
|
||||||
Reference in New Issue
Block a user