最近在优化轻量化卷积神经网络,需要对模型的内存占用、FLOPs、MACCs等进行分析。
在使用caffe框架进行训练时,打印出的日志中有Memory required for data的值,以前没仔细了解过这个值是什么意思,现在得去看看代码,首先得找到这个输出语句是哪里输出的,经过查找发现,这个语句在net.cpp的init()函数中:
这个输出的值是:变量memory_used_ * 类型所占内存的大小
跟踪这个变量memory_used_:
这个值累加的是每一层的top_vecs_大小,而每一层的top_vecs_有可能包含好几个top(比如网络出现分叉或者数据层分别送到了不同的层,这时候得在这一层保存所有的top),所以通俗的讲就是:
memory_used_=0 #所需内存数
for layer in layers: #层层累加
for top in layer.tops: #每一层中的所有top累加
memory_used_+=top.count()
print(memory_used_ * 4) #假设这里是float型,占4个字节
举个例子:
这是一个关键点检测网络的头部,输入图像大小:3x48x120,我们先看一下模型训练的日志(只分析到第一个卷积层conv1_1,后面的bn层什么的先不管):
I0320 09:31:22.050493 15828 db_lmdb.cpp:39] Opened lmdb E:\dataset\CarPlateKeyPoint\foreign_countries\train_lmdb48_countries_total2
I0320 09:31:22.066486 17060 mtcnn_data_layer.cpp:57] output data size: 64,3,48,120
I0320 09:31:22.077488 17060 net.cpp:185] Setting up data
I0320 09:31:22.077488 17060 net.cpp:192] Top shape: 64 3 48 120 (1105920)
I0320 09:31:22.077488 17060 net.cpp:192] Top shape: 64 1 (64)
I0320 09:31:22.077488 17060 net.cpp:192] Top shape: 64 4 (256)
I0320 09:31:22.077488 17060 net.cpp:192] Top shape: 64 8 (512)
I0320 09:31:22.077488 17060 net.cpp:200] Memory required for data: 4427008
I0320 09:31:22.077488 17060 layer_factory.hpp:77] Creating layer label_data_1_split
I0320 09:31:22.077488 17060 net.cpp:134] Creating Layer label_data_1_split
I0320 09:31:22.077488 17060 net.cpp:473] label_data_1_split <- label
I0320 09:31:22.077488 17060 net.cpp:447] label_data_1_split -> label_data_1_split_0
I0320 09:31:22.078490 17060 net.cpp:447] label_data_1_split -> label_data_1_split_1
I0320 09:31:22.078490 17060 net.cpp:447] label_data_1_split -> label_data_1_split_2
I0320 09:31:22.078490 17060 net.cpp:447] label_data_1_split -> label_data_1_split_3
I0320 09:31:22.078490 17060 net.cpp:185] Setting up label_data_1_split
I0320 09:31:22.078490 17060 net.cpp:192] Top shape: 64 1 (64)
I0320 09:31:22.078490 17060 net.cpp:192] Top shape: 64 1 (64)
I0320 09:31:22.078490 17060 net.cpp:192] Top shape: 64 1 (64)
I0320 09:31:22.078490 17060 net.cpp:192] Top shape: 64 1 (64)
I0320 09:31:22.078490 17060 net.cpp:200] Memory required for data: 4428032
I0320 09:31:22.078490 17060 layer_factory.hpp:77] Creating layer conv1_1
I0320 09:31:22.078490 17060 net.cpp:134] Creating Layer conv1_1
I0320 09:31:22.078490 17060 net.cpp:473] conv1_1 <- data
I0320 09:31:22.078490 17060 net.cpp:447] conv1_1 -> conv1_1
I0320 09:31:22.872668 17060 net.cpp:185] Setting up conv1_1
I0320 09:31:22.872668 17060 net.cpp:192] Top shape: 64 12 48 120 (4423680)
I0320 09:31:22.872668 17060 net.cpp:200] Memory required for data: 22122752
数据层和第一个卷积层内存占用分析如下:
MTCNNData层分成了四个分支,一个传到后面的卷积层,一个是类别label,一个是bbox的label,还有一个是keypoint的label
Top shape: 64 3 48 120 (1105920)
Top shape: 64 1 (64)
Top shape: 64 4 (256)
Top shape: 64 8 (512)
Top shape: 64 1 (64)
Top shape: 64 1 (64)
Top shape: 64 1 (64)
Top shape: 64 1 (64)
总的内存需求量就是四个分支的数据大小相加,然后乘以4
total memory: (1105920+64+256+512+64+64+64+64)*4=4428032
-----------------------------------------------------------------------------------------
conv1_1层:输入 3x48x120,核大小3x3,stride=1,pad=1,输出12x48x120
Top shape: 64 12 48 120 (4423680)
总的内存需求量:前面所有层的内存需求大小+本层的所有top的内存需求大小
total memory: 4428032+ (4423680)*4=22,122,752
和前面的训练日志对照可以看到是符合计算结果的。
总结
Memory required for data这个值仅仅是统计了到当前层为止所有的数据层和feature map的大小,并没有统计各层参数所占内存,以及各层运算所需的内存。