前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TensorFlow从入门到精通 | 01 简单线性模型(上篇)

TensorFlow从入门到精通 | 01 简单线性模型(上篇)

作者头像
Amusi
修改2019-12-17 15:38:30
8020
修改2019-12-17 15:38:30
举报
文章被收录于专栏:CVerCVer

导言

[TensorFlow从入门到精通] 01 简单线性模型(上)介绍了TensorFlow如何加载MNIST、定义数据维度、TensorFlow图、占位符变量和One-Hot Encoding等知识点.

作者: Magnus Erik Hvass Pedersen

编辑: Amusi

校稿: Amusi

前言

前些天,Amusi整理了一份重磅 | TensorFlow学习资料最全集锦,里面包含TensorFlow相关的书籍、视频和在线学习网站等资料。

其中,Amusi很喜欢 Magnus Erik Hvass Pedersen大佬制作的TensorFlow Tutorials 课程。该课程提供视频教程(在YouTube上,需要访问外国网站观看),并在github上发布了源码。为此,Amusi决定推出【TensorFlow从入门到精通】系列文章,详情请看TensorFlow从入门到精通 | 预告篇

Amusi 曾经也学过一点 TensorFlow的知识,但觉得不够系统,所以觉得按部就班的将TensorFlow Tutorials学习一遍。日常整理的翻译和笔记都会同步发布到 TensorFlow-From-Zero-to-One 上。点击文末的“阅读全文”,即可查看。

正文

介绍

本教程介绍了使用TensorFlow实现简单线性模型的workflow。在加载MNISIT(手写字符图像数据集)后,我们使用TensorFlow定义并优化一个简单的数学模型。然后绘制并讨论结果。

你应该熟悉基本的线性代数,Python,Jupyter Notebook编辑器。如果你对机器学习和分类有基本的了解,这也会帮助到你。

导入必要库(Imports)

代码语言:javascript
复制
1%matplotlib inline  
2import matplotlib.pyplot as plt
3import tensorflow as tf
4import numpy as np
5from sklearn.metrics import confusion_matrix
6}

大家可能会对上述代码中的第一句 %matplotlib inline有所好奇,该语句怎么是这样的?其作用是什么?

这里Amusi引出两种介绍,第一种是根本性解释,第二种是适用于此代码的解释。

第一种解释[1]:

%matplotlib inline 是一个魔法函数(Magic Functions)。官方给出的定义是:IPython有一组预先定义好的所谓的魔法函数(Magic Functions),你可以通过命令行的语法形式来访问它们。可见“%matplotlib inline”就是模仿命令行来访问magic函数的在IPython中独有的形式。

magic函数分两种:一种是面向行的,另一种是面向单元型的。

行magic函数是用前缀“%”标注的,很像我们在系统中使用命令行时的形式,例如在Mac中就是你的用户名后面跟着“$”。“%”后面就是magic函数的参数了,但是它的参数是没有被写在括号或者引号中来传值的。

单元型magic函数是由两个“%%”做前缀的,它的参数不仅是当前“%%”行后面的内容,也包括了在当前行以下的行。

注意:既然是IPython的内置magic函数,那么在Pycharm中是不会支持的。

总结:%matplotlib inline 可以在Ipython编译器里直接使用,功能是可以内嵌绘图,并且可以省略掉plt.show()这一步。

第二种解释[2]:

%matplotlib inline比较奇怪,而且无论你是用哪个python的IDE如spyder或者pycharm,这个地方都会报错,显示是invalid syntax(无效语法)。那为什么代码里面还是会有这一句呢?原来是这样的。 %matplotlib作用

是在使用jupyter notebook 或者 jupyter qtconsole的时候,才会经常用到%matplotlib,也就是说那一份代码可能就是别人使用jupyter notebook 或者 jupyter qtconsole进行编辑的。关于jupyter notebook是什么,可以参考这个链接:[Jupyter Notebook介绍、安装及使用教程][1] 而%matplotlib具体作用是当你调用matplotlib.pyplot的绘图函数plot()进行绘图的时候,或者生成一个figure画布的时候,可以直接在你的python console里面生成图像。 而我们在spyder或者pycharm实际运行代码的时候,可以直接注释掉这一句,也是可以运行成功的。如下示例:

Amusi 总结:

为了在Jupyter Notebook中使用matplotlib.pyplot的plot函数,即实现内嵌绘图,而需要加上%matplotlib inline

参考:

[1]:https://blog.csdn.net/liangzuojiayi/article/details/78183783?locationNum=8&fps=1

[2]:https://www.jianshu.com/p/2dda5bb8ce7d

加载数据(Load Data)

如果在给定路径下,没有MNIST数据集,那么程序会自动下载该数据集(大约11MB)

The MNIST data-set is about 11 MB and will be downloaded automatically if it is not located in the given path.

代码语言:javascript
复制
1from tensorflow.examples.tutorials.mnist import input_data
2data = input_data.read_data_sets("data/MNIST/", one_hot=True)

现在 MNIST数据集已经加载好,该数据集包含70,000幅图像和标签(即图像的类别)。数据集被分成3个互不交叉的子集(训练集、测试集和验证集),在本教程中,我们将只使用训练集和测试集。

其中:

  • 训练集(Training set):55000幅图像
  • 测试集(Test set):10000幅图像
  • 验证集(Validation set):5000幅图像
代码语言:javascript
复制
1print("Size of:")
2print("- Training-set:\t\t{}".format(len(data.train.labels)))
3print("- Test-set:\t\t{}".format(len(data.test.labels)))
4print("- Validation-set:\t{}".format(len(data.validation.labels)))

代码语言:javascript
复制
Size of:
- Training-set:		55000
- Test-set:		10000
- Validation-set:	5000

独热编码(One-Hot Encoding)

MNIST数据集由One-hot encoding方式加载。这意味着标签由单个数字(类别)转换成一个向量,其长度等价于可能类别数量(如有10类,则长度为10)。向量的所有元素除了第i个元素为 1之外(因为该标签的类别是i),其它元素都为0。

代码语言:javascript
复制
1# 输出测试集前5个标签的向量数据
2data.test.labels[0:5, :]

输出:

代码语言:javascript
复制
array([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
       [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
       [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])

我们还需要将类(classes)作为单个数字进行各种比较和性能测量,因此我们通过获取最高元素(其值为1)的索引来将One-Hot编码向量转换为单个数字。请注意,'class'这个词是Python中使用的关键字,因此我们需要使用名称'cls'。

代码语言:javascript
复制
1# argmax(): Returns the indices of the maximum values along an axis# argma 
2data.test.cls = np.array([label.argmax() for label in data.test.labels])

上面代码,我们使用了numpy的argmax()函数。该函数的作用是:Returns the indices of the maximum values along an axis。因为类别向量中只有1是最大值,而1所在的索引位置就是我们所要的值。argmax()正好完美适用!

现在我们可以知道测试集中前5幅图像的类别。你可以将其与上述One-Hot编码向量进行比较。例如,第一幅图像的类是7,其对应于One-Hot编码向量中索引为7的元素,该元素值为1。

代码语言:javascript
复制
1data.test.cls[0:5]

输出:

代码语言:javascript
复制
array([7, 2, 1, 0, 4], dtype=int64)

数据维度(Data dimensions)

数据维度会在下面的代码中被使用。在计算机编程中,最好使用使用变量(variables)和常量(constants),而不是每次使用该编号时候都必须对特定数字进行硬编码(hard-code)。这意味着数字只需要在一个地方被修改。理想情况下,这些数据可以从已经读取的数据中推断(inferred)出来,但在这里我们只是写出数字。

代码语言:javascript
复制
 1# MNIST图像数据的每个维度是28个像素(即28x28)
 2img_size = 28
 3
 4# 图像存储在一维数组中
 5img_size_flat = img_size * img_size
 6
 7# 将图像的高度和宽度变成不可变的元组(tuple),用于 reshape arrays。
 8img_shape = (img_size, img_size)
 9
10# 类别的数量:10,即每一类用一个数值来表示
11num_classes = 10

绘图的帮助函数(Helper-function for plotting images)

函数使用3x3网格绘制9幅图像,并在每幅图像下面显示真实正确的类别和预测的类别。

代码语言:javascript
复制
 1def plot_images(images, cls_true, cls_pred=None):
 2    # 判断输入参数是否符合要求
 3    assert len(images) == len(cls_true) == 9
 4
 5    # 创建3x3的图和subplots的集合
 6    fig, axes = plt.subplots(3, 3)
 7    fig.subplots_adjust(hspace=0.3, wspace=0.3)
 8
 9    for i, ax in enumerate(axes.flat):
10        # 绘图
11        ax.imshow(images[i].reshape(img_shape), cmap='binary')
12
13        # 显示正确和预测的类别
14        if cls_pred is None:
15            xlabel = "True: {0}".format(cls_true[i])  # "{N}".format(n0,n1,...,nN)一定要掌握这种写法
16        else:
17            xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i])
18
19        ax.set_xlabel(xlabel)
20
21        # 删除plot的刻度(ticks)
22        ax.set_xticks([])
23        ax.set_yticks([])
24
25    # 在单个Notebook 单元格中正确的显示plot图。
26    plt.show()

绘制一些图像检查数据是否正确

代码语言:javascript
复制
1# 从测试集中获得前9幅图像数据
2images = data.test.images[0:9]
3
4# 获得相应的正确类别
5cls_true = data.test.cls[0:9]
6
7# 使用上述函数绘制图像和标签(非预测)
8plot_images(images=images, cls_true=cls_true)

TensorFlow 图(Graph)

TensorFlow 的目的是实现一个计算图(computational graph),与直接在Python中执行的计算相比,其可以更有效的执行。TensorFlow可以比Numpy更有效,因为TensorFlow知道必须执行的整个计算图,而Numpy一次只知道单个数学运算的计算。

TensorFlow 还可以自动计算优化图中变量所需的梯度,以使得模型更好地运行。这是因为图(Graph)是简单数学表达式的组合,因此可以使用微分(derivatives)的链式法则(chain-rule)来计算整个图的梯度。

TensorFlow 还可以利用多核CPU和GPU的,而且Google甚至为TensorFlow研发了专用芯片,称为TPU(Tensor Processing Units),甚至比GPU更快。

TensorFlow图由以下部分组成,将在下面详述:

  • 占位符(Placeholder)变量用于改变图的输入
  • 模型变量将进行优化,以使模型表现更好
  • 模型本质上是数学函数,它很具占位符变量和模型变量的输入计算一些输出
  • 一种指导变量优化的代价度量(cost measure)
  • 一种更新模型变量的优化方法

此外,TensorFlow图还可以包含各种调试语句,例如:可以由TensorBoard可视化的日志数据(本教程没有介绍)

占位符变量(Placeholder variables)

占位符变量(Placeholder variables)作为图的输入,我们可以在每次执行图的时候进行更改。我们称之为 喂(feeding)占位符变量,并在下面进一步说明。

首先,我们定义输入图像的占位符变量‘x’。这允许我们改变输入到TensorFlow图的图像。这是一个所谓的张量(tensor),这意味着它是一个多维向量或矩阵。该占位符的数据类型设置成‘float32’,形状设置成‘[None, img_size_flat]’,其中‘None’表示张量可以存储(hold)任意数量的图像,每个图像是长度为‘img_size_flat’的向量。

代码语言:javascript
复制
1x = tf.placeholder(tf.float32, [None, img_size_flat])

接下来,我们定义占位符变量‘y_true’,其是存放与占位符‘x’中输入图像相关联的真实标签。该占位符变量的数据类型设置成‘float32’,形状是‘[None, num_classes]’,这意味着它可以包含任意数量的标签,每个标签是长度为‘num_classes’的向量,在这种情况下为10。

代码语言:javascript
复制
1y_true = tf.placeholder(tf.float32, [None, num_classes])

最后,我们定义占位符变量‘y_true_cls’,其实存放与占位符‘x’中输入图像相关的类别。该占位符的数据类型设置成‘int64’,形状设置为‘[None]’,这意味着该占位符变量是任意长度的一维向量。

代码语言:javascript
复制
1y_true_cls = tf.placeholder(tf.int64, [None])

待优化的变量(Variables to be optimized)

除了上面定义用作将输入数据输入到模型中的占位符变量之外,还有一些模型变量必须由TensorFlow进行更改,以使模型在训练数据上表现更好。

必须优化的第一个变量称为“权重(weights)”,在这里定义为TensorFlow变量,必须用零初始化,形状为[img_size_flat,num_classes],因此它是具有img_size_flat行和num_classes列的二维张量(或矩阵) 。

代码语言:javascript
复制
1# tf.zeros: 返回全是由0元素组成的值
2weights = tf.Variable(tf.zeros([img_size_flat, num_classes]))

第二个必须要优化的变量称为“偏置(biases)”,其实长度为‘num_classes’的一维度张量(或向量)。这里也初始化为零。

代码语言:javascript
复制
1biasesbiases  ==  tftf..VariableVariable(tf.zeros([num_classes]))

模型(Model)

简单的数学模型是将占位符变量‘x’乘以权重‘weights’,并加上偏置‘biases’

根据矩阵性质,输出结果是形状为‘[num_images, num_classes]’的矩阵。因为‘x’的形状为‘[num_images, img_size_flat]’,‘weights’的形状为‘[img_size_flat, num_classes]’,所以这两个矩阵相乘的结果是形状为‘[num_images, num_classes]’的矩阵。然后将‘biases’向量加到矩阵的每一行上(利用广播的特性)。

注意:名称‘logits’是典型的TensorFlow术语(terminogy),但你也可以叫做其它变量。

代码语言:javascript
复制
1logits = tf.matmul(x, weights) + biases

现在logits是一个带有num_images行和num_classes列的矩阵,其中第 i 行和第 j 列的元素是对第 i 幅输入图像估计为第 j 类的可能性(概率值)。

然而,这些估计是大概的(rough)值且难以解释,因为这些数字可能非常小或很大,所以我们想对它们进行归一化处理,以使logits矩阵的每一行总和为1(因为概率值和为1),并且每个元素被限制在[0,1]。这是使用所谓的softmax函数(又称归一化指数函数)计算的,结果存储在y_pred中。

注:附上Softmax相关资源(点击阅读全文即可查看)

[1] Softmax function wiki

[2] Softmax 函数的特点和作用是什么?

[3] Softmax回归

代码语言:javascript
复制
1y_pred = tf.nn.softmax(logits)

可以通过获取 y_pred矩阵中每行中最大元素的索引计算预测的类别 y_pred_cls

代码语言:javascript
复制
1y_pred_cls = tf.argmax(y_pred, axis=1)

限于篇幅过大,便将【TensorFlow从入门到精通】01 简单线性模型内容分成上篇和下篇来介绍。

预告下篇将介绍代价函数、优化器、衡量指标、TensorFlow会话(Session)、变量初始化等知识点。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CVer 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 独热编码(One-Hot Encoding)
  • 数据维度(Data dimensions)
  • 绘图的帮助函数(Helper-function for plotting images)
  • 绘制一些图像检查数据是否正确
  • TensorFlow 图(Graph)
    • 占位符变量(Placeholder variables)
      • 待优化的变量(Variables to be optimized)
        • 模型(Model)
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档