Compartilhamento de projetos | Como implementar aprendizagem por reforço para jogar através do MindSpore

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.

foto

Após a criação do ambiente virtual, você ainda precisa configurar o programa terminal nas configurações:

foto

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:

foto

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

foto

Usando a rede DQN acima como agente, a interação entre o agente e o ambiente do jogo pode ser realizada. A rede fotogera ações com base nas observações atuais foto, controla o controle deslizante na parte inferior e as mudanças no ambiente geram novas observações foto. 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:

foto

Inserimos a observação atual na fototupla 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 fotopela observação atual deste array . Este valor está obviamente relacionado ao parâmetro atual θ da rede.fotofotofoto

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 fotoda recompensa obtida após a ação fotoe o valor esperado da próxima observação correspondente.

foto

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 à fotoação tomada pela observação atual obtida através da rede DQN .fotofoto

O valor atual é estimado utilizando a recompensa e o valor máximo estimado da próxima observação multiplicado pelo fator de desconto foto. 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:

foto

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 enve 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 como nn.Adame 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_fne, 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_stepa 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_fnfunção, o cálculo da estimativa do valor é concluído foto. 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 yque a entrada da função fotoé inserida após ser calculada fora da função, porque fotoo cálculo de aproximadamente também requer a rede DQN, e o gradiente de Perda não deve ser propagado de volta no fotoprocesso de cálculo de aproximadamente, caso contrário, os parâmetros da rede serão não ser atualizado. Portanto, fotoo 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_gradUsando a função de cálculo de perda definida forward_fn, uma função de cálculo de gradiente grad_fn pode ser retornada.

Em seguida, na função de treinamento train_step, podemos grad_fncalcular o gradiente e, em seguida, usar o otimizador optimizerpara 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 fotoos valores e use train_stepa 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 fotoque ele é calculado aqui, porque não há necessidade de retropropagação de gradiente no fotoprocesso de cálculo, portanto, ele é calculado primeiro aqui e, em seguida, inserido na train_stepfunçã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.

foto

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:

foto

 

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.
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4736317/blog/11072521
Recomendado
Clasificación