aklk 2017-03-02
【AI100 导读】本文是《数学不好,也可以学习人工智能》系列的第四篇文章,主要内容围绕 Tensors(张量)展开。
现在的你是否已经下载好 TensorFlow 并准备好开始深度学习了呢?
但是紧接着你就有可能会想:tensor 到底是什么鬼?
为了了解什么是 tensor,你可能会查一下维基百科,但是接下来你却更加迷茫了。你可能发现有个叫 NASA 的教程,但是看过之后仍然不知道到底是什么意思。
这其中的问题就在于,大多数谈论 tensor 的教程早就默认了听众或者观众已经明白了所有的描述性的数学语言。
没什么好怕的!
像小孩子一样,我也很讨厌数学。所以的话,如果连我都能弄懂人工智能,你也可以!肯定没问题!我们要做的,就是用最简单的术语去解释有关人工智能的一切。
所以,到底什么是 tensor?他又是怎么 flow 的?
Tensors = Containers
Tensor 是现代机器学习中最基本的构件。
从 tensor 的核心本质来看,tensor 实际上是一个数据容器。大多数情况下,这个容器里装的是许许多多的数字。有时候装的也可能是字符串,但是这样的情况比较少。
所以,可以试着把 tensor 想象成装有数字的“桶”或者“筐”。
Tensor 有很多种不同的尺寸,大小不一。接下来我会向大家介绍深度学习中 tensor 的最基本的几个尺寸,也就是从0维到5维的这个区间。
我们可以把这些 tensor 做如下的可视化处理(猫在后面!):
我们将所有进入 tensor 容器的数字称为 scalar。
一个 scalar 就相当于一个数字。
你可能会问,为什么不直接叫数字呢?
我也不知道,可能数学家们觉得 scalar 听起来比较酷?确实,scalar 叫起来要比 number 酷些。
事实上,你是可以拥有只包含一个数字的 tensor 的,这样的 tensor 我们通常称作0维张量,这就好比一个桶或筐里只有一滴水。一个桶里只有一滴水的情况与0维 tensor 中只有一滴水的情况十分类似。
在本篇教程中,我们将会用到 Python、Keras、TensorFlow 以及 NumPy,在之前的系列文章《数学不好,也可以学习人工智能(三)》中都已经介绍过。因此,如果你想快速获得深度学习的工作基站的话,翻看一下之前的文章吧!
在 Python 中,tensors 一般存储在 Numpy 数组中。NumPy 是处理数字的科学计算库,当下几乎所有的 AI 框架都用到了 NumPy。
import numpy
x = np.array(5)
print(x)
输出结果是:
5
在数据科学竞赛网站 Kaggle 上,你经常可以看到 Jupyter Notebooks(本站的在线开发环境也是基于 Jupyter Notebooks)提到要把数据转换为 Numpy 数组。Jupyter Notebook 将文档与代码的功能集为一体。也就是说,其融讲解和编程于一体。
为什么要把数据转换成 Numpy 数组呢?
原因很简单。因为我们需要处理各种各样的输入数据,包括字符、图像、股价或者视频等,我们需要将不同类型的输入数据转换成通用的标准,方便之后的工作。
在这种情况下,我们就把数据转换成了“一桶又一桶”的数字,而后通过 TensorFlow 来操纵它们。
实际上,这个过程就是把数据组织成一种可用的格式。在网络编程中,你可能会选择用 XML 来呈现,可以快捷地定义和操纵数据。同样的,在深度学习中我们选择使用 tensor 这个容器作为乐高里最小的零件。
如果你是一名程序员的话,那么你肯定已经知道这种跟1维 tensor 非常接近的东西了:数组。
每种编程语言都包含数组,数组其实就是一行或一列数据。在深度学习中,我们将这样的数组称作1维 tensor。Tensor 是由轴的数量来定义的,1维 tensor 只有一个数轴。
一个1维 tensor 称为一个矢量(vector)。
我们可以把某个矢量可视化为一行或一列数字。
如果我们想在 Numpy 中查看这一过程的话,可以执行以下操作:
x = np.array([1,2,3,4])
print(x)
输出结果是:
array([1,2,3,4])
与此同时,我们也可以用 Numpy 的 ndim 功能查看 tensor 的数轴数量。让我们试一下1维 tensor:
x.ndim
输出结果是:
1
你很可能已经想到了另外一种 tensor:矩阵
我们将2维 tensor 称为矩阵(matrix)。
不,这里指的并不是基努·里维斯(Keanu Reeves)的那个电影,而是类似Excel 表格的这样一个数据结构。
我们可以将其可视化为具有行/列的数字网格。
行和列分别代表两个不同的轴,每个矩阵都相当于是一个2维 tensor。在 NumPy 中我们可以如此表示:
x = np.array([[5,10,15,30,25],
[20,30,65,70,90],
[7,80,95,20,30]])
同样地,我们也可以把人物的属性存储在一个2维的 tensor 中,非常适用于诸如典型的邮件列表等这样的情况。
假设我们有10000个人,并且每个人又具有以下属性:
姓
名
街道
市
省
国家
邮编
也就是说,这里我们所说的这10000个人都具备以上7种特征。
Tensor 是有“形状”的,这个类似桶一样的“形状”非常适合我们的数据,并且决定着 tensor 的最大尺寸。我们可以把上述人物的属性放入一个形状为(10000, 7)的2维 tensor 中。
你可能在猜想,或许这个 tensor 有10000个列和7个行。
并不是!
每个 tensor 的行与列之间是可以相互转换的,而且可以认为控制,不存在具体的“行”与“列”的定义。
事实上,只有达到3维的情况下,tensor 才开始真正有用。通常情况下,我们需要把2维 tensor 再装进另一个“桶”里,形成3维 tensor。
在 Numpy 中,我们可以这样来表示:
x = np.array([[[5,10,15,30,25],
[20,30,65,70,90],
[7,80,95,20,30]]
[[3,0,5,0,45],
[12,-2,6,7,90],
[18,-9,95,120,30]]
[[17,13,25,30,15],
[23,36,9,7,80],
[1,-7,-5,22,3]]])
每个3维 tensor 都有3个轴,我们可以通过以下代码来看到:
x.ndim
输出结果是:
3
以上面的邮件列表为例。假设现在有10个邮件列表,我们可以把2维张量存至另一个“桶”中,构成3维 tensor。形状如下:
(number_of_mailing_lists,number_of_people,number_of_characteristics_per_person)
(10,10000,7)
你可能已经猜到了,3维 tensor 是数字立方。
我们可以继续堆砌这样的立方体来构建越来越大的 tensor,最终构建出4维、5维乃至N维的 tensor。
实际上,3维 tensor 用层级网格来表示的话,效果会更好:
以下是几类常见的数据集,我们将其存储在各种不同的 tensor 中:
3D = 时间序列
4D = 图像
5D = 视频
其中一条贯穿所有 tensors 的线索就是“样本大小”。所谓样本大小指的是数据集中的数据个数,可以是图片的张数、视频的段数、文件的份数,也可以是微博的条数。
一般情况下,实际的数据都会比样本小一些:
rest_of_dimensions - sample_size =actual_dimensions_of_data
考虑到不同维数下的形状(以不同的维度代表),我们要寻找能够描述数据的最少维度。
4维 tensor 通常用于存储图像,这是因为样本大小就是 tensor 的第4个维度。
例如,一张图片可以用3个维度来表征:
(width, height, color_depth) = 3D
但在机器学习中,我们一般不是只跟一张图片或一份文件打交道,而是一个庞大的数据集。我们可能会有10,000张郁金香的照片,这就意味着它是一个4维 tensor,如:
(sample_size, width, height,color_depth) = 4D
下面我们一同来看几个不同维度的 tensors 的实例。
3维tensor对于时序数据非常有效。
医学影像
我们可以把脑电波 EEG 信号编码为3维 tensor,因为它可以用3个参数指代:
(time, frequency, channel)
转换过程大致如下:
现在如果我们有很多病人扫描了脑电波,那么就会变成个4维的 tensor 了,如下:
(sample_size, time, frequency, channel)
股价
股价可以说是瞬息万变,分分钟都处于变化之中,有高价、低价和最终价。纽交所从上午9:30开到下午4:00,共计6个半小时,390分钟。 股价的变化一般用K线图表示:
我们可以把每分钟的高价、低价和最终价存储在2维 tensor 中(390,3)。如果想要观察一星期(5个交易日)的变化情况,就要用到3维 tensor 了,形状如下:
(week_of_data, minutes, high_low_price)
其表现形式为:
(5,390,3)
如果我们有10支不同的股票,那么就会变成4维 tensor,其形状如下:
(10,5,390,3)
假设现在有个互惠基金,由若干支股票组成,以4维 tensor 的形式来表征。我们可以持有25支互惠基金作为投资组合,于是就会有一系列的4维 tensor,这就相当于我们拥有了一个5维 tensor,其形状如下:
(25,10,5,390,3)
文本数据
文本数据也可以存为3维 tensor,以 Tweets 为例。
Tweets 由140个字符组成。它采用的是 UTF-8 标准,虽然可以呈现上百万字,但实际上我们只对前128个感兴趣,因为它与 ASCII 的编码是一样的。单条 tweet 可以装载进一个(140,128)的2维矢量。
假如我们下载了100万条 Trump 的 tweets,我们可以以3维 tensor 的形式进行存储,形式如下:
(number_of_tweets_captured, tweet,character)
这就意味着,有关 Donald Trump 的新闻可以表示如下:
(1000000,140,128)
4维张量非常适合存储一系列图像(如 Jpeg 格式)。如前所述,一张图片可以有以下三个参数:
宽
高
色彩深度
单张图片是3维的,但是一系列的图片就变成4维的了。这里的第4维就是 sample_size。
著名的 MNIST 数据集实际就是一系列手写数字,曾经是困扰众多数据科学家的难题,但如今已经解决。机器已经能够达到99%甚至更高的精度。但是这个数据集仍然发挥着余热,通常用作新机器学习应用的样板,或者练手的素材。
Keras 甚至集成了 MNIST 数据集,只需要简单的命令就可以实现自动导入:
from keras.datasets import mnist
(train_images, train_labels),(test_images, test_labels) = mnist.load_data()
数据集被分为两部分:
训练集
测试集
每个图片都有一个标签,即该图的真实数字,如3、7或9等,这些标签是人工手动添加的。
训练集用来教会神经网络,测试集则是神经网络学习后试图分类的目标。
MNIST 都是灰度图像,也就是说可以将其编码为2维 tensor。但是按照惯例,所有图片依旧编码为3维 tensor,第三个轴代表色彩深度。
MNIST 数据集中有60,000张图片,每张图片的长和宽均为28像素,色彩深度为1,即灰度图片。
TensorFlow 是这样存储图片的:
(sample_size, height, width,color_depth)
因此,我们可以得到 MNIST 数据集的4维 tensor,形式如下:
(60000,28,28,1)
彩色照片有着不同的色彩深度,取决于分辨率和编码格式。典型的 JPG 图像是用 RGB 编码的,所以色彩深度为3,分别代表着红、绿、蓝。
这是我家的猫 Dove 的照片,图片的分辨率为750x750(实际上是751x750,因为我在用 Photoshop 处理图片的时候出了点小差错,但是请假装它是750x750的吧!)。这就意味着,我们会有个3维 tensor:
(750,750,3)
接下来我家 Dove 将要变成一系列冷冰冰的 tensor 和公式了,与神经网络中的“变形”或是“流动”(Flow)过程类似。
假设我们有一堆各种猫的图片(尽管它们都没有 Dove 漂亮),例如10,000张别家猫的750x750照片。在Keras中,我们可以这样定义该4维 tensor:
(10000,750,750,3)
5维张量可以存视频数据。在 TensorFlow 中,视频数据的编码形式如下:
(sample_size, frames, width, height,color_depth)
如果我们有一个5分钟的视频(300秒),其为1080p的高清视频(1920x1080像素),每秒有15个关键帧,色彩深度3,那么我们就可以将其存储在4维的 tensor 中了,形式如下:
(4500,1920,1080,3)
Tensor 中的第五个维度是视频集中的视频个数。所以如果我们有10个视频的话,就可以得到5维 tensor:
(10,4500,1920,1080,3)
这个例子其实很疯狂。
张量的体积可以大到不可思议,甚至能超过1TB。在现实世界中,我们需要尽可能地缩小采样视频的大小,否则模型可能永远都训练不完。
5维 tensor 的值的个数为:
10 x 4500 x 1920 x 1080 x 3 =279,936,000,000
Keras 允许我们使用32位或64位的浮点数(dtype):
float32
float64
上述每个值都是一个32位的数字,也就是说我们要用值的个数乘以32,转换为比特数,继而转换为TB:
279,936,000,000 x 32 =8,957,952,000,000
我不觉得这适用于32位系统(我会再找人再确认一下这个数字),所以还是需要下采样。
实际上,我之所以引用这个疯狂的例子,是为了引出预处理和数据缩减。
你不能直接就把原始数据扔进 AI 模型中,必须对原始数据进行必要的整理和压缩,使其更易于处理。
此外,降低分辨率、删减冗余数据、限制帧数等也是数据科学家的任务之一。
如果你不能把数据玩儿坏,那么你也不能把它玩儿好。
现在你应该对 tensor 及相关的数据类型有了更好的理解。
在下一篇中,我们将学习如何用数学方法对 tensor 进行变形。也就是说,我们要让 Tensor "flow" 起来。
本文作者 Daniel Jeffries 是一位作家、工程师和企业家,研究领域涵盖了从 Linux 到虚拟化和容器的各种技术。
本文由 AI100 编译,转载需得到本公众号同意。
编译:AI100
原文链接:https://hackernoon.com/learning-ai-if-you-suck-at-math-p4-tensors-illustrated-with-cats-27f0002c9b32