[PYTHON] [Renforcer l'apprentissage] Enfin surpassé les humains! ?? J'ai essayé d'expliquer / d'implémenter Agent57 (Keras-RL)

C'est un jeu Atari qui est souvent utilisé dans l'évaluation de l'apprentissage par renforcement, mais il semble qu'une méthode au-delà des humains soit finalement apparue dans les 57 jeux. J'ai essayé de le mettre en œuvre immédiatement.

Code entier

Le code créé dans cet article est ci-dessous.

table des matières

Quant à la configuration, la première moitié est l'explication technique et la seconde moitié est l'explication de mise en œuvre.

introduction

Agent57 est une méthode d'apprentissage par renforcement de la série DQN. J'ai déjà écrit sur la technologie jusqu'à l'agent 57 de la série DQN, alors n'hésitez pas à me contacter.

À propos de l'agent 57

Les 57 jeux d'Atari2600 sont souvent utilisés comme indicateurs de l'apprentissage par renforcement, mais finalement les 57 jeux ont révélé des méthodes d'apprentissage par renforcement qui dépassent les performances humaines. Il y avait des jeux tels que Montezuma's Revenge qui étaient difficiles à apprendre avec la méthode existante, mais Agent57 semble être capable d'apprendre correctement.

Vous trouverez ci-dessous une comparaison de chaque méthode citée dans l'article de Deep Mind.

Artboard 1 copy.png

Je pensais que F (ApeX) et G (R2D2) étaient incroyables, mais ce sont des performances écrasantes au-delà.

·référence Agent57: Outperforming the human Atari benchmark Atari Complete Conquest! Atari57 Qu'est-ce que l'Agent57 qui surpasse les humains dans tous les jeux!?

Jusqu'à Agent57

Artboard 1 copy 3.png

(Figure tirée de l'article de Deep Mind)

Cet article décrit NGU (Never Give Up) et Agent57.

Comme le montre la figure, l'agent 57 est une amélioration de la méthode DQN existante. J'espère que vous pourrez vous référer à mes articles passés pour le contenu qui vous intéresse sur les méthodes passées.

Le changement majeur dans NGU / Agent57 est qu'il se concentre sur l'exploration et l'exploitation, et introduit un mécanisme qui permet une exploration efficace même dans des environnements où les récompenses sont difficiles à obtenir. En plus de cela, diverses méthodes ont été adoptées, je voudrais donc les expliquer une par une.

NGU(Never Give Up)

Il y a un compromis entre l'exploration d'un territoire inconnu et l'obtention d'une récompense (exploitation) en apprentissage intensif. Il y avait un problème que la méthode existante ne pouvait pas bien apprendre dans les jeux où la récompense était rare (il a fallu beaucoup de temps pour obtenir la récompense). Par conséquent, NGU réalise une recherche efficace en ajoutant une récompense interne (récompense intrinsèque) à la récompense.

Les récompenses internes doivent remplir les trois conditions suivantes.

+1 Évitez de visiter le même état dans un épisode (renforcer)

·référence (Papier) Ne jamais abandonner: Apprendre les stratégies d'exploration dirigée [Ne jamais abandonner! Atari Renforcer l'apprentissage de la recherche sans abandonner même dans des environnements difficiles qui mène à une domination complète!](Https://ai-scholar.tech/articles/reinforcement-learning/never-give-up-ai- 394)

Récompense intrinsèque

NGU définit les récompenses en ajoutant des récompenses internes (récompenses intrinsèques) à des récompenses externes (récompenses extrinsèques).

r_{t}=r^e_t + \beta r^i_t

Où $ r ^ e_t $ est la récompense externe, $ r ^ i_t $ est la récompense interne et $ \ beta $ est la constante qui pondère la récompense interne. Ensuite, nous nous entraînerons en utilisant $ r_ {t} $ (récompense étendue) qui est la somme de ceux-ci.

Regardons les récompenses internes. (La figure est tirée du papier, et cette figure est appelée figure A ci-après)

01.png

Les récompenses internes sont créées à partir du module de nouveauté à vie (cadre vert sur le côté droit de la figure A) et de la mémoire d'épisode (cadre rouge sur le côté droit de la figure A).

Générez une valeur de $ \ alpha_t $ à partir du stockage à vie et $ r ^ {épisode} _t $ à partir du stockage des épisodes, et synthétisez-les comme suit.

r ^ i_t = r ^ {épisode} _t ・ min (max (\ alpha _ {t}, 1), L)

Écrit en japonais, récompense interne = mémoire d'épisode x mémoire à vie.

Commençons par la section de la mémoire des épisodes.

Mémoire d'épisode (module de nouveauté épisodique)

Dans le département de la mémoire des épisodes, la récompense est décidée afin que le même état ne soit pas visité dans un épisode. Le flux global est le suivant. (Correspond au cadre rouge de la Fig. A)

  1. Utilisez une fonction intégrée (réseau d'intégration) pour générer un état contrôlable à partir de l'état actuel
  2. À partir de l'état contrôlable et de la mémoire d'épisode M, utilisez la méthode des k voisins les plus proches pour obtenir une approximation du nombre de visites dans l'état actuel.
  3. Générez le stockage de l'épisode ($ r ^ {episode} _t $) à partir de la valeur approximative du nombre de visites
  4. Ajouter un état contrôlable à la mémoire des épisodes

La fonction intégrée et la valeur approximative du nombre de visites seront décrites plus loin. La mémoire des épisodes est initialisée au début d'un épisode. Cela semble déterminer le nombre de visites dans un épisode.

Fonction intégrée (réseau d'intégration)

Les fonctions intégrées sont des fonctions de réseau neuronal qui génèrent des états contrôlables.

ngu_zu1.PNG

Cela ressemble à un simple réseau de neurones qui compresse simplement l'état actuel en p dimension. Le problème est l'apprentissage, qui est assimilé au réseau siamois comme suit.

ngu_zu2.PNG

(Cette figure est une figure détaillée sur le côté gauche de la figure A)

L'entrée est l'état précédent et l'état actuel, et la sortie est la probabilité que chaque action soit sélectionnée. En bref, c'est un réseau qui apprend quelle action a été effectuée à partir de la différence entre l'état précédent et l'état actuel.

Il semble que ce réseau n'apprenne que les états qui changent en relation avec le comportement.

Référence: [Apprentissage à distance] Explication approfondie du réseau siamois et de la perte de contraste

Nombre approximatif de visites selon la méthode du quartier k

Le stockage de l'épisode ($ r ^ {épisode} _t $) est calculé en fonction du nombre de visites. Le nombre de visites est calculé en rapprochant la mémoire des épisodes et l'état actuel à l'aide de la méthode k-voisinage. Ce qui suit est une explication utilisant une formule.

Le stockage des épisodes ($ r ^ {épisode} _t $) est le suivant.

r^{episode}_t = \frac{1}{ \sqrt{ n(f(x _{t})) } }

$ n (f (x_t)) $ est le nombre de visites. Le nombre de visites est estimé à l'aide de la fonction du noyau K et se présente comme suit.

\frac{1}{ \sqrt{ n(f(x_t)) } } \approx \frac{1}{ \sqrt{ \sum_(f_i \in N_k)K(f(x_t), f_i) } + c}

c est une constante qui garantit un nombre minimum de pseudo visites. (c = 0,001) K est calculé par la méthode k-voisinage de l'état contrôlable en mémoire et de l'état contrôlable actuel.

K(x,y) = \frac{\epsilon}{ \frac{d^2(x,y)}{d^2_m} + \epsilon}

$ \ Epsilon $ est une petite constante. ($ \ Epsilon $ = 0,001) d représente la distance euclidienne et $ d ^ 2_m $ représente la moyenne mobile de la distance euclidienne.

Module de nouveauté à vie

RND (Random Network Distillation) est utilisé pour la mémoire à vie.

·référence L'exploration par Random Network Distillation a été testée sur MountainCar. (Paper) Exploration by Random Network Distillation

Quant à l'explication du RND, quand on veut juger s'il s'agit d'un état inconnu dans un certain état, on compte généralement le nombre de visites et on pense que plus on a de visites, plus on connaît l'état. Cependant, RND a une idée de renversement. L'analogie du blog de référence était bonne, je vais donc l'utiliser, mais au RND, je préparerai d'abord une carte à gratter. Au début, la carte est recouverte de papier argenté, mais elle est progressivement grattée à chaque visite. RND est une méthode permettant de juger à quel point il est inconnu en regardant le degré de grattage.

Ensuite, comment réaliser cela est de préparer deux réseaux de neurones avec la même structure. (UN B) A quitte l'état initial et B apprend à approcher A. Cet apprentissage de B équivaut à l'acte de gratter du papier argenté. En conséquence, en comparant A et B, l'erreur est grande = l'endroit qui n'est pas recherché, et l'erreur est petite = l'endroit qui est bien recherché.

MDP et POMDP

Revenons à la prémisse de l'apprentissage intensif. L'apprentissage Q est fondé sur un modèle probabiliste de MDP (processus de détermination de Markov). Pour faire simple, si vous effectuez une action dans un certain état, elle passera à un état aléatoire et vous recevrez une récompense fixe. (C'est un modèle général d'apprentissage par renforcement)

Cependant, dans NGU, des récompenses internes sont ajoutées, donc même si vous passez au même état, les récompenses changeront. Par conséquent, la NGU doit être considérée comme un modèle de POMDP (processus de détermination de Markov d'observation partielle), et non de MDP.

·référence [Processus décisionnel Markov (Wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95%E6%B1% BA% E5% AE% 9A% E9% 81% 8E% E7% A8% 8B) [Processus de décision Markov d'observation partielle (Wikipedia)](https://ja.wikipedia.org/wiki/%E9%83%A8%E5%88%86%E8%A6%B3%E6%B8%AC%E3% 83% 9E% E3% 83% AB% E3% 82% B3% E3% 83% 95% E6% B1% BA% E5% AE% 9A% E9% 81% 8E% E7% A8% 8B)

Cependant, penser comme POMDP est beaucoup plus difficile que MDP, donc NGU a introduit deux solutions de contournement:

  1. Saisissez les récompenses externes directement dans le réseau Q
  2. Conservez une représentation d'état interne qui résume l'historique de toutes les entrées (états, actions et récompenses) de l'épisode

De plus, puisque l'action de recherche par la récompense interne est ajoutée directement à la récompense, l'action de recherche ne peut pas être facilement désactivée. Pour résoudre ce problème, NGU propose une méthode pour apprendre à la fois la récompense externe et le comportement exploratoire.

UVFA(Universal Value Function Approximators)

DQN estime généralement la valeur Q en prenant un certain état comme entrée. Ici, UVFA est une fonction de valeur qui généralise l'entrée en ajoutant non seulement l'état mais aussi l'objectif.

NGU utilise cet UVFA, mais au lieu de la cible, $ \ beta $ (taux de réflexion de récompense interne: taux de recherche) est entré. En faisant cela, nous proposons d'apprendre le comportement exploratoire en même temps. Si $ \ beta = 0 $, vous pouvez obtenir le résultat lorsque la recherche est désactivée, et si $ \ beta> 0 $, vous pouvez obtenir le résultat lorsque la recherche est activée.

·référence (Diapositive Deep Mind) Approximateurs de la fonction de valeur universelle (Papier) Approximateurs de la fonction de valeur universelle

Retrace

L'apprentissage Q utilise une méthode de recherche hors politique dans l'apprentissage TD. (À l'inverse, Sarsa est l'une des recherches sur la politique dans l'apprentissage TD.)

La différence est la référence à la valeur Q à mettre à jour, et dans le cas de hors politique, la politique n'est pas suivie. (Dans l'apprentissage Q, l'action avec la valeur Q maximale est sélectionnée) Dans le cas d'On-Policy, il est acquis conformément à la politique. (Par exemple, si vous effectuez une recherche avec ε-greedy, utilisez également ε-greedy comme destination de référence.)

Le problème avec Off-Policy est que la stratégie sur laquelle vous avez réellement agi (stratégie de comportement) et la stratégie que vous souhaitez apprendre (stratégie cible) sont différentes. Si cela est différent, les valeurs peuvent ne jamais converger (non sécurisé). Dans l'article de Retrace, il existe quatre méthodes pour résoudre ce problème (méthode existante 3). (2 + Retrace) est comparé et cela montre que Retrace est supérieur.

Pour faire simple, Retrace est une méthode de prédiction d'une stratégie basée sur les résultats passés et de contrôle de l'apprentissage par la différence. (Les coefficients utilisés pour contrôler l'apprentissage sont appelés coefficients de traces de coupe ($ c_s $))

NGU intègre Retrace.

·référence Renforcer l'apprentissage (10) que je n'entends plus: différence entre l'apprentissage Sarsa et Q Politique et non-politique de renforcement de l'apprentissage (Paper on Off-policy 1) Q (λ) with Off-Policy Corrections (Article 2 sur l'apprentissage hors politique) Apprentissage par différence temporelle hors politique avec approximation des fonctions (Deep Mind slide) Off-policy deep RL (Document de Retrace) Apprentissage sûr et efficace par renforcement hors politique (Diapositive japonaise du document Retrace) Apprentissage sûr et efficace du renforcement des politiques Bases de la théorie de l'apprentissage amélioré 2 [Review] UCL_RL Lecture05 Model Free Control

Taux de remise

Le taux de remise ($ \ gamma $) dépend de $ \ beta $ (taux de réflexion de la récompense interne) et des changements. Si $ \ beta = 0 $, alors $ \ gamma = max $, et si $ \ beta = max $, alors $ \ gamma = min $. (Plus précisément, $ \ beta = 0 $ est $ \ gamma = 0.997 $, $ \ beta = max $ est $ \ gamma = 0.99 $)

Comme l'influence des récompenses externes est faible pendant l'exploration, il s'agit d'un taux d'actualisation pour l'ajustement.

Agent57

Nous avons pu réaliser une exploration efficace avec NGU, mais dans certains jeux, nous ne pouvions obtenir que le même score qu'une simple exploration aléatoire. En outre, l'un des inconvénients de NGU est qu'il recherche quel que soit le progrès de l'apprentissage.

Agent57 a proposé ce qui suit et les a améliorés.

  1. Introduction d'un nouveau paramètre qui sépare les récompenses externes et internes pour stabiliser l'apprentissage des récompenses internes
  2. Introduit un méta-contrôleur et introduit un mécanisme qui permet de sélectionner le taux de recherche en fonction de la priorité.

(Paper) Agent57: Outperforming the Atari Human Benchmark

Changements dans l'architecture de la fonction valeur d'action (fonction Q)

L'apprentissage pourrait être instable à NGU. Cela se produit lorsque les récompenses externes et internes ont des échelles différentes, ou lorsqu'une seule récompense réagit de manière excessive par rapport aux autres récompenses.

L'agent57 a émis l'hypothèse qu'il serait difficile d'apprendre la fonction de valeur comportementale lorsque la nature de la récompense était très différente entre les récompenses externes et internes, et a proposé un changement dans l'architecture de la fonction de valeur comportementale.

Plus précisément, la fonction de valeur d'action est définie dans $ Q (x, a, j; \ theta ^ e) $ pour l'apprentissage des récompenses externes et $ Q (x, a, j; \ theta ^ i) $ pour l'apprentissage des récompenses internes. Divisez et trouvez la valeur Q avec la formule suivante. (Il semble être basé sur l'opérateur Bellman transformé)

Q(x,a,j;\theta) = h(h^{-1}(Q(x,a,j;\theta^e)) + \beta_j h^{-1}( Q(x,a,j;\theta^i)))

$ \ Beta_j $ est le taux de réflexion (taux de recherche) de la fonction de valeur interne, et h est la fonction d'opérateur de Belman?. h n'est pas très bien compris, mais il est identique à la fonction de remise à l'échelle de R2D2, et se présente comme suit.

h(z) = sign(z)(\sqrt{|z|+1}-1 ) + \epsilon z
h^{-1}(z) = sign(z)(( \frac{ \sqrt{1+4\epsilon (|z|+1+\epsilon} + 4\epsilon }{ 2\epsilon } ) -1)

Contrôleur Meta

NGU et Agent57 peuvent désormais définir le taux de recherche ($ \ beta_j $) à l'aide de récompenses internes.

Cependant, dans NGU, le taux de recherche était fixé pour chaque acteur. Par exemple, lorsque Actor a 4 ans, cela ressemble à ce qui suit. (La valeur est provisoire)

Acteur1: $ \ beta_j $ = 0 (pas de recherche) Acteur2: $ \ beta_j $ = 0,1 (recherche en quelque sorte) Acteur3: $ \ beta_j $ = 0,2 (chercher un peu) Acteur4: $ \ beta_j $ = 0.3 (recherche so-so)

Il est préférable d'utiliser une valeur élevée pour le taux de recherche au début de la formation, mais on s'attend à ce qu'il soit préférable d'utiliser une valeur faible à mesure que la formation progresse. Par conséquent, Agent57 a proposé un méta-contrôleur afin d'adopter une méthode de sélection d'un taux de recherche efficace.

Dans le méta-contrôleur, la sélection d'un taux de recherche efficace est assimilée à un problème de bandit multi-armé (problème MAB), dont la politique de recherche (acteur dans NGU) doit être sélectionnée pour une récompense maximale. Ceci est en train d'être résolu. (La récompense se réfère ici au total des récompenses externes non actualisées dans un épisode)

·référence Article que j'ai écrit plus tôt: [Renforcer l'apprentissage] Mettre en œuvre / expliquer et comparer plusieurs politiques de recherche (problème de bandit multi-armé) Théorie et algorithme du problème des bandits multi-armés Introduction au renforcement de l'apprentissage: problème de bandit multi-armé

Problème de bandit multi-armé (problème MAB)

Pour faire simple, le problème du MAB est le problème de la maximisation de la récompense lors de la sélection de plusieurs emplacements (bras) un certain nombre de fois. Par exemple, supposons que vous ayez 4 emplacements (A, B, C, D). Quelle est la meilleure façon de choisir le prix maximum après avoir choisi une machine à sous 100 fois? C'est le problème. Je ne connais pas la probabilité que les quatre machines à sous gagnent.

Dans un problème MAB général, la probabilité de gagner un prix est constante pour chaque créneau. (Cela ne change pas après la première décision) Cependant, avec Agent57, la probabilité d'obtenir une récompense (résultat de récompense) change. Par conséquent, le contrôleur méta est un peu conçu.

méthode UCB à fenêtre coulissante

Agent57 utilise la méthode UCB comme algorithme pour les problèmes MAB. Cependant, comme la récompense change, la méthode UCB ne peut pas être appliquée telle quelle. Par conséquent, nous proposons de n'utiliser la méthode UCB que pour les derniers épisodes. C'est ce qu'on appelle dans l'article la méthode UCB à fenêtre coulissante. C'est la même chose que la méthode UCB sauf que vous ne voyez que les derniers épisodes.

la mise en oeuvre

Récompense intrinsèque

Fonction intégrée (réseau d'intégration)

Il est nécessaire de créer un réseau neuronal spécial dans lequel la structure du réseau au moment de l'apprentissage et la structure du réseau au moment de l'utilisation sont différentes. La première est la fonction intégrée pour l'acquisition de valeur.

Untitled Diagram (12)-Page-1.jpg

Il n'y a aucune mention de la couche de traitement d'image dans le papier, et c'est le terme utilisé dans cet article. (Parce que le papier est basé sur l'entrée d'image)

Vient ensuite la fonction intégrée d'apprentissage.

Untitled Diagram (12)-Page-2.jpg

Le code qui implémente la figure ci-dessus est le suivant.

input_sequence =Nombre de trames d'entrée
input_shape =Format d'entrée
nb_actions =Nombre d'actions

Fonction intégrée pour l'acquisition de valeur


c = input_ = Input(shape=(input_sequence,) + input_shape)
c = Conv2D(32, (8, 8), strides=(4, 4), padding="same", name="l0")(c)
c = Conv2D(64, (4, 4), strides=(2, 2), padding="same", name="l1")(c)
c = Conv2D(64, (3, 3), strides=(1, 1), padding="same", name="l2")(c)
c = Dense(32, activation="relu", name="l3")(c)
emb_model = Model(input_, c)

Fonction intégrée pour la formation


#Faire deux entrées
c1 = input1 = Input(shape=(input_sequence,) + input_shape)
c2 = input2 = Input(shape=(input_sequence,) + input_shape)

#Créez un réseau tout en partageant des poids
l = Conv2D(32, (8, 8), strides=(4, 4), padding="same", name="l0")
c1 = l(c1)
c2 = l(c2)
l = Conv2D(32, (4, 4), strides=(2, 2), padding="same", name="l1")
c1 = l(c1)
c2 = l(c2)
l = Conv2D(64, (3, 3), strides=(1, 1), padding="same", name="l2")
c1 = l(c1)
c2 = l(c2)
l = Dense(32, activation="relu", name="l3")
c1 = l(c1)
c2 = l(c2)

#Joindre
c = Concatenate()([c1, c2])
c = Dense(128, activation="relu")(c)
c = Dense(nb_actions, activation="softmax")(c)

emb_train_model = Model([input1, input2], c)

#optimiseur du papier
model.compile(
    loss='mean_squared_error', 
    optimizer=Adam(lr=0.0005, epsilon=0.0001))

Bien qu'il s'agisse d'une fonction de perte, il n'y avait qu'une description dans l'article selon laquelle elle a été apprise par la méthode d'estimation la plus probable. (Peut-être…) Donc, pour le moment, l'erreur quadratique moyenne est utilisée.

·référence Technique TPU de Keras dans le noir: Comment transférer les coefficients d'un modèle à deux entrées et d'un modèle à une entrée l'un à l'autre Modèle multi-entrées multi-sorties (officiel Keras)

Vient ensuite le code qui copie les poids de emb_train_model vers emb_model.

def sync_embedding_model():
    for i in range(4):  #couche Tourner pendant quelques minutes
        train_layer = emb_train_model.get_layer("l" + str(i))
        val_layer = emb_model.get_layer("l" + str(i))

        #Copier le poids
        val_layer.set_weights(train_layer.get_weights())

Nous avons créé un excellent modèle avec des entrées disjointes et des poids partagés. .. ..

Apprentissage des fonctions embarquées (réseau d'intégration)

Il semble que ce soit à peine écrit dans le papier ... Pour le moment, l'intervalle de mise à jour de la cible Embeddings est écrit une fois par épisode. Qu'est-ce qu'une cible Embeddings ...

Pour le moment, la méthode d'apprentissage a été exécutée en utilisant le même exemple que l'apprentissage de la fonction de valeur d'action, et la synchronisation avec emb_train_model → emb_model a été définie sur une fois par épisode.

batch_size =Taille du lot

def forward(observation):
    #Moment de l'apprentissage de chaque image

    #Acquérir de l'expérience de manière aléatoire pour un lot à partir de la mémoire d'expérience
    batchs = memory.sample(batch_size)

    #Formater les données
    state0_batch = []   #État précédent
    state1_batch = []   #État suivant
    emb_act_batch = []
    for batch in batchs:
        state0_batch.append(batchs["État précédent"])
        state1_batch.append(batchs["État suivant"])

        #L'action est une-Créer des données en tant que vecteur chaud
        a = np_utils.to_categorical(
            batchs["action"],
            num_classes=nb_actions
        )
        emb_act_batch.append(a)
    
    #entraînement
    emb_train_model.train_on_batch(
        [state0_batch, state1_batch],  #Il y a deux entrées, l'état précédent et l'état suivant
        emb_act_batch                  #L'enseignant est l'action
    )

def backward(self, reward, terminal):
    if terminal:
        #Synchroniser à la fin de l'épisode
        sync_embedding_model()    

* Omettre numpy

Obtenez la valeur d'une fonction embarquée (réseau d'intégration)

Vous obtenez juste la valeur de emb_model.

state =État actuel
cont_state = emb_model.predict([state], batch_size=1)[0]

* Omettre numpy

Calcul du stockage des épisodes

Heureusement, le pseudo code a été écrit dans le papier pour le calcul ici. C'est comme suit lorsqu'il est exprimé par un pseudo-code de type python.

def calc_int_episode_reward(():
    state =État actuel
    k =Nombre dans la méthode k-voisinage(k=10)
    epsilon = 0.001
    c = 0.001
    cluster_distance = 0.008
    maximum_similarity = 8

    #Obtenez un état contrôlable à partir de la fonction intégrée
    cont_state = embedding_network.predict(state, batch_size=1)[0]

    #Trouver tous les éléments dans la mémoire des épisodes et la distance euclidienne
    euclidean_list = []
    for mem_cont_state in int_episodic_memory:
        euclidean = np.linalg.norm(mem_cont_state - cont_state)
        euclidean_list.append(euclidean)

    #Haut k
    euclidean_list.sort()
    euclidean_list = euclidean_list[:k]

    #Distance euclidienne au carré
    euclidean_list = np.asarray(euclidean_list) ** 2

    #Obtenez la moyenne
    ave = np.average(euclidean_list)

    #Approximer le nombre de visites(Calcul de Σ dans la formule)
    count = 0
    for euclidean in euclidean_list:
        d = euclidean / ave

        #Il n'y a pas d'explication dans l'article, mais c'est écrit dans le pseudo code ...
        #Une certaine distance se résume-t-elle à la distance la plus courte?
        d -= cluster_distance
        if d < euclidean_list[0]:
            d = euclidean_list[0]
        
        count += epsilon / (d+epsilon)
    s = np.sqrt(count) + c

    #Il n'y a aucune explication dans l'article ici non plus, mais certaines petites valeurs sont-elles arrondies à 0?
    if s > maximum_similarity:
        episode_reward = 0
    else:
        episode_reward = 1/s

    #Ajout d'un état contrôlable à la mémoire des épisodes, pas dans le pseudo code du papier
    int_episodic_memory.append(cont_state)
    if len(int_episodic_memory) >= 30000:
        int_episodic_memory.pop(0)

    return episode_reward

Module de nouveauté à vie

Modèle RND

Le modèle de RND est le suivant.

rdn.png

La sortie ne signifie pas grand-chose. Le code lorsqu'il existe une couche de traitement d'image est le suivant.

def build_rnd_model():
    #Couche d'entrée
    c = input = Input(shape=(input_sequence,) + input_shape)

    #Couche de traitement d'image
    c = Conv2D(32, (8, 8), strides=(4, 4), padding="same")(c)
    c = Conv2D(64, (4, 4), strides=(2, 2), padding="same")(c)
    c = Conv2D(64, (3, 3), strides=(1, 1), padding="same")(c)

    # Dense
    c = Dense(128)(c)

    model = Model(input, c)

    #perte, optimiseur du papier
    model.compile(
        loss='mean_squared_error', 
        optimizer=Adam(lr=0.0005, epsilon=0.0001))
    
    return model

# train_le modèle est la cible_C'est un modèle proche de l'image
rnd_target_model = build_rnd_model()
rnd_train_model = build_rnd_model()

Apprentissage RND

Je pense que c'est aussi rarement écrit dans le journal ... Il utilise le même exemple que l'apprentissage de la fonction de valeur d'action ainsi que de la fonction intégrée. (Je l'ai utilisé pour apprendre = je l'ai visité (mais c'est peut-être un peu suspect ...))

def forward(observation):
    #Moment de l'apprentissage de chaque image

    #Acquérir de l'expérience de manière aléatoire pour un lot à partir de la mémoire d'expérience
    batchs = memory.sample(batch_size)

    #Formater les données
    state0_batch = []   #État précédent
    state1_batch = []   #État suivant
    for batch in batchs:
        state0_batch.append(batchs["État précédent"])
        state1_batch.append(batchs["État suivant"])

    #Obtenez la valeur de la cible
    rnd_target_val = rnd_target_model.predict(state1_batch, batch_size)
    #entraînement
    rnd_train_model.train_on_batch(state1_batch, rnd_target_val)

* Omettre numpy

Calcul de la mémoire à vie

En ce qui concerne la formule de calcul du stockage à vie, tout d'abord, l'erreur carrée de rnd_target_model et rnd_train_model est calculée.

err(x_t) = || \hat{g}(x_t;\theta) - g(x_t)||^2

Sur cette base, la section de mémoire à vie est calculée à l'aide de la formule suivante.

\alpha_t = 1 + \frac{ err(x_t) - \mu_e }{ \sigma_e }

Où $ \ sigma_e $ est l'écart type de $ err (x_t) $ et $ \ mu_e $ est la moyenne de $ err (x_t) $.

L'écart type et la moyenne sont sortis ... Il n'y a pas de description dans l'article sur la façon de le calculer, mais pour le calculer, vous devez enregistrer les résultats antérieurs. Pour le moment, j'ai créé un tableau pour stocker $ err (x_t) $. Cependant, je fais une limite supérieure parce que ce sera un problème si elle est ajoutée à l'infini.

Ci-dessous le code.


#---Variables de calcul
rnd_err_vals = []
rnd_err_capacity = 10_000

#---Partie calcul
def calc_int_lifelong_reward():
    state =État actuel

    #Obtenez RND
    rnd_target_val = rnd_target_model.predict(state, batch_size=1)[0]
    rnd_train_val = rnd_train_model.predict(state, batch_size=1)[0]

    #Donnez une erreur carrée
    mse = np.square(rnd_target_val - rnd_train_val).mean()
    rnd_err_vals.append(mse)
    if len(rnd_err_vals) > rnd_err_capacity:
        rnd_err_vals.pop(0)

    #écart-type
    sd = np.std(rnd_err_vals)
    if sd == 0:
        return 1

    #moyenne
    ave = np.average(rnd_err_vals)

    # life long reward
    lifelong_reward = 1 + (mse - ave)/sd

    return lifelong_reward

Calcul de la récompense interne

La récompense interne est la formule suivante.

r ^ i_t = r ^ {épisode} _t ・ min (max (\ alpha _ {t}, 1), L)
L = 5
episode_reward =Mémoire d'épisode
lifelong_reward =Département de la mémoire à vie

if lifelong_reward < 1:
    lifelong_reward = 1
if lifelong_reward > L:
    lifelong_reward = L

intrinsic_reward = episode_reward * lifelong_reward

Taux de recherche (β) et taux d'actualisation (γ)

La politique de recherche est représentée par une paire de taux de recherche (β) et de taux d'actualisation ($ \ gamma $) et est calculée par la formule suivante. Le taux d'actualisation est calculé différemment pour NGU et Agent57. (Je vais laisser les deux pour le moment)

La première est la formule de calcul du taux de recherche.

\beta_i = \left\{
\begin{array}{ll}
0 \qquad (i = 0) \\
\beta \qquad (i = N-1) \\
\bêta ・\sigma(10\frac{2i-(N-2)}{N-2}) \quad (otherwise)
\end{array}
\right.

$ \ Sigma $ est la fonction sigmoïde et $ \ beta $ est le taux de réflexion maximum.

def sigmoid(x, a=1):
    return 1 / (1 + np.exp(-a * x))

def create_beta_list(N, max_beta=0.3):
    beta_list = []
    for i in range(N):
        if i == 0:
            b = 0
        elif i == N-1:
            b = max_beta
        else:
            b = 10 * (2*i-(N-2)) / (N-2)
            b = max_beta * sigmoid(b)
        beta_list.append(b)
    return beta_list

Taux d'actualisation NGU.

\gamma_i = 1 - exp \Bigl( \frac{ (N-1-i)log(1-\gamma_max) + (ilog(1-\gamma_min)) }{N-1} \Bigr)
def create_gamma_list_ngu(N, gamma_min=0.99, gamma_max=0.997):
    if N == 1:
        return [gamma_min]
    if N == 2:
        return [gamma_min, gamma_max]
    gamma_list = []
    for i in range(N):
        g = (N - 1 - i)*np.log(1 - gamma_max) + i*np.log(1 - gamma_min)
        g /= N - 1
        g = 1 - np.exp(g)
        gamma_list.append(g)
    return gamma_list

Taux d'actualisation Agent57.

\gamma_j = \left\{
\begin{array}{ll}
\gamma0 \qquad (j=0) \\
\gamma1 + (\gamma0 - \gamma1)\sigma(10 \frac{2i-6}{6} ) \qquad (j \in (1,...,6)) \\
\gamma1 \qquad (j=7) \\
1-exp(\frac{(N-9)log(1-\gamma1) + (j-8)log(1-\gamma2)}{N-9}) \quad (otherwise)
\end{array}
\right.
def create_gamma_list_agent57(N, gamma0=0.9999, gamma1=0.997, gamma2=0.99):
    gamma_list = []
    for i in range(N):
        if i == 1:
            g = gamma0
        elif 2 <= i and i <= 6:
            g = 10*((2*i-6)/6)
            g = gamma1 + (gamma0 - gamma1)*sigmoid(g)
        elif i == 7:
            g = gamma1
        else:
            g = (N-9)*np.log(1-gamma1) + (i-8)*np.log(1-gamma2)
            g /= N-9
            g = 1-np.exp(g)
        gamma_list.append(g)
    return gamma_list

Modèle de récompense interne (UVFA)

Je soupçonne de comprendre ici ...

La figure ci-dessous est un modèle de la fonction de valeur comportementale de l'agent 57.

ronbun_zu1.PNG

En bas à droite se trouve la description de [Action, Récompense externe, Récompense interne, Taux de recherche]. Cependant, il ne dit pas comment ajouter cela ...

Pour le moment, le taux de recherche est ajouté en tant que vecteur ohe-hot uniquement à la fonction de valeur d'action de la récompense interne comme indiqué ci-dessous. (Si vous saisissez la récompense interne ou externe telle quelle, vous n'apprendrez pas ...)

actval.png

Ci-dessous le code. Seule la fonction de valeur d'action pour la récompense interne est décrite. (La partie avec le commentaire (UVFA) est la partie modifiée par UVFA)

from keras.utils import to_categorical

#Où créer un modèle pour la fonction Q
def build_actval_int_model():

    #Couche d'entrée
    c1 = input1 = Input(shape=(input_sequence,) + input_shape)
    c2 = input1 = Input(shape=(policy_num,))  # (UVFA)ajouter à

    #Couche de traitement d'image
    c1 = Conv2D(32, (8, 8), strides=(4, 4), padding="same")(c1)
    c1 = Conv2D(64, (4, 4), strides=(2, 2), padding="same")(c1)
    c1 = Conv2D(64, (3, 3), strides=(1, 1), padding="same")(c1)

    c = Concatenate()([c1, c2])  # (UVFA)ajouter à

    # lstm
    c = LSTM(512)(c)

    # dueling network
    c =Créer un modèle pour Dueling Network(c)

    model = Model([input1, input2], c)  # (UVFA)Changement
    model.compile(loss=clipped_error_loss, optimizer=Adam(lr=0.0001, epsilon=0.0001))

    return model

#Créer un modèle
actval_int_model = build_actval_int_model()
actval_int_model_target = build_actval_int_model()

Formation sur le modèle de récompense interne


#Chaque image
def forward(observation):
    #Obtenir des données de lot
    batchs = memory.sample()

    #Formater les données
    state0_batch = []
    state1_batch = []
    policy_batch = []
    for batch in batchs:
        state0_batch.append(batchs["État précédent"])
        state1_batch.append(batchs["État suivant"])
        #Première politique de découverte-chaud
        t = to_categorical(batchs["Politique de découverte"], num_classes=policy_num)
        policy_batch.append(t)

    #L'entrée est la politique d'état et de découverte
    state0_batch = [state0_batch, policy_batch]
    state1_batch = [state1_batch, policy_batch]
    
    #Exemple de définition de la valeur Q
    state0_qvals = actval_int_model.predict(state0_batch, batch_size)

(State0 pour mise à jour_Calcul des qvals)

    #Apprentissage
    actval_int_model.train_on_batch(state0_batch, state0_qvals)

Calcul de la valeur Q

Le calcul de la valeur Q dans NGU est omis car il n'est plus dû à la division de la fonction de valeur d'action de l'Agent57. La formule de calcul de la valeur Q dans Agent57 est la suivante, qui est une combinaison de récompenses internes et externes.

Q(x,a,j;\theta) = h(h^{-1}(Q(x,a,j;\theta^e)) + \beta_j h^{-1}( Q(x,a,j;\theta^i)))

def rescaling(x, epsilon=0.001):
    if x == 0:
        return 0
    n = math.sqrt(abs(x)+1) - 1
    return np.sign(x)*n + epsilon*x

def rescaling_inverse(x, epsilon=0.001):
    if x == 0:
        return 0
    n = math.sqrt(1 + 4*epsilon*(abs(x)+1+epsilon)) - 1
    return np.sign(x)*( n/(2*epsilon) - 1)


def get_qvals():
    state =État actuel
    policy_index =Politique de découverte

    #Obtenez une valeur Q externe
    qvals_ext = avtval_ext_model.predict(state, batch_size=1)[0]

    #Première politique de découverte-hot
    policy_onehot = to_categorical(policy_index, num_classes=policy_num)

    #Obtenez la valeur Q interne
    qvals_int = avtval_int_model.predict([state, policy_onehot], batch_size=1)[0]

    #Taux de recherche
    beta = int_beta_list[policy_index]

    #Calculer la valeur Q
    qvals = []
    for i in range(nb_actions):
        q_ext = rescaling_inverse(qvals_ext[i])
        q_int = rescaling_inverse(qvals_int[i])
        qval = rescaling(q_ext + beta * q_int)
        qvals.append(qvals)

    return qvals

Retrace

Comme je l'ai dit plus tôt, l'implémentation de Retrace est en attente (je ne comprends pas le contenu ...) Je décrirai les contenus que je ne comprends pas.

La fonction Retrace est:

c_s = \lambda min(1, \frac{\pi(A_s|X_s)}{\mu(A_s|X_s)})

$ \ pi $ est la politique cible et $ \ mu $ est la distribution de probabilité pour chaque action de la politique de comportement.

Cependant, dans DQN, la politique de recherche est complètement gourmande (ne sélectionnez que la valeur Q maximale), donc j'estime que la distribution de probabilité est de 1 pour l'action avec la valeur Q maximale et de 0 pour les autres. Dans ce cas, la molécule ne prendra que 0 ou 1, donc j'ai l'impression qu'elle sera toujours 0, mais ... orz

La politique de comportement sera probablement ε-gourmande, donc je pense que ce sera comme suit (?)

\mu(\alpha|s) = \left\{
\begin{array}{ll}
\epsilon/N + 1 - \epsilon \quad (argmax_{\alpha \in A} Q(s, \alpha)) \\
\epsilon/N \quad (otherwise)
\end{array}
\right.

Où N est le nombre d'actions.

Épilogue

Je n'ai pas complètement expliqué les détails tels que l'environnement LSTM, les files d'attente et le traitement parallèle. .. .. Le code source est ouvert au public, veuillez donc vérifier les détails ici.

Avec cela, je sens que j'ai atteint un objectif en tant qu'algorithme d'apprentissage par renforcement, mais je pense qu'il y a encore place à l'amélioration. Ce que je souhaite que vous amélioriez le plus, ce sont les spécifications requises. C'est le cas depuis R2D2, mais le nombre d'acteurs dans l'article est de 512. Mon PC a une limite de 2 et au plus 4 ... (bien qu'il puisse n'avoir qu'un seul processeur) J'attends avec impatience la prochaine nouvelle méthode.

Recommended Posts

[Renforcer l'apprentissage] Enfin surpassé les humains! ?? J'ai essayé d'expliquer / d'implémenter Agent57 (Keras-RL)
[Deep Learning from scratch] J'ai essayé d'expliquer le décrochage
J'ai essayé d'implémenter PCANet
J'ai essayé d'implémenter StarGAN (1)
J'ai essayé d'implémenter la détection d'anomalies par apprentissage de structure clairsemée
J'ai essayé d'implémenter ListNet d'apprentissage de rang avec Chainer
J'ai essayé d'implémenter Perceptron Part 1 [Deep Learning from scratch]
J'ai essayé d'implémenter Deep VQE
J'ai essayé de mettre en place une validation contradictoire
J'ai essayé l'apprentissage par renforcement avec PyBrain
J'ai essayé d'implémenter Realness GAN
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé d'implémenter la permutation en Python
[Renforcer l'apprentissage] J'ai implémenté / expliqué R2D3 (Keras-RL)
J'ai essayé d'implémenter PLSA dans Python 2
J'ai essayé d'implémenter ADALINE en Python
J'ai essayé d'implémenter PPO en Python
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé d'implémenter TOPIC MODEL en Python
J'ai essayé d'implémenter diverses méthodes d'apprentissage automatique (modèle de prédiction) en utilisant scicit-learn
J'ai essayé d'implémenter Cifar10 avec la bibliothèque SONY Deep Learning NNabla [Nippon Hurray]
J'ai essayé d'implémenter le tri sélectif en python
J'ai essayé de mettre en œuvre le problème du voyageur de commerce
[Mac] J'ai essayé de renforcer l'apprentissage avec Open AI Baselines
J'ai essayé de créer un environnement d'apprentissage amélioré pour Othello avec Open AI gym
J'ai essayé de déplacer l'apprentissage automatique (détection d'objet) avec TouchDesigner
J'ai essayé de mettre en œuvre la gestion des processus statistiques multivariés (MSPC)
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
Je veux escalader une montagne avec l'apprentissage par renforcement
J'ai essayé d'implémenter un pseudo pachislot en Python
J'ai essayé d'implémenter le poker de Drakue en Python
J'ai essayé d'implémenter GA (algorithme génétique) en Python
J'ai essayé d'implémenter Grad-CAM avec keras et tensorflow
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
J'ai essayé d'implémenter le calcul automatique de la preuve de séquence
J'ai essayé de compresser l'image en utilisant l'apprentissage automatique
J'ai essayé le deep learning
J'ai essayé de déboguer.
[Deep Learning from scratch] J'ai essayé d'expliquer la confirmation du gradient d'une manière facile à comprendre.
J'ai essayé d'implémenter une ligne moyenne mobile de volume avec Quantx
J'ai essayé d'implémenter un automate cellulaire unidimensionnel en Python
J'ai essayé de mettre en œuvre une évasion (type d'évitement de tromperie) avec Quantx
[Django] J'ai essayé d'implémenter des restrictions d'accès par héritage de classe.
J'ai essayé l'apprentissage automatique pour convertir des phrases en style XX
Mayungo's Python Learning Episode 3: J'ai essayé d'imprimer des nombres
J'ai essayé d'implémenter la fonction d'envoi de courrier en Python
[TF] J'ai essayé de visualiser le résultat de l'apprentissage en utilisant Tensorboard
J'ai essayé de mettre en œuvre le chapeau de regroupement de Harry Potter avec CNN
[Apprentissage automatique] J'ai essayé de résumer la théorie d'Adaboost
J'ai essayé d'implémenter le blackjack du jeu Trump en Python
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai essayé d'implémenter SSD avec PyTorch maintenant (édition du modèle)
J'ai essayé d'apprendre PredNet
J'ai essayé de réintroduire Linux