caffe提供了很多深度学习网络,例如Lenet,Imagenet,Alenet.但是最重要的我们会利用这些网络训练自己的数据集以及调参数,甚至发明自己net.本篇博文主要是记录利用caffe中的Lenet训练kaggle中的手写体数据集.

mnist数据集

首先需要关注一下kaggle mnist数据比赛的数据格式信息:
kaggle 手写体比赛
大家可以从上面网站下载到本地,考虑到下载慢,这里百度云分享链接:
kaggle mnist百度云链接

Lenet数据处理和网络构建

为了与现有的caffe例子相融合,保存caffe源码的风格,有如下配置

数据

在caffe/data目录下新建文件夹kaggle_mnist,并且将下载好的train.csv,test.csv,保存在此.

训练文件

首先在caffe/examples目录下新建文件夹kaggle_mnist.
1.csv数据转HDF5
首先声明caffe不止可以接收HDF5数据,欲知更多,移步官网.
以下python脚本实现数据转换的功能,并按caffe example风格放置各个文件.该文件命名为create_mnist.py,放置在examples/kaggle_mnist文件夹下,这里提醒一下,训练只用到train.csv中的数据,代码中test准确的表达应该是validation.这里只是把train.csv中的数据分为两部分了

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
from __future__ import print_function
import os
import logging
import numpy as np
import pandas as pd
import h5py
DATA_ROOT = '../../data/kaggle_mnist'
os.mkdir('mnist_train_hdf5')
os.mkdir('mnist_test_hdf5')
join = os.path.join
TRAIN = join(DATA_ROOT, 'train.csv')
DIR_TRAIN='mnist_train_hdf5'
DIR_TEST='mnist_test_hdf5'
train_file = join(DIR_TRAIN, 'mnist_train.h5')
test_file = join(DIR_TEST, 'mnist_test.h5')
train_file_txt = join(DIR_TRAIN, 'mnist_train.txt')
test_file_txt = join(DIR_TEST, 'mnist_test.txt')
# logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
sh = logging.StreamHandler()
sh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
sh.setFormatter(formatter)
logger.addHandler(sh)
# load data from train.csv
logger.info('Load data from %s', TRAIN)
df = pd.read_csv(TRAIN)
data = df.values
logger.info('Get %d Rows in dataset', len(data))
# random shuffle
np.random.shuffle(data)
# all dataset
labels = data[:, 0]
images = data[:, 1:]
# process data
images = images.reshape((len(images), 1, 28, 28))
images = images / 255.
# train dataset number
trainset = len(labels) * 3 / 4
# train dataset
labels_train = labels[:trainset]
images_train = images[:trainset]
# test dataset
labels_test = labels[trainset:]
images_test = images[trainset:]
# write to hdf5 and txt
if os.path.exists(train_file):
os.remove(train_file)
if os.path.exists(test_file):
os.remove(test_file)
logger.info('Write train dataset to %s', train_file)
with h5py.File(train_file, 'w') as f:
f['label'] = labels_train.astype(np.float32)
f['data'] = images_train.astype(np.float32)
train_file = join('examples/kaggle_mnist/', train_file)
with open(train_file_txt, 'w') as f:
print(train_file, file = f)
logger.info('Write test dataset to %s', test_file)
with h5py.File(test_file, 'w') as f:
f['label'] = labels_test.astype(np.float32)
f['data'] = images_test.astype(np.float32)
test_file = join('examples/kaggle_mnist/', test_file)
with open(test_file_txt, 'w') as f:
print(test_file, file = f)
logger.info('Done')

2.lenet网路配置
从/examples/mnist复制lenet_train_test.prototxt/examples/kaggle_mnist,并修改数据层的内容,整个文件如下:

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
name: "LeNet"
layer {
name: "mnist"
type: "HDF5Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
hdf5_data_param {
source: "examples/kaggle_mnist/mnist_train_hdf5/mnist_train.txt"
batch_size: 64
}
}
layer {
name: "mnist"
type: "HDF5Data"
top: "data"
top: "label"
include {
phase: TEST
}
hdf5_data_param {
source: "examples/kaggle_mnist/mnist_test_hdf5/mnist_test.txt"
batch_size: 100
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer {
name: "ip2"
type: "InnerProduct"
bottom: "ip1"
top: "ip2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 10
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}

3.solver配置
同样从/examples/mnist复制到lenet_solver.prototxt/examples/kaggle_mnist,只要将net处修改即可,所有类容如下:

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
# The train/test net protocol buffer definition
net: "examples/kaggle_mnist/lenet_train_test.prototxt"
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
test_iter: 100
# Carry out testing every 500 training iterations.
test_interval: 500
# The base learning rate, momentum and the weight decay of the network.
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# The learning rate policy
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# Display every 100 iterations
display: 100
# The maximum number of iterations
max_iter: 10000
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "examples/kaggle_mnist/lenet"
# solver mode: CPU or GPU
solver_mode: CPU

4.训练文件
examples/kaggle_mnist下新建train_lenet.sh,内容如下:

1
2
3
4
#!/usr/bin/env sh
set -e
./build/tools/caffe train -solver=examples/kaggle_mnist/lenet_solver.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel $@

值得注意的是,这里其实是在fine tunning,因为这里用到了caffe自带mnist训练出来的模型,也就是这一句:

1
-weights examples/mnist/lenet_iter_10000.caffemodel

Lenet训练

这一步很简单,只要在caffe根目录下执行:

1
./examples/kaggle_mnist/train_lenet.sh

我的机器大概用了10分钟,最后就出来带.caffemodel后缀的model.

kaggle数据测试

为了上传数据到kaggle,我们必须用最后训练出来的model预测一下test.csv中的数据.这里用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
import os
import logging
import numpy as np
import pandas as pd
import caffe
DATA_ROOT = '../../data/kaggle_mnist'
MODEL_ROOT = './'
join = os.path.join
TEST = join(DATA_ROOT, 'test.csv')
OUTPUT = join(DATA_ROOT, 'result.csv')
CAFFE_MODEL = join(MODEL_ROOT, 'lenet_iter_10000.caffemodel')
CAFFE_SOLVER = join(MODEL_ROOT, 'deploy.prototxt')
# logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
sh = logging.StreamHandler()
sh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
sh.setFormatter(formatter)
logger.addHandler(sh)
# load test dataset
logger.info('Load test dataset from %s', TEST)
df = pd.read_csv(TEST)
data = df.values
data = data.reshape((len(data), 28, 28, 1))
data = data / 255.
# set caffe net
net = caffe.Classifier(CAFFE_SOLVER, CAFFE_MODEL)
# predict
logger.info('Start predict')
BATCH_SIZE = 100
iter_k = 0
labels = []
while True:
logger.info('ITER %d', iter_k)
batch = data[iter_k*BATCH_SIZE: (iter_k+1)*BATCH_SIZE]
if batch.size == 0:
break
result = net.predict(batch)
for label in np.argmax(result, 1):
labels.append(label)
iter_k = iter_k + 1
logger.info('Prediction Done')
# write to file
logger.info('Save result to %s', OUTPUT)
if os.path.exists(OUTPUT):
os.remove(OUTPUT)
with open(OUTPUT, 'w') as fd:
fd.write('ImageId,Label\n')
for idx, label in enumerate(labels):
fd.write(str(idx+1))
fd.write(',')
fd.write(str(label))
fd.write('\n')

最后出来的预测结果保存在caffe/data/kaggle_mnist/result.csv中,只要将该文件上传到kaggle上就可以知道你的预测的准确率了.