前言

Caffe是目前比較常用的深度學習框架,這個框架安裝沒有其他一下主流框架那麼簡單,直接使用pip命令安裝,它更常用的是使用編譯的方式安裝。所以寫下這個文章記錄一下。

在Ubuntu上安裝Caffe

如果Ubuntu版本是>= 17.04的,就可以使用以下的方式安裝Caffe,注意安裝的是Python 3的版本。

apt install caffe-cpu

如果是低於這版本,就要使用源碼編譯了,筆者的系統是64位的Ubuntu 16.04,下面就介紹安裝步驟,使用的Python 2。

安裝依賴環境

首先我們要安裝依賴環境,依賴環境有點多,需要保證都安裝了,以免在編譯的時候出錯。如果之前安裝過了,重複執行命令也沒有問題的。

apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
apt-get install --no-install-recommends libboost-all-dev  
apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev
apt-get install libatlas-base-dev
apt-get install python-numpy
apt-get install libhdf5-serial-dev
apt-get install python-dev
apt install python-pip
pip install scikit-image

修改編譯文件

我們使用的是源碼編譯,所以要先克隆源碼,然後拷貝官方提供的編譯配置例子。

# 切換到opt目錄下
cd /opt
# 克隆caffe源碼
git clone git://github.com/BVLC/caffe.git
# 切入到源碼根目錄
cd caffe/
# 複製官方提供的編譯配置文件例子
cp Makefile.config.example Makefile.config
# 開始編寫配置信息
vim Makefile.config

修改這個配置文件如下:

  • 把第8行的註釋取消,編譯CPU版本的Caffe,即如下:
CPU_ONLY := 1
  • 然後版96、97、98行,改成如下:
# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial

開始編譯

現在就可以開始編譯了,前面兩條是編譯源碼,後面兩條是編譯測試,-j4是表示使用4個線程並行編譯,加快編譯速度。

make -j4 pycaffe
make -j4 all
make -j4 test
make -j4 runtest

添加環境變量

使用命令vim /etc/profile,在該文件的最後加上下面的這行代碼。

export PYTHONPATH=/opt/caffe/python:$PYTHONPATH

我們可以簡單測試一下是否安裝成功了,正常的話是可以輸出caffe的版本信息的。

# python
Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import caffe
>>> caffe.__version__

會輸出如下信息:

'1.0.0'

使用模型預測圖片

安裝完成caffe之後,我們可以使用模型來預測一下圖片。筆者在這裏下載caffe模型,下面的代碼中我們使用的是modelnet V2的模型。

# coding=utf-8
from __future__ import print_function
import numpy as np
import caffe

# 修改圖片大小
def get_img(img_path, nh, nw):
    im = caffe.io.load_image(img_path)
    h, w, _ = im.shape
    if h < w:
        off = (w - h) / 2
        im = im[:, off:off + h]
    else:
        off = (h - w) / 2
        im = im[off:off + h, :]
    im = caffe.io.resize_image(im, [nh, nw])
    return im

def eval(image_path, nh, nw):
    caffe.set_mode_cpu()
    # 加載模型
    net = caffe.Net("mobilenet_v2_deploy.prototxt", "mobilenet_v2.caffemodel", caffe.TEST)

    # 設置對圖片預處理的方式
    transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2, 0, 1))  # row to col
    transformer.set_channel_swap('data', (2, 1, 0))  # RGB to BGR
    transformer.set_raw_scale('data', 255)  # [0,1] to [0,255]
    # 減去圖片的均值
    img_mean = np.array([103.94, 116.78, 123.68], dtype=np.float32)
    transformer.set_mean('data', img_mean)
    # 乘上一個比例
    transformer.set_input_scale('data', 0.017)
    # 改變圖片維度
    net.blobs['data'].reshape(1, 3, nh, nw)

    im = get_img(image_path, nh, nw)
    net.blobs['data'].data[...] = transformer.preprocess('data', im)
    out = net.forward()
    # 得到預測結果
    prob = out['prob']
    prob = np.squeeze(prob)
    idx = np.argsort(-prob)
    # 獲取最大概率的label
    label = idx[0]
    # 讀取label文件內容
    label_names = np.loadtxt('synset.txt', str, delimiter='\t')
    print('%.5f - %s' % (prob[label], label_names[label]))

if __name__ == '__main__':
    image_path = "cat.jpg"
    nh, nw = 224, 224
    eval(image_path, nh, nw)

以下這函數是改變圖片的大小,使它滿足模型的需求,注意如果是Python 3的話,除法要使用//,而不是/,這是Python 3的一個改變。

def get_img(img_path, nh, nw):
    im = caffe.io.load_image(img_path)
    h, w, _ = im.shape
    if h < w:
        off = (w - h) / 2
        im = im[:, off:off + h]
    else:
        off = (h - w) / 2
        im = im[off:off + h, :]
    im = caffe.io.resize_image(im, [nh, nw])
    return im

以下代碼是指定CPU和加載模型的定義文件和權重文件,這個兩個文件就是我們從GitHub那裏下載的。

    caffe.set_mode_cpu()
    net = caffe.Net("mobilenet_v2_deploy.prototxt", "mobilenet_v2.caffemodel", caffe.TEST)

下面代碼片段是定義圖片的預處理方式,如改變通道順序,每個像素減去均值,每個像素乘上一個比例。

    transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2, 0, 1))  # row to col
    transformer.set_channel_swap('data', (2, 1, 0))  # RGB to BGR
    transformer.set_raw_scale('data', 255)  # [0,1] to [0,255]
    img_mean = np.array([103.94, 116.78, 123.68], dtype=np.float32)
    transformer.set_mean('data', img_mean)
    transformer.set_input_scale('data', 0.017)
    net.blobs['data'].reshape(1, 3, nh, nw)

以下代碼片段是加載圖片得到預測結果的,out['prob']輸出的是每個label的概率,使用到的synset.txt也是剛纔那個GitHub上的文件,這個文件的內容是每個label對應的名稱。最後輸出的是概率最大的label對應的概率和這個label對應的名字。

    im = get_img(image_path, nh, nw)
    net.blobs['data'].data[...] = transformer.preprocess('data', im)
    out = net.forward()
    prob = out['prob']
    prob = np.squeeze(prob)
    idx = np.argsort(-prob)
    label = idx[0]
    label_names = np.loadtxt('synset.txt', str, delimiter='\t')
    print('%.5f - %s' % (prob[label], label_names[label]))

輸出的結果如下:

0.25784 - 'n02123159 tiger cat'

參考資料

  1. http://caffe.berkeleyvision.org/installation.html
  2. https://blog.csdn.net/qq_25737169/article/details/77773884
  3. https://github.com/shicai/MobileNet-Caffe
小夜