[PYTHON] Spielen Sie, um den Rennwert vorherzusagen und geben Sie den Pokemon-Namen in TensorFlow ein

Neulich ging ich als Moderator zu TensorFlow Study Group. Die Leute um mich herum fragten mich, ob ich nichts über den Inhalt der Lernsitzung schreiben würde, aber ich hatte Angst vor der Anzahl der Leute Ankündigung, dass niemand glücklich sein würde ), Also werde ich stattdessen das tote Material verbrauchen, das ich ursprünglich verwenden wollte.

Ziel

Was Sie tun möchten, ist sehr einfach, wie der Titel schon sagt. Wenn Sie den Namen des Pokémon eingeben, möchte ich, dass Sie den Rassenwert und die typähnliche Sache sehen. Es fühlt sich so an, als würde ich etwas ausprobieren, was bei Twitter-Diagnostikern oft der Fall ist.

Modelldesign

Details eingeben

Wir haben den Pokemon-Namen Zeichen für Zeichen zerlegt und die Anzahl der Vorkommen jedes Zeichens und 2 Gramm als Merkmalsmenge verwendet. Zum Beispiel im Fall von Dedenne:

{
De: 2,Nieder: 1,Ne: 1,
Dede: 1,Den: 1,Nne: 1
}

Das Erstellen von n-Gramm-Funktionen selbst ist mühsam, aber die Verwendung von scikit-learns Vectorizer 2, 3 Sie können n-Gramm-Funktionen erstellen, während Sie detaillierte Einstellungen in Zeilen vornehmen. Sie können problemlos einen Vektorisierer speichern, in dem alle erforderlichen Informationen gespeichert sind. Daher wird Ultra Super Miracle empfohlen. Wenn Sie keine Tugend sammeln müssen, um sich auf die nächste Welt vorzubereiten, oder wenn besondere Umstände vorliegen, sollten Sie sie auf jeden Fall nutzen.

Ausgabedetails

Die Ausgabe ist etwas umständlich und muss grob in die folgenden drei Ausgaben unterteilt werden.

Sie können für jedes Modell ein Modell erstellen und Vorhersagen treffen, aber die Flexibilität, alles zusammen zu packen, ist die Stärke des neuronalen Netzes (ich persönlich denke, das ist es). Deshalb habe ich versucht, alles in einem Netzwerk zusammenzufassen. T. Mit anderen Worten, das ist es.

graph.png

Die Anzahl der Einheiten in der letzten Ebene beträgt 6 + 18 + 19. Der Teil, der dem Rennwert entspricht, wurde so ausgegeben, wie er war, und der Verlust wurde durch den quadratischen Fehler definiert. Die Ausgabe entspricht 18 oder 19 Typen, von denen jeder in Softmax verschoben wird, und der Verlust wird durch jede Kreuzentropie definiert. Die endgültige Zielfunktion ist die gewichtete Addition dieser Verluste.

Datensammlung

~~ Es handelt sich nicht um vertrauliche Daten. Wenn Sie also Ihr Bestes geben, werden Sie zusammenkommen. Bitte geben Sie Ihr Bestes. ~~ Nur die verwendeten Daten wurden mit dem Code (https://github.com/sfujiwara/pn2bs) [auf GitHub hochgeladen].

Der fertige Code

# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.externals import joblib
from sklearn.feature_extraction import DictVectorizer


def inference(x_placeholder, n_in, n_hidden1, n_hidden2):
    """
    Description
    -----------
    Forward step which build graph.

    Parameters
    ----------
    x_placeholder: Placeholder for feature vectors
    n_in: Number of units in input layer which is dimension of feature
    n_hidden1: Number of units in hidden layer 1
    n_hidden2: Number of units in hidden layer 2

    Returns
    -------
    y_bs: Output tensor of predicted values for base stats
    y_type1: Output tensor of predicted values for type 1
    y_type2: Output tensor of predicted values for type 2
    """
    # Hidden1
    with tf.name_scope('hidden1') as scope:
        weights = tf.Variable(
            tf.truncated_normal([n_in, n_hidden1]),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([n_hidden1]))
        hidden1 = tf.nn.sigmoid(tf.matmul(x_placeholder, weights) + biases)

    # Hidden2
    with tf.name_scope('hidden2') as scope:
        weights = tf.Variable(
            tf.truncated_normal([n_hidden1, n_hidden2]),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([n_hidden2]))
        hidden2 = tf.nn.sigmoid(tf.matmul(hidden1, weights) + biases)

    # Output layer for base stats
    with tf.name_scope('output_base_stats') as scope:
        weights = tf.Variable(
            tf.truncated_normal([n_hidden2, 6]),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([6]))
        y_bs = tf.matmul(hidden2, weights) + biases

    # Output layer for type1
    with tf.name_scope('output_type1') as scope:
        weights = tf.Variable(
            tf.truncated_normal([n_hidden2, 18]),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([18]))
        # y_type1 = tf.nn.softmax(tf.matmul(hidden2, weights) + biases)
        y_type1 = tf.matmul(hidden2, weights) + biases

    # Output layer for type2
    with tf.name_scope('output_type2') as scope:
        weights = tf.Variable(
            tf.truncated_normal([n_hidden2, 19]),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([19]))
        y_type2 = tf.matmul(hidden2, weights) + biases
        # y_type2 = tf.nn.softmax(tf.matmul(hidden2, weights) + biases)

    return [y_bs, y_type1, y_type2]


def build_loss_bs(y_bs, t_ph_bs):
    """
    Parameters
    ----------
    y_bs: Output tensor of predicted values for base stats
    t_ph_bs: Placeholder for base stats

    Returns
    -------
    Loss tensor which includes placeholder of features and labels
    """
    loss_bs = tf.reduce_mean(tf.nn.l2_loss(t_ph_bs - y_bs), name='LossBaseStats')
    return loss_bs


def build_loss_type1(y_type1, t_ph_type1):
    """
    Parameters
    ----------
    y_type1: Output tensor of predicted values for base stats
    t_ph_type1: Placeholder for base stats

    Returns
    -------
    Loss tensor which includes placeholder of features and labels
    """
    loss_type1 = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(y_type1, t_ph_type1),
        name='LossType1'
    )
    return loss_type1


def build_loss_type2(y_type2, t_ph_type2):
    """
    Parameters
    ----------
    y_type2: Output tensor of predicted values for base stats
    t_ph_type2: Placeholder for base stats

    Returns
    -------
    Loss tensor which includes placeholder of features and labels
    """
    loss_type2 = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(y_type2, t_ph_type2),
        name='LossType2'
    )
    return loss_type2


def build_optimizer(loss, step_size):
    """
    Parameters
    ----------
    loss: Tensor of objective value to be minimized
    step_size: Step size for gradient descent

    Returns
    -------
    Operation of optimization
    """
    optimizer = tf.train.GradientDescentOptimizer(step_size)
    global_step = tf.Variable(0, name='global_step', trainable=False)
    train_op = optimizer.minimize(loss, global_step=global_step)
    return train_op


if __name__ == '__main__':
    # Set seed
    tf.set_random_seed(0)

    # Load data set and extract features
    df = pd.read_csv('data/poke_selected.csv')

    # Fill nulls in type2
    df.loc[df.type2.isnull(), 'type2'] = 'Nichts'

    # Vectorize pokemon name
    pokename_vectorizer = CountVectorizer(analyzer='char', min_df=1, ngram_range=(1, 2))
    x = pokename_vectorizer.fit_transform(list(df['name_jp'])).toarray()
    t_bs = np.array(df[['hp', 'attack', 'block', 'contact', 'defense', 'speed']])

    # Vectorize pokemon type1
    poketype1_vectorizer = DictVectorizer(sparse=False)
    d = df[['type1']].to_dict('record')
    t_type1 = poketype1_vectorizer.fit_transform(d)

    # Vectorize pokemon type2
    poketype2_vectorizer = DictVectorizer(sparse=False)
    d = df[['type2']].to_dict('record')
    t_type2 = poketype2_vectorizer.fit_transform(d)

    # Placeholders
    x_ph = tf.placeholder(dtype=tf.float32)
    t_ph_bs = tf.placeholder(dtype=tf.float32)
    t_ph_type1 = tf.placeholder(dtype=tf.float32)
    t_ph_type2 = tf.placeholder(dtype=tf.float32)

    # build graph, loss, and optimizer
    y_bs, y_type1, y_type2 = inference(x_ph, n_in=1403, n_hidden1=512, n_hidden2=256)
    loss_bs = build_loss_bs(y_bs, t_ph_bs)
    loss_type1 = build_loss_type1(y_type1, t_ph_type1)
    loss_type2 = build_loss_type2(y_type2, t_ph_type2)
    loss = tf.add_n([1e-4 * loss_bs, loss_type1, loss_type2], name='ObjectiveFunction')
    optim = build_optimizer(loss, 1e-1)

    # Create session
    sess = tf.Session()

    # Initialize variables
    init = tf.initialize_all_variables()
    sess.run(init)

    # Create summary writer and saver
    summary_writer = tf.train.SummaryWriter('log', graph_def=sess.graph_def)
    tf.scalar_summary(loss.op.name, loss)
    tf.scalar_summary(loss_bs.op.name, loss_bs)
    tf.scalar_summary(loss_type1.op.name, loss_type1)
    tf.scalar_summary(loss_type2.op.name, loss_type2)
    summary_op = tf.merge_all_summaries()
    saver = tf.train.Saver()

    # Run optimization
    for i in range(1500):
        # Choose indices for mini batch update
        ind = np.random.choice(802, 802)
        batch_xs = x[ind]
        batch_ts_bs = t_bs[ind]
        batch_ts_type1 = t_type1[ind]
        batch_ts_type2 = t_type2[ind]
        # Create feed dict
        fd = {
            x_ph: batch_xs,
            t_ph_bs: batch_ts_bs,
            t_ph_type1: batch_ts_type1,
            t_ph_type2: batch_ts_type2
        }
        # Run optimizer and update variables
        sess.run(optim, feed_dict=fd)
        # Show information and write summary in every n steps
        if i % 100 == 99:
            # Show num of epoch
            print 'Epoch:', i + 1, 'Mini-Batch Loss:', sess.run(loss, feed_dict=fd)
            # Write summary and save checkpoint
            summary_str = sess.run(summary_op, feed_dict=fd)
            summary_writer.add_summary(summary_str, i)
            name_model_file = 'model_lmd1e-4_epoch_' + str(i+1) + '.ckpt'
            save_path = saver.save(sess, 'model/tensorflow/'+name_model_file)
    else:
        name_model_file = 'model_lmd1e-4_epoch_' + str(i+1) + '.ckpt'
        save_path = saver.save(sess, 'model/tensorflow/'+name_model_file)

    # Show example
    poke_name = 'Donner'
    v = pokename_vectorizer.transform([poke_name]).toarray()
    pred_bs = sess.run(y_bs, feed_dict={x_ph: v})
    pred_type1 = np.argmax(sess.run(y_type1, feed_dict={x_ph: v}))
    pred_type2 = np.argmax(sess.run(y_type2, feed_dict={x_ph: v}))
    print poke_name
    print pred_bs
    print pred_type1, pred_type2
    print poketype1_vectorizer.get_feature_names()[pred_type1]
    print poketype2_vectorizer.get_feature_names()[pred_type2]

    # Save vectorizer of scikit-learn
    joblib.dump(pokename_vectorizer, 'model/sklearn/pokemon-name-vectorizer')
    joblib.dump(poketype1_vectorizer, 'model/sklearn/pokemon-type1-vectorizer')
    joblib.dump(poketype2_vectorizer, 'model/sklearn/pokemon-type2-vectorizer')

Lass mich lernen

Das bedeutet nicht, dass das Material ernsthaft abgestimmt ist, weil es ein Material ist. Deshalb habe ich mir TensorBoard angesehen, um festzustellen, ob der Verlust beim Mindesttyp und der Verlust beim Rennwert in ausgewogener Weise verringert wurden.

Versuche zu spielen

Laden wir das Modell und spielen wir so damit.

# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.externals import joblib
import pn2bs


# Placeholder
x_ph = tf.placeholder(dtype=tf.float32)
t_ph = tf.placeholder(dtype=tf.float32)

y_bs, y_type1, y_type2 = pn2bs.inference(x_ph, n_in=1403, n_hidden1=512, n_hidden2=256)

# Create session
sess = tf.Session()

# Load TensorFlow model
saver = tf.train.Saver()
saver.restore(sess, "model/tensorflow/model_lmd1e-4_epoch_1500.ckpt")

# Load vectorizer of scikit-learn
pokename_vectorizer = joblib.load("model/sklearn/pokemon-name-vectorizer")
poketype1_vectorizer = joblib.load("model/sklearn/pokemon-type1-vectorizer")
poketype2_vectorizer = joblib.load("model/sklearn/pokemon-type2-vectorizer")

poke_name = 'Gonzales'
v = pokename_vectorizer.transform([poke_name]).toarray()
pred_bs = sess.run(y_bs, feed_dict={x_ph: v})
pred_type1 = np.argmax(sess.run(y_type1, feed_dict={x_ph: v}))
pred_type2 = np.argmax(sess.run(y_type2, feed_dict={x_ph: v}))
result = {
    'name'   : poke_name,
    'hp'     : pred_bs[0][0],
    'attack' : pred_bs[0][1],
    'block'  : pred_bs[0][2],
    'contact': pred_bs[0][3],
    'defense': pred_bs[0][4],
    'speed'  : pred_bs[0][5],
    'type1'  : poketype1_vectorizer.get_feature_names()[pred_type1],
    'type2'  : poketype2_vectorizer.get_feature_names()[pred_type2],
}
print result['name']
print result['hp']
print result['attack']
print result['block']
print result['contact']
print result['defense']
print result['speed']
print result['type1']
print result['type2']

Ein Beispiel für das Ergebnis. Es gibt nichts Besonderes zu sagen, aber bitte raten Sie etwas über jeden.

Name H A B C D S Type 1 Type 2
Tensolfluss 92 102 84 85 65 73 Fee böse
Mega Pikachu 74 80 50 97 85 80 Elektrisch Nichts
Gonzales 81 103 107 86 103 65 Drachen Elektrisch
Mega Gonzales 100 137 131 118 117 103 Drachen böse

Zukünftige Ausgaben (um nicht zu sagen, dass wir daran arbeiten werden)

Zusammenfassung

Ich fand die Flexibilität der Modellierung großartig, weil das neuronale Netz der Taube mit aller Kraft die guten Eigenschaften der Konvexität und Funktionen wegwirft. Wenn Sie beispielsweise versuchen, dasselbe mit SVM zu tun, werden Sie sich zunächst nicht mehr fragen, was zu tun ist, wenn Sie nach mehrdimensionalen Ausgaben wie Rennwerten gefragt werden, und sogar das Klassifizierungsproblem in Bezug auf Typen gemeinsam lösen. An dem Tag, an dem mir gesagt wurde, ich sollte schlafen und Schlaf sagen. Wenn es jedoch darum geht, die 2 Outs im unteren Bereich des 9. Innings dem neuronalen Netz zu überlassen, fühlt es sich wie hmm an. so ähnlich.

Nachtrag

2016-01-26

Es tut mir ein wenig leid, dass ich es nicht in einem Zustand veröffentlicht habe, in dem ich es richtig ausprobieren kann, obwohl es Leute gibt, die es immer noch von Zeit zu Zeit auf Lager haben. Deshalb habe ich etwas gepostet, das [auf GitHub] funktioniert (https: / /github.com/sfujiwara/pn2bs). Ich dachte, es wäre cool, eine Radarkarte mit Google Charts oder etwas entsprechend dem eingegebenen Namen zu erstellen, aber ich wollte den Bot darauf treffen lassen, also habe ich daraus eine Web-API gemacht.

Ich denke, dass es wahrscheinlich herauskommen wird, wenn ich versuche, es zu verwenden. Wenn ich es also zuerst gestehe, wenn ich ein vorhandenes Pokemon einsetze, wird es verdorren, wenn der Status völlig anders ist als der tatsächliche, also habe ich absichtlich ein Modell übernommen, das überlernt zu sein scheint.

Recommended Posts

Spielen Sie, um den Rennwert vorherzusagen und geben Sie den Pokemon-Namen in TensorFlow ein
Prognostizieren Sie das Geschlecht anhand des Namens mithilfe der Gender-API und von Pykakasi in Python
[How to!] Lerne und spiele Super Mario mit Tensorflow !!
Ausländer sprechen: Wie man Klassen und Methoden auf Englisch benennt
Lesen Sie json mit C # und konvertieren Sie es in den Wörterbuchtyp (erzwungen)
Clipping und Normalisierung in TensorFlow
[Python] Drücken Sie Keras von TensorFlow und TensorFlow von c ++, um die Ausführung zu beschleunigen.
Was tun, wenn der Werttyp in Python nicht eindeutig ist?