最近由於項目需要用到caffe,學習了下caffe的用法,在使用過程中也是遇到了些問題,通過上網搜索和問老師的方法解決了,在此記錄下過程,方便以后查看,也希望能為和我一樣的新手們提供幫助。
順帶附上老師寫的教程
安裝Caffe並運行Mnist例程
我主要參考了這篇教程: Mac極簡安裝Caffe並訓練MNIST。然后進行了examples文件夾里的Mnist的訓練,期間並沒有碰到什么問題。
將圖片轉換為LMDB文件
Mnist中已經給出了現成的LMDB數據文件,在實際項目中,需要我們將圖片文件轉換為LMDB文件。可以參考下examples里的imagenet,里面的readme寫了完整的過程,也可以參考上面貼的教程。在這里就不復述了,主要說下注意點:
轉換文件只要參考imagenet的create_imagenet.sh並更改相應路徑即可,如下:
set -e
#生成的lmdb文件夾位置
EXAMPLE=examples/myMnistTest
#train.txt和val.txt位置
DATA=examples/myMnistTest/MNIST_Dataset
#tools文件夾位置,寫相對位置的話要在caffe根目錄運行
TOOLS=build/tools
#train圖片位置
TRAIN_DATA_ROOT=/Users/messier/caffe/examples/myMnistTest/MNIST_Dataset/train_images/
#val圖片位置
VAL_DATA_ROOT=/Users/messier/caffe/examples/myMnistTest/MNIST_Dataset/train_images/
# Set RESIZE=true to resize the images to 256x256. Leave as false if images have
# already been resized using another tool.
#這邊寫成false,我寫了true結果生成了10個多GB的lmdb...不過訓練出來的模型還是能用的
RESIZE=true
if $RESIZE; then
RESIZE_HEIGHT=256
RESIZE_WIDTH=256
else
RESIZE_HEIGHT=0
RESIZE_WIDTH=0
開始訓練
這一步之前可以選擇進行計算圖像均值的操作。然后去mnist文件夾中把之前用到過的prototxt拿過來,更改路徑,按之前的操作進行即可。
要注意的是,沒進行過均值操作的話,要把所有的mean_pixel注釋掉。
在opencv中調用訓練好的模型
opencv3.3中將dnn模塊從contrib中提到了主倉庫中,可以直接調用caffe訓練好的模型,且不需要任意依賴。
這里我主要參考了opencv中一個用caffe模型識別航空飛機的sample。
稍加修改即可。
首先要把幾個文件的路徑改下,如下:
String modelTxt = "lenet_deploy.prototxt";
String modelBin = "_iter_6714.caffemodel";
String imageFile = (argc > 1) ? argv[1] : "3_00715.jpg";
需要注意的是,當時訓練用的模型文件不能在這里直接用了,要把輸入和輸出改下,如下:
- 更改輸入
原來:
name: "LeNet"
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "./train_lmdb"
batch_size: 64
backend: LMDB
}
}
更改為:
name: "LeNet"
input: "data"
input_dim: 1 #每次輸入圖片數
input_dim: 1 #channels
input_dim: 256 #width
input_dim: 256 #height
2.更改輸出:
原來:
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}
更改為:
layer {
name: "prob"
type: "Softmax"
bottom: "ip2"
top: "prob"
}
在這里推薦下老師告訴我的caffe網絡可視化工具Netscope
看下更改前后的網絡:
最后程序運行結果如下:
12.12更新:程序源碼已經上傳了,直接用cmake構建工程即可。
順帶再略微解析下程序的流程:
1、 載入模型文件
readNetFromCaffe(modelTxt, modelBin);
2、 讀取圖片,轉換為blob的數據格式。
Mat inputBlob = blobFromImage(img, 0.00390625f, Size(256, 256), Scalar(), false); //Convert Mat to batch of images
看下這個函數,第一個參數是圖片,第二個參數是訓練時的特征縮放系數,這里是1/256,第三個參數是blob對應的圖片大小,之前說過,我在訓練時誤把圖像縮放到了256* 256,這里輸入圖像大小還是28 * 28的,但作為輸入要縮放到256*256,第四個參數是各通道均值,我沒作均值處理所以給默認值,第六個參數的意思是是否交換R B通道,這里是單通道圖片所以不交換。
3、 前向傳播,計算各個label的prob,結果用一個10維向量保存。
Mat prob;
cv::TickMeter t;
for (int i = 0; i < 10; i++)
{
CV_TRACE_REGION("forward");
net.setInput(inputBlob, "data"); //set the network input
t.start();
prob = net.forward("prob"); //compute output
t.stop();
}
4、 找出prob最大的label,輸出結果。
getMaxClass(prob, &classId, &classProb);