Skip to content

Instantly share code, notes, and snippets.

@GilLevi
Last active July 25, 2023 18:05
Show Gist options
  • Save GilLevi/c9e99062283c719c03de to your computer and use it in GitHub Desktop.
Save GilLevi/c9e99062283c719c03de to your computer and use it in GitHub Desktop.
Age and Gender Classification using Convolutional Neural Networks

Age and Gender Classification using Convolutional Neural Networks

name: Age Classification CNN

caffemodel: age_net.caffemodel

caffemodel_url: https://github.com/GilLevi/AgeGenderDeepLearning/raw/master/models/age_net.caffemodel

name: Gender Classification CNN

caffemodel: gender_net.caffemodel

caffemodel_url: https://github.com/GilLevi/AgeGenderDeepLearning/raw/master/models/gender_net.caffemodel

--

mean_file_proto: https://github.com/GilLevi/AgeGenderDeepLearning/raw/master/models/mean.binaryproto

gist_id: c9e99062283c719c03de

Description

Convolutional neural networks for age and gender classification as described in the following work:

Gil Levi and Tal Hassner, Age and Gender Classification Using Convolutional Neural Networks, IEEE Workshop on Analysis and Modeling of Faces and Gestures (AMFG), at the IEEE Conf. on Computer Vision and Pattern Recognition (CVPR), Boston, June 2015

Project page: http://www.openu.ac.il/home/hassner/projects/cnn_agegender/

If you find our models useful, please add suitable reference to our paper in your work.


Copyright 2015, Gil Levi and Tal Hassner

The SOFTWARE provided in this page is provided "as is", without any guarantee made as to its suitability or fitness for any particular use. It may contain bugs, so use of this tool is at your own risk. We take no responsibility for any damage of any sort that may unintentionally be caused through its use.

net: "/home/ubuntu/AdienceFaces/age/train_val.prototxt"
test_iter: 1000
test_interval: 1000
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 10000
display: 20
max_iter: 50000
momentum: 0.9
weight_decay: 0.0005
snapshot: 1000
snapshot_prefix: "caffenet_train"
solver_mode: GPU
name: "CaffeNet"
layers {
name: "data"
type: DATA
top: "data"
top: "label"
data_param {
source: "/home/ubuntu/AdienceFaces/lmdb/age_train_lmdb"
backend: LMDB
batch_size: 50
}
transform_param {
crop_size: 227
mean_file: "/home/ubuntu/AdienceFaces/mean_image/mean.binaryproto"
mirror: true
}
include: { phase: TRAIN }
}
layers {
name: "data"
type: DATA
top: "data"
top: "label"
data_param {
source: "/home/ubuntu/AdienceFaces/lmdb/age_val_lmdb"
backend: LMDB
batch_size: 50
}
transform_param {
crop_size: 227
mean_file: "/home/ubuntu/AdienceFaces/mean_image/mean.binaryproto"
mirror: false
}
include: { phase: TEST }
}
layers {
name: "conv1"
type: CONVOLUTION
bottom: "data"
top: "conv1"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 96
kernel_size: 7
stride: 4
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
name: "relu1"
type: RELU
bottom: "conv1"
top: "conv1"
}
layers {
name: "pool1"
type: POOLING
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm1"
type: LRN
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv2"
type: CONVOLUTION
bottom: "norm1"
top: "conv2"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu2"
type: RELU
bottom: "conv2"
top: "conv2"
}
layers {
name: "pool2"
type: POOLING
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm2"
type: LRN
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv3"
type: CONVOLUTION
bottom: "norm2"
top: "conv3"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers{
name: "relu3"
type: RELU
bottom: "conv3"
top: "conv3"
}
layers {
name: "pool5"
type: POOLING
bottom: "conv3"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "fc6"
type: INNER_PRODUCT
bottom: "pool5"
top: "fc6"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 512
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu6"
type: RELU
bottom: "fc6"
top: "fc6"
}
layers {
name: "drop6"
type: DROPOUT
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc7"
type: INNER_PRODUCT
bottom: "fc6"
top: "fc7"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 512
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu7"
type: RELU
bottom: "fc7"
top: "fc7"
}
layers {
name: "drop7"
type: DROPOUT
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc8"
type: INNER_PRODUCT
bottom: "fc7"
top: "fc8"
blobs_lr: 10
blobs_lr: 20
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 8
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
name: "accuracy"
type: ACCURACY
bottom: "fc8"
bottom: "label"
top: "accuracy"
include: { phase: TEST }
}
layers {
name: "loss"
type: SOFTMAX_LOSS
bottom: "fc8"
bottom: "label"
top: "loss"
}
name: "CaffeNet"
input: "data"
input_dim: 1
input_dim: 3
input_dim: 227
input_dim: 227
layers {
name: "conv1"
type: CONVOLUTION
bottom: "data"
top: "conv1"
convolution_param {
num_output: 96
kernel_size: 7
stride: 4
}
}
layers {
name: "relu1"
type: RELU
bottom: "conv1"
top: "conv1"
}
layers {
name: "pool1"
type: POOLING
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm1"
type: LRN
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv2"
type: CONVOLUTION
bottom: "norm1"
top: "conv2"
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
}
}
layers {
name: "relu2"
type: RELU
bottom: "conv2"
top: "conv2"
}
layers {
name: "pool2"
type: POOLING
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm2"
type: LRN
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv3"
type: CONVOLUTION
bottom: "norm2"
top: "conv3"
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
}
}
layers{
name: "relu3"
type: RELU
bottom: "conv3"
top: "conv3"
}
layers {
name: "pool5"
type: POOLING
bottom: "conv3"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "fc6"
type: INNER_PRODUCT
bottom: "pool5"
top: "fc6"
inner_product_param {
num_output: 512
}
}
layers {
name: "relu6"
type: RELU
bottom: "fc6"
top: "fc6"
}
layers {
name: "drop6"
type: DROPOUT
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc7"
type: INNER_PRODUCT
bottom: "fc6"
top: "fc7"
inner_product_param {
num_output: 512
}
}
layers {
name: "relu7"
type: RELU
bottom: "fc7"
top: "fc7"
}
layers {
name: "drop7"
type: DROPOUT
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc8"
type: INNER_PRODUCT
bottom: "fc7"
top: "fc8"
inner_product_param {
num_output: 8
}
}
layers {
name: "prob"
type: SOFTMAX
bottom: "fc8"
top: "prob"
}
name: "CaffeNet"
input: "data"
input_dim: 1
input_dim: 3
input_dim: 227
input_dim: 227
layers {
name: "conv1"
type: CONVOLUTION
bottom: "data"
top: "conv1"
convolution_param {
num_output: 96
kernel_size: 7
stride: 4
}
}
layers {
name: "relu1"
type: RELU
bottom: "conv1"
top: "conv1"
}
layers {
name: "pool1"
type: POOLING
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm1"
type: LRN
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv2"
type: CONVOLUTION
bottom: "norm1"
top: "conv2"
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
}
}
layers {
name: "relu2"
type: RELU
bottom: "conv2"
top: "conv2"
}
layers {
name: "pool2"
type: POOLING
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm2"
type: LRN
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv3"
type: CONVOLUTION
bottom: "norm2"
top: "conv3"
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
}
}
layers{
name: "relu3"
type: RELU
bottom: "conv3"
top: "conv3"
}
layers {
name: "pool5"
type: POOLING
bottom: "conv3"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "fc6"
type: INNER_PRODUCT
bottom: "pool5"
top: "fc6"
inner_product_param {
num_output: 512
}
}
layers {
name: "relu6"
type: RELU
bottom: "fc6"
top: "fc6"
}
layers {
name: "drop6"
type: DROPOUT
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc7"
type: INNER_PRODUCT
bottom: "fc6"
top: "fc7"
inner_product_param {
num_output: 512
}
}
layers {
name: "relu7"
type: RELU
bottom: "fc7"
top: "fc7"
}
layers {
name: "drop7"
type: DROPOUT
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc8"
type: INNER_PRODUCT
bottom: "fc7"
top: "fc8"
inner_product_param {
num_output: 2
}
}
layers {
name: "prob"
type: SOFTMAX
bottom: "fc8"
top: "prob"
}
net: "/home/ubuntu/AdienceFaces/gender/train_val.prototxt"
test_iter: 1000
test_interval: 1000
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 10000
display: 20
max_iter: 50000
momentum: 0.9
weight_decay: 0.0005
snapshot: 1000
snapshot_prefix: "caffenet_train"
solver_mode: GPU
name: "CaffeNet"
layers {
name: "data"
type: DATA
top: "data"
top: "label"
data_param {
source: "/home/ubuntu/AdienceFaces/lmdb/gender_train_lmdb"
backend: LMDB
batch_size: 50
}
transform_param {
crop_size: 227
mean_file: "/home/ubuntu/AdienceFaces/mean_image/mean.binaryproto"
mirror: true
}
include: { phase: TRAIN }
}
layers {
name: "data"
type: DATA
top: "data"
top: "label"
data_param {
source: "/home/ubuntu/AdienceFaces/lmdb/gender_val_lmdb"
backend: LMDB
batch_size: 50
}
transform_param {
crop_size: 227
mean_file: "/home/ubuntu/AdienceFaces/mean_image/mean.binaryproto"
mirror: false
}
include: { phase: TEST }
}
layers {
name: "conv1"
type: CONVOLUTION
bottom: "data"
top: "conv1"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 96
kernel_size: 7
stride: 4
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
name: "relu1"
type: RELU
bottom: "conv1"
top: "conv1"
}
layers {
name: "pool1"
type: POOLING
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm1"
type: LRN
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv2"
type: CONVOLUTION
bottom: "norm1"
top: "conv2"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu2"
type: RELU
bottom: "conv2"
top: "conv2"
}
layers {
name: "pool2"
type: POOLING
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "norm2"
type: LRN
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
name: "conv3"
type: CONVOLUTION
bottom: "norm2"
top: "conv3"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers{
name: "relu3"
type: RELU
bottom: "conv3"
top: "conv3"
}
layers {
name: "pool5"
type: POOLING
bottom: "conv3"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
name: "fc6"
type: INNER_PRODUCT
bottom: "pool5"
top: "fc6"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 512
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu6"
type: RELU
bottom: "fc6"
top: "fc6"
}
layers {
name: "drop6"
type: DROPOUT
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc7"
type: INNER_PRODUCT
bottom: "fc6"
top: "fc7"
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 512
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
name: "relu7"
type: RELU
bottom: "fc7"
top: "fc7"
}
layers {
name: "drop7"
type: DROPOUT
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layers {
name: "fc8"
type: INNER_PRODUCT
bottom: "fc7"
top: "fc8"
blobs_lr: 10
blobs_lr: 20
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
name: "accuracy"
type: ACCURACY
bottom: "fc8"
bottom: "label"
top: "accuracy"
include: { phase: TEST }
}
layers {
name: "loss"
type: SOFTMAX_LOSS
bottom: "fc8"
bottom: "label"
top: "loss"
}
@darshanime
Copy link

Solved !

Had to make the following changes in 'caffe-master'/python/caffe/io.py with :

-                raise ValueError('Mean shape incompatible with input shape.')
+                print(self.inputs[in_])
+            in_shape = self.inputs[in_][1:]
+            m_min, m_max = mean.min(), mean.max()
+            normal_mean = (mean - m_min) / (m_max - m_min)
+            mean = resize_image(normal_mean.transpose((1,2,0)),
+                        in_shape[1:]).transpose((2,0,1)) * \
+                        (m_max - m_min) + m_min
+        #raise ValueError('Mean shape incompatible with input shape.')

@kli-casia
Copy link

@darshanime How did you creat age_train_lmdb, which file do you use? the aligned folder? Thank you

@berak
Copy link

berak commented Sep 14, 2015

hi @gil , any tips on making e.g. the gender classification run with opencv's new dnn module / caffe wrapper ?

@GilLevi
Copy link
Author

GilLevi commented Sep 15, 2015

@UttamDwivedi - sorry, but I've just seen your message. If it's still relevant, please mail me at gil.levi100@gmail.com and I'll try to help.

@darshanime, indeed there is a problem with a newer implementation of Caffe's io.py. We reported it in the project page: http://www.openu.ac.il/home/hassner/projects/cnn_agegender/

@berak, nice to see that CNN finally made it into OpenCV! I'll try to create a demo of our age/gender nets.

Gil.

@kli-casia
Copy link

@gil , which part is your traing data at http://www.cslab.openu.ac.il/download/AdienceBenchmarkOfUnfilteredFacesForGenderAndAgeClassification/

I find there are some image with age None, and some image don't have gender label. Did you use them for training? Because I want to use your dataset and compare to your result.
Thank you.

@GilLevi
Copy link
Author

GilLevi commented Oct 5, 2015

@kli-nlpr , I used only the labelled images. I can send you the train/val.txt to create the lmdb for training.

Gil

@kli-casia
Copy link

Hi, @gil, can you send the train/val.txt to me?
My email is kai.li@nlpr.ia.ac.cn
Thank you very much

@GilLevi
Copy link
Author

GilLevi commented Oct 19, 2015

@kli-nlpr, sorry for the late response.

I've added a new git repository for creating the train/val.txt files:
https://github.com/GilLevi/AgeGenderDeepLearning

@nitish11
Copy link

nitish11 commented Aug 16, 2016

Hi,

I am using the gender detection model in Torch and in Caffe for detection from live camera.

Running the code on CPU and keeping the same models file, I am getting different prediction times.
For Caffe, it is ~1.30 seconds per frame.
For Torch, it is ~0.45 seconds per frame.

What could be the possible reason for the time difference? Is Torch faster than Caffe?

@GilLevi
Copy link
Author

GilLevi commented Aug 25, 2016

@nitish11, like I commented in the repository , I don't have any experience in Torch, so I really can't tell which is faster.

@engesilva
Copy link

Hi Levi,

Levi I have some doubts about the network architecture used for the genre classification training:

  • Its current architecture identifies the "type" layer by capital letters (eg, CONVOLUTION.), Because you can not conduct training for replacing CONVOLUTION by "Convolution"; DATA by "Data"?

@GilLevi
Copy link
Author

GilLevi commented Oct 24, 2016

Hi @engesilva,

I think you might need to replace ALL CAPITALS with lowercase letters, depending on the version of Caffe you are using.

@akashjobanputra
Copy link

@GilLevi The dropbox links are not working. Hitting them shows file not found.

@GilLevi
Copy link
Author

GilLevi commented Sep 14, 2017

Hi @akashjobanputra, thank you for your interest in our work. I updated the links, they are now working.

@Gensoukyou1337
Copy link

Hi @GilLevi,

I've tested your Caffe models in the OpenCV DNN module on a live camera preview, and it's taking 1.6-1.7 seconds to process each frame. Are there any possible further optimizations I can use on the model, without sacrificing accuracy or with a minimum accuracy tradeoff, to make it faster? Because I've gotten another model that could do it in 11 ms (though with very low accuracy - most female faces are guessed male) that was only 2.5 MB in size (maybe trained with 510 images only).

@GilLevi
Copy link
Author

GilLevi commented Oct 27, 2017

Hi @Gensoukyou1337,

The easiest thing to consider is running on GPU and subsampling so you won't run on every single frame, but run the model on every X frames.

Aside from that, you can train a new model which is smaller and faster, but that would require a lot more work.

Best,
Gil

@fabito
Copy link

fabito commented Nov 14, 2017

Hi @GilLevi,

I wrote a simple sample using OpenCV 3.3.1 dnn module (see snippet below). I'm just a bit confused about the mean.binaryproto utilization. In the OpenCV API there is a mean parameter which, I suppose, plays the same role. I'm currently using:

Mat inputBlob = blobFromImage(img, 1.0f, Size(256, 256), Scalar(104, 117, 123), false);

Note the Scalar(104, 117, 123) which corresponds to the mean values which are subtracted from channels (BGR). Is that correct ?

#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/utils/trace.hpp>
using namespace cv;
using namespace cv::dnn;
#include <fstream>
#include <iostream>
#include <cstdlib>
using namespace std;

/* Find best class for the blob (i. e. class with maximal probability) */
static void getMaxClass(const Mat &probBlob, int *classId, double *classProb)
{
    Mat probMat = probBlob.reshape(1, 1); //reshape the blob to 1x1000 matrix
    Point classNumber;
    minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
    *classId = classNumber.x;
}
static std::vector<String> readClassNames(const char *filename = "cnn_age_gender_models_and_data.0.0.2/gender_synset_words.txt")
{
    std::vector<String> classNames;
    std::ifstream fp(filename);
    if (!fp.is_open())
    {
        std::cerr << "File with classes labels not found: " << filename << std::endl;
        exit(-1);
    }
    std::string name;
    while (!fp.eof())
    {
        std::getline(fp, name);
        if (name.length())
            classNames.push_back(name);
    }
    fp.close();
    return classNames;
}
int main(int argc, char **argv)
{
    CV_TRACE_FUNCTION();
    std::cout << "FRESH BINARIES" << std::endl;
    String modelTxt = "cnn_age_gender_models_and_data.0.0.2/deploy_gender.prototxt";
    String modelBin = "cnn_age_gender_models_and_data.0.0.2/gender_net.caffemodel";
    String imageFile = (argc > 1) ? argv[1] : "cnn_age_gender_models_and_data.0.0.2/example_image.jpg";
    Net net;
    try {
        net = dnn::readNetFromCaffe(modelTxt, modelBin);
    }
    catch (cv::Exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        if (net.empty())
        {
            std::cerr << "Can't load network by using the following files: " << std::endl;
            std::cerr << "prototxt:   " << modelTxt << std::endl;
            std::cerr << "caffemodel: " << modelBin << std::endl;
            exit(-1);
        }
    }
    Mat img = imread(imageFile);
    if (img.empty())
    {
        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
        exit(-1);
    }
    Mat inputBlob = blobFromImage(img, 1.0f, Size(256, 256), Scalar(104, 117, 123), false);
    Mat prob;
    cv::TickMeter t;
    for (int i = 0; i < 10; i++)
    {
        CV_TRACE_REGION("forward");
        net.setInput(inputBlob, "data");        //set the network input
        t.start();
        prob = net.forward("prob");                          //compute output
        t.stop();
    }
    int classId;
    double classProb;
    getMaxClass(prob, &classId, &classProb);//find the best class
    std::vector<String> classNames = readClassNames();
    std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
    std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
    std::cout << "Time: " << (double)t.getTimeMilli() / t.getCounter() << " ms (average from " << t.getCounter() << " iterations)" << std::endl;
    return 0;
}

I'm getting this for gender:

Best class: #1 'Female'
Probability: 99.7108%
Time: 17.9049 ms (average from 1 iterations)

And this for age:

Best class: #0 '(0, 2)'
Probability: 96.4613%
Time: 16.2971 ms (average from 10 iterations)

@Zumbalamambo
Copy link

is there any keras or tensorflow implementation of the same?

@koduruhema
Copy link

@fabito, Can you please share the link or the file of gender_synset_words.txt.
Thanks.

@BaderMudarra
Copy link

@Zumbalamambo

is there any keras or tensorflow implementation of the same?

https://github.com/dpressel/rude-carnie

@bengo12
Copy link

bengo12 commented Mar 12, 2018

How this model support multiple people?

@iChiaGuo
Copy link

accury is so low

@FrankieTong89
Copy link

Hi,@GilLevi,Can you sent me a set of images to me?I want to transform the data for training.
my email address is 304087818@qq.com,thanks, if you like ...you can directly sent me the lmdb

@GilLevi
Copy link
Author

GilLevi commented May 6, 2018

@fabito, amazing!! The model we released assume a mean image, where in more recent implementation you can simply use mean value per image channel. We did not re-train the model this way, so using mean value per channel might hurt performance, but I assume that the difference won't be dramatic.

@koduruhema, the "gender_synset_words" is simply "male, femail".

@bengo12, the model receives a single image which assumes to contain one cropped face. It supports multiple people by applying face detection on the image and running the model on each detected face.

@jianti, you can find the images in the AdienceFaces webpage https://www.openu.ac.il/home/hassner/Adience/data.html

@binanhiasm
Copy link

Hi everyone, Can you give me how to train this model? how is flow? Please give an explanation. Thank you.

@GilLevi
Copy link
Author

GilLevi commented Aug 26, 2018

Hi @binanhiasm,

The code for training is given in my repository: https://github.com/GilLevi/AgeGenderDeepLearning

@Akshayz-123
Copy link

Hi @GilLevi,

Can you please sent me the output of age-gendernet ,i.e., age_gendernet.caffemodel. this is for my learning purpose.Thanks in advance

@Harshapriya123
Copy link

Harshapriya123 commented Oct 31, 2020

How to get additional gender like in place of kid I should get the male kid and female kid and how to save the segmentation results in csv ? @GilLevi

@GilLevi
Copy link
Author

GilLevi commented Nov 20, 2020

@Akshayz-123, the link the the models in at the top of this page

@Harshapriya123, sounds like you would need to run both age and gender models for that.

@lynnwilliam
Copy link

Can this be used in a commercial product what is the license?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment