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.
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).
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 ...).
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))
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.
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.
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?
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?
Le reste est une couche étroitement couplée. Ceci est inchangé par rapport à Deep MNIST, y compris Drop Apt.
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.
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.
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 |
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. La figure ci-dessous montre le développement de la partie d'inférence principale.
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
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