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对图片作预测,在终端输入:

    三、结束语

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

  • 相关阅读:
    关于android中透明、半透明、百分比转换
    详解 RestTemplate 操作
    springboot No Identifier specified for entity的解决办法
    Java-Spring-获取Request,Response对象
    java 如何判断操作系统是Linux还是Windows
    Spring中使用Ehcache的方法和注意事项
    Protostuff序列化
    如何使用apache自带的ab压力测试工具
    java 调用 wsdl形式的webservice 示例
    web service 异常
  • 原文地址:https://www.cnblogs.com/jyxbk/p/7770904.html
Copyright © 2011-2022 走看看