Tensorflow占位持有人与TensorFlow常数与Numpy阵列



我试图在具有卷积层的卷积神经网络上运行一个正向通行,然后是池层,最后是一个矫正的线性单元(relu(激活层。有关输入数据和卷积层过滤器的详细信息如下:

  • X:具有形状[N, H, W, C]的4维输入数据,其中N = 60000是批处理大小,H = 32是输入图像的高度,W = 32是输入图像的宽度,而C = 1是输入图像中的通道数。
  • W:具有形状[F, F, C, Cout]的4维卷积过滤器,其中F = 3是过滤器的高度和宽度,C = 1是输入图像中的通道数,而Cout = 6是输出图像中的通道数。li>

有三种方法可以做到这一点。

方法1:不使用tf.constant()tf.placeholder()

import numpy as np
import tensorflow as tf
X = np.random.random([60000, 32, 32, 1])
W = np.random.random([3, 3, 1, 6])
C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
A = tf.nn.relu(P)
with tf.Session() as sess:
  result = sess.run(A)       # Takes 14.98 seconds

方法2:使用tf.constant()

import numpy as np
import tensorflow as tf
X = tf.constant(np.random.random([60000, 32, 32, 1]), dtype=tf.float64)
W = tf.constant(np.random.random([3, 3, 1, 6]), dtype=tf.float64)
C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
A = tf.nn.relu(P)
with tf.Session() as sess:
  result = sess.run(A)       # Takes 14.73 seconds

方法3:使用tf.placeholder()

import numpy as np
import tensorflow as tf 
x = np.random.random([60000, 32, 32, 1])
w = np.random.random([3, 3, 1, 6])
X = tf.placeholder(dtype=tf.float64, shape=[None, 32, 32, 1])
W = tf.placeholder(dtype=tf.float64, shape=[3, 3, 1, 6])
C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
A = tf.nn.relu(P)
with tf.Session() as sess:
  result = sess.run(A, feed_dict={X:x, W:w})       # Takes 3.21 seconds

方法3(使用tf.placeholder()(比方法1和方法2快4-5倍。所有这些实验均在NVIDIA GEFORCE GTX 1080 GPU上进行。

问题是,与方法1和方法2相比,仅在方法3中使用tf.placeholder()来获得几乎4-5倍的速度?在其基本实现中,tf.placeholder()在做什么,可以具有如此良好的性能?

我分别得到12秒12秒和1秒。但是。

您的方法无法解释设置时间:图形构造,内存分配,图形优化等。我亲自推进了您的实验。也就是说,我对每种方法拨打了10个呼叫session.run((,不仅要衡量总时间,还要衡量每个单独呼叫的时间。以下是这些实验的结果。相交部分是第一个呼叫的执行时间。

%%time
import numpy as np
import tensorflow as tf
​
X = np.random.random([60000, 32, 32, 1])
W = np.random.random([3, 3, 1, 6])
​
C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
A = tf.nn.relu(P)
​
with tf.Session() as sess:
    for i in range(10):
        ts = time.time()
        result = sess.run(A)  
        te = time.time()
        print('%2.2f sec' % (te-ts))

10.44 sec
0.24 sec
0.23 sec
0.23 sec
0.23 sec
0.24 sec
0.23 sec
0.23 sec
0.24 sec
0.23 sec
CPU times: user 17 s, sys: 7.56 s, total: 24.5 s
Wall time: 13.8 s

2:

%%time
import numpy as np
import tensorflow as tf
​
X = tf.constant(np.random.random([60000, 32, 32, 1]), dtype=tf.float64)
W = tf.constant(np.random.random([3, 3, 1, 6]), dtype=tf.float64)
​
C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
A = tf.nn.relu(P)
​
with tf.Session() as sess:
    for i in range(10):
        ts = time.time()
        result = sess.run(A) 
        te = time.time()
        print('%2.2f sec' % (te-ts))

10.53 sec
0.23 sec
0.23 sec
0.24 sec
0.23 sec
0.23 sec
0.23 sec
0.23 sec
0.23 sec
0.26 sec
CPU times: user 17 s, sys: 7.77 s, total: 24.8 s
Wall time: 14.1 s

3:

    %%time
    import numpy as np
    import tensorflow as tf 
    ​
    x = np.random.random([60000, 32, 32, 1])
    w = np.random.random([3, 3, 1, 6])
    ​
    X = tf.placeholder(dtype=tf.float64, shape=[None, 32, 32, 1])
    W = tf.placeholder(dtype=tf.float64, shape=[3, 3, 1, 6])
    ​
    C = tf.nn.conv2d(X, W, strides=[1,1,1,1], padding="VALID")
    P = tf.nn.avg_pool(C, ksize=[1,2,2,1], strides=[1,2,2,1], padding="VALID")
    A = tf.nn.relu(P)
    ​
    with tf.Session() as sess:
        for i in range(10):
            ts = time.time()
            result = sess.run(A, feed_dict={X:x, W:w})  
            te = time.time()
            print('%2.2f sec' % (te-ts))
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
0.45 sec
CPU times: user 2.81 s, sys: 2.31 s, total: 5.12 s
Wall time: 5.02 s

您可以看到,对于第一个方法,首先致电SESS.run确实需要安静一段时间(10秒(,而方法3总是以0.45秒为单位。但是,前两个的第二次和进一步的运行速度是.23秒

的两倍。

大喊 @y.selivonchyk的宝贵实验,但是我觉得答案没有详细介绍为什么出现这些结果。

我相信这不是关于"占位符"的"好",而是其他两种方法是一个坏主意。

i会假定1(和2(实际上是相同的,而1(将数组转换为引擎盖下的常数 - 至少这可以解释相同的行为。

原因1(和2(花费很长时间,即constant S明确嵌入到计算图中。因为它们是相当大的张量,所以这解释了为什么该图需要这么长时间才能构建。但是,一旦构建图,随后的运行速度更快,因为其中所有内容都"包含"。通常,您应该尝试避免在图本身中包含大量数据 - 理想情况下应该是一组计算说明(即TensorFlow OPS(。

使用3(,该图的构建速度要快得多,因为我们没有嵌入其中的巨大数组,只是一个符号占位符。但是,执行速度慢于1(和2(,因为每次都需要将其值送入占位符(这也意味着如果您在一个人运行时,必须将数据传输到GPU上(。

<</p> <</p>

最新更新