caffe通过python(pycaffe)在已有模型上进行批量预测,批量提取特征

来源:互联网 发布:linux根据端口查进程 编辑:程序博客网 时间:2024/05/23 19:21


相关模块:

import numpy as np 
import caffe
import cv2


我使用的是net.Classifier()这个接口,先看看这个类的初始化函数,了解一下各个参数:

def __init__(self, model_file, pretrained_file, image_dims=None, mean=None, input_scale=None, raw_scale=None,             channel_swap=None):    caffe.Net.__init__(self, model_file, pretrained_file, caffe.TEST)# configure pre-processingin_ = self.inputs[0]self.transformer = caffe.io.Transformer({in_: self.blobs[in_].data.shape})self.transformer.set_transpose(in_, (2, 0, 1))if mean is not None:self.transformer.set_mean(in_, mean)if input_scale is not None:        self.transformer.set_input_scale(in_, input_scale)    if raw_scale is not None:        self.transformer.set_raw_scale(in_, raw_scale)    if channel_swap is not None:        self.transformer.set_channel_swap(in_, channel_swap)    self.crop_dims = np.array(self.blobs[in_].data.shape[2:])    if not image_dims:        image_dims = self.crop_dims    self.image_dims = image_dims
可以看到,主要的处理还是在caffe.io.Transformer({in_: self.blobs[in_].data.shape})里面
以下是我对各个参数的理解
model_file,是使用模型的deploy,而不是训练或者测试的deploy
pretrained_file,是模型文件,即'*.caffemodel'
image_dims=(256, 256),针对网络的输入尺寸进行crop(不是resize,随机crop?),默认为None,即输入整幅图,所以图片在输入之前要先resize到网络要求的尺寸
mean,均值,设置之后net会对输入的图片减去mean,默认为None
channel_swap=(2,1,0),将图片通道调换,如果输入之前是rgb,网络就把它变为bgr,默认为None,即不进行转换
raw_scale=255,将像素值乘以255,假如图片在输入之前的像素值是0~1的,这里可以设置(如果图片已经是0~255,那么会变为0~255*255?),默认为None,这个看你网络情况而定吧
input_scale,这个是什么鬼?看caffe.io.Transformer()里面,我猜input_scale是配合raw_scale一起用的把。。。。具体怎么用我也不知道

class Transformer:    """    Transform input for feeding into a Net.    Note: this is mostly for illustrative purposes and it is likely better    to define your own input preprocessing routine for your needs.    Parameters    ----------    net : a Net for which the input should be prepared    """    def __init__(self, inputs):        self.inputs = inputs        self.transpose = {}        self.channel_swap = {}        self.raw_scale = {}        self.mean = {}        self.input_scale = {}    def __check_input(self, in_):        if in_ not in self.inputs:            raise Exception('{} is not one of the net inputs: {}'.format(                in_, self.inputs))    def preprocess(self, in_, data):        """        Format input for Caffe:        - convert to single        - resize to input dimensions (preserving number of channels)        - transpose dimensions to K x H x W        - reorder channels (for instance color to BGR)        - scale raw input (e.g. from [0, 1] to [0, 255] for ImageNet models)        - subtract mean        - scale feature        Parameters        ----------        in_ : name of input blob to preprocess for        data : (H' x W' x K) ndarray        Returns        -------        caffe_in : (K x H x W) ndarray for input to a Net        """        self.__check_input(in_)        caffe_in = data.astype(np.float32, copy=False)        transpose = self.transpose.get(in_)        channel_swap = self.channel_swap.get(in_)        raw_scale = self.raw_scale.get(in_)        mean = self.mean.get(in_)        input_scale = self.input_scale.get(in_)        in_dims = self.inputs[in_][2:]        if caffe_in.shape[:2] != in_dims:            caffe_in = resize_image(caffe_in, in_dims)        if transpose is not None:            caffe_in = caffe_in.transpose(transpose)        if channel_swap is not None:            caffe_in = caffe_in[channel_swap, :, :]        if raw_scale is not None:            caffe_in *= raw_scale ####        if mean is not None:            caffe_in -= mean        if input_scale is not None:            caffe_in *= input_scale ####        return caffe_in

一、网络初始化


我用的vgg_face,基于vgg16的一个人脸识别模型,这个model的相关信息可以看这里VGG Face Descriptor

caffe.Classifier我只传入了模型文件和网络定义文件,其他都用默认,所以要使用之前要对图像进行一系列的预处理

def init_net():    caffe.set_mode_gpu() # CPU太慢了....    model_def = '/home/hy/d/huangying/305git/code/vgg_face_caffe/VGG_FACE_deploy.prototxt'    model_pretrained = '/home/hy/d/huangying/305git/code/vgg_face_caffe/VGG_FACE.caffemodel'    net = caffe.Classifier(model_def, model_pretrained)    return net


二、图片数据预处理


一般是从图片路径直接把图片读取到python内存中,这个可以用很多模块实现,cv2、plt、Image之类的,不赘述
假设把所有要处理的图片都读进到了一个名为faces的矩阵里,格式为:
num * height * width * channels
接下来要先对图片预处理,包括
1.resize成网络输入的尺寸大小
2.减去网络训练数据的均值
3.如果是灰度图,复制成3通道图片,如果是彩色图,把rgb转为bgr
注意 image = cv2.resize(faces[i],(224,224)) 这个函数
如果输入的是单通道(灰度图),resize后输出则去掉了通道那个维度,e.g [48,48,1]=>[48,48]
如果输入的是3通道(彩色图),resize后输出维度保持不变, e.g [48,48,3]=>[48,48,3]

def prepare_data(faces):    '''    faces: num * height * width * channel    '''    num = faces.shape[0]    faces_resize = np.empty([num,3,224,224])    averageImg = np.array([129.1863,104.7624,93.5940])    for i in range(num):        face =  np.empty([224,224,3])        if faces[i].shape[2] == 1:            image = cv2.resize(faces[i],(224,224)) # input grayscale e.g. [48,48,1], out no reduce dim for channel e.g [48,48]            face[:,:,0] = image            face[:,:,1] = image            face[:,:,2] = image        elif face[i].shape[2] == 3:            image = cv2.resize(faces[i],(224,224)) # input rgb e.g. [48,48,3], out keep dims e.g. [48,48,3]            face = image[:,:,::-1]        else:            print('channel must be 1 for grayscale or 3 for rgb')            raise ValueError        face = face - averageImg        face = face.transpose((2,0,1)) # c * h * w, for "out = net.forward_all( data = X )"        faces_resize[i] = face    return faces_resize


三、批量预测、提取中间层输出(特征)

(1)
假如要处理很多图片,一张一张的forward是很耗时的
但是也不能一次性传入太多图片,这样显存(内存)会不足
所以这里对图片分batch进行处理

def extract_feat(faces,blobname,shape):    '''    faces: num * height * width * channel    blobname: e.g. 'fc6', 'pool5' ...    shape: shape for this blob, e.g fc6: [4096] , pool5:[512,7,7]    '''    net = init_net()    num = faces.shape[0]    batch_size=50 # 每次处理的数量    iters = num/batch_size # 全部图片一共要处理多少次(iters是循环的意思,用词貌似不恰当,然而习惯了-_-||)    mod = np.mod(num,batch_size) # 余数    netdata = np.empty([num] + shape )    if mod!=0:        iters += 1 # 注意,假如batch不能整除num,最后需要再添加一次    for i in range(iters):        print('forward process %d/%d'%(i+1,iters))        idx0 = i*batch_size        if i==(iters-1) and mod!=0:            idx1 = i*batch_size+mod # 注意,假如batch不能整除num,最后处理的数量就不是batch_size而是mod了        else:            idx1 = (i+1)*batch_size        data_batch = faces[idx0:idx1] # 选取从idx0到idx1之间的数据,python中的下标规则是,假如a=[1,2,3],那么a[0:2]=[ a[0],a[1] ] = [1,2](随便写的,不要计较语法...)        netdata_batch = pro_batch(data_batch,net,blobname,shape) # 处理batch数据        netdata[idx0:idx1]=netdata_batch    return netdata


(2)

注意net.forward_all()这个函数,返回的是一个dict
很多人说用out=net.forward_all( data = faces)就可以了(faces是包含多张图片)
然而这样的话
1、out字典里只有网络最后一层的输出,对于vggface的话就是out['prob'],表示各个类别的概率
2、out里面确实保留了所有batch的输出,即如果faces是5张图片,那么out['prob']的shape就是 5*num_classes
3、关键的是,很多人用feat = net.blobs['fc6'].data来获取中间数据,实际上我再尝试的时候发现feat的num只有1个!应该是net每次forward后只保留最后一张图的数据。
那么如何批量提取中间层特征?
经过各种查考,终于找到了办法用:
feat = net.forward_all( data = faces,blobs=[blobname] ) # blobname就是layername啦,层的名字
传入要提取中间层的name,那么在最后返回的dict中,就会发现不仅有’prob‘层的值,还有我们需要的中间层输出值
可以通过
feat = net.forward_all( data = faces,blobs=[name1,name2,...] )
传递多个层的name,就可以同时获取多个中间层的输出(特征)了

def pro_batch(faces,net,blobname,shape):    '''    faces: num * height * width * channel    blobname: e.g. 'fc6', 'pool5' ...    shape: shape for this blob, e.g fc6: [4096] , pool5:[512,7,7]    '''    faces = prepare_data(faces)    netdata_batch = net.forward_all( data = faces,blobs=[blobname] )[blobname]    return netdata_batch























0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为g7开不了机怎么办 警务通手机丢了怎么办 手机被伪基站覆盖怎么办 听了高频率声音怎么办 qq音乐签到没了怎么办 手机qq音乐不能播放怎么办 台式电脑放歌没有声音怎么办 微信图片上传大愎怎么办 行车记录仪内存卡丢了怎么办 投资项目失败lp的钱怎么办 无线网无ip分配怎么办 为什么电脑的暴风影音打不开怎么办 电枪充电板进水怎么办 捡到一颗子弹该怎么办 防弹衣只保护身体那手臂怎么办? 被子被宝宝尿湿怎么办 眼睛被子弹打了怎么办 gta5买了2套衣服怎么办 gta5车被摧毁了怎么办 gta5车被损坏了怎么办 头盔玻璃磨花了怎么办 浇花喷水壶坏了怎么办 电力专用光缆撞了怎么办 国防电缆挖断了怎么办 国防光缆挖断了怎么办 房门前乱挂光纤线影响住户怎么办 挂断低于限高的光缆怎么办 开大车挂住光缆怎么办 风把树枝挂断压到车该怎么办 货车柴油冻住了怎么办 尖头鞋老是折尖怎么办 打 氟氯西林疼怎么办 多余的十字绣线怎么办 硅胶类的东西沾到蓝药水怎么办? ph计斜率不到90怎么办 ph计斜率低于90怎么办 顾客说衣服起球怎么办 买的手机壳太滑怎么办 硅胶手机壳太滑怎么办 磨砂手机壳太滑怎么办 被热胶棒烫了怎么办