[PYTHON] Ich habe ein wenig über die wachsende API von TensorFlow nachgedacht

Intro

Schließlich wurde TensorFLow 1.0 auf dem TensorFlow Dev Summit angekündigt. Es ist die Rede von einer Testversion des Graph Compilers XLA, aber ich persönlich habe mich gefragt, wie die API-Konfiguration (Application Programming Interface) von TensorFlow aussehen würde.

(Auszug aus dem Google Developers Blog "Ankündigung von TensorFlow 1.0".)

  • Higher-level API modules tf.layers, tf.metrics, and tf.losses - brought over from tf.contrib.learn after incorporating skflow and TF Slim

Vor kurzem hatte ich erwartet, dass Version 1.0 sehen würde, wie die High-Level-API, die viel Ärger gezeigt hatte, organisiert sein würde, also habe ich die Situation ein wenig untersucht.

Früher CNN-Modellcode

Zuvor habe ich beim Umgang mit dem CNN-Modell (Convolutional Neural Network) in einer Situation, in der es nicht viele High-Level-APIs gab, meine eigene Klasse vorbereitet und wie folgt codiert.

#   my_lib_nn.py
#Zum Beispiel...  Convolution 2-D Layer
class Convolution2D(object):
    '''
      constructor's args:
          input     : input image (2D matrix)
          input_siz ; input image size
          in_ch     : number of incoming image channel
          out_ch    : number of outgoing image channel
          patch_siz : filter(patch) size
          weights   : (if input) (weights, bias)
    '''
    def __init__(self, input, input_siz, in_ch, out_ch, patch_siz, activation='relu'):
        self.input = input      
        self.rows = input_siz[0]
        self.cols = input_siz[1]
        self.in_ch = in_ch
        self.activation = activation
        
        wshape = [patch_siz[0], patch_siz[1], in_ch, out_ch]
                w_cv = tf.Variable(tf.truncated_normal(wshape, stddev=0.1), 
                            trainable=True)
        b_cv = tf.Variable(tf.constant(0.1, shape=[out_ch]), 
                            trainable=True)
        self.w = w_cv
        self.b = b_cv
        self.params = [self.w, self.b]
        
    def output(self):
        shape4D = [-1, self.rows, self.cols, self.in_ch]
        
        x_image = tf.reshape(self.input, shape4D)  # reshape to 4D tensor
        linout = tf.nn.conv2d(x_image, self.w, 
                  strides=[1, 1, 1, 1], padding='SAME') + self.b
        if self.activation == 'relu':
            self.output = tf.nn.relu(linout)
        elif self.activation == 'sigmoid':
            self.output = tf.sigmoid(linout)
        else:
            self.output = linout
        
        return self.output

Die Funktion von "tf.nn.xxx ()" wird als Bibliothek für die Vergabe von Unteraufträgen verwendet, ist jedoch eine Methode zum Erstellen und Verwenden eines Wrappers, die die Verwendung vereinfacht. Es ist einfach, Ihre eigene Bibliothek anzupassen, aber Sie müssen die detaillierte Wartung aus diesem Grund selbst durchführen. (Es ist keine große Bibliothek, aber ...)

Nachdem ich ** Keras ** kannte, entschied ich mich für "Soll ich Keras verwenden?". In Anbetracht der Vertrautheit, der Leichtigkeit des detaillierten Debuggens und der Flexibilität gab es jedoch viele Codierungsstile, die die TensorFlow-Bibliothek direkt verwendeten.

TensorFlow Slim vs. tf.layers

"Slim" stand aus der Sicht des "Thin Tensor Flow Wapper" im Mittelpunkt der Aufmerksamkeit. Es scheint, dass einige Fälle in Qiita aufgegriffen wurden. Der Code zum Klassifizieren von MNIST anhand dieses Codes lautet wie folgt.

import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("../MNIST_data/", one_hot=True)

# Create the model
def my_nn(images, keep_prob):
   net = slim.layers.conv2d(images, 32, [5,5], scope='conv1')
   net = slim.layers.max_pool2d(net, [2,2], scope='pool1')
   net = slim.layers.conv2d(net, 64, [5,5], scope='conv2')
   net = slim.layers.max_pool2d(net, [2,2], scope='pool2')
   net = slim.layers.flatten(net, scope='flatten3')
   net = slim.layers.fully_connected(net, 1024, scope='fully_connected4')
   net = slim.layers.dropout(net, keep_prob)
   net = slim.layers.fully_connected(net, 10, activation_fn=None, 
                                        scope='fully_connected5')
   return net

def inference(x, y_, keep_prob):
    x_image = tf.reshape(x, [-1, 28, 28, 1])
    y_pred = my_nn(x_image, keep_prob)

    slim.losses.softmax_cross_entropy(y_pred, y_)
    total_loss = slim.losses.get_total_loss()
    correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    
    return total_loss, accuracy, y_pred

Das Nueral-Netzwerkmodell kann auf leicht verständliche Weise in einem Kurzcode geschrieben werden. Wie in der Funktion "Inferenz" verwendet, könnte die Verlustfunktion auch mit der schlanken API geschrieben werden. Ich hatte den Eindruck, dass es ziemlich einfach zu bedienen war.

Als nächstes untersuchte ich dieses Mal das von TensorFlow 1.0 vorbereitete Modul ** tf.layers **. Das API-Dokument enthielt eine gute Erklärung, daher habe ich mit Bezug darauf codiert.

** Aus Abb. TensorFlow API-Dokument (Bildauszug) ** Module_tf_layers.png

Wie im Auszug aus der obigen Google-Ankündigung erwähnt, wird ** tf.contrib.layers ** auch im Dokument erwähnt, aber diesmal ist ** tf.layers ** anders. Seien Sie also vorsichtig.

Das Folgende ist der CNN-Code, der ** tf.layers ** verwendet.

import tensorflow as tf
from tensorflow.python.layers import layers
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("../MNIST_data/", one_hot=True)

# Create the model
def my_nn(images, drop_rate):
   net = tf.layers.conv2d(images, 32, [5,5], padding='same', 
                                activation=tf.nn.relu, name='conv1')
   net = tf.layers.max_pooling2d(net, pool_size=[2,2], strides=[2,2], 
                                name='pool1')
   net = tf.layers.conv2d(net, 64, [5,5], padding='same', 
                                activation=tf.nn.relu, name='conv2')
   net = tf.layers.max_pooling2d(net, pool_size=[2,2], strides=[2,2], 
                                name='pool2')
   net = tf.reshape(net, [-1, 7*7*64])
   net = tf.layers.dense(net, 1024, activation=tf.nn.relu, name='dense1')
   net = tf.layers.dropout(net, rate=drop_rate)
   net = tf.layers.dense(net, 10, activation=None, name='dense2')
   return net

def inference(x, y_, keep_prob):
    x_image = tf.reshape(x, [-1, 28, 28, 1])
    drop_rate = 1.0 - keep_prob
    y_pred = my_nn(x_image, drop_rate)
    
    loss = tf.losses.softmax_cross_entropy(y_, y_pred)
    correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    
    return loss, accuracy, y_pred
 

Zuerst begann ich mit dem Slim-Code mit dem Vorurteil, dass es so etwas wie Slim sein würde, aber ich war verwirrt, weil es einen überraschenden Unterschied in den Funktionsspezifikationen gab. (Beachten Sie den Code in der Funktion "my_nn ()".)

Unter der Annahme, dass unterschiedliche Funktionsnamen (max_pool2d <-> max_pooling2d, vollständig_verbunden <-> dicht) als "gemeinsam" akzeptiert werden, waren Feineinstellungen erforderlich, z. B. unterschiedliche Argumentschlüsselwörter und unterschiedliche Argumentstandards. .. Als besonders besorgniserregender Punkt (unverzeihlich) wurde als Dropout-Parameter die Spezifikation, die das Verhältnis "keep_prob" angibt, das den Einfluss der Einheit nach der Verarbeitung verlässt, in die Spezifikation geändert, die das Verhältnis zum Auslassen (Löschen) des Effekts angibt. Das ist der Punkt. (Als Gegenmaßnahme habe ich eine Zeile mit drop_rate = 1.0 --keep_prob eingefügt.) Es kann ein Punkt sein, der nach den" Vorlieben "des Programmierers unterteilt ist, aber ich wollte, dass Sie die Kompatibilität mit der Vergangenheit berücksichtigen ...

Dies bedeutete nicht, dass die TensorFlow-API organisiert und aufgeräumt war, und ich hatte den Eindruck, dass die aktuellen Spezifikationen etwas enttäuschend waren.

Was soll ich machen?

In Anbetracht der obigen Situation werde ich Ihnen einige Optionen geben.

Da sich "Einstellungen" häufig in Details wie Dropout-Parametern (verbleibendes Verhältnis oder Verwerfungsverhältnis) widerspiegeln, ist es meines Erachtens unvermeidlich, sich zu viele Gedanken darüber zu machen, "welches die beste API ist". Dieses Mal konzentrierte ich mich auf CNN-Funktionen, die Bilder verarbeiten, aber angesichts der flexiblen Modellierungsfunktionen von Deep Learning (z. B. RNN- und Generierungsmodelle) waren mir die Details der API (je nach Bedarf) egal. Es kann konstruktiver sein, einer Vielzahl technischer Inhalte zu folgen (während sie ordnungsgemäß verwendet werden).

(Wenn Sie Meinungen oder Ratschläge haben, kommentieren Sie diese bitte.) (Die Programmierumgebung zum Zeitpunkt des Schreibens ist wie folgt: Python 3.5.2, TensorFlow 1.0.0)

Referenzen, Website

Recommended Posts

Ich habe ein wenig über die wachsende API von TensorFlow nachgedacht
Ein bisschen mehr über FIFO
Ich dachte an einen Anfängerkurs über Python, der auf Blockchain-Spielen basiert
Ich habe eine Frage zu Leerzeichen
Nachdem ich die Python-Bibliothek recherchiert hatte, verstand ich ein wenig über ei.info.
Ich habe eine Web-API erstellt
[PyTorch] Ich war ein wenig verloren in torch.max ()
Ich habe ein wenig über die Klasse recherchiert
Python Qiita API Wrapper "qiipy" gemacht
Ich dachte darüber nach, warum Python selbst mit dem Gefühl eines Python-Interpreters notwendig ist
Ein paar süchtig machende Informationen über Cliff, das CLI-Framework
Zeichne ein Diagramm mit Julia ... Ich habe eine kleine Analyse versucht
Ich dachte darüber nach, wie man kostenlos Programmieren lernt.
[Python] [Gracenote Web API] Eine kleine Anpassung von Pygn
Ein Hinweis darauf, was ich gelernt habe, als ich über die Verwendung von pyenv oder virtualenv unter Windows nachdachte
Ich dachte ein wenig nach, weil Trace Plot von Stan's Parameter schwer zu sehen ist
Verändert TensorFlow das Bild des tiefen Lernens? Was ich dachte, nachdem ich ein wenig berührt hatte