日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【caffe速成】caffe图像分类从模型自定义到测试

發(fā)布時間:2025/3/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【caffe速成】caffe图像分类从模型自定义到测试 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章首發(fā)于微信公眾號《與有三學(xué)AI》

【caffe速成】caffe圖像分類從模型自定義到測試

這是給大家準(zhǔn)備的caffe速成例子

這一次我們講講 Caffe 這個主流的開源框架從訓(xùn)練到測試出結(jié)果的全流程。到此,我必須假設(shè)大家已經(jīng)有了深度學(xué)習(xí)的基礎(chǔ)知識并了解卷積網(wǎng)絡(luò)的工作原理。

相關(guān)的代碼、數(shù)據(jù)都在我們 Git 上,希望大家 Follow 一下這個 Git 項目,后面會持續(xù)更新不同框架下的任務(wù)。

https://github.com/longpeng2008/LongPeng_ML_Course

這一篇我們說一個分類任務(wù),給大家準(zhǔn)備了 500 張微笑的圖片、500 張非微笑的圖片,放置在 data 目錄下,圖片預(yù)覽如下,已經(jīng)縮放到 60*60 的大小:

這是非微笑的圖片:

?

這是微笑的圖片:

?

?

01 Caffe 是什么

Caffe 是以 C++/CUDA 代碼為主,最早的深度學(xué)習(xí)框架之一,比 TensorFlow、Mxnet、Pytorch 等都更早,支持命令行、Python 和 Matlab 接口,單機(jī)多卡、多機(jī)多卡等都可以很方便的使用,CPU 和 GPU 之間無縫切換。

對于入門級別的任務(wù),如圖像分類,Caffe 上手的成本最低,幾乎不需要寫一行代碼就可以開始訓(xùn)練,所以我推薦 Caffe 作為入門學(xué)習(xí)的框架。

Caffe 相對于 TensorFlow 等使用 pip 一鍵安裝的方式來說,編譯安裝稍微麻煩一些,但其實(shí)依舊很簡單,我們以 Ubuntu 16.04 為例子,官網(wǎng)的安裝腳本足夠用了,它有一些依賴庫。

sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
sudo apt-get install --no-install-recommends libboost-all-devsudo apt-get install libatlas-base-dev
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev

裝完之后,到?Git 上 clone 代碼,修改 Makefile.config 就可以進(jìn)行編譯安裝,如果其中有任何問題,多 Google,還有什么問題,留言吧。當(dāng)然,對于有 GPU 的讀者,還需要安裝 cuda 以及 Nvidia 驅(qū)動。

?

02 Caffe 訓(xùn)練

Caffe 完成一個訓(xùn)練,必要準(zhǔn)備以下資料:一個是 train.prototxt 作為網(wǎng)絡(luò)配置文件,另一個是 solver.prototxt 作為優(yōu)化參數(shù)配置文件,再一個是訓(xùn)練文件 list。

另外,在大多數(shù)情況下,需要一個預(yù)訓(xùn)練模型作為權(quán)重的初始化。

(1)準(zhǔn)備網(wǎng)絡(luò)配置文件

我們準(zhǔn)備了一個 3*3 的卷積神經(jīng)網(wǎng)絡(luò),它的 train.prototxt 文件是這樣的:

name: "mouth"
layer {
?name: "data"
?type: "ImageData"
?top: "data"
?top: "clc-label"
?image_data_param {
? ?source: "all_shuffle_train.txt"
? ?batch_size: 96
? ?shuffle: true
?}
?transform_param {
? ?mean_value: 104.008
? ?mean_value: 116.669
? ?mean_value: 122.675
? ?crop_size: 48
? ?mirror: true
?}
?include: { phase: TRAIN}
}
layer {
?name: "data"
?type: "ImageData"
?top: "data"
?top: "clc-label"
?image_data_param {
? ?source: "all_shuffle_val.txt"
? ?batch_size: 30
? ?shuffle: false
?}
?transform_param {
? ?mean_value: 104.008
? ?mean_value: 116.669
? ?mean_value: 122.675
? ?crop_size: 48
? ?mirror: false
?}
?include: { phase: TEST}
}
layer {
?name: "conv1"
?type: "Convolution"
?bottom: "data"
?top: "conv1"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 12
? ?pad: 1
? ?kernel_size: 3
? ?stride: 2
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.01
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu1"
?type: "ReLU"
?bottom: "conv1"
?top: "conv1"
}
layer {
?name: "conv2"
?type: "Convolution"
?bottom: "conv1"
?top: "conv2"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 20
? ?kernel_size: 3
? ?stride: 2
? ?pad: 1
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.1
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu2"
?type: "ReLU"
?bottom: "conv2"
?top: "conv2"
}
layer {
?name: "conv3"
?type: "Convolution"
?bottom: "conv2"
?top: "conv3"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 40
? ?kernel_size: 3
? ?stride: 2
? ?pad: 1
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.1
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu3"
?type: "ReLU"
?bottom: "conv3"
?top: "conv3"
}
layer {
?name: "ip1-mouth"
?type: "InnerProduct"
?bottom: "conv3"
?top: "pool-mouth"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?inner_product_param {
? ?num_output: 128
? ?weight_filler {
? ? ?type: "xavier"
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0
? ?}
?}
}

layer {
? ?bottom: "pool-mouth"
? ?top: "fc-mouth"
? ?name: "fc-mouth"
? ?type: "InnerProduct"
? ?param {
? ? ? ?lr_mult: 1
? ? ? ?decay_mult: 1
? ?}
? ?param {
? ? ? ?lr_mult: 2
? ? ? ?decay_mult: 1
? ?}
? ?inner_product_param {
? ? ? ?num_output: 2
? ? ? ?weight_filler {
? ? ? ? ? ?type: "xavier"
? ? ? ?}
? ? ? ?bias_filler {
? ? ? ? ? ?type: "constant"
? ? ? ? ? ?value: 0
? ? ? ?}
? ?}
}
layer {
? ?bottom: "fc-mouth"
? ?bottom: "clc-label"
? ?name: "loss"
? ?type: "SoftmaxWithLoss"
? ?top: "loss"
}
layer {
? ?bottom: "fc-mouth"
? ?bottom: "clc-label"
? ?top: "acc"
? ?name: "acc"
? ?type: "Accuracy"
? ?include {
? ? ? ?phase: TRAIN
? ?}
? ?include {
? ? ? ?phase: TEST
? ?}
}

可以看出,Caffe 的這個網(wǎng)絡(luò)配置文件,每一個卷積層,都是以 layer{} 的形式定義,layer 的bottom、top 就是它的輸入輸出,type 就是它的類型,有的是數(shù)據(jù)層、有的是卷積層、有的是 loss 層。

我們采用 netscope 來可視化一下這個模型。

從上面看很直觀的看到,網(wǎng)絡(luò)的輸入層是 data 層,后面接了3個卷積層,其中每一個卷積層都后接了一個 relu 層,最后 ip1-mouth、fc-mouth 是全連接層。Loss 和 acc 分別是計算 loss 和 acc 的層。

各層的配置有一些參數(shù),比如 conv1 有卷積核的學(xué)習(xí)率、卷積核的大小、輸出通道數(shù)、初始化方法等,這些可以后續(xù)詳細(xì)了解。

(2)準(zhǔn)備訓(xùn)練 list

我們看上面的 data layer,可以到?

image_data_param?里面有

source: "all_shuffle_train.txt"

它是什么呢,就是輸入用于訓(xùn)練的 list,它的內(nèi)容是這樣的:

../../../../datas/mouth/1/182smile.jpg 1

../../../../datas/mouth/1/435smile.jpg 1

../../../../datas/mouth/0/40neutral.jpg 0

../../../../datas/mouth/1/206smile.jpg 1

../../../../datas/mouth/0/458neutral.jpg 0

../../../../datas/mouth/0/158neutral.jpg 0

../../../../datas/mouth/1/322smile.jpg 1

../../../../datas/mouth/1/83smile.jpg 1

../../../../datas/mouth/0/403neutral.jpg 0

../../../../datas/mouth/1/425smile.jpg 1

../../../../datas/mouth/1/180smile.jpg 1

../../../../datas/mouth/1/233smile.jpg 1

../../../../datas/mouth/1/213smile.jpg 1

../../../../datas/mouth/1/144smile.jpg 1

../../../../datas/mouth/0/327neutral.jpg 0

格式就是,圖片的名字 + 空格 + label,這就是 Caffe 用于圖片分類默認(rèn)的輸入格式。

(3)準(zhǔn)備優(yōu)化配置文件:

net: "./train.prototxt"

test_iter: 100

test_interval: 10

base_lr: 0.00001

momentum: 0.9

type: "Adam"

lr_policy: "fixed"

display: 100

max_iter: 10000

snapshot: 2000

snapshot_prefix: "./snaps/conv3_finetune"

solver_mode: GPU

介紹一下上面的參數(shù)。

net 是網(wǎng)絡(luò)的配置路徑。test_interval是指訓(xùn)練迭代多少次之后,進(jìn)行一次測試。test_iter是測試多少個batch,如果它等于 1,就說明只取一個 batchsize 的數(shù)據(jù)來做測試,如果 batchsize 太小,那么對于分類任務(wù)來說統(tǒng)計出來的指標(biāo)也不可信,所以最好一次測試,用到所有測試數(shù)據(jù)。因?yàn)?#xff0c;常令test_iter*test_batchsize=測試集合的大小。

base_lr、momentum、type、lr_policy是和學(xué)習(xí)率有關(guān)的參數(shù),base_lr和lr_policy決定了學(xué)習(xí)率大小如何變化。type 是優(yōu)化的方法,以后再談。max_iter是最大的迭代次數(shù),snapshot 是每迭代多少次之后存儲迭代結(jié)果,snapshot_prefix為存儲結(jié)果的目錄,caffe 存儲的模型后綴是 .caffemodel。solver_mode可以指定用 GPU 或者 CPU 進(jìn)行訓(xùn)練。

(4)訓(xùn)練與結(jié)果可視化

我們利用 C++ 的接口進(jìn)行訓(xùn)練,命令如下:

SOLVER=./solver.prototxt

WEIGHTS=./init.caffemodel

../../../../libs/Caffe_Long/build/tools/caffe train -solver $SOLVER -weights $WEIGHTS -gpu 0 2>&1 | tee log.txt

其中,caffe train 就是指定訓(xùn)練。我們可以利用腳本可視化一下訓(xùn)練結(jié)果,具體參考git項目:

?

03 Caffe 測試

上面我們得到了訓(xùn)練結(jié)果,下面開始采用自己的圖片進(jìn)行測試。

train.prototxt 與 test.prototxt 的區(qū)別

訓(xùn)練時的網(wǎng)絡(luò)配置與測試時的網(wǎng)絡(luò)配置是不同的,測試沒有 acc 層,也沒有 loss 層,取輸出的 softmax 就是分類的結(jié)果。同時,輸入層的格式也有出入,不需要再輸入 label,也不需要指定圖片 list,但是要指定輸入尺度,我們看一下 test.prototxt 和可視化結(jié)果。

name: "mouth"
layer {
?name: "data"
?type: "Input"
?top: "data"
?input_param { shape: { dim: 1 dim: 3 dim: 48 dim: 48 } }
}

layer {
?name: "conv1"
?type: "Convolution"
?bottom: "data"
?top: "conv1"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 12
? ?pad: 1
? ?kernel_size: 3
? ?stride: 2
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.01
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu1"
?type: "ReLU"
?bottom: "conv1"
?top: "conv1"
}
layer {
?name: "conv2"
?type: "Convolution"
?bottom: "conv1"
?top: "conv2"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 20
? ?kernel_size: 3
? ?stride: 2
? ?pad: 1
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.1
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu2"
?type: "ReLU"
?bottom: "conv2"
?top: "conv2"
}
layer {
?name: "conv3"
?type: "Convolution"
?bottom: "conv2"
?top: "conv3"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?convolution_param {
? ?num_output: 40
? ?kernel_size: 3
? ?stride: 2
? ?pad: 1
? ?weight_filler {
? ? ?type: "xavier"
? ? ?std: 0.1
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0.2
? ?}
?}
}
layer {
?name: "relu3"
?type: "ReLU"
?bottom: "conv3"
?top: "conv3"
}
layer {
?name: "ip1-mouth"
?type: "InnerProduct"
?bottom: "conv3"
?top: "pool-mouth"
?param {
? ?lr_mult: 1
? ?decay_mult: 1
?}
?param {
? ?lr_mult: 2
? ?decay_mult: 0
?}
?inner_product_param {
? ?num_output: 128
? ?weight_filler {
? ? ?type: "xavier"
? ?}
? ?bias_filler {
? ? ?type: "constant"
? ? ?value: 0
? ?}
?}
}
layer {
? ?bottom: "pool-mouth"
? ?top: "fc-mouth"
? ?name: "fc-mouth"
? ?type: "InnerProduct"
? ?param {
? ? ? ?lr_mult: 1
? ? ? ?decay_mult: 1
? ?}
? ?param {
? ? ? ?lr_mult: 2
? ? ? ?decay_mult: 1
? ?}
? ?inner_product_param {
? ? ? ?num_output: 2
? ? ? ?weight_filler {
? ? ? ? ? ?type: "xavier"
? ? ? ?}
? ? ? ?bias_filler {
? ? ? ? ? ?type: "constant"
? ? ? ? ? ?value: 0
? ? ? ?}
? ?}
}
layer {
? ?bottom: "fc-mouth"
? ?name: "loss"
? ?type: "Softmax"
? ?top: "prob"
}

使用 Python 進(jìn)行測試

由于 Python 目前廣泛使用,下面使用 Python 來進(jìn)行測試,它要做的就是導(dǎo)入模型、導(dǎo)入圖片、輸出結(jié)果。

下面是所有的代碼,我們詳細(xì)解釋下:

---代碼段1,這一段,我導(dǎo)入一些基本庫,同時導(dǎo)入caffe的路徑---

#_*_ coding:utf8

import sys

sys.path.insert(0, '../../../../../libs/Caffe_Long/python/')

import caffe

import os,shutil

import numpy as np

from PIL import Image as PILImage

from PIL import ImageMath

import matplotlib.pyplot as plt

import time

import cv2

---代碼段2,這一段,我們添加一個參數(shù)解釋器,方便參數(shù)管理---

debug=True

import argparse

def parse_args():

? ?parser = argparse.ArgumentParser(description='test resnet model for portrait segmentation')

? ?parser.add_argument('--model', dest='model_proto', help='the model', default='test.prototxt', type=str)

? ?parser.add_argument('--weights', dest='model_weight', help='the weights', default='./test.caffemodel', type=str)

? ?parser.add_argument('--testsize', dest='testsize', help='inference size', default=60,type=int)

? ?parser.add_argument('--src', dest='img_folder', help='the src image folder', type=str, default='./')

? ?parser.add_argument('--gt', dest='gt', help='the gt', type=int, default=0)

? ?args = parser.parse_args()

? ?return args

def start_test(model_proto,model_weight,img_folder,testsize):

---代碼段3,這一段,我們就完成了網(wǎng)絡(luò)的初始化---

? ?caffe.set_device(0)

? ?#caffe.set_mode_cpu()

? ?net = caffe.Net(model_proto, model_weight, caffe.TEST)

? ?imgs = os.listdir(img_folder)

? ?pos = 0

? ?neg = 0

? ?for imgname in imgs:

---代碼段4,這一段,是讀取圖片并進(jìn)行預(yù)處理,還記得我們之前的訓(xùn)練,是采用 BGR 的輸入格式,減去了圖像均值吧,同時,輸入網(wǎng)絡(luò)的圖像,也需要 resize 到相應(yīng)尺度。預(yù)處理是通過 caffe 的類,transformer 來完成,set_mean 完成均值,set_transpose 完成維度的替換,因?yàn)?caffe blob 的格式是 batch、channel、height、width,而 numpy 圖像的維度是 height、width、channel 的順序---

? ? ? imgtype = imgname.split('.')[-1]

? ? ? imgid = imgname.split('.')[0]

? ? ? if imgtype != 'png' and imgtype != 'jpg' and imgtype != 'JPG' and imgtype != 'jpeg' and imgtype != 'tif' and imgtype != 'bmp':

? ? ? ? ? print imgtype,"error"

? ? ? ? ? continue

? ? ? imgpath = os.path.join(img_folder,imgname)

? ? ? img = cv2.imread(imgpath)

? ? ? if img is None:

? ? ? ? ? print "---------img is empty---------",imgpath

? ? ? ? ? continue

? ? ? img = cv2.resize(img,(testsize,testsize))

? ? ? transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})

? ? ? transformer.set_mean('data', np.array([104.008,116.669,122.675]))

? ? ? transformer.set_transpose('data', (2,0,1))

---代碼段5,這一段,就得到了輸出結(jié)果了,并做一些可視化顯示---

? ? ? out = net.forward_all(data=np.asarray([transformer.preprocess('data', img)]))

? ? ? result = out['prob'][0]

? ? ? print "---------result prob---------",result,"-------result size--------",result.shape

? ? ? probneutral = result[0]

? ? ? print "prob neutral",probneutral?

? ? ? probsmile = result[1]

? ? ? print "prob smile",probsmile

? ? ? problabel = -1

? ? ? probstr = 'none'

? ? ? if probneutral > probsmile:

? ? ? ? ? probstr = "neutral:"+str(probneutral)

? ? ? ? ? pos = pos + 1

? ? ? else:

? ? ? ? ? probstr = "smile:"+str(probsmile)

? ? ? ? ? neg = neg + 1

? ? ? if debug:

? ? ? ? ?showimg = cv2.resize(img,(256,256))

? ? ? ? ?cv2.putText(showimg,probstr,(30,50),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),1)

? ? ? ? ?cv2.imshow("test",showimg)

? ? ? ? ?k = cv2.waitKey(0)

? ? ? ? ?if k == ord('q'):

? ? ? ? ? ? ?break

? ?print "pos=",pos?

? ?print "neg=",neg?

if __name__ == '__main__':

? ? args = parse_args()

? ? start_test(args.model_proto,args.model_weight,args.img_folder,args.testsize)

經(jīng)過前面的介紹,我們已經(jīng)學(xué)會了 Caffe 的基本使用,但是我們不能停留于此。Caffe 是一個非常優(yōu)秀的開源框架,有必要去細(xì)讀它的源代碼。

至于怎么讀 Caffe 的代碼,建議閱讀我寫的Caffe代碼閱讀系列內(nèi)容。

?

04 總結(jié)

雖然現(xiàn)在很多人沒有從 Caffe 開始學(xué),但是希望提升自己 C++ 水平和更深刻理解深度學(xué)習(xí)中的一些源碼的,建議從 Caffe 開始學(xué)起。

?

同時,在我的知乎專欄也會開始同步更新這個模塊,歡迎來交流

https://zhuanlan.zhihu.com/c_151876233

注:部分圖片來自網(wǎng)絡(luò)

—END—

本系列完整文章:

第一篇:【caffe速成】caffe圖像分類從模型自定義到測試

第二篇:【tensorflow速成】Tensorflow圖像分類從模型自定義到測試

第三篇:【pytorch速成】Pytorch圖像分類從模型自定義到測試

第四篇:【paddlepaddle速成】paddlepaddle圖像分類從模型自定義到測試

第五篇:【Keras速成】Keras圖像分類從模型自定義到測試

第六篇:【mxnet速成】mxnet圖像分類從模型自定義到測試

第七篇:【cntk速成】cntk圖像分類從模型自定義到測試

第八篇:【chainer速成】chainer圖像分類從模型自定義到測試

第九篇:【DL4J速成】Deeplearning4j圖像分類從模型自定義到測試

第十篇:【MatConvnet速成】MatConvnet圖像分類從模型自定義到測試

第十一篇:【Lasagne速成】Lasagne/Theano圖像分類從模型自定義到測試

第十二篇:【darknet速成】Darknet圖像分類從模型自定義到測試

感謝各位看官的耐心閱讀,不足之處希望多多指教。后續(xù)內(nèi)容將會不定期奉上,歡迎大家關(guān)注有三公眾號 有三AI

?

總結(jié)

以上是生活随笔為你收集整理的【caffe速成】caffe图像分类从模型自定义到测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。