赞
踩
我的图片来源于徐其华的博客,(http://www.cnblogs.com/denny402/p/5083300.html).这是一个小型的图片数据库,这个图片数据库有500张图片;训练样本400张,测试样本100张;分为5类:bus,dinosaur,elephant,rose,horse(大巴,恐龙,大象,鲜花,马)。
图片的size==(384*256);图片格式为JPG格式.由于我在此块使用的是CIFAR-10模型,而在CIFAR10模型中,训练样本和测试样本的图片size==(32*32)(pixel),因此在我们开始训练自己的模型之前,我们首先需要对所有的图片进行预处理.其中最重要的预处理操作就是:图片尺寸的归一化.
在此块,我基于OpenCv写了一个预处理Demo程序,具体的程序如下所示:
- /*******************************************************************************************************************
- *文件功能:
- * 1--针对CIFRA-10模型,进行的图片处理程序,将图片处理成32*32的大小
- * 2--用于更改图片的图片名,后缀图片格式,图片的大小
- * win10+vs2013+OpenCv2.4.8
- *时间地点:
- * 陕西师范大学 2016.10.28
- ********************************************************************************************************************/
-
- #include<stdio.h>
- #include<iostream>
-
- #include<opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- #include<opencv2/imgproc/imgproc.hpp>
-
- #include<opencv2/core/core_c.h>
- #include<opencv2/imgproc/imgproc_c.h>
-
- using namespace std;
- using namespace cv;
-
-
- int main()
- {
- char strFilename[100]; //【1】定义一个字符数组保存----图片的存储路径
- char strWindowname[100]; //【2】定义一个字符数组保存----用于动态更新窗口的窗口名
- char strFilenameAft[100]; //【3】定义一个字符数组保存----用于给处理之后的图片动态的命名
- int j = 1;
- for (int i = 720; i <=799; i++)
- { //【4】将图片的路径名动态的写入到strFilename这个地址的内存空间
- sprintf_s(strFilename, "D:\\mydata\\train\\%d.jpg", i);
- sprintf_s(strFilenameAft, "D:\\mydata\\aft_train\\horse%d.jpeg", j);
- sprintf_s(strWindowname, "srcImg%d", j);
-
- //===========================================================================================
- //【模块1】将图片读入内存,并显示
- //===========================================================================================
- IplImage* pImg = cvLoadImage(strFilename); //【1】从指定的路径,将图片加载到内存中
- cvNamedWindow(strWindowname, CV_WINDOW_AUTOSIZE); //【2】创建一个显示图片的窗口
- cvMoveWindow(strWindowname, 200, 200); //【3】将显示窗口固定在(200,200)这个位置显示都进来的图片
- cvShowImage(strWindowname, pImg); //【4】显示图片
- //===========================================================================================
- //【模块2】高斯金字塔下采样
- // 1----将图片size调节到32*32左右,并显示
- // 2----384*256:经过连续三次下采样,变为48*32
- //============================================================================================
- IplImage* pPyrDownImg = cvCreateImage(cvSize(pImg->width / 2, pImg->height / 2), pImg->depth, pImg->nChannels);
- IplImage* pPyrDownImg1 = cvCreateImage(cvSize(pPyrDownImg->width / 2, pPyrDownImg->height / 2), pPyrDownImg->depth, pPyrDownImg->nChannels);
- IplImage* pPyrDownImg2 = cvCreateImage(cvSize(pPyrDownImg1->width / 2, pPyrDownImg1->height / 2), pPyrDownImg1->depth, pPyrDownImg1->nChannels);
- cvPyrDown(pImg, pPyrDownImg, CV_GAUSSIAN_5x5); //【1】384*256--->192*128
- cvPyrDown(pPyrDownImg, pPyrDownImg1, CV_GAUSSIAN_5x5);//【2】192*128--->96*64
- cvPyrDown(pPyrDownImg1,pPyrDownImg2, CV_GAUSSIAN_5x5);//【3】96*64----->48*32
- cvNamedWindow("【PyrDown】", CV_WINDOW_AUTOSIZE);
- cvMoveWindow ("【PyrDown】", 500, 200);
- cvShowImage("【PyrDown】", pPyrDownImg2);
- //============================================================================================
- //【模块3】设置ROI区域裁剪图片----利用ROI区域将图片裁剪为:32*32
- //============================================================================================
- cvSetImageROI(pPyrDownImg2, cvRect(8, 0, 32, 32));//【1】设置一个32*32的ROI区域
- cvNamedWindow("【ROI_Img】");
- cvMoveWindow ("【ROI_Img】", 700, 200);
- cvShowImage ("【ROI_Img】", pPyrDownImg2);
- cvSaveImage (strFilenameAft, pPyrDownImg2); //【2】将修改图片size之后的图片保存在指定的文件夹下
- ++j;
- cv::waitKey(10);
- //============================================================================================
- //【模块4】释放内存空间
- //============================================================================================
- cvReleaseImage(&pPyrDownImg);
- cvReleaseImage(&pImg); //【1】释放掉存储图片的内存
- cvDestroyWindow(strWindowname); //【2】销毁窗口的内存
- cvDestroyWindow("【ROI_Img】");
- cvDestroyWindow("【PyrDown】");
- }
-
- return 0;
-
- }
使用上面程序对Image进行图片尺寸归一化,命名的统一等操作.
没有使用程序处理之前的图片(384*256),图片的命名也不统一,如下图所示:
使用程序处理之后的图片,全部变为32*32的JPEG格式的图片,并且图片的命名也进行了统一:
在./caffe/data/目录下建立自己的数据文件夹myself,并且在myself文件夹下建立train文件夹和val文件夹.train文件夹用于存放训练样本,val文件夹用于存放测试样本(验证集),如下图所示:
然后,将你处理好的训练样本图片放在./caffe/data/myself/train/这个文件夹下面,测试样本放在./caffe/data/myself/val/这个文件夹下面.
1----train.txt----存放训练图片的图片名和类别标签,一行一张图片,如下所示:
(这块要特别注意的一点是:在下面这两个文本文件中,图片名和标签之间的距离,只能是一个空格键),如果这两者之间的距离多于或者少于一个[空格键的话],那么,在图片数据---》LMDB数据格式这一步一般不会报错,但是,当计算均值的时候,会出现错误或者问题)
(比如下面文本文档,我使用了4个空格,就出现了这种问题,现在大家把他们之间的距离调整为一个空格,就可以运行了)
2----val.txt------存放测试样本的图片名和类别标签,一行代表一张图片,如下图所示:
在./caffe/examples/文件夹下面,建立myself文件夹,并且将:./caffe/examples/imagenet/文件夹下面的create_imagenet.sh这个shell脚本copy到myself文件夹下,打开,将里面的内容更改为下面的形式,如图所示:
- #!/usr/bin/env sh
- # Create the myself lmdb inputs
- # N.B. set the path to the myself train + val data dirs
- set -e
-
- EXAMPLE=examples/myself
- DATA=data/myself
- TOOLS=build/tools
-
- echo "Creating train lmdb..."
-
- GLOG_logtostderr=1 $TOOLS/convert_imageset.bin \
- --resize_height=32 \
- --resize_width=32 \
- --shuffle \
- /home/wei/caffe/data/myself/train/ \
- $DATA/train.txt \
- $EXAMPLE/myself_cifar10_train_lmdb
-
- echo "Creating val lmdb..."
-
- GLOG_logtostderr=1 $TOOLS/convert_imageset.bin \
- --resize_height=32 \
- --resize_width=32 \
- --shuffle \
- /home/wei/caffe/data/myself/val/ \
- $DATA/val.txt \
- $EXAMPLE/myself_cifar10_val_lmdb
-
- echo "Done."
并且,将这个shell脚本的文件名改为:create_cifar_lmdb.sh,使用下面的命令运行,则会产生两个数据库文件:
产生的连个数据库文件,如下图所示:
在./caffe/examples/myself/文件夹下面,创建make_myself_mean.sh这个shell脚本,并且编辑内容如下所示:
- #!/usr/bin/env sh
- # Compute the mean image from the myself training lmdb
- # N.B. this is available in data/myself
- TOOLS=./build/tools
- DATA=./data/myself
- EXAMPLE=./examples
-
- $TOOLS/compute_image_mean.bin $EXAMPLE/myself/myself_cifar10_train_lmdb $EXAMPLE/myself/myself_cifar10_mean.binaryproto
-
- echo "Done."
此快,我们使用CIFAR10网络模型,因此,将./examples/cifar10/文件夹下的cifar10_quick_train_test.prototxt网络模型配置文件copy到我们的文件夹./examples/myself/下面,并且进行如下的修改:
- name: "CIFAR10_quick"
- layer {
- name: "cifar"
- type: "Data"
- top: "data"
- top: "label"
- include {
- phase: TRAIN
- }
- transform_param { //【第1块修改的地方】下面是均值文件所在的路径,改为你自己的均值文件所在的路径
- mean_file: "examples/myself/myself_cifar10_mean.binaryproto"
- }
- data_param { //【第2块修改的地方】下面改为训练样本生成的数据库所在的目录[注意:是训练样本数据库]
- source: "examples/myself/myself_cifar10_train_lmdb"
- batch_size: 10 //【第3块修改的地方】由于我们的训练样本只有400张图片,所以我们一次读入10张图片就可以了
- backend: LMDB
- }
- }
- layer {
- name: "cifar"
- type: "Data"
- top: "data"
- top: "label"
- include {
- phase: TEST
- }
- transform_param { //【第4块修改的地方】下面是均值文件所在的路径,改为你自己的均值文件所在的路径
- mean_file: "examples/myself/myself_cifar10_mean.binaryproto"
- }
- data_param { //【第5块修改的地方】下面改为测试样本生成的数据库所在的目录[注意:是测试样本数据库]
- source: "examples/myself/myself_cifar10_val_lmdb"
- batch_size: 10 //【第6块修改的地方】由于我们的测试样本只有100张图片,所以我们一次读入10张图片就可以了
- backend: LMDB
- }
- }
- layer {
- name: "conv1"
- type: "Convolution"
- bottom: "data"
- top: "conv1"
- param {
- lr_mult: 1
- }
- param {
- lr_mult: 2
- }
- 中间的省略.......
- layer {
- name: "ip2"
- type: "InnerProduct"
- bottom: "ip1"
- top: "ip2"
- param {
- lr_mult: 1
- }
- param {
- lr_mult: 2
- }
- inner_product_param {
- num_output: 5 //【第7块修改的地方】我们现在是5分类问题,所以将第二个全连接层改为5
- weight_filler {
- type: "gaussian"
- std: 0.1
- }
- bias_filler {
- type: "constant"
- }
- }
- }
- layer {
- name: "accuracy"
- type: "Accuracy"
- bottom: "ip2"
- bottom: "label"
- top: "accuracy"
- include {
- phase: TEST
- }
- }
- layer {
- name: "loss"
- type: "SoftmaxWithLoss"
- bottom: "ip2"
- bottom: "label"
- top: "loss"
- }
我们也是用同样的方法,直接将./examples/cifar10/文件夹下的cifar10_quick_solver.prototxt这个超参数配置文件
copy到我们的目录下,然后,进行下面的修改就可以了:
- #!/usr/bin/env sh
- set -e
-
- TOOLS=./build/tools
-
- $TOOLS/caffe train \
- --solver=examples/myself/cifar10_quick_solver.prototxt $@
- //【1】改为你自己的网络模型配置文件的目录
- net: "examples/myself/cifar10_quick_train_test.prototxt"
- test_iter: 10 //【2】预测阶段迭代次数,我们设为10,这样就可以覆盖我们的100张测试样本
- test_interval: 50 //【3】由于我们只有400张训练样本,所以我们将此改为50,每迭代50次,进行一次测试
- base_lr: 0.001 //【4】权值学习率,其实就是在反向传播阶段,权值每次的调整量的程度
- momentum: 0.9
- weight_decay: 0.004
- lr_policy: "fixed" //【5】在整个过程中,我们使用固定的学习率,当然,你也可以试一下可变学习率
- display: 20
- max_iter: 500 //【6】400张训练样本,所以我就将最大的迭代次数设为400
- snapshot: 400
- snapshot_format: HDF5
- snapshot_prefix: "examples/myself/cifar10_quick"
- solver_mode: CPU //【7】我用的是CPU,所以将此快设置为CPU
- #!/usr/bin/env sh
- set -e
-
- TOOLS=./build/tools
-
- $TOOLS/caffe train \
- --solver=examples/myself/cifar10_quick_solver.prototxt $@
sudo sh ./examples/myself/train_quick.sh
训练过程,如下所示:
训练结果显示,正确率为90%,accuracy==0.9,如下图所示:
我们以迭代次数为X轴,以准确率为Y轴,输出的曲线如下所示:
我们同样以迭代次数为X轴,以损失率为Y轴,可视化结果如下所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。