文档章节

TensorFlow从1到2(一)续讲从锅炉工到AI专家

o
 osc_gu9d45li
发布于 2019/04/07 09:57
字数 4430
阅读 3
收藏 0

精选30+云产品,助力企业轻松上云!>>>

引言

原来引用过一个段子,这里还要再引用一次。是关于苹果的。大意是,苹果发布了新的开发语言Swift,有非常多优秀的特征,于是很多时髦的程序员入坑学习。不料,经过一段头脑体操一般的勤学苦练,发现使用Swift做开发,不仅要学习Swift,还要学习Swift2、Swift3、Swift4...
后来我发现,这个段子很有普遍性,并非仅仅苹果如此,今天的TensorFlow 2.0也有点这样的趋势。以至于我不得不专门写一个课程的续集,来面对使用新版本软件开始机器学习的读者。
事实上大多具有革命性的公司都是这样,一方面带来令人兴奋的新特征,另一方面则是高企不落的学习成本。

《从锅炉工到AI专家》一文中,已经对机器学习的基本概念做了很详细的介绍。所以在这里我们就省掉闲言絮语,直接从TensorFlow2.0讲起。
当然即便没有看过这个系列,假设你对TensorFlow 1.x很熟悉,也可以直接通过阅读本文,了解从TensorFlow 1.x迁移至2.x的知识。
如果你不了解机器学习的概念,试图通过直接学习TensorFlow 2.0开始AI开发,那可能比较困难。TensorFlow只是工具。没有技能,只凭工具,你恐怕无法踏上旅程。

安装

截至本文写作的时候,TensorFlow 2.0尚未正式的发布。pip仓库中仍然是1.13稳定版。所以如果想开始TensorFlow 2.0的学习,需要指定版本号来安装。此外由于Python2系列将于2020年元月停止官方维护,本文的示例使用Python3的代码来演示:

$ pip3 install tensorflow==2.0.0-alpha0

(注: 上面$是Mac/Linux的提示符,假如用Windows,你看到的提示符应当类似C:\Users\Administrator>这样子。)

如果希望使用GPU计算,安装的预先准备会麻烦一些,请参考这篇文档:https://www.tensorflow.org/install/gpu。主要是安装CUDA/cuDNN等计算平台的工具包。其中CUDA可以使用安装程序直接安装。cuDNN是压缩包,如果不打算自己编译TensorFlow的话,放置到CUDA相同目录会比较省事。
这里提醒一下,除非自己编译TensorFlow,否则一定使用CUDA 10.0的版本,低了、高了都不成,因为官方的2.0.0-alpha0使用了CUDA 10.0的版本编译。
此外TensorFlow的安装请使用如下命令:

$ pip3 install tensorflow-gpu==2.0.0-alpha0

安装完成后,可以在Python的交互模式,来确认TensorFlow正常工作:

$ python3
Python 3.7.2 (default, Feb 13 2019, 13:59:29) 
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> tf.__version__
'2.0.0-alpha0'
>>> 

本文中还会用到几个第三方的python扩展库,也是在机器学习中非常常用的,建议一起安装:

$ pip3 install numpy matplotlib pillow pandas seaborn sklearn

第一个例子:房价预测

本示例中的源码来自于《从锅炉工到AI专家》系列2,使用了最简单的线性函数来做房价预测。原始TensorFlow 1.x/ Python 2.x代码如下:

#!/usr/bin/env python 
# -*- coding=UTF-8 -*-

#本代码在mac电脑,python2.7环境测试通过
#第一行是mac/Linux系统脚本程序的标志,表示从环境参量中寻找python程序解释器来执行本脚本
#省去了每次在命令行使用 python <脚本名> 这样的执行方式
#第二行表示本脚本文本文件存盘使用的代码是utf-8,并且字符串使用的编码也是utf-8,
#在本源码中,这一点其实没有什么区别,但如果需要中文输出的时候,这一行就必须要加了。

#引入TensorFlow库
import tensorflow as tf
#引入数值计算库
import numpy as np

#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
# np.dot的意思就是向量x * 0.5
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
#以下使用TensorFlow构建数学模型,在这个过程中,
#直到调用.run之前,实际上都是构造模型,而没有真正的运行。
#这跟上面的numpy库每一次都是真正执行是截然不同的区别
# 请参考正文,我们假定房价的公式为:y=a*x+b

#tf.Variable是在TensorFlow中定义一个变量的意思
#我们这里简单起见,人为给a/b两个初始值,都是0.3,注意这也是相当于规范化之后的数值
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))

#这是定义主要的数学模型,模型来自于上面的公式
#注意这里必须使用tf的公式,这样的公式才是模型
#上面使用np的是直接计算,而不是定义模型
# TensorFlow的函数名基本就是完整英文,你应当能读懂
y_value = tf.multiply(x,a) + b

# 这里是代价函数,同我们文中所讲的唯一区别是用平方来取代求绝对值,
#目标都是为了得到一个正数值,功能完全相同,
#平方计算起来会更快更容易,这种方式也称为“方差“
loss = tf.reduce_mean(tf.square(y_value - y))
# TensorFlow内置的梯度下降算法,每步长0.5
optimizer = tf.train.GradientDescentOptimizer(0.5)
# 代价函数值最小化的时候,代表求得解
train = optimizer.minimize(loss)

# 初始化所有变量,也就是上面定义的a/b两个变量
init = tf.global_variables_initializer()

#启动图
sess = tf.Session()
#真正的执行初始化变量,还是老话,上面只是定义模型,并没有真正开始执行
sess.run(init)

#重复梯度下降200次,每隔5次打印一次结果
for step in xrange(0, 200):
    sess.run(train)	
    if step % 5 == 0:
        print step, sess.run(loss),sess.run(a), sess.run(b)

代码保留了原始的注释,希望如果概念已经没有问题的话,可以让你不用跑回原文去看详细讲解。
程序使用numpy生成了一组样本集,样本集是使用线性函数生成的。随后使用TensorFlow学习这些样本,从而得到线性函数中未知的权重(Weight)和偏移(Bias)值。
原文中已经说了,这个例子并没有什么实用价值,只是为了从基础开始讲解“机器学习”的基本原理。

使用2.0中的v1兼容包来沿用1.x代码

TensorFlow 2.0中提供了tensorflow.compat.v1代码包来兼容原有1.x的代码,可以做到几乎不加修改的运行。社区的contrib库因为涉及大量直接的TensorFlow引用代码或者自己写的Python扩展包,所以无法使用这种模式。TensorFlow 2.0中也已经移除了contrib库,这让人很有点小遗憾的。
使用这种方式升级原有代码,只需要把原有程序开始的TensorFlow引用:

import tensorflow as tf

替换为以下两行就可以正常的继续使用:

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

其它代码无需修改。个人觉得,如果是稳定使用中、并且没有重构意愿的代码,这种方式算的上首选。

使用迁移工具来自动迁移1.x代码到2.0

TensorFlow 2.0中提供了命令行迁移工具,来自动的把1.x的代码转换为2.0的代码。工具使用方法如下(假设我们的程序文件名称为first-tf.py):

tf_upgrade_v2 --infile first-tf.py --outfile first-tf-v2.py

迁移工具还可以对整个文件夹的程序做升级,请参考工具自身的帮助文档。
使用迁移工具升级的代码,实质上也是使用了tensorflow.compat.v1兼容包来提供在TensorFlow 2.0环境中执行1.x的代码。这里贴出自动转换后的新代码供你对比参考:

#引入TensorFlow库
import tensorflow as tf
#import tensorflow.compat.v1 as tf
tf.compat.v1.disable_v2_behavior()

#引入数值计算库
import numpy as np

#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
# np.dot的意思就是向量x * 0.5
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
#以下使用TensorFlow构建数学模型,在这个过程中,
#直到调用.run之前,实际上都是构造模型,而没有真正的运行。
#这跟上面的numpy库每一次都是真正执行是截然不同的区别
# 请参考正文,我们假定房价的公式为:y=a*x+b

#tf.Variable是在TensorFlow中定义一个变量的意思
#我们这里简单起见,人为给a/b两个初始值,都是0.3,注意这也是相当于规范化之后的数值
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))

#这是定义主要的数学模型,模型来自于上面的公式
#注意这里必须使用tf的公式,这样的公式才是模型
#上面使用np的是直接计算,而不是定义模型
# TensorFlow的函数名基本就是完整英文,你应当能读懂
y_value = tf.multiply(x,a) + b

# 这里是代价函数,同我们文中所讲的唯一区别是用平方来取代求绝对值,
#目标都是为了得到一个正数值,功能完全相同,
#平方计算起来会更快更容易,这种方式也称为“方差“
loss = tf.reduce_mean(input_tensor=tf.square(y_value - y))
# TensorFlow内置的梯度下降算法,每步长0.5
optimizer = tf.compat.v1.train.GradientDescentOptimizer(0.5)
# 代价函数值最小化的时候,代表求得解
train = optimizer.minimize(loss)

# 初始化所有变量,也就是上面定义的a/b两个变量
init = tf.compat.v1.global_variables_initializer()

#启动图
sess = tf.compat.v1.Session()
#真正的执行初始化变量,还是老话,上面只是定义模型,并没有真正开始执行
sess.run(init)

#重复梯度下降200次,每隔5次打印一次结果
for step in range(0, 200):
    sess.run(train)	
    if step % 5 == 0:
        print(step, sess.run(loss),sess.run(a), sess.run(b))

转换之后,代码中的注释部分会完美的保留,喜欢用代码来代替文档的程序员可以放心。所有2.0中变更了的类或者方法,转换工具将使用tensorflow.compat.v1中的对应类或方法来替代,比如:

optimizer = tf.compat.v1.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
init = tf.compat.v1.global_variables_initializer()

所以从本质上,这种方式跟第一种方法,采用tensorflow.compat.v1包作为tensorflow替代包的方式是完全相同的。

编写原生的TensorFlow 2.0程序

推荐的演进方式,当然还是学习TensorFlow 2.0的相关特征,重构原有代码为新版本代码才是正路。平心而论,毕竟绝大多数系统的升级都是为了提供更多功能和降低使用门槛。TensorFlow 2.0也是大幅的降低了使用门槛的。大多数的工作比起1.x版本来,都能使用更少的代码量来完成。
首先了解一下TensorFlow 2.0同1.x之间的重要区别:

  • 在API层面的类、方法有了较大的变化,这个需要在使用中慢慢熟悉
  • 取消了Session机制,每一条命令直接执行,而不需要等到Session.run
  • 因为取消了Session机制,原有的数学模型定义,改为使用Python函数编写。原来的feed_dict和tf.placeholder,成为了函数的输入部分;原来的fetches,则成为了函数的返回值。
  • 使用keras的模型体系对原有的TensorFlow API进行高度的抽象,使用更容易
  • 使用tf.keras.Model.fit来替代原有的训练循环。

正常情况下,最后一项tf.keras.Model.fit能够大大的降低训练循环的代码量。但在本例中,我们模拟了一个现实中并不适用的例子,keras中并未对这种情形进行优化。所以在本例中反而无法使用tf.keras.Model.fit(实际上一定要使用也是可以的,不过要自定义模型,工作量更不划算)。因此本例中仍然要自己编写训练循环。并且因为2.0中API的变化,代码更复杂了。不过相信我,等到比较正式应用中,使用神经网络、卷积等常用算法,代码就极大的简化了。
使用TensorFlow 2.0原生代码的程序代码如下:

#!/usr/bin/env python3
#上面一行改为使用python3解释本代码

#引入python新版本的语言特征
from __future__ import absolute_import, division, print_function

#引入TensorFlow库,版本2.0
import tensorflow as tf

#引入数值计算库
import numpy as np

#使用 NumPy 生成假数据集x,代表房间的平米数,这里的取值范围是0-1的浮点数,
#原因请看正文中的说明,属于是“规范化”之后的数据
# 生成的数据共100个,式样是100行,每行1个数据
x = np.float32(np.random.rand(100,1))
#我们假设每平米0.5万元,基础费用0.7万,这个数值也是规范化之后的,仅供示例
#最终运行的结果,应当求出来0.5/0.7这两个值代表计算成功
#计算最终房价y,x和y一同当做我们的样本数据
y = np.dot(x,0.5) + 0.7
#---------------------------------数据集准备完成
# 请参考正文,我们假定房价的公式为:y=a*x+b
#定义tensorflow变量,a是权重,b是偏移
b = tf.Variable(np.float32(0.3))
a = tf.Variable(np.float32(0.3))

#以上代码基本同tensorflow1.x版本一致
#以下有了区别
#使用python语言定义数学模型,模型来自于上面的公式
#上面使用np的是直接计算得到训练样本,而不是定义模型
#模型中并非必须使用tensorflow的计算函数来代替python的乘法运算
@tf.function
def model(x):
        return a*x+b

#定义代价函数,也是python函数
def loss(predicted_y, desired_y):
    return tf.reduce_sum(tf.square(predicted_y - desired_y))

# TensorFlow内置Adam算法,每步长0.1
optimizer = tf.optimizers.Adam(0.1)
# 还可以选用TensorFlow内置SGD(随机最速下降)算法,每步长0.001
#不同算法要使用适当的步长,步长过大会导致模型无法收敛
#optimizer = tf.optimizers.SGD(0.001)

#重复梯度下降200次,每隔5次打印一次结果
for step in range(0, 200):
        with tf.GradientTape() as t:
                outputs = model(x)	#进行一次计算
                current_loss = loss(outputs, y)	#得到当前损失值
                grads = t.gradient(current_loss, [a, b])	#调整模型中的权重、偏移值
                optimizer.apply_gradients(zip(grads,[a, b]))	#调整之后的值代回到模型
        if step % 5 == 0:	#每5次迭代显示一次结果
                print( "Step:%d loss:%%%2.5f weight:%2.7f bias:%2.7f " % 
                        (step,current_loss.numpy(), a.numpy(), b.numpy()))

程序在升级中所做的修改和特殊的处理,都使用注释保留在了源码中。我觉得这种方式比打散摘出来讲解的能更透彻。
最后看一下新版程序的执行结果:

Step:0 loss:%25.78244 weight:0.4000000 bias:0.4000000 
Step:5 loss:%2.71975 weight:0.7611420 bias:0.7740188 
Step:10 loss:%3.09600 weight:0.6725605 bias:0.7224629 
Step:15 loss:%0.87834 weight:0.4931822 bias:0.5800986 
Step:20 loss:%1.24737 weight:0.4960071 bias:0.6186275 
Step:25 loss:%0.22444 weight:0.5730734 bias:0.7264798 
Step:30 loss:%0.47145 weight:0.5464076 bias:0.7252067 
Step:35 loss:%0.09156 weight:0.4736322 bias:0.6712209 
Step:40 loss:%0.14845 weight:0.4771673 bias:0.6866464 
Step:45 loss:%0.06199 weight:0.5101752 bias:0.7255269 
Step:50 loss:%0.03108 weight:0.4946054 bias:0.7112849 
Step:55 loss:%0.04115 weight:0.4770990 bias:0.6918764 
Step:60 loss:%0.00145 weight:0.4950625 bias:0.7060429 
Step:65 loss:%0.01781 weight:0.5029647 bias:0.7096580 
Step:70 loss:%0.00211 weight:0.4934593 bias:0.6963260 
Step:75 loss:%0.00298 weight:0.4983235 bias:0.6982682 
Step:80 loss:%0.00345 weight:0.5049748 bias:0.7031375 
Step:85 loss:%0.00004 weight:0.5001755 bias:0.6976562 
Step:90 loss:%0.00102 weight:0.5002422 bias:0.6978318 
Step:95 loss:%0.00065 weight:0.5029225 bias:0.7010939 
Step:100 loss:%0.00001 weight:0.5000774 bias:0.6990223 
Step:105 loss:%0.00021 weight:0.4996552 bias:0.6993059 
Step:110 loss:%0.00015 weight:0.5007215 bias:0.7008768 
Step:115 loss:%0.00000 weight:0.4993480 bias:0.6997767 
Step:120 loss:%0.00003 weight:0.4995552 bias:0.7000407 
Step:125 loss:%0.00004 weight:0.5001000 bias:0.7004969 
Step:130 loss:%0.00001 weight:0.4995880 bias:0.6998325 
Step:135 loss:%0.00000 weight:0.4999941 bias:0.7000810 
Step:140 loss:%0.00001 weight:0.5001197 bias:0.7000892 
Step:145 loss:%0.00000 weight:0.4999250 bias:0.6998329 
Step:150 loss:%0.00000 weight:0.5001498 bias:0.7000451 
Step:155 loss:%0.00000 weight:0.5000388 bias:0.6999565 
Step:160 loss:%0.00000 weight:0.4999948 bias:0.6999494 
Step:165 loss:%0.00000 weight:0.5000526 bias:0.7000424 
Step:170 loss:%0.00000 weight:0.4999576 bias:0.6999717 
Step:175 loss:%0.00000 weight:0.4999971 bias:0.7000214 
Step:180 loss:%0.00000 weight:0.4999900 bias:0.7000131 
Step:185 loss:%0.00000 weight:0.4999775 bias:0.6999928 
Step:190 loss:%0.00000 weight:0.5000094 bias:0.7000152 
Step:195 loss:%0.00000 weight:0.4999923 bias:0.6999906 

模型通过学习后,得到的结果是很接近我们的预设值的。
程序中还可以考虑使用随机快速下降算法(SGD),你可以把当前的Adam算法使用注释符屏蔽上,打开SGD算法的注释屏蔽来尝试一下。对于本例中的数据集来讲,SGD的下降步长需要的更小,同样循环次数下,求解的精度会低一些。可以看出对于本例,Adam算法显然是更有效率的。而在TensorFlow的支持下,对于同样的数据集和数学模型,变更学习算法会很容易。

(待续...)

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
从锅炉工到AI专家 ---- 系列教程

TensorFlow从1到2(十二)生成对抗网络GAN和图片自动生成 那些令人惊艳的TensorFlow扩展包和社区贡献模型 从锅炉工到AI专家(11)(END) 从锅炉工到AI专家(10) 从锅炉工到AI专家(9) 从锅炉工到A...

osc_5xuqrjao
2019/05/07
10
0
tensorflow兼容处理 tensorflow.compat.v1

https://www.wandouip.com/t5i183316/ 引言 原来引用过一个段子,这里还要再引用一次。是关于苹果的。大意是,苹果发布了新的开发语言Swift,有非常多优秀的特征,于是很多时髦的程序员入坑学...

osc_vf6gypzr
2019/09/02
8
0
TensorFlow从1到2(十三)图片风格迁移

风格迁移 《从锅炉工到AI专家(8)》中我们介绍了一个“图片风格迁移”的例子。因为所引用的作品中使用了TensorFlow 1.x的代码,算法也相对复杂,所以文中没有仔细介绍风格迁移的原理。 今天在...

osc_hrz7rg5h
2019/05/09
1
0
TensorFlow从1到2(二)续讲从锅炉工到AI专家

图片样本可视化 原文第四篇中,我们介绍了官方的入门案例MNIST,功能是识别手写的数字0-9。这是一个非常基础的TensorFlow应用,地位相当于通常语言学习的"Hello World!"。 我们先不进入Tenso...

osc_gu9d45li
2019/04/10
1
0
从锅炉工到AI专家(7)

说说计划 不知不觉写到了第七篇,理一下思路: 学会基本的概念,了解什么是什么不是,当前的位置在哪,要去哪。这是第一篇希望做到的。同时第一篇和第二篇的开始部分,非常谨慎的考虑了非IT专...

osc_mf6gua6n
2018/03/09
2
0

没有更多内容

加载失败,请刷新页面

加载更多

Saga分布式事务框架

1优点 1、避免服务之间的循环依赖,因为saga协调器会调用saga参与者,但参与者不会调用协调器 2、集中分布式事务编排 3、降低参与者的复杂性 4、回滚更容易管理 Saga模式的一大优势是它支持长...

战略板儿砖
56分钟前
11
0
为什么要使用static_cast (x)而不是(int)x? - Why use static_cast(x) instead of (int)x?

问题: I've heard that the static_cast function should be preferred to C-style or simple function-style casting. 我听说static_cast函数应该比C样式或简单的函数样式转换更可取。 Is......

fyin1314
58分钟前
18
0
最难的几道Java面试题,看看你跪在第几个?

这是我收集的10个最棘手的Java面试问题列表。这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。你可能知道这些棘手的 Java 问题的答案,或者觉得这些不足以挑战你的 Java 知识,但...

码农突围
59分钟前
20
0
浅谈Spring核心技术 IOC与AOP

IOC: IOC(Inversion Of Controll,控制反转)是一种设计思想,将原本在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC容器是Spring用来实现IOC的载体,IOC容器实际上就是一个M...

创业789
今天
13
0
智能金融丨神州信息助某省联社实现一体化智能运维建设

近日,由神州信息实施的某省联社“IT服务管理平台项目”顺利通过验收,并获得客户的高度认可。该项目是神州信息在农信领域打造的又一标杆项目,为客户实现了IT运维流程标准化及运维系统一体化...

脉脉小达人
今天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部