caffe之特征图可视化及特征提取
上一篇博客,介紹了怎么對訓(xùn)練好的model的各層權(quán)重可視化,這篇博客,我們介紹測試圖片輸入網(wǎng)絡(luò)后產(chǎn)生的特征圖的可視化
記得上篇中,我們是寫了一個(gè)新的文件test.cpp,然后編譯運(yùn)行那個(gè)文件的,這是因?yàn)闄?quán)重可視化,是不需要網(wǎng)絡(luò)的前向傳播,只要加載model就好了,而我們?nèi)绻枰梢暬卣鲌D,那就必須進(jìn)行網(wǎng)絡(luò)的前向傳播了,所以,這次,我們對caffe根目錄下的examples/cpp_classification/classification.cpp文件基礎(chǔ)上,進(jìn)行修改,添加我們自己需要的功能(可視化),同樣的,我們把這個(gè)文件拷貝過來,放在自己的某個(gè)文件夾下,假設(shè)取名依然為test.cpp,而我們要修改的,就是Predict函數(shù),定位到Predict函數(shù),在net_->Forward();后面加入以下代碼:
?
//打印出一張圖片經(jīng)過網(wǎng)絡(luò)各層產(chǎn)出的各層輸出
cout<<"網(wǎng)絡(luò)中的Blobs名稱為:\n";
vector<shared_ptr<Blob<float> > > blobs=net_->blobs(); //得到各層的輸出特征向量
vector<string> blob_names=net_->blob_names(); //各層的輸出向量名字
cout<<blobs.size()<<" "<<blob_names.size()<<endl;
for(int i=0;i<blobs.size();i++){
cout<<blob_names[i]<<" "<<blobs[i]->shape_string()<<endl;
}
cout<<endl;
編譯該文件,編譯命令參照上一篇博客,此時(shí)會(huì)打印出如下信息
網(wǎng)絡(luò)中的Blobs名稱為:
15 15
data 1 3 227 227 (154587)
conv1 1 96 55 55 (290400)
pool1 1 96 27 27 (69984)
norm1 1 96 27 27 (69984)
conv2 1 256 27 27 (186624)
pool2 1 256 13 13 (43264)
norm2 1 256 13 13 (43264)
conv3 1 384 13 13 (64896)
conv4 1 384 13 13 (64896)
conv5 1 256 13 13 (43264)
pool5 1 256 6 6 (9216)
fc6 1 4096 (4096)
fc7 1 4096 (4096)
fc8 1 1000 (1000)
prob 1 1000 (1000)
可以看到,此時(shí)將每個(gè)層的輸出特征圖的維度信息都打印出來了,比如data層的輸出是1 3 227 277,因?yàn)榫W(wǎng)絡(luò)的輸入圖片是1個(gè),3通道,尺寸是227*227;經(jīng)過conv1層的輸出是1 96 55 55,因?yàn)閏onv1層有96個(gè)卷積核,卷積核大小為11*11,步長為4,所以其輸出的每個(gè)特征圖的尺寸為(227-11)/4+1=55,所以特征圖的尺寸也對應(yīng)著1 96 55 55.
?
好了,我們接下來再輸入一下代碼,進(jìn)行對經(jīng)過conv1的特征圖可視化,其尺寸是1 96 55 55,也就看出是96個(gè)55*55大小的灰度圖
?
//將測試圖片經(jīng)過第一個(gè)卷積層的特征圖可視化
string blobName="conv1"; //我們?nèi)〗?jīng)過第一個(gè)卷積層的特征圖
assert(net_->has_blob(blobName)); //為免出錯(cuò),我們必須斷言,網(wǎng)絡(luò)中確實(shí)有名字為blobName的特征圖
shared_ptr<Blob<float> > conv1Blob=net_->blob_by_name(blobName); //1*96*55*55 斷言成功后,按名字返回該 特征向量
cout<<"測試圖片的特征響應(yīng)圖的形狀信息為:"<<conv1Blob->shape_string()<<endl; //打印輸出的特征圖的形狀信息
//和前面的博客一樣,此時(shí)的特征向量是經(jīng)過了ReLU激活函數(shù)的,范圍在0~無窮大,我們?yōu)榱丝梢暬?#xff0c;仍然需要?dú)w一化到0~255
//下面的代碼,跟上一篇博客中是一樣的
float maxValue=-10000000,minValue=10000000;
const float* tmpValue=conv1Blob->cpu_data();
for(int i=0;i<conv1Blob->count();i++){
maxValue=std::max(maxValue,tmpValue[i]);
minValue=std::min(minValue,tmpValue[i]);
}
int width=conv1Blob->shape(2); //響應(yīng)圖的寬度
int height=conv1Blob->shape(3); //響應(yīng)圖的高度
int num=conv1Blob->shape(1); //個(gè)數(shù)
int imgHeight=(int)(1+sqrt(num))*height;
int imgWidth=(int)(1+sqrt(num))*width;
Mat img2(imgHeight,imgWidth,CV_8UC1,Scalar(0)); //此時(shí),應(yīng)該是灰度圖
int kk=0;
for(int x=0;x<imgHeight;x+=height){
for(int y=0;y<imgWidth;y+=width){
if(kk>=num)
continue;
Mat roi=img2(Rect(y,x,width,height));
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
float value=conv1Blob->data_at(0,kk,i,j);
roi.at<uchar>(i,j)=(value-minValue)/(maxValue-minValue)*255;
}
}
kk++;
}
}
resize(img2,img2,Size(500,500));//進(jìn)行顯示
imshow("2",img2);
waitKey(0);
?
?
輸入圖片
特征圖
?
會(huì)了這一點(diǎn)后,大家如果想將CNN單純的當(dāng)做特征提取器,可以將第一個(gè)全連接層的前一層的輸出特征向量(比如這個(gè)網(wǎng)絡(luò),是pool5層的輸出特征1*256*6*6=9216)提取出來,這是該圖片經(jīng)過CNN后的最初步的特征,當(dāng)然如果覺得維度高,也可以提取出第一個(gè)全連接層的特征向量,這里是4096維,然后再送進(jìn)泛化性能更好的分類器(如SVM)去分類識別,我用提取第一個(gè)全連接層的4096維特征試驗(yàn)了下SVM,在線性核下,分類效果大致相當(dāng)。大家可以根據(jù)自己的需求去嘗試。
總結(jié)
以上是生活随笔為你收集整理的caffe之特征图可视化及特征提取的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: caffe模型weightsfeatur
- 下一篇: 学习Caffe(二)使用Caffe:Ca