With the rapid development of in-depth learning, there have been a lot of in-depth learning framework. These frameworks each have their own advantages and disadvantages, and Caffe as a big brother, personally think its advantage is convenient, concise. In the creation of some structural comparison of the traditional network model, with the help of Caffe we can not write a line of code, only to be based on the rules of Caffe to define the model and Solver proto files can be. The advantage of this is that we can put more time and energy into the design of the model, instead of constantly debugging the wrong place to check the code. Another point is that Caffe has an advantage over other frameworks (TensorFlow) in speed.
The advantages mentioned above is actually a major drawback of Caffe, that is, relative to other frameworks, Caffe appears less flexible, the whole training process compared to black boxes, to the adjustment of the greater difficulties. In addition, because of the lack of flexibility, when we design models and traditional networks are slightly different, we can only according to the rules of Caffe custom layer or from the source code to proceed to modify.
The problem I'm having today is the question of training multiple label tasks. Since Caffe's datum only supports a single label, and I want a piece of data to contain more than one label, how do I implement this problem? Through the rapid browsing data, found that there are about three ways to achieve the idea: Modify the Caffe source to support multiple label input (this article is very clear) HDF5 + Slice Layer,hdf5 support multiple tags, but caffe read the HDF5 will be all data in one time in memory, In the large amount of data on the memory is higher requirements, you can also fragment the data by adding slice layer layer in the Prototxt file to enable Caffe to sequentially read each data fragment. Use two data inputs (for example, two lmdb, one storage picture, one storage multiple tags), and then modify the Prototxt file configuration two data layer
From the point of view of a slag, I chose the simplest third solution. Because Lmdb also has a Python interface, I only need to use these interfaces to process my input file and save the result to two Lmdb, and then check that the picture data in the lmdb containing the data is normal and that the label is normal in the lmdb of the tag. If the two lmdb are normal after the check, then if there is an exception in the training process I can take the input data is a problem.
So I happily began to deal with my lmdb. However, things are not as smooth as I thought, Caffe read Datum's data and read it in Uint8 type, but our labels are not necessarily less than 256 and therefore cannot be stored in Uint8 type (typically in type int), and uint8 and int are of type digits. This results in Caffe not being able to read more than one label as we expected.
After discovering this problem, I realized that I could customize a simple input layer to deal with multiple label input, the only thing this input layer to do is read the input tag in int type. The code is as follows:
#!/usr/bin/env python #-*-coding:utf-8-*-# @Date: 2017-04-03 15:44:25 # @Author: Raymond Wong import OS Import SYS import NumPy as NP import Caffe Import Lmdb ' This layer are meant to read multi labels from lmdb ' ' Class Multil Abelinputlayer (Caffe.
Layer): Def setup (self, bottom, top): Assert len = 1 and len (bottom) = = 0 Params = eval (self.param_str) Self.source = params[' source '] self.batch_size = params[' batch_size '] self.env = Lmdb.open (Self.source, readonl
y=true) Self.txn = Self.env.begin () Self.cursor = Self.txn.cursor () top[0].reshape (Self.batch_size, 3, 1, 1)
def reshape (self, bottom, top): Pass Def forward (self, bottom, top): For I in Xrange (self.batch_size):
Top[0].data[i, ...] = Self.__get_one () def __get_one (self): if not Self.cursor.next (): Self.cursor.first () Datum = Caffe.proto.caffe_pb2. Datum () Datum. Parsefromstring (Self.cursor.value ()) flat_x = Np.fromstring (Datum.data, Dtype=np.int) x = Flat_x.reshape (Datum.channels, Datum.height, Datum.width) return x-Def backward (self, top, p Ropagate_down, bottom): Pass
Read the next Caffe data reader and then change the implementation again