Python3调用训练好的Caffe模型

在此之前你需要把caffe(最好为GPU版)安装好,ubuntu安装参考,windows安装参考。

顺便把scikit-learn安装一下:

pip install scikit-learn

读图像可以用opencv:

pip install opencv-python

首先贴上通用代码,具体介绍请看注释

import cv2

import caffe
import numpy as np
from caffe.proto import caffe_pb2


class CaffeNet:
    # caffemodel  .caffemodel文件
    # deploy_file  .protxt文件
    # transformer  transformer对象,在下面介绍
    # caffemodel  显卡编号,从0开始,如果你只有一个显卡那就填0吧
    def __init__(self, caffemodel, deploy_file, transformer, device_id=0):
        caffe.set_device(device_id)
        caffe.set_mode_gpu()
        self.net = caffe.Net(deploy_file, caffemodel, caffe.TEST)
        self.transformer = transformer
 
    # 前向传播,images表示输入图片序列,这里的每张图片应该与你网络的输入层尺寸一样。
    # batch_size,同时前向传播的图片数量,看显存设置,设置高了显存可能会溢出。
    # layer,这是个字符串,是你网络中某层网络的名称,当传入改参数时,会返回该层的输出。
    # 
    def forward_pass(self, images, batch_size=1, layer=None):
        caffe_images = []
        for image in images:
            if image.ndim == 2:
                caffe_images.append(image[:, :, np.newaxis])
            else:
                caffe_images.append(image)

        caffe_images = np.array(caffe_images)
        dims = self.transformer.inputs['data'][1:]

        scores = None
        fea = None
        for chunk in [caffe_images[x:x+batch_size] for x in range(0, len(caffe_images), batch_size)]:
            new_shape = (len(chunk), ) + tuple(dims)
            if self.net.blobs['data'].data.shape != new_shape:
                self.net.blobs['data'].reshape(*new_shape)
            for idx, img in enumerate(chunk):
                image_data = self.transformer.preprocess('data', img)
                self.net.blobs['data'].data[idx] = image_data
            
            # 网络的输出层在这,当然,你的deploy.prototxt中可能去掉了输出层,但这里始终表示网络的最后一层的输出。
            output = self.net.forward()[self.net.outputs[-1]]

            if layer is not None:
                if fea is None:
                    fea = np.copy(self.net.blobs[layer].data)
                else:
                    fea = np.vstack((fea, self.net.blobs[layer].data))

            if scores is None:
                scores = np.copy(output)
            else:
                scores = np.vstack((scores, output))
        # 这里返回得分、指定layer层的输出
        return scores, fea


    # 前向传播,这里加了一个锁,并发时如果出现报错的情况可以使用此方法,但是会降低效率。
    def forward_pass_sync(self, images, batch_size, layer, lock):
        lock.acquire()
        try:
            return self.forward_pass(images, batch_size, layer)
        except Exception as e:
            print(e)
        finally:
            lock.release()
    
    # 分类方法,其实也就是在之前的forward_pass方法上对得分进行取最大值的角标,即取所属分类
    def classify(self, image_list, layer_name=None):
        if self.net.blobs['data'].data.shape[1] == 1:
            image_list = [cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) for img in image_list]
        scores, fea = self.forward_pass(image_list, batch_size=1, layer=layer_name)
        return scores, np.argmax(scores, 1), fea

有了上述代码之后就可以进一步初始化一个Caffe网络了,这里以VGG FACE网络为例。

网络下载戳这https://pan.baidu.com/s/1jzMhE2QjqKwIRL-GKg_lXg

import caffe
import cv2
import numpy as np
import sklearn.metrics.pairwise
from facetk.engine.basis.caffenet import CaffeNet
from present import present

caffe_model = 'VGG_FACE.caffemodel'
deploy_file = 'VGG_FACE_deploy.prototxt'

# 构建transformer对象
# 输入层
transformer = caffe.io.Transformer(inputs={'data': [1, 3, 224, 224]})
# 当你的图片是OPENCV读入时,是BGR,这里2,0,1指将BR调换,即将BGR转RGB
transformer.set_transpose('data', (2, 0, 1))
# opencv读入图像时是height * width * channel,即长×宽×通道数,需要将通道数提前到第一个,这是Caffe要求的,照做就OK
transformer.set_channel_swap('data', (2, 1, 0))
# 设置均值,减均值大家都知道的吧。当然有些网络不需要减均值,这里就可以不写。
transformer.set_mean('data', np.array([129.1863,104.7624,93.5940]))
# 归一化了解一下
transformer.set_input_scale('data', 0.00390625)

#由于我最近在搞人脸识别,需要将某全连接层提出作为特征向量,所以有这么个东西,前向传播的时候会返回对应层的输出。
feature_layer = "fc7"

net = CaffeNet(self, caffe_model, deploy_file, transformer)

#有了网络就可以进行前向传播了,这里输入的两张图片是我裁好的人脸图像,大小均为224×224,也就是VGG的输入层尺寸,当然也可以不是这个尺寸,但会降低人脸识别的准确率。
images = [cv2.imread('a.jpg'),cv2.imread('b.jpg')]

# 这里会返回两张图像的得分、以及对应的特征向量
scores, fea = net.forward_pass(images ,2 , feature_layer)

# 计算两张图片的特征向量的cos距离,得出两张人脸的相似度
sim = sklearn.metrics.pairwise.cosine_similarity([fea[0]], [fea[1]])[0][0]
print(sim)



那么至此也就结束了,代码中如果有什么错误的地方欢迎指正。

猜你喜欢

转载自my.oschina.net/kalnkaya/blog/1824284