INTRODUCTION
L'image ci-dessus provient du Miss Campus Ritsumeikan 2014. Tout le monde est très beau.
En revanche, à première vue, tout le monde semble avoir le même visage. Est-ce que la gentillesse appelle des amis? J'appellerai ce visage de __Ritsumeikan __.
Aussi, j'entends souvent des mots comme "Seigaku-ish" et "Allons à Gakuin", mais c'est aussi parce qu'il y a __ des visages de type Seigaku __ et __ des visages de type Gakuin __. Je le pense.
Par conséquent, cette fois, j'ai fait un apprentissage approfondi de la tendance faciale de chaque université et créé un modèle qui peut déterminer dans quelle université une belle femme est susceptible d'être.
APPROACH
Premièrement, obtenez les images des femmes de chaque université. J'ai utilisé le Site Portail Miss Concours car les photos du passé Miscon de chaque université étaient systématiquement collectées.
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()
Une fois exécuté, il sera enregistré avec la structure de répertoires suivante.
http://misscolle.com/img/contests/aoyama2015/1/1.jpg est mappé sur photos / aoyama / 2015 / 1_1.jpg
.
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
│ │ ├── ...
En conséquence, un total de 10725 images (environ 2,5G) provenant de 82 universités ont été collectées. Cela me fait plaisir de le voir.
Ensuite, la zone du visage est détectée par OpenCV à partir de ces images et découpée. L'évaluateur utilisé était 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()
Quand ceci est exécuté, l'image du visage sera enregistrée dans faces /
avec la même structure de répertoire qu'auparavant. Je suis heureux de voir ça aussi (ry
Enfin, apprenons avec CNN. Premièrement, nous avons sélectionné les universités en fonction des critères suivants.
--Il existe des données sur les erreurs au cours des 5 dernières années ou plus.
Ensuite, parmi les 20 universités pressées par cette présélection, nous avons décidé de sélectionner les 10 universités suivantes à notre discrétion et de les classer en 10 classes.
Les données de test pour chaque université et la dernière année sont utilisées, et les autres données de formation sont utilisées. Les données d'entraînement et les données de test étaient respectivement de 1 700 et 154.
Créez un CNN avec Tensorflow et effectuez un apprentissage.
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()
En raison du manque de données de formation, le taux de précision était d'environ 20% et l'apprentissage n'a pas beaucoup progressé. Cependant, la précision des données de test est de 19,48% (la base est de 10% car elle est classée en 10 classes), ce qui signifie qu'une personne sur 5 est affectée, donc à partir de ce résultat d'apprentissage, il est dit qu'une tendance raisonnable a été supprimée. Est-ce vrai ...
EXPERIMENTAL RESULTS
En utilisant ce modèle d'apprentissage, je vais essayer de déterminer à quelle université Gacky ressemble à partir de l'image ci-dessous. Remplacement de main dans cnn.py
par ce qui suit.
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])
Voici le résultat de l'exécution. Le résultat était que Gacky avait un visage aux yeux bleus (34,83%). J'ai l'impression de savoir ce que c'est. Après Seigaku, l'Université Nihon et Rikkyo ont continué.
#Correspond à ce qui suit
#
# 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
L'autre jour annoncé à Singapour, j'ai trouvé ça incroyable.
Pouvez-vous identifier avec une grande précision l'application ChiChi que vous avez développée auparavant (elle n'a pas passé l'examen d'Apple) et vous pouvez connaître le nombre de tasses simplement en tenant votre smartphone dans votre poitrine? Je veux concourir.
FUTURE WORK
Dans chaque université, les résultats suggèrent qu'il y a une légère tendance dans le visage, mais la précision est encore faible, je voudrais donc améliorer la précision en augmentant les données et en ajustant le modèle. .. Cette fois, j'ai construit un modèle assez simple, mais si vous regardez le code dans cifar10 dans le didacticiel Tensorflow, Je pense qu'il y a des éléments épars qui peuvent être réglés.
De plus, en tant que développement horizontal, apprenons les images de belles femmes dans chaque préfecture de Beauty Clock et montrons quel visage de préfecture a une certaine belle femme. Je pense que c'est aussi intéressant.
Recommended Posts