Skip to content

4 Gender Classifier

Ahmadreza Zibaei edited this page Nov 14, 2018 · 1 revision

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.

Time to train classifier !

We used dlib binary classificationthat worked with SVM.

Here is how we trained our SVM model ,

Following this algorithm :

  1. Read image file.
  2. Adjust gamma of image.
  3. Find faces using dlib face detector.
  4. Extract face landmarks.
  5. Create 128D vector of face ( face descriptor )
  6. If image file is from females category , label it -1
  7. Else label it +1 ( male )
  8. Set SVM's C parameter to 10
  9. Train using svm_c_trainer_radial_basis
  10. If result was not good , change C parameter and goto step 9
  11. Else , save classifier using pickle module.

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.py

for 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

demo of gender detection

Credits to Shahrzad series.

Clone this wiki locally