caffe总结(十一)
hdf5文件类型使用探讨
最近用caffe做regression问题,先用data layer中的data,float_data试了一下,data用来存放图片,float_data存放regression的values,label存放标签,发现不行,因为float_data和label这俩是指向同一块内存,两者不能共存,除非改caffe源码。关于更改caffe源码进行回归参考博客https://blog.csdn.net/weixin_42535423/article/details/103810673
我又仔细看了一下caffe的源码,具体来讲,caffe读取image和label是这样一个流程:
-
编写程序将image和label转换成Datum格式,并写入lmdb
-
Data layer从lmdb中读取Datum格式的数据,然后转化成一个Batch
-
从Batch里面把image和label的数据复制到top的内存或显存
上述的2,3步可以查看data_layer.cpp,base_data_layer.cpp和base_data_layer.cu这三个文件,里面和float_data半点关系都没有,所以就算你把regression values保存在Datum的float_data里面,Data layer也不会把它读出来的。我目前想到的办法只有两种,要么改caffe源码,要么lmdb和hdf5一起用,源码怕改出错,就尝试了一下hdf5格式做输入,虽然搞定了,但也有坑。
说一下怎么把数据写入hdf5文件,我用的是python,numpy格式的数组可以直接存放进去,方法如下:
#1. 先创建一个空的numpy数组
hdf_data = np.zeros((len(all_samples), num), dtype=np.float32)
#2. 填充hdf_data
#3.打开h5文件然后写入hdf_data
h5_file = h5py.File(h5_path, 'w')
h5_file.create_dataset('hdf_data', data=hdf_data)
h5_file.close()
#把h5文件路径写到一个txt中
h5txt_file = open(h5txt_path, 'w')
h5txt_file.write(h5_path)
h5txt_file.close()
在定义网络的prototxt文件中,这样使用
layer {
name: "hdf5_data"
type: "HDF5Data"
top: "hdf_data"
include {
phase: TRAIN
}
hdf5_data_param {
source: "your_h5txt_file_path"
batch_size: 1024
}
}
其中source是那个只有一行的txt的路径。top是你需要使用的h5中保存的数据块名称。
需要注意的是,如果是图像数据,预处理要先做,再存进h5文件,因为HDF5Data layer不支持预处理功能。另外这里有个坑,尽量不要把图片放在h5文件中,**因为HDF5Data layer不能按照batch来读取数据,只能一次性把所有数据从h5文件中读到内存中,如果h5文件非常大,就会报错,**具体是挂在HDF5Data的实现代码中了,有一个数据大小的断言。所以既不想改caffe代码又想保证训练程序能跑起来的方法如下:
把regression values按照hdf5格式存放,image和label按照正常数据存放在lmdb即可。在定义网络的prototxt中可以读取不同来源的数据,例如下面这种方法:
layer {
name: "lmdb_data"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
data_param {
source: "train_data"
batch_size: 1024
backend: LMDB
}
transform_param {
mean_value: 128
scale: 0.0078125
}
}
layer {
name: "hdf5_data"
type: "HDF5Data"
top: "bbox"
include {
phase: TRAIN
}
hdf5_data_param {
source: "hdf5_train.txt"
batch_size: 1024
}
}
单纯将图片只改为HDF5格式的案例说明
参考资料:
- http://stackoverflow.com/questions/33766689/caffe-hdf5-pre-processing
- http://corpocrat.com/2015/02/24/facial-keypoints-extraction-using-deep-learning-with-caffe/
- http://stackoverflow.com/questions/31774953/test-labels-for-regression-caffe-float-not-allowed/31808324#31808324
在caffe的框架上,如何根据现有的图像及其分值、标准差对图像进行回归,caffe_model是Imagenet训练得到模型、solver.prototxt和train_val.prototxt。本次的数据来源为:http://live.ece.utexas.edu/。 注意:所有的工程建立都是在caffe的根目录下执行。
一、环境:
编码成功的caffe;图像数据库。
二、数据预处理:
- 在data下建立文件夹“face_key_point”,之后所有的数据处理均在“face_key_point”文件夹下,该文件夹下包含images文件夹和其他文件(.py和.txt文件)。
- images文件夹里包含所有的train、test和val图像;
- 其他文件
*.py生成文件准备
- meancreat_hdf5.py
用于产生train.h5和train_h5_list.txt(注意检查该文件中train.h5的路径是否是绝对路径,如果不是,请改一下),可以用HDF5View查看train.h5检查数据是否正确,ImageNum3227*227(SIZE,最好和Imagenet模型的保持一致),适合所有类型的图像(.JPG和.bmp同时处理),代码里对图像已经做过均值处理,具体代码如下:
import h5py, os
import caffe
import numpy as np
SIZE = 227 # fixed size to all images
with open( 'train.txt', 'r' ) as T :
lines = T.readlines()
with open( 'num.txt', 'r' ) as M :
lines_Num = M.readlines()
# If you do not have enough memory split data into
# multiple batches and generate multiple separate h5 files
X = np.zeros( (len(lines), 3, SIZE, SIZE), dtype='f4' )
XMean = np.zeros( (len(lines), 3, 1, 1), dtype='f4' )
y = np.zeros( (len(lines_Num)), dtype='f4' )
print len(lines)
for i,l in enumerate(lines):
sp = l.split('\r\n')
img = caffe.io.load_image( sp[0] )
img = caffe.io.resize_image( img, (SIZE, SIZE), 3 ) # resize to fixed size
img = np.transpose(img, (2, 0, 1))
# you may apply other input transformations here...
X[i] = img
# Compute the mean of all images
XMean = sum(X)/len(X)
X = X - XMean
print 'image OK'
for j, eachLine in enumerate(lines_Num):
y[j] = float(float(eachLine)/92.432)
print 'Num OK'
with h5py.File('train.h5','w') as H:
H.create_dataset( 'X', data=X ) # note the name X given to the dataset!
H.create_dataset( 'y', data=y ) # note the name y given to the dataset!
with open('train_h5_list.txt','w') as L:
L.write( '/home2/xj_jin/experiment/caffe-master/data/face_key_point/train.h5' ) # list all h5 files you are going to use
- meancreat_hdf5test.py
同理,用于产生test.h5和test_h5_list.txt(检查路径),代码里对图像已经做过均值处理,具体代码如下:
import h5py, os
import caffe
import numpy as np
SIZE = 227 # fixed size to all images
with open( 'test.txt', 'r' ) as T :
lines = T.readlines()
with open( 'num_test.txt', 'r' ) as M :
lines_Num = M.readlines()
# If you do not have enough memory split data into
# multiple batches and generate multiple separate h5 files
X = np.zeros( (len(lines), 3, SIZE, SIZE), dtype='f4' )
XMean = np.zeros( (len(lines), 3, 1, 1), dtype='f4' )
y = np.zeros( (len(lines_Num)), dtype='f4' )
print len(lines)
for i,l in enumerate(lines):
sp = l.split('\r\n')
img = caffe.io.load_image( sp[0] )
img = caffe.io.resize_image( img, (SIZE, SIZE), 3 ) # resize to fixed size
img = np.transpose(img, (2, 0, 1))
# you may apply other input transformations here...
X[i] = img
# Compute the mean of all images
XMean = sum(X)/len(X)
X = X - XMean
print 'image OK'
for j, eachLine in enumerate(lines_Num):
y[j] = float(float(eachLine)/87.0656)
print 'Num OK'
with h5py.File('test.h5','w') as H:
H.create_dataset( 'X', data=X ) # note the name X given to the dataset!
H.create_dataset( 'y', data=y ) # note the name y given to the dataset!
with open('train_h5_list.txt','w') as L:
L.write( '/home2/xj_jin/experiment/caffe-master/data/face_key_point/test.h5' ) # list all h5 files you are going to use
- (3)train.txt和num.txt
train.txt存放着待训练的图片,num.txt存放待训练图片的分值。具体格式如下:
train.txt:(建议检查路径是否存在空格)
/home2/xj_jin/experiment/caffe-master/data/face_key_point/images/00t1.bmp
/home2/xj_jin/experiment/caffe-master/data/face_key_point/images/00t2.bmp
/home2/xj_jin/experiment/caffe-master/data/face_key_point/images/00t3.bmp
/home2/xj_jin/experiment/caffe-master/data/face_key_point/images/00t4.bmp
/home2/xj_jin/experiment/caffe-master/data/face_key_point/images/00t5.bmp
num.txt:
63.9634
25.3353
48.9366
35.8863
66.5092
- (4) test.txt和num_test.txt
test.txt存放着待训练的图片,num_test.txt存放待训练图片的分值。具体格式和上述一致。
生成train.h5和test.h5数据
在caffe/data/face_key_point下执行:
命令: python meancreat_hdf5.py和 python meancreat_hdf5test.py
三、模型修改
在caffe/model下建立自己的文件夹“face_key_point”,将下载得到的Imagenet的模型和网络结构bvlc_reference_caffenet.caffemodel、train_val.prototxt、solver.prototxt放入该文件夹下。
1.修改solver.prototxt
net: "models/face_key_point/train_val.prototxt" -----------------------路径要改
test_iter: 100
test_interval: 1000
# lr for fine-tuning should be lower than when starting from scratch
base_lr: 0.001 -----------------------基础学习率根据实际情况改
lr_policy: "step"
gamma: 0.1
# stepsize should also be lower, as we're closer to being done
stepsize: 20000
display: 20
max_iter: 100000
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "models/face_key_point/finetune_face_key_point" ---------------------------路径+自己取名新生成的模型名称
# uncomment the following to default to CPU mode solving
# solver_mode: CPU ---------------------------根据自己的实际情况设置
2. 修改train_val.prototxt网络结构
这里只提供部分的网络结构。
name: "FaceKeyPointCaffeNet" ------自己训练的网络模型名称
layer { -------处理.h5数据的data层
name: "data"
type: "HDF5Data"
top: "X" -------和meancreat_hdf5test.py中最后的输出保持一致,原来是data,现在是X
top: "y" ----------和meancreat_hdf5test.py中最后的输出保持一致,原来是label,现在是y
include {
phase: TRAIN
}
hdf5_data_param {
source: "data/face_key_point/train_h5_list.txt" -----------保存的train.h5的绝对路径,可以处理多个.h5数据
batch_size: 64
}
}
layer {
name: "data"
type: "HDF5Data"
top: "X"
top: "y"
include {
phase: TEST
}
hdf5_data_param {
source: "data/face_key_point/test_h5_list.txt"
batch_size: 100
}
}
。。。
layer {
name: "ip"
type: "InnerProduct"
bottom: "fc8"
top: "ip"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 1
weight_filler {
type: "gaussian"
std: 0.1
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "loss"
type: "EuclideanLoss"
bottom: "ip"
bottom: "label"
top: "loss"
}
卷积层、池化层、全连接层、损失等;
最后,因为本次处理的是一个回归问题,所以最后的损失函数(loss)应该是一个回归,而不是分类,保证最后几层的bottom是y,而不是label。
四、训练
注意改掉对应路径即可:
./build/tools/caffe train --solver=models/face_key_point/solver.prototxt --weights=models/face_key_point/bvlc_reference_caffenet.caffemodel -gpu 0