caffe实现性别预测

前言

自定义网络模型实现图像识别中介绍了caffe的基本用法,关于caffe的介绍在此不再赘述。
介绍这篇文章之前首先特别感谢夏天大神的指导交流。这篇文章中使用了caffe的python接口,数据为数组元素而非图像,依然有参考价值。

数据输入

数据如下显示:
性别预测数据

数据转换代码如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# -*- coding: utf-8 -*-
import numpy as np
import random
import subprocess
import platform
import sys,os
sys.path.append('/home/hero/caffe/python')
import caffe
import lmdb
from sklearn.cross_validation import StratifiedShuffleSplit
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math
matrix = np.loadtxt('train.csv', dtype='string', skiprows= 1,delimiter=',', usecols=(1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28))
matrix = np.asarray(matrix)
features = matrix[:,1:27]
labels = matrix[:,0]
features = features.astype(np.float) #convert string to float
#将性别转成int
for i in range(len(labels)):
if labels[i] == '\xc4\xd0':
labels[i] = 1
else :
if labels[i] != '1':
labels[i] = 0
#向量化操作
vec_log = np.vectorize(lambda x: math.log(x+1))
vec_int = np.vectorize(lambda str: int(str[-1]))
features = vec_log(features)
labels = vec_int(labels)
#这里将数据分割成训练数据和测试数据
sss = StratifiedShuffleSplit(labels, 1, test_size=0.02, random_state=0)
sss = list(sss)[0]
features_training = features[sss[0],]
labels_training = labels[sss[0],]
features_testing = features[sss[1],]
labels_testing = labels[sss[1],]
#这个函数中将数据转成lmdb格式
def load_data_into_lmdb(lmdb_name, features, labels=None):
env = lmdb.open(lmdb_name, map_size=features.nbytes*10)
features = features[:,:,None,None]
for i in range(features.shape[0]):
datum = caffe.proto.caffe_pb2.Datum()
datum.channels = features.shape[1] # features's number(26)
datum.height = 1 # due to eachone only have one data
datum.width = 1 # so the size is 1x1
if features.dtype == np.int: # convert data to string
datum.data = features[i].tostring()
elif features.dtype == np.float:
datum.float_data.extend(features[i].flat)
else:
raise Exception("features.dtype unknown.")
if labels is not None:
datum.label = int(labels[i])
str_id = '{:08}'.format(i)
with env.begin(write=True) as txn:
txn.put(str_id, datum.SerializeToString())
#这个函数用于获取数据进行预测
def get_data_from_lmdb_evalue(lmdb_name):
lmdb_env = lmdb.open(lmdb_name, readonly=True)
lmdb_txn = lmdb_env.begin()
lmdb_cursor = lmdb_txn.cursor()
datum = caffe.proto.caffe_pb2.Datum()
success = 0
count = 0
#raw_datum = lmdb_txn.get()
for key, value in lmdb_cursor:
datum.ParseFromString(value)
label = datum.label
feature = caffe.io.datum_to_array(datum)
out = net.forward(**{net.inputs[0]: np.asarray([feature])})
count+=1
if np.argmax(out["prob"][0]) == label :
success+=1
print "success", out
return count,success
load_data_into_lmdb("train_data_lmdb", features_training, labels_training)
load_data_into_lmdb("test_data_lmdb", features_testing, labels_testing)

关于以上代码的几点说明:

  • 使用numpy工具以矩阵形式读入csv数据文件,因为性别为string类型,需要将其转换成int类型;
  • 为了提高准确度,夏天大神写了一个nomalize函数对数据进行了归一化处理,而我就在对数据向量化处理时对数据做log运算操作
    vec_log = np.vectorize(lambda x: math.log(x+1))
  • 其他细节可以看上面代码注释,整体来说还是通俗易懂的。

训练及预测

训练和预测的python代码很简单,如下所示:

1
2
3
4
5
6
7
8
#根据配置文件开始训练模型
solver = caffe.get_solver("train.prototxt")
solver.solve()
net = caffe.Net("model_prod.prototxt","_iter_500000.caffemodel", caffe.TEST)
total,success = get_data_from_lmdb_evalue("test_data_lmdb/")
print "accuracy:", success*100/total,"%"

网络模型定义了两个全连接层,relu激发函数,学习率变化策略使用了inv,数据较少,迭代次数都调到上万。训练时准确度到过80+,实际预测准确度最终达到71%。
结果如下所示:
训练结果
预测结果

参考链接