Caffe_stu03_小训练

参考:https://blog.csdn.net/sst___/article/details/79847697

获得数据集

使用官方的数据集 mnist

caffe文件夹下 执行./data/mnist/get_mnist.sh

或者编写以下shell文件

#!/usr/bin/env sh
# This scripts downloads the mnist data and unzips it.

DIR="$( cd "$(dirname "$0")" ; pwd -P )"
cd "$DIR"

echo "Downloading..."

for fname in train-images-idx3-ubyte train-labels-idx1-ubyte t10k-images-idx3-ubyte t10k-labels-idx1-ubyte
do
    if [ ! -e $fname ]; then
        wget --no-check-certificate http://yann.lecun.com/exdb/mnist/${fname}.gz
        gunzip ${fname}.gz
    fi
done

执行得到数据集

image-20200618161929250

使用自己的数据集

这里我借用的是别人的数据集 百度网盘
下载之后只保留train和val即可,因为我们后面用这两个文件来自己生成train.txt和val.txt.
caffe/examples文件夹下新建一个myfile_tostudy 文件夹 放入data文件
image-20200618171706147

如果没有 caffe文件夹 那么可以随便建立一个文件夹用来放数据(只是需要更改后续各个文件的路径)。
这里我因为之前不知道直接安装了caffe后各种bulid/tools 已经自动写入到了Linux的PATH里面去了

所以我git clone了 caffe的源码文件
git clone https://github.com/BVLC/caffe.git
未进行编译,因为后面做着做着发现 所需要的tools都可以直接从命令行使用(下载caffe时自动写入了PATH)

1. 数据格式处理

生成txt文件

myfile_tostudy下建立一个shell 文件。我的命名为create_filelist.sh

目的是根据所下载的百度网盘里面的图片的进行分类(百度网盘中的文件内容根据文件名进行了分类)

#!/usr/bin/env sh
DATA=examples/myfile_tostudy/data    #数据来源的路径 
MY=examples/myfile_tostudy/data      #生成的txt文件存储位置
 
echo "Create train.txt..."
rm -rf $MY/train.txt          #先把文件中原有的同名文件删除
# find $DATA/train -name 15001*.jpg 是在文件加下找到所有前几位名为15001的图片
# cut -d '/' -f4-5   是以'/'为分界符,找到第四至五段的内容截取下来
# sed "s/$/ 0/"     在截取的文件名后面加一个空格和一个标签0
# MY/train.txt    存储到train.txt中
find $DATA/train -name 15001*.jpg | cut -d '/' -f4-5 | sed "s/$/ 0/">>$MY/train.txt    
find $DATA/train -name 15059*.jpg | cut -d '/' -f4-5 | sed "s/$/ 1/">>$MY/train.txt
find $DATA/train -name 62047*.jpg | cut -d '/' -f4-5 | sed "s/$/ 2/">>$MY/train.txt
find $DATA/train -name 68021*.jpg | cut -d '/' -f4-5 | sed "s/$/ 3/">>$MY/train.txt
find $DATA/train -name 73018*.jpg | cut -d '/' -f4-5 | sed "s/$/ 4/">>$MY/train.txt
find $DATA/train -name 73063*.jpg | cut -d '/' -f4-5 | sed "s/$/ 5/">>$MY/train.txt
find $DATA/train -name 80012*.jpg | cut -d '/' -f4-5 | sed "s/$/ 6/">>$MY/train.txt
find $DATA/train -name 92002*.jpg | cut -d '/' -f4-5 | sed "s/$/ 7/">>$MY/train.txt
find $DATA/train -name 92017*.jpg | cut -d '/' -f4-5 | sed "s/$/ 8/">>$MY/train.txt
find $DATA/train -name 95005*.jpg | cut -d '/' -f4-5 | sed "s/$/ 9/">>$MY/train.txt
  
echo "Create test.txt..."
rm -rf $MY/val.txt
 
find $DATA/val -name 15001*.jpg | cut -d '/' -f4-5 | sed "s/$/ 0/">>$MY/val.txt
find $DATA/val -name 15059*.jpg | cut -d '/' -f4-5 | sed "s/$/ 1/">>$MY/val.txt
find $DATA/val -name 62047*.jpg | cut -d '/' -f4-5 | sed "s/$/ 2/">>$MY/val.txt
find $DATA/val -name 68021*.jpg | cut -d '/' -f4-5 | sed "s/$/ 3/">>$MY/val.txt
find $DATA/val -name 73018*.jpg | cut -d '/' -f4-5 | sed "s/$/ 4/">>$MY/val.txt
find $DATA/val -name 73063*.jpg | cut -d '/' -f4-5 | sed "s/$/ 5/">>$MY/val.txt
find $DATA/val -name 80012*.jpg | cut -d '/' -f4-5 | sed "s/$/ 6/">>$MY/val.txt
find $DATA/val -name 92002*.jpg | cut -d '/' -f4-5 | sed "s/$/ 7/">>$MY/val.txt
find $DATA/val -name 92017*.jpg | cut -d '/' -f4-5 | sed "s/$/ 8/">>$MY/val.txt
find $DATA/val -name 95005*.jpg | cut -d '/' -f4-5 | sed "s/$/ 9/">>$MY/val.txt
 
echo "All done"

执行该文件,注意在caffe文件夹下面执行 ,因为前面DATA变量 使用的路径是caffe下的相对路径 examples/myfile_tostudy/data
如果执行不了,给该文件添加执行权限
chmod a+x examples/myfile_tostudy/create_filelist.sh

执行之后就会得到 train.txtval.txt
image-20200618172454076

转化为db文件

接着把.txt文件转换成caffe能识别的db文件。还是在myfile_tostudy下建立该文件,文件名为create_lmdb.sh。内容如下:

#!/usr/bin/env sh
# lmdb文件存储的位置
MY=examples/myfile_tostudy
 
TRAIN_DATA_ROOT=/home/hzq/Caffe_stu_dir/caffe/examples/myfile_tostudy/data/
VAL_DATA_ROOT=/home/hzq/Caffe_stu_dir/caffe/examples/myfile_tostudy/data/
 
echo "Create train lmdb.."
rm -rf $MY/img_train_lmdb
# 这句是利用caffe自带的图片处理工具对图片进行处理
# 这里因为我未对caffe源码进行编译,所以不存在build/tools/ 目录,直接使用即可(安装时自动写入了PATH)
# convert_imageset命令行使用格式 convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME     
# FLAGS是处理的参数,像图片的大小,随机抽取还是怎么样。
# ROOTFOLDER是图片存放的绝对目录。
# LISTFILE是文件列表清单。
# DB_NAME是生成的文件存放的位置。
convert_imageset \
--resize_height=32 \
--resize_width=32 \
--shuffle \
$TRAIN_DATA_ROOT \
$MY/data/train.txt \
$MY/img_train_lmdb
 
echo "Create test lmdb.."
rm -rf $MY/img_val_lmdb
convert_imageset \
--resize_height=32 \
--resize_width=32 \
--shuffle \
$VAL_DATA_ROOT \
$MY/data/val.txt \
$MY/img_val_lmdb  
 
echo "All Done.."

同理,执行该文件
如果不能执行使用 chmod a+x增加执行权限

执行之后myfile_tostudy文件夹下生成img_val_lmdb和img_train_lmdb文件,
里面就是我们想要的caffe能识别的db文件

计算均值

计算均值的原因是保证所有特征都在0附近

在大多数情况下,我们并不关心所输入图像的整体明亮程度

比如对象识别任务中,图像的整体明亮程度,并不会影响图像中存在的是什么物体,我们对图像的平均亮度感兴趣,所以可以减去这个值来进行均值规整化。

创建的文件名为,create_meanfile.sh 代码如下:

EXAMPLE=examples/myfile_tostudy
DATA=examples/myfile_tostudy/

# compute_image_mean 是caffe自带的工具,
# 如果没加入到PATH里面需要自己编译caffe源码,然后使用build/tools/compute_image_mean 调用
# $EXAMPLE/img_train_lmdb要处理的文件的位置,$DATA/mean1.binaryproto文件的存储位置
compute_image_mean $EXAMPLE/img_train_lmdb $DATA/mean1.binaryproto
 
echo "Done."

2.构建网络

myfile_tostudy 下建立一个.prototxt文件,来搭建网络。文件名为:myfile_tostudy_train_test.prototxt 构建的网络内容如下:

数据层及其参数 参考

1、数据来自于数据库(如LevelDB和LMDB)
name: 表示该层的名称,可随意取

type: 层类型,如果是Data,表示数据来源于LevelDB或LMDB。根据数据的来源不同,数据层的类型也不同(后面会详细阐述)。一般在练习的时候,我们都是采 用的LevelDB或LMDB数据,因此层类型设置为Data。

top或bottom: 每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个 top或多个bottom,表示有多个blobs数据的输入和输出。

data 与 label: 在数据层中,至少有一个命名为data的top。如果有第二个top,一般命名为label。 这种(data,label)配对是分类模型所必需的。

include: 一般训练的时候和测试的时候,模型的层是不一样的。该层(layer)是属于训练阶段的层,还是属于测试阶段的层,需要用include来指定。如果没有include参数,则表示该层既在训练模型中,又在测试模型中。

Transformations: 数据的预处理,可以将数据变换到定义的范围内。如设置scale为0.00390625,实际上就是1/255, 即将输入数据由0-255归一化到0-1之间

name: "myfile_tostudy"
# 定义网络结构
layer {
  name: "data" 							# 网络层的名字
  type: "Data"							# 网络层类型,数据层
  top: "data"							# 这一层产生两个blob输出 一个是数据
  top: "label"							# 一个是标签
  include {
    phase: TRAIN						# TRAIN:=用于训练,TEST:=用于测试
  }
  # caffe中transform_param有四个选项:scale,mean,mirror,crop_size
  # 执行顺序是mean(file)、mean(value)、crop、mirror、scale
  transform_param{
  mean_file:"examples/myfile_tostudy/mean1.binaryproto"     # 用一个配置文件来进行均值操作
 }
  data_param {
    source: "examples/myfile_tostudy/img_train_lmdb"		# 包含数据库的目录名称
    batch_size: 50										 # 每次处理的数据个数
    backend: LMDB										 # 指定数据库格式,LMDB/LevelDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param{
  mean_file:"examples/myfile_tostudy/mean1.binaryproto"
 }
  data_param {
    source: "examples/myfile_tostudy/img_val_lmdb"
    batch_size: 50
    backend: LMDB
  }
}
layer {
  name: "conv1"										
  type: "Convolution"							# 卷积层
  bottom: "data"								# 上一层的输出作为输入
  top: "conv1"									# 输出
  param {
    lr_mult: 1		#卷积层参数w的学习率
  }
  param {			#卷积层参数b的学习率
    lr_mult: 2
  }
  convolution_param {
    num_output: 32								# 卷积层输出的feature map数量 
    pad:2									    # 卷积层的填充大小
    kernel_size: 5								# 卷积层的大小
    stride: 1								    # 进行卷积的步长
    weight_filler {								# 参数w的初始话策略
      type:"gaussian"
      std:0.0001
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
  name: "pool1"
  type: "Pooling"								# 池化层,即下采样层
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX									# 最大值池化,还有AVE均值池化
    kernel_size: 3
    stride: 2
  }
}
layer {
   name:"relu1"
   type:"ReLU"									# 激活函数层
   bottom:"pool1"
   top:"pool1"
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 32
    pad:2
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "gaussian"
      std:0.01
    }
    bias_filler {
      type: "constant"
    }
  }
}
layer {
    name:"relu2"
    type:"ReLU"
    bottom:"conv2"
    top:"conv2"
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: AVE
    kernel_size: 3
    stride: 2
  }
}
layer {
   name:"conv3"
   type:"Convolution"
   bottom:"pool2"
   top:"conv3"
   param{
     lr_mult:1
  }
   param{
     lr_mult:2
  }
  convolution_param {
     num_output:64
     pad:2
     kernel_size:5
     stride:1
     weight_filler {
       type:"gaussian"
       std:0.01
   }
    bias_filler{
      type:"constant"
    }
  }
}
layer {
  name:"relu3"
  type:"ReLU"
  bottom:"conv3"
  top:"conv3"
}
layer {
  name:"pool3"
  type:"Pooling"
  bottom:"conv3"
  top:"pool3"
  pooling_param {
    pool:AVE
    kernel_size:3
    stride:2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"						# 全连接层
  bottom: "pool3"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 64
    weight_filler {
      type: "gaussian"
      std:0.1
    }
    bias_filler {
      type: "constant"
    }
  }
}
 
layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 10
    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"
 
}

3. 编写网络求解文件

也是建立一个.prototxt文件。文件名为myfile_tostudy_solver.prototxt

solver这个文件主要存放模型训练所用到的一些超参数:

  • net := 指定待训练模型结构文件,即train_val.prototxt
  • test_interval :=
  • test_initialization := 指定是否进行初始测试,即模型未进行训练时的测试
  • test_iteration := 指定测试时进行的迭代次数
  • base_lr :=
  • lr_policy := 学习率变更策略,这里有介绍,可供参考
  • gamma := 学习率变更策略需要用到的参数
  • power := 同上
  • stepsize := 学习率变更策略Step的变更步长(固定步长)
  • stepvalue := 学习率变更策略Multistep的变更步长(可变步长)
  • max_iter :=
  • momentum := 动量,这是优化策略(Adam, SGD, … )用到的参数
  • momentum2 := 优化策略Adam用到的参数
  • weight_decay := 权重衰减率
  • clip_gradients := 固定梯度范围
  • display := 每隔几次迭代显示一次结果
  • snapshot := 快照,每隔几次保存一次模型参数
  • snapshot_prefix := 保存模型文件的前缀,可以是路径
  • solver_mode :=

用户根据自己的情况进行相应设置,黑体参数为必须指定的,其余参数为可选(根据情况选择)

内容如下:

# 选择网络结构文件
net: "examples/myfile_tostudy/myfile_tostudy_train_test.prototxt"

test_iter: 2					# 在测试的时候,需要迭代的次数
test_interval: 50				# 测试间隔,即每隔多少次迭代进行一次测试
base_lr: 0.001					# 指定基本学习率
lr_policy: "step"				 # 学习率变更策略
gamma: 0.1						# 学习率变更策略需要用到的参数
stepsize:400					# 学习率变更策略Step的变更步长(固定步长)
momentum:0.9					# 动量,这是优化策略(Adam, SGD, … )用到的参数
weight_decay:0.004				 # 权重衰减率
display:10						# 每隔几次迭代显示一次结果
max_iter: 2000					# 模型训练的最大迭代次数
snapshot: 2000					# 快照,每隔几次保存一次模型参数
snapshot_prefix: "examples/myfile_tostudy" # 保存模型文件的前缀,可以是路径
solver_mode: CPU				# 指定训练模式,即GPU/CPU

4.训练

执行 caffe train -solver examples/myfile_tostudy/myfile_tostudy_solver.prototxt

image-20200618182847715

耐心等待之后
image-20200618182928817

5.测试

将以下两种图片放入imgs文件夹 用来测试模型

更名为: test_xiangzi01

更名为:test_xiezi01

建立deploy.prototex文件

myfile_tostudy文件夹新增文件deploy.prototxt

name: "myfile4"
layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param{shape:{dim:1 dim:3 dim:32 dim:32}}
  
}

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 32
    pad:2
    kernel_size: 5
    stride: 1
  }
}
layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 3
    stride: 2
  }
}
layer {
   name:"relu1"
   type:"ReLU"
   bottom:"pool1"
   top:"pool1"
}
layer {
  name: "conv2"
  type: "Convolution"
  bottom: "pool1"
  top: "conv2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 32
    pad:2
    kernel_size: 5
    stride: 1
  }
}
layer {
    name:"relu2"
    type:"ReLU"
    bottom:"conv2"
    top:"conv2"
}
layer {
  name: "pool2"
  type: "Pooling"
  bottom: "conv2"
  top: "pool2"
  pooling_param {
    pool: AVE
    kernel_size: 3
    stride: 2
  }
}
layer {
   name:"conv3"
   type:"Convolution"
   bottom:"pool2"
   top:"conv3"
   param{
     lr_mult:1
  }
   param{
     lr_mult:2
  }
  convolution_param {
     num_output:64
     pad:2
     kernel_size:5
     stride:1
  }
}
layer {
  name:"relu3"
  type:"ReLU"
  bottom:"conv3"
  top:"conv3"
}
layer {
  name:"pool3"
  type:"Pooling"
  bottom:"conv3"
  top:"pool3"
  pooling_param {
    pool:AVE
    kernel_size:3
    stride:2
  }
}
layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool3"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 64
  }
}

layer {
  name: "ip2"
  type: "InnerProduct"
  bottom: "ip1"
  top: "ip2"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 10
  }
}

layer {
  name: "prob"
  type: "Softmax"
  bottom: "ip2"
  top: "prob"
}
建立 synset.txt

myfile_tostudy文件夹中新建文件synset_work.txt,内容如下:

biao
fajia
kuzi
xiangzi
yizi
dianshi
suannai
xiangshui
hufupin
xiezi

myfile_tostudy文件夹下新建demo.sh。内容如下:

classification examples/myfile_tostudy/deploy.prototxt examples/myfile_tostudy_iter_2000.caffemodel examples/myfile_tostudy/mean1.binaryproto examples/myfile_tostudy/synset_work.txt examples/myfile_tostudy/imgs/111.jpg

上述要注意各个路径、文件的命名
否则会报错

运行结果如下
image-20200618214014936

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值