为什么要从源代码构建Tensorflow?
Tensorflow是谷歌广受欢迎的机器学习库。它于2015年推出,截至撰写本文时,它是世界上最受欢迎的机器学习库。使用pip安装Tensorflow非常简单直接。但是,tensorflow的官方最佳实践指南说,如果使用CPU,最好从源代码构建Tensorflow。这是为什么?这是因为从源代码构建时,您可以编译Tensorflow以使用可用于特定CPU的所有优化。这会产生重大影响。
首先,要从源代码构建,您需要安装Bazel,然后克隆Tensorflow github存储库。详细说明可在此处找到(https://www.tensorflow.org/install/install_sources)。完成后,您需要确定选项,以便优化CPU的构建。这可以通过两种方式完成:
- 谷歌。找出您正在使用的CPU以及可用于CPU的所有优化。
- 使用这个脚本(https://gist.github.com/venik/9ba962c8b301b0e21f99884cbd35082f),适用于MacOS和Linux。它可以自动计算出您的CPU和平台,并使用所有正确的标志运行Bazel构建。
问题是它真的加快了性能吗?
首先,让我们进行基本矩阵乘法以查看加速。Python实现如下:
import tensorflow as tf
import time
m1 = []
m2 = []
result = []
i = 10
while i <= 10000:
m1.append(tf.random_uniform(shape = [i, i]))
m2.append(tf.random_uniform(shape = [i, i]))
i *= 10
for t1, t2 in zip(m1, m2):
result.append(tf.matmul(t1, t2))
sess = tf.Session()
for tensor in result:
start = time.time()
sess.run(tensor)
print(tensor.shape, time.time() - start)
结果如下:
速度从22%上升到52%,这看起来很有希望,接下来我们尝试使用神经网络。
我写了一个简单的前馈全连接神经网络分类器并使用了MNIST数据集。代码从命令行中获取了一个参数:隐藏层的数量。所以我将测试从3个隐藏层运行到10个隐藏层,每个层有1000个节点。Python代码如下:
from tensorflow.examples.tutorials.mnist import input_data
import sys
layers = int(sys.argv[1])
import tensorflow as tf
from time import time
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
hiddenLayer = tf.layers.dense(x, 1000, activation = tf.nn.tanh)
lastLayer = hiddenLayer
for i in range(layers):
lastLayer = tf.layers.dense(lastLayer, 1000, activation = tf.nn.tanh)
output = tf.layers.dense(lastLayer, 10)
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels = y_, logits = output)
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
then = time()
for _ in range(550):
print(_, end = "")
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
print(layers, time() - then)
结果如下:
正如我们所看到的,增长速度是28-43%。那么卷积神经网络(CNN)呢?
我写了一个简单的CNN网络来分类相同的MNIST数据集。网络有n个卷积层,然后是最大池化层,然后是一个的全连接隐藏层。Python代码如下:
import tensorflow as tf
tf.logging.set_verbosity(tf.logging.ERROR)
from tensorflow.examples.tutorials.mnist import input_data
from time import time
import sys
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
image_size = 28
x = tf.placeholder(tf.float32, [None, 784])
input2d = tf.reshape(x, [-1, image_size, image_size, 1])
layers = int(sys.argv[1])
conv1 = tf.layers.conv2d(inputs=input2d, filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
conv = conv1
for i in range(layers):
conv = tf.layers.conv2d(inputs=conv, filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
pool1 = tf.layers.max_pooling2d(inputs=conv, pool_size=[2, 2], strides=2)
pool_flat = tf.layers.flatten(pool1)
hidden = tf.layers.dense(inputs= pool_flat, units=1024, activation=tf.nn.relu)
output = tf.layers.dense(inputs=hidden, units=10)
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels = y_, logits = output)
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
then = time()
for _ in range(550):
print(_, end = "")
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
print(layers, time() - then)
结果如下:
加速只有18-26%,为什么呢?为什么加速降低?这是因为当你从源码构建时,最大的加速是在矩阵乘法中,因为tensorflow使用Eigen进行矩阵乘法使用CPU,这是相当优化的。前馈神经网络主要由矩阵乘法组成,其中CNN大部分时间都在卷积中。