zoukankan      html  css  js  c++  java
  • 使用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对图片作预测,在终端输入:

    三、结束语

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

  • 相关阅读:
    HDU 1058 Humble Numbers
    HDU 1421 搬寝室
    HDU 1176 免费馅饼
    七种排序算法的实现和总结
    算法纲要
    UVa401 回文词
    UVa 10361 Automatic Poetry
    UVa 537 Artificial Intelligence?
    UVa 409 Excuses, Excuses!
    UVa 10878 Decode the tape
  • 原文地址:https://www.cnblogs.com/jyxbk/p/7770904.html
Copyright © 2011-2022 走看看