[PYTHON] Le tutoriel MNIST de TensorFlow est compatible avec l'entrée d'image

Après avoir essayé le didacticiel TensorFlow MNIST, j'ai pensé. .. .. "Ce n'est pas très amusant car seule cette précision est affichée ..."

En d'autres termes, je veux faire quelque chose comme ça

I "Quel numéro pensez-vous que c'est?" test.png

PC "Je pense que c'est 2 !!" Je "bonne réponse! Mon partenaire !!"

J'ai donc créé un programme qui renvoie une prédiction lorsque je mets une image numérique manuscrite.

Je viens de changer un peu le code du tutoriel MNIST, donc si je peux faire Deep MNIST for Experts doit.

Puisque je suis un débutant de TensorFlow pour la première fois le 5, je pense qu'il y a des erreurs, mais dans ce cas, j'apprécierais que vous me donniez quelques conseils dans les commentaires. Mais pour le moment, le programme fonctionne bien.

Flux global

  1. Apprenez à utiliser le jeu de données MNIST et enregistrez les paramètres
  2. Lisez les paramètres appris et effectuez la reconnaissance des nombres manuscrits

Seulement ça. Droite? N'est-ce pas facile?

Apprenez avec MNIST

train_mnist.py


import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import cv2
import numpy as np
#Télécharger les données MNIST
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

NUM_CLASSES = 10    #Nombre de classes de modèles

sess = tf.InteractiveSession()


def interence(imegs_placeholder, keep_prob):
    """Fonctions qui créent des modèles prédictifs

argument:
      images_placeholder:Espace réservé pour l'image
      keep_prob:espace réservé pour le taux d'abandon

Valeur de retour:
      y_conv:Probabilité de chaque classe(Quelque chose comme)

     with tf.name_scope("xxx") as scope:
Maintenant, il apparaîtra comme un morceau de nœuds sur le TensorBoard
    """


    #Écart type de poids 0.Initialisé avec une distribution normale de 1
    def weight_variable(shape):
        inital = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(inital)

    #Biais par rapport à l'écart type 0.Initialisé avec une distribution normale de 1
    def bias_variable(shape):
        inital = tf.constant(0.1, shape=shape)
        return tf.Variable(inital)

    #Couche pliante
    def conv2d(x, W):
        return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding="SAME")

    #Couche de regroupement
    def max_pool_2x2(x):
        return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding="SAME")

    #28 couches d'entrée*28*Transformé en 1
    x_image = tf.reshape(imegs_placeholder, [-1, 28, 28, 1])

    #Création de la couche de convolution 1
    with tf.name_scope("conv1") as scope:
        W_conv1 = weight_variable([3,3,1,16])
        b_conv1 = bias_variable([16])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    #Création de la couche de convolution 2
    with tf.name_scope("conv2") as scope:
        W_conv2 = weight_variable([3,3,16,16])
        b_conv2 = bias_variable([16])
        h_conv2 = tf.nn.relu(conv2d(h_conv1, W_conv2) + b_conv2)

    #Création de la couche de pooling 1
    with tf.name_scope("pool1") as scope:
        h_pool1 = max_pool_2x2(h_conv2)

    #Création de la couche de convolution 3
    with tf.name_scope("conv3") as scope:
        W_conv3 = weight_variable([3,3,16,32])
        b_conv3 = bias_variable([32])
        h_conv3 = tf.nn.relu(conv2d(h_pool1, W_conv3) + b_conv3)

    #Création de la couche de convolution 4
    with tf.name_scope("conv4") as scope:
        W_conv4 = weight_variable([3,3,32,32])
        b_conv4 = bias_variable([32])
        h_conv4 = tf.nn.relu(conv2d(h_conv3, W_conv4) + b_conv4)

    #Création du pooling layer 2
    with tf.name_scope("pool2") as scope:
        h_pool2 = max_pool_2x2(h_conv4)

    #Création de la couche de convolution 5
    with tf.name_scope("conv5") as scope:
        W_conv5 = weight_variable([3,3,32,64])
        b_conv5 = bias_variable([64])
        h_conv5 = tf.nn.relu(conv2d(h_pool2, W_conv5) + b_conv5)

    #Création de la couche de convolution 6
    with tf.name_scope("conv6") as scope:
        W_conv6 = weight_variable([3,3,64,64])
        b_conv6 = bias_variable([64])
        h_conv6 = tf.nn.relu(conv2d(h_conv5, W_conv6) + b_conv6)

    #Création de la couche de pooling 3
    with tf.name_scope("pool3") as scope:
        h_pool3 = max_pool_2x2(h_conv6)

    #Création de la couche de liaison 1
    with tf.name_scope("fc1") as scope:
        W_fc1 = weight_variable([4*4*64, 1024])   
        b_fc1 = bias_variable([1024])
        h_pool3_flat = tf.reshape(h_pool3, [-1, 4*4*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool3_flat, W_fc1) + b_fc1)
        #paramètre dropout1
        h_fc_1_drop = tf.nn.dropout(h_fc1, keep_prob)

    #Création de la couche de liaison 2
    with tf.name_scope("fc2") as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    #Normalisation par fonction softmax
    with tf.name_scope("softmax") as scope:
        y_conv = tf.nn.softmax(tf.matmul(h_fc_1_drop, W_fc2) + b_fc2)

    #Renvoie quelque chose comme la probabilité de chaque étiquette
    return y_conv

def loss(logits, labels):
    """Fonction pour calculer la perte
argument:
      logits:Tenseur logit, float - [batch_size, NUM_CLASSES]
      labels:Tenseur d'étiquette, int32 - [batch_size, NUM_CLASSES]

Valeur de retour:
      cross_entropy:Tenseur d'entropie croisée, float
    """
    #Calcul de l'entropie croisée
    cross_entropy = -tf.reduce_sum(labels*tf.log(logits))
    #Spécifiez pour afficher dans TensorBoard
    tf.summary.scalar("cross_entropy", cross_entropy)   #v0.12 à tf.summary.scalar()Devenu#référence: https://teratail.com/questions/68531
    return cross_entropy

def training(loss, learning_rate):
    """Fonctions qui définissent les opérations d'entraînement

argument:
      loss:Tenseur de perte, loss()Résultat de
      learning_rate:Coefficient d'apprentissage

Valeur de retour:
      train_step:Op de formation

    """

    train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
    return train_step

def accuracy(logits, labels):
    """Taux de réponse correct(accuracy)Fonction à calculer
argument:
        logits: inference()Résultat de
        labels:Tenseur d'étiquette, int32 - [batch_size, NUM_CLASSES]
Valeur de retour:
        accuracy:Taux de réponse correct(float)
    """

    correct_prediction = tf.equal(tf.argmax(logits, 1), tf.arg_max(labels, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    tf.summary.scalar("accuracy", accuracy)
    return accuracy

if __name__=="__main__":
    with tf.Graph().as_default():
        #Paramètres variables utilisés dans les expressions
        x_image = tf.placeholder("float", shape=[None, 784])    #contribution
        y_label = tf.placeholder("float", shape=[None, 10])
        W = tf.Variable(tf.zeros([784,10]))
        b = tf.Variable(tf.zeros([10]))
        #y_label = tf.nn.softmax(tf.matmul(x_image,W)+b)     # y=softmax(Wx+b)La différenciation se fait également sans autorisation
        keep_prob = tf.placeholder("float")
        #init_op = tf.global_variables_initializer()    #Initialisation variable(Doit être obligatoire lors de l'utilisation de variables)
        logits = interence(x_image, keep_prob) # inference()Pour créer un modèle
        loss_value = loss(logits, y_label)     # loss()Pour calculer la perte
        train_op = training(loss_value,1e-4)   # training()Appeler et former (1e-4 est le taux d'apprentissage)
        accur = accuracy(logits, y_label)      # accuracy()Pour calculer la précision
        init_op = tf.global_variables_initializer()
        sess = tf.Session()
        sess.run(init_op)
        #Définition de la valeur à afficher sur TensorBoard
        summary_op = tf.summary.merge_all()
        summary_writer = tf.summary.FileWriter("./tmp/data", graph=sess.graph)

        saver = tf.train.Saver()    #Ajout d'un OP boiteux qui enregistre et restaure toutes les variables

        init = tf.global_variables_initializer()
        sess.run(init) #Initialiser et exécuter des variables

        #Exécution de la formation
        for step in range(20000)
            batch = mnist.train.next_batch(50)
            if step % 100 == 0:
                train_accury = sess.run(accur, feed_dict={x_image: batch[0], y_label: batch[1], keep_prob: 1.0})
                print("step%d, train_accury : %g"%(step, train_accury))
            sess.run(train_op, feed_dict={x_image: batch[0], y_label: batch[1], keep_prob:0.5})
            #Ajouter une valeur à afficher sur le TensorBoard après chaque étape
            summary_str = sess.run(summary_op, feed_dict={x_image: batch[0], y_label: batch[1], keep_prob: 1.0})
            summary_writer.add_summary(summary_str, step)
            summary_writer.flush()

        #Affichage des résultats
        print("test accuracy : %g" %sess.run(accur, feed_dict={x_image: mnist.test.images, y_label: mnist.test.labels, keep_prob: 1.0}))
        saver.save(sess, ".\ckpt\model.ckpt") #Stockage variable des données

L'important ici est

 saver = tf.train.Saver () # Ajouter un OP boiteux qui enregistre et restaure toutes les variables
 saver.save (sess, ". \ Ckpt \ model.ckpt") # Enregistrer les données de la variable

Ces deux sauvegardent les paramètres lorsque l'apprentissage est terminé. Sans cela, des dizaines de minutes d'apprentissage automatique commenceront même si vous souhaitez simplement renvoyer la prédiction de chaque image. Je me suis référé à ce site → Comment enregistrer et charger les paramètres d'apprentissage Tensorflow

Charger l'image et renvoyer la prédiction

input_num.py


import tensorflow as tf
import cv2
import numpy as np

NUM_CLASSES = 10

def interence(imegs_placeholder, keep_prob):
    """Fonctions qui créent des modèles prédictifs

argument:
      images_placeholder:Espace réservé pour l'image
      keep_prob:espace réservé pour le taux d'abandon

Valeur de retour:
      y_conv:Probabilité de chaque classe(Quelque chose comme)

     with tf.name_scope("xxx") as scope:
Maintenant, il apparaîtra comme un morceau de nœuds sur le TensorBoard
    """


    #Écart type de poids 0.Initialisé avec une distribution normale de 1
    def weight_variable(shape):
        inital = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(inital)

    #Biais par rapport à l'écart type 0.Initialisé avec une distribution normale de 1
    def bias_variable(shape):
        inital = tf.constant(0.1, shape=shape)
        return tf.Variable(inital)

    #Couche pliante
    def conv2d(x, W):
        return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding="SAME")

    #Couche de regroupement
    def max_pool_2x2(x):
        return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding="SAME")

    #28 couches d'entrée*28*Transformé en 1
    x_image = tf.reshape(imegs_placeholder, [-1, 28, 28, 1])

    #Création de la couche de convolution 1
    with tf.name_scope("conv1") as scope:
        W_conv1 = weight_variable([3,3,1,16])
        b_conv1 = bias_variable([16])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    #Création de la couche de convolution 2
    with tf.name_scope("conv2") as scope:
        W_conv2 = weight_variable([3,3,16,16])
        b_conv2 = bias_variable([16])
        h_conv2 = tf.nn.relu(conv2d(h_conv1, W_conv2) + b_conv2)

    #Création de la couche de pooling 1
    with tf.name_scope("pool1") as scope:
        h_pool1 = max_pool_2x2(h_conv2)

    #Création de la couche de convolution 3
    with tf.name_scope("conv3") as scope:
        W_conv3 = weight_variable([3,3,16,32])
        b_conv3 = bias_variable([32])
        h_conv3 = tf.nn.relu(conv2d(h_pool1, W_conv3) + b_conv3)

    #Création de la couche de convolution 4
    with tf.name_scope("conv4") as scope:
        W_conv4 = weight_variable([3,3,32,32])
        b_conv4 = bias_variable([32])
        h_conv4 = tf.nn.relu(conv2d(h_conv3, W_conv4) + b_conv4)

    #Création du pooling layer 2
    with tf.name_scope("pool2") as scope:
        h_pool2 = max_pool_2x2(h_conv4)

    #Création de la couche de convolution 5
    with tf.name_scope("conv5") as scope:
        W_conv5 = weight_variable([3,3,32,64])
        b_conv5 = bias_variable([64])
        h_conv5 = tf.nn.relu(conv2d(h_pool2, W_conv5) + b_conv5)

    #Création de la couche de convolution 6
    with tf.name_scope("conv6") as scope:
        W_conv6 = weight_variable([3,3,64,64])
        b_conv6 = bias_variable([64])
        h_conv6 = tf.nn.relu(conv2d(h_conv5, W_conv6) + b_conv6)

    #Création de la couche de pooling 3
    with tf.name_scope("pool3") as scope:
        h_pool3 = max_pool_2x2(h_conv6)

    #Création de la couche de liaison 1
    with tf.name_scope("fc1") as scope:
        W_fc1 = weight_variable([4*4*64, 1024])
        b_fc1 = bias_variable([1024])
        h_pool3_flat = tf.reshape(h_pool3, [-1, 4*4*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool3_flat, W_fc1) + b_fc1)
        #paramètre dropout1
        h_fc_1_drop = tf.nn.dropout(h_fc1, keep_prob)

    #Création de la couche de liaison 2
    with tf.name_scope("fc2") as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    #Normalisation par fonction softmax
    with tf.name_scope("softmax") as scope:
        y_conv = tf.nn.softmax(tf.matmul(h_fc_1_drop, W_fc2) + b_fc2)

    #Renvoie quelque chose comme la probabilité de chaque étiquette
    return y_conv

if __name__ == "__main__":

    #Chargement d'image
    img = input("Veuillez entrer le chemin de l'image>")
    img = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
    img = cv2.resize(img, (28, 28))
    ximage = img.flatten().astype(np.float32)/255.0 #Changer de format

    #Paramètres variables utilisés dans les expressions
    x_image = tf.placeholder("float", shape=[None, 784])    #contribution
    y_label = tf.placeholder("float", shape=[None, 10])
    keep_prob = tf.placeholder("float")

    logits = interence(x_image, keep_prob)
    sess = tf.InteractiveSession()

    saver = tf.train.Saver()
    sess.run(tf.global_variables_initializer())
    ckpt = tf.train.get_checkpoint_state('./ckpt')
    saver.restore(sess, ckpt.model_checkpoint_path) #Lecture de données variables

    pred = np.argmax(logits.eval(feed_dict={x_image: [ximage], keep_prob: 1.0})[0])
    print(pred)

Comme vous l'avez peut-être remarqué ici, la première moitié est presque la même. C'est parce que vous devez d'abord déterminer les variables à utiliser avant de mettre les paramètres appris.

** Traitement d'image **

 #Charger l'image
 img = input ("Entrez le chemin de l'image>")
    img = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
    img = cv2.resize(img, (28, 28))
 ximage = img.flatten (). astype (np.float32) /255.0 #change format

Ici, après avoir lu l'image en utilisant cv2, redimensionnez-la à 28 * 28, rendez le format unidimensionnel, puis divisez l'échelle de gris de 0 à 255 par 255. Ensuite, le blanc [255] devient 1 et le noir [0] devient [0]. Les couleurs subtiles (gris, etc.) sont des fractions de type flottant, En d'autres termes, il était compris entre 0 et 1. Cela vous permet de faire des prédictions en utilisant ce que vous avez appris précédemment.

    saver = tf.train.Saver()
    sess.run(tf.global_variables_initializer())
    ckpt = tf.train.get_checkpoint_state('./ckpt')
 saver.restore (sess, ckpt.model_checkpoint_path) #Lire les données de la variable

Initialisez les variables avant de charger les paramètres entraînés enregistrés par le premier programme d'entraînement, puis chargez les paramètres.

    pred = np.argmax(logits.eval(feed_dict={x_image: [ximage], keep_prob: 1.0})[0])
    print(pred)

Enfin, l'image traitée, le taux d'abandon, etc. sont transmis au réseau et le plus grand résultat renvoyé est affiché.

test.png Si vous l'exécutez et passez une image comme celle-ci (même si elle peut être un peu différente), elle devrait ressembler à celle ci-dessous.

C:\User\...\MNIST > python input_num.py
 Veuillez entrer le chemin de l'image> (chemin de l'image)
3

C'est la fin du programme qui renvoie la prédiction lorsque vous entrez le chemin de l'image. Veuillez l'essayer!

Supplément

En ce qui concerne "l'image" lors du passage des données d'image, si l'épaisseur des caractères est mince, elle disparaîtra lors du redimensionnement à 28 * 28, veuillez donc l'écrire assez épaisse.

Le code est également publié sur GitHub. Code pour cet article

Sites, etc. auxquels j'ai fait référence

Identifiez la société de production d'anime Yuruyuri avec TensorFlow Comment enregistrer et charger les paramètres d'apprentissage d'ensorflow Chargement des images de base de Python OpenCV (image fixe)

Recommended Posts

Le tutoriel MNIST de TensorFlow est compatible avec l'entrée d'image
Outil de rognage d'image GUI réalisé avec Python + Tkinter
Classification d'image MNIST (numéro manuscrit) avec Perceptron multicouche
Création d'un programme de génération d'images MNIST par DCGAN (tutoriel tensorflow)
Challenge classification des images par TensorFlow2 + Keras 3 ~ Visualiser les données MNIST ~