微信号:SparkDaily

介绍:每日播报Spark相关技术及资讯,我们坚信Spark才是未来的通用大数据处理框架.

一文了解 Tensorflow 基础

2018-09-03 17:59 祝威廉

001

Tensorflow 基础


大部分机器学习算法(包括深度学习),其实是在一个理想空间里(接下来我们会以三维空间为例子)寻找一个最大/最小值。三维空间是无限大的,在某个实际场景,假设我们有了解决某个问题的数据的全集(或者说是无限的数据),基于这些数据我们得到的优化函数的所有解构成了一座山。

我们并不知道这座山的最低点是哪里,所以为了找到它,我们随机定位在一个点,试图沿着比较陡峭的方向下移动,并且希望能够因此而找到最低点。现实情况是我们并不能看到这座山,因为它笼罩在一阵迷雾里,我们只能根据已有的训练数据拨开一小片云雾,看到一小片地方,然后沿着比较陡峭的地方向下移动一点点,然后新进来的数据重复这个动作。

大部分机器学习算法都需要转化成我描述的这个步骤来进行。大致想下面的这个图片:

深度学习训练的过程是在优化一个数值叫Loss/Cost,我们把数据丢给网络,网络里面有大量的权重参数,经过这些参数的计算网络会最后给出一个值,由于我们的目标是努力让这个值变小,通过BP算法(其实就是偏微分的链式乘法)告诉网络,你们的权重参数应该是增加还是减少,最终完成权重参数的训练。

现在再来看看,通常一个深度学习算法有哪些构成要素:

  • 链接模式,比如全连接,卷积,残差,循环等。

  • 非线性函数,比如Relu,Sigmoid,Tanh,GRU,LSTM等

  • 优化函数,比如SGD,Momentum, Adagrad等

  • 损失函数,Cross Entroy, Adversarial等

  • 超参数,比如学习速率,批次,层大小,权重初始化等。


Tensorflow做为一个分布式深度学习的计算框架, 提供了上面的要素,他让深度学习的门槛越来越低,并且支持Python, C++, Java等多个编程语言。类似Spark DAG, TensorFlow有一个Graph的概念,本质是定义计算的图,也就是你可以先定义好计算规则,然后在Session会话里通过Placeholder把数据喂给TF完成最后的计算。

讲了那么多,没有理解也不打紧。理论的东西也不是看一篇文章能搞定的。不过Tensorflow的代码非常具有套路,按着套路走,很多情况你不了解原理也能让代码work, 甚至实现amazing的效果。

该章节读者将会学习如何利用DNN学习XOR。所谓XOR其实就是让DNN网络学习到如下的规则:

[0,0]->[0] [1,0]->[1] [1,1]->[0] [0,1]->[1] 

我们先用Tensorflow定义输入:

import tensorflow as tf
input_x = tf.placeholder(tf.int32, [None, 2], name="input_x")
input_y = tf.placeholder(tf.float32, [None, 1], name="input_y")

placeholder很好理解,就是占位符,定义接收训练数据的类型。第一个参数指定接收数据类型,第二个参数是一个shape,表示数据是一个二维数组。

None表示不确定一个batch会进来多少数据,也就是第一维是数据条数,第二维则是数组的长度。在现在的场景里,输入是一个2维的向量,输出是一个预测值。

接着定义计算图(Graph),也就是告诉TF网络结构是啥样子的,loss是啥?选用什么优化器优化Lost。

我们先定义网络结构,这次我们采用的是DNN,也就是全连接神经网络。一个典型的全连接网络如下:

一个竖列我们称为一层,所以我们可以定一个fc_layer函数:

def fc_layer(input, size_in, size_out, active="relu", name="fc"):
    with tf.name_scope(name):
        w = tf.Variable(tf.truncated_normal([size_in, size_out], stddev=0.1), name="W_" + name)
        b = tf.Variable(tf.constant(0.1, shape=[size_out], name="B_" + name))        if active == "sigmoid":
            act = tf.nn.sigmoid(tf.matmul(input, w) + b)        elif active is None:
            act = tf.matmul(input, w) + b        else:
            act = tf.nn.relu(tf.matmul(input, w) + b)        
        return act

input指的上一层的输入,size_in 表示上一层节点数目,size_out表示本层节点数。active表示本层每个节点的激活函数是什么,这里支持relu和sigmoid,name是我们给这个层取的名字。方便在可视化工具比如tensorboard上呈现。

tf.Variable 定义变量,tf.truncated_normal 构建了一个二维数组,而且随机数填充,w是一个二维数组,b是偏置,最后矩阵乘法(tf.matmul)。对于这一块,建议大家参看《深度学习》第109页。

之后根据active的值确定是采用激活函数 sigmoid还是relu进一步处理。现在,我们尝试构建一个两个隐层的网络。

fc1 = fc_layer(input_x, 2, 16, active="relu", name="fc1")fc2 = fc_layer(fc1, 16, 1, active="relu", name="fc2")

fc1 对应我们最原始的输入,向量长度是2,然后我们把fc1设置为16个激活单元,激活函数采用relu。接着把fc1作为输入提供给第二层fc2,因为最后输出是1,其实已经是预测答案了。有了这个网络之后,我们要让算法预测出来的值尽可能和标注值是一样的,我们通过欧式距离来衡量:

with tf.name_scope("cost"):
    cost = tf.reduce_mean(tf.square(input_y - fc2))

这里的tf.name_scope也是为了方便去名字。把每个样本的实际值减去预测值,然后求平均,值越小,说明预测和标注值越接近。

现在我们需要一个优化器,去执行优化的动作:

with tf.name_scope("train"):
    optimizer = tf.train.AdamOptimizer(learning_rate=0.01).minimize(cost)

很好理解,采用AdamOptimizer,以0.01作为学习速率,然后目标是最小化cost。

最后,我们要衡量下我们的准确度:

with tf.name_scope("accuracy"):
    correct_pred = tf.equal(fc2, input_y)
    accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

到目前为止,网络有了,优化的目标有了,执行优化的优化器有了,准确度衡量也有了,现在我们要开始让tensorflow运行它,但是我们还缺两个东西:

  1. 数据

  2. 让程序跑起来


数据定义比较简单:

data_x = [[0., 0.], [1., 0.], [1., 1.], [0., 1.]]data_y = [0., 1., 0., 1.]

要执行实际的逻辑,需要有一个会话的概念,也就是session:

tf.reset_default_graph
sess = tf.Session()
sess.run(tf.global_variables_initializer())

sess.run(tf.global_variables_initializer())其实对我们前面申明的哪些图啊,随机值啊做一些初始化动作。有了session,有了数据,也做了初始化, 现在就可以开始执行学习过程了。

for ep in range(1000000):    print("epoch: %d" % ep)
    batch_xs = np.reshape(data_x, [-1, 2])
    batch_ys = np.reshape(data_y, [-1, 1])
    _, cost_, accuracy_ = sess.run([optimizer, cost, accuracy], feed_dict={input_x: batch_xs, input_y: batch_ys})    print("cost: {}, accuracy_: {}".format(cost_, accuracy_))

    test_accuracy, fc2_, input_y_ = sess.run([accuracy, fc2, input_y], feed_dict={input_x: batch_xs, input_y: batch_ys})    print("{} {}".format(fc2_, input_y_))

data_x 经过reshape没变化,data_y经过reshape会变成下面这个样子:

[0., 1., 0., 1.] =>
[[0.],[ 1.],[ 0.],[ 1.]] 

然后就可以把数据丢给session:

sess.run([optimizer, cost, accuracy], feed_dict={input_x: batch_xs, input_y: batch_ys})

我这里把优化器提供给了sess,sess会按着优化器的要求进行优化。cost, accuracy是可以放进去也可以不放进去计算的。

最后为了方便看到学习过程,我把预测值也打印出来了:

test_accuracy, fc2_, input_y_ = sess.run([accuracy, fc2, input_y], feed_dict={input_x: batch_xs, input_y: batch_ys})    print("预测值:{} 标注值:{}".format(fc2_, input_y_))

大概学习到600次之后,模型就已经掌握了XOR的规律了:

epoch: 647cost: 0.0, accuracy_: 1.0预测值:[[ 0.]
 [ 1.]
 [ 0.]
 [ 1.]] 
标注值:[[ 0.]
 [ 1.]
 [ 0.]
 [ 1.]]

完整的程序如下:

import tensorflow as tfimport numpy as np

input_x = tf.placeholder(tf.float32, [None, 2], name="input_x")
input_y = tf.placeholder(tf.float32, [None, 1], name="input_y")

data_x = [[0., 0.], [1., 0.], [1., 1.], [0., 1.]]
data_y = [0., 1., 0., 1.]def fc_layer(input, size_in, size_out, active="relu", name="fc"):
    with tf.name_scope(name):
        w = tf.Variable(tf.truncated_normal([size_in, size_out], stddev=0.1), name="W_" + name)
        b = tf.Variable(tf.constant(0.1, shape=[size_out], name="B_" + name))        if active == "sigmoid":
            act = tf.nn.sigmoid(tf.matmul(input, w) + b)        elif active is None:
            act = tf.matmul(input, w) + b        else:
            act = tf.nn.relu(tf.matmul(input, w) + b)        return act


fc1 = fc_layer(input_x, 2, 16, active="relu", name="fc1")
fc2 = fc_layer(fc1, 16, 1, active="relu", name="fc2")with tf.name_scope("cost"):
    cost = tf.reduce_mean(tf.square(input_y - fc2))with tf.name_scope("train"):
    optimizer = tf.train.AdamOptimizer(learning_rate=0.01).minimize(cost)with tf.name_scope("accuracy"):
    correct_pred = tf.equal(fc2, input_y)
    accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

tf.reset_default_graph
sess = tf.Session()

sess.run(tf.global_variables_initializer())for ep in range(1000):
    print("epoch: %d" % ep)
    batch_xs = np.reshape(data_x, [-1, 2])
    batch_ys = np.reshape(data_y, [-1, 1])
    _, cost_, accuracy_ = sess.run([optimizer, cost, accuracy], feed_dict={input_x: batch_xs, input_y: batch_ys})
    print("cost: {}, accuracy_: {}".format(cost_, accuracy_))

    test_accuracy, fc2_, input_y_ = sess.run([accuracy, fc2, input_y], feed_dict={input_x: batch_xs, input_y: batch_ys})
    print("预测值:{} 标注值:{}".format(fc2_, input_y_))

sess.close()

所以我们看到,Tensorflow程序是高度套路化的,你需要做如下几步:

  1. 定义你要喂进去数据格式,也就是placeholder

  2. 建立网络结构

  3. 定义你要优化的目标值

  4. 选择优化器

  5. 定义一些指标衡量结果,比如准确率

  6. 打开session会话

  7. 执行训练过程以及验证结果

  8. 关闭会话


前面我们说到,Tensorflow让深度学习门槛变得很低,很多事情非算法工程师只要了解一些套路,然后数据足够的好,也是可以做出很好效果的。

请各位兄弟帮忙点赞转发,感谢 

↓↓↓

 
Spark技术日报 更多文章 用Python语言写Spark 一篇文章搞懂 PySpark MLlib 如何衔接Spark 和Tensorflow? Spark SQL 实战 Spark SQL 2.3.0:深入浅出
猜您喜欢 如何成为技术人中 3% 的领导者 酷派官方升级竟然带病毒,是黑客所为还是官方失误? MTSC2018 | 美团技术团队出品,精彩Topic分享邀你来现场 【SAS Says】基础篇:复制、堆叠、合并数据 108天做149稿LOGO,结果还是被吐槽成了打火机。