Vor ungefähr einem Jahr geschrieben in Chainer Dies ist ein Programm zum Klassifizieren von Anime-Gesichtern, aber dieses Mal habe ich es in Keras geschrieben. Das Programm ist auf GitHub aufgeführt.
Der Datensatz kann aus Animeface-Character-Dataset bezogen werden. Referenz: Ich habe versucht, die Funktionen des animierten Gesichts mit Denoising AutoEncoder zu extrahieren
Ich habe es etwas mehr als zuvor verbessert. Ändern Sie die Größe auf 32 x 32 RGB-Daten (Form = (3, 32, 32)). Der Unterschied zum letzten Mal besteht darin, dass es wahrscheinlich auch dann funktioniert, wenn Sie den leeren Ordner, der keine Daten enthält, nicht löschen. Bedarf
Es ist.
#! -*- 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()
Wenn ich es tatsächlich lese
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,)
Daher beträgt die Anzahl der Daten 14490 und die Anzahl der Klassen (Anzahl der Zeichen) 176. (Bis zu diesem Punkt ist es fast das gleiche wie beim letzten Mal.)
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
Sie können ein Netzwerk einfach aufbauen, indem Sie zuerst ein sequentielles Modell mit model = Sequential ()
generieren und dann Convolutional2D
und Dense
hinzufügen.
Es fühlt sich an, als ob "Convolutional2D" der Faltungsschicht entspricht und "Dense" der vollständig verbundenen Schicht entspricht.
Der aller erste,
Convolution2D(96, 3, 3, border_mode='same', input_shape=(3, 32, 32))
Es muss nur "input_shape" angegeben werden. Um "Convolutional2D" kurz zu erklären, gibt das erste Argument die Anzahl der Faltungskerne an, und das zweite und dritte Argument geben die Größe des Faltungskerns an. Es gibt zwei Arten von "border_mode", "same" und "valid", aber in "same" ist das Auffüllen halb so groß wie der Kernel, dh die vertikale und horizontale Größe der Ausgabe ändert nichts an der vertikalen und horizontalen Größe der Eingabe. .. "gültig" bedeutet, dass keine Auffüllung vorhanden ist, dh die vertikalen und horizontalen Abmessungen der Ausgabe sind kleiner als die vertikalen und horizontalen Abmessungen der Eingabe. In Bezug auf die Polsterung ist hier leicht zu verstehen. Dieses Mal ist die "Form" des Faltungskerns "(96, 3, 3)" und die "Form" der Eingabe ist "(3, 32, 32)", also ist die "Form" der Ausgabe dieser Schicht " Es wird (96, 32, 32) `. Im Fall von "gültig" ist die Ausgabeform "(96, 32- (3-1), 32- (3-1)) = (96, 30, 30)". Sie können auch "Schritt" usw. einstellen.
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])
Geben Sie für die "Rückrufe" der "Fit" -Funktion "EarlyStopping" an, das das Lernen automatisch beendet, wenn die Konvergenz bestimmt wird, oder "LearningRateScheduler", mit dem die Lernrate für jede "Epoche" angepasst werden kann. Es ist bequem und kann getan werden.
Um "LearningRateScheduler" kurz zu erklären, wird "eine Funktion verwendet, die die Lernrate zurückgibt, wenn dem Argument die aktuelle" Epochennummer "(beginnend mit 0) gegeben wird". Zum Beispiel
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))
Wenn Sie dies mögen, beträgt die anfängliche Lernrate 0,01 und die Lernrate wird alle 5 Epochen halbiert.
Zusätzlich wird die Fehlerfunktion für jede Epoche in der ".history" des Rückgabewertobjekts "fit" in einem Wörterbuchtyp gespeichert. Pandas und Matplotlib können zur bequemen Visualisierung verwendet werden.
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")
Die Ergebnisse sind wie folgt und die korrekte Antwortrate für die Überprüfung betrug weniger als 60%. Wenn Adam als Optimierungsmethode verwendet wird, liegt die korrekte Antwortrate für die Überprüfung tatsächlich über 70%. Versuchen Sie es also bitte.
Recommended Posts