[PYTHON] Stärkste Pokemon-Generation mit LSTM

Motivation

In der Zeitung, die ich zuvor gelesen habe, gab es eine interessante Arbeit mit dem Titel ** Reproduktion von Tonsymbolen durch maschinelles Lernen: Erzeugung des stärksten Pokémon **. Ich habe es selbst unter Bezugnahme auf dieses Papier arrangiert und es für die Seminarpräsentation verwendet, also werde ich es veröffentlichen. Ich habe es mit ein wenig Energie gemacht, also habe ich es gepostet, weil ich es nach außen werfen wollte.

Normalerweise beschäftige ich mich mit Bildsystemen, und da die Verarbeitung natürlicher Sprache ein Amateur- und erster Beitrag ist, denke ich, dass es viele Punkte gibt, die nicht erreicht werden können, aber bitte verzeihen Sie mir. * In der Seminarpräsentation verwendeter Materiallink

Was ist diesmal zu tun?

Dieses Mal wollen wir unter Bezugnahme auf die Ideen in den folgenden Abhandlungen versuchen, das stärkste Pokémon mit derselben Methode zu erzeugen und gleichzeitig den Akzent des tiefen Lernens (LSTM) zu setzen. In der Arbeit wurde der Fragebogen verwendet, um den Eindruck von Klang zu quantifizieren. Da wir jedoch keine solchen Daten haben, werden wir stattdessen den Rennwert verwenden.

Reproduktion von Tonsymbolen durch maschinelles Lernen: Erzeugung des stärksten Pokémon Satoshi Miura ∗ 1 Masaki Murata ∗ 1 Sho Yasuda ∗ 2 Mai Miyabe ∗ 2 Eiji Aramaki ∗ 2 ∗ 1 Tottori University Graduate School * 2 Proceedings of the 18. Jahrestagung der Language Processing Society der Universität (März 2012) http://luululu.com/paper/2012/C1-1.pdf

Umriss des Originalpapiers (3 Zeilen)

・ Prognostizieren Sie die Stärke von Pokemon durch Paarvergleich mit 8 Probanden (die Pokemon nicht kennen).

Datenvorverarbeitung

Nutzungsdaten

Die diesmal verwendeten Daten sind die Tabellendaten von Pokemon bis zur 7. Generation. Da der Name eines Pokémon bis zu 6 Zeichen lang sein kann, löschen Sie den Wert eines Pokémon (Landros Beast, Jigarde 10% usw.), dessen Name länger ist. Außerdem wurde diesmal auch Mega Evolution Pokemon ausgeschlossen.

Pokemon-Daten werden über den unten stehenden Link ausgeliehen.

https://rikapoke.hatenablog.jp/entry/pokemon_datasheet_gne7

import pandas as pd
status = pd.read_csv("pokemon_status.csv", encoding="shift_jis")
status

Diesmal behandelte CSV-Daten ↓ スクリーンショット 2020-11-07 17.54.24.png

Wir werden dem eine Vorbehandlung hinzufügen.

#Entfernung von extra Mega Pokemon
status = status[~status['Bilderbuchnummer'].str.contains('-')]
status
#Pokemon entfernt, dessen Name 7 oder länger ist
status['len'] = status['Pokemon Name'].map(lambda x: len(x))
de = status[status['len']>6]
status = status[status['len']<7]
de
#Für Daten nur verwendete Daten
status = status.loc[:, ['Pokemon Name','gesamt']]
status

Vervollständigung der diesmal verwendeten Daten! スクリーンショット 2020-11-07 18.00.59.png

Von hier aus werden wir die Vorbehandlung fortsetzen, um das LSTM zu füttern.

#tokenize
def function(name):
    n_gram = ''
    for n in name:
        n_gram = n_gram + n + ' '
    return n_gram

status['Pokemon Name'] = status['Pokemon Name'].map(function)
status
#Normalisierung des Rassenwerts& 0or1
from sklearn import preprocessing

def labeling(pred, p=0.5):
    if pred < p:
        pred_label = 0
    else:
        pred_label = 1
    
    return pred_label

status['gesamt'] = preprocessing.minmax_scale(status['gesamt'])
status['gesamt'] = status['gesamt'].map(labeling)
status

Daten nach Vorverarbeitung ↓ スクリーンショット 2020-11-07 18.07.12.png

Klassifizieren Sie die erstellten Daten in Zug und Wert und speichern Sie sie.

from sklearn.model_selection import train_test_split

train_df, val_df = train_test_split(status, random_state=1234, test_size=0.2)
train_df.to_csv("./train_df.tsv", sep='\t')
val_df.to_csv("./val_df.tsv", sep='\t')

Ein Modell bauen

Da ich ein Pytorch-Gläubiger bin, werde ich ein Modell mit Fackel bauen und den Code kurz vorstellen. Der vollständige Code ist unter dem folgenden Link verfügbar. Wenn Sie interessiert sind, beziehen Sie sich bitte darauf.

https://github.com/drop-ja/pokemon

from torchtext import data
import torchtext

batch_size = 4
max_len = 6

#Tokenize-Methode
tokenizer = lambda x: x.split()

#Etiketteninformationen usw.
TEXT = data.Field(sequential=True, tokenize=tokenizer, include_lengths=True, 
                 batch_first=True, fix_length=max_len)
LABEL = data.LabelField()

fields_train = [('id', None), ('name', TEXT), ('bs', LABEL)]

dataset_train, dataset_valid = data.TabularDataset.splits(
                             path = './',
                             format='TSV',
                             skip_header=True, 
                             train="train_df.tsv",
                             validation="val_df.tsv", 
                             fields=fields_train)
TEXT.build_vocab(dataset_train)
LABEL.build_vocab(dataset_train)

train_iter = data.BucketIterator(dataset=dataset_train, batch_size=batch_size, 
                                 sort_key=lambda x: len(x.name), repeat=False, shuffle=True)
val_iter = data.BucketIterator(dataset=dataset_valid, batch_size=1, 
                                 sort_key=lambda x: len(x.name), repeat=False, shuffle=False)
#Modelldefinition
import torch
import torch.nn as nn
import torch.nn.init as init
import torch.optim as optim
import torch.nn.functional as F

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class LSTMPVClassifier(nn.Module):
    def __init__(self, vocab_size, embedding_dim, lstm_hidden_size,  mlp_hidden_size, output_size):
        super(LSTMPVClassifier, self).__init__()
        self.lstm_hidden_size = lstm_hidden_size
   
        self.embed = nn.Embedding(vocab_size, embedding_dim, padding_idx=1)
        self.lstm = nn.LSTM(embedding_dim, self.lstm_hidden_size, batch_first=True, 
                        num_layers=1, bidirectional=False, dropout=0.0)
    
        self.fc1 = nn.Linear(self.lstm_hidden_size, mlp_hidden_size)
        self.fc2 = nn.Linear(mlp_hidden_size, output_size)
    
    def forward(self, x):
        b_size = x.size(0) #Chargengröße
        seq_len  = x.size(1) #Pokemon Namenslänge

        x = self.embed(x)
        h0 = torch.zeros(1, b_size, self.lstm_hidden_size).to(device)
        c0 = torch.zeros(1, b_size, self.lstm_hidden_size).to(device)
  
        lstm_output_seq, (h_n, c_n) = self.lstm(x, (h0, c0))
   
        out = torch.relu(self.fc1(lstm_output_seq))
        out = torch.sigmoid(self.fc2(out)) 

        return out

Ergebnis

Hier ist das Ergebnis der 10. Epoche mit dem obigen Modell. "Total" ist das richtige Antwortetikett und "Predicted Value" ist das vom Modell vorhergesagte Ergebnis.

スクリーンショット 2020-11-07 18.19.30.png

So zeigen Sie den F-Wert des obigen Ergebnisses an. Für das richtig modellierte Modell wird ein ziemlich guter Wert zurückgegeben.

スクリーンショット 2020-11-07 18.21.24.png

Spielen Sie mit dem generierten Modell

Ich habe einen Namen eingegeben und damit gespielt. Ich habe die Namen der Labormitglieder eingegeben und sie eingestuft, und es war ziemlich aufregend, nur damit zu spielen.

スクリーンショット 2020-11-07 18.25.41.png

Code unten

#Datensatz
#Überprüfen Sie den konvertierten Wert
def to_dataset(list_obj, pri=True):
    index = pd.DataFrame(list_obj)
    index[0] = index[0].map(function)
    index.to_csv('./test.tsv', sep='\t')
    
    fields_test = [('id', None), ('name', TEXT)]
    dataset_test = data.TabularDataset(path='./test.tsv',
                             format='TSV', skip_header=True, fields=fields_test)
    
    test_iter = data.BucketIterator(dataset=dataset_test, batch_size=1, 
                                 sort_key=lambda x: len(x.name), repeat=False, shuffle=False)
    
    batch = next(iter(test_iter))
    
    if pri:
        print(batch.name)
    
    return test_iter

list_obj = ['Denshi Wasserkocher', 'Gagigugego', 'Mikrowelle', 'Bratpfanne', 'Jisaboke', 'Pokémon']
test_iter = to_dataset(list_obj)
def result_show(test_iter, pri=True):
    test_predicted = []
    
    for batch in test_iter:
        text = batch.name[0]
        text = text.to(device)
        outputs = eval_net(text)
        outputs = outputs[:, -1]
        tmp_pred_label = outputs.to('cpu').detach().numpy().copy()
        test_predicted.extend(tmp_pred_label[0])
    
    if pri:
        print(test_predicted)
    
    return test_predicted
        
result = result_show(test_iter)

df = pd.DataFrame(list_obj, columns=['Name'])
df['Voraussichtlicher Wert'] = result
df['0,1 Etikett'] = labeling(df['Voraussichtlicher Wert'])
df

Generiere das stärkste Pokémon

Endlich das Thema dieser Zeit.

Die stärkste Pokemon-Generierungsmethode folgt dem Papier und wird nach derselben Methode generiert.

** Papiermethode ** --Wählen Sie eine Probe entsprechend aus --Ersetzen Sie ein Zeichen nach dem Zufallsprinzip --Vergleichen Sie mit dem ersetzten Namen und Modell --Loop die obigen 3 Schritte 50 Mal

In der Arbeit wurde es aus "Parasect" und "Nidoquin" generiert, also werde ich es verfolgen. Der Code unten.

def generate_pokemon(string):
    history = []
    score = []
    history.append(string)
    
    for i in range(50):
        changed_string = change_name(string, 1)
        cd_result = result_show(to_dataset([string, changed_string], False), False)
        
        #Nur am Anfang hinzufügen
        if i ==0:
            score.append(cd_result[0])
            
        if cd_result[0] > cd_result[1]:
            score.append(cd_result[0])
        else:
            string = changed_string
            score.append(cd_result[1])
            
        history.append(string)
        
    cd_df = pd.DataFrame(history, columns=['Name'])
    cd_df['Voraussichtlicher Wert'] = score
    
    return string, cd_df


string = 'Parasect'
saikyou, port = generate_pokemon(string)

print('Stärkster Name: ', saikyou)
pd.DataFrame(port)

Generationsergebnis aus Parasit (Prozess 10/50) スクリーンショット 2020-11-07 18.35.14.png

Das Endergebnis ist "Egineo". Da die Zeichen zufällig ausgetauscht werden, war es interessant, dass sich das Ergebnis jedes Mal änderte, wenn ich es drehte, und ich drehte es viele Male. Es macht Spaß, sich zu bewegen, während Sie die Ergebnisse auf diese Weise überprüfen.

Auch ich habe diesmal Pokemon verwendet, aber es scheint interessant, dies mit dem Namen des Ramen-Shops und der Auswertung des Essensprotokolls zu tun.

Recommended Posts

Stärkste Pokemon-Generation mit LSTM
[LSTM-Satzgenerierung] Verwenden Sie ml5js
Aktienkursprognose mit LSTM_1
Automatisierung der Algorithmusgenerierung mit genetischen Algorithmen
[PyTorch] Japanische Satzgenerierung mit Transformer