Тренируем нейросеть tensorflow для распознавания эмоций на основе фотобанка FER2013

06.06.2017
By

На основе материала https://www.tensorflow.org/tutorials/image_retraining потренируем нейросеть для распознавания эмоций. Фотографии эмоций, разделенные на несколько подгрупп (злость, отвращение, слезы, счастье, удрученность, удивление, нейтральность) хранятся в csv файле ( в первом столбце – номер эмоции по порядку (от 0 до 6), во втором – 48х48 пикселей картинка в сером цвете (биты 0-255)).

Преобразовать в jpg файлы можно программой Python

#! /usr/bin/env
# -*-coding: utf-8-*-
 
__author__ = 'fer_2013'
 
import numpy as np
import cv2
import mxnet as mx
import pandas as pd
import random
import os
 
curdir = os.path.abspath(os.path.dirname(__file__))
 
def gen_record(csvfile,channel):
    data = pd.read_csv(csvfile,delimiter=',',dtype='a')
    labels = np.array(data['emotion'],np.float)
    # print(labels,'\n',data['emotion'])
         
    imagebuffer = np.array(data['pixels'])
    images = np.array([np.fromstring(image,np.uint8,sep=' ') for image in imagebuffer])
    del imagebuffer
    num_shape = int(np.sqrt(images.shape[-1]))
    images.shape = (images.shape[0],num_shape,num_shape)
    # img=images[0];cv2.imshow('test',img);cv2.waitKey(0);cv2.destroyAllWindow();exit()
    dirs = set(data['Usage'])
    subdirs = set(labels)
    class_dir = {}
    for dr in dirs:
        dest = os.path.join(curdir,dr)
        class_dir[dr] = dest
        if not os.path.exists(dest):
            os.mkdir(dest)
             
    data = zip(labels,images,data['Usage'])
     
    for d in data:
        destdir = os.path.join(class_dir[d[-1]],str(int(d[0])))
        if not os.path.exists(destdir):
            os.mkdir(destdir)
        img = d[1]
        filepath = unique_name(destdir,d[-1])
        print('[^_^] Write image to %s' % filepath)
        if not filepath:
            continue
        sig = cv2.imwrite(filepath,img)
        if not sig:
            print('Error')
            exit(-1)
 
 
def unique_name(pardir,prefix,suffix='jpg'):
    filename = '{0}_{1}.{2}'.format(prefix,random.randint(1,10**8),suffix)
    filepath = os.path.join(pardir,filename)
    if not os.path.exists(filepath):
        return filepath
    unique_name(pardir,prefix,suffix)
     
 
 
if __name__ == '__main__':
    filename = 'fer2013.csv'
    filename = os.path.join(curdir,filename)
    gen_record(filename,1)
     
    # ##################### test
    # tmp = unique_name('./Training','Training')
    # print(tmp)

После преобразования переименовываем директории 0-6  в англоязычные (angry, disgust, … neutral).

создаем еще одно виртуальное окружение virtualenv ( мое название -  tensorflow)

$ virtualenv ~/.virtualenvs/tensorflow

Заходим $ source ~/.virtualenvs/tensorflow/bin/activate

Устанавливаем Bazel https://bazel.build/versions/master/docs/install-ubuntu.html

были проблемы с jre но установка из исходников помогла. Также пришлось поставить mock $pip install mock

Моя директория  установленными примерами tensorflow выглядит так (клонирована гитом с https://github.com/tensorflow/tensorflow):

Поэтому для того, чтобы зайти в директорию для запуска bazel необходимо выполнить $ cd tf/tensorflow

Если это первый запуск после установки – не забудьте сконфигурировать  ./configure !!!!!!

Запускаем bazel для создания исполняемого файла $ bazel build tensorflow/examples/image_retraining1:retrain

перед этим неплохо установить необходимые библиотеки  $ sudo apt-get install python-numpy python-scipy python-matplotlib ipython ipython-notebook python-pandas python-sympy python-nose

Я сделал дубликат пример image_retrain для дальнейшей модификации и назвал его image_retrain1 (скопировал папку с примером).

Создание исполняемого файла на моей машине (ntel® Core™ i3-4160 CPU @ 3.60GHz ? 4 6Gb) занимает примерно 30 минут. Надо бы задействовать установленную на машине NVidia GT720 2Mb для вычислений… :)

Затем запускаем собственно тренировку нейросети. В моем случае:

$bazel-bin/tensorflow/examples/image_retraining1/retrain --image_dir ~/fer2013/training1

В директории ~/fer2013/training1 содержатся папки (angry, disgust, fear,… neutral) с графическими файлами внутри.
нейросеть тренировалась примерно 3 часа ( больше всего времени было потрачено на создание bottleneck файлов – но точность получилась как в анекдоте – 50/50…

Тестирование результата получившейся нейросети можно с использованием программы eldor4do https://github.com/eldor4do/TensorFlow-Examples/blob/master/retraining-example.py

Она показалась мне более простой и понятной.

"""
Preparing model:
 - Install bazel ( check tensorflow's github for more info )
    Ubuntu 14.04:
        - Requirements:
            sudo add-apt-repository ppa:webupd8team/java
            sudo apt-get update
            sudo apt-get install oracle-java8-installer
        - Download bazel, ( https://github.com/bazelbuild/bazel/releases )
          tested on: https://github.com/bazelbuild/bazel/releases/download/0.2.0/bazel-0.2.0-jdk7-installer-linux-x86_64.sh
        - chmod +x PATH_TO_INSTALL.SH
        - ./PATH_TO_INSTALL.SH --user
        - Place bazel onto path ( exact path to store shown in the output)
- For retraining, prepare folder structure as
    - root_folder_name
        - class 1
            - file1
            - file2
        - class 2
            - file1
            - file2
- Clone tensorflow
- Go to root of tensorflow
- bazel build tensorflow/examples/image_retraining:retrain
- bazel-bin/tensorflow/examples/image_retraining/retrain --image_dir /path/to/root_folder_name  --output_graph /path/output_graph.pb --output_labels /path/output_labels.txt --bottleneck_dir /path/bottleneck
** Training done. **
For testing through bazel,
    bazel build tensorflow/examples/label_image:label_image && \
    bazel-bin/tensorflow/examples/label_image/label_image \
    --graph=/path/output_graph.pb --labels=/path/output_labels.txt \
    --output_layer=final_result \
    --image=/path/to/test/image
For testing through python, change and run this code.
"""

import numpy as np
import tensorflow as tf

imagePath = '/tmp/imagenet/neutral1.jpg'
modelFullPath = '/tmp/output_graph.pb'
labelsFullPath = '/tmp/output_labels.txt'

def create_graph():
    """Creates a graph from saved GraphDef file and returns a saver."""
    # Creates graph from saved graph_def.pb.
    with tf.gfile.FastGFile(modelFullPath, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        _ = tf.import_graph_def(graph_def, name='')

def run_inference_on_image():
    answer = None

    if not tf.gfile.Exists(imagePath):
        tf.logging.fatal('File does not exist %s', imagePath)
        return answer

    image_data = tf.gfile.FastGFile(imagePath, 'rb').read()

    # Creates graph from saved GraphDef.
    create_graph()

    with tf.Session() as sess:

        softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
        predictions = sess.run(softmax_tensor,
                               {'DecodeJpeg/contents:0': image_data})
        predictions = np.squeeze(predictions)

        top_k = predictions.argsort()[-5:][::-1]  # Getting top 5 predictions
        f = open(labelsFullPath, 'rb')
        lines = f.readlines()
        labels = [str(w).replace("\n", "") for w in lines]
        for node_id in top_k:
            human_string = labels[node_id]
            score = predictions[node_id]
            print('%s (score = %.5f)' % (human_string, score))

        answer = labels[top_k[0]]
        return answer

if __name__ == '__main__':
    run_inference_on_image()

Добавить комментарий