[PYTHON] Erstellen Sie durch tiefes Lernen einen "Bot, der Ihnen AV-Schauspielerinnen mit ähnlichen Gesichtern sagt"

Überblick

Verwenden der Facebook Messenger API Ich habe einen Bot implementiert, der mir ähnliche AV-Schauspielerinnen mitteilt, wenn ich ein Bild hochlade.

スクリーンショット 2016-05-05 12.51.16_censored.jpg

Systemkonfiguration

Der Server, der die Bot-Antwort ausführt, wird aus verschiedenen Gründen mit "Go" erstellt, die Bildunterscheidung wird mit "Python" erstellt (die Gesichtserkennung ist "OpenCV" und das Faltungsnetzwerk für die Klassifizierung ist "TensorFlow"). Die I / F zwischen den Sprachen ist "gRPC", und RPC wird von "Gehe zu Python" ausgeführt.

Implementierung

Geh zur Seite

Ein Worker-Prozess, der einen Webhook von Facebook Messenger empfängt und eine Bot-Antwort gibt.

Messenger Bot Server Gin wird für den Webserver verwendet. Es ist nicht besonders schwierig, aber wenn der Datenverkehr zunimmt, scheinen Nachrichten von mehreren Benutzern gemeinsam an den Webhook gesendet zu werden. Wenn Sie es in einem Unternehmen verwenden, müssen Sie vorsichtig sein. Bitte verzeihen Sie, dass die Fehlerbehandlung süß ist.

const (
    PORT = ":3000"
    VERIFICATION_TOKEN = "{{YOUR_VERIFICATION_TOKEN}}"
    ENDPOINT_URL = "https://graph.facebook.com/v2.6/me/messages"
)

func main() {
	router := gin.Default()
	router.GET("/messenger", varifyToken)
	router.POST("/messenger", processMessages)
	router.Run(PORT)
}

func varifyToken(c *gin.Context) {
    token := c.Query("hub.verify_token")
    challenge := c.Query("hub.challenge")

    if token == VERIFICATION_TOKEN {
        c.String(http.StatusOK, challenge + "\n")
    } else {
        log.WithFields(log.Fields{
            "received": token,
            "expected": VERIFICATION_TOKEN,
        }).Warn("Invalid token.")
    }
}

func processMessages(c *gin.Context) {
    var json model.Webhook
    if c.BindJSON(&json) == nil {
        for _, e := range json.Entry {
            for _, m := range e.Messaging {
                respondToOneMessage(&m)
            }
        }
        c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    }
}

func respondToOneMessage(m *model.Messaging) {
    sender := m.Sender.Id

    switch {
    // Receive Text
    case m.Message.Text != "":

    // Receive Image
    case m.Message.Attachments[0].Type == "image":
        url := m.Message.Attachments[0].Payload.Url
        path := util.SaveImg(url)
        rs, err := classifyImg(path)
	if err != nil {
	    log.Fatal(err)
	}

	txt := fmt.Sprintf("Die Person auf dem Foto%Ähnlichkeit mit s%f%%ist.", rs.Result[0].Label, rs.Result[0].Accuracy * 100)
        err2 := sendTextMessage(sender, txt)
	if err2 != nil {
	    log.Fatal(err2)
	}

    default:
        log.Error("Unexpected Message")
    }
}

func sendTextMessage(recipient int64, text string) error {
    endpoint := fmt.Sprintf("%s?%s=%s", ENDPOINT_URL, "access_token", VERIFICATION_TOKEN)
    json := `{"recipient":{"id":%d},"message":{"text":"%s"}}`
    body := fmt.Sprintf(json, recipient, text)

    req, err := http.NewRequest(
        "POST",
        endpoint,
        strings.NewReader(body),
    )
    if err != nil {
        return err
    }

    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{ Timeout: time.Duration(3 * time.Second) }
    resp, err := client.Do(req)
    log.Printf("requested")
    defer resp.Body.Close()

    return err
}

Python-Seite

Unter Berücksichtigung des Bildweges wird das Gesicht erkannt und das trainierte Faltungs-Neuronale Netz bestimmt die Ähnlichkeit des Gesichts.

Gesichtserkennung mit OpenCV

Nun, das Bild, das ich bekommen habe, egal wie tief es lernt, selbst wenn es von CNN so klassifiziert wird, wie es ist, wird es nicht sehr genau sein, also schneiden Sie zuerst nur das Gesichtsteil. Dieses Mal habe ich "OpenCV" zur Erkennung verwendet. Nimmt ein Array im NumPy-Format als Argument und gibt das Ergebnis des Zuschneidens nur des Gesichtsteils zurück. Es gab auch ein Horrorbild, in dem das rechte Ohr aus irgendeinem Grund als Gesicht erkannt wurde. Ich habe ein wenig Angst, weil es psychische Fotos zu erkennen scheint.

def face_detect(img):
    face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.1,
        minNeighbors=5,
        minSize=(30, 30),
        flags = cv2.CASCADE_SCALE_IMAGE
    )
    if len(faces) > 0:
        fc = faces[0]
        x = fc[0]
        y = fc[1]
        w = fc[2]
        h = fc[3]
        return img[y:y+h, x:x+w]
    else:
        return None

Ich dachte, es wäre ziemlich schwierig, aber das war's. Ich war überrascht, weil es zu bequem war. Ich werde den Algorithmus dieses Mal richtig studieren.

CNN in TensorFlow

Trainieren Sie Netzwerkgewichte mit gesammelten und vorverarbeiteten Bildern.

Die Struktur des Faltungs-Neuronalen Netzes ist Deep MNIST for Experts. das Gleiche,

Es ist 6 Schichten.

Ich weiß nicht, wie ich TensorFlow nur mit dem Tutorial verwenden soll. Lesen Sie daher TensorFlow Mechanics 101 sorgfältig durch. Ist empfohlen.

Der Modellierungsteil ist ein Auszug.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cv2
import numpy as np
import tensorflow as tf

NUM_CLASSES = 5
IMAGE_SIZE = 28

class CNNetwork:

    def inference(self, x_images, keep_prob):

        def weight_variable(shape):
          initial = tf.truncated_normal(shape, stddev=0.1)
          return tf.Variable(initial)

        def bias_variable(shape):
          initial = tf.constant(0.1, shape=shape)
          return tf.Variable(initial)

        def conv2d(x, W):
          return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

        def max_pool_2x2(x):
          return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                                strides=[1, 2, 2, 1], padding='SAME')

        with tf.name_scope('conv1') as scope:
            W_conv1 = weight_variable([5, 5, 3, 32])
            b_conv1 = bias_variable([32])
            h_conv1 = tf.nn.relu(tf.nn.bias_add(conv2d(x_images, W_conv1), b_conv1))

        with tf.name_scope('pool1') as scope:
            h_pool1 = max_pool_2x2(h_conv1)
        
        with tf.name_scope('conv2') as scope:
            W_conv2 = weight_variable([5, 5, 32, 64])
            b_conv2 = bias_variable([64])
            h_conv2 = tf.nn.relu(tf.nn.bias_add(conv2d(h_pool1, W_conv2), b_conv2))

        with tf.name_scope('pool2') as scope:
            h_pool2 = max_pool_2x2(h_conv2)

        with tf.name_scope('fc1') as scope:
            W_fc1 = weight_variable([7*7*64, 1024])
            b_fc1 = bias_variable([1024])
            h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
            h_fc1 = tf.nn.relu(tf.nn.bias_add(tf.matmul(h_pool2_flat, W_fc1), b_fc1))
            h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

        with tf.name_scope('fc2') as scope:
            W_fc2 = weight_variable([1024, NUM_CLASSES])
            b_fc2 = bias_variable([NUM_CLASSES])

        with tf.name_scope('softmax') as scope:
            y_conv=tf.nn.softmax(tf.nn.bias_add(tf.matmul(h_fc1_drop, W_fc2), b_fc2))

        return y_conv

Zum Zeitpunkt des Trainings führt das Speichern des Gewichts des Trainings zu einer Binärdatei wie folgt: Es kann verwendet werden, wenn die Klassifizierungsfunktion von RPC aufgerufen wird.

saver = tf.train.Saver()
save_path = saver.save(sess, "model.ckpt")

Dies ist eine Klassifizierungsfunktion, die das Ausführungsergebnis der Softmax-Funktion auf der tiefsten Ebene des Netzwerks zurückgibt.

def classify(self, image_path):
    try:
        img = cv2.imread(image_path)
        img = face_detect(img)
        img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE))
        img = img.astype(np.float32)/255.0

        images_placeholder = tf.placeholder("float", shape=(None, IMAGE_SIZE, IMAGE_SIZE, 3))
        labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
        keep_prob = tf.placeholder("float")

        logits = self.inference(images_placeholder, keep_prob)
        sess = tf.InteractiveSession()

        saver = tf.train.Saver()
        sess.run(tf.initialize_all_variables())
        saver.restore(sess, "./model.ckpt")

        pred = logits.eval(feed_dict={images_placeholder: [img],keep_prob: 1.0 })[0]
        return pred

    except Exception as e:
        print 'message:' + e.message

gRPC Schließlich RPC TensorFlow vom Bot-Server in Go-Sprache implementiert. gRPC verwendet Protokollpuffer als Datenformat. Grob gesagt handelt es sich um eine universelle Datendefinition für die Kommunikation zwischen Programmen. Wenn Sie eine .proto-Datei erstellen, die eine Definitionsdatei ist, können Sie mit einem Befehl eine Bibliothek zum Serialisieren / Deserialisieren für jede Sprache generieren.

Datenstrukturdefinition

Erstellen Sie zunächst eine "Proto" -Datei, die die Datenstruktur wie unten gezeigt definiert. cnn.proto

syntax = "proto3";

package cnn;

service Classifier {
    rpc classify (CnnRequest) returns (CnnResponse){}
}

message CnnRequest {
    string filepath = 1;
}

message CnnResponse {
    repeated Result result = 1;
}

message Result {
    string label = 1;
    double accuracy = 2;
}

Erstellen Sie nach Abschluss der Definition Bibliotheksdateien für jede Sprache von Go und Python.

# go
protoc --go_out=plugins=grpc:./ cnn.proto

# Python
protoc --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` cnn.proto

Damit werden Bibliotheken für jede Sprache, "cnn.pb.go" und "cnn_pb2.py", generiert.

Aufbau eines gRPC-Servers

Implementieren Sie den gRPC-Server mithilfe der generierten Bibliothek.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import cnn_pb2 as pb
import cnn

_ONE_DAY_IN_SECONDS = 60 * 60 * 24

class Classier(pb.BetaClassifierServicer):

  def classify(self, request, context):
    path = request.filepath
    print path
    n = cnn.CNNetwork() 
    accuracies = n.classify(path)
    print accuracies
    labels = ['Kaho Shibuya', 'AIKA', 'Aki Sasaki', 'Ai Uehara', 'Ayumi Shinoda']
    nameWithAccuracy = []
    for i in range (0, len(labels)):
        nameWithAccuracy.append((accuracies[i], labels[i]))
    nameWithAccuracy.sort(reverse=True)

    response = pb.CnnResponse()
    try:
        #Geben Sie vorerst die drei besten Personen zurück
        for i in range(0, 3):
            r = pb.Result()
            label = nameWithAccuracy[i][1]
            accuracy = float(nameWithAccuracy[i][0])
            response.result.add(label=label, accuracy=accuracy)

    except Exception as e:
        print e.message

    return response


def serve():
  server = pb.beta_create_Classifier_server(Classier())
  server.add_insecure_port('[::]:50051')
  server.start()
  try:
    while True:
      time.sleep(_ONE_DAY_IN_SECONDS)
  except KeyboardInterrupt:
    server.stop(0)

if __name__ == '__main__':
  serve()

gRPC-Client

Als nächstes implementieren wir den gRPC-Client in der Sprache Go.

//Auszug
func classifyImg(filepath string) (*cnn.CnnResponse, error) {
    address := "localhost:50051"

    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := cnn.NewClassifierClient(conn)

    result, err := c.Classify(context.Background(), &cnn.CnnRequest{Filepath: filepath})
    if err != nil {
        log.Fatalf("couldn't classify: %v", err)
        return nil, err
    }
    return result, nil
}

abschließend

Impressionen

Technisch gesehen war das Erstellen von OpenCV unter Amazon Linux am aufwändigsten als das Programmieren. Die Unterscheidungsgenauigkeit des Faltungs-Neuronalen Netzes unter Verwendung der Testdaten betrug 79%. Wenn es sich um ein Bild handelt, das wie die Aufnahme zu Beginn von vorne aufgenommen wurde, ist die Beurteilungsgenauigkeit jedoch relativ hoch Ich konnte das Bild des Ausdrucks nicht unterscheiden wie Teruhide, der weinte.

Verweise

[Lineare Algebra für die Programmierung](http://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83% 9F% E3% 83% B3% E3% 82% B0% E3% 81% AE% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E7% B7% 9A% E5% BD% A2% E4% BB% A3% E6% 95% B0-% E5% B9% B3% E5% B2% A1-% E5% 92% 8C% E5% B9% B8 / dp / 4274065782) Ich kannte die Grundlagen der linearen Algebra überhaupt nicht und lernte von Grund auf.

[Deep Learning (Machine Learning Professional Series)](https://www.amazon.co.jp/%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92-%E6 % A9% 9F% E6% A2% B0% E5% AD% A6% E7% BF% 92% E3% 83% 97% E3% 83% AD% E3% 83% 95% E3% 82% A7% E3% 83 % 83% E3% 82% B7% E3% 83% A7% E3% 83% 8A% E3% 83% AB% E3% 82% B7% E3% 83% AA% E3% 83% BC% E3% 82% BA -% E5% B2% A1% E8% B0% B7% E8% B2% B4% E4% B9% 8B-ebook / dp / B018K6C99A? Ie = UTF8 & btkr = 1 & ref_ = dp-kindle-redirect) Da die Entwicklung der Formel sehr detailliert geschrieben ist, konnte ich sie in letzter Minute lesen.

Identifizieren Sie die Anime Yuruyuri Produktionsfirma mit TensorFlow Für die Implementierung des Faltungs-Neuronalen Netzes habe ich darauf hingewiesen, was sorgfältig erklärt wird.

Recommended Posts

Erstellen Sie durch tiefes Lernen einen "Bot, der Ihnen AV-Schauspielerinnen mit ähnlichen Gesichtern sagt"
Geben Sie das Know-how bekannt, das einen ähnlichen Bildsuchdienst für AV-Schauspielerinnen durch tiefes Lernen durch Chainer geschaffen hat
Klassifizieren Sie Anime-Gesichter durch Fortsetzung / Deep Learning mit Keras
Versuchen Sie, ein Deep Learning / Neuronales Netzwerk mit Scratch aufzubauen
(Jetzt) Erstellen Sie eine GPU Deep Learning-Umgebung mit GeForce GTX 960
Ich suchte mit Deep Learning nach einer ähnlichen Karte von Hearthstone
Klassifizieren Sie Anime-Gesichter mit tiefem Lernen mit Chainer
99,78% Genauigkeit bei tiefem Lernen durch Erkennen von handgeschriebenem Hiragana
Erstellen Sie eine Python-Umgebung für maschinelles Lernen mit Containern
Eine Geschichte über die Vorhersage des Wechselkurses mit Deep Learning
Erstellen Sie mit Python eine Entwicklungsumgebung für maschinelles Lernen
Lern-Roadmap, mit der Sie Services mit Python von Grund auf neu entwickeln und veröffentlichen können
Ich habe versucht, Othello AI zu machen, dass ich 7,2 Millionen Hände durch tiefes Lernen mit Chainer gelernt habe