Я пытаюсь запустить прямой проход по сверточной нейронной сети, имеющей сверточный уровень, за которым следует слой объединения и, наконец, уровень активации выпрямленной линейной единицы (ReLU). Подробности о входных данных и фильтрах сверточного слоя следующие:
X
: 4-мерные входные данные, имеющие форму [N, H, W, C]
, где N = 60000
- размер пакета, H = 32
- высота входного изображения, W = 32
- ширина входного изображения, и C = 1
- количество каналов во входном изображении.
W
: 4-мерный сверточный фильтр, имеющий форму [F, F, C, Cout]
, где F = 3
- высота и ширина фильтра, C = 1
- количество каналов во входном изображении, а Cout = 6
- это количество каналов в выходном изображении.
Для этого есть три подхода.
Подход 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()
) работает почти в 4-5 раз быстрее, чем Подход 1 и Подход 2.
Все эти эксперименты проводились на графическом процессоре NVIDIA GeForce GTX 1080.
Вопрос в том, почему мы получаем почти 4-5-кратное ускорение, просто используя tf.placeholder()
в подходе 3 по сравнению с подходом 1 и подходом 2?
В своей базовой реализации, что делает tf.placeholder()
, что позволяет ему иметь такую хорошую производительность?