[PYTHON] J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow [Partie 2]

J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow et CNN (réseau de neurones convolutifs). Ceci est une suite de l'article "J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow [Partie 1]". Cette fois, je me concentrerai sur la partie apprentissage de TensorFlow dans l'ensemble du processus. Je suis désolé qu'il y ait de nombreuses parties que je ne comprends pas en disant un commentaire: bow_tone1: Continuez vers la Partie 2, qui se concentre sur la partie jugement. 60.Summary01_flow.JPG

Aperçu du processus d'apprentissage

Comme je l'ai expliqué dans la première partie, j'apprends à utiliser TensorFlow. C'est presque le même modèle que le didacticiel TensorFlow Expert Deep MNIST for Experts. Pour obtenir des explications, consultez l'article ["[Explication pour les débutants] Tutoriel TensorFlow Deep MNIST"] Veuillez vous référer à (http://qiita.com/FukuharaYohei/items/0aef74a0411273705512). 10.Summary02_model.JPG

Flux de traitement d'image

1. Changer la taille de l'image

Bien que cela n'apparaisse pas dans la figure «Vue d'ensemble du processus d'apprentissage», la taille de l'image est modifiée en une taille unifiée à l'aide d'OpenCV avant le traitement avec TensorFlow. Comme pour "[Explication pour les débutants] Tutoriel TensorFlow Deep MNIST", 27 pixels carrés est trop petit, donc cette fois il fait 81 pixels carrés. ↓ est une image de référence, mais pour une raison quelconque, la couleur est étrange lorsque vous regardez l'image après le redimensionnement avec TensorBoard (c'est normal lors de l'affichage ...). 70.process01_resize.JPG

En Python, il dit (mettez tout le code derrière):

img = cv2.imread(file_name[0])
img = cv2.resize(img, (FLAGS.image_size, FLAGS.image_size))

2. Processus de pliage de première couche

Dans le processus de convolution de la première couche, le processus de convolution est effectué en utilisant 32 types de filtres avec un carré de 5 pixels. C'est la même chose que "[Explication pour les débutants] Tutoriel TensorFlow Deep MNIST". La fonction d'activation reste ReLU. Pour une explication du processus de convolution, reportez-vous à l'article "[Explication pour les débutants] Introduction au processus de convolution (expliqué dans TensorFlow)". Seule une partie de l'image est introduite dans ↓. Il est caractérisé par le processus de convolution. Dans l'image à l'extrême droite, vous pouvez voir que le nez et la bouche ont disparu, montrant les caractéristiques des yeux. Le filtre n'a pas vraiment de sens. 70.process02_conv01.JPG

3. Processus de mise en commun de la première couche

Dans le processus de regroupement de la première couche, l'image du résultat du pliage de la première couche est regroupée au maximum à 1/3. Étant donné que la taille initiale de l'image était aussi grande que 81, je l'ai changée de 1/2 à 1/3 par rapport à Deep MNIST. Pour plus d'informations sur le pooling, reportez-vous à l'article "[Explication for beginners] Introduction to pooling (expliqué dans TensorFlow)". Si vous regardez l'image, vous pouvez voir qu'elle est rendue rugueuse par la mise en commun maximale. 70.process03_pool01.JPG

4. Processus de pliage de la deuxième couche

Dans le processus de convolution de la deuxième couche, le processus de convolution est effectué en utilisant 4 types de filtres avec 8 pixels carrés. J'ai choisi 8 pixels parce que je pensais que c'était à peu près la taille de mon nez. De plus, j'ai essayé 4 types pour affiner les fonctionnalités (bien que le résultat n'ait pas de sens). Si vous regardez l'image, vous pouvez voir qu'elle a échoué à ce stade. Loin des traits, la plupart ont disparu ... L'image que vous avez prise est-elle mauvaise? 70.process04_conv02.JPG

5. Processus de mise en commun de la deuxième couche

Dans le processus de regroupement de la deuxième couche, l'image du résultat du pliage de la deuxième couche est regroupée au maximum à 1/3. Si vous regardez l'image, vous pouvez voir que nous recherchons des caractéristiques sur les bords. Regardez-vous votre coiffure? 70.process05_pool02.JPG

6. Couche étroitement liée

Le reste est une couche étroitement couplée. Ceci est inchangé par rapport à Deep MNIST, y compris Drop Apt.

Exécution de l'apprentissage

Prêt à courir

La structure des dossiers ressemble à ceci, et les fichiers texte délimités par des tabulations appelés test data test.txt et training data train.txt sont placés dans le dossier «inputs». Cette structure de dossier / fichier peut être modifiée avec les paramètres d'exécution.

inputs 
│  test.txt 
│  train.txt 

Le contenu du fichier est comme l'image, la première colonne est le fichier, la deuxième colonne est 0 ou 1 (0 est Yuki Kashiwagi). Le code de caractère est S-JIS et le code de saut de ligne est CR-LF. 80.text_data.JPG

Exécution de l'apprentissage

python fully_connected_feed.py

Lorsqu'elle est exécutée avec la commande ci-dessus, la progression et le résultat seront affichés comme indiqué dans la figure ci-dessous. 81.Learning.JPG

Les éléments suivants sont fournis en tant que paramètres d'exécution. Implémenté à l'aide de la bibliothèque argparse, qui est un peu expliquée dans l'article "Spécifier les paramètres avec la détection de visage openCV pour améliorer rapidement la précision de détection" Faire.

Paramètres Contenu valeur initiale Remarques
learning_rate Taux d'apprentissage 1e-4 AdamOptimizerのTaux d'apprentissage
batch_size Taille du lot 20 Nous apprendrons les données d'entraînement pour chacun de ces nombres. Bien qu'il y ait peu de données d'entraînement, la valeur initiale est petite en raison du déplacement
input_train_data Données d'entraînement ./inputs/train.txt この値を変えればDonnées d'entraînementのフォルダ・ファイルを指定可能
input_test_data données de test ./inputs/test.txt この値を変えればdonnées de testのフォルダ・ファイルを指定可能
log_dir Répertoire de stockage des journaux /tmp/tensorflow/kashiwagi/logs Répertoire pour enregistrer les paramètres appris et les journaux TensorBoard
image_size Taille de l'image 81 resizeするときの初期Taille de l'image
pool_size Taille de la mise en commun 3 マックスTaille de la mise en commun

Flux de traitement

L'ensemble du processus appelé Computational Graph dans TensorBorad (["[Introduction] TensorFlow Basic Syntax and Concept"](http: // qiita. com / FukuharaYohei / items / 0825c3518d8596c09396 # computational-graph)) est affiché comme indiqué dans la figure ci-dessous. Le déroulement de ce processus se fait en se référant au tutoriel officiel TensorFlow Mechanics 101. 10.Summary03_CGraph_Overview.JPG La figure ci-dessous montre le développement de la partie d'inférence principale. 10.Summary04_CGraph_Inference.JPG

Programme Python

Pièce de modèle (model_deep.py)

Mnist.py de TensorFlow Mechanics 101 Il s'agit de la partie du modèle d'apprentissage créée en référence à (/tutorials/mnist/mnist.py).

import tensorflow as tf

#Balise d'image à envoyer vers TensorBoard
IMAGE_SOURCE = 'source'
IMAGE_FILTER = 'filter'
IMAGE_CONV   = 'conv'
IMAGE_POOL   = 'pool'

#Nombre d'étiquettes d'identification(Cette fois, Yuki Kashiwagi:0,Autres: 1)
NUM_CLASSES       = 2
NUM_OUTPUT_IMAGES = 64
NUM_FILTER1       = 32
NUM_FILTER2       = 4
SIZE_FILTER1      = 5
SIZE_FILTER2      = 8
NUM_FC            = 1024

def inference(images, keep_prob, image_size, pool_size):
    
    with tf.name_scope('inference'):
        #Écart type de poids 0.Défini par un nombre aléatoire de distribution normale de 1
        def weight_variable(shape):
            return tf.Variable(tf.truncated_normal(shape, stddev=0.1))

        #Valeur initiale du biais 0.Défini par 1 constante
        def bias_variable(shape):
            return tf.Variable(tf.constant(0.1, shape=shape))

        #Définition de la couche de convolution
        def conv2d(x, W):
            return tf.nn.conv2d(x, W, [1, 1, 1, 1], 'SAME')

        #Définition de la couche de regroupement
        def max_pool(x):
            return tf.nn.max_pool(x, ksize=[1, pool_size, pool_size, 1], strides=[1, pool_size, pool_size, 1], padding='SAME')

        #Informations d'entrée
        with tf.name_scope('input'):
            tf.summary.image(IMAGE_SOURCE, images, NUM_OUTPUT_IMAGES, family=IMAGE_SOURCE)

        #1ère couche
        with tf.name_scope('1st_layer'):
            #1ère couche de convolution
            with tf.name_scope('conv1_layer') as scope:
                W_conv1 = weight_variable([SIZE_FILTER1, SIZE_FILTER1, 3, NUM_FILTER1])
                b_conv1 = bias_variable([NUM_FILTER1])
                h_conv1 = tf.nn.relu(conv2d(images, W_conv1) + b_conv1)
                
                #Tenseur[Verticale,côté,3,Nombre de filtres]De[Nombre de filtres,Verticale,côté,3]Et sortie d'image
                tf.summary.image(IMAGE_FILTER, tf.transpose(W_conv1, perm=[3,0,1,2]), 4, family=IMAGE_FILTER)
                
                #Tenseur[-1,Verticale,côté,Nombre de filtres]De[-1,Nombre de filtres,Verticale,côté]Et commandez la conversion, fusionnez les deux premières dimensions et sortez l'image
                tf.summary.image(IMAGE_CONV, tf.reshape(tf.transpose(h_conv1, perm=[0,3,1,2]), [-1,image_size,image_size,1]), 4 , family=IMAGE_CONV)

            #1ère couche de mise en commun
            with tf.name_scope('pool1_layer') as scope:
                
                #Calcul de la taille de l'image après le processus de regroupement
                image_size1 = int(image_size / pool_size)
                
                h_pool1 = max_pool(h_conv1)
               
                #Tenseur[-1,Verticale,côté,Nombre de filtres]De[-1,Nombre de filtres,Verticale,côté]Et commandez la conversion, fusionnez les deux premières dimensions et sortez l'image
                tf.summary.image(IMAGE_POOL, tf.reshape(tf.transpose(h_pool1,perm=[0,3,1,2]),[-1, image_size1, image_size1, 1]),
                                 NUM_OUTPUT_IMAGES, family=IMAGE_POOL)
                
        #2ème couche
        with tf.name_scope('2nd_layer'):
            #2ème couche de convolution
            with tf.name_scope('conv2_layer') as scope:
                W_conv2 = weight_variable([SIZE_FILTER2, SIZE_FILTER2, NUM_FILTER1, NUM_FILTER2])
                b_conv2 = bias_variable([NUM_FILTER2])
                h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
                
                #Tenseur[Verticale,côté,Nombre de filtres 1,Nombre de filtres 2]De[Nombre de filtres 1*Nombre de filtres 2,Verticale,côté,1]Et sortie iimage vers TensorBoard
                tf.summary.image(IMAGE_FILTER, tf.reshape(tf.transpose(W_conv2,perm=[2,3,0,1]),[-1,SIZE_FILTER2,SIZE_FILTER2,1]), 4, family=IMAGE_FILTER)
                #Tenseur[-1,Verticale,côté,64]De[-1,64,Verticale,côté]Et la conversion de commande,[-1]Quand[64]Et sortie iimage vers TensorBoard
                tf.summary.image(IMAGE_CONV, tf.reshape(tf.transpose(h_conv2,perm=[0,3,1,2]),[-1,image_size1,image_size1,1]), 4, family=IMAGE_CONV)

            #2ème couche de pooling
            with tf.name_scope('pool2_layer') as scope:

                #Calcul de la taille de l'image après le processus de regroupement
                image_size2 = int(image_size1 / pool_size)

                h_pool2 = max_pool(h_conv2)
                #Tenseur[-1,Verticale,côté,Nombre de filtres 2]De[-1,Nombre de filtres 2,Verticale,côté]Et commandez la conversion, fusionnez les dimensions de la tête 2 et envoyez l'image vers TensorBoard
                tf.summary.image(IMAGE_POOL, tf.reshape(tf.transpose(h_pool2,perm=[0,3,1,2]),[-1,image_size2,image_size2,1]), 
                                 NUM_OUTPUT_IMAGES, family=IMAGE_POOL)

        #Création de la couche 1 entièrement connectée
        with tf.name_scope('fc1_layer') as scope:
            W_fc1 = weight_variable([image_size2 ** 2 * NUM_FILTER2, NUM_FC])
            b_fc1 = bias_variable([NUM_FC])
            h_pool2_flat = tf.reshape(h_pool2, [-1, image_size2 ** 2 * NUM_FILTER2])
            
            h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
            h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

        #Création de la couche 2 entièrement connectée(Lire la couche)
        with tf.name_scope('fc2_layer') as scope:
            W_fc2 = weight_variable([NUM_FC, NUM_CLASSES])
            b_fc2 = bias_variable([NUM_CLASSES])

            logits = tf.matmul(h_fc1_drop, W_fc2) + b_fc2

        return logits
    
def loss(logits, labels):

    with tf.name_scope('loss'):
        #Calcul de l'entropie croisée
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits, name='xentropy')

        #Valeur du taux d'erreur(cross_entropy)rends le
        return tf.reduce_mean(cross_entropy)

#Erreur(loss)Former un modèle d'apprentissage conçu à l'aide d'une rétropropagation d'erreur basée sur
def training(loss, learning_rate):
    with tf.name_scope('training'):
        #Sortie scalaire d'erreur vers TensorBoard
        tf.summary.scalar('loss', loss)
        
        #Optimisé avec Adam
        train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)
        return train_op

#Calculer le nombre de réponses correctes pour les résultats de prédiction produits par le modèle d'apprentissage
def evaluation(logits, labels, batch_size):

    with tf.name_scope('evaluation'):
        
        #Calcul du nombre de bonnes réponses
        correct = tf.reduce_sum(tf.cast(tf.nn.in_top_k(logits, labels, 1), tf.int32))
        
        #Calcul du taux de réponse correct et de la sortie scalaire vers TensorBoard
        accuracy = correct / batch_size
        tf.summary.scalar('accuracy', accuracy)
        return correct, accuracy

Programme d'appel de modèle d'apprentissage (Fully_connected_feed.py)

TensorFlow Mechanics 101 [Fully_connected_feed.py](https://www.github.com/tensorflow/tensorflow/blob/r1.3/tensorflow /examples/tutorials/mnist/fully_connected_feed.py) est un programme d'appel modèle pour l'apprentissage. Étant donné que les données d'entraînement sont créées pour un petit nombre, veuillez modifier le code de manière appropriée s'il y en a beaucoup.

import argparse
import cv2
import os
import time
import numpy as np
import random
import sys
import tensorflow as tf
import model_deep

#Paramètres de base du modèle
FLAGS = None

#Répondre à toutes les données
def do_eval(sess,
            eval_correct,
            images_placeholder,
            labels_placeholder,
            images_data, labels_data,
            keep_prob):
    
    true_count = 0  #Nombre de bonnes réponses

    #Calculez le nombre total
    steps_per_epoch = len(images_data) // FLAGS.batch_size  #Division tronquée
    num_examples = steps_per_epoch * FLAGS.batch_size       # num_les exemples ne soustraient finalement que la troncature

    #Évaluation de tous les cas
    for step in range(steps_per_epoch):

        #Recevez le nombre de bonnes réponses et ajoutez
        true_count += sess.run(eval_correct, 
                               feed_dict={images_placeholder: images_data[step * FLAGS.batch_size: step * FLAGS.batch_size + FLAGS.batch_size],
                                          labels_placeholder: labels_data[step * FLAGS.batch_size: step * FLAGS.batch_size + FLAGS.batch_size],
                                          keep_prob: 1.0
                                         })

    #Calcul et affichage corrects du taux de réponse
    print('  Num examples: %d  Num correct: %d  Precision @ 1: %0.04f' % (num_examples, true_count, (float(true_count) / num_examples)))
    
def run_training():
    #Spécifiez la portée à afficher dans le graphique TensorBoard
    with tf.Graph().as_default():
        
        #Définition d'espace réservé
        images_placeholder = tf.placeholder(tf.float32, name='images', shape=(FLAGS.batch_size, FLAGS.image_size, FLAGS.image_size, 3))
        labels_placeholder = tf.placeholder(tf.int32,   name='labels', shape=(FLAGS.batch_size) )    
        keep_prob = tf.placeholder(tf.float32, name='keep_probability' )

        # inference()Faire un modèle
        logits = model_deep.inference(images_placeholder, keep_prob, FLAGS.image_size, FLAGS.pool_size)
        
        # loss()Pour calculer la perte
        loss_value = model_deep.loss(logits, labels_placeholder)
        
        # training()Pour former et ajuster les paramètres du modèle d'apprentissage
        train_op = model_deep.training(loss_value, FLAGS.learning_rate)
        
        #Calcul de la précision
        eval_correct, accuracy = model_deep.evaluation(logits, labels_placeholder, FLAGS.batch_size)
        
        #Exportez le contenu jusqu'à présent vers TensorBoard
        summary = tf.summary.merge_all()

        #Prêt à économiser
        saver = tf.train.Saver()
                
        #Créer une session
        with tf.Session() as sess:

            #Préparation à l'écriture sur TensorBoard
            summary_writer = tf.summary.FileWriter(FLAGS.log_dir, sess.graph)
            
            #Initialisation variable
            sess.run(tf.global_variables_initializer())

            #Boucle de données d'image
            for step in range(len(FLAGS.train_image) // FLAGS.batch_size):
                
                #Heure de début enregistrer
                start_time = time.time()
                
                # batch_Exécution de la formation pour les images de taille
                train_batch = FLAGS.batch_size * step
                
                #Exécution de la formation
                feed_dict = {
                    images_placeholder: FLAGS.train_image[train_batch:train_batch + FLAGS.batch_size],
                    labels_placeholder: FLAGS.train_label[train_batch:train_batch+FLAGS.batch_size],
                    keep_prob: 0.5
                    }

                # train_Je jette des op, mais je ne suis pas intelligent sauf si je le spécifie
                _, loss_val, accuracy_val = sess.run([train_op, loss_value, accuracy] , feed_dict=feed_dict)
                
                # (Par époque)Calcul du temps de traitement
                duration = time.time() - start_time

                #Résumé toutes les 5 fois(Instance de carte tensorielle)Obtenir et ajouter à l'écrivain
                if step % 5 == 0:
                    #Sortie de résultat toutes les 10 fois
                    print('Step %d: loss = %.2f, accuracy = %.3f (%.4f sec)' % (step, loss_val, accuracy_val, duration))

                    #Exécuter une session et obtenir un résumé de TensorBoard
                    summary_str = sess.run(summary, feed_dict=feed_dict)
                    
                    #Résumé ajouté à TensorBoard
                    summary_writer.add_summary(summary_str, step)
                    summary_writer.flush()

                #Évalué lors de la boucle finale
                if (step + 1) == len(FLAGS.train_image)//FLAGS.batch_size:
                    saver.save(sess, os.path.join(FLAGS.log_dir, 'model.ckpt'), global_step=step)

                    print('Training Data Eval:')                
                    #Évaluation des données de formation
                    do_eval(sess, eval_correct, images_placeholder, labels_placeholder, FLAGS.train_image, FLAGS.train_label, keep_prob)

                    #Évaluation des données de test
                    print('Test Data Eval:')
                    do_eval(sess, eval_correct, images_placeholder, labels_placeholder, FLAGS.test_image, FLAGS.test_label, keep_prob)

            #TensorBoard écriture close
            summary_writer.close()

#Lire le fichier de liste d'images et convertir des fichiers image individuels et des étiquettes au format TensorFlow
def read_images(file_image_list):
    
    #Tableau pour mettre des données
    image_list = []
    label_list = []

    #Ouvrir le fichier en mode lecture
    with open(file_image_list) as file:
        file_data = file.readlines()
    
    #Ordre aléatoire
    random.shuffle(file_data)
    
    for line in file_data:
        #Séparé par des espaces sauf pour les sauts de ligne
        line      = line.rstrip()     #Supprimer l'espace de fin
        file_name = line.split('\t')  #Chaîne Delimita(languette)Séparer comme
        #Lire les données d'image et les FLAGS.image_taille réduite de tous les côtés
        img = cv2.imread(file_name[0])
        img = cv2.resize(img, (FLAGS.image_size, FLAGS.image_size))

        # 0-Convertir en une valeur flottante de 1
        image_list.append(img.astype(np.float32)/255.0)
        
        #Ajouter à la fin du tableau d'étiquettes
        label_list.append(int(file_name[1]))

    #Convertir au format numpy et retourner
    return np.asarray(image_list), np.asarray(label_list)

#Traitement principal
def main(_):

    #Si le répertoire de sauvegarde TensorBoard existe, supprimez-le et recréez-le.
    if tf.gfile.Exists(FLAGS.log_dir):
        tf.gfile.DeleteRecursively(FLAGS.log_dir)
    tf.gfile.MakeDirs(FLAGS.log_dir)

    #Données d'entraînement et de test Lecture de fichier image
    print('Start reading images')
    FLAGS.train_image, FLAGS.train_label = read_images(FLAGS.input_train_data)
    FLAGS.test_image,  FLAGS.test_label  = read_images(FLAGS.input_test_data)

    #Commence l'entraînement
    print('Start training')
    run_training()

#Rendez-le utilisable même lorsqu'il est importé
parser = argparse.ArgumentParser()

#Définition des paramètres d'entrée
parser.add_argument(
    '--learning_rate',
    type=float,
    default=1e-4,
    help='Initial learning rate.'
)
parser.add_argument(
    '--batch_size',
    type=int,
    default=20,
    help='Batch size.  Must divide evenly into the dataset sizes.'
)
parser.add_argument(
    '--input_train_data',
    type=str,
    default='./inputs/train.txt',
    help='File list data to put the input train data.'
)
parser.add_argument(
    '--input_test_data',
    type=str,
    default='./inputs/test.txt',
    help='File list data to put the input test data.'
)
parser.add_argument(
    '--log_dir',
    type=str,
    default='/tmp/tensorflow/kashiwagi/logs',
    help='Directory to put the log data.'
)
parser.add_argument(
    '--image_size',
    type=int,
    default=81,
    help='Input image size'
)
parser.add_argument(
    '--pool_size',
    type=int,
    default=3,
    help='MAX pooling size'
)

FLAGS, unparsed = parser.parse_known_args()

if __name__ == '__main__':
    #démarrage de la fonction principale
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

Recommended Posts

J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow [Partie 2]
J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow [Partie 2]
J'ai examiné les traits du visage de Yuki Kashiwagi pour comprendre TensorFlow [Partie 1]
Je veux comprendre à peu près systemd
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé de visualiser AutoEncoder avec TensorFlow
Je veux gérer la rime part1
Je veux gérer la rime part3
J'ai essayé de classer le texte en utilisant TensorFlow
Je veux gérer la rime part2
Je veux gérer la rime part5
Je veux gérer la rime part4
Implémentation de DQN avec TensorFlow (je voulais ...)
Je n'ai pas compris le redimensionnement de TensorFlow, alors je l'ai résumé visuellement.