前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TensorFlow从1到2(一)续讲从锅炉工到AI专家

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

作者头像
俺踏月色而来
发布2019-04-18 11:25:34
8720
发布2019-04-18 11:25:34
举报
文章被收录于专栏:月色的自留地月色的自留地
引言

原来引用过一个段子,这里还要再引用一次。是关于苹果的。大意是,苹果发布了新的开发语言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的支持下,对于同样的数据集和数学模型,变更学习算法会很容易。

(待续...)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-04-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 安装
  • 第一个例子:房价预测
  • 使用2.0中的v1兼容包来沿用1.x代码
  • 使用迁移工具来自动迁移1.x代码到2.0
  • 编写原生的TensorFlow 2.0程序
相关产品与服务
迁移服务平台
迁移服务平台(Migration Service Platform,MSP)是帮助客户将系统从源平台迁移到腾讯云的工具。为迁移上云项目提供源端资源调研、上云规划、目标资源创建、批量迁移实施等能力,帮助降低客户迁移上云的复杂度,提升迁移效率。迁移服务平台 MSP 不收取任何额外费用,您只需为购买的资源及 DTS 数据迁移工具付费。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档