[Aprendizado por Reforço] Explicação Detalhada do Algoritmo de Gradiente de Política (Gradiente de Estratégia)

1 Introdução ao gradiente de política

1.1 Os métodos de aprendizado por reforço baseados em políticas e baseados em valores são diferentes

O aprendizado por reforço é um mecanismo para aprender o comportamento correto por meio de recompensas e punições. Existem muitos membros diferentes na família, com recompensas e punições de aprendizado, e escolha comportamentos com base no que você acha que são valores altos, como Q-Learning, Deep-Q-network, e também há um método de saída direta de comportamentos sem analisando recompensas e punições. Este é o gradiente de política sobre o qual falaremos hoje, adiciona uma rede neural para gerar ações previstas. Comparado com métodos baseados em valor, a maior vantagem da saída direta de ações do Policy Gradient é que ele pode selecionar ações em um intervalo contínuo, enquanto métodos baseados em valor, como Q-Learning, se calcular o valor de um número infinito de ações, então ele escolhe se comportar, o que é demais para ele.

1.2 Atualização do algoritmo

Certamente é conveniente ter uma rede neural, mas como reverter o erro de transferência da rede neural? Qual é o erro do Policy Gradient? A resposta é nenhum erro. Mas ele está de fato realizando uma espécie de transmissão reversa. O objetivo desse retorno é tornar o comportamento selecionado mais provável de acontecer na próxima vez. Mas como determinamos se esse comportamento deve aumentar a probabilidade de ser selecionado? Neste momento, recompensas e punições podem ser úteis neste momento.

1.3 Etapas de atualização específicas

insira a descrição da imagem aqui

Agora demonstre novamente, a informação observada é analisada pela rede neural, e o comportamento à esquerda é selecionado, e realizamos diretamente a transmissão reversa, de modo que a possibilidade de ser selecionado na próxima vez aumenta, mas a informação de recompensa e punição diz nós que esse comportamento não é correto. Ok, então o aumento em nossas possibilidades de ação é reduzido de acordo. Dessa forma, as recompensas podem ser usadas para controlar o retrocesso de nossa rede neural. Vamos dar outro exemplo, se a informação de observação desta vez fizer com que a rede neural escolha o comportamento da direita, o comportamento da direita será transmitido ao contrário, de forma que o comportamento da direita será selecionado um pouco mais na próxima vez. desta vez, as informações de recompensa e punição também virão, diga-nos que este é um bom comportamento, então aumentaremos nossos esforços neste passe reverso, para que ele seja selecionado com mais violência na próxima vez. Essa é a ideia central do Policy Gradient.

2 Atualização do Algoritmo de Gradiente de Política

O endereço de download gratuito de todos os códigos é o seguinte:
https://download.csdn.net/download/shoppingend/85194070

2.1 Pontos principais

Policy Gradient é uma grande família em RL. Não é como o método Value-based (Q-Learning, Sarsa), mas também recebe informações ambientais (observação). A diferença é que não gera o valor da ação, mas a ação específica That, de modo que o Policy Gradient ignore o estágio de valor. E uma das maiores vantagens do Policy Gradient é que a saída da ação pode ser um valor contínuo. O método baseado em valor que mencionamos anteriormente gera valores descontínuos e, em seguida, a ação com o maior valor é selecionada. O Policy Gradient pode selecionar uma ação em uma distribuição contínua.

2.2 Algoritmo

O algoritmo Policy Gradient mais simples que introduzimos é uma atualização baseada em toda a rodada de dados, também chamada de método REINFORCE. Este método é o método mais básico do Policy Gradient. Com esta base, faremos outros mais avançados.
insira a descrição da imagem aqui
Δ(log(Policy(s,a))*V representa o grau de surpresa da ação selecionada a no estado s, se a probabilidade de Policy(s,a) for menor, o log(Policy(s,a)) reverso ( Ou seja, -log§) é maior. Se você obtiver um R grande quando Policy(s,a) for pequeno, ou seja, um V grande, então -Δ(log(Policy(s,a))* O V é maior, o que significa mais surpresa, (escolhi uma ação que não é selecionada com frequência, mas descobri que pode obter uma boa recompensa, então tenho que fazer uma grande modificação em meus parâmetros desta vez). Este é o significado físico de o espanto se foi.

2.3 Formação do código do algoritmo

Primeiro defina o loop para a atualização principal:

import gym
from RL_brain import PolicyGradient
import matplotlib.pyplot as plt

RENDER = False  # 在屏幕上显示模拟窗口会拖慢运行速度, 我们等计算机学得差不多了再显示模拟
DISPLAY_REWARD_THRESHOLD = 400  # 当 回合总 reward 大于 400 时显示模拟窗口

env = gym.make('CartPole-v0')   # CartPole 这个模拟
env = env.unwrapped     # 取消限制
env.seed(1)     # 普通的 Policy gradient 方法, 使得回合的 variance 比较大, 所以我们选了一个好点的随机种子

print(env.action_space)     # 显示可用 action
print(env.observation_space)    # 显示可用 state 的 observation
print(env.observation_space.high)   # 显示 observation 最高值
print(env.observation_space.low)    # 显示 observation 最低值

# 定义
RL = PolicyGradient(
    n_actions=env.action_space.n,
    n_features=env.observation_space.shape[0],
    learning_rate=0.02,
    reward_decay=0.99,   # gamma
    # output_graph=True,    # 输出 tensorboard 文件
)

circuito principal:

for i_episode in range(3000):

    observation = env.reset()

    while True:
        if RENDER: env.render()

        action = RL.choose_action(observation)

        observation_, reward, done, info = env.step(action)

        RL.store_transition(observation, action, reward)    # 存储这一回合的 transition

        if done:
            ep_rs_sum = sum(RL.ep_rs)

            if 'running_reward' not in globals():
                running_reward = ep_rs_sum
            else:
                running_reward = running_reward * 0.99 + ep_rs_sum * 0.01
            if running_reward > DISPLAY_REWARD_THRESHOLD: RENDER = True     # 判断是否显示模拟
            print("episode:", i_episode, "  reward:", int(running_reward))

            vt = RL.learn() # 学习, 输出 vt, 我们下节课讲这个 vt 的作用

            if i_episode == 0:
                plt.plot(vt)    # plot 这个回合的 vt
                plt.xlabel('episode steps')
                plt.ylabel('normalized state-action value')
                plt.show()
            break

        observation = observation_

3 Decisão de pensamento de gradiente de política

3.1 Estrutura do código principal

Usando o algoritmo básico de gradiente de política, ele se parece muito com o algoritmo baseado em valor anterior.

class PolicyGradient:
    # 初始化 (有改变)
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):

    # 建立 policy gradient 神经网络 (有改变)
    def _build_net(self):

    # 选行为 (有改变)
    def choose_action(self, observation):

    # 存储回合 transition (有改变)
    def store_transition(self, s, a, r):

    # 学习更新参数 (有改变)
    def learn(self, s, a, r, s_):

    # 衰减回合的 reward (新内容)
    def _discount_and_norm_rewards(self):

inicialização:

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate     # 学习率
        self.gamma = reward_decay   # reward 递减率

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []    # 这是我们存储 回合信息的 list

        self._build_net()   # 建立 policy 神经网络

        self.sess = tf.Session()

        if output_graph:    # 是否输出 tensorboard 文件
            # $ tensorboard --logdir=logs
            # http://0.0.0.0:6006/
            # tf.train.SummaryWriter soon be deprecated, use following
            tf.summary.FileWriter("logs/", self.sess.graph)

        self.sess.run(tf.global_variables_initializer())

3.2 Estabelecer Política de Rede Neural

A rede neural que vamos construir desta vez é assim:
insira a descrição da imagem aqui
por se tratar de aprendizado por reforço, não há rótulo y no aprendizado supervisionado na rede neural. Em vez disso, escolhemos a ação.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        with tf.name_scope('inputs'):
            self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features], name="observations")  # 接收 observation
            self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")   # 接收我们在这个回合中选过的 actions
            self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value") # 接收每个 state-action 所对应的 value (通过 reward 计算)

        # fc1
        layer = tf.layers.dense(
            inputs=self.tf_obs,
            units=10,   # 输出个数
            activation=tf.nn.tanh,  # 激励函数
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc1'
        )
        # fc2
        all_act = tf.layers.dense(
            inputs=layer,
            units=self.n_actions,   # 输出个数
            activation=None,    # 之后再加 Softmax
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc2'
        )

        self.all_act_prob = tf.nn.softmax(all_act, name='act_prob')  # 激励函数 softmax 出概率

        with tf.name_scope('loss'):
            # 最大化 总体 reward (log_p * R) 就是在最小化 -(log_p * R), 而 tf 的功能里只有最小化 loss
            neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts) # 所选 action 的概率 -log 值
            # 下面的方式是一样的:
            # neg_log_prob = tf.reduce_sum(-tf.log(self.all_act_prob)*tf.one_hot(self.tf_acts, self.n_actions), axis=1)
            loss = tf.reduce_mean(neg_log_prob * self.tf_vt)  # (vt = 本reward + 衰减的未来reward) 引导参数的梯度下降

        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss)

Por que usar loss=-log(prob)*Vt como perda. Simplificando, dois tipos de linhas são mencionados acima para calcular neg_log_prob.Esses dois tipos de linhas são exatamente iguais, exceto que a segunda é a expansão da primeira. Se você olhar atentamente para a primeira linha, é entropia cruzada no problema de classificação da rede neural. Os parâmetros da rede neural são aprimorados de acordo com essa verdade básica usando softmax. Obviamente, isso não é muito diferente de um problema de classificação. Podemos entender esse neg_log_prob como um erro de classificação de entropia cruzada. O rótulo no problema de classificação é o y correspondente ao x real, e em nosso Gradiente de Política, x é o estado e y é o número da ação que ele faz de acordo com esse x. Então também pode ser entendido que a ação que ele faz de acordo com x é sempre correta (a ação que sai é sempre o rótulo correto, e ele sempre modificará seus parâmetros de acordo com esse rótulo correto. Mas não é esse o caso, seu as ações não são necessariamente todas É o rótulo correto, que é a diferença entre Gradiente de política e classificação.
Para garantir que esta ação seja o rótulo correto, nossa perda é multiplicada por Vt na linha de entropia cruzada original, e Vt é usado para dizer a cruz O gradiente calculado por -entropia é um gradiente confiável. Se Vt for pequeno ou negativo, significa que a descida do gradiente está na direção errada e devemos atualizar os parâmetros em outra direção. Se esse Vt for positivo , ou Se for muito grande, Vt vai elogiar o gradiente da entropia cruzada, e o gradiente vai cair nessa direção. Há uma imagem abaixo, que é exatamente a ideia explicada. E por que loss=-log(prob
insira a descrição da imagem aqui
) Vt em vez de perda = -prob Vt. A razão é que o prob aqui vem de softmax, e o cálculo de todos os gradientes de parâmetros na rede neural usa entropia cruzada e, em seguida, multiplica esse gradiente por Vt para controlar a direção e a intensidade de Gradiente descendente.

3.3 Comportamento de seleção

Esse comportamento não é mais selecionado pelo valor Q, mas pela probabilidade. Mesmo sem epsilon-greedy, tem um certo grau de aleatoriedade.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        prob_weights = self.sess.run(self.all_act_prob, feed_dict={
    
    self.tf_obs: observation[np.newaxis, :]})    # 所有 action 的概率
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())  # 根据概率来选 action
        return action

3.4 Rodada de armazenamento

Esta parte é para adicionar a observação, ação e recompensa desta etapa à lista. Como a lista precisa ser limpa após o final desta rodada e, em seguida, os dados para a próxima rodada serão armazenados, limparemos a lista em learn()

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        self.ep_obs.append(s)
        self.ep_as.append(a)
        self.ep_rs.append(r)

3.5 Aprendizagem

O método learn() nesta seção é muito simples. Primeiro, temos que manipular todos os reawrds nesta rodada para torná-lo mais adequado para o aprendizado. A primeira é usar γ para atenuar as recompensas futuras à medida que o tempo avança e, em seguida, reduzir a variação da rodada do gradiente de política até certo ponto.

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        ...
    def learn(self):
        # 衰减, 并标准化这回合的 reward
        discounted_ep_rs_norm = self._discount_and_norm_rewards()   # 功能再面

        # train on episode
        self.sess.run(self.train_op, feed_dict={
    
    
             self.tf_obs: np.vstack(self.ep_obs),  # shape=[None, n_obs]
             self.tf_acts: np.array(self.ep_as),  # shape=[None, ]
             self.tf_vt: discounted_ep_rs_norm,  # shape=[None, ]
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []    # 清空回合 data
        return discounted_ep_rs_norm    # 返回这一回合的 state-action value

Olhe para discounted_ep_rs_norm novamente

vt = RL.learn() # 学习, 输出 vt, 我们下节课讲这个 vt 的作用

if i_episode == 0:
    plt.plot(vt)    # plot 这个回合的 vt
    plt.xlabel('episode steps')
    plt.ylabel('normalized state-action value')
    plt.show()

Finalmente, como usar o algoritmo para perceber a atenuação de recompensas futuras

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=False):
        ...
    def _build_net(self):
        ...
    def choose_action(self, observation):
        ...
    def store_transition(self, s, a, r):
        ...
    def learn(self):
        ...
    def _discount_and_norm_rewards(self):
        # discount episode rewards
        discounted_ep_rs = np.zeros_like(self.ep_rs)
        running_add = 0
        for t in reversed(range(0, len(self.ep_rs))):
            running_add = running_add * self.gamma + self.ep_rs[t]
            discounted_ep_rs[t] = running_add

        # normalize episode rewards
        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)
        return discounted_ep_rs

Fonte do artigo: Mofan Reinforcement Learning https://mofanpy.com/tutorials/machine-learning/reinforcement-learning/

Acho que você gosta

Origin blog.csdn.net/shoppingend/article/details/124297444
Recomendado
Clasificación