INTRODUCTION
Das Bild oben ist vom Miss Campus Ritsumeikan 2014. Jeder ist sehr schön.
Andererseits scheint auf den ersten Blick jeder das gleiche Gesicht zu haben. Rufen Sie freundlicherweise Freunde an? Ich werde dieses __Ritsumeikan-ähnliche Gesicht __ nennen.
Außerdem höre ich oft Wörter wie "Seigaku-ish" und "Lass uns nach Gakuin gehen", aber das liegt auch daran, dass es __ Seigaku-ähnliche Gesichter __ und __ Gakuin-ähnliche Gesichter __ gibt. Ich glaube schon.
Daher habe ich dieses Mal die Gesichtstendenz jeder Universität gründlich gelernt und ein Modell erstellt, das bestimmen kann, an welcher Universität eine schöne Frau wahrscheinlich ist.
APPROACH
Holen Sie sich zuerst die Bilder von Frauen von jeder Universität. Ich habe die Miss Contest Portal Site verwendet, weil die Fotos der vergangenen Miscon jeder Universität systematisch gesammelt wurden.
photo_collector.py
# -*- coding:utf-8 -*-
import os
import bs4
import time
import random
import urllib2
from itertools import chain
from urllib import urlretrieve
base_url = 'http://misscolle.com'
def fetch_page_urls():
html = urllib2.urlopen('{}/versions'.format(base_url))
soup = bs4.BeautifulSoup(html, 'html.parser')
columns = soup.find_all('ul', class_='columns')
atags = map(lambda column: column.find_all('a'), columns)
with open('page_urls.txt', 'w') as f:
for _ in chain.from_iterable(atags):
path = _.get('href')
if not path.startswith('http'): # Relative path
path = '{}{}'.format(base_url, path)
if path[-1] == '/': # Normalize
path = path[:-1]
f.write('{}\n'.format(path))
def fetch_photos():
with open('page_urls.txt') as f:
for url in f:
# Make directories for saving images
dirpath = 'photos/{}'.format(url.strip().split('/')[-1])
os.makedirs(dirpath)
html = urllib2.urlopen('{}/photo'.format(url.strip()))
soup = bs4.BeautifulSoup(html, 'html.parser')
photos = soup.find_all('li', class_='photo')
paths = map(lambda path: path.find('a').get('href'), photos)
for path in paths:
filename = '_'.join(path.split('?')[0].split('/')[-2:])
filepath = '{}/{}'.format(dirpath, filename)
# Download image file
urlretrieve('{}{}'.format(base_url, path), filepath)
# Add random waiting time (4 - 6 sec)
time.sleep(4 + random.randint(0, 2))
if __name__ == '__main__':
fetch_page_urls()
fetch_photos()
Bei der Ausführung wird es mit der folgenden Verzeichnisstruktur gespeichert.
http://misscolle.com/img/contests/aoyama2015/1/1.jpg ist photos / aoyama / 2015 / 1_1.jpg
zugeordnet.
photos/
├── aoyama
│ ├── 2008
│ │ ├── 1_1.jpg
│ │ ├── 1_2.jpg
│ │ ├── ...
│ │ ├── 2_1.jpg
│ │ ├── 2_2.jpg
│ │ ├── ...
│ │ └── 6_9.jpg
│ ├── 2009
│ │ ├── 1_1.jpg
│ │ ├── 1_2.jpg
│ │ ├── ...
Als Ergebnis wurden insgesamt 10.725 Bilder (ca. 2,5 G) von 82 Universitäten gesammelt. Es freut mich, es zu sehen.
Als nächstes wird der Gesichtsbereich von OpenCV anhand dieser Bilder erkannt und zugeschnitten. Der verwendete Evaluator war "frontalface_alt2".
face_detecter.py
# -*- coding:utf-8 -*-
import os
import cv2
def main():
for srcpath, _, files in os.walk('photos'):
if len(_):
continue
dstpath = srcpath.replace('photos', 'faces')
os.makedirs(dstpath)
for filename in files:
if filename.startswith('.'): # Pass .DS_Store
continue
try:
detect_faces(srcpath, dstpath, filename)
except:
continue
def detect_faces(srcpath, dstpath, filename):
cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml')
image = cv2.imread('{}/{}'.format(srcpath, filename))
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = cascade.detectMultiScale(gray_image)
# Extract when just one face is detected
if (len(faces) == 1):
(x, y, w, h) = faces[0]
image = image[y:y+h, x:x+w]
image = cv2.resize(image, (100, 100))
cv2.imwrite('{}/{}'.format(dstpath, filename), image)
if __name__ == '__main__':
main()
Wenn dies ausgeführt wird, wird das Gesichtsbild in "Gesichter /" mit derselben Verzeichnisstruktur wie zuvor gespeichert. Ich bin froh, das auch zu sehen (ry
Lassen Sie uns zum Schluss mit CNN lernen. Zunächst haben wir Universitäten anhand der folgenden Kriterien überprüft.
Aus den 20 Universitäten, die durch dieses Screening unter Druck gesetzt wurden, haben wir uns entschlossen, die folgenden 10 Universitäten nach eigenem Ermessen auszuwählen und in 10 Klassen einzuteilen.
Die Testdaten für jede Universität und das letzte Jahr werden verwendet, und die anderen Trainingsdaten werden verwendet. Die Trainingsdaten und Testdaten betrugen 1.700 bzw. 154.
Erstellen Sie mit Tensorflow ein CNN und führen Sie das Lernen durch.
cnn.py
# -*- coding:utf-8 -*-
import os
import random
import numpy as np
import tensorflow as tf
label_dict = {
'aoyama': 0, 'jissen': 1, 'keio': 2, 'phoenix': 3, 'rika': 4,
'rikkyo': 5, 'seikei': 6, 'sophia': 7, 'todai': 8, 'tonjo': 9
}
def load_data(data_type):
filenames, images, labels = [], [], []
walk = filter(lambda _: not len(_[1]) and data_type in _[0], os.walk('faces'))
for root, dirs, files in walk:
filenames += ['{}/{}'.format(root, _) for _ in files if not _.startswith('.')]
# Shuffle files
random.shuffle(filenames)
# Read, resize, and reshape images
images = map(lambda _: tf.image.decode_jpeg(tf.read_file(_), channels=3), filenames)
images = map(lambda _: tf.image.resize_images(_, [32, 32]), images)
images = map(lambda _: tf.reshape(_, [-1]), images)
for filename in filenames:
label = np.zeros(10)
for k, v in label_dict.iteritems():
if k in filename:
label[v] = 1.
labels.append(label)
return images, labels
def get_batch_list(l, batch_size):
# [1, 2, 3, 4, 5,...] -> [[1, 2, 3], [4, 5,..]]
return [np.asarray(l[_:_+batch_size]) for _ in range(0, len(l), batch_size)]
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')
def inference(images_placeholder, keep_prob):
# Convolution layer
x_image = tf.reshape(images_placeholder, [-1, 32, 32, 3])
W_conv1 = weight_variable([5, 5, 3, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
# Pooling layer
h_pool1 = max_pool_2x2(h_conv1)
# Convolution layer
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
# Pooling layer
h_pool2 = max_pool_2x2(h_conv2)
# Full connected layer
W_fc1 = weight_variable([8 * 8 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 8 * 8 * 64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
# Dropout
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# Full connected layer
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
return tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
def main():
with tf.Graph().as_default():
train_images, train_labels = load_data('train')
test_images, test_labels = load_data('test')
x = tf.placeholder('float', shape=[None, 32 * 32 * 3]) # 32 * 32, 3 channels
y_ = tf.placeholder('float', shape=[None, 10]) # 10 classes
keep_prob = tf.placeholder('float')
y_conv = inference(x, keep_prob)
# Loss function
cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv))
tf.summary.scalar('cross_entropy', cross_entropy)
# Minimize cross entropy by using SGD
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
# Accuracy
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
tf.summary.scalar('accuracy', accuracy)
saver = tf.train.Saver()
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
summary_op = tf.summary.merge_all()
summary_writer = tf.summary.FileWriter('./logs', sess.graph)
batched_train_images = get_batch_list(train_images, 25)
batched_train_labels = get_batch_list(train_labels, 25)
train_images = map(lambda _: sess.run(_).astype(np.float32) / 255.0, np.asarray(train_images))
test_images = map(lambda _: sess.run(_).astype(np.float32) / 255.0, np.asarray(test_images))
train_labels, test_labels = np.asarray(train_labels), np.asarray(test_labels)
# Train
for step, (images, labels) in enumerate(zip(batched_train_images, batched_train_labels)):
images = map(lambda _: sess.run(_).astype(np.float32) / 255.0, images)
sess.run(train_step, feed_dict={ x: images, y_: labels, keep_prob: 0.5 })
train_accuracy = accuracy.eval(feed_dict = {
x: train_images, y_: train_labels, keep_prob: 1.0 })
print 'step {}, training accuracy {}'.format(step, train_accuracy)
summary_str = sess.run(summary_op, feed_dict={
x: train_images, y_: train_labels, keep_prob: 1.0 })
summary_writer.add_summary(summary_str, step)
# Test trained model
test_accuracy = accuracy.eval(feed_dict = {
x: test_images, y_: test_labels, keep_prob: 1.0 })
print 'test accuracy {}'.format(test_accuracy)
# Save model
save_path = saver.save(sess, "model.ckpt")
if __name__ == '__main__':
main()
Aufgrund des Mangels an Trainingsdaten lag die Präzisionsrate bei etwa 20% und das Lernen machte keine großen Fortschritte. Die Genauigkeit der Testdaten beträgt jedoch 19,48% (die Basis beträgt 10%, da sie in 10 Klassen eingeteilt ist), was bedeutet, dass 1 von 5 Personen zugeordnet ist. Aus diesem Lernergebnis geht hervor, dass eine vernünftige Tendenz unterdrückt wurde. Ist das so ...
EXPERIMENTAL RESULTS
Anhand dieses Lernmodells werde ich versuchen, anhand des folgenden Bildes festzustellen, wie die Universität Gacky aussieht. Main in cnn.py
wurde durch Folgendes ersetzt.
cnn.py
def main():
with tf.Graph().as_default():
test_images, test_labels = load_data('experiment')
x = tf.placeholder('float', shape=[None, 32 * 32 * 3]) # 32 * 32, 3 channels
y_ = tf.placeholder('float', shape=[None, 10]) # 10 classes
keep_prob = tf.placeholder('float')
y_conv = inference(x, keep_prob)
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(sess, "./model.ckpt")
test_images = map(lambda _: sess.run(_).astype(np.float32) / 255.0, np.asarray(test_images))
print y_conv.eval(feed_dict={ x: [train_images[0]], keep_prob: 1.0 })[0]
print np.argmax(y_conv.eval(feed_dict={ x: [train_images[0]], keep_prob: 1.0 })[0])
Das Folgende ist das Ausführungsergebnis. Das Ergebnis war, dass Gacky ein blauäugiges Gesicht hatte (34,83%). Ich habe das Gefühl zu wissen, was es ist. Nach Seigaku gingen die Nihon University und Rikkyo weiter.
#Entspricht dem Folgenden
#
# label_dict = {
# 'aoyama': 0, 'jissen': 1, 'keio': 2, 'phoenix': 3, 'rika': 4,
# 'rikkyo': 5, 'seikei': 6, 'sophia': 7, 'todai': 8, 'tonjo': 9
# }
[ 0.34834844 0.0005422 0.00995418 0.21047674 0.13970862 0.15559362 0.03095848 0.09672297 0.00721581 0.00047894]
# argmax
0
RELATED WORK
Neulich in Singapur angekündigt fand ich es erstaunlich.
Können Sie die App ChiChi, die Sie zuvor entwickelt haben (sie hat Apples Prüfung nicht bestanden), mit hoher Genauigkeit identifizieren und die Anzahl der Tassen ermitteln, indem Sie einfach Ihr Smartphone in der Brust halten? Ich möchte konkurrieren.
FUTURE WORK
An jeder Universität deuten die Ergebnisse darauf hin, dass das Gesicht eine leichte Tendenz aufweist, die Genauigkeit jedoch immer noch gering ist. Daher möchte ich die Genauigkeit verbessern, indem ich die Daten erhöhe und das Modell optimiere. .. Dieses Mal habe ich ein ziemlich einfaches Modell erstellt, aber wenn Sie sich den Code in cifar10 im Tensorflow-Tutorial ansehen, Ich denke, es gibt verstreute Elemente, die abgestimmt werden können.
Lassen Sie uns außerdem als horizontale Entwicklung die Bilder schöner Frauen in jeder Präfektur von Beauty Clock lernen und zeigen, welches präfekturähnliche Gesicht eine bestimmte schöne Frau hat. Ich finde es auch interessant.
Recommended Posts