caffe之训练数据格式

秒速五厘米 2022-06-05 12:46 398阅读 0赞

原文地址:http://blog.csdn.net/hjimce/article/details/49248231

作者:hjimce

caffe对于训练数据格式,支持:lmdb、![Image 1][]![Image 1][]h5py……,其中lmdb数据格式常用于单标签数据,像分类等,经常使用lmdb的数据格式。对于回归等问题,或者多标签数据,一般使用h5py数据的格式。当然好像还有其它格式的数据可用,不过我一般使用这两种数据格式,因此本文就主要针对这两种数据格式的制作方法,进行简单讲解。

一、lmdb数据

lmdb用于单标签数据。为了简单起见,我后面通过一个性别分类作为例子,进行相关数据制作讲解。

1、数据准备

首先我们要准备好训练数据,然后新建一个名为train的文件夹和一个val的文件夹:

Center

train文件存放训练数据,val文件存放验证数据。然后我们在train文件下面,把训练数据性别为男、女图片各放在一个文件夹下面:

Center 1

同样的我们在val文件下面也创建文件夹:

Center 2

两个文件也是分别存我们用于验证的图片数据男女性别文件。我们在test_female下面存放了都是女性的图片,然后在test_male下面存放的都是验证数据的男性图片。

2、标签文件.txt文件制作.

接着我们需要制作一个train.txt、val.txt文件,这两个文件分别包含了我们上面的训练数据的图片路径,以及其对应的标签,如下所示。

Center 3

我们把女生图片标号为1,男生图片标记为0。标签数据文件txt的生成可以通过如下代码,通过扫描路径男、女性别下面的图片,得到标签文件train.txt和val.txt:

[python] view plain copy

  1. import os
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. import cv2
  5. import shutil
  6. #扫面文件
  7. def GetFileList(FindPath,FlagStr=[]):
  8. import os
  9. FileList=[]
  10. FileNames=os.listdir(FindPath)
  11. if len(FileNames)>0:
  12. for fn in FileNames:
  13. if len(FlagStr)>0:
  14. if IsSubString(FlagStr,fn):
  15. fullfilename=os.path.join(FindPath,fn)
  16. FileList.append(fullfilename)
  17. else:
  18. fullfilename=os.path.join(FindPath,fn)
  19. FileList.append(fullfilename)
  20. if len(FileList)>0:
  21. FileList.sort()
  22. return FileList
  23. def IsSubString(SubStrList,Str):
  24. flag=True
  25. for substr in SubStrList:
  26. if**not(substr in** Str):
  27. flag=False
  28. return flag
  29. txt=open(‘train.txt’,’w’)
  30. #制作标签数据,如果是男的,标签设置为0,如果是女的标签为1
  31. imgfile=GetFileList(‘first_batch/train_female’)
  32. for img in imgfile:
  33. str=img+’\t’+‘1’+‘\n’
  34. txt.writelines(str)
  35. imgfile=GetFileList(‘first_batch/train_male’)
  36. for img in imgfile:
  37. str=img+’\t’+‘0’+‘\n’
  38. txt.writelines(str)
  39. txt.close()

把生成的标签文件,和train\val文件夹放在同一个目录下面:

Center 4

需要注意,我们标签数据文件里的文件路径和图片的路径要对应的起来,比如val.txt文件的某一行的图片路径,是否在val文件夹下面:

Center 5

3、生成lmdb数据

接着我们的目的就是要通过上面的四个文件,把图片的数据和其对应的标签打包起来,打包成lmdb数据格式,打包脚本如下:

[python] view plain copy

  1. #!/usr/bin/env sh
  2. # Create the imagenet lmdb inputs
  3. # N.B. set the path to the imagenet train + val data dirs
  4. EXAMPLE=. # 生成模型训练数据文化夹
  5. TOOLS=//../build/tools # caffe的工具库,不用变
  6. DATA=. # python脚步处理后数据路径
  7. TRAIN_DATA_ROOT=train/ #待处理的训练数据
  8. VAL_DATA_ROOT=val/ # 带处理的验证数据
  9. # Set RESIZE=true to resize the images to 256x256. Leave as false if images have
  10. # already been resized using another tool.
  11. RESIZE=true#是否需要对图片进行resize
  12. if $RESIZE; then
  13. RESIZE_HEIGHT=256
  14. RESIZE_WIDTH=256
  15. else
  16. RESIZE_HEIGHT=0
  17. RESIZE_WIDTH=0
  18. fi
  19. if [ ! -d “$TRAIN_DATA_ROOT” ]; then
  20. echo “Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT”
  21. echo “Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path” \
  22. “where the ImageNet training data is stored.”
  23. exit 1
  24. fi
  25. if [ ! -d “$VAL_DATA_ROOT” ]; then
  26. echo “Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT”
  27. echo “Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path” \
  28. “where the ImageNet validation data is stored.”
  29. exit 1
  30. fi
  31. echo “Creating train lmdb…”
  32. GLOG_logtostderr=1 $TOOLS/convert_imageset \
  33. --resize_height=$RESIZE_HEIGHT \
  34. --resize_width=$RESIZE_WIDTH \
  35. --shuffle \
  36. $TRAIN_DATA_ROOT \
  37. $DATA/train.txt \
  38. $EXAMPLE/train_lmdb
  39. echo “Creating val lmdb…”
  40. GLOG_logtostderr=1 $TOOLS/convert_imageset \
  41. --resize_height=$RESIZE_HEIGHT \
  42. --resize_width=$RESIZE_WIDTH \
  43. --shuffle \
  44. $VAL_DATA_ROOT \
  45. $DATA/val.txt \
  46. $EXAMPLE/val_lmdb
  47. echo “Done.”

通过运行上面的脚本,我们即将得到文件夹train_lmdb\val_lmdb:

Center 6

我们打开train_lmdb文件夹

Center 7

并查看一下文件data.mdb数据的大小,如果这个数据包好了我们所有的训练图片数据,查一下这个文件的大小是否符合预期大小,如果文件的大小才几k而已,那么就代表你没有打包成功,估计是因为路径设置错误。我们也可以通过如下的代码读取上面打包好的数据,把图片、和标签打印出来,查看一下,查看lmdb数据请参考下面的代码:

python lmdb数据验证:

[python] view plain copy

  1. # coding=utf-8
  2. caffe_root = ‘/home/hjimce/caffe/‘
  3. import sys
  4. sys.path.insert(0, caffe_root + ‘python’)
  5. import caffe
  6. import os
  7. import lmdb
  8. import numpy
  9. import matplotlib.pyplot as plt
  10. def readlmdb(path,visualize = False):
  11. env = lmdb.open(path, readonly=True,lock=False)
  12. datum = caffe.proto.caffe_pb2.Datum()
  13. x=[]
  14. y=[]
  15. with env.begin() as txn:
  16. cur = txn.cursor()
  17. for key, value in cur:
  18. # 转换为datum
  19. datum.ParseFromString(value)
  20. # 读取datum数据
  21. img_data = numpy.array(bytearray(datum.data))\
  22. .reshape(datum.channels, datum.height, datum.width)
  23. print img_data.shape
  24. x.append(img_data)
  25. y.append(datum.label)
  26. if visualize:
  27. img_data=img_data.transpose([1,2,0])
  28. img_data = img_data[:, :, ::-1]
  29. plt.imshow(img_data)
  30. plt.show()
  31. print datum.label
  32. return x,y

通过上面的函数,我们可以是读取相关的lmdb数据文件。

4、制作均值文件。

这个是为了图片归一化而生成的图片平均值文件,把所有的图片相加起来,做平均,具体的脚本如下:

[python] view plain copy

  1. #!/usr/bin/env sh
  2. # Compute the mean image from the imagenet training lmdb
  3. # N.B. this is available in data/ilsvrc12
  4. EXAMPLE=.
  5. DATA=train
  6. TOOLS=../../build/tools
  7. $TOOLS/compute_image_mean $EXAMPLE/train_lmdb \  #train_lmdb是我们上面打包好的lmdb数据文件
  8. $DATA/imagenet_mean.binaryproto
  9. echo “Done.”

运行这个脚本,我们就可以训练图片均值文件:imagenet_mean.binaryproto

至此,我们得到了三个文件:imagenet_mean.binaryproto、train_lmdb、val_lmdb,这三个文件就是我们最后打包好的数据,这些数据我们即将作为caffe的数据输入数据格式文件,把这三个文件拷贝出来,就可以把原来还没有打包好的数据删了。这三个文件,我们在caffe的网络结构文件,数据层定义输入数据的时候,就会用到了:

[python] view plain copy

  1. name: “CaffeNet”
  2. layers {
  3. name: “data”
  4. type: DATA
  5. top: “data”
  6. top: “label”
  7. data_param {
  8. source: “train_lmdb”#lmbd格式的训练数据
  9. backend: LMDB
  10. batch_size: 50
  11. }
  12. transform_param {
  13. crop_size: 227
  14. mirror: true
  15. mean_file:”imagenet_mean.binaryproto”#均值文件
  16. }
  17. include: { phase: TRAIN }
  18. }
  19. layers {
  20. name: “data”
  21. type: DATA
  22. top: “data”
  23. top: “label”
  24. data_param {
  25. source: “val_lmdb”#lmdb格式的验证数据
  26. backend: LMDB
  27. batch_size: 50
  28. }
  29. transform_param {
  30. crop_size: 227
  31. mirror: false
  32. mean_file:”imagenet_mean.binaryproto”#均值文件
  33. }
  34. include: { phase: TEST }
  35. }

二、h5py格式数据

上面的lmdb一般用于单标签数据,图片分类的时候,大部分用lmdb格式。然而假设我们要搞的项目是人脸特征点识别,我们要识别出68个人脸特征点,也就是相当于136维的输出向量。网上查了一下,对于caffe多标签输出,需要使用h5py格式的数据,而且使用h5py的数据格式的时候,caffe是不能使用数据扩充进行相关的数据变换的,很是悲剧啊,所以如果caffe使用h5py数据格式的话,需要自己在外部,进行数据扩充,数据归一化等相关的数据预处理操作。

1、h5py数据格式生成

下面演示一下数据h5py数据格式的制作:

[python] view plain copy

  1. # coding: utf-8
  2. caffe_root = ‘/home/hjimce/caffe/‘
  3. import sys
  4. sys.path.insert(0, caffe_root + ‘python’)
  5. import os
  6. import cv2
  7. import numpy as np
  8. import h5py
  9. from common import shuffle_in_unison_scary, processImage
  10. import matplotlib.pyplot as plt
  11. def readdata(filepath):
  12. fr=open(filepath,’r’)
  13. filesplit=[]
  14. for line in fr.readlines():
  15. s=line.split()
  16. s[1:]=[float(x) for x in s[1:]]
  17. filesplit.append(s)
  18. fr.close()
  19. return filesplit
  20. #因为我们的训练数据可能不是正方形,然而网络的输入的大小是正方形图片,为了避免强制resize引起的图片扭曲,所以我们采用填充的方法
  21. def sqrtimg(img):
  22. height,width=img.shape[:2]
  23. maxlenght=max(height,width)
  24. sqrtimg0=np.zeros((maxlenght,maxlenght,3),dtype=’uint8’)
  25. sqrtimg0[(maxlenght*.5-height*.5):(maxlenght*.5+height*.5),(maxlenght*.5-width*.5):(maxlenght*.5+width*.5)]=img
  26. return sqrtimg0
  27. def generate_hdf5():
  28. labelfile =readdata(‘../data/my_alige_landmark.txt’)
  29. F_imgs = []
  30. F_landmarks = []
  31. for i,l in enumerate(labelfile):
  32. imgpath=’../data/‘+l[0]
  33. img=cv2.imread(imgpath)
  34. maxx=max(img.shape[0],img.shape[1])
  35. img=sqrtimg(img)#把输入图片填充成正方形,因为我们要训练的图片的大小是正方形的图片255*255
  36. img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#图片转为灰度图像
  37. f_face=cv2.resize(img,(39,39))#把图片缩放成255*255的图片
  38. # F
  39. plt.imshow(f_face,cmap=’gray’)
  40. f_face = f_face.reshape((1, 39, 39))
  41. f_landmark =np.asarray(l[1:],dtype=’float’)
  42. F_imgs.append(f_face)
  43. #归一化人脸特征点标签,因为上面height等于width,这里比较懒,直接简写
  44. f_landmark=f_landmark/maxx #归一化到0~1之间
  45. print f_landmark
  46. F_landmarks.append(f_landmark)
  47. F_imgs, F_landmarks = np.asarray(F_imgs), np.asarray(F_landmarks)
  48. F_imgs = processImage(F_imgs)#图片预处理,包含均值归一化,方差归一化等
  49. shuffle_in_unison_scary(F_imgs, F_landmarks)#打乱数据
  50. #生成h5py格式
  51. with h5py.File(os.getcwd()+ ‘/train_data.h5’, ‘w’) as f:
  52. f[‘data’] = F_imgs.astype(np.float32)
  53. f[‘landmark’] = F_landmarks.astype(np.float32)
  54. #因为caffe的输入h5py不是直接使用上面的数据,而是需要调用.txt格式的文件
  55. with open(os.getcwd() + ‘/train.txt’, ‘w’) as f:
  56. f.write(os.getcwd() + ‘/train_data.h5\n’)
  57. print i
  58. if __name__ == ‘__main__‘:
  59. generate_hdf5()

利用上面的代码,可以生成一个train.txt、train_data.h5的文件,然后在caffe的prototxt中,进行训练的时候,可以用如下的代码,作为数据层的调用:

[python] view plain copy

  1. layer {
  2. name: “hdf5_train_data”
  3. type: “HDF5Data”#需要更改类型
  4. top: “data”
  5. top: “landmark”
  6. include {
  7. phase: TRAIN
  8. }
  9. hdf5_data_param { #这个参数类型h5f5_data_param记得要更改
  10. source: “h5py/train.txt”#上面生成的train.txt文件
  11. batch_size: 64
  12. }
  13. }

上面需要注意的是,相比与lmdb的数据格式,我们需要该动的地方,我标注的地方就是需要改动的地方,还有h5py不支持数据变换。

2、h5py数据读取

[python] view plain copy

  1. f=h5py.File(‘../h5py/train.h5’,’r’)
  2. x=f[‘data’][:]
  3. x=np.asarray(x,dtype=’float32’)
  4. y=f[‘label’][:]
  5. y=np.asarray(y,dtype=’float32’)
  6. print x.shape
  7. print y.shape

可以通过上面代码,查看我们生成的.h5格式文件。

在需要注意的是,我们输入caffe的h5py图片数据为四维矩阵(number_samples,nchannels,height,width)的矩阵,标签矩阵为二维(number_samples,labels_ndim),同时数据的格式需要转成float32,用于回归任务。

**********************作者:hjimce 时间:2015.10.2 联系QQ:1393852684 原创文章,转载请保留原文地址、作者等信息***************

[Image 1]:

发表评论

表情:
评论列表 (有 0 条评论,398人围观)

还没有评论,来说两句吧...

相关阅读