-
Notifications
You must be signed in to change notification settings - Fork 22
4 Gender Classifier
We use a binary classification to separate female faces as male faces. To train this classification , we need a dataset , I wrote a scraper ! A bot that can download faces from imdb. Here is script of scraper :
import requests
import bs4
import urllib2
base = "http://www.imdb.com"
gender = "female"
for start in range(200, 4000, 100):
print "Sending GET request ..."
url = '{}/search/name?gender={}&count=100&start={}'.format(base, gender, start)
r = requests.get(url)
html = r.text
soup = bs4.BeautifulSoup(html, 'html.parser')
for img in soup.select('.lister-item .lister-item-image'):
link = img.find('a').get('href')
name = img.find('img').get('alt')
print "Going to {} profile ...".format(name)
r = requests.get(base + link)
html = r.text
soup = bs4.BeautifulSoup(html, 'html.parser')
selector = soup.find('time')
if selector is None:
continue
date = selector.get('datetime')
selector = soup.find('img', {"id": "name-poster"})
if selector is None:
continue
image = selector.get('src')
print "Downloading profile picture ..."
image_file = urllib2.urlopen(image)
with open("{}_{}_{}.jpg".format(gender, start, date), 'wb') as output:
output.write(image_file.read())We can run this script for both genders , males and females. After retrieving more than 300 images for each gender , It's time to train our classifier.
Note : We used imdb-datasets , The file scanner.py may not work with new imdb front-end ! BTW , Repository contains more than 800 images.
We used dlib binary classificationthat worked with SVM.
Here is how we trained our SVM model ,
Following this algorithm :
- Read image file.
- Adjust gamma of image.
- Find faces using dlib face detector.
- Extract face landmarks.
- Create 128D vector of face ( face descriptor )
- If image file is from females category , label it
-1 - Else label it
+1( male ) - Set SVM's C parameter to
10 - Train using
svm_c_trainer_radial_basis - If result was not good , change C parameter and goto step
9 - Else , save classifier using
picklemodule.
face.py :
import dlib
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("./data/shape_predictor_68_face_landmarks.dat")
face_model = dlib.face_recognition_model_v1("./data/dlib_face_recognition_resnet_model_v1.dat")and train.py :
import glob
import dlib
import cv2
import pickle
import random
import face
import numpy as np
def adjust_gamma(input_image, gamma=1.0):
table = np.array([((iteration / 255.0) ** (1.0 / gamma)) * 255
for iteration in np.arange(0, 256)]).astype("uint8")
return cv2.LUT(input_image, table)
def read_image(path, gamma=0.75):
output = cv2.imread(path)
return adjust_gamma(output, gamma=gamma)
def face_vector(input_image):
faces = face.detector(input_image, 1)
if not faces:
return None
f = faces[0]
shape = face.predictor(input_image, f)
face_descriptor = face.face_model.compute_face_descriptor(input_image, shape)
return face_descriptor
max_size = 340
male_label = +1
female_label = -1
print "Retrieving males images ..."
males = glob.glob("./imdb-datasets/images/males/*.jpg")
print "Retrieved {} faces !".format(len(males))
print "Retrieving females images ..."
females = glob.glob("./imdb-datasets/images/females/*.jpg")
print "Retrieved {} faces !".format(len(females))
females = females[:max_size]
males = males[:max_size]
vectors = dlib.vectors()
labels = dlib.array()
print "Reading males images ..."
for i, male in enumerate(males):
print "Reading {} of {}\r".format(i, len(males))
face_vectors = face_vector(read_image(male))
if face_vectors is None:
continue
vectors.append(dlib.vector(face_vectors))
labels.append(male_label)
print "Reading females images ..."
for i, female in enumerate(females):
print "Reading {} of {}\r".format(i, len(females))
face_vectors = face_vector(read_image(female))
if face_vectors is None:
continue
vectors.append(dlib.vector(face_vectors))
labels.append(female_label)
svm = dlib.svm_c_trainer_radial_basis()
svm.set_c(10)
classifier = svm.train(vectors, labels)
print "Prediction for male sample: {}".format(classifier(vectors[random.randrange(0, max_size)]))
print "Prediction for female sample: {}".format(classifier(vectors[max_size + random.randrange(0, max_size)]))
with open('gender_model.pickle', 'wb') as handle:
pickle.dump(classifier, handle)then , open terminal and run these commands:
# create a directory
# paste codes from train and face module in train.py and face.py
git clone https://github.com/mrl-athomelab/imdb-datasets
mkdir data
cd data
# download shape_predictor_68_face_landmarks.dat and
# dlib_face_recognition_resnet_model_v1.dat in this place
cd ..
python train.pyfor test your model , you can use gender_model.pickle like this :
classifier = pickle.load(open('gender_model.pickle', 'r'))
# face_descriptor from compute_face_descriptor function
prediction = classifier(compute_face_descriptor)result of classifier is a float number , you can make it logical with following code :
def is_male(p, thresh=0.5):
return p > thresh
def is_female(p, thresh=-0.5):
return p < thresh
Credits to Shahrzad series.