caffe添加python数据层(ImageData)

caffe 添加python数据层
本文主要是详细介绍如何在caffe中添加自定义python数据层(imagedata类型)。我之所以要实现这个python数据层是因为最近准备使用caffe+LSTM结构做行为识别,需要给视频每帧添加一个clips数据层,这意味着整个网络的输入有三个(data,label,clips),而caffe中是没有的,所以就尝试使用python实现自定义数据层,废话不多说,下面就开始详细介绍如何实现python数据层(imagedata类型)。
1.修改prototxt文件,格式如下图所示
caffe添加python数据层(ImageData)_第1张图片
从上图可以看出,python_param中有三个部分:module,layer,param_str。其中module就是我们需要实现python层的文件名,如下图示:

注意,这个文件一定要和上面的prototxt文件放在同一个路径下。下面就具体看一下image_data_layer.py文件具体都需要实现哪些内容。
2.实现image_data_layer.py
在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward_cpu),在python 中是(setup,reshape,forward_cpu,backword_cpu)。下面是.py文件的具体内容:
import sys
sys.path.append('../python')
import caffe
import numpy as np
import skimage.io
from PIL import Image
import scipy
import random
class ImageDataLayer(caffe.Layer):
    """  This is a simple python datalayer for reading image data  """   def setup(self, bottom, top):
        self.top_names = ['data', 'label']

        # === Read input parameters ===

        # params is a python dictionary with layer parameters.
        params = eval(self.param_str)

        # Check the parameters for validity.
        check_params(params)

        # store input as class variables
        self.batch_size = params['batch_size']

        # Create a batch loader to load the images.
        self.batch_loader = BatchLoader(params, None)

        # === reshape tops ===
        # since we use a fixed input image size, we can shape the data layer
        # once. Else, we'd have to do it in the reshape call.
        top[0].reshape(self.batch_size, 3, params['crop_size'][0], params['crop_size'][1])

        top[1].reshape(self.batch_size, 1) #each image label is a intger

        print_info("ImageDataLayer", params)

    def forward(self, bottom, top):
        """  Load data.  """  for itt in range(self.batch_size):
            # Use the batch loader to load the next image.
            im, label = self.batch_loader.load_next_image()

            # Add directly to the caffe data layer
            top[0].data[itt, ...] = im
            top[1].data[itt, ...] = label

    def reshape(self, bottom, top):
        """  There is no need to reshape the data, since the input is of fixed size  (rows and columns)  """  pass   def backward(self, top, propagate_down, bottom):
        """  These layers does not back propagate  """  pass   class BatchLoader(object):
    """  This class abstracts away the loading of images.  Images can either be loaded singly, or in a batch. The latter is used for  the asyncronous data layer to preload batches while other processing is  performed.  """   def __init__(self, params, result):
        self.result = result
        self.source = params['source']
        self.batch_size = params['batch_size']

        self.crop_size = params['crop_size']
        self.isshuffle = params['shuffle']

        # get list of image indexes.
        self.imagelist = open(self.source, 'r').read().splitlines()

        self._cur = 0  # current image
        # this class does some simple data-manipulations
        #self.transformer = SimpleTransformer()

        print "BatchLoader initialized with {} images".format(
            len(self.imagelist))

    def load_next_image(self):
        """  Load the next image in a batch.  """  # Did we finish an epoch?
        if self._cur == len(self.imagelist):
            self._cur = 0

            if int(self.isshuffle):
                self._cur=random.randint(0,len(self.imagelist)-1)

        # Load an image
        image_sample = self.imagelist[self._cur]  # Get an image   eg: xxx.jpg 0

        im = np.asarray(Image.open(image_sample.split(' ')[0]))
        im = scipy.misc.imresize(im, self.crop_size)  # resize
        im=im/255


        # do a simple horizontal flip as data augmentation
        flip = np.random.choice(2) * 2 - 1
        im = im[:, ::flip, :]

        im = im[:, :, ::-1]  # change to BGR
        im = im.transpose((2, 0, 1))

        # Load and prepare ground truth
        #label = np.zeros(7).astype(np.float32)
        gt_classes=image_sample.split(' ')[1]
        
        #label[gt_classes] = 1  # eg: [0,1,0,0,0,0,0]
        self._cur += 1
        return im, int(gt_classes)



def check_params(params):
    """  A utility function to check the parameters for the data layers.  """  required = ['batch_size', 'source', 'crop_size']
    for r in required:
        assert r in params.keys(), 'Params must include {}'.format(r)


def print_info(name, params):
    """  Output some info regarding the class  """  print "{} initialized for with batch_size: {}, crop_size: {}.".format(
        name,params['batch_size'],params['crop_size'])



3.运行
以下是我的.sh脚本文件的具体内容:

caffe添加python数据层(ImageData)_第2张图片
上面的export PYTHONPATH=.
必须添加,不然会出现如下错误:ImportError:No module named image_data_layer错误


添加完数据层运行时出现下面问题时,想要运行自己的数据集,因此使用了Python写了数据的输入层,但是当运行的时候确报错
This program requires version 3.3.0 of the Protocol Buffer runtime library
通过问题的前几行发现问题主要出在Protocol Buffer上,说是版本太低,升级库的版本可以解决。千万不要升级,只会在这上面浪费时间。
问题原因
主要是因为caffe编译的时候默认的protobuf的版本是2.6.1,而Python通过pip install protobuf 安装的版本是最新版本3.4.0!
而在caffe环境中我们必须统一ProtoBuffer的版本才可以避免各种不易排查的错误!! 
为此,我们先卸载Python的版本ProtoBuffer,再重新安装2.6.1的版本就完美的解决了这个问题。 
操作:
pip uninstall protobuf
然后再重新安装:
pip install protobuf==2.6.1
解决。

你可能感兴趣的:(caffe学习)