Caffe中对MNIST执行train操作执行流程解析
之前在?http://blog.csdn.net/fengbingchun/article/details/49849225?中簡(jiǎn)單介紹過使用Caffe train MNIST的文章,當(dāng)時(shí)只是仿照caffe中的example實(shí)現(xiàn)了下,下面說(shuō)一下執(zhí)行流程,并精簡(jiǎn)代碼到僅有10余行:
1.????????先注冊(cè)所有層,執(zhí)行l(wèi)ayer_factory.hpp中類LayerRegisterer的構(gòu)造函數(shù),類LayerRegistry的AddCreator和Registry靜態(tài)函數(shù);關(guān)于Caffe中Layer的注冊(cè)可以參考?http://blog.csdn.net/fengbingchun/article/details/54310956
2.????????指定執(zhí)行mode是采用CPU還是GPU;
3.????????構(gòu)造SolverParameter類對(duì)象,存放Solver 參數(shù)信息;
4.????????調(diào)用ReadProtoFromTextFile函數(shù)解析Solver文本文件(lenet_solver.prototxt),其文件內(nèi)的各字段名需要在caffe.proto的message SolverParameter中存在,否則會(huì)解析不成功,其文件內(nèi)容如下:
# The train/test net protocol buffer definition
# Proto filename for the train net, possibly combined with one or more test nets.
# train net 和 test net在同一個(gè)文件中
net: "E:/GitCode/Caffe_Test/test_data/model/mnist/lenet_train_test.prototxt"
# Solver type,采用哪種Solver優(yōu)化方法
solver_type: SGD
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
# The number of iterations for each test net.
# batch size * test iter = test images,即 100 * 100 = 10000
test_iter: 100
# Carry out testing every 500 training iterations.
# The number of iterations between two testing phases.
# 指定執(zhí)行多少次訓(xùn)練網(wǎng)絡(luò)執(zhí)行一次測(cè)試網(wǎng)絡(luò)
test_interval: 500
# The base learning rate, momentum and the weight decay of the network.
# The base learning rate, 基礎(chǔ)學(xué)習(xí)率
base_lr: 0.01
# The momentum value, 動(dòng)量
momentum: 0.9
# The weight decay, 權(quán)值衰減
weight_decay: 0.0005
# The learning rate policy, 學(xué)習(xí)策略
lr_policy: "inv"
# The parameter to compute the learning rate,學(xué)習(xí)率計(jì)算參數(shù)
gamma: 0.0001
# The parameter to compute the learning rate,學(xué)習(xí)率計(jì)算參數(shù)
power: 0.75
# Display every 100 iterations
# the number of iterations between displaying info.
# If display = 0, no info will be displayed.
# 指定訓(xùn)練多少次顯示一次結(jié)果信息,如loss值等
display: 100
# The maximum number of iterations,最多執(zhí)行訓(xùn)練次數(shù)
max_iter: 10000
# snapshot intermediate results,執(zhí)行多少次訓(xùn)練保存一次中間結(jié)果
snapshot: 5000
# The prefix for the snapshot, file save position,中間結(jié)果保存位置
snapshot_prefix: "E:/GitCode/Caffe_Test/test_data/model/mnist/lenet"
5.????????將MNIST原始數(shù)據(jù)轉(zhuǎn)換成LMDB數(shù)據(jù)庫(kù)格式,在train和test時(shí)會(huì)使用;
6.????????根據(jù)Solver type,New一個(gè)SGDSolver類對(duì)象并進(jìn)行初始化操作:
(1)、調(diào)用GetSolver函數(shù),new一個(gè)SGDSolver了對(duì)象;
(2)、調(diào)用Solver類的Init函數(shù);
(3)、調(diào)用SolverParameter的DebugString函數(shù)打印解析后的lenet_solver.prototxt信息,輸出結(jié)果如下:
test_iter: 100
test_interval: 500
base_lr: 0.01
display: 100
max_iter: 10000
lr_policy: "inv"
gamma: 0.0001
power: 0.75
momentum: 0.9
weight_decay: 0.0005
snapshot: 5000
snapshot_prefix: "E:/GitCode/Caffe_Test/test_data/model/mnist/lenet"
net: "E:/GitCode/Caffe_Test/test_data/model/mnist/lenet_train_test.prototxt"
solver_type: SGD
(4)、調(diào)用ReadNetParamsFromTextFileOrDie函數(shù),解析lenet_train_test.prototxt文件(此文件中的各個(gè)layer段的位置不是固定的,每個(gè)layer內(nèi)的各個(gè)段位置也不是固定的,它們的位置無(wú)關(guān)緊要,只是一般按照流程順序從上到下排列),各個(gè)字段的說(shuō)明如下:
name: "LeNet" # net名
layer { # memory required: (50175+64)*4=200960name: "mnist" # layer名字type: "Data" # layer類型,數(shù)據(jù)層,Data enters Caffe through data layers,read data from LEVELDB or LMDBtop: "data" # top名字, shape: 64 1 28 28 (50175)top: "label" # top名字, shape: 64 (64)include { # 指定何時(shí)將此layer mnist包含到網(wǎng)絡(luò)中phase: TRAIN # 訓(xùn)練階段會(huì)將此layer mnist包含到網(wǎng)絡(luò)中}transform_param { # 圖像預(yù)處理scale: 0.00390625 # 對(duì)圖像像素值進(jìn)行scale操作,范圍[0, 1)}data_param { # data parametersource: "E:/GitCode/Caffe_Test/test_data/MNIST/train" # 數(shù)據(jù)存放路徑batch_size: 64 # 指定一次處理圖像的數(shù)量backend: LMDB # 數(shù)據(jù)存儲(chǔ)方式}
}
layer { # memory required: (78400+100)*4=314000name: "mnist" # layer名字type: "Data" # layer類型,數(shù)據(jù)層,Data enters Caffe through data layers,read data from LEVELDB or LMDBtop: "data" # top名字, shape: 100 1 28 28 (78400)top: "label" # top名字, shape: 100 (100)include { # 指定何時(shí)將此layer mnist包含到網(wǎng)絡(luò)中phase: TEST # 測(cè)試階段會(huì)將此layer mnist包含到此網(wǎng)絡(luò)中}transform_param { # 圖像預(yù)處理scale: 0.00390625 # 對(duì)圖像像素值進(jìn)行scale操作,范圍[0, 1)}data_param { # data parametersource: "E:/GitCode/Caffe_Test/test_data/MNIST/test" # 數(shù)據(jù)存放路徑batch_size: 100 # 指定一次處理圖像的數(shù)量backend: LMDB # 數(shù)據(jù)存儲(chǔ)方式}
}
# test 階段會(huì)創(chuàng)建一個(gè)layer: label_mnist_1_split,如下:
# layer_factory.hpp:75] Creating layer label_mnist_1_split
# net.cpp:110] Creating Layer label_mnist_1_split
# net.cpp:476] label_mnist_1_split <- label
# net.cpp:432] label_mnist_1_split -> label_mnist_1_split_0
# net.cpp:432] label_mnist_1_split -> label_mnist_1_split_1
# net.cpp:155] Setting up label_mnist_1_split
# net.cpp:163] Top shape: 100 (100)
# net.cpp:163] Top shape: 100 (100)
layer { # memory required: 737280*4=2949120/1152000*4=4608000name: "conv1" # layer名字type: "Convolution" # layer類型,卷積層bottom: "data" # bottom名字top: "conv1" # top名字, shape: 64 20 24 24 (737280)/100 20 24 24 (1152000)param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 1 # The multiplier on the global learning rate}param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 2 # The multiplier on the global learning rate}convolution_param { # convolution parameternum_output: 20 # 輸出特征圖(feature map)數(shù)量kernel_size: 5 # 卷積核大小(卷積核其實(shí)就是權(quán)值)stride: 1 # 滑動(dòng)步長(zhǎng)weight_filler { # The filler for the weighttype: "xavier" # 權(quán)值使用xavier濾波}bias_filler { # The filler for the biastype: "constant" # 偏置使用常量濾波}}
}
layer { # memory required: 184320*4=737280/288000*4=1152000name: "pool1" # layer名字type: "Pooling" # layer類型,Pooling層bottom: "conv1" # bottom名字top: "pool1" # top名字, shape: 64 20 12 12 (184320)/ 100 20 12 12 (288000)pooling_param { # pooling parameter,pooling層參數(shù)pool: MAX # pooling方法:最大值采樣kernel_size: 2 # 濾波器大小stride: 2 # 滑動(dòng)步長(zhǎng)}
}
layer { # memory required: 204800*4=819200/320000*4=1280000name: "conv2" # layer名字type: "Convolution" # layer類型,卷積層bottom: "pool1" # bottom名字top: "conv2" # top名字, shape: 64 50 8 8 (204800)/ 100 50 8 8 (320000)param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 1 # The multiplier on the global learning rate}param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 2 # The multiplier on the global learning rate}convolution_param { # convolution parameter,卷基層參數(shù)num_output: 50 # 輸出特征圖(feature map)數(shù)量kernel_size: 5 # 卷積核大小(卷積核其實(shí)就是權(quán)值)stride: 1 # 滑動(dòng)步長(zhǎng)weight_filler { # The filler for the weighttype: "xavier" # 權(quán)值使用xavier濾波}bias_filler { # The filler for the biastype: "constant" # 偏置使用常量濾波}}
}
layer { # memory required: 51200*4=204800/80000*4=320000name: "pool2" # layer名字type: "Pooling" # layer類型,Pooling層bottom: "conv2" # bottom名字top: "pool2" # top名字, shape: 64 50 4 4 (51200)/ 100 50 4 4 (80000)pooling_param { # pooling parameter,卷積層參數(shù)pool: MAX # pooling方法:最大值采樣kernel_size: 2 # 濾波器大小stride: 2 # 滑動(dòng)步長(zhǎng)}
}
layer { # memory required: 32000*4=128000/50000*4=200000name: "ip1" # layer名字type: "InnerProduct" # layer類型,全連接層bottom: "pool2" # bottom名字top: "ip1" # top名字, shape: 64 500 (32000)/ 100 500 (50000)param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 1 # The multiplier on the global learning rate}param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 2 # The multiplier on the global learning rate}inner_product_param { # 全連接層參數(shù)num_output: 500 # 輸出特征圖(feature map)數(shù)量weight_filler { # The filler for the weighttype: "xavier" # 權(quán)值使用xavier濾波}bias_filler { # The filler for the biastype: "constant" # 偏置使用常量濾波}}
}
# ReLU: Given an input value x, The ReLU layer computes the output as x if x > 0 and
# negative_slope * x if x <= 0. When the negative slope parameter is not set,
# it is equivalent to the standard ReLU function of taking max(x, 0).
# It also supports in-place computation, meaning that the bottom and
# the top blob could be the same to preserve memory consumption
layer { # memory required: 32000*4=128000/50000*4=200000name: "relu1" # layer名字type: "ReLU" # layer類型bottom: "ip1" # bottom名字top: "ip1" # top名字 (in-place), shape: 64 500 (32000)/ 100 500 (50000)
}
layer { # memory required: 640*4=2560/1000*4=4000name: "ip2" # layer名字type: "InnerProduct" # layer類型,全連接層bottom: "ip1" # bottom名字top: "ip2" # top名字, shape: 64 10 (640)/ 100 10 (1000)param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 1 # The multiplier on the global learning rate}param { # 訓(xùn)練時(shí)用到的參數(shù)lr_mult: 2 # The multiplier on the global learning rate}inner_product_param { # 全連接層參數(shù)num_output: 10 # 輸出特征圖(feature map)數(shù)量weight_filler { # The filler for the weighttype: "xavier" # 權(quán)值使用xavier濾波}bias_filler { # The filler for the biastype: "constant" # 偏置使用常量濾波}}
}
# test階段會(huì)創(chuàng)建一個(gè)layer: ip2_ip2_0_split,如下:
# layer_factory.hpp:75] Creating layer ip2_ip2_0_split
# net.cpp:110] Creating Layer ip2_ip2_0_split
# net.cpp:476] ip2_ip2_0_split <- ip2
# net.cpp:432] ip2_ip2_0_split -> ip2_ip2_0_split_0
# net.cpp:432] ip2_ip2_0_split -> ip2_ip2_0_split_1
# net.cpp:155] Setting up ip2_ip2_0_split
# net.cpp:163] Top shape: 100 10 (1000)
# net.cpp:163] Top shape: 100 10 (1000)
layer { # memory required: 1*4=4name: "accuracy" # layer名字type: "Accuracy" # layer類型,計(jì)算輸出準(zhǔn)確率bottom: "ip2" # bottom名字bottom: "label" # bottom名字top: "accuracy" # top名字, shape: (1)include { # 指定何時(shí)將此layer accuracy包含到網(wǎng)絡(luò)中phase: TEST # 測(cè)試階段會(huì)將此layer accuracy包含到此網(wǎng)絡(luò)中}
}
# SoftmaxWithLoss: Computes the multinomial logistic loss for a one-of-many
# classification task, passing real-valued predictions through a
# softmax to get a probability distribution over classes.
layer { # memory required: 1*4=4/1*4=4name: "loss" # layer名字type: "SoftmaxWithLoss" # layer類型bottom: "ip2" # bottom名字bottom: "label" # bottom名字top: "loss" # top名字, shape: (1)/ (1)
}# 在訓(xùn)練網(wǎng)絡(luò)中,占用總內(nèi)存大小為:200960+2949120+737280+819200+204800+128000+128000+2560+4=5169924
# 在測(cè)試網(wǎng)絡(luò)中,占用總內(nèi)存大小為:314000+(100+100)*4+4608000+1152000+1280000+320000+200000+200000+4000+(1000+1000)*4+4+4=8086808
lenet_train_test.prototxt可視化結(jié)果如下圖(
http://ethereon.github.io/netscope/quickstart.html):此視圖給出的是train階段時(shí)的流程圖,不包括測(cè)試階段:
(5)、創(chuàng)建訓(xùn)練網(wǎng)絡(luò)Net對(duì)象,并調(diào)用Net類的InitTrainNet函數(shù)構(gòu)建訓(xùn)練網(wǎng)絡(luò),訓(xùn)練網(wǎng)絡(luò)輸出結(jié)果如下:
name: "LeNet"
state {phase: TRAIN
}
layer {name: "mnist"type: "Data"top: "data"top: "label"include {phase: TRAIN}transform_param {scale: 0.00390625}data_param {source: "E:/GitCode/Caffe_Test/test_data/MNIST/train"batch_size: 64backend: LMDB}
}
layer {name: "conv1"type: "Convolution"bottom: "data"top: "conv1"param {lr_mult: 1}param {lr_mult: 2}convolution_param {num_output: 20kernel_size: 5stride: 1weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "pool1"type: "Pooling"bottom: "conv1"top: "pool1"pooling_param {pool: MAXkernel_size: 2stride: 2}
}
layer {name: "conv2"type: "Convolution"bottom: "pool1"top: "conv2"param {lr_mult: 1}param {lr_mult: 2}convolution_param {num_output: 50kernel_size: 5stride: 1weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "pool2"type: "Pooling"bottom: "conv2"top: "pool2"pooling_param {pool: MAXkernel_size: 2stride: 2}
}
layer {name: "ip1"type: "InnerProduct"bottom: "pool2"top: "ip1"param {lr_mult: 1}param {lr_mult: 2}inner_product_param {num_output: 500weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "relu1"type: "ReLU"bottom: "ip1"top: "ip1"
}
layer {name: "ip2"type: "InnerProduct"bottom: "ip1"top: "ip2"param {lr_mult: 1}param {lr_mult: 2}inner_product_param {num_output: 10weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "loss"type: "SoftmaxWithLoss"bottom: "ip2"bottom: "label"top: "loss"
}
(6)、創(chuàng)建測(cè)試網(wǎng)絡(luò)Net對(duì)象,并調(diào)用Net類的InitTestNets函數(shù)構(gòu)建測(cè)試網(wǎng)絡(luò),測(cè)試網(wǎng)絡(luò)輸出結(jié)果如下:
name: "LeNet"
state {phase: TEST
}
layer {name: "mnist"type: "Data"top: "data"top: "label"include {phase: TEST}transform_param {scale: 0.00390625}data_param {source: "E:/GitCode/Caffe_Test/test_data/MNIST/test"batch_size: 100backend: LMDB}
}
layer {name: "conv1"type: "Convolution"bottom: "data"top: "conv1"param {lr_mult: 1}param {lr_mult: 2}convolution_param {num_output: 20kernel_size: 5stride: 1weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "pool1"type: "Pooling"bottom: "conv1"top: "pool1"pooling_param {pool: MAXkernel_size: 2stride: 2}
}
layer {name: "conv2"type: "Convolution"bottom: "pool1"top: "conv2"param {lr_mult: 1}param {lr_mult: 2}convolution_param {num_output: 50kernel_size: 5stride: 1weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "pool2"type: "Pooling"bottom: "conv2"top: "pool2"pooling_param {pool: MAXkernel_size: 2stride: 2}
}
layer {name: "ip1"type: "InnerProduct"bottom: "pool2"top: "ip1"param {lr_mult: 1}param {lr_mult: 2}inner_product_param {num_output: 500weight_filler {type: "xavier"}bias_filler {type: "constant"}}
}
layer {name: "relu1"type: "ReLU"bottom: "ip1"top: "ip1"
}
layer {name: "ip2"type: "InnerProduct"bottom: "ip1"top: "ip2"param {lr_mult: 1}param {lr_mult: 2}inner_product_param {num_output: 10weight_filler {type: "xavier"}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"
}
(7)、調(diào)用SGDSolver類的PreSolve函數(shù)。
7.????????調(diào)用Solver類的Solve函數(shù)開始進(jìn)行訓(xùn)練和測(cè)試:
(1)、當(dāng)訓(xùn)練次數(shù)是500的倍數(shù)時(shí)(在lenet_solver.prototxt中設(shè)置test_interval為500),執(zhí)行一次測(cè)試網(wǎng)絡(luò)的Forward計(jì)算,循環(huán)100次(在lenet_solver.prototxt中設(shè)置test_iter為100,在lenet_train_test.prototxt文件中,測(cè)試階段batch size為100,這樣100*100=10000正好覆蓋到所有的測(cè)試圖像),測(cè)試網(wǎng)絡(luò)最終會(huì)有兩個(gè)結(jié)果輸出,一個(gè)是accuracy,一個(gè)是loss;
(2)、執(zhí)行一次訓(xùn)練網(wǎng)絡(luò)的ForwardBackward計(jì)算,訓(xùn)練網(wǎng)絡(luò)最終會(huì)有一個(gè)結(jié)果輸出即loss;
(3)、更新訓(xùn)練網(wǎng)絡(luò)的權(quán)值和偏置;
(4)、每訓(xùn)練5000次(在lenet_solver.prototxt中設(shè)置snapshot為5000)保存一次結(jié)果,包括.caffemodel和.caffestate;
(5)、按照以上(1)、(2)、(3)、(4)中的步驟,循環(huán)執(zhí)行10000次(在lenet_solver.prototxt中設(shè)置max_iter為10000)。
精簡(jiǎn)后的mnist train代碼如下:
#include "funset.hpp"
#include "common.hpp"int mnist_train()
{caffe::Caffe::set_mode(caffe::Caffe::CPU);const std::string filename{ "E:/GitCode/Caffe_Test/test_data/model/mnist/lenet_solver.prototxt" };caffe::SolverParameter solver_param;if (!caffe::ReadProtoFromTextFile(filename.c_str(), &solver_param)) {fprintf(stderr, "parse solver.prototxt fail\n");return -1;}mnist_convert(); // convert MNIST to LMDBboost::shared_ptr<caffe::Solver<float> > solver(caffe::GetSolver<float>(solver_param));solver->Solve();fprintf(stderr, "train finish\n");return 0;
}
train最終結(jié)果如下:
GitHub:https://github.com/fengbingchun/Caffe_Test
總結(jié)
以上是生活随笔為你收集整理的Caffe中对MNIST执行train操作执行流程解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中try/catch/throw的
- 下一篇: 使用Caffe进行手写数字识别执行流程解