[PYTHON] Faisons une IA à trois yeux avec Pylearn 2

introduction

Je veux faire du Deep Learning avec pylearn2. Mais je ne sais pas si je fais simplement de la discrimination d'image dans le didacticiel. Donc, je vais faire une IA pour la troisième ligne (soi-disant jeu ○ ×). Je voulais vraiment faire l'IA d'Othello, mais comme c'est la première fois que j'utilise pylearn2, j'ai choisi un jeu plus simple. Au fait, je suis un débutant en apprentissage automatique, pylearn2. Veuillez signaler toute erreur. Ignorez les étapes pour installer les packages requis tels que pylearn2 et numpy.

Conception de réseau neuronal

Puisqu'il s'agit d'une IA à trois yeux, numérotez d'abord les carrés sur la carte 3x3 pour indiquer l'état sur la carte. 3x3.png

L'entrée est un certain état de la carte 3x3, et la position de la main suivante est la sortie. Par conséquent, considérez le réseau suivant. n-net.png

Les nombres sur les épaules des cercles d'entrée et de sortie sont les nombres des carrés sur le plateau. L'entrée est de 9 entrées, c'est-à-dire l'état de 9 carrés. La couche cachée est une couche et la fonction d'activation est la fonction sigmoïde. La sortie étant divisée en 9 classes, utilisez la fonction softmax. Ici, «diviser en 9 classes» signifie classer une certaine entrée (état du plateau) en fonction de la case du prochain coup. En d'autres termes, s'il est classé en 0, le coup suivant sera effectué sur la case 0.

Création de données pédagogiques

L'IA créée cette fois ne recherche pas la force. Si vous pouvez continuer le jeu sans vous écarter des données d'enseignement, nous le diviserons en une lettre. Par conséquent, au lieu de collecter uniquement les données de combat qui font le mieux, préparez une grande quantité de données qui concourent simplement selon les règles. Afin de générer une grande quantité de données de combat, j'ai créé un script Ruby qui le place simplement dans un endroit où les premier et deuxième mouvements peuvent être placés au hasard. On vous dira peut-être pourquoi vous n'écrivez pas en python, mais cela ne veut pas dire grand-chose simplement parce que vous êtes fatigué d'écrire uniquement python ces derniers temps. Le premier mouvement est 〇 et le deuxième mouvement est ×. Vous pouvez créer un syllabaire en spécifiant le nombre de boucles dans l'argument et en l'exécutant. Ceci est utilisé comme données d'enseignement. Le nombre est le numéro de la case placée, et la victoire et la défaite à la fin indiquent la victoire ou la défaite de la première attaque.

tic_tac_toe.rb


#!/usr/bin/env ruby
#
# tic tac toe
#
# 0 : O (first)
# 1 : X (second)
# 2 : none
#

def show_board(array)
  p array[0][0].to_s + "," + array[0][1].to_s + "," + array[0][2].to_s
  p array[1][0].to_s + "," + array[1][1].to_s + "," + array[1][2].to_s
  p array[2][0].to_s + "," + array[2][1].to_s + "," + array[2][2].to_s
  p ""
end

def judge(array)
  ret = 2
  for stone in [0, 1] do
    for i in [0 ,1, 2] do
      if (array[i][0]==stone && array[i][1]==stone && array[i][2]==stone) ||
         (array[0][i]==stone && array[1][i]==stone && array[2][i]==stone)   then
        ret = stone
      end
    end
   
    if (array[0][0]==stone && array[1][1]==stone && array[2][2]==stone) ||
       (array[0][2]==stone && array[1][1]==stone && array[2][0]==stone)   then
      ret = stone
    end
  end
  return ret
end

loop_max = ARGV[0].to_i
#p "loop max=" + loop_max.to_s
cell_array = [] 
stone_array = [] 

loop_cnt = 0
until loop_cnt >= loop_max do
  cell_array = Array.new(9)
  stone_array = Array.new(3).map { Array.new(3, 2) }
  9.times do |num|
    cell_array[num] = num
  end

  i = 10
  history = []
  9.times do |num|
    #p i
    rnd = rand(i) - 1
    if num % 2 == 0
      stone_array[cell_array[rnd].divmod(3)[0]][cell_array[rnd].divmod(3)[1]] = 0
    else
      stone_array[cell_array[rnd].divmod(3)[0]][cell_array[rnd].divmod(3)[1]] = 1
    end
    history.push(cell_array[rnd])
    #show_board(stone_array)
    ret = judge(stone_array)
    if ret == 0 then
      history.push("win")    # "O" is winner.
      break
    elsif ret == 1 then
      history.push("lose")   # "O" is loser.
      break
    end
    
    cell_array.delete_at(rnd)

    i -= 1
  end
  p history.join(",")
  loop_cnt += 1
end
$ ruby tic_tac_toe.rb 500 | tee tic-tac-toe_records.log
"6,8,3,4,2,0,lose"
"7,1,4,5,0,2,8,win"
"6,2,3,0,5,8,1,7,4,win"
"3,8,4,2,6,5,lose"
"1,8,2,7,3,0,6,4,lose"
"8,0,3,6,7,4,1,2,lose"
"6,8,3,5,2,7,4,win"
"2,1,7,4,3,5,8,6,0"
"4,8,6,7,1,3,2,win"
"6,1,3,0,8,7,5,4,lose"
"8,2,7,1,4,3,0,win"
"8,6,1,2,7,0,3,4,lose"
"4,3,8,1,2,6,7,0,lose"
"8,6,3,4,1,5,7,2,lose"
"1,2,0,4,7,8,5,6,lose"
"0,5,2,3,6,7,8,4,lose"
"7,1,2,6,4,5,0,3,8,win"
"2,1,0,8,3,5,7,4,6,win"
"2,0,8,5,6,7,4,win"
...

Je traiterai ces données de score en csv afin qu'elles puissent être utilisées facilement comme entrée. Cette fois, afin de créer une IA qui décide de la deuxième attaque, seules celles remportées par la deuxième attaque sont extraites.

$ awk '{gsub("\"","");print $0;}' tic-tac-toe_records.log | grep lose | tee tic-tac-toe_records_lose.csv

Ce sera comme ça après le traitement.

tic-tac-toe_records_lose.csv


6,8,3,4,2,0,lose
3,8,4,2,6,5,lose
1,8,2,7,3,0,6,4,lose
8,0,3,6,7,4,1,2,lose
...

Maintenant, vous êtes prêt à partir.

Modèle MLP utilisant pylearn2

Tout d'abord, le code source est affiché.

tic_tac_toe.py


#!/usr/bin/env python
# -*- cording: utf-8 -*-

import theano
from pylearn2.models import mlp
from pylearn2.training_algorithms import sgd
from pylearn2.termination_criteria import EpochCounter
from pylearn2.datasets.dense_design_matrix import DenseDesignMatrix
import numpy as np
import csv

class TicTacToe(DenseDesignMatrix):
    def __init__(self):
        X = []
        y = []
        X_temp = [0,0,0,0,0,0,0,0,0]  # 3x3 board
        y_temp = [0,0,0,0,0,0,0,0,0]  # 3x3 board

        # (1)
        self.class_names = ['0', '3']
        f = open("tic-tac-toe_records_lose.csv", "r")
        reader = csv.reader(f)

        # (2)
        for row in reader:
            for i, cell_index in enumerate(row):
                if cell_index == "win" or cell_index == "lose":
                    X_temp = [0,0,0,0,0,0,0,0,0]
                elif i % 2 == 0:
                    temp = []
                    X_temp[int(cell_index)] = 1
                    for x in X_temp:
                        temp.append(x)

                    #print "  temp = " + str(temp)
                    X.append(temp)
                else:
                    X_temp[int(cell_index)] = 2
                    y_temp[int(cell_index)] = 3
                    #print "y_temp = " + str(y_temp)
                    y.append(y_temp)
                    y_temp = [0,0,0,0,0,0,0,0,0]

        X = np.array(X)
        y = np.array(y)
        super(TicTacToe, self).__init__(X=X, y=y)

# (3)
data_set = TicTacToe()
h0 = mlp.Sigmoid(layer_name='h0', dim=9, irange=.1, init_bias=1.)
out = mlp.Softmax(layer_name='out', n_classes=9, irange=0.)
trainer = sgd.SGD(learning_rate=.05, batch_size=200, termination_criterion=EpochCounter(5000))
layers = [h0, out]

ann = mlp.MLP(layers, nvis=9)
trainer.setup(ann, data_set)

# (4)
while True:
    trainer.train(dataset=data_set)
    ann.monitor.report_epoch()
    ann.monitor()
    if trainer.continue_learning(ann) == False:
        break

# (5)-1
next_move = [0,0,0,0,0,0,0,0,0]
inputs = np.array([[0,0,1,0,0,0,0,0,0]])
output = ann.fprop(theano.shared(inputs, name='inputs')).eval()
print output[0]
for i in range(0,9):
    if max(output[0]) == output[0][i]:
        next_move[i] = 3

print next_move

# (5)-2
next_move = [0,0,0,0,0,0,0,0,0]
inputs = np.array([[1,0,2,1,0,0,0,1,2]])
output = ann.fprop(theano.shared(inputs, name='inputs')).eval()
print output[0]
for i in range(0,9):
    if max(output[0]) == output[0][i]:
        next_move[i] = 3

print next_move

Je vais vous expliquer un peu. Veuillez le lire en correspondance avec (1), (2) ... dans le code. En principe, 〇 est "1", × est "2" et la cellule vide est "0". (Il est différent du code ruby utilisé pour créer les données d'enseignement. Désolé pour l'incompréhension.)

(1) Réglage de la valeur de sortie La valeur à prendre comme valeur de sortie. J'utilise 0,1,2 pour l'entrée, j'ai donc décidé d'utiliser 3 pour la sortie. (2) Conversion d'échecs Correspond au score d'échecs lu à l'entrée et à la sortie du réseau neuronal. Par exemple, si l'entrée du score est "6,8,3,4,2,0, perdez", l'expansion sera la suivante.

La musique: 6,8,3,4,2,0,lose
X[n]   = [0,0,0,0,0,0,1,0,0]  : "6"Dans la position de"〇"C'est"1"Entrer
y[n]   = [0,0,0,0,0,0,0,0,3]  :Prochaine étape"8"Dans la position de"×"Alors"8"Dans la position de"3"Les sorties
X[n+1] = [0,0,0,1,0,0,1,0,2]  : "8"Dans la position de"×"C'est"2",prochain"3"Dans la position de"〇"C'est"1"Entrer
y[n+1] = [0,0,0,0,3,0,0,0,0]  :Prochaine étape"4"Dans la position de"×"Alors"4"Dans la position de"3"Les sorties
X[n+2] = [0,0,1,1,2,0,1,0,2]  : "4"Dans la position de"×"C'est"2",prochain"2"Dans la position de"〇"C'est"1"Entrer
y[n+2] = [3,0,0,0,0,0,0,0,0]  :Prochaine étape"0"Dans la position de"×"Alors"0"Dans la position de"3"Les sorties

(3) Description de la structure MLP La couche cachée h0 est générée avec dim (dimension) = 9 (nombre de carrés) en utilisant la fonction sigmoïde comme fonction d'activation. irange et init_bias conviennent. La couche de sortie out est générée avec n_classes (nombre de classifications) = 9 (nombre de cellules) en utilisant la fonction softmax comme fonction d'activation. irange convient. [Méthode de descente de gradient probabiliste](https://ja.wikipedia.org/wiki/%E7%A2%BA%E7%8E%87%E7%9A%84%E5%8B%BE%E9%85%8D Entraîner avec% E9% 99% 8D% E4% B8% 8B% E6% B3% 95). learning_rate et batch_size sont appropriés. terminaison_criterion spécifie quand terminer la formation.

ann = mlp.MLP(layers, nvis=9)

Ce qui précède spécifie la structure de MLP. nvis a une dimension d'entrée = 9 (nombre de carrés). (4) Formation C'est une boucle d'entraînement. Nous avons également un suivi des progrès. (5) Test Testez à quoi ressemble la sortie pour certaines entrées. La partie avec la probabilité la plus élevée (sortie [0]) de 9 classes est le prochain mouvement (next_move).

La sortie lorsque le programme est exécuté est la suivante.

$ python tic_tac_toe.py
Parameter and initial learning rate summary:
	h0_W: 0.05
	h0_b: 0.05
	softmax_b: 0.05
	softmax_W: 0.05
Compiling sgd_update...
Compiling sgd_update done. Time elapsed: 0.203131 seconds
compiling begin_record_entry...
compiling begin_record_entry done. Time elapsed: 0.003911 seconds
Monitored channels: 
Compiling accum...
Compiling accum done. Time elapsed: 0.000039 seconds
Monitoring step:
	Epochs seen: 1
	Batches seen: 3
	Examples seen: 542
Monitoring step:
	Epochs seen: 2
	Batches seen: 6
	Examples seen: 1084

...

Monitoring step:
	Epochs seen: 5000
	Batches seen: 15000
	Examples seen: 2710000
Monitoring step:
	Epochs seen: 5001
	Batches seen: 15003
	Examples seen: 2710542
[ 0.07985083  0.10700001  0.00255253  0.15781951  0.08504663  0.16470689
  0.11459433  0.12293593  0.16549335]
[0, 0, 0, 0, 0, 0, 0, 0, 3]
[  2.56981722e-03   1.25923571e-01   2.05250923e-04   6.14268028e-04
   1.85819252e-02   2.43921569e-02   8.27328217e-01   3.84348076e-04
   4.45556802e-07]
[0, 0, 0, 0, 0, 0, 3, 0, 0]

De ce qui précède, Si l'entrée est [0,0,1,0,0,0,0,0,0], le mouvement suivant est [0,0,0,0,0,0,0,0,3]. En d'autres termes, l'IA frappe comme le montre la figure ci-dessous. example01.png

Si l'entrée est [1,0,2,1,0,0,0,1,2], le mouvement suivant est [0,0,0,0,0,0,3,0,0]. En d'autres termes, l'IA frappe comme le montre la figure ci-dessous. example02.png

Eh bien, si vous frappez "X" à la position "5", vous gagnez et vous avez terminé, mais vous allez arrêter la portée de "O". Eh bien, c'est correct pour le fait qu'il soit basé sur un score aléatoire.

C'est un peu ennuyeux parce que je dois jouer avec le code source à chaque fois, mais j'ai le prochain mouvement pour une entrée arbitraire.

À l'avenir, sur la base des résultats d'un entraînement, je faciliterai l'obtention du prochain coup pour n'importe quelle entrée et l'implémenterai dans un jeu à trois yeux. Tout d'abord, je dois créer un programme de jeu d'affilée. **J'ai fait. Veuillez consulter l'article suivant. ** ** Faisons une IA de troisième ordre avec Pylearn2 --Save and load model-

référence

http://www.arngarden.com/2013/07/29/neural-network-example-using-pylearn2/ [http://sinhrks.hatenablog.com/entry/2014/11/30/085119] (http://sinhrks.hatenablog.com/entry/2014/11/30/085119) https://www.safaribooksonline.com/blog/2014/02/10/pylearn2-regression-3rd-party-data/

Recommended Posts

Faisons une IA à trois yeux avec Pylearn 2
Créons une IA à trois voies avec Pylearn2 --Save and load model -
Faisons une interface graphique avec python.
Faisons une rupture de bloc avec wxPython
Faisons l'IA d'Othello avec Chainer-Part 1-
Faisons un graphe avec python! !!
Faisons un spacon avec xCAT
Faisons l'IA d'Othello avec Chainer-Part 2-
Faisons la voix lentement avec Python
Créez un framework Web avec Python! (1)
Faisons un bot Twitter avec Python!
Créez un framework Web avec Python! (2)
Remplaçons UWSC par Python (5) Faisons un robot
Faisons un robot Discord.
[Jouons avec Python] Créer un livre de comptes de ménage
Faisons Othello avec wxPython
Essayez de créer un jeu simple avec Python 3 et iPhone
Créez Puyopuyo AI avec Python
Faites une loterie avec Python
Essayez de créer une grille sphérique avec Rhinoceros / Grasshopper / GHPython
[Super facile] Faisons un LINE BOT avec Python.
Faire un feu avec kdeplot
Créons un client de socket Web avec Python. (Authentification par jeton d'accès)
Faisons un diagramme sur lequel on peut cliquer avec IPython
Faisons une rumba distante [Matériel]
Faisons une rumba distante [Logiciel]
Faites un son avec le notebook Jupyter
Faisons un service de vente au comptant 2
Faisons un service de vente au comptant 1
Créer un système de recommandation avec python
Créer un filtre avec un modèle django
Créer un itérateur de modèle avec PySide
Faire un joli graphique avec plotly
Faisons un service de vente au comptant 3
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 1
Faisons un ordinateur de vélo avec Raspberry Pi Zero (W, WH)
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 2
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 3
Faisons une application WEB pour l'annuaire téléphonique avec flacon Partie 4
Faisons une discussion WEB en utilisant WebSocket avec AWS sans serveur (Python)!
Créer un lecteur vidéo avec PySimpleGUI + OpenCV
Créons un groupe gratuit avec Python
Créez un simulateur de gacha rare avec Flask
Créez un pipeline de notebook avec Kedro + Papermill
[Facile] Reconnaissance automatique AI avec une webcam!
Faire une figure partiellement zoomée avec matplotlib
Raclons un site dynamique avec Docker
Créez un quiz de dessin avec kivy + PyTorch
Créez un classificateur en cascade avec Google Colaboratory
[Python] Rendons matplotlib compatible avec le japonais
Faire un circuit logique avec Perceptron (Perceptron multicouche)
Faire Oui Non Popup avec Kivy
Faisons un site multilingue en utilisant flask-babel
Faire une minuterie de lavage-séchage avec Raspberry Pi
Créer une animation GIF avec surveillance des dossiers
Faisons un calcul de combinaison avec Python
Créez une application de bureau avec Python avec Electron
Faisons un plug-in backend pour Errbot