我在图像分类实验中使用tensorflow来构建cnn net
,我发现了这样的现象:
操作1:tf.nn.conv2d(x, [3,3,32,32], strides=[1,1,1,1], padding='SAME')
x的形状为[128,128,32]
,表示在x上使用3x3内核进行卷积,输入通道和输出通道均为32,总乘法次数为
3*3*32*32*128*128=150994944
操作2:tf.nn.conv2d(x, [3,3,64,64], strides=[1,1,1,1], padding='SAME')
x的形状为[64,64,64]
,表示在x上使用3x3内核进行卷积,输入通道和输出通道均为64,总乘法次数为
3*3*64*64*64*64=150994944
与操作1相比,操作2的特征映射大小缩小到1/2并且通道号加倍。乘法次数相同,因此运行时间应相同。但实际上,操作1的运行时间比操作2长。
我的测量方法如下所示
消除操作1的卷积,一个纪元的训练时间减少23秒,意味着操作1的运行时间为23秒。
消除操作2的卷积,一个纪元的训练时间缩短13秒,意味着操作2的运行时间为13秒。
gtx980Ti
,os是ubuntu 16.04
。
这就是问题:为什么操作1的运行时间比操作2长?
答案 0 :(得分:0)
如果我不得不猜测它与图像在内存中的排序方式有关。请记住,在内存中,所有内容都以平面格式存储。这意味着如果你有一个形状张量[128,128,32],32个特征/通道将存储在每个旁边。然后是所有行,然后是所有列。 https://en.wikipedia.org/wiki/Row-major_order
访问密集存储器对性能非常重要,尤其是在具有大内存总线且针对内存访问对齐进行优化的GPU上。如果图像较大,则必须更多地跳过图像,并且内存访问更加乱序。在案例2中,您可以在订单内存访问中执行更多操作,从而提高速度。乘法是非常快速的操作。如果瓶颈限制了性能,我打赌使用卷积内存访问。
答案 1 :(得分:0)
chasep255的答案很好,可能是正确的。
另一种可能性(或者考虑chasep255的答案的另一种方式)是考虑如何缓存(所有可以加速内存提取,地址映射等的小硬件技巧)可以产生你所看到的......
你基本上有两件事:X输入数据流和静态过滤矩阵。在案例1中,您有9 * 1024个静态元素,在案例2中,您有4倍的静态元素。这两种情况都具有相同的总乘法数,但是在情况2中,该过程发现了它所期望的更多数据(即它上次被要求的位置)。净结果:更少的内存访问停顿,更快的速度。