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

导言

[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)

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.

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幅图像
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)))
Size of:
- Training-set:		55000
- Test-set:		10000
- Validation-set:	5000

独热编码(One-Hot Encoding)

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

1# 输出测试集前5个标签的向量数据
2data.test.labels[0:5, :]

输出:

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'。

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。

1data.test.cls[0:5]

输出:

array([7, 2, 1, 0, 4], dtype=int64)

数据维度(Data dimensions)

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

 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幅图像,并在每幅图像下面显示真实正确的类别和预测的类别。

 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()

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

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’的向量。

1x = tf.placeholder(tf.float32, [None, img_size_flat])

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

1y_true = tf.placeholder(tf.float32, [None, num_classes])

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

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列的二维张量(或矩阵) 。

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

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

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),但你也可以叫做其它变量。

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回归

1y_pred = tf.nn.softmax(logits)

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

1y_pred_cls = tf.argmax(y_pred, axis=1)

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

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

原文发布于微信公众号 - CVer(CVerNews)

原文发表时间:2018-07-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏鸿的学习笔记

写给开发者的机器学习指南(十三)

在我们实际使用支持向量机(SVM)之前,我先简要介绍一下SVM是什么。 基本SVM是一个二元分类器,它通过选取代表数据点之间最大间隔的超平面将数据集分成2部分。...

831
来自专栏Java 源码分析

动态规划

​ 动态规划一般来说和分治有点类似都是让他们去处理相同的子问题,但是在动态规划里面你会遇到更多的相同子问题。然后我们就会导致很多的重复计算,所以一般我们可...

3085
来自专栏机器学习和数学

[编程经验] SciPy之图像处理小结

Python中可以处理图像的module有很多个,比如Opencv,Matplotlib, Numpy, PIL以及今天要分享的SciPy。其他几个后续都会总结...

8607
来自专栏祥子的故事

tensorflow | 重新学习 | 了解graph 和 Session

3738
来自专栏大数据风控

Python中的交叉分析pivot_table

交叉分析 通常用于分析两个或两个以上,分组变量之间的关系,以交叉表形式进行变量间关系的对比分析; 从数据的不同维度,综合进行分组细分,进一步了解数据的构成、分...

3178
来自专栏人工智能LeadAI

TensorFlow Tutorial-1

1、Why TensorFlow? 网上有关介绍太多了,我就不多说了,这里主要注重使用。 ? Intro.PNG ? github.PNG 2、Programi...

38811
来自专栏学习有记

2018 蓝桥杯省赛 B 组模拟赛(五)题目及解析

1102
来自专栏xiaoxi666的专栏

最长滑道问题(非递归,C++)

题目描述请参考博客http://blog.csdn.net/sinat_30186009/article/details/52356053,在此表示感谢。

1123
来自专栏每日一篇技术文章

OpenGL ES _ 着色器_纹理图像

玩过游戏的同学们,都知道在游戏人物身上穿的那个叫皮肤,专业点将那个就叫做纹理图像。GLSL 支持在顶点和片段着色器使用纹理图像。

2103
来自专栏数据科学与人工智能

【算法】 Keras 四步工作流程

Francois Chollet在他的“深度学习Python”一书中概述了与Keras开发神经网络的概述。 通过本书前面的一个简单的MNIST示例,Cholle...

1372

扫码关注云+社区

领取腾讯云代金券