作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Oliver Holloway
Verified Expert in Engineering

Oliver是一名多才多艺的全栈软件工程师,拥有超过7年的经验和牛津大学的研究生数学学位.

Read More

PREVIOUSLY AT

Goldman Sachs
Share

最近在人工智能领域有了一些显著的发展, 从广为宣传的自动驾驶汽车到现在的机器 composing Chopin imitations or 我只是很擅长玩电子游戏.

这些进步的核心是一些 tools 来帮助推导深度学习和其他机器学习模型, with Torch, Caffe, 而西阿诺在最前面. However, 因为谷歌大脑在2015年11月开源了他们自己的框架, TensorFlow, 我们已经看到这个软件库的受欢迎程度飙升,成为最受欢迎的深度学习框架.

TensorFlow

Why has this happened? 原因包括大量可用的支持和文档, its production readiness, 在一系列设备上分配计算的便利性, 和一个优秀的可视化工具: TensorBoard.

Ultimately, TensorFlow设法将一套全面而灵活的技术特性与易用性相结合.

In this article, 通过使用它来解决一般的数值问题,您将获得对该工具的机制的理解, 完全超出了机器学习通常涉及的范围, 在介绍它在深度学习中的应用之前,用一个简单的神经网络实现.

Before You Begin

假定具有机器学习方法的基本知识. 如果你需要赶上进度,看看这个非常有用 post.

由于我们将演示Python API,了解Numpy也是有益的.

要设置TensorFlow,请按照找到的说明进行操作 here.

如果您正在使用Windows,应该注意,在撰写本文时,您必须使用Python 3.4+, not 2.7.

然后,当你准备好了,你应该能够导入库使用:

import tensorflow as tf

TensorFlow解决方案2的第1步:创建一个图

TensorFlow程序的构建通常由两个主要步骤组成, 首先是建立一个计算图, 哪个将描述您希望执行的计算, 但不实际执行它们或保留任何值.

和任何图一样,我们有节点和边. 这些边代表张量,一个张量代表一个n维数组. For example, 维度为0的张量(在TensorFlow中为秩)是标量, rank 1 a vector, rank 2 a matrix and so on.

节点表示产生输出张量的操作,如果需要,将张量作为输入. 这些操作包括添加(tf.add), matrix multiplications (tf.matmul),以及创建常量(tf.constant).

那么,我们把这些结合起来做第一个图.

a = tf.constant([2.5, 2])
b = tf.constant([3, 6], dtype=tf.float32)
total = tf.add(a, b)

这里我们创建了三个操作,其中两个用于创建常量一维数组.

数据类型是从传入的values参数推断出来的,或者您可以使用 dtype argument. 如果我没有这么做 b, then an int32 将被推断并抛出错误为 tf.add 会试图在两个不同的类型上定义一个加法吗.

TensorFlow解决方案2的第2步:执行操作

The graph is defined, 但为了在它(或它的任何部分)上实际做任何计算,我们必须建立一个TensorFlow会话.

sess = tf.Session()

或者,如果我们在交互式shell中运行会话,比如IPython,那么我们使用:

sess = tf.InteractiveSession()

The run 方法是计算张量的一种方法.

Therefore, 来计算上面定义的加法计算, we pass ‘total’, the Tensor to retrieve, 的输出是什么 tf.add op.

print(sess.run(total)) # [ 5.5  8. ]

现在,我们引入TensorFlow的Variable类. 常量是图定义的固定部分,而变量可以更新. 类构造函数需要一个初始值, but even then, 在对变量执行任何其他操作之前,需要对其进行显式初始化操作.

变量保存了特定会话中图形的状态,因此我们应该观察使用相同图形的多个会话会发生什么,以便更好地理解变量.

#创建一个初始值为1的变量
some_var = tf.Variable(1)

#创建op来运行变量初始化器
init_op = tf.global_variables_initializer ()
 
#创建一个op将some_var保存的值替换为3
assign_op = some_var.assign(3)
 
#建立会话的两个实例
sess1 = tf.Session()
sess2 = tf.Session()

#在两个会话中初始化变量
sess1.run(init_op)
sess2.run(init_op)
print(sess1.run(some_var)) # Outputs 1

#修改session1的some_var
sess1.run(assign_op)
print(sess1.run(some_var)) # Outputs 3
print(sess2.run(some_var)) # Outputs 1

# Close sessions
sess1.close()
sess2.close()

我们已经建立了图表和两个会话.

在两个会话上执行初始化后(如果我们不运行此操作,然后对变量求值,则会出现错误),我们只在一个会话上执行assign操作. 可以看到,变量值持续存在,但不是跨会话.

用图来解决数值问题

TensorFlow的另一个重要概念是占位符. 而变量保持状态, 占位符用于定义图形可以期望的输入及其数据类型(以及可选的形状). 然后,当我们运行计算时,我们可以通过这些占位符将数据输入到图中.

TensorFlow图开始类似于我们最终想要训练的神经网络, but before that, 让我们用这些概念来解决金融领域的一个常见数值问题.

Suppose we want to find y in an equation like this:

v = Ce-0.5y+ Ce-y+Ce-1.5y+(C+P)e-2y

for a given v (with C and P constant).

这是一个计算到期收益率(y)对具有市场价值的债券 v, principal P, and coupon C 每半年支付一次,但现金流以连续复利贴现.

我们基本上必须用试错法来解这样的方程, 我们将选择等分法来将最终值归零 y.

首先,我们将这个问题建模为一个TensorFlow图.

C and P 固定常数和构成图形定义的一部分吗. 我们希望有一个过程来细化的下限和上限 y. 因此,这些界限表示为 a and b)是每次猜测后需要更改的变量的良好候选者 y (被认为是…的中点 a and b).

指定常量操作将输出的值
C = tf.constant(5.0)
P = tf.constant(100.0)

我们指定初始化时的下界和上界的初始值.
显然,这个算法的最终成功取决于合适的起点
a = tf.Variable(-10.0)
b = tf.Variable(10.0)
 
我们期望在图中插入一个浮点数
v_target = tf.placeholder("float")
 
记住下面的操作都是定义,
在会话中执行操作之前,不执行任何操作!
y = (a+b)/2
v_guess = C*tf.exp(-0.5*y) + C*tf.exp(-y) + C*tf.exp(-1.5*y) + (C + P)*tf.exp(-2*y)
 
设置临时值(a_和b_)作为a和b的下一个值的操作.
# e.g. 如果猜测的结果是v大于目标v,
我们将设置a_为y的当前值
a_ = tf.where(v_guess > v_target, y, a)
b_ = tf.where(v_guess < v_target, y, b)
 
图的最后一步是给变量赋两个临时值
step = tf.group( a.assign(a_), b.assign(b_) )

现在我们有了一个操作和变量的列表, 其中任何一个都可以根据特定的会话进行评估. 其中一些操作依赖于其他操作来运行,比如, v_guess 会引发链式反应得到其他张量,比如 C and P, to be evaluated first.

其中一些操作依赖于需要为其指定值的占位符, 那么我们该如何把这个价值灌输进去呢?

This is done through the feed_dict argument in the run function itself.

If we want to evaluate a_,我们为占位符插入值 v_target, like so:

sess.运行(a_, feed_dict={v_target: 100})

giving us 0.0.

Plug in a v_target of 130 and we get -10.0.

这是我们的“步进”操作,它实际上需要执行所有其他操作作为先决条件,并且实际上执行整个图. 它也是一个在整个会话中改变实际状态的操作. 因此,我们运行的步骤越多,我们对变量的增量调整就越多 a and b 的实际值 y.

So, let’s say our value for v 在方程中等于95. 让我们建立一个会话并在其上执行我们的图表100次.

#建立会话并初始化变量
sess = tf.Session()
tf.global_variables_initializer ().run()
#运行步进操作(因此整个图)100次
for i in range (100):
	sess.运行(步骤,feed_dict = {v_target: 95})

If we evaluate the y 张量,我们得到了一个理想的答案

print(sess.run(y)) # 0.125163

Neural Networks

现在我们已经了解了TensorFlow的机制, 我们可以将它与内置在TensorFlow中的一些额外的机器学习操作结合起来,来训练一个简单的神经网络.

Here, 我们希望在二维坐标系中对数据点进行分类,这取决于它们是否属于一个特定的区域——一个半径为0的圆.5 centered at the origin.

当然,这可以通过检查一个给定的点来具体验证 (a,b) if a^2 + b^2 < 0.5, 但是为了这个机器学习实验的目的, 我们想传递一个训练集:一系列随机点,以及它们是否落在我们的预期区域内. 这里有一种创建方法:

import numpy as np
NO_OF_RANDOM_POINTS = 100
CIRCLE_RADIUS = 0.5
random_spots = np.random.rand(NO_OF_RANDOM_POINTS, 2) * 2 - 1
is_inside_circle = (np.Power (random_spots[:,0],2) + np.power(random_spots[:,1],2) < CIRCLE_RADIUS).astype(int)

我们将制作一个具有以下特征的神经网络:

  1. 它由一个带有两个节点的输入层组成, 其中,我们输入包含在random_spots中的一系列二维向量. 这将由等待训练数据的占位符表示.
  2. 输出层也将有两个节点, 因此,我们需要将我们的一系列训练标签(“is_inside_circle”)提供给标量的占位符, 然后把这些值转换成一维二维向量.
  3. 我们将有一个由三个节点组成的隐藏层, 所以我们需要用变量来表示我们的权重矩阵和偏置向量, 因为这些是在执行训练时需要改进的值.
INPUT_LAYER_SIZE = 2
HIDDEN_LAYER_SIZE = 3
OUTPUT_LAYER_SIZE = 2
 
#权重和偏差的起始值随机且均匀地从[- 1,1]中提取
例如,W1是形状为2x3的矩阵
W1 = tf.Variable(tf.random_uniform([INPUT_LAYER_SIZE, HIDDEN_LAYER_SIZE], -1, 1))
b1 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE], -1, 1))
W2 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE, OUTPUT_LAYER_SIZE], -1, 1))
b2 = tf.Variable(tf.random_uniform([OUTPUT_LAYER_SIZE], -1, 1))
#指定占位符X可以期望一个2列(但任意行数)的矩阵
# representing random spots
X = tf.placeholder(tf.float32, [None, INPUT_LAYER_SIZE])
#占位符Y可以期望整数表示相应的点是否在圆中
#或否(没有指定形状)
Y = tf.placeholder(tf.uint8)
将op转换为单热向量
onehot_output = tf.OUTPUT_LAYER_SIZE one_hot (Y)

来完成图的定义, 我们定义了一些操作,这些操作将帮助我们训练变量以获得更好的分类器. 其中包括矩阵计算、激活函数和优化器.

LEARNING_RATE = 0.01
# Op执行矩阵计算X*W1 + b1
hidden_layer = tf.add(tf.matmul(X, W1), b1)
#在结果上使用sigmoid激活函数
activated_hidden_layer = tf.sigmoid(hidden_layer)
#应用下一个权重和偏差(W2, b2)到隐藏层,然后应用softmax功能
#来得到我们的输出层(每个向量加起来等于1)
output_layer = tf.nn.softmax(tf.add(tf.matmul(activated_hidden_layer, W2), b2)
计算损失函数的交叉熵
loss = -tf.Reduce_sum (onehot_output * tf.log(output_layer))
#使用梯度下降优化器在指定的学习率最小化损失张量给出的值
train_step = tf.train.GradientDescentOptimizer (LEARNING_RATE).minimize(loss)

Having set up our graph, 现在是时候建立一个会话并运行“train_step”(它还运行任何必要的操作)了。. 其中一些操作使用占位符,因此需要为它们提供值. 这个训练步骤代表了我们学习算法中的一个epoch, as such, 在我们希望运行的历元数上循环. 我们可以运行图的其他部分,例如用于信息目的的“损失”张量.

EPOCH_COUNT = 1000
sess = tf.Session()
tf.global_variables_initializer ().run()
for i in range(EPOCH_COUNT):
    if i%100 == 0:
    	print(' %d运行后丢失:%f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle}))
	sess.运行(train_step, feed_dict={X: random_spots, Y: is_inside_circle})
print(' %d运行后的最终损失:%f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle}))

一旦我们训练了算法, 我们可以输入一个点并得到神经网络的输出,如下所示:

sess.run(output_layer, feed_dict={X:[[1,1]]}) #希望接近[1,0]
sess.run(output_layer, feed_dict={X:[[0,0]]}) #希望接近[0,1]

如果输出向量的第一个元素大于0,我们可以把这个点归为圆外.5, inside otherwise.

By running the output_layer tensor for many points, 我们可以知道学习者是如何设想包含正分类点的区域的. 训练集的大小是值得考虑的, the learning rate, 还有其他参数,看看我们能多接近我们想要的圆.

Almost triangle

Small triangle

Large triangle

Almost circle

Wrap Up

这是一个很好的教训,增加的训练集或epoch数量并不能保证一个好的学习者——学习率应该适当调整.

Hopefully, 这些演示让您对TensorFlow的核心原理有了很好的了解, 并为实现更复杂的技术提供坚实的基础.

我们还没有涵盖诸如Tensorboard或跨gpu训练我们的模型等概念, 但是这些都很好地覆盖在 TensorFlow documentation. 在文档中可以找到许多食谱,可以帮助您使用这个强大的框架快速处理令人兴奋的深度学习任务!

Understanding the basics

  • What is a dataflow graph?

    数据流图是一种计算图, 它描述了您希望执行但实际上不执行或不保存任何值的计算.

  • 什么是TensorFlow变量?

    TensorFlow中的变量保存了特定会话中图的状态. 而TensorFlow图中的常量是图定义的固定部分, 变量可以使用操作来更新.

聘请Toptal这方面的专家.
Hire Now
Oliver Holloway

Oliver Holloway

Verified Expert in Engineering

London, United Kingdom

Member since May 10, 2016

About the author

Oliver是一名多才多艺的全栈软件工程师,拥有超过7年的经验和牛津大学的研究生数学学位.

Read More
作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

PREVIOUSLY AT

Goldman Sachs

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.