使用LeNet训练自己的手写图片数据

一、前言

本文主要尝试将自己的数据集制作成lmdb格式,送进lenet作训练和测试,参考了http://blog.csdn.net/liuweizj12/article/details/52149743http://blog.csdn.net/xiaoxiao_huitailang/article/details/51361036这两篇博文

二、从训练模型到使用模型预测图片分类

(1)自己准备的图像数据

由于主要是使用lenet模型训练自己的图片数据,我的图像数据共有10个类别,分别是0~9,相应地保存在名为0~9的文件夹,在/homg/您的用户名/下新建一文件夹char_images,用于保存图像数据,在/homg/您的用户名/char_images/下新建两个文件夹,名字分别为train和val,各自都包含了名为0~9的文件夹,例如文件夹0内存放的是字符”0”的图像,我的文件夹 如下:

(2)对图像数据作统一缩放至28*28,并生成txt标签

 

为了计算均值文件,需要将所有图片缩放至统一的尺寸,在train和val文件夹所在路径下创建python文件,命名getPath.py,并写入以下内容:

 

[python] view plain copy
 
  1. #coding:utf-8  
  2.   
  3. import cv2  
  4. import os  
  5.   
  6. def IsSubString( SubStrList , Str):  #判断SubStrList的元素  
  7.     flag = True                  #是否在Str内  
  8.     for substr in SubStrList:  
  9.         if not ( substr in Str):  
  10.             flag = False            
  11.    
  12.     return flag  
  13.   
  14. def GetFileList(FindPath,FlagStr=[]):  #搜索目录下的子文件路径  
  15.     FileList=[]    
  16.     FileNames=os.listdir(FindPath)    
  17.     if len(FileNames)>0:    
  18.         for fn in FileNames:    
  19.             if len(FlagStr)>0:    
  20.                 if IsSubString(FlagStr,fn): #不明白这里判断是为了啥  
  21.                     fullfilename=os.path.join(FindPath,fn)    
  22.                     FileList.append(fullfilename)    
  23.             else:    
  24.                 fullfilename=os.path.join(FindPath,fn)    
  25.                 FileList.append(fullfilename)    
  26.         
  27.     if len(FileList)>0:    
  28.         FileList.sort()    
  29.             
  30.     return FileList  
  31.   
  32.   
  33. train_txt = open('train.txt' , 'w') #制作标签数据  
  34. classList =['0','1','2','3','4','5','6','7','8','9']  
  35. for idx in range(len(classList)) :  
  36.     imgfile=GetFileList('train/'+ classList[idx])#将数据集放在与.py文件相同目录下       
  37.     for img in imgfile:   
  38.         srcImg = cv2.imread( img);  
  39.                 resizedImg = cv2.resize(srcImg , (28,28))  
  40.                 cv2.imwrite( img  ,resizedImg)   
  41.         strTemp=img+' '+classList[idx]+' '        #用空格代替转义字符       
  42.             train_txt.writelines(strTemp)    
  43. train_txt.close()   
  44.   
  45.   
  46. test_txt = open('val.txt' , 'w') #制作标签数据  
  47. for idx in range(len(classList)) :  
  48.     imgfile=GetFileList('val/'+ classList[idx])  
  49.     for img in imgfile:    
  50.                 srcImg = cv2.imread( img);  
  51.                 resizedImg = cv2.resize(srcImg , (28,28))  
  52.                 cv2.imwrite( img  ,resizedImg)  
  53.         strTemp=img+' '+classList[idx]+' '        #用空格代替转义字符       
  54.             test_txt.writelines(strTemp)    
  55. test_txt.close()  
  56.   
  57. print("成功生成文件列表")  

运行该py文件,可将所有图片缩放至28*28大小,并且在rain和val文件夹所在路径下生成训练和测试图像数据的标签txt文件,文件内容为:
         

(3)生成lmdb格式的数据集

首先于caffe路径下新建一文件夹My_File,并在My_File下新建两个文件夹Build_lmdb和Data_label,将(2)中生成文本文件train.txt和val.txt搬至Data_label下

  

将caffe路径下 examples/imagenet/create_imagenet.sh 复制一份到Build_lmdb文件夹下

打开create_imagenet.sh ,修改内容如下:

 

[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. set -e  
  5.   
  6. EXAMPLE=My_File/Build_lmdb         #生成的lmdb格式数据保存地址  
  7. DATA=My_File/Data_label                 #两个txt标签文件所在路径  
  8. TOOLS=build/tools                            #caffe自带工具,不用管  
  9.   
  10. TRAIN_DATA_ROOT=/home/zjy/char_images/    #预先准备的训练图片路径,该路径和train.txt上写的路径合起来是图片完整路径  
  11. VAL_DATA_ROOT=/home/zjy/char_images/         #预先准备的测试图片路径,...  
  12.   
  13. # Set RESIZE=true to resize the images to 256x256. Leave as false if images have  
  14. # already been resized using another tool.  
  15. RESIZE=false  
  16. if $RESIZE; then  
  17.   RESIZE_HEIGHT=28  
  18.   RESIZE_WIDTH=28  
  19. else  
  20.   RESIZE_HEIGHT=0  
  21.   RESIZE_WIDTH=0  
  22. fi  
  23.   
  24. if [ ! -d "$TRAIN_DATA_ROOT" ]; then  
  25.   echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"  
  26.   echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path"   
  27.        "where the ImageNet training data is stored."  
  28.   exit 1  
  29. fi  
  30.   
  31. if [ ! -d "$VAL_DATA_ROOT" ]; then  
  32.   echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT"  
  33.   echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path"   
  34.        "where the ImageNet validation data is stored."  
  35.   exit 1  
  36. fi  
  37.   
  38. echo "Creating train lmdb..."  
  39.   
  40. GLOG_logtostderr=1 $TOOLS/convert_imageset   
  41.     --resize_height=$RESIZE_HEIGHT   
  42.     --resize_width=$RESIZE_WIDTH   
  43.     --shuffle   
  44.     --gray         #灰度图像加上这个  
  45.     $TRAIN_DATA_ROOT   
  46.     $DATA/train.txt   
  47.     $EXAMPLE/train_lmdb                   #生成的lmdb格式训练数据集所在的文件夹  
  48.   
  49. echo "Creating val lmdb..."  
  50.   
  51. GLOG_logtostderr=1 $TOOLS/convert_imageset   
  52.     --resize_height=$RESIZE_HEIGHT   
  53.     --resize_width=$RESIZE_WIDTH   
  54.     --shuffle   
  55.     --gray         #灰度图像加上这个  
  56.     $VAL_DATA_ROOT   
  57.     $DATA/val.txt   
  58.     $EXAMPLE/val_lmdb              #生成的lmdb格式训练数据集所在的文件夹  
  59.   
  60. echo "Done."  

以上只是为了说明修改的地方才添加汉字注释,实际时sh文件不要出现汉字,运行该sh文件,可在Build_lmdb文件夹内生成2个文件夹train_lmdb和val_lmdb,里面各有2个lmdb格式的文件

(4)更改lenet_solver.prototxt和lenet_train_test.prototxt
将caffe/examples/mnist下的 train_lenet.sh 、lenet_solver.prototxt 、lenet_train_test.prototxt 这三个文件复制至 My_File,首先修改train_lenet.sh 如下,只改了solver.prototxt的路径

 

[python] view plain copy
 
  1. #!/usr/bin/env sh  
  2. set -e  
  3.   
  4. ./build/tools/caffe train --solver=My_File/lenet_solver.prototxt $@    #改路径  

然后再更改lenet_solver.prototxt,如下:

 

[python] view plain copy
 
  1. # The train/test net protocol buffer definition  
  2. net: "My_File/lenet_train_test.prototxt"            #改这里  
  3. # test_iter specifies how many forward passes the test should carry out.  
  4. # In the case of MNIST, we have test batch size 100 and 100 test iterations,  
  5. # covering the full 10,000 testing images.  
  6. test_iter: 100  
  7. # Carry out testing every 500 training iterations.  
  8. test_interval: 500  
  9. # The base learning rate, momentum and the weight decay of the network.  
  10. base_lr: 0.01  
  11. momentum: 0.9  
  12. weight_decay: 0.0005  
  13. # The learning rate policy  
  14. lr_policy: "inv"  
  15. gamma: 0.0001  
  16. power: 0.75  
  17. # Display every 100 iterations  
  18. display: 100  
  19. # The maximum number of iterations  
  20. max_iter: 10000  
  21. # snapshot intermediate results  
  22. snapshot: 5000  
  23. snapshot_prefix: "My_File/"         #改这里  
  24. # solver mode: CPU or GPU  
  25. solver_mode: GPU  

最后修改lenet_train_test.prototxt ,如下:

[python] view plain copy
 
  1. name: "LeNet"  
  2. layer {  
  3.   name: "mnist"  
  4.   type: "Data"  
  5.   top: "data"  
  6.   top: "label"  
  7.   include {  
  8.     phase: TRAIN  
  9.   }  
  10.   transform_param {  
  11.     scale: 0.00390625  
  12.   }  
  13.   data_param {  
  14.     source: "My_File/Build_lmdb/train_lmdb"       #改成自己的  
  15.     batch_size: 64  
  16.     backend: LMDB  
  17.   }  
  18. }  
  19. layer {  
  20.   name: "mnist"  
  21.   type: "Data"  
  22.   top: "data"  
  23.   top: "label"  
  24.   include {  
  25.     phase: TEST  
  26.   }  
  27.   transform_param {  
  28.     scale: 0.00390625  
  29.   }  
  30.   data_param {  
  31.     source: "My_File/Build_lmdb/val_lmdb"        #改成自己的  
  32.     batch_size: 100  
  33.     backend: LMDB  
  34.   }  
  35. }  
  36. layer {  
  37.   name: "conv1"  
  38.   type: "Convolution"  
  39.   bottom: "data"  
  40.   top: "conv1"  
  41.   param {  
  42.     lr_mult: 1  
  43.   }  
  44.   param {  
  45.     lr_mult: 2  
  46.   }  
  47.   convolution_param {  
  48.     num_output: 20  
  49.     kernel_size: 5  
  50.     stride: 1  
  51.     weight_filler {  
  52.       type: "xavier"  
  53.     }  
  54.     bias_filler {  
  55.       type: "constant"  
  56.     }  
  57.   }  
  58. }  
  59. layer {  
  60.   name: "pool1"  
  61.   type: "Pooling"  
  62.   bottom: "conv1"  
  63.   top: "pool1"  
  64.   pooling_param {  
  65.     pool: MAX  
  66.     kernel_size: 2  
  67.     stride: 2  
  68.   }  
  69. }  
  70. layer {  
  71.   name: "conv2"  
  72.   type: "Convolution"  
  73.   bottom: "pool1"  
  74.   top: "conv2"  
  75.   param {  
  76.     lr_mult: 1  
  77.   }  
  78.   param {  
  79.     lr_mult: 2  
  80.   }  
  81.   convolution_param {  
  82.     num_output: 50  
  83.     kernel_size: 5  
  84.     stride: 1  
  85.     weight_filler {  
  86.       type: "xavier"  
  87.     }  
  88.     bias_filler {  
  89.       type: "constant"  
  90.     }  
  91.   }  
  92. }  
  93. layer {  
  94.   name: "pool2"  
  95.   type: "Pooling"  
  96.   bottom: "conv2"  
  97.   top: "pool2"  
  98.   pooling_param {  
  99.     pool: MAX  
  100.     kernel_size: 2  
  101.     stride: 2  
  102.   }  
  103. }  
  104. layer {  
  105.   name: "ip1"  
  106.   type: "InnerProduct"  
  107.   bottom: "pool2"  
  108.   top: "ip1"  
  109.   param {  
  110.     lr_mult: 1  
  111.   }  
  112.   param {  
  113.     lr_mult: 2  
  114.   }  
  115.   inner_product_param {  
  116.     num_output: 500  
  117.     weight_filler {  
  118.       type: "xavier"  
  119.     }  
  120.     bias_filler {  
  121.       type: "constant"  
  122.     }  
  123.   }  
  124. }  
  125. layer {  
  126.   name: "relu1"  
  127.   type: "ReLU"  
  128.   bottom: "ip1"  
  129.   top: "ip1"  
  130. }  
  131. layer {  
  132.   name: "ip2"  
  133.   type: "InnerProduct"  
  134.   bottom: "ip1"  
  135.   top: "ip2"  
  136.   param {  
  137.     lr_mult: 1  
  138.   }  
  139.   param {  
  140.     lr_mult: 2  
  141.   }  
  142.   inner_product_param {  
  143.     num_output: 10  
  144.     weight_filler {  
  145.       type: "xavier"  
  146.     }  
  147.     bias_filler {  
  148.       type: "constant"  
  149.     }  
  150.   }  
  151. }  
  152. layer {  
  153.   name: "accuracy"  
  154.   type: "Accuracy"  
  155.   bottom: "ip2"  
  156.   bottom: "label"  
  157.   top: "accuracy"  
  158.   include {  
  159.     phase: TEST  
  160.   }  
  161. }  
  162. layer {  
  163.   name: "loss"  
  164.   type: "SoftmaxWithLoss"  
  165.   bottom: "ip2"  
  166.   bottom: "label"  
  167.   top: "loss"  
  168. }  

运行 My_File/train_lenet.sh ,得到最后的训练结果,在My_File下生成训练的caffemodel和solverstate。

(5)生成均值文件
均值文件主要用于图像预测的时候,由caffe/build/tools/compute_image_mean生成,在My_File文件夹下新建一文件夹Mean,用于存放均值文件,在caffe/下执行:
build/tools/compute_image_mean My_File/Build_lmdb/train_lmdb My_File/Mean/mean.binaryproto
可在My_File/Mean/下生成均值文件mean.binaryproto 
(6)生成deploy.prototxt
deploy.prototxt是在lenet_train_test.prototxt的基础上删除了开头的Train和Test部分以及结尾的Accuracy、SoftmaxWithLoss层,并在开始时增加了一个data层描述,结尾增加softmax层,可以参照博文http://blog.csdn.net/lanxuecc/article/details/52474476 使用python生成,也可以直接由train_val.prototxt上做修改,在My_File文件夹下新建一文件夹Deploy,将 lenet_train_test.prototxt复制至文件夹Deploy下,并重命名为deploy.prototxt ,修改里面的内容如下:

 

[python] view plain copy
 
  1. name: "LeNet"  
  2. layer {                   #删去原来的Train和Test部分,增加一个data层  
  3.   name: "data"  
  4.   type: "Input"  
  5.   top: "data"  
  6.   input_param { shape: { dim: 1 dim: 1 dim: 28 dim: 28 } }  
  7. }  
  8. layer {  
  9.   name: "conv1"  
  10.   type: "Convolution"  
  11.   bottom: "data"  
  12.   top: "conv1"  
  13.   param {  
  14.     lr_mult: 1  
  15.   }  
  16.   param {  
  17.     lr_mult: 2  
  18.   }  
  19.   convolution_param {  
  20.     num_output: 20  
  21.     kernel_size: 5  
  22.     stride: 1  
  23.     weight_filler {  
  24.       type: "xavier"  
  25.     }  
  26.     bias_filler {  
  27.       type: "constant"  
  28.     }  
  29.   }  
  30. }  
  31. layer {  
  32.   name: "pool1"  
  33.   type: "Pooling"  
  34.   bottom: "conv1"  
  35.   top: "pool1"  
  36.   pooling_param {  
  37.     pool: MAX  
  38.     kernel_size: 2  
  39.     stride: 2  
  40.   }  
  41. }  
  42. layer {  
  43.   name: "conv2"  
  44.   type: "Convolution"  
  45.   bottom: "pool1"  
  46.   top: "conv2"  
  47.   param {  
  48.     lr_mult: 1  
  49.   }  
  50.   param {  
  51.     lr_mult: 2  
  52.   }  
  53.   convolution_param {  
  54.     num_output: 50  
  55.     kernel_size: 5  
  56.     stride: 1  
  57.     weight_filler {  
  58.       type: "xavier"  
  59.     }  
  60.     bias_filler {  
  61.       type: "constant"  
  62.     }  
  63.   }  
  64. }  
  65. layer {  
  66.   name: "pool2"  
  67.   type: "Pooling"  
  68.   bottom: "conv2"  
  69.   top: "pool2"  
  70.   pooling_param {  
  71.     pool: MAX  
  72.     kernel_size: 2  
  73.     stride: 2  
  74.   }  
  75. }  
  76. layer {  
  77.   name: "ip1"  
  78.   type: "InnerProduct"  
  79.   bottom: "pool2"  
  80.   top: "ip1"  
  81.   param {  
  82.     lr_mult: 1  
  83.   }  
  84.   param {  
  85.     lr_mult: 2  
  86.   }  
  87.   inner_product_param {  
  88.     num_output: 500  
  89.     weight_filler {  
  90.       type: "xavier"  
  91.     }  
  92.     bias_filler {  
  93.       type: "constant"  
  94.     }  
  95.   }  
  96. }  
  97. layer {  
  98.   name: "relu1"  
  99.   type: "ReLU"  
  100.   bottom: "ip1"  
  101.   top: "ip1"  
  102. }  
  103. layer {  
  104.   name: "ip2"  
  105.   type: "InnerProduct"  
  106.   bottom: "ip1"  
  107.   top: "ip2"  
  108.   param {  
  109.     lr_mult: 1  
  110.   }  
  111.   param {  
  112.     lr_mult: 2  
  113.   }  
  114.   inner_product_param {  
  115.     num_output: 10  
  116.     weight_filler {  
  117.       type: "xavier"  
  118.     }  
  119.     bias_filler {  
  120.       type: "constant"  
  121.     }  
  122.   }  
  123. }  
  124. layer {                   #增加softmax层  
  125.   name: "prob"  
  126.   type: "Softmax"  
  127.   bottom: "ip2"  
  128.   top: "prob"  
  129. }  

(7)预测图片
在My_File文件夹下创建一文件夹Pic,用于存放测试的图片;在My_File文件夹下创建另一文件夹Synset,在其中新建synset_words.txt文件,之后在里面输入:
0
1
2
3
4
5
6
7
8
9

看看My_File文件夹都有啥了

 

最后使用caffe/build/examples/cpp_classification/classification.bin对图片作预测,在终端输入:

三、结束语

真是篇又臭又长的博文,高手自行忽略,刚刚入门的可以看看!

原文地址:https://www.cnblogs.com/jyxbk/p/7770904.html