classification_demo.m 是個很好的學習資料,了解這個代碼之后,就能在matlab里用訓練好的model對輸入圖像進行分類了,而且我在里邊還學到了oversample的實例,終於了解數據增強是個怎么回事。
caffe-master\matlab\demo\classification_demo.m這個demo是針對 ImageNet圖像分類的(1000個類), 主要是調用訓練好model,對輸入的圖像進行分類,輸出分類結果。
要想運行此demo,需要的東西有:
1. 模型描述文件:deploy.prototxt(這個文件本來就有,不用管)
2. 模型本身:bvlc_reference_caffenet.caffemodel
3. 標簽文件:用來描述1000個類分別是什么
4. 均值文件:即訓練樣本的均值文件(沒看過相關資料,暫時認為是訓練樣本的均值文件),ilsvrc_2012_mean.mat,文件已經存在於caffe-master\matlab\+caffe\imagenet之中
從以上可以知道,當我們想將classification運用於自己的數據集的時候就要對應的更改以上4點。
Matalb接口的配置以及demo的運行請看之前的博客:【caffe-windows】 caffe-master 之 matlab接口配置 (http://blog.csdn.net/u011995719/article/details/53994570)
現在來分析 classification_demo.m,方便之后應用於自己的項目中。
首先我們來看看輸入輸出:
input
im color image as uint8HxWx3
use_gpu 1 to use the GPU, 0 touse the CPU
output
scores 1000-dimensional ILSVRCscore vector
maxlabel the label of the highest score
輸入有兩個參數,一個是圖片,為單張圖(若要測試多張,用for解決),另外一個則是CPU和GPU的選擇。
輸出也有兩個參數,一個是得分,即該圖片對應所有類別的一個概率分布,另外一個則是最高得分所對應的類別,這就和標簽文件有關了。
下面直接貼源碼進行分析(刪減原注釋,建議對照原注釋):
%此處為添加路徑,確保能找到caffe-master\matlab\+caffe if exist('../+caffe', 'dir') addpath('..'); else error('Please run this demo from caffe/matlab/demo'); end % 設置CPU or GPU if exist('use_gpu', 'var') && use_gpu caffe.set_mode_gpu(); gpu_id = 0; % we will use the first gpu in this demo caffe.set_device(gpu_id); else caffe.set_mode_cpu(); end model_dir = '../../models/bvlc_reference_caffenet/';% 模型所在文件夾路徑 net_model = [model_dir 'deploy.prototxt']; % 模型描述文件的路徑 net_weights = [model_dir 'bvlc_reference_caffenet.caffemodel']; % 模型的路徑 phase = 'test'; % 指出網絡狀態為test,防止使用dropout if ~exist(net_weights, 'file')% 檢測模型是否存在,不存在則報錯提醒 error('Please download CaffeNet from Model Zoo before you run this demo'); end net = caffe.Net(net_model, net_weights, phase); % 初始化網絡 % 若classification_demo這個函數的輸入參數小於1,即無輸入參數,則默認使用 caffe/examples/images/cat.jpg 這張圖片 if nargin < 1 fprintf('using caffe/examples/images/cat.jpg as input image\n'); im = imread('../../examples/images/cat.jpg'); end % 重點來了! 由於caffe里的數據是 BGR的順序,而matlab是RGB的順序,因此需要對輸入圖片進行變換 % 這里用一個prepare_image函數將RGB轉成BGR,而且對輸入圖片進行了resize操作,crop操作以及減均值 % 跑到最下面去看看 prepare_image函數 tic; input_data = {prepare_image(im)}; toc; tic; scores = net.forward(input_data); % 將數據輸入到網絡,進行前向傳播,得出分數,scores是一個細胞元組 toc; scores = scores{1}; % scores 是 1000*10 的矩陣 10是對應了10個crop圖片 scores = mean(scores, 2); % 對10個crop進行求平均 [~, maxlabel] = max(scores); % 再找出最大的那一個 % 重置 caffe caffe.reset_all(); % ------------------------------------------------------------------------ function crops_data = prepare_image(im) % ------------------------------------------------------------------------ % caffe/matlab/+caffe/imagenet/ilsvrc_2012_mean.mat contains mean_data that % is already in W x H x C with BGR channels d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat'); % 讀取均值文件通道順序已經是BGR mean_data = d.mean_data; IMAGE_DIM = 256; % resize的大小 CROPPED_DIM = 227; % crop的大小,因為模型的輸入就是 227*227的,所以最終要得到一個227*227的 % Convert an image returned by Matlab's imread to im_data in caffe's data % format: W x H x C with BGR channels im_data = im(:, :, [3, 2, 1]); % RGB 轉成了 BGR ,im_data通道順序已經是 BGR im_data = permute(im_data, [2, 1, 3]); % 對輸入圖像進行了轉置, 長和寬換一換 im_data = single(im_data); % 數據格式轉成uint8類型 im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear'); % 采取雙線性插值法,對輸入圖片進行resize至 IMAGE_DIM 大小 im_data = im_data - mean_data; % 再減去均值 % oversample (4 corners, center, and their x-axis flips) % oversample 就是 數據增強 2012年Alex等人提出的一個技術,這里是在圖片(此處256*256的)的4個角以及正中心截取出5張 % 227*227的圖片,然后將這5張圖片在x軸上進行鏡像,總共獲得10張 227*227的圖片作為模型的輸入 crops_data = zeros(CROPPED_DIM, CROPPED_DIM, 3, 10, 'single'); indices = [0 IMAGE_DIM-CROPPED_DIM] + 1; n = 1; for i = indices % for循環只是截取了4個角的 for j = indices crops_data(:, :, :, n) = im_data(i:i+CROPPED_DIM-1, j:j+CROPPED_DIM-1, :); % 截取一個角的 227*227的圖片 crops_data(:, :, :, n+5) = crops_data(end:-1:1, :, :, n); % 將該圖片在x軸上作鏡像,+5是因為共截取5張227*227 n = n + 1; % 截取5張,再分別鏡像,一張圖片變成了10張圖片進行輸入 end end center = floor(indices(2) / 2) + 1; % 截取中心的圖片,再進行鏡像 crops_data(:,:,:,5) = ... im_data(center:center+CROPPED_DIM-1,center:center+CROPPED_DIM-1,:); crops_data(:,:,:,10) = crops_data(end:-1:1, :, :, 5);
PS:
1. 大家可以看以下模型描述文件, deploy.prototxt ,里的這行 “input_param { shape: { dim: 10 dim: 3 dim: 227 dim: 227 } } ” 為什么輸入是 10*3*227*227。一開始我還以為這個10是batch數,但是看完了 classification_demo后終於明白這個10是怎么來的了!
有興趣的同學可以打開caffe-master\examples\mnist 下的 lenet.prototxt , 看這行 input_param { shape: { dim: 64 dim: 1 dim: 28 dim: 28 } },為什么是64??求解答
為了做參考,caffe-master\examples\cifar10 下的 cifar10_quick.prototxt 是 input_param { shape: { dim: 1 dim: 3 dim: 32 dim: 32 } }
2. 發現求scores的時候是有 1000*10的矩陣,也就是每一張crop圖片是獨立的input,輸入並不是 一個10*3*227*227的一個數據,而是 10個 3*227*227的數據,然后得到10組得分,然后再求平均! (怎么老感覺有種作弊的嫌疑!!) 所以要運用此代碼到自己的數據集時候,請記得留意 scores!!