Autor: Hamwon
Resumo
"Jogando Atari com Deep Reinforcement Learning" é o primeiro artigo clássico de aprendizagem por reforço profundo que combina aprendizagem por reforço com aprendizagem profunda. Foi projetado e desenvolvido pela equipe DeepMind. O algoritmo foi testado no ambiente de jogo Atari 2600 e seu desempenho de teste em. alguns jogos eram melhores que os jogadores humanos.
URL do artigo: https://paperswithcode.com/paper/playing-atari-with-deep-reinforcement
01
Crie um projeto de ambiente virtual com Pycharm
O código do projeto e os resultados do treinamento foram carregados no Baidu Netdisk e podem ser baixados primeiro. No entanto, como o ambiente virtual é muito grande, você não precisa fazer o download e instalá-lo. Para operações específicas, consulte a introdução. abaixo.
Link: https://pan.baidu.com/s/1zoh0glqH4xcNSbOUuR2r7g?pwd=00wdCódigo
de extração: 00wd
Primeiro crie um novo projeto usando Pycharm e depois adicione o ambiente virtual nas configurações conforme mostrado abaixo:
O objetivo de criar um projeto de ambiente virtual é separar o ambiente em execução do projeto atual do seu próprio ambiente Python. Em seguida, você instalará os pacotes necessários no ambiente virtual para evitar afetar seu ambiente Python anterior. A versão do Pycharm que uso é a versão 2019. As configurações da nova versão do Pycharm devem ser semelhantes. Você pode usar o Baidu de acordo com sua situação. O caminho do Anaconda para cada pessoa é diferente e você precisa escolher o interpretador básico de acordo com o local de instalação.
Para a configuração do ambiente virtual, consulte o artigo CSDN: Pycharm cria e gerencia um ambiente virtual.
Após a criação do ambiente virtual, você ainda precisa configurar o programa terminal nas configurações:
Neste momento, abra a guia do terminal em Pycharm e você poderá ver o prompt (venv) na frente do terminal, indicando que o terminal atual está em um ambiente virtual:
Neste momento, todos os pacotes que precisamos podem ser instalados através do pip neste terminal.
Lembre-se de copiar as três pastas código, Imgs e modelo baixado do Baidu Cloud para a pasta do projeto atual. Os pacotes Python necessários para o projeto já estão incluídos no arquivo requirements.tx na pasta code . Abra a aba do terminal do Pycharm e entre na pasta code através do comando cd:
cd code
Então pip instala os pacotes necessários:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
Normalmente, após a configuração do ambiente acima, o código na pasta de código deve poder ser executado normalmente. Se não funcionar normalmente, pode haver um problema com o ambiente de jogo do Atari. Para obter detalhes, consulte este artigo da CSDN: [ginásio] Instalação da nova versão (0.21 ou superior) e configuração do ambiente Atari, super simples (Windows).
02
Explicação do modelo de papel
Simplificando, o artigo projeta uma rede DQN, que empilha 4 quadros consecutivos de imagens de jogos cortados em 84X84 na entrada 4X84X84 e, em seguida, usa convolução + ReLU, convolução + ReLU, Flatten, conexão completa + ReLU e conexão completa. o resultado correspondente à dimensão da ação. Aqui treinamos e testamos principalmente o jogo BreakOut (pinball e bloco). Existem 4 tipos de ações correspondentes a este jogo, então a dimensão de saída aqui é 4.
A matriz quadridimensional de saída representa os valores Q(s,a) correspondentes às quatro ações, respectivamente. O número correspondente ao maior valor Q é selecionado como o código de ação gerado pela rede:
0: significa nenhum movimento
1: Indica o início do jogo (se o jogo já começou, então 1 ainda não se move)
2: Indica mudança para a direita
3: Indica deslocamento para a esquerda
Cálculo do tamanho da convolução:
Tamanho de saída = (tamanho de entrada - tamanho do kernel de convolução + 2 x preenchimento) / passo + 1
Usando a rede DQN acima como agente, a interação entre o agente e o ambiente do jogo pode ser realizada. A rede gera ações com base nas observações atuais
, controla o controle deslizante na parte inferior e as mudanças no ambiente geram novas observações
. o controle deslizante move a bola com sucesso. Pule e acerte os blocos acima. Você receberá recompensa = 1 para cada bloco que acertar, caso contrário não haverá recompensa = 0.
A próxima coisa que precisa ser resolvida é como o algoritmo de aprendizado por reforço atualiza continuamente os parâmetros da rede DQN do agente por meio da interação entre o agente e o ambiente, para que o agente aprenda a jogar.
O algoritmo de aprendizagem por reforço salva a experiência de interação entre o agente e o ambiente, podendo obter uma série de tuplas de experiência, a saber (observação atual, ação, próxima observação, recompensa, marca final, de acordo com o método de escrita no artigo). pode ser expresso como:
Inserimos a observação atual na tupla de experiência na rede, e a saída da rede é uma matriz quadridimensional, correspondendo aos valores de 4 ações realizadas na observação atual. De acordo com a ação real realizada pela observação atual na tupla de experiência , podemos obter o valor correspondente à ação realizada
pela observação atual deste array . Este valor está obviamente relacionado ao parâmetro atual θ da rede.
Na verdade, de acordo com a equação de Bellman na qual se baseia a aprendizagem por reforço, também podemos estimar o valor atual através da recompensa obtida após a ação
e o valor esperado da próxima observação correspondente.
Para a situação de final de jogo, existe apenas a recompensa obtida após a realização da ação, não há próxima observação, portanto a estimativa do valor atual é a recompensa.
Para a situação em que o jogo não acabou, a estimativa do valor atual inclui a recompensa obtida, mais o maior valor estimado entre as 4 ações realizadas na próxima observação, multiplicado pelo fator de desconto γ. Este fator de desconto representa o valor atual e o. valor subsequente. As conexões entre eles estão próximas? Se for 0, significa que não está próximo. O valor atual depende apenas da recompensa atual. Quanto maior for γ, mais próxima será a conexão.
Agora temos:
O valor estimado correspondente à ação tomada pela observação atual obtida através da rede DQN .
O valor atual é estimado utilizando a recompensa e o valor máximo estimado da próxima observação multiplicado pelo fator de desconto . De acordo com a equação de Bellman, as duas estimativas deveriam ser iguais, porém, como a estimativa do valor da rede é imprecisa, há uma diferença entre as duas estimativas:
O objetivo do algoritmo de aprendizagem por reforço profundo para treinamento de rede é reduzir a diferença entre as duas estimativas, de modo que a estratégia da rede DQN satisfaça a equação de Bellman, para que a rede DQN possa aprender a estratégia ideal deste jogo. No processo de interação da rede DQN do agente com o ambiente, o objetivo acima pode ser alcançado usando as tuplas de experiência salvas para calcular a perda acima e, em seguida, atualizando os parâmetros da rede DQN com gradiente descendente.
A seguir fornecerá a implementação específica do código usando a estrutura MindSpore no ambiente Python e fornecerá as explicações correspondentes.
03
Implementação do código Shengsi MindSpore
Abra o arquivo Playing_atari.py na pasta de código. O significado específico do código é o seguinte:
3.1 Criação do ambiente de jogo
Depois de importar as bibliotecas correspondentes, primeiro crie o ambiente do jogo:
env = gym.make("BreakoutNoFrameskip-v4") # 游戏环境
env = gym.wrappers.RecordEpisodeStatistics(env)
env = gym.wrappers.ResizeObservation(env, (84, 84)) # 设置图片放缩
env = gym.wrappers.GrayScaleObservation(env) # 设置图片为灰度图
env = gym.wrappers.FrameStack(env, 4) # 4帧图片堆叠在一起作为一个观测
env = MaxAndSkipEnv(env, skip=4) # 跳帧,一个动作维持4帧
O ambiente foi encapsulado aqui
env
e suas imagens de saída foram pré-processadas. Cada saída de observação é uma imagem empilhada em escala de cinza 4X84X84.
3.2 Definição de rede DQN
Use Sengsi MindSpore para definir a rede DQN, use diretamente nn.SequentialCell() e defina-a de acordo com a rede projetada:
class DQN(nn.Cell):
def __init__(self, nb_actions):
super().__init__()
self.network = nn.SequentialCell(
nn.Conv2d(in_channels=4, out_channels=16, kernel_size=8, stride=4, pad_mode='valid'),
nn.ReLU(),
nn.Conv2d(in_channels=16, out_channels=32, kernel_size=4, stride=2, pad_mode='valid'),
nn.ReLU(),
nn.Flatten(),
nn.Dense(in_channels=2592, out_channels=256),
nn.ReLU(),
nn.Dense(in_channels=256, out_channels=nb_actions),
)
def construct(self, x):
return self.network(x / 255.)
construct() representa a saída da rede, semelhante a forward() na estrutura Pytorch
3.3 Design de pool de armazenamento de experiência
class ReplayBuffer():
def __init__(self, replay_memory_size):
def add(self, obs, next_obs, action, reward, done):
def sample(self, sample_num):
...
return Tensor(temp_obs, ms.float32), Tensor(temp_next_obs, ms.float32), Tensor(temp_action, ms.int32), Tensor(temp_reward, ms.float32), Tensor(temp_done, ms.float32)
O código específico não será postado aqui. Simplificando, ele realiza o armazenamento de tuplas de experiência e amostragem em lote para facilitar o treinamento subsequente da rede neural.
3.4 Definição de função de perda, otimizador e função de treinamento
Primeiro instancie uma rede para a classe DQN definida
q_network
, depois defina o otimizador comonn.Adam
e a função de perda comonn.HuberLOss()
q_network = DQN(nb_actions=env.action_space.n) # 网络实例化
optimizer = nn.Adam(params=q_network.trainable_params(), learning_rate=1.25e-4) # 优化器
loss_fn = nn.HuberLoss() # 损失函数
A seguir estão as etapas exclusivas do MindSpore ao definir o treinamento de rede, chamadas de diferenciação automática funcional. Você pode consultar o tutorial sobre diferenciação automática funcional no site oficial . Especificamente, primeiro defina uma função de cálculo de perda forward_fn
, depois gere uma função de cálculo de gradiente com base na função de cálculo de perda grad_fn
e, em seguida, use a função de cálculo de gradiente para definir uma função para uma etapa do treinamento de rede train_step
. Desta forma, usando train_step
a função, você só precisa inserir os dados necessários, podendo atualizar os parâmetros da rede uma vez e concluir o treinamento em uma etapa.
# 损失值计算函数
def forward_fn(observations, actions, y):
current_q_value = q_network(observations).gather_elements(dim=1, index=actions).squeeze() # 把经验对中这个动作对应的q_value给提取出来
loss = loss_fn(current_q_value, y)
return loss
Na
forward_fn
função, o cálculo da estimativa do valor é concluído. No código
current_q_value
, a rede DQN é necessária para calcular o valor Q nesta função. O gradiente de perda subsequente será retropropagado para os parâmetros da rede DQN neste processo de cálculo. . Atualizações para redes neurais.
Observe
y
que a entrada da funçãoé inserida após ser calculada fora da função, porque
o cálculo de aproximadamente também requer a rede DQN, e o gradiente de Perda não deve ser propagado de volta no
processo de cálculo de aproximadamente, caso contrário, os parâmetros da rede serão não ser atualizado. Portanto,
o cálculo sobre precisa ser calculado fora da função e depois inserido
forward_fn
.
# 损失梯度函数
grad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters)
# 参考:https://www.mindspore.cn/tutorials/zh-CN/r2.1/beginner/autograd.html
# 训练一步的函数
def train_step(observations, actions, y):
loss, grads = grad_fn(observations, actions, y)
optimizer(grads)
return loss
ms.ops.value_and_grad
Usando a função de cálculo de perda definidaforward_fn
, uma função de cálculo de gradiente grad_fn pode ser retornada.Em seguida, na função de treinamento
train_step
, podemosgrad_fn
calcular o gradiente e, em seguida, usar o otimizadoroptimizer
para realizar a retropropagação do gradiente, atualizar os parâmetros da rede e concluir o treinamento em uma etapa.
3.4 Treinamento em rede
A seguir, você pode treinar a rede. Aqui estão algumas explicações dos principais códigos-chave:
def Deep_Q_Learning(env, replay_memory_size=100_000, nb_epochs=40000_000, update_frequency=4, batch_size=32,
discount_factor=0.99, replay_start_size=5000, initial_exploration=1, final_exploration=0.01,
exploration_steps=100_000):
Primeiro, defina os parâmetros relevantes necessários para o treinamento, incluindo o tamanho da capacidade do pool de experiência 100_000, o total de épocas de treinamento = 40.000_000, os parâmetros de rede são atualizados a cada 4 épocas, o fator de desconto é 0,99, o treinamento começa quando o pool de experiência está cheio de 5.000 , e a probabilidade de exploração inicial é 1. O total de épocas de exploração é 100_000
Exploração aqui significa que para que o DQN aprenda uma estratégia melhor, as ações são geradas aleatoriamente para exploração antes do treinamento. A probabilidade de exploração diminuirá gradualmente e então dependerá inteiramente do DQN para gerar ações. estratégia.
Antes do treino, coloque a rede no modo de treino:
q_network.set_train() # 设置网络为训练模式
Então deixe o DQN interagir com o jogo, e o código correspondente para gerar ações é (exploração aleatória ou ações geradas pelo DQN):
if random.random() < epsilon: # With probability ε select a random action a
action = np.array(env.action_space.sample())
else: # Otherwise select a = max_a Q∗(φ(st), a; θ)
temp_input = Tensor(obs, ms.float32).unsqueeze(0)
q_values = q_network(temp_input)
action = q_values.argmax(axis=1).item().asnumpy()
Salve cada tupla de experiência no conjunto de experiências:
rb.add(obs, real_next_obs, action, reward, done)
Escolha um lote de tuplas de experiência do conjunto de experiências, calcule os valores e use
train_step
a função para atualizar os parâmetros de rede:
data_obs, data_next_obs, data_action, data_reward, data_done = rb.sample(batch_size)
# 这一部分不用求梯度,所以写在forward_fn和train_step函数之外
max_q_value = q_network(data_next_obs).max(1)
y = data_reward.flatten() + discount_factor * max_q_value * (1 - data_done.flatten())
loss = train_step(data_obs, data_action, y)
Observe
que ele é calculado aqui, porque não há necessidade de retropropagação de gradiente no
processo de cálculo, portanto, ele é calculado primeiro aqui e, em seguida, inserido na
train_step
função definida anteriormente para concluir uma sessão de treinamento.
Em seguida vem o longo processo de treinamento, que durou cerca de 10 dias usando meu próprio laptop. Testei a velocidade de treinamento em meu laptop e é quase igual ao Pytorch. Ascend MindSpore pode usar o Huawei Ascend 910 (chip AI desenvolvido pela Huawei) para acelerar o treinamento, mas como um aluno pobre, penso nisso, então gostaria de tentar com o vivo50 (`・ω・´).
A curva de treinamento é a seguinte: o resultado do treinamento do chefe no github usando Pytorch é de cerca de 200. Limitado pela memória do notebook de 16g, o melhor resultado que pode ser treinado sob a capacidade atual do pool de experiência é de cerca de 150.
04
Resultados experimentais
Pode-se observar que após o treinamento, DQN aprendeu a jogar este jogo. Geralmente, pode obter cerca de 150 pontos. Se você tiver sorte, poderá obter 300 pontos assim:
Um programador nascido na década de 1990 desenvolveu um software de portabilidade de vídeo e faturou mais de 7 milhões em menos de um ano. O final foi muito punitivo! Google confirmou demissões, envolvendo a "maldição de 35 anos" dos programadores chineses nas equipes Flutter, Dart e . Python Arc Browser para Windows 1.0 em 3 meses oficialmente GA A participação de mercado do Windows 10 atinge 70%, Windows 11 GitHub continua a diminuir a ferramenta de desenvolvimento nativa de IA GitHub Copilot Workspace JAVA. é a única consulta de tipo forte que pode lidar com OLTP + OLAP. Este é o melhor ORM. Nos encontramos tarde demais.