深度学习:从基础到实践(全2册)
上QQ阅读APP看书,第一时间看更新

2.2 随机变量

随机数在许多机器学习算法中都起着重要的作用,我们会使用各种工具来控制随机数的种类以及对它们的选择,而不是凭空挑选任意的数字。

这种思想是这样的,当有人跟我们说:“从1~10选一个数字”,这时他就把我们的选择限制在这个范围内的10个整数(integer)中。当魔术师让我们“选择一张牌”时,他们通常会给我们一副有52张的牌,让我们从中任选一张。在这两个例子中,我们的选择都来自有限数量的选项(分别是10个和52张)。但是我们也可以有无数个选择。有人可能会让我们“从1~10中选出一个实数”,然后我们就可以选择3.3724或者6.9858302,抑或是1和10之间无限多的实数(real number)中的任何一个。

在谈论数字的范围时,我们经常讨论的是它们的“平均值”,这里有3种不同的常见的平均值类型,让我们在此命名它们,以免日后混淆。

作为示例,我们列出了5个数字:1、3、4、4、13。

均值(mean)是我们日常用语中所说的“平均”,它是由所有条目之和除以列表中的条目数得到的。在上述示例中,我们将所有列表元素相加得到25,有5个元素,那么均值是25/5,也即5。

众数是列表中出现频率最高的值。在上述示例中,4出现了两次,其他3个值都只出现了一次,因此4是众数。如果没有值出现的频率比其他任何值都高,就说列表没有众数。

把列表数字按照从小到大的顺序排列时,中间的数字是中位数(median)。在已经排好序的列表中,左边是1和3,右边是4和13,中间是4,所以4是中位数。如果一个列表包含偶数个条目,中位数就是两个中间条目的平均值,对于列表1、3、4、8,中位数是3和4的平均值,也就是3.5。

让我们用一个类比来进一步研究这些问题。假设我们是摄影师,要给一篇关于汽车垃圾场的文章配上很多报废汽车的照片,为此我们去了一个汽车垃圾场,那里有数百辆报废的车辆,很有冒险的感觉。

我们与汽车垃圾场场主沟通,并谈妥了她为我们寻找每一辆可拍摄汽车的价格。为了让这件事更有趣,她在办公室里放置了一个老式的嘉年华轮盘,每辆车都对应着一个条框,各个条框的大小是相同的,如图2.1所示。

图2.1 汽车垃圾场场主的嘉年华轮盘。每辆车都对应一个大小相同的条框,每个条框都对应一个数字,当轮盘停下来时,她就会带我们去拍指针所指的车

我们一付钱,她就转动轮盘,当轮盘停下来时,她会记下车号,然后出去用拖车把相应的车辆拖到我们面前。

我们拍了几张照片,她就会把车还到停车场。如果我们想再拍一辆车,就需要再付钱,她会再次转动轮盘,重复上述过程。

对于我们而言,她带给我们的每一辆车都是随机选择的,因为我们事先不知道是哪一辆。但汽车也不是完全任意的,因为我们在开始之前就知道一些关于车辆的信息,例如,它不可能是未来的汽车,也不可能是一辆没有停在该停车场的汽车。所以汽车垃圾场场主并没有(通过她的嘉年华轮盘)选择所有可能的车辆,而选择的是她可以选择的特定选项。

假设我们的任务目标是拍摄5种不同类型汽车的照片:轿车、皮卡、面包车、SUV和货车。我们想知道当她每次转动轮盘并从停车场里随机取出一辆车时,该车是其中一种的概率。

为了解决这个问题,假设我们进入汽车垃圾场检查了每一辆车,并把每一辆车归到这5种类型中的一种,结果如图2.2所示。

图2.2 该汽车垃圾场中有5种不同类型的汽车,每种类型的车的数量用条形图加以表示

在这个汽车垃圾场中,有近950辆汽车,其中面包车最多,其次是皮卡、货车、轿车和SUV。因为这里的每一辆车被选中的概率相等,那么旋转一次轮盘后,我们最有可能得到一辆面包车。

但是具体而言,我们有多大可能得到一辆面包车呢?为了回答这个问题,我们可以用每一个条形块的高度除以汽车的总数,就可以得出我们得到选择给定类型的汽车的概率,如图2.3所示。

图2.3 如果我们进入汽车垃圾场,并且随机选择一辆车,那么得到每种类型的车的概率取决于有多少辆这种类型的车,并且与车的总数有关。最终我们一定会得到什么东西,因此所有概率加起来应该等于1。如果将所有可能性包含进来而且所有概率加起来已经为1,就可以称其为概率分布

为了将图2.3中的数字转换为百分比,我们将它们乘以100%,例如,面包车在条形图中的高度是0.34,就说有34%的机会得到一辆面包车。

如果我们把所有5根条形的高度加起来,就会发现其总和是1。每个条形块的高度被称为我们得到这种类型的车的概率(probability)。只有所有条形块相加会得到1,才能使用这个术语,这告诉我们得到某物的概率是1(或100%),或者说是必然的。如果这些条形块加起来不等于1,那么我们可以把这些条形图称为各种各样的非正式名称(如“得到这种车的期望”),但是不能把它们称为概率。

我们将图2.3称为概率分布(probability distribution),因为它将100%的概率“分布”在5个可能选项中。我们有时也会说,图2.3是图2.2的归一化(normalized)版本。这里的“归一化”意味着这些值加起来等于1,在这种情况下,“归一”的用法来自它在数学中的含义。

我们可以将概率分布表示为一个简化的嘉年华轮盘,如图2.4所示。指针指向给定区域的概率是通过占轮盘圆周的部分来表达的,我们在这里所画出的比例与图2.3中的相同。

图2.4 一个简化的嘉年华轮盘。这告诉我们如果汽车垃圾场场主旋转图2.1中的轮盘,我们会得到什么样的车。每种车型的圆周占比遵循图2.3中的概率分布

大多数情况下,在计算机上生成随机数时,我们并没有嘉年华轮盘,而是依赖软件去模拟这个过程。我们会给例程一个值列表,比如图2.3中的各个条形的高度,然后让它返回一个值。我们会设定希望能在34%的情况下得到“面包车”,26%的情况下得到“皮卡”,以此类推。

要从选项列表中“随机”选择一个值(每个选项都有自己的概率),就需要做一些工作。为了方便起见,我们将这个选择的过程打包到一个称为随机变量(random variable)的概念中。这个术语可能会让程序员感到困惑,因为程序员认为“变量”是一种被命名的可以存储数据的存储空间。但是,我们在这里使用的术语是来自它在数学中的用法,有着不同的含义。

随机变量不是一个存储的空间,而是一个函数(function),意味着它将一些信息作为输入,并产出一些信息作为输出[Wikipedia17c]。在这种情况下,随机变量的输入是概率分布(或者说是它能产生的每个可能值的概率),而它的输出则是一个特定的根据概率选择的值,生成这个值的过程称为从随机变量中抽取(draw)值。

我们把图2.3称为概率分布,但也可以把它看作一个函数,也就是说,对于每个输入值(在本例中是车的类型),它会返回一个输出值(得到那种类型的车的概率)。这样想,我们就得到了一个更加完整和正式的名字:概率分布函数(probability distribution function)或者pdf(通常小写)。有时人们也会用更加隐晦的名字来指代这种分布:概率质量函数(probability mass function)或pmf

我们的概率分布函数有着有限数量的选项,每个选项都有一个概率,因此我们也可以进一步专门化它的名称,将其称为离散概率分布(discrete probability distribution)(末尾加不加“函数”都可以)。这个名称表明它的选项是离散的(如整数),而不是连续的(如实数)。

我们可以很容易地创建连续的概率分布。假设我们想知道汽车垃圾场场主展示给我们的每辆车里还剩下多少油,油量就是一个连续的变量,因为它可以取任意的实数(当然,是测量仪器可测范围内的实数。这里假设测量是如此精确,以至于我们可以把它看作连续值)。

图2.5显示了汽油测量的连续图。这幅图展示了不同返回值的概率,不只是一些特定值,而是任意实数,这里这个实数是在0(油箱是空的)和1(油箱是满的)之间的。

图2.5 一个连续范围内值的概率分布,所有概率之和仍然是1。注意,纵轴范围为0~0.018

像图2.5这样的分布称为连续概率分布(continuous probability distribution,cpd)或概率密度函数,后一个术语也被缩写为pdf,但是上下文通常会清楚地表明缩写所指代的内容。

图2.5显示了从0到约0.02的输入值,但输入是可以跨越任何范围的,唯一的条件与之前一样,即图表必须进行归一化,这意味着所有值加起来必须等于1。当曲线连续时,曲线下方面积为1。

大多数情况下,我们是通过选择一个符合自身要求的分布来使用随机数的,然后调用库函数来从这一分布中产生一个值(也就是说,我们从给定分布的随机变量中抽取了一个值)。

我们可以在需要的时候创建自己的分布,但是大多数库会提供一些分布。这些分布基本上可以涵盖大多数情况。这样我们就可以使用这些预先构建的、预先归一化的分布来控制随机数。

实践中的随机数

我们一直在讨论通过一个分布来构建一个随机数,这里有必要暂停一下,来看看这个概念在理论与实践表现中有什么不同。

这里的“随机”指的是“不可预测的”,不仅是说这个数字很难预测,比如一个灯泡能用多久。因为如果有足够的信息,我们就能算出灯泡的使用寿命。但是相比之下,随机数从根本上来说就是不可预测的(要得出一个数字或一串数字何时从“难以预测”转变为“不可预测”是一个很大的挑战,远远超出了本书[Marsaglia02]的范畴)。

使用计算机很难得到不可预测的随机数[Wikipedia17b],问题在于正常运行的计算机程序是具有确定性的(deterministic),这意味着给定的输入总是会产生相同的输出。所以从根本上说,如果我们能够访问源代码,那么一个计算机程序永远不会出乎我们的意料。给我们“随机数”的库的例程也只是一些程序。和其他程序一样,每当我们调用这些例程时,如果足够仔细地观察它在做什么,就能够预测它的返回值,换句话说,这并不是随机的。为了强调这一点,我们有时把这些算法称为伪随机数生成器,称它们产生的是伪随机数(pseudo-random number)。

假设我们正在编写一个使用伪随机数的程序,随后出现了一些问题。为了调试这个问题,我们希望它再次按照相同的操作形式运行,换句话说,我们希望它返回错误发生时使用的伪随机数流。

我们之所以能做到这一点,是因为伪随机数生成器以序列的形式生成它们的输出,每个新的值都建立在对以前的值的计算之上。为此,我们会给这个例程一个名为种子的数字。许多库的程序都是从一个种子开始的,这个种子来自当前的时间,或者是从鼠标指针移动那一刻起的毫秒数,抑或是其他我们无法预先预测的值,这使得第一个输出变得不可预测,并为下一个输出奠定了基础。

因此,在开始要求产生输出之前,我们可以手动设置种子,这样在每次运行程序时,都会得到相同的伪随机数序列。

如果我们不想的话,就不需要设定种子。随机数字可以通过不断变化、不可预知的场景照片来生成,就像熔岩灯墙[Schwab17]那样。真实的随机数也可以通过真实的物理数据来在线获取,例如大气噪声导致的天线上的静电干扰[Random17]。通常,以这种形式获取值要比使用内置的伪随机数生成器慢得多,但是当我们需要真正的随机数时,这就是一种选择。

一种可能的折中方法是从物理数据中收集一组真正的随机数,然后将它们存储在文件中。之后,就像使用只有一个种子的某个伪随机数生成器一样,每次都会得到相同的值,但我们知道这些值是随机的。当然,每次使用相同的数字序列意味着它们不再是不可预测的,因此这种技术在系统的设计和调试阶段可能会显得尤为有用。

在实践中,我们很少使用前缀“伪”来表示软件生成的随机数,但要记住是有这么一个东西存在的,因为每个伪随机数生成器都存在一些风险,它们创建的数字可能具有一些可辨别的模式 [Austin17],而这些模式可能会对学习算法产生影响。幸运的是,一个不可预测的种子和一个精心设计的伪随机算法的结合就可以为我们提供一系列值来很好地模拟所需的真正随机数。也许随着机器学习的发展,一些算法将会出现,它们会对“接近”随机的数字序列和真正随机的数字序列之间的差异表现得很敏感,这可能会迫使我们采取新的策略来生成这些值,而现在似乎还没到那个时候。