[机器学习系列二]TensorFlow入门

1. 写在最前面

1.1 机器学习如何入门

关于机器学习如何入门可以参考机器学习该怎么入门?,相关课程可以参考吴恩达机器学习系列课程

1.2 关于框架的选择

无论是TensorFlow还是PyTorch都是非常优秀的框架,关于两者如何选择,可以参2021 年了,TensorFlow 和 PyTorch 两个深度学习框架地位又有什么变化吗?,最高赞的结论是:

2021年学术圈 Pytorch会继续称霸天下,而Tensorflow引以为傲的工业界地位会进一步衰退,Pytorch会借助ONNX所带来的落地能力在工业界逐渐抢走主导地位。

但是因为项目中使用的是TensorFlow, 所以这里选择的是TensorFlow,每天是身在tf营,心在torch。关于Pytorch,可以参考PyTorch 中文教程 & 文档

1.3 tf1、tf2、keras与tf.keras

tf1与tf2的区别可以参考: https://www.tensorflow.org/guide/migrate/tf1_vs_tf2

  • TensorFlow 1.X需要用户使用tf.*里的API手动构建计算图,然后用session.run()传入输入tensor并且计算某些输出tensor。
  • TensorFlow 2.X默认是Eager执行模式,我们在定义一个Operation的时候会动态构造计算图并且马上计算。这样的好处就是我们的代码就像在执行普通的Python代码,Graph和Session等实现细节概念都被隐藏在后面了。
  • Keras可以看成是一种深度学习框架的高阶接口规范,它帮助用户以更简洁的形式定义和训练深度学习网络。随着谷歌对Keras的收购,Keras库2.3.0版本后也将不再进行更新,用户应当使用tf.keras而不是使用pip安装的Keras。
  • tf.keras是在TensorFlow中以TensorFlow低阶API为基础实现的这种高阶接口,它是Tensorflow的一个子模块。
1.4 Tensorflow接口层次结构
  1. 最底层为硬件层,TensorFlow支持CPU、GPU或TPU加入计算资源池;

  2. 第二层为C++实现的内核,kernel可以跨平台分布运行;

  3. 第三层为Python实现的操作符,提供了封装C++内核的低级API指令,主要包括各种张量操作算子、计算图、自动微分。如tf.Variable,tf.constant,tf.function, tf.GradientTape, tf.nn.softmax... 如果把模型比作一个房子,那么第三层API就是【模型之砖】;

  4. 第四层为Python实现的模型组件,对低级API进行了函数封装,主要包括各种模型层,损失函数,优化器,数据管道,特征列等等。 如tf.keras.layers, tf.keras.losses, tf.keras.metrics, tf.keras.optimizers,tf.data.DataSet, tf.feature_column... 如果把模型比作一个房子,那么第四层API就是【模型之墙】。

  5. 第五层为Python实现的模型成品,一般为按照OOP方式封装的高级API,主要为tf.keras.models提供的模型的类接口。 如果把模型比作一个房子,那么第五层API就是模型本身,即【模型之屋】。

TensorFlow的层次结构

2. Tensorflow基本概念

TensorFlow,顾名思义就是流动着的Tensor。首先,我们要搞清楚什么是tensor,它在哪里以何种方式流动?用最简单的话来说,Tensor实际上就是一个多维数组(multidimensional array),是TF的主要数据结构。它们在一个或多个由节点(nodes)和边(edges)组成的图(graphs)中流动。边代表的是tensors,节点代表的是对tensors的操作(operations)。tensors在图中从一个节点流向另一个节点,每次经过一个节点都会接受一次操作。

2.1 Tensor

1. tensor基本概念
tensor有两个属性:

  • dtype: Tensor 存储的数据的类型,可以为tf.float32、tf.int32、tf.string…
  • shape: Tensor 存储的多维数组中每个维度的数组中元素的个数
    此外还有一个rank,是shape的另一种表达方式,即维数
# 0阶张量,即标量,shape=0
t0 = tf.constant(3, dtype=tf.int32)
# 1阶张量,即矢量,shape=[2]
t1 = tf.constant([3., 4.1, -.2], dtype=tf.float32)
# 2阶张量,二维数组,shape=[2, 3]
t2 = tf.constant([['A', 'B'], ['C', 'D']], dtype=tf.string)
# 3阶张量,三维数组,shape=[2, 1, 3],数据默认类型为整形
t3 = tf.constant([[[1, 3]], [[5, 7]]])

print打印tensor的属性定义,tf.print(tensor)打印tensor的值,tf.print如果数量太多默认会省略中间部分,如果不想省略可以增加参数summarize=-1

> print(t0)
tf.Tensor(3, shape=(), dtype=int32)
> print(t1)
tf.Tensor([ 3.   4.1 -0.2], shape=(3,), dtype=float32)
> print(t2)
tf.Tensor(
[[b'A' b'B']
[b'C' b'D']], shape=(2, 2), dtype=string)
> print(t3)
tf.Tensor(
[[[1 3]]

[[5 7]]], shape=(2, 1, 2), dtype=int32)

> print(t2.get_shape())
(2, 2)
> tf.print(t0)
3
> tf.print(t1)
[3 4.1 -0.2]
> tf.print(t2)
[["A" "B"]
 ["C" "D"]]
> tf.print(t3)
[[[1 3]]

 [[5 7]]]
> tf.print(tf.range(1, 11, delta=1, dtype=tf.float32))
[1 2 3 ... 8 9 10]
> tf.print(tf.range(1, 11, delta=1, dtype=tf.float32),  summarize=-1)
[1 2 3 4 5 6 7 8 9 10]

2. tensor的创建
创建tensor的方法可以分为2种

  1. 使用tf自带的函数直接创建,例如:
# create a zero filled tensor
t0 = tf.zeros([1, 2])
# [[0 0]]

# create a one filled tensor
t1 = tf.ones([1, 2])
# [[1 1]]

# create a constant filled tensor
t2 = tf.fill([1, 2], 42)
# [[42 42]]

# create a tensor out of an existing constant
t3 = tf.constant([1, 2, 3])
# [1 2 3]

# generate random numbers from a uniform distribution
t4 = tf.random.uniform([1, 2], minval=0, maxval=1)
# [[0.809502 0.184664249]]

# generate random numbers from a normal distribution
t5 = tf.random.normal([1, 2], mean=0.0, stddev=1.0)
# [[-0.717701077 -1.32147753]]
  1. 将Python对象(Numpy arrays, Python lists,Python scalars)转成tensor,例如:
import numpy as np
x_data = np.array([[1., 2., 3.], [3., 2., 6.]])
tf.convert_to_tensor(x_data, dtype=tf.float32)

# [[1 2 3]
#  [3 2 6]]
2.2 operation

operation代表对tensor的操作,如下图所示:节点a接收了一个1-D tensor,该tensor从节点a流出后,分别流向了节点b和c,节点b执行的是prod操作(5*3),节点c执行的是sum操作(5+3)。当tensor从节点b流出时变成了15,从节点c流出时变成了8。此时,2个tensor又同时流入节点d,接受的是add操作(15+8),最后从节点d流出的tensor就是23。

image.png

相应的代码为:

import tensorflow as tf
a = tf.constant([5, 3], name='input_a')
b = tf.reduce_prod(a, name='prod_b')
c = tf.reduce_sum(a, name='sum_c')
d = tf.add(b, c, name='add_d')

3. Tensorflow入门示例

正如大部分的编程语言入门从hello world!开始, tensorflow的入门以最简单线性回归(Linear Regression)开始。
线性回归就是在坐标系中有很多点, 线性回归的目的就是找到一条线使得这些点都在这条直线上或者直线的周围。我们要对其进行线性回归,则建立线性数学模型:

y=W∗x+b

那么如何评估我们线性回归出来的直线方程呢?我们需要建立一个损失模型(loss model)来评估模型的合理性:

loss=Σ(yn−y′n)2

3.1 构造数据集

利用函数Y = 2*X + 3并增加正态随机构造数据集,相关代码如下所示

import tensorflow as tf
w = 2
b = 3
X = tf.range(1, 11, delta=1, dtype=tf.float32)
Y = X * w + b + tf.random.normal([10,], mean = 0.0, stddev= 1.0)

构造好的数据集如下所示

X = [1 2 3 4 5 6 7 8 9 10]
Y = [5.69277859 5.68863153 7.6934948 10.7271547 13.6772203 14.6714172 15.488286 20.2158928 21.2844448 24.5952759]

如下图所示,将Y = 2*X + 3(绿线部分)和X、Y(蓝点)画在同一图像上,画图代码如下所示:

from matplotlib import pyplot as plt
plt.plot(X, X * w + b, color='green')
plt.scatter(X, Y, color='blue')
plt.xlabel('x')
plt.ylabel('y')
plt.title("Data")
plt.ylim(ymin=0)
plt.show()
image.png

将数据集拆分为训练数据集和评估数据集

# 训练数据
x_train = [1.0, 3.0, 5.0, 7.0, 9.0]
y_train = [5.69277859, 7.6934948, 13.6772203, 15.488286, 21.2844448]
# 评估数据
x_eval = [2.0, 4.0, 6.0, 8.0, 10.0]
y_eval = [5.68863153, 10.7271547, 14.6714172, 20.2158928, 24.5952759]
3.2 训练

训练代码如下所示

import tensorflow as tf

# create data
x_train = [1.0, 3.0, 5.0, 7.0, 9.0]
y_train = [5.69277859, 7.6934948, 13.6772203, 15.488286, 21.2844448]


# create tensorflow structure
W = tf.Variable(tf.random.uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))


# alias: tf.losses.mse
loss = lambda: tf.keras.losses.MSE(y_train, W * x_train + b)
# alias: tf.optimizers.SGDS
optimizer = tf.keras.optimizers.SGD(learning_rate=0.004)

num_epoch = 6001
for step in range(num_epoch):
    optimizer.minimize(loss, var_list=[W, b])
    if step % 100 == 0:
        print( "{} step, weights = {}, biases = {}, loss = {}".format(step, W.read_value(), b.read_value(), loss()) )

迭代过程如下所示

0 step, weights = [0.6796642], biases = [0.09973339], loss = 99.73298645019531
100 step, weights = [2.285599], biases = [0.8164981], loss = 2.1074492931365967
200 step, weights = [2.2274106], biases = [1.1977823], loss = 1.7347787618637085
300 step, weights = [2.1792789], biases = [1.5131716], loss = 1.4797898530960083
400 step, weights = [2.139465], biases = [1.7740546], loss = 1.3053206205368042
500 step, weights = [2.106532], biases = [1.989852], loss = 1.1859443187713623
600 step, weights = [2.0792909], biases = [2.1683528], loss = 1.104265809059143
700 step, weights = [2.0567577], biases = [2.3160055], loss = 1.0483779907226562
800 step, weights = [2.0381184], biases = [2.4381416], loss = 1.010138750076294
900 step, weights = [2.0227005], biases = [2.5391688], loss = 0.9839746356010437
1000 step, weights = [2.009947], biases = [2.622736], loss = 0.9660736322402954
1100 step, weights = [1.999398], biases = [2.6918607], loss = 0.9538244009017944
1200 step, weights = [1.9906719], biases = [2.74904], loss = 0.9454426765441895
1300 step, weights = [1.9834539], biases = [2.7963367], loss = 0.9397082328796387

……

5300 step, weights = [1.9489253], biases = [3.02259], loss = 0.9272836446762085
5400 step, weights = [1.9489214], biases = [3.0226138], loss = 0.9272834658622742
5500 step, weights = [1.948918], biases = [3.0226376], loss = 0.927282989025116
5600 step, weights = [1.9489162], biases = [3.0226493], loss = 0.9272829294204712
5700 step, weights = [1.9489162], biases = [3.0226493], loss = 0.9272829294204712
5800 step, weights = [1.9489162], biases = [3.0226493], loss = 0.9272829294204712
5900 step, weights = [1.9489162], biases = [3.0226493], loss = 0.9272829294204712
6000 step, weights = [1.9489162], biases = [3.0226493], loss = 0.9272829294204712

可以看到迭代到5600步时,loss已经收敛了, 最终训练出的结果是:W = 1.9489162b = 3.0226493 ,与构造的数据用的 W = 2b = 3已经很接近了。将评估训练集带入模型,发现最终的损失也很小,说明训练出的模型还是有很好的泛化性

import tensorflow as tf

x_eval = [2.0, 4.0, 6.0, 8.0, 10.0]
y_eval = [5.68863153, 10.7271547, 14.6714172, 20.2158928, 24.5952759]

W = tf.constant(1.9489162, dtype=tf.float32)
b = tf.constant(3.0226493, dtype=tf.float32)
tf.print(tf.keras.losses.MSE(y_eval, W * x_eval + b))
# 1.6869427
3.3 TensorBoad

TensorBoad是Google为TensorFlow开发了一款可视化工具,使用流程如下

  1. 建立文件夹存放 TensorBoard 的记录文件;
  2. 实例化记录器;
# 日志目录
logdir = "/tmp/tensorflow"
# create the file writer object
writer = tf.summary.create_file_writer(logdir)
  1. 将参数(一般是标量)记录到指定的记录器中;
    with writer.as_default():
        tf.summary.scalar('training loss', loss(), step=step+1)
  1. 访问 TensorBoard 的可视界面。
tensorboard --logdir /tmp/tensorflow

根据提示访问http://localhost:6006/,就可以看到如下界面,可以看到前1000步之前loss急剧下降,然后loss下降趋于平缓。

image.png

TensorBoad完整代码请参考附录1

参考文献:

  1. http://www.codebaoku.com/it-python/it-python-231750.html

  2. 【深度学习-2】TensorFlow基础(一): tensor and operation

  3. 30天吃掉那只TensorFlow2.0

  4. TensorFlow学习笔记:第一个Demo——线性回归

  5. TensorFlow入门:第一个机器学习Demo

附录

1. LinearRegression.py
import tensorflow as tf

# 日志目录
logdir = "/tmp/tensorflow"
# create the file writer object
writer = tf.summary.create_file_writer(logdir)

# create data
x_train = [1.0, 3.0, 5.0, 7.0, 9.0]
y_train = [5.69277859, 7.6934948, 13.6772203, 15.488286, 21.2844448]

# create tensorflow structure
W = tf.Variable(tf.random.uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))

# alias: tf.losses.mse
loss = lambda: tf.keras.losses.MSE(y_train, W * x_train + b)
# alias: tf.optimizers.SGDS
optimizer = tf.keras.optimizers.SGD(learning_rate=0.004)

num_epoch = 6001
for step in range(num_epoch):
    optimizer.minimize(loss, var_list=[W, b])
        # write the loss value
    with writer.as_default():
        tf.summary.scalar('training loss', loss(), step=step+1)
        
    if step % 100 == 0:
        print( "{} step, weights = {}, biases = {}, loss = {}".format(step, W.read_value(), b.read_value(), loss()))  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容