[PYTHON] Laissez la machine "apprendre" les règles de FizzBuzz

** * Une addition ** Il y avait déjà un post avec un contenu similaire.

Bonsoir. C'est Rizento.

La plupart d'entre vous qui lisez cet article connaissent FizzBuzz. Si vous êtes un programmeur, vous pouvez avoir une sortie de 1 à 100 selon les règles de FizzBuzz. Cette fois, je vais essayer de faire que FizzBuzz "laisse AI le faire sans écrire de code". Le programme créé est publié sur GitHub.

table des matières

  1. [Qu'est-ce que FizzBuzz](Qu'est-ce que #FizzBuzz)
  2. [Organiser les éléments du jeu](#Organiser les éléments du jeu)
  3. [Création d'un environnement de jeu](#Construction d'un environnement de jeu)
  4. [Construire un modèle d'apprentissage](# Construire un modèle d'apprentissage)
  5. [Créer une mémoire d'apprentissage](#Construire une mémoire d'apprentissage)
  6. [Build Learning Agent](#Build Learning Agent)
  7. [Essayez d'apprendre](# Apprenons)
  8. Résultat

Qu'est-ce que FizzBuzz

Si vous savez ce que c'est, sautez-le.

Jetez un œil à Wikipedia.

Fizz Buzz (également connu sous le nom de Fizz Buzz, Bizz Buzz ou Buzz) est un jeu de mots qui se déroule lors de longues distances en voiture et de beuveries dans le monde anglophone.

En termes simples, lors de la liste des nombres dans l'ordre, ** Fizz ** au lieu des nombres lorsque les multiples de 3, ** Buzz ** lorsque les multiples de 5, ** FizzBuzz dans les deux cas. C'est un jeu appelé **. Ce sont les Nabeats du monde.

Organisez les éléments du jeu

Le temps est 2020, et il est obsolète pour les humains de jouer à FizzBuzz plus. Préparons uniquement les règles du jeu par les humains et laissons la machine jouer le reste.

La méthode utilisée cette fois est l '** apprentissage amélioré **. C'est une technique souvent utilisée pour l'IA dans les jeux, et est également utilisée pour l'IA dans Go et Shogi.

Je n'écrirai pas sur l'apprentissage par renforcement ici. Si vous êtes intéressé, veuillez le vérifier par vous-même.

Lorsque les humains jouent à FizzBuzz, ils peuvent en fait donner une réponse s'ils ne connaissent que le numéro actuel, mais comme il n'a aucun goût d'IA, cette fois ** La réponse pour les 15 derniers tours ** est maintenant Donner à l'IA le ** statut ** de.

Construire un environnement de jeu

Tout d'abord, créez l'environnement de jeu de FizzBuzz. Plus précisément, les fonctions suivantes sont implémentées.

Le ** score ** indique ici la qualité de chaque réponse (nombre, FIzz, Buzz, FizzBuzz) à la situation actuelle pour l'IA. L'IA grandira dans le but de continuer à marquer ce score.

FizzBuzz.py


from random import randint
from numpy import array

class FizzBuzz:
    def __init__(self, start, end):
        self.start = start #Le début
        self.end   = end   #la fin

    def reset(self): #Initialisation
        self.turn = self.start #Numéros actuels
        self.state = []        #État actuel

        #Définir le statut initial(15 derniers tours)
        for i in range(self.turn - 15, self.turn):
            if i % 15 == 0:
                self.state.append(3)
            elif i % 3 == 0:
                self.state.append(1)
            elif i % 5 == 0:
                self.state.append(2)
            else:
                self.state.append(0)

    #Si vous avez suffisamment appris
    def is_learned(self):
        return self.turn == self.end

    #Transition de virage
    def step(self, action, verbose=False):
        if verbose:
            print(self.turn, [self.turn, 'Fizz', 'Buzz', 'FizzBuzz'][action])

        reward   = 0     #But
        terminal = False #Jugement de fin de partie

        self.state = self.state[1:] + [action]

        if action == 1:   # Fizz
            if self.turn % 3 == 0 and self.turn % 5 != 0:
                reward   = 1
                terminal = False
            else:
                reward   = -1
                terminal = True
        elif action == 2: # Buzz
            if self.turn % 5 == 0 and self.turn % 3 != 0:
                reward   = 1
                terminal = False
            else:
                reward   = -1
                terminal = True
        elif action == 3: # FizzBuzz
            if self.turn % 15 == 0:
                reward   = 1
                terminal = False
            else:
                reward   = -1
                terminal = True
        else:             # Number
            if self.turn % 3 != 0 and self.turn % 5 != 0:
                reward   = 1
                terminal = False
            else:
                reward   = -1
                terminal = True

        if self.turn == self.end:
            terminal = True

        self.turn += 1

        return array(self.state), reward, terminal

    def random_step(self): #Pour l'initialisation
        return array(self.state), 0, False

Après l'initialisation avec reset (), l'apprentissage est répété pendant la transition avec l'étape (). De plus, j'ai écrit is_learned () pour juger de la fin afin que l'apprentissage puisse être automatiquement arrondi lorsque le jeu atteint le dernier nombre.

Construire un modèle d'apprentissage

Ensuite, créez un ** modèle ** que vous utiliserez réellement pour l'apprentissage. Cette fois, nous utiliserons un réseau de neurones avec une structure plus simple dans la couche intermédiaire.

model.py


from keras.models import Sequential
from keras.layers import Dense, Reshape
from keras.optimizers import Adam
import numpy as np

class Model:
    def __init__(self):
        learning_rate = 0.01 #Taux d'apprentissage
        state_size    = 15   #Taille d'entrée(État actuel)
        action_size   = 4    #Taille de sortie(0, 1, 2, 3)
        hidden_size   = 16   #La taille du calque caché

        self.model = Sequential()
        self.model.add(Dense(hidden_size, activation='relu', input_dim=state_size))
        self.model.add(Dense(action_size, activation='softmax'))
        self.optimizer = Adam(lr=learning_rate)
        self.model.compile(loss='mse', optimizer=self.optimizer)
        self.model.summary()

    #Fonctions à apprendre réellement
    def replay(self, memory, batch_size, gamma, target_model):
        inputs     = np.zeros((batch_size, 15))
        outputs    = np.zeros((batch_size, 4))
        mini_batch = memory.sample(batch_size)

        for i, (state, action, reward, next_state) in enumerate(mini_batch):
            inputs[i:i + 1] = state
            target          = reward

            if not (next_state == np.zeros(state.shape)).all():
                q = self.model.predict(next_state.reshape(1, 15))[0].argmax()
                next_action = np.argmax(q) #Sélectionnez l'action avec la valeur Q la plus élevée comme action suivante
                target = reward + gamma * target_model.model.predict(
                    next_state.reshape(1, 15)
                )[0][next_action] #Récompense réelle

            #Corrigez la valeur attendue actuelle et laissez-la apprendre
            outputs[i] = self.model.predict(state.reshape(1, 15))
            outputs[i][action.argmax()] = target

        self.model.fit(inputs, outputs, epochs=1, verbose=0)

Utilisez replay () lors de l'apprentissage. Si vous vous entraînez à chaque tour, le modèle sera affecté par la série chronologique de données, donc une certaine quantité de données sera stockée dans la ** mémoire ** qui sera implémentée plus tard, et elle en sera extraite au hasard pour l'entraînement. Je vais.

Construire la mémoire d'apprentissage

Implémentez une mémoire pour stocker les données utilisées pour l'apprentissage.

memory.py


from collections import deque
import numpy as np

class Memory:
    def __init__(self):
        self.buffer = deque()

    #Stocke la situation actuelle, son fonctionnement, ce qui s'est passé à la suite et la récompense pour cette action
    def add(self, exp):
        self.buffer.append(exp)

    #Récupérer des données stockées au hasard
    def sample(self, batch_size):
        indice = np.random.choice(np.arange(len(self.buffer)), size=batch_size, replace=False)
        return [self.buffer[i] for i in indice]

Créer un agent d'apprentissage

Une personne (?) Qui décide réellement d'une action pendant l'apprentissage et apprend en fonction du résultat est appelée un ** agent **.

agent.py


import numpy as np
from keras.utils.np_utils import to_categorical

class Agent:
    #Choisissez une action
    def get_action(self, state, epoch, main_model):
        epsilon = 0.001 + 0.9 / (1.0 + epoch)

        if epsilon < np.random.uniform(0, 1):
            action = main_model.model.predict(state.reshape(1, 15))[0].argmax()
        else: #Comportement aléatoire avec une certaine probabilité
            action = np.random.choice([0, 1, 2, 3])

        return to_categorical(action, 4)

Sélectionnez l'action avec get_action (). En gros, le comportement attendu par le modèle est sélectionné, mais en effectuant des mouvements aléatoires avec une certaine probabilité, il est possible de faire une soi-disant ** aventure ** et de découvrir un nouveau bon coup.

Apprenons réellement

Tournons l'apprentissage en utilisant les personnes implémentées ci-dessus.

train.py


from fizzbuzz import FizzBuzz
from model import Model
from memory import Memory
from agent import Agent

def evaluate(env):
    env.reset()
    state, _, finished = env.random_step()
    while not finished:
        action = agent.get_action(state, N_EPOCHS, main_model)
        next_state, _, finished = env.step(action.argmax(), verbose=True)
        state = next_state

if __name__ == '__main__':
    N_EPOCHS = 5000 #Nombre maximum de formations
    S_BATCH  = 4    #Taille du lot
    GAMMA    = 0.99 #Taux de réduction des récompenses au fil du temps

    env = FizzBuzz(1, 1000) #Environnement d'apprentissage

    main_model   = Model()
    target_model = Model()

    memory = Memory() #Mémoire
    agent  = Agent()  #Agent

    learned_flag = False #Si l'apprentissage est terminé

    for epoch in range(N_EPOCHS):
        if learned_flag:
            break

        print('Epoch: {}'.format(epoch + 1))

        #Réglage de l'état initial
        env.reset()
        state, reward, finished = env.random_step() 
        target_model.model.set_weights(main_model.model.get_weights())

        while not finished:
            action = agent.get_action(state, epoch, main_model)
            learned_flag = env.is_learned()
            next_state, reward, finished = env.step(action.argmax())

            memory.add((state, action, reward, next_state))

            state = next_state

            if len(memory.buffer) > S_BATCH:
                main_model.replay(memory, S_BATCH, GAMMA, target_model)

            target_model.model.set_weights(main_model.model.get_weights())

    env = FizzBuzz(1, 100)
    evaluate(env)

Nous avons également implémenté evaluer () pour évaluer en fin d'apprentissage. Vous pouvez le vérifier lors de la sortie de FizzBuzz.

résultat

C'est un résultat d'apprentissage.

Epoch: 70
Epoch: 71
Epoch: 72
1 1, 2 2, 3 Fizz, 4 4, 5 Buzz, 6 Fizz, 7 7, 8 8, 9 Fizz, 10 Buzz, 11 11, 12 Fizz, 13 13, 14 14,
15 FizzBuzz, 16 16, 17 17, 18 Fizz, 19 19, 20 Buzz, 21 Fizz, 22 22, 23 23, 24 Fizz, 25 Buzz, 26 26,
27 Fizz, 28 28, 29 29, 30 FizzBuzz, 31 31, 32 32, 33 Fizz, 34 34, 35 Buzz, 36 Fizz, 37 37, 38 38,
39 Fizz, 40 Buzz, 41 41, 42 Fizz, 43 43, 44 44, 45 FizzBuzz, 46 46, 47 47, 48 Fizz, 49 49, 50 Buzz,
51 Fizz, 52 52, 53 53, 54 Fizz, 55 Buzz, 56 56, 57 Fizz, 58 58, 59 59, 60 FizzBuzz, 61 61, 62 62,
63 Fizz, 64 64, 65 Buzz, 66 Fizz, 67 67, 68 68, 69 Fizz, 70 Buzz, 71 71, 72 Fizz, 73 73, 74 74,
75 FizzBuzz, 76 76, 77 77, 78 Fizz, 79 79, 80 Buzz, 81 Fizz, 82 82, 83 83, 84 Fizz, 85 Buzz, 86 86,
87 Fizz, 88 88, 89 89, 90 FizzBuzz, 91 91, 92 92, 93 Fizz, 94 94, 95 Buzz, 96 Fizz, 97 FizzBuzz,
98 98, 99 Fizz, 100 Buzz

Après 72 tours d'apprentissage, j'ai pu atteindre 1 à 100.

Essayons le résultat de 4000.

4000 Buzz, 4001 4001, 4002 Fizz, 4003 4003, 4004 4004, 4005 FizzBuzz, 4006 4006, 4007 4007, 4008 Fizz,
4009 4009, 4010 Buzz, 4011 Fizz, 4012 4012, 4013 4013, 4014 Fizz, 4015 Buzz, 4016 4016, 4017 Fizz,
4018 4018, 4019 4019, 4020 FizzBuzz, 4021 4021, 4022 4022, 4023 Fizz, 4024 4024, 4025 Buzz, 4026 Fizz,
4027 4027, 4028 4028, 4029 Fizz, 4030 Buzz, 4031 4031, 4032 Fizz, 4033 4033, 4034 4034, 4035 FizzBuzz,
4036 4036, 4037 4037, 4038 Fizz, 4039 4039, 4040 Buzz, 4041 Fizz, 4042 4042, 4043 4043, 4044 Fizz,
4045 Buzz, 4046 4046, 4047 Fizz, 4048 4048, 4049 4049, 4050 FizzBuzz, 4051 4051, 4052 4052, 4053 Fizz,
4054 4054, 4055 Buzz, 4056 Fizz, 4057 4057, 4058 4058, 4059 Fizz, 4060 Buzz, 4061 4061, 4062 Fizz,
4063 4063, 4064 4064, 4065 FizzBuzz, 4066 4066, 4067 4067, 4068 Fizz, 4069 4069, 4070 Buzz, 4071 Fizz,
4072 4072, 4073 4073, 4074 Fizz, 4075 Buzz, 4076 4076, 4077 Fizz, 4078 4078, 4079 4079, 4080 FizzBuzz,
4081 4081, 4082 4082, 4083 Fizz, 4084 4084, 4085 Buzz, 4086 Fizz, 4087 4087, 4088 4088, 4089 Fizz,
4090 Buzz, 4091 4091, 4092 Fizz, 4093 4093, 4094 4094, 4095 FizzBuzz, 4096 4096, 4097 4097, 4098 Fizz,
4099 4099, 4100 Buzz, 4101 Fizz, 4102 4102, 4103 4103, 4104 Fizz, 4105 Buzz, 4106 4106, 4107 Fizz,
4108 4108, 4109 4109, 4110 FizzBuzz, 4111 4111, 4112 4112, 4113 Fizz, 4114 4114, 4115 Buzz, 4116 Fizz,
4117 4117, 4118 4118, 4119 Fizz, 4120 Buzz, 4121 4121, 4122 Fizz, 4123 4123, 4124 4124, 4125 FizzBuzz,
4126 4126, 4127 4127, 4128 Fizz, 4129 4129, 4130 Buzz, 4131 Fizz, 4132 4132, 4133 4133, 4134 Fizz,
4135 Buzz, 4136 4136, 4137 Fizz, 4138 4138, 4139 4139, 4140 FizzBuzz, 4141 4141, 4142 4142, 4143 Fizz,
4144 4144, 4145 Buzz, 4146 Fizz, 4147 4147, 4148 4148, 4149 Fizz, 4150 Buzz, 4151 4151, 4152 Fizz,
4153 4153, 4154 4154, 4155 FizzBuzz, 4156 4156, 4157 4157, 4158 Fizz, 4159 4159, 4160 Buzz, 4161 Fizz,
4162 4162, 4163 4163, 4164 Fizz, 4165 Buzz, 4166 4166, 4167 Fizz, 4168 4168, 4169 4169, 4170 FizzBuzz,
4171 4171, 4172 4172, 4173 Fizz, 4174 Fizz

Dans le 174e 4174, la sortie de ** 4174 ** a été confondue avec ** Fizz **. Il ne devrait y avoir qu'une quinzaine de types d'états, alors je me demande pourquoi j'ai fait une erreur ...

Au fait, si vous ajoutez l'argument verbose = True à step () sur la 43ème ligne de train.py, vous pouvez voir comment il apprend tout en augmentant progressivement le nombre de tours. mignonne.

Si vous le souhaitez, veuillez suivre Twitter. À plus.

Recommended Posts

Laissez la machine "apprendre" les règles de FizzBuzz
Revue des bases de Python (FizzBuzz)
Apprenez les bases de Python ① Débutants élémentaires
Apprenez à nouveau les bases de Theano
[Linux] Découvrez les bases des commandes shell
Apprenez intuitivement la refonte de Python np
Jusqu'à ce que vous essayiez de laisser DNN apprendre la vérité de l'image en utilisant Colab
À propos du contenu de développement de l'apprentissage automatique (exemple)
Apprenez Nim avec Python (dès le début de l'année).
Impressions d'avoir obtenu le nano-diplôme Udacity Machine Learning Engineer
Apprenez le modèle de conception «Chaîne de responsabilité» en Python
Prédire le sexe des utilisateurs de Twitter grâce à l'apprentissage automatique
Résumé du flux de base de l'apprentissage automatique avec Python
Le début de cif2cell
Le sens de soi
le zen de Python
L'histoire de sys.path.append ()
Apprenez en quelque sorte le machine learning
La vengeance des types: la vengeance des types
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de régression
Enquête sur l'utilisation du machine learning dans les services réels
Prédire la présence ou l'absence d'infidélité par l'apprentissage automatique
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de classification
[Apprentissage automatique] J'ai essayé de résumer la théorie d'Adaboost