[PYTHON] Classer les visages d'anime par suite / apprentissage profond avec Keras

introduction

Il y a environ un an écrit en Chainer C'est un programme pour classer les visages d'anime, mais cette fois je l'ai écrit dans Keras. Le programme est répertorié sur GitHub.

base de données

L'ensemble de données peut être obtenu à partir de animeface-character-dataset. Référence: j'ai essayé d'extraire les caractéristiques du visage animé avec Denoising AutoEncoder

Prétraitement de l'ensemble de données

Je l'ai amélioré un peu plus qu'avant. Redimensionner en données RVB 32x32 (forme = (3, 32, 32)). La différence avec la dernière fois est que cela fonctionne probablement même si vous ne supprimez pas le dossier vide qui ne contient aucune donnée. Exigences

Il est.

#! -*- coding: utf-8 -*-

import os
import six.moves.cPickle as pickle
import numpy as np
try:
	import cv2 as cv
except:
	pass
from progressbar import ProgressBar

class AnimeFaceDataset:
	def __init__(self):
		self.data_dir_path = u"./animeface-character-dataset/thumb/"
		self.data = None
		self.target = None
		self.n_types_target = -1
		self.dump_name = u'animedata'
		self.image_size = 32

	def get_dir_list(self):
		tmp = os.listdir(self.data_dir_path)
		if tmp is None:
			return None
		ret = []
		for x in tmp:
			if os.path.isdir(self.data_dir_path+x):
				if len(os.listdir(self.data_dir_path+x)) >= 2:
					ret.append(x)
		return sorted(ret)

	def get_class_id(self, fname):
		dir_list = self.get_dir_list()
		dir_name = filter(lambda x: x in fname, dir_list)
		return dir_list.index(dir_name[0])

	def get_class_name(self, id):
		dir_list = self.get_dir_list()
		return dir_list[id]

	def load_data_target(self):
		if os.path.exists(self.dump_name+".pkl"):
			print "load from pickle"
			self.load_dataset()
			print "done"
		else:
			dir_list = self.get_dir_list()
			ret = {}
			self.target = []
			self.data = []
			print("now loading...")
			pb = ProgressBar(min_value=0, max_value=len(dir_list)).start()
			for i, dir_name in enumerate(dir_list):
				pb.update(i)
				file_list = os.listdir(self.data_dir_path+dir_name)
				for file_name in file_list:
					root, ext = os.path.splitext(file_name)
					if ext == u'.png':
						abs_name = self.data_dir_path+dir_name+'/'+file_name
						# read class id i.e., target
						class_id = self.get_class_id(abs_name)
						self.target.append(class_id)
						# read image i.e., data
						image = cv.imread(abs_name)
						image = cv.resize(image, (self.image_size, self.image_size))
						image = image.transpose(2,0,1)
						image = image/255.
						self.data.append(image)
			pb.finish()
			print("done.")
			self.data = np.array(self.data, np.float32)
			self.target = np.array(self.target, np.int32)

			self.dump_dataset()

	def dump_dataset(self):
		pickle.dump((self.data,self.target), open(self.dump_name+".pkl", 'wb'), -1)

	def load_dataset(self):
		self.data, self.target = pickle.load(open(self.dump_name+".pkl", 'rb'))


if __name__ == '__main__':
	dataset = AnimeFaceDataset()
	dataset.load_data_target()

Quand je l'ai lu

In [1]: from animeface import AnimeFaceDataset

In [2]: dataset = AnimeFaceDataset()

In [3]: dataset.load_data_target()
load from pickle
done

In [4]: x = dataset.data

In [5]: y = dataset.target

In [6]: print x.shape, y.shape
(14490, 3, 32, 32) (14490,)

Par conséquent, le nombre de données est de 14490 et le nombre de classes (nombre de caractères) est de 176. (Jusqu'à présent, c'est presque la même chose que la dernière fois.)

Implémentation de réseaux de neurones convolutifs par Keras

Construire un modèle

from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Dense
from keras.layers.core import Dropout
from keras.layers.core import Flatten
from keras.models import Sequential

def build_deep_cnn(num_classes=3):
	model = Sequential()

	model.add(Convolution2D(96, 3, 3, border_mode='same', input_shape=(3, 32, 32)))
	model.add(Activation('relu'))

	model.add(Convolution2D(128, 3, 3))
	model.add(Activation('relu'))
	model.add(MaxPooling2D(pool_size=(2, 2)))
	model.add(Dropout(0.5))

	model.add(Convolution2D(256, 3, 3, border_mode='same'))
	model.add(Activation('relu'))

	model.add(Convolution2D(256, 3, 3))
	model.add(Activation('relu'))
	model.add(MaxPooling2D(pool_size=(2, 2)))
	model.add(Dropout(0.5))

	model.add(Flatten())
	model.add(Dense(1024))
	model.add(Activation('relu'))
	model.add(Dropout(0.5))

	model.add(Dense(num_classes))
	model.add(Activation('softmax'))
	
	return model

Vous pouvez construire un réseau simplement en générant d'abord un modèle séquentiel avec model = Sequential () puis en y ajoutant Convolutional2D et Dense. On a l'impression que «Convolutional2D» correspond à la couche de convolution et «Dense» correspond à la couche entièrement connectée. Le tout premier,

Convolution2D(96, 3, 3, border_mode='same', input_shape=(3, 32, 32))

Il suffit de spécifier ʻinput_shape. Pour expliquer brièvement Convolutional2D, le premier argument spécifie le nombre de noyaux convolutifs, et les deuxième et troisième arguments spécifient la taille du noyau convolutif. Il existe deux types de border_mode, sameetvalid, mais dans same, le remplissage est la moitié de la taille du noyau, c'est-à-dire que la taille verticale et horizontale de la sortie ne change pas la taille verticale et horizontale de l'entrée. .. «valide» signifie qu'il n'y a pas de remplissage, c'est-à-dire que les dimensions verticale et horizontale de la sortie sont plus petites que les dimensions verticale et horizontale de l'entrée. En ce qui concerne le remplissage, [ici](https://github.com/vdumoulin/conv_arithmetic) est facile à comprendre. Cette fois, la "forme" du noyau de convolution avec "même" est "(96, 3, 3)", et la "forme" de l'entrée est "(3, 32, 32)", donc la "forme" de la sortie de cette couche est ". Cela devient (96, 32, 32) ». Dans le cas de «valide», la forme de sortie »est« (96, 32- (3-1), 32- (3-1)) = (96, 30, 30) ». Vous pouvez également définir stride`, etc.

Apprentissage de modèle

from keras.callbacks import EarlyStopping
from keras.callbacks import LearningRateScheduler
from keras.optimizers import Adam
from keras.optimizers import SGD
from animeface import AnimeFaceDataset

class Schedule(object):
	def __init__(self, init=0.01):
		self.init = init
	def __call__(self, epoch):
		lr = self.init
		for i in xrange(1, epoch+1):
			if i%5==0:
				lr *= 0.5
		return lr

def get_schedule_func(init):
	return Schedule(init)

dataset = AnimeFaceDataset()
dataset.load_data_target()
x = dataset.data
y = dataset.target
n_class = len(set(y))
perm = np.random.permutation(len(y))
x = x[perm]
y = y[perm]

model = build_deep_cnn(n_class)
model.summary()
init_learning_rate = 1e-2
opt = SGD(lr=init_learning_rate, decay=0.0, momentum=0.9, nesterov=False)
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=["acc"])
early_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=0, mode='auto')
lrs = LearningRateScheduler(get_schedule_func(init_learning_rate))

hist = model.fit(x, y, 
				batch_size=128, 
				nb_epoch=50, 
				validation_split=0.1, 
				verbose=1, 
				callbacks=[early_stopping, lrs])

Pour les callbacks de l'argument de la fonction fit à apprendre, spécifiez ʻEarly Stopping, qui termine automatiquement l'apprentissage lorsque la convergence est déterminée, ou LearningRateScheduler, qui peut ajuster le taux d'apprentissage pour chaque ʻepoch. C'est pratique et peut être fait.

Pour expliquer brièvement «LearningRateScheduler», nous prenons «une fonction qui renvoie le taux d'apprentissage lorsque le nombre actuel de« epoch »est donné à l'argument (commençant par 0)» comme argument. Par exemple

class Schedule(object):
    def __init__(self, init=0.01):
        self.init = init
    def __call__(self, epoch):
        lr = self.init
        for i in xrange(1, epoch+1):
            if i%5==0:
                lr *= 0.5
        return lr

def get_schedule_func(init):
    return Schedule(init)

lrs = LearningRateScheduler(get_schedule_fun(0.01))

Si vous faites comme cela, le taux d'apprentissage initial sera de 0,01 et le taux d'apprentissage sera divisé par deux toutes les 5 époques.

De plus, la fonction d'erreur pour chaque époque est enregistrée dans le ".history" de l'objet de valeur de retour de "fit" dans un type de dictionnaire. Pandas et Matplotlib peuvent être utilisés pour une visualisation pratique.

import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")

df = pd.DataFrame(hist.history)
df.index += 1
df.index.name = "epoch"
df[["acc", "val_acc"]].plot(linewidth=2)
plt.savefig("acc_history.pdf")
df[["loss", "val_loss"]].plot(linewidth=2)
plt.savefig("loss_history.pdf")

Résultat expérimental

Les résultats sont les suivants, et le taux de réponse correcte pour la vérification était inférieur à 60%. En fait, si Adam est utilisé comme méthode d'optimisation, le taux de réponse correct pour la vérification dépasse 70%, alors essayez-le.

Transition de la fonction d'erreur

スクリーンショット 2016-06-12 14.40.39.png

Transition du taux de réponse correcte

スクリーンショット 2016-06-12 14.40.15.png

Recommended Posts

Classer les visages d'anime par suite / apprentissage profond avec Keras
Classez les visages d'anime avec l'apprentissage en profondeur avec Chainer
Classer les numéros mnist par keras sans apprentissage par l'enseignant [Auto Encoder Edition]
Détection d'objets par apprentissage profond pour comprendre en profondeur par Keras
[Introduction à StyleGAN2] Apprentissage indépendant avec 10 visages d'anime ♬
99,78% de précision avec apprentissage en profondeur en reconnaissant les hiragana manuscrits
Apprentissage parallèle du deep learning par Keras et Kubernetes
Analyse d'images par apprentissage profond à partir de Kaggle et Keras
Classer les articles avec des balises spécifiées par Qiita par apprentissage non supervisé
Créez un "bot qui vous informe des actrices audiovisuelles aux visages similaires" grâce à l'apprentissage en profondeur
Essayez l'apprentissage en profondeur avec TensorFlow
Apprentissage profond du noyau avec Pyro
Générez des Pokémon avec Deep Learning
Essayez le Deep Learning avec les concombres FPGA-Select
Identification de la race de chat avec Deep Learning
Faites de l'art ASCII avec l'apprentissage en profondeur
J'ai essayé de rendre le deep learning évolutif avec Spark × Keras × Docker
Apprentissage automatique avec docker (42) Programmation PyTorch pour l'apprentissage en profondeur par Ian Pointer
Apprentissage profond appris par l'implémentation 1 (édition de retour)
Vérifiez la forme de squat avec l'apprentissage en profondeur
Catégoriser les articles de presse grâce au Deep Learning
Prévisions des ventes de collations avec apprentissage en profondeur
Faites sourire les gens avec le Deep Learning
Triez les visages d'anime en grattant les pages de personnages d'anime avec Beautiful Soup et Selenium
J'ai essayé de classer Oba Hanana et Otani Emiri par apprentissage profond
Deep learning 2 appris par l'implémentation (classification d'images)
Tentative de classification des polices de pictogrammes avec Keras
Essayez les prévisions de prix Bitcoin avec Deep Learning
Essayez avec Chainer Deep Q Learning - Lancement
Reconnaissance faciale des personnages d'anime avec Keras
Produisez de belles vaches de mer par apprentissage profond
Essayez l'apprentissage profond de la génomique avec Kipoi
L'apprentissage en profondeur
J'ai essayé de classer Hanana Oba et Emiri Otani par apprentissage profond (partie 2)
J'ai essayé de rendre le deep learning évolutif avec Spark × Keras × Docker 2 Multi-host edition
Chainer et deep learning appris par approximation de fonction
Apprentissage profond appris par la mise en œuvre ~ Détection d'anomalies (apprentissage sans enseignant) ~
Interpolation d'images vidéo par apprentissage en profondeur, partie 1 [Python]
Classer les informations liées à l'apprentissage automatique par modèle de sujet
Apprentissage profond appris par mise en œuvre (segmentation) ~ Mise en œuvre de SegNet ~
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 16) J'ai essayé de créer SimpleConvNet avec Keras
Apprenez en exécutant avec le nouveau Python! Manuel d'apprentissage automatique par Makoto Ito numpy / keras Attention!
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 17) J'ai essayé de créer DeepConvNet avec Keras
[Pour les débutants en apprentissage profond] Implémentation d'une classification binaire simple par couplage complet à l'aide de Keras