caffe:debug之数据预取流程
在caffe中我们经常会看到数据读取,但对其入口函数却无从下手。其实训练和预取数据在caffe中是使用了不同的线程,所以在网络训练流程中找不到数据读取的源码。现在我们来分析一下caffe的另一个线程,perfetchingData。读取数据在搭建网络,第一次测试所给权重损失(TestAll),和整个网路训练测试时候的前向传播(Forward(layer.cpp))中都频繁出现。具体如下:
首先当一个操作指向了数据层,需要取数据时会进入到BasePrefetchingDataLayer(base_data_layer.cpp)
具体如下:
此处的return也是返回的一个函数,对于每一层创建不同的层类型,例如第一层是Data,即数据层,位于data_layer.cpp
此宏定义如下
进入
成功进入 BaseprefetchingDataLayer(实现位于base_data_layer.cpp)
BasePrefetchingDataLayer是一个模板类,继承了BaseDataLayer和InternalThread
此模板类具体如下:
我们的debug进入其构造函数:
然后首先看其初始化列表BaseDataLayer(base_data_layer.cpp)的构造函数
继续深入。进入其初始化列表Layer(layer.hpp)构造函数
(重点要来了)然后看其第二个父类InternalThread的构造函数,此线程就是用来读取数据的
此类的介绍为
意思是是要实现了上述函数即可创建一个自己想要的新的线程
在此类中还包含了一个startThread函数在此函数中开了一个线程
线程如下,回调入口函数为entry
在entry的最后就包含了我们所需要实现的InternalThreadEntry()
在BasePrefetchingDataLayer构造函数执行完后进入DataLayer(data_layer.cpp)
然后进入DataReader(data_reader.cpp)
其构造函数中函数Body(data_reader.cpp)于是找到
终于找到了心心念念的StartInternalThread,于是按照上述所说,创建一个新的线程。
在data_reader.cpp中找到我们要实现的InternalThreadEntry函数
不难看到
此处便是要读取的数据的类型
然后我们接着往下看 看到了两个read_one函数,如果没理解错,第一个read_one应该是检查用,而第二个是训练时取数据所使用的。但read_one内容一样
read_one(data_reader.cpp)具体实现
当read_one执循环执行读取数据后线程获取到InternalThreadEntry
进入load_batch(实现位于data_layer.cpp)
其实现如下
当然 在数据读取时首先读取的是datum然后从datum转换为blob,在转换过程中实现了对图片的处理,如宽高,和我们之前定义的均值文件等,确保数据在网络中可以正确运行计算。数据转换位于(data_transformer.cpp)
于是会有
中的
其源码为
同时 !!! 在layersetup中也有此函数,也就是说,当创建该层的时候,另一个线程就开始运行。