Utilisation de l 'API Facebook Messenger J'ai implémenté un bot qui me dit des actrices AV similaires lorsque je télécharge une image.
Le serveur qui exécute la réponse Bot est créé avec «Go» pour diverses raisons, la discrimination d'image est créée avec «Python» (la détection de visage est «OpenCV» et le réseau de neurones convolutifs pour la classification est «TensorFlow»).
L'I / F entre les langages est gRPC
, et le RPC est exécuté de Go à Python.
Un processus Worker qui reçoit un webhook de Facebook Messenger et fait une réponse de bot.
Messenger Bot Server Gin est utilisé pour le serveur Web. Ce n'est pas particulièrement difficile, mais lorsque le trafic augmente, il semble que les messages de plusieurs utilisateurs puissent être postés collectivement sur le webhook. Si vous l'utilisez dans une entreprise, vous devez faire attention à cela. Veuillez pardonner que la gestion des erreurs est douce.
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("La personne sur la photo%Similitude avec s%f%%est.", 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
}
Compte tenu du trajet de l'image, le visage est détecté et le réseau neuronal convolutif entraîné détermine la similitude du visage.
Eh bien, l'image que j'ai obtenue, peu importe son apprentissage en profondeur, même si elle est classée par CNN telle quelle, elle ne sera pas très précise, alors coupez d'abord uniquement la partie du visage. Cette fois, j'ai utilisé «OpenCV» pour la détection. Prend un tableau au format NumPy comme argument et renvoie le résultat de l'ajustement uniquement de la partie de face. Il y avait aussi une image d'horreur dans laquelle l'oreille droite a été détectée comme un visage pour une raison quelconque. J'ai un peu peur car il semble détecter des photographies psychiques.
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
Je pensais que ce serait assez difficile, mais c'est tout. J'ai été surpris car c'était trop pratique. J'étudierai correctement l'algorithme cette fois.
Former les poids du réseau à l'aide d'images collectées et prétraitées.
La structure du réseau de neurones convolutifs est Deep MNIST for Experts le même,
C'est 6 couches de.
Je ne sais pas comment utiliser TensorFlow uniquement avec le tutoriel, alors lisez attentivement TensorFlow Mechanics 101 attentivement. Est recommandé.
La partie modélisation est extraite.
#!/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
Au moment de l'entraînement, en sauvegardant le poids du résultat d'entraînement dans un fichier binaire comme suit, Il peut être utilisé lors de l'appel de la fonction de classification par RPC.
saver = tf.train.Saver()
save_path = saver.save(sess, "model.ckpt")
Il s'agit d'une fonction de classification qui renvoie le résultat de l'exécution de la fonction softmax au niveau de la couche la plus profonde du réseau.
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
Enfin, RPC TensorFlow du serveur bot implémenté en langage Go.
gRPC utilise Protocol Buffers comme format de données.
En gros, il s'agit d'une définition de données à usage général pour la communication entre programmes.
Si vous créez un fichier .proto
qui est un fichier de définition, vous pouvez générer une bibliothèque pour la sérialisation / désérialisation pour chaque langue avec une commande.
Tout d'abord, créez un fichier proto
qui définit la structure de données comme indiqué ci-dessous.
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;
}
Une fois la définition terminée, créez des fichiers de bibliothèque pour chaque langue de Go et 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
Cela seul générera des bibliothèques pour chaque langue, cnn.pb.go
et cnn_pb2.py
.
Implémentez le serveur gRPC à l'aide de la bibliothèque générée.
#!/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:
#Renvoyez les 3 meilleures personnes pour le moment
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()
Ensuite, nous implémenterons le client gRPC en langage Go.
//Extrait
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
}
Techniquement, la création d'OpenCV sur Amazon Linux a demandé plus d'efforts que la programmation. La précision de discrimination du réseau neuronal convolutif utilisant les données de test était de 79%. S'il s'agit d'une photo prise de face comme la capture au début, la précision du jugement est relativement élevée, mais Je ne pouvais pas distinguer l'image de l'expression comme Teruhide qui pleurait.
[Algèbre linéaire pour la programmation](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) Je ne connaissais pas les bases de l'algèbre linéaire en premier lieu, alors j'ai étudié à partir de zéro.
[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) Étant donné que l'élaboration de la formule est écrite de manière assez détaillée, je pourrais la lire à la dernière minute.
Identifiez la société de production d'anime Yuruyuri avec TensorFlow Pour la mise en œuvre du réseau neuronal convolutif, je me suis référé à ceci, qui est expliqué avec soin.
Recommended Posts