为什么tf.nn.conv2d函数的执行时间不同而乘法次数相同?

时间:2016-11-02 09:08:21

标签: performance tensorflow deep-learning convolution conv-neural-network

我在图像分类实验中使用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. 消除操作1的卷积,一个纪元的训练时间减少23秒,意味着操作1的运行时间为23秒。

  2. 消除操作2的卷积,一个纪元的训练时间缩短13秒,意味着操作2的运行时间为13秒。

  3. 这种现象每次都可以再现。 我的gpu是nvidia gtx980Ti,os是ubuntu 16.04

    这就是问题:为什么操作1的运行时间比操作2长?

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中,该过程发现了它所期望的更多数据(即它上次被要求的位置)。净结果:更少的内存访问停顿,更快的速度。