salut! Je suis @eve_yk, un ingénieur Liaro. S'il vous plaît voir Partie 1 pour le début du sujet (pleurer) La dernière fois, nous avons collecté et traité des données pour former le classificateur. Cette fois, nous décrirons le modèle du classificateur et apprendrons et évaluerons réellement (identification du visage)!
Ensuite, décrivez le modèle du classificateur d'images de visage à entraîner dans Chainer. J'ai fait référence au code suivant (y compris la création de l'ensemble de données précédent). https://github.com/mitmul/chainer-cifar10
YTNet
class YTNet(chainer.Chain):
def __init__(self):
"""
Définition du modèle
"""
super(YTNet, self).__init__(
conv1=L.Convolution2D(3, 32, 5, stride=1, pad=2),
bn1 =L.BatchNormalization(32),
conv2=L.Convolution2D(32, 32, 5, stride=1, pad=2),
bn2 =L.BatchNormalization(32),
conv3=L.Convolution2D(32, 64, 5, stride=1, pad=2),
fc4=F.Linear(16384, 4096),
fc5=F.Linear(4096, 2),
)
self.train = True
def __call__(self, x, t):
"""
traitement avant
"""
h = F.max_pooling_2d(F.relu(self.conv1(x)), 3, stride=2)
h = F.max_pooling_2d(F.relu(self.conv2(h)), 3, stride=2)
h = F.relu(self.conv3(h))
h = F.dropout(F.relu(self.fc4(h)), ratio=0.5, train=self.train)
h = self.fc5(h)
self.loss = F.softmax_cross_entropy(h, t)
self.accuracy = F.accuracy(h, t)
if self.train:
return self.loss
else:
self.pred = F.softmax(h)
return self.pred
En vous basant sur le code en 3., écrivez le code pour entraîner le modèle. Cette fois, la formation sera terminée relativement rapidement, mais lorsque vous essayez de travailler avec un plus grand ensemble de données, il est bon pour la santé mentale de montrer les progrès de la formation.
train.py
# -*- coding: utf-8 -*-
import argparse
import os
import six
import chainer
import chainer.functions as F
import chainer.links as L
import numpy as np
from chainer import optimizers
from chainer import cuda
from chainer import serializers
from chainer import Variable
from progressbar import ProgressBar
class YTNet(chainer.Chain):
def __init__(self):
"""
Définition du modèle
"""
super(YTNet, self).__init__(
conv1=L.Convolution2D(3, 32, 5, stride=1, pad=2),
bn1 =L.BatchNormalization(32),
conv2=L.Convolution2D(32, 32, 5, stride=1, pad=2),
bn2 =L.BatchNormalization(32),
conv3=L.Convolution2D(32, 64, 5, stride=1, pad=2),
fc4=F.Linear(16384, 4096),
fc5=F.Linear(4096, 2),
)
self.train = True
def __call__(self, x, t):
"""
traitement avant
"""
h = F.max_pooling_2d(F.relu(self.conv1(x)), 3, stride=2)
h = F.max_pooling_2d(F.relu(self.conv2(h)), 3, stride=2)
h = F.relu(self.conv3(h))
h = F.dropout(F.relu(self.fc4(h)), ratio=0.5, train=self.train)
h = self.fc5(h)
self.loss = F.softmax_cross_entropy(h, t)
self.accuracy = F.accuracy(h, t)
if self.train:
return self.loss
else:
self.pred = F.softmax(h)
return self.pred
def one_epoch(args, model, optimizer, data, label, epoch, train):
"""
1epoch formation ou traitement d'évaluation
"""
model.train = train
xp = cuda.cupy if args.gpu >= 0 else np
sum_accuracy = 0
sum_loss = 0
p = ProgressBar(min_value=0, max_value=data.shape[0]) #Pour vérifier les progrès
perm = np.random.permutation(data.shape[0])
for i in xrange(0, data.shape[0], args.batchsize):
p.update(i)
#Créer un mini lot
target = perm[i:i + args.batchsize]
x = xp.array(data[target], dtype=xp.float32)
t = xp.array(label[target], dtype=xp.int32)
#Créer une variable
volatile = 'off' if train else 'on'
x = Variable(x, volatile=volatile)
t = Variable(t, volatile=volatile)
#Mise à jour des paramètres ou prédiction d'étiquettes
if train:
optimizer.update(model, x, t)
else:
pred = model(x, t).data
sum_loss += float(model.loss.data) * t.data.shape[0]
sum_accuracy += float(model.accuracy.data) * t.data.shape[0]
del x, t
print "" #Pour les sauts de ligne
if train:
print "train epoch " + str(epoch)
print " train loss : " + str(sum_loss / data.shape[0])
print " train acc : " + str(sum_accuracy / data.shape[0])
else:
print "test epoch " + str(epoch)
print " test loss : " + str(sum_loss / data.shape[0])
print " test acc : " + str(sum_accuracy / data.shape[0])
def load_dataset(datadir):
"""
Charger le jeu de données
"""
train_data = np.load('%s/train_data.npy' % datadir)
train_labels = np.load('%s/train_label.npy' % datadir)
test_data = np.load('%s/test_data.npy' % datadir)
test_labels = np.load('%s/test_label.npy' % datadir)
return train_data, train_labels, test_data, test_labels
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--gpu", type=int, default=-1)
parser.add_argument("--batchsize", type=int, default=10)
parser.add_argument('--data_dir', type=str, default='dataset')
parser.add_argument('--output_dir', type=str, default='result')
args = parser.parse_args()
# model,Créer un optimiseur
model = YTNet()
optimizer = optimizers.Adam(alpha=0.00005)
optimizer.setup(model)
#Chargement de l'ensemble de données
dataset = load_dataset(args.data_dir)
tr_data, tr_labels, te_data, te_labels = dataset
#Boucle principale
for epoch in range(1, 20):
#Entraînement
one_epoch(args, model, optimizer, tr_data, tr_labels, epoch, True)
#Évaluation
one_epoch(args, model, optimizer, te_data, te_labels, epoch, False)
#Enregistrer le modèle
if not os.path.exists(args.output_dir):
os.makedirs(args.output_dir)
serializers.save_npz(args.output_dir + "YTNet.chainermodel", model)
serializers.save_npz(args.output_dir + "YTNet.state", optimizer)
Après un entraînement d'environ 20 époques, la précision des données d'entraînement dépassait 99%.
Enfin, nous évaluerons les performances. Testez avec les 10 images suivantes. Cinq d'entre eux sont @eve_yk et cinq sont Super Maradona Tanaka. Un exemple de visage peut être trouvé dans Article précédent, alors essayez de savoir si vous pouvez le deviner.
Je suis un peu inquiet, mais vous pouvez le voir à l'œil nu. C'est différent de la couleur des verres. La bonne réponse est eve_yk pour 1,2,4,7,10 et M. Tanaka pour 3,5,6,8,9.
Maintenant, qu'en est-il du CNN que vous avez appris cette fois? Testez avec le code ci-dessous.
test.py
# coding:utf-8
import os
import sys
import argparse
import glob
import cv2
import numpy as np
from chainer import Variable
from chainer import serializers
from train import YTNet
def transpose_opencv2chainer(x):
"""
Conversion du format opencv npy au format chainer npy
opencv => (height, width, channel)
chainer => (channel, height, width)
"""
return x.transpose(2,0,1)
file2labels = {"01.jpg ":"eve_yk", "02.jpg ":"eve_yk", "03.jpg ":"tanaka",
"04.jpg ":"eve_yk", "05.jpg ":"tanaka", "06.jpg ":"tanaka",
"07.jpg ":"eve_yk", "08.jpg ":"tanaka", "09.jpg ":"tanaka",
"10.jpg ":"eve_yk"}
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Créer un ensemble de données pour CNN')
parser.add_argument('--input_path', required=True, type=str)
parser.add_argument('--model_path', required=True, type=str)
args = parser.parse_args()
#Obtenir la liste des fichiers jpg
test_files = glob.glob(args.input_path+"/*.jpg ")
#Chargement du modèle
model = YTNet()
model = serializers.load_npz(args.model_path, , model)
#Évaluer un par un
collect_count = 0.0
test_count = 0.0
for file_path in test_files:
image = cv2.imread(file_path)
if image is None:
#Échec de lecture
continue
test_count += 1.0
#Obtenir le nom de fichier de la structure de répertoires
file_name = file_path.split("/")[-1]
print file_name+"("+file2labels[file_name]+") :",
#Convertir au format de chaîne
image = transpose_opencv2chainer(image)
x = Variable(np.asarray([image], dtype=np.float32), volatile="on")
t = Variable(np.asarray([[0]], dtype=np.int32), volatile="on")
#Évaluation
pred = model(x, t).data
if int(pred) == 0: # tanaka
print u"Résultat d'identification "tanaka""
if file2labels[file_name] == u"tanaka":
collect_count += 1.0
else: # eve_yk
print u"Résultat d'identification "eve_yk」"
if file2labels[file_name] == u"eve_yk":
collect_count += 1.0
print u"total:{}%".format(collect_count/test_count*100)
Le résultat est cette rue
python test.py --input_path test/ --model_path result/YTNet.chainermodel
08.jpg(tanaka) :Résultat d'identification "tanaka"
09.jpg(tanaka) :Résultat d'identification "eve_yk」
07.jpg(eve_yk) :Résultat d'identification "eve_yk」
01.jpg(eve_yk) :Résultat d'identification "eve_yk」
03.jpg(tanaka) :Résultat d'identification "tanaka"
06.jpg(tanaka) :Résultat d'identification "eve_yk」
02.jpg(eve_yk) :Résultat d'identification "eve_yk」
05.jpg(tanaka) :Résultat d'identification "tanaka"
04.jpg(eve_yk) :Résultat d'identification "eve_yk」
10.jpg(eve_yk) :Résultat d'identification "eve_yk」
total:8.0/10
J'ai confondu M. Tanaka de 6 et 9 avec eve_yk. S'agit-il d'une prédiction biaisée en raison de la différence de quantité de données d'entraînement? Cependant, j'ai le sentiment que l'image qui dérange l'œil humain est fausse. Après tout, il semble difficile de distinguer Doppelgenger avec un système à moitié fini.
J'ai créé un classificateur de visage qui identifie mon sosie. La précision est correcte. Je pense que c'était bien qu'il y ait eu de nombreux compromis tels que le nombre de données et le prétraitement. Il serait intéressant de travailler dur pour collecter des données et de classer un plus grand nombre de personnes, ou de travailler dur sur le prétraitement pour améliorer la précision!
Liaro et eve_yk soutiennent Super Maradona!
https://github.com/mitmul/chainer-cifar10
Profil de l'artiste Yoshimoto Kogyo Co., Ltd. | Super Maradona
Recommended Posts