线性回归

单变量线性回归 (Linear Regression with One Variable)

模型表示(Model Representation)

我们的第一个学习算法是线性回归算法。在本节课中,你会看到这个算法的概况,更重要的是你将会了解监督学习过程完整的流程。

让我们通过一个例子来开始:这个例子是预测住房价格的,我们要使用一个数据集,数据集包含俄勒冈州波特兰市的住房价格。在这里,我要根据不同房屋尺寸所售出的价格,画出我的数据集。比方说,如果你朋友的房子是 1250 平方尺大小,你要告诉他们这房子能卖多少钱。那么,你可以做的一件事就是构建一个模型,也许是条直线,从这个数据模型上来看,也许你可以告诉你的朋友,他能以大约 220000 美元左右的价格卖掉这个房子。这就是监督学习算法的一个例子。

它被称作监督学习是因为对于每个数据来说,我们给出了 "正确的答案",即告诉我们:根据我们的数据来说,房子实际的价格是多少,而且,更具体来说,这是一个回归问题。回归一词指的是,我们根据之前的数据预测出一个准确的输出值,对于这个例子就是价格,同时,还有另一种最常见的监督学习方式,叫做分类问题,当我们想要预测离散的输出值,例如,我们正在寻找癌症肿瘤,并想要确定肿瘤是良性的还是恶性的,这就是 0/1 离散输出的问题。更进一步来说,在监督学习中我们有一个数据集,这个数据集被称训练集。

因此对于房价的例子,我们有一个训练集,包含不同的房屋价格,我们的任务就是从这个数据中学习预测房屋价格。现在我们给出这门课中经常使用的一些符号定义,我们要定义颇多符号,不过没关系,现在你记不住所有的符号也没关系,随着课程的进展,你会发现记住这些符号会很有用。

我将在整个课程中用小写的 \(m\) 来表示训练样本的数目。因此,在这个数据集中,如果表中有 47 行,那么我们就有 47 组训练样本,\(m\) 就等于 47。让我用小写字母 \(x\) 来表示输入变量,往往也被称为特征量,这就是用 \(x\) 表示输入的特征,并且我们将用 \(y\) 来表示输出变量或者目标变量,也就是我的预测结果。那么这就是第二列,在这里,我要使用 \((x, y)\) 来表示一个训练样本,所以,在这个表格中的单独的一行对应于一个训​​练样本,为了表示某个训练样本,我将使用 \(x\) 上标 \((i)\)\(y\) 上标 \((i)\) 来表示。所以 \(x^{(i)}\) 表示第 \(i\) 个训练样本,所以这个上标 \(i\) 不是求幂运算。这个 \((x^{(i)}, y^{(i)})\) 括号里的上标 \(i\) 只是一个索引,表示我的训练集里的第 \(i\) 行,这里不是 \(x\)\(i\)\(y\)\(i\) 次方,仅仅是指 \((x^{(i)}, y^{(i)})\) 是在此表中的第 \(i\) 行。举个例子 \(x^{(1)}\) 指的是第一个训练集里值为 2104 的输入值,这个就是第一行里的 \(x\)\(x^{(2)}\) 等于 1416 吧?这是第二个 \(x\)\(y^{(1)}\) 等于 460,这是我第一个训练集样本的 \(y\) 值,这就是 \((1)\) 所代表的含义。

\(m\) 代表训练集中实例的数量
\(x\) 代表特征 / 输入变量
\(y\) 代表目标变量 / 输出变量
\((x,y)\) 代表训练集中的实例
\((x^{(i)},y^{(i)})\) 代表第 \(i\) 个训练样本
\(h\) 代表学习算法的解决方案或函数也称为假设(hypothesis)

这就是一个监督学习算法的工作方式,我们可以看到这里有我们的训练集里房屋价格,我们把它喂给我们的学习算法,这就是学习算法的工作了。然后输出一个函数,按照惯例,通常表示为小写 \(h\),代表 hypothesis(假设)。\(h\) 表示一个函数,输入是房屋尺寸大小,就像你朋友想出售的房屋。因此,\(h\) 根据输入的 \(x\) 值来得出 \(y\) 值,\(y\) 值对应房子的价格。因此,\(h\) 是一个从 \(x\)\(y\) 的函数映射。人们经常问我为什么这个函数被称作假设(hypothesis),你们中有些人可能知道 hypothesis 的意思,从字典或者其它什么方式可以查到。其实在机器学习中,这是一个在早期被用于机器学习的名称,它有点绕口。对这类函数来说,这可能不是一个很恰当的名字,对表示从房屋的大小到价格的函数映射,我认为这个词 "hypothesis" 可能不是最好的名称。但是这是人们在机器学习中使用的标准术语,所以不用太纠结人们为什么这么叫它。

当设计学习算法的时候,我们接下来需要去思考的是,怎样得到这个假设 \(h\),对于这一点在接下来的几节课程中,我将选择最初的使用规则 \(h\) 代表 hypothesis,我们把 \(h\) 写成 \(h_{\theta}(x)=\theta_0+\theta_1x\)。有时候简单起见,\(h_{\theta}(x)\) 我就写成 \(h(x)\),这是缩写方式,但一般来说我会保留这个下标 \(\theta\)。从这个图片中 所有这一切意味着我们要预测一个关于 \(x\) 的线性函数 \(y\) 对吧? 所以这就是数据集和函数的作用,用来预测,这里是 \(y\) 关于 \(x\) 的线性函数 \(h_{\theta}(x)=\theta_0+\theta_1x\)。那么为什么是一个线性函数呢? 有时候,我们会有更复杂的函数,也许是非线性函数。但是,由于线性方程是简单的形式,我们将先从线性方程的例子入手。当然,最终我们将会建立更复杂的模型,以及更复杂的学习算法。好吧,让我们也给这模型起一个名字,这个模型被称为线性回归(linear regression)模型。另外,这实际上是关于单个变量的线性回归,这个变量就是 \(x\),根据 \(x\) 来预测所有的价格函数。同时,对于这种模型有另外一个名称,称作单变量线性回归,单变量是对一个变量的一种特别的表述方式。

总而言之,这就是线性回归。在接下来的课程中,我们将开始讨论如何去实现这种模型。

代价函数(Cost Function)

在本节中我们将定义代价函数的概念,这有助于我们弄清楚如何把最有可能的直线与我们的数据相拟合。

在线性回归中我们有一个像这样的训练集,\(m\) 代表了训练样本的数量,比如 \(m = 47\)。而我们的假设函数,也就是用来进行预测的函数,是这样的线性函数形式:\(h_\theta(x)=\theta_0+\theta_1x\)

接下来我们会引入一些术语,这些 \(\theta_0\)\(\theta_1\)。这些 \(\theta_i\) 我把它们称为模型参数。在这本节课中,我们要做的就是谈谈如何选择这两个参数值 \(\theta_0\)\(\theta_1\)。选择不同的参数 \(\theta_0\)\(\theta_1\) 我们会得到不同的假设函数。我知道你们中的有些人可能已经知道我在这张幻灯片上要讲的,但我们还是用这几个例子来复习回顾一下。如果 \(\theta_0\) 是 1.5,\(\theta_1\) 是 0,那么假设函数会看起来是这样,是吧。因为你的假设函数是 \(h(x)=1.5+0*x\),是这样一个常数函数,恒等于 1.5。如果 \(\theta_0=0\) 并且 \(\theta_1=0.5\),那么假设会看起来像这样,它会通过点 \((2,1)\),这样你又得到了 \(h(x)\) 或者 \(h_{\theta}(x)\),但是有时我们为了简洁会省略 \(\theta\)。因此 \(h(x)\) 将等于 0.5 倍的 \(x\),就像这样。最后,如果 \(\theta_0=1\) 并且 \(\theta_1=0.5\),我们最后得到的假设会看起来像这样,让我们来看看,它应该通过点 \((2,2)\),这是我的新的 \(h(x)\) 或者写作 \(h_{\theta}(x)\) 对吧?你还记得之前我们提到过 \(h_{\theta}(x)\) 的,但作为简写,我们通常只把它写作 \(h(x)\)。在线性回归中,我们有一个训练集,可能就像我在这里绘制的,我们要做的就是得出 \(\theta_0\)\(\theta_1\) 这两个参数的值,来让假设函数表示的直线,尽量地与这些数据点很好的拟合,也许就像这里的这条线一样。

那么我们如何得出 \(\theta_0\)\(\theta_1\) 的值,来使它很好地拟合数据的呢?我们的想法是,我们要选择能使 \(h(x)\),也就是输入 \(x\) 时,我们预测的值最接近该样本对应的 \(y\) 值的参数 \(\theta_0\)\(\theta_1\)。所以,在我们的训练集中我们会得到一定数量的样本,我们知道 \(x\) 表示卖出哪所房子,并且知道这所房子的实际价格。所以,我们要尽量选择参数值,使得在训练集中给出训练集中的 \(x\) 值,我们能合理准确地预测 \(y\) 的值。让我们给出标准的定义,在线性回归中,我们要解决的是一个最小化问题,所以我要写出关于 \(\theta_0\)\(\theta_1\) 的最小化。而且,我希望这个式子极其小,是吧?我想要 \(h(x)\)\(y\) 之间的差异要小,我要做的事情是尽量减少假设的输出与房子真实价格之间的差的平方,明白吗?接下来我会详细的阐述,别忘了我用符号 \((x^{(i)},y^{(i)})\) 代表第 \(i\) 个样本。所以我想要做的是对所有训练样本进行一个求和,对 \(i=1\)\(i=m\) 的样本,将对假设进行预测得到的结果,此时的输入是第 \(i\) 号房子的面积,对吧?将第 \(i\) 号对应的预测结果,减去第 \(i\) 号房子的实际价格,所得的差的平方相加得到总和,而我希望尽量减小这个值,也就是预测值和实际值的差的平方误差和,或者说预测价格和实际卖出价格的差的平方。我说了这里的 \(m\) 指的是训练集的样本容量,对吧?这个井号是训练样本 "个数" 的缩写,对吧?而为了让表达式的数学意义变得容易理解一点,我们实际上考虑的是这个数的 1/m,因此我们要尝试尽量减少我们的平均误差,也就是尽量减少其 1/2m。通常是这个数的一半,前面的这些只是为了使数学更直白一点,因此对这个求和值的二分之一求最小值,应该得出相同的 \(\theta_0\) 值和相同的 \(\theta_1\) 值来。请大家一定弄清楚这个道理,没问题吧?在这里 \(h\theta(x)\) 的这种表达是我们的假设,它等于 \(\theta_0\) 加上 \(\theta_1\)\(x^{(i)}\) 的乘积。而这个表达,表示关于 \(\theta_0\)\(\theta_1\) 的最小化过程,这意味着我们要找到 \(\theta_0\)\(\theta_1\) 的值,来使这个表达式的值最小,这个表达式因 \(\theta_0\)\(\theta_1\) 的变化而变化对吧?因此,简单地说,我们正在把这个问题变成,找到能使我的训练集中预测值和真实值的差的平方的和的 1/2m 最小的 \(\theta_0\)\(\theta_1\) 的值。因此,这将是我的线性回归的整体目标函数,为了使它更明确一点,我们要改写这个函数。按照惯例,我要定义一个代价函数,正如屏幕中所示,这里的这个公式,我们想要做的就是关于 \(\theta_0\)\(\theta_1\) 对函数 \(J(\theta_0,\theta_1)\) 求最小值,这就是我们的代价函数。代价函数也被称作平方误差函数,有时也被称为平方误差代价函数。事实上,我们之所以要求出误差的平方和,是因为误差平方代价函数对于大多数问题,特别是回归问题,都是一个合理的选择。

还有其他的代价函数也能很好地发挥作用,但是平方误差代价函数可能是解决回归问题最常用的手段了。在后续课程中,我们还会谈论其他的代价函数,但我们刚刚讲的选择是对于大多数线性回归问题非常合理的,好吧?到目前为止,我们已经介绍了代价函数的数学定义,也许这个函数 \(J(\theta_0,\theta_1)\) 有点抽象,可能你仍然不知道它的内涵,在接下来的几节课里,我们要更进一步解释代价函数 \(J\) 的工作原理,并尝试更直观地解释它在计算什么,以及我们使用它的目的。

代价函数的直观理解 I(Cost Function - Intuition I)

在上节课中,我们给了代价函数一个数学上的定义。在本节课里,让我们通过一些例子来获取一些直观的感受,看看代价函数到底是在干什么。

回顾一下,这是我们上次所讲过的内容,我们想找一条直线来拟合我们的数据,所以我们用 \(\theta_0\)\(\theta_1\) 等参数,得到了这个假设,而且通过选择不同的参数,我们会得到不同的直线拟合,所以拟合出的数据就像这样。然后我们还有一个代价函数,这就是我们的优化目标。在本节课里,为了更好地将代价函数可视化,我将使用一个简化的假设函数,就是右边这个函数。然后我将会用这个简化的假设,也就是 \(\theta_1*x\),我们可以将这个函数看成是把 \(\theta_0\) 设为 0,所以我只有一个参数,也就是 \(\theta_1\)。代价函数看起来与之前的很像,唯一的区别是现在 \(h(x)\) 等于 \(\theta_1*x\),只有一个参数 \(\theta_1\)。所以我们的优化目标是将 \(J(\theta_1)\) 最小化。用图形来表示就是,如果 \(\theta_0\) 等于零,也就意味这我们选择的假设函数会经过原点,也就是经过坐标 (0,0)。通过利用简化的假设得到的代价函数,我们可以试着更好地理解代价函数这个概念。我们要理解的是这两个重要的函数,第一个是假设函数,第二个是代价函数。注意这个假设函数 \(h(x)\) 对于一个固定的 \(\theta_1\),这是一个关于 \(x\) 的函数。所以这个假设函数就是一个关于 \(x\) 这个房子大小的函数。与此不同的是,代价函数 \(J\) 是一个关于参数 \(\theta_1\) 的函数,而 \(\theta_1\) 控制着这条直线的斜率。现在我们把这写函数都画出来,试着更好地理解它们。我们从假设函数开始,比如说这里是我的训练样本,它包含了三个点 (1,1) (2,2) 和 (3,3)。现在我们选择一个值 \(\theta_1\),所以当 \(\theta_1\) 等于 1,如果这是我选择的 \(\theta_1\),那么我的假设函数看起来就会像是这条直线。我将要指出的是,当我描绘出我的假设函数 X 轴,我的横轴被标定为 X 轴,X 轴是表示房子大小的量。现在暂时把 \(\theta_1\) 定为 1,我想要做的就是算出在 \(\theta_1\) 等于 1 的时候 \(J(\theta_1)\) 等于多少。所以我们按照这个思路来计算代价函数的大小,和之前一样,代价函数定义如下,是吧?对这个误差平方项进行求和,这就等于这样一个形式,简化以后就等于三个 0 的平方和,当然还是 0。现在,在代价函数里,我们发现所有这些值都等于 0。因为对于我所选定的这三个训练样本 ( 1 ,1 ) (2,2) 和 (3,3),如果 \(\theta_1\) 等于 1,那么 \(h(x^{(i)})\) 就会正好等于 \(y^{(i)}\)。让我把这个写得好一点,对吧?所以 \(h(x)-y\),所有的这些值都会等于零,这也就是为什么 \(J(1)\) 等于零。所以,我们现在知道了 \(J(1)\) 是 0。让我把这个画出来,我将要在屏幕右边画出我的代价函数 \(J\)。要注意的是,因为我的代价函数是关于参数 \(\theta_1\) 的函数,当我描绘我的代价函数时,X 轴就是 \(\theta_1\),现在我有 \(J(1)\) 等于零。让我们继续把函数画出来,结果我们会得到这样一个点。现在我们来看其它一些样本 \(\theta_1\) 可以被设定为某个范围内各种可能的取值。所以 \(\theta_1\) 可以取负数 0,或者正数。所以如果 \(\theta_1\) 等于 0.5 会发生什么呢?继续把它画出来,现在要把 \(\theta_1\) 设为 0.5,在这个条件下,我的假设函数看起来就是这样,这条线的斜率等于 0.5。现在让我们计算 \(J(0.5)\),所以这将会等于 1 除以 2m 乘以那一块,其实我们不难发现后面的求和,就是这条线段的高度的平方,加上这条线段高度的平方,再加上这条线段高度的平方,三者求和,对吗?就是 \(y^{(i)}\) 与预测值 \(h(x^{(i)})\) 的差,对吗?所以第一个样本将会是 0.5 减去 1 的平方,因为我的假设函数预测的值是 0.5,而实际值则是 1。第二个样本,我得到的是 1 减去 2 的平方,因为我的假设函数预测的值是 1,但是实际房价是 2。最后,加上 1.5 减去 3 的平方,那么这就等于 1 除以 2 乘以 3,因为训练样本有三个点,所以 m 等于 3,对吧?然后乘以括号里的内容,简化后就是 3.5,所以这就等于 3.5 除以 6,也就约等于 0.68。让我们把这个点画出来,不好意思,有一个计算错误,这实际上该是 0.58。所以我们把点画出来,大约会是在这里,对吗?现在,让我们再多做一个点,让我们试试 \(\theta_1\) 等于 0,那么 \(J(0)\) 会等于多少呢?如果 \(\theta_1\) 等于 0,那么 \(h(x)\) 就会等于一条水平的线,对了,就会像这样是水平的。所以,测出这些误差,我们将会得到 \(J(0)\) 等于 1 除以 2m 乘以 1 的平方,加上 2 的平方,加上 3 的平方,也就是 1 除以 6 乘以 14,也就是 2.3 左右。所以让我们接着把这个点也画出来,所以这个点最后是 2.3,当然我们可以接着设定 \(\theta_1\) 等于别的值进行计算,你也可以把 \(\theta_1\) 设定成一个负数,所以如果 \(\theta_1\) 是负数,那么 \(h(x)\) 将会等于,打个比方说 -0.5 乘以 x,然后 \(\theta_1\) 就是 -0.5。那么这将会对应着一个斜率为 -0.5 的假设函数,而且你可以继续计算这些误差,结果你会发现对于 0.5,结果会是非常大的误差,最后会得到一个较大的数值,类似于 5.25 等等。对于不同的 \(\theta_1\) 你可以计算出这些对应的值,对吗?结果你会发现,你算出来的这些值,你得到一条这样的曲线,通过计算这些值,你可以慢慢地得到这条线,这就是 \(J(\theta)\) 的样子了。

我们来回顾一下,任何一个 \(\theta_1\) 的取值对应着一个不同的假设函数,或者说对应着左边一条不同的拟合直线。对于任意的 \(\theta_1\),你可以算出一个不同的 \(J(\theta_1)\) 的取值。举个例子,你知道的 \(\theta_1\) 等于 1 时,对应着穿过这些数据的这条直线。当 \(\theta_1\) 等于 0.5,也就是这个玫红色的点,也许对应着这条线。然后 \(\theta_1\) 等于 0,也就是蓝色的这个点,对应着这条水平的线,对吧?所以对于任意一个 \(\theta_1\) 的取值,我们会得到一个不同的 \(J(\theta_1)\),而且我们可以利用这些来描出右边的这条曲线。现在你还记得,学习算法的优化目标 是我们想找到一个 \(\theta_1\) 的值,来将 \(J(\theta_1)\) 最小化,对吗?这是我们线性回归的目标函数,嗯,看这条曲线,让 \(J(\theta_1)\) 最小化的值是 \(\theta_1\) 等于 1,然后你看,这个确实就对应着最佳的通过了数据点的拟合直线,这条直线就是由 \(\theta_1=1\) 的设定而得到的。然后,对于这个特定的训练样本,我们最后能够完美地拟合,这就是为什么最小化 \(J(\theta_1)\) 对应着寻找一个最佳拟合直线的目标。

总结一下,在本节课里,我们看到了一些图形来理解代价函数,要做到这个,我们简化了算法,让这个函数只有一个参数 \(\theta_1\),也就是说我们把 \(\theta_0\) 设定为 0。在下节课里,我们将回到原来的问题的公式,然后看一些带有 \(\theta_0\)\(\theta_1\) 的图形,也就是说不把 \(\theta_0\) 设置为 0 了,希望这会让你更好地理解在原来的线性回归公式里代价函数 \(J\) 的意义。

代价函数的直观理解 II(Cost Function - Intuition II)

这节课中,我们将更深入地学习代价函数的作用,本节课的内容假设你已经认识轮廓图,如果你对轮廓图不太熟悉的话,本节课中的某些内容你可能会听不懂,但不要紧,如果你跳过本节课的话,也没什么关系,不听这节课对后续课程理解影响不大。

和之前一样,这是我们的几个重要公式,包括了假设 \(h\)、参数 \(\theta\)、代价函数 \(J\),以及优化目标。跟前上节课不同的是,我还是把 \(\theta\) 写成 \(\theta_0\)\(\theta_1\) 的形式,便于这里我们要对代价函数进行的可视化。和上次一样,首先来理解假设 \(h\) 和代价函数 \(J\)。这是房价数据组成的训练集数据,让我们来构建某种假设,就像这条线一样,很显然这不是一个很好的假设,但不管怎样,如果我假设 \(\theta_0\) 等于 50,\(\theta_1\) 等于 0.06 的话,那么我将得到这样一个假设函数。对应于这条直线,给出 \(\theta_0\)\(\theta_1\) 的值,我们要在右边画出代价函数的图像。上一次,我们是只有一个 \(\theta_1\),也就是说,画出的代价函数是关于 \(\theta_1\) 的函数,但现在我们有两个参数 \(\theta_0\)\(\theta_1\),因此图像就会复杂一些了。当只有一个参数 \(\theta_1\) 的时候,我们画出来是这样一个弓形函数,而现在我们有了两个参数,那么代价函数仍然呈现类似的某种弓形,实际上这取决于训练样本。你可能会得到这样的图形,因此这是一个三维曲面图,两个轴分别表示 \(\theta_0\)\(\theta_1\),随着你改变 \(\theta_0\)\(\theta_1\) 的大小,你便会得到不同的代价函数 \(J(\theta_0,\theta_1)\)。对于某个特定的点,\((\theta_0,\theta_1)\) 这个曲面的高度,也就是竖直方向的高度,就表示代价函数 \(J(\theta_0,\theta_1)\) 的值,不难发现这是一个弓形曲面。我们来看看三维图,这是这个曲面的三维图,水平轴是 \(\theta_0\)\(\theta_1\),竖直方向表示 \(J(\theta_0,\theta_1)\)。旋转一下这个图,你就更能理解这个弓形曲面所表示的代价函数了。在本节课的后半部分,为了描述方便,我将不再像这样给你用三维曲面图的方式解释代价函数 \(J\),而还是用轮廓图来表示,contour plot 或 contour figure 意思一样。右边就是一个轮廓图,两个轴分别表示 \(\theta_0\)\(\theta_1\),而这些一圈一圈的椭圆形,每一个圈就表示 \(J(\theta_0,\theta_1)\) 相同的所有点的集合。具体举例来说,我们选三个点出来,这三个桃红色的点,都表示相同的 \(J(\theta_0,\theta_1)\) 的值,对吧?横纵坐标分别是 \(\theta_0\)\(\theta_1\),这三个点的 \(J(\theta_0,\theta_1)\) 值是相同的。如果你之前没怎么接触轮廓图的话,你就这么想,你就想象一个弓形的函数从屏幕里冒出来,因此最小值,也就是这个弓形的最低点就是这个点,对吧?也就是这一系列同心椭圆的中心点,想象一下这个弓形从屏幕里冒出来,所以这些椭圆形都从我的屏幕上冒出相同的高度,弓形的最小值点是这个位置,因此轮廓图是一种很方便的方法,能够直观地观察代价函数 \(J\)

接下来让我们看几个例子,在这里有一点,这个点表示 \(\theta_0\) 等于 800,\(\theta_1\) 大概等于 -0.15。那么这个红色的点,代表了某个 \((\theta_0,\theta_1)\) 组成的数值组,而这个点也对应于左边这样一条线,对吧?\(\theta_0\) 等于 800,也就是跟纵轴相交于大约 800,斜率大概是 -0.15。当然,这条线并不能很好地拟合数据,对吧?以这组 \(\theta_0\)\(\theta_1\) 为参数的这个假设 \(h(x)\) 并不是数据的较好拟合。并且你也发现了这个代价值,就是这里的这个值,距离最小值点还很远,也就是说这个代价值还是算比较大的,因此不能很好拟合数据。让我们再来看几个例子,这是另一个假设,你不难发现,这依然不是一个好的拟合,但比刚才稍微好一点,这是我的 \(\theta_0\)\(\theta_1\) 点,这是 \(\theta_0\) 的值,大约为 360,\(\theta_1\) 的值为 0。我们把它写下来 \(\theta_0=360\)\(\theta_1=0\)。因此这组 \(\theta\) 值对应的假设是,这条水平的直线,也就是 \(h(x)=360+0\times x\),这就是假设,这个假设同样也有某个代价值,而这个代价值就对应于这个代价函数在这一点的高度。让我们再来看一些例子,这是另一个例子,这个点,这组 \(\theta_0\)\(\theta_1\) 对应这样一条假设 \(h(x)\),同样地,还是对数据拟合不好,离最小值更远了。最后一个例子,这个点其实不是最小值,但已经非常靠近最小值点了,这个点对数据的拟合就很不错,它对应这样两个 \(\theta_0\)\(\theta_1\) 的值,同时也对应这样一个 \(h(x)\),这个点虽然不在最小值点,但非常接近了,因此误差平方和,或者说训练样本和假设的距离的平方和,这个距离值的平方和,非常接近于最小值,尽管它还不是最小值。好的,通过这些图形,我希望你能更好地理解这些代价函数 \(J\) 所表达的值,它们是什么样的,它们对应的假设是什么样的,以及什么样的假设对应的点更接近于代价函数 \(J\) 的最小值。当然,我们真正需要的是一种有效的算法,能够自动地找出这些使代价函数 \(J\) 取最小值的参数 \(\theta_0\)\(\theta_1\) 来,对吧?我想我们也不希望编个程序,把这些点画出来,然后人工的方法来读出这些点的数值,这很明显不是一个好办法。事实上,我们后面就会学到,我们会遇到更复杂、更高维度、更多参数的情况,这在我们在后面的课程中很快就会遇到,而这些情况是很难画出图的,因此更无法将其可视化,因此我们真正需要的,是编写程序来找出这些最小化代价函数的 \(\theta_0\)\(\theta_1\) 的值。

在下节课中,我们将介绍一种算法,它能够自动地找出能使代价函数 \(J\) 最小化的参数 \(\theta_0\)\(\theta_1\) 的值。

梯度下降(Gradient Descent)

我们已经定义了代价函数 \(J\),而在本节课中,我想向你们介绍梯度下降这种算法,这种算法可以将代价函数 \(J\) 最小化,梯度下降是很常用的算法,它不仅被用在线性回归上,它实际上被广泛的应用于机器学习领域中的众多领域。在后面课程中,为了解决其他非线性回归问题,我们也将使用梯度下降法最小化其他函数,而不仅仅是只用在本节课的代价函数 \(J\)。因此在本节课中,我将讲解用梯度下降算法最小化函数 \(J\),在后面的课程中,我们还会将此算法应用于具体的代价函数 \(J\) 中来解决线性回归问题。

下面是问题概述:

在这里,我们有一个函数 \(J(\theta_0,\theta_1)\),也许这是一个线性回归的代价函数,也许是一些其他函数,要使其最小化,我们需要用一个算法来最小化函数 \(J(\theta_0,\theta_1)\),就像刚才说的。事实证明,梯度下降算法可应用于多种多样的函数求解,所以想象一下,如果你有一个函数 \(J(\theta_0,\theta_1,...\theta_n)\),你希望可以通过最小化 \(\theta_0\)\(\theta_n\) 来最小化此代价函数 \(J(\theta_0,\theta_1,...\theta_n)\),用 n 个 \(\theta\) 是为了证明梯度下降算法可以解决更一般的问题。但为了简洁起见,为了简化符号,在接下来的课程中,我只用两个参数。

下面就是关于梯度下降的构想:

我们要做的是,我们要开始对 \(\theta_0\)\(\theta_1\) 进行一些初步猜测,它们到底是什么其实并不重要,但通常的选择是将 \(\theta_0\) 设为 0,将 \(\theta_1\) 也设为 0,将它们都初始化为 0。我们在梯度下降算法中要做的,就是不停地一点点地改变 \(\theta_0\)\(\theta_1\),试图通过这种改变使得 \(J(\theta_0,\theta_1)\) 逐渐变小,直到我们找到 \(J\) 的最小值,或许是局部最小值。

让我们通过一些图片来看看梯度下降法是如何工作的。我在试图让这个函数值最小,注意坐标轴 \(\theta_0\)\(\theta_1\) 在水平轴上,而函数 \(J\) 在垂直坐标轴上,图形表面高度则是 \(J\) 的值。我们希望最小化这个函数,所以我们从 \(\theta_0\)\(\theta_1\) 的某个值出发,所以想象一下 对 \(\theta_0\)\(\theta_1\) 赋以某个初值,也就是对应于从这个函数表面上的某个起始点出发,对吧?所以不管 \(\theta_0\)\(\theta_1\) 的取值是多少,我将它们初始化为 0,但有时你也可把它初始化为其他值。现在我希望大家把这个图像想象为一座山,想像类似这样的景色,公园中有两座山,想象一下你正站立在山的这一点上,站立在你想象的公园这座红色山上。在梯度下降算法中,我们要做的就是环顾 360 度,看看我们的周围,并问自己,我要在某个方向上用小碎步尽快下山,如果我想尽快走下山,这些小碎步需要朝什么方向?如果我们站在山坡上的这一点,你看一下周围,​​你会发现最佳的下山方向,大约是那个方向,好的,现在你在山上的新起点上,你再看看周围,然后再一次想想,我应该从什么方向迈着小碎步下山?然后你按照自己的判断又迈出一步,往那个方向走了一步,然后重复上面的步骤。从这个新的点,你环顾四周,并决定从什么方向将会最快下山,然后又迈进了一小步,又是一小步,并依此类推,直到你接近这里,直到局部最低点的位置。此外,这种下降有一个有趣的特点,第一次我们是从这个点开始进行梯度下降算法的,是吧?在这一点上从这里开始,现在想象一下,我们在刚才的右边一些的位置,对梯度下降进行初始化,想象我们在右边高一些的这个点 开始使用梯度下降,如果你重复上述步骤,停留在该点,并环顾四周,往下降最快的方向迈出一小步,然后环顾四周,又迈出一步,然后如此往复。如果你从右边不远处开始,梯度下降算法将会带你来到,这个右边的第二个局部最优处。如果从刚才的第一个点出发,你会得到这个局部最优解。但如果你的起始点偏移了一些,起始点的位置略有不同,你会得到一个非常不同的局部最优解,这就是梯度下降算法的一个特点。我们会在之后继续探讨这个问题,好的,这是我们从图中得到的直观感受。

看看这个图,这是梯度下降算法的定义。我们将会反复做这些,直到收敛。我们要更新参数 \(\theta_j\),方法是用 \(\theta_j\) 减去 \(\alpha\) 乘以这一部分,让我们来看看,这个公式有很多细节问题,我来详细讲解一下。首先,注意这个符号 :=,我们使用 := 表示赋值,这是一个赋值运算符。具体地说,如果我写 a:= b,在计算机专业内,这意味着不管 a 的值是什么,取 b 的值并将其赋给 a,这意味着我们让 a 等于 b 的值,这就是赋值。我也可以做 a := a + 1,这意味着取出 a 值,并将其增加 1。与此不同的是,如果我使用等号 =,并且写出 a = b,那么这是一个判断为真的声明,如果我写 a = b 就是在断言 a 的值是等于 b 的值。在左边这里,这是计算机运算,将一个值赋给 a,而在右边这里,这是声明,声明 a 的值与 b 的值相同。因此,我可以写 a := a + 1,这意味着将 a 的值再加上 1,但我不会写 a = a + 1,因为这本来就是错误的。a 和 a+1 永远不会是同一个值,这是这个定义的第一个部分。这里的 \(\alpha\) 是一个数字,被称为学习速率。什么是 \(\alpha\) 呢? 在梯度下降算法中,它控制了我们下山时会迈出多大的步子,因此如果 \(\alpha\) 值很大,那么相应的梯度下降过程中,我们会试图用大步子下山。如果 \(\alpha\) 值很小,那么我们会迈着很小的小碎步下山。关于如何设置 \(\alpha\) 的值等内容,在之后的课程中,我会回到这里并且详细说明。最后,是公式的这一部分,这是一个微分项,我现在不想谈论它,但我会推导出这个微分项,并告诉你到底这要如何计算。你们中有人大概比较熟悉微积分,但即使你不熟悉微积分,也不用担心,我会告诉你,对这一项,你最后需要做什么。现在,在梯度下降算法中,还有一个更微妙的问题,在梯度下降中,我们要更新 \(\theta_0\)\(\theta_1\),当 \(j=0\)\(j=1\) 时,会产生更新,所以你将更新 \(\theta_0\),还有 \(\theta_1\)。实现梯度下降算法的微妙之处是,在这个表达式中,如果你要更新这个等式,你需要同时更新 \(\theta_0\)\(\theta_1\)。我的意思是在这个等式中,我们要这样更新,\(\theta_0\) := \(\theta_0\) - 一些东西,并更新 \(\theta_1\) := \(\theta_1\) - 一些东西。实现方法是,你应该计算公式右边的部分,通过那一部分计算出 \(\theta_0\)\(\theta_1\) 的值,然后同时更新 \(\theta_0\)\(\theta_1\)。让我进一步阐述这个过程,在梯度下降算法中,这是正确实现同时更新的方法,我要设 temp0 等于这些,设 temp1 等于那些。所以首先计算出公式右边这一部分,然后将计算出的结果,一起存入 temp0 和 temp1 之中,然后同时更新 \(\theta_0\)\(\theta_1\),因为这才是正确的实现方法。与此相反,下面是不正确的实现方法,因为它没有做到同步更新,在这种不正确的实现方法中,我们计算 temp0 然后我们更新 \(\theta_0\),然后我们计算 temp1,然后我们将 temp1 赋给 \(\theta_1\)。右边的方法和左边的区别是,让我们看这里,就是这一步,如果这个时候你已经更新了 \(\theta_0\)。那么你会使用 \(\theta_0\) 的新的值来计算这个微分项,所以由于你已经在这个公式中使用了新的 \(\theta_0\) 的值,那么这会产生一个与左边不同的 temp1 的值,所以右边并不是正确地实现梯度下降的做法。我不打算解释为什么你需要同时更新,同时更新是梯度下降中的一种常用方法。我们之后会讲到,实际上同步更新是更自然的实现方法,当人们谈到梯度下降时,他们的意思就是同步更新,如果用非同步更新去实现算法,代码可能也会正确工作,但是右边的方法并不是人们所指的那个梯度下降算法,而是具有不同性质的其他算法。由于各种原因,这其中会表现出微小的差别,你应该做的是,在梯度下降中真正实现同时更新,这些就是梯度下降算法的梗概。在接下来的课程中,我们要进入这个微分项的细节之中,我已经写了出来但没有真正定义,如果你已经修过微积分课程,如果你熟悉偏导数和导数,这其实就是这个微分项。如果你不熟悉微积分,不用担心,即使你之前没有看过微积分,或者没有接触过偏导数,在接下来的课程中,你会得到一切你需要知道的,如何计算这个微分项的知识。

梯度下降的直观理解(Gradient Descent Intuition)

在之前的课程中,我们给出了一个数学上关于梯度下降的定义,本节课我们将更深入研究一下,更直观地感受一下这个算法是做什么的,以及梯度下降算法的更新过程有什么意义。

这是我们上节课中看到的梯度下降算法,提醒一下,这个参数 \(\alpha\),术语称为学习速率,它控制我们以多大的幅度更新这个参数 \(\theta_j\)。第二部分是导数项,而我在本节课中要做的就是给你一个更直观的认识,这两部分有什么用,以及为什么当把这两部分放一起时,整个更新过程是有意义的。

为了更好地让你明白,我要做是用一个稍微简单的例子,比如我们想最小化的那个函数,只有一个参数的情形。所以,假如我们有一个代价函数 \(J\),只有一个参数 \(\theta_1\),就像我们前几节课中讲的 \theta_1 是一个实数,对吧?那么我们可以画出一维的曲线,看起来很简单,让我们试着去理解 为什么梯度下降法会在这个函数上起作用。所以 假如这是我的函数,关于 \(\theta_1\) 的函数 \(J\)\(\theta_1\) 是一个实数,对吧?现在我们已经对这个点上用于梯度下降法的 \(\theta_1\) 进行了初始化,想象一下在我的函数图像上,从那个点出发,那么梯度下降要做的事情是不断更新 \theta_1 等于 \theta_1 减 \(\alpha\) 倍的 \(\frac{d}{d\theta_1}J(\theta_1)\) 这个项,对吧?哦,顺便插一句,你知道这个微分项是吧?可能你想问为什么我改变了符号,之前用的是偏导数的符号,如果你不知道偏导数的符号和 \(\frac{d}{d\theta}\) 之间的区别是什么,不用担心,从技术上讲,在数学中,我们称这是一个偏导数,这是一个导数,这取决于函数 \(J\) 的参数数量,但是这是一个数学上的区别,就本课的目标而言,可以默认为这些偏导数符号和 \(\frac{d}{d\theta_1}\) 是完全一样的东西,不用担心是否存在任何差异,我会尽量使用数学上的精确的符号,但就我们的目的而言,这些符号是没有区别的。好的,那么我们来看这个方程,我们要计算这个导数,我不确定之前你是否在微积分中学过导数,但对于这个问题,求导的目的基本上可以说是取这一点的切线,就是这样一条红色的直线,刚好与函数相切于这一点。让我们看看这条红色直线的斜率,其实这就是导数,也就是说,直线的斜率,也就是这条刚好与函数曲线相切的这条直线,这条直线的斜率正好是,这个高度除以这个水平长度。现在,这条线有一个正斜率,也就是说它有正导数。因此,我得到的新的 \(\theta\)\(\theta_1\) 更新后等于 \(\theta_1\) 减去一个正数乘以 \(\alpha\)\(\alpha\) 也就是学习速率,也是一个正数。所以,我要使 \(\theta_1\) 减去一个东西,所以相当于我将 \(\theta_1\) 向左移,使 \(\theta_1\) 变小了。我们可以看到,这么做是对的,因为实际上我往这个方向移动,确实让我更接近那边的最低点。所以,梯度下降到目前为止似乎是在做正确的事。让我们来看看另一个例子,让我们用同样的函数 \(J\),同样再画出函数 \(J(\theta_1)\) 的图像。而这次,我们把参数初始化到左边这点,所以 \(\theta_1\) 在这里,同样把这点对应到曲线上。现在,导数项 \(\frac{d}{d\theta_1}J(\theta_1)\) 在这点上计算时,看上去会是这样。但是这条线向下倾斜,所以这条线具有负斜率,对吧?或者说,这个函数有负导数,也就意味着在那一点上有负斜率。因此,这个导数项小于等于零。所以,当我更新 \(\theta\) 时,\(\theta\) 被更新为 \(\theta\) 减去 \(\alpha\) 乘以一个负数。因此我是在用 \(\theta_1\) 减去一个负数,这意味着我实际上是在增加 \(\theta_1\),对不对?因为这是减去一个负数,意味着给 \(\theta\) 加上一个数,这就意味着最后我实际上增加了 \(\theta\) 的值。因此,我们将从这里开始,增加 \(\theta\)。似乎这也是我希望得到的,也就是让我更接近最小值了。所以,我希望这样很直观地给你解释了导数项的意义。

让我们接下来再看一看学习速率 \(\alpha\),我们来研究一下它有什么用。这就是我梯度下降法的更新规则,就是这个等式,让我们来看看如果 \(\alpha\) 太小或 \(\alpha\) 太大会出现什么情况。

这第一个例子,\(\alpha\) 太小会发生什么呢?这是我的函数 \(J(\theta)\),就从这里开始,如果 \(\alpha\) 太小了,那么我要做的是要去用一个比较小的数乘以更新的值,所以最终它就像一个小宝宝的步伐,这是一步,然后从这个新的起点开始,对吧?小碎步,所以如果我的学习速率太小,结果就是 只能这样像小宝宝一样一点点地挪动,去努力接近最低点,这样就需要很多步才能到达最低点,所以如果 \(\alpha\) 太小的话,可能会很慢,因为它会一点点挪动,它会需要很多步才能到达全局最低点。那么如果 \(\alpha\) 太大又会怎样呢?这是我的函数 \(J(\theta)\),如果 \(\alpha\) 太大,那么梯度下降法可能会越过最低点,甚至可能无法收敛。我的意思是,比如我们从这个点开始,实际上这个点已经接近最低点,因此导数指向右侧,但如果 \(\alpha\) 太大的话,我会迈出很大一步,也许像这样巨大的一步,对吧?所以我最终迈出了一大步。现在,我的代价函数变得更糟,因为离这个最低点越来越远,现在我的导数指向左侧,实际上在减小 \(\theta\),但是你看,如果我的学习速率过大,我会移动一大步,从这点一下子又到那点了,对吗?如果我的学习率太大,下一次迭代又移动了一大步,越过一次。又越过一次,一次次越过最低点,直到你发现,实际上,离最低点越来越远。所以,如果 \(\alpha\) 太大,它会导致无法收敛,甚至发散。现在,我还有一个问题,这问题挺狡猾的,当我第一次学习这个地方时,我花了很长一段时间才理解这个问题。如果我们预先把 \(\theta_1\) 放在一个局部的最低点,你认为下一步梯度下降法会怎样工作?所以假设你将 \(\theta_1\) 初始化在局部最低点,假设这是你的 \(\theta_1\) 的初始值,在这儿,它已经在一个局部的最优处或局部最低点,结果是局部最优点的导数将等于零。因为它是那条切线的斜率,而这条线的斜率将等于零。因此,此导数项等于 0,在你的梯度下降更新过程中,你有一个 \(\theta_1\),然后用 \(\theta_1\)\(\alpha\) 乘以 0 来更新 \(\theta_1\)。所以这意味着什么?这意味着你已经在局部最优点,它使得 \(\theta_1\) 不再改变,也就是新的 \(\theta_1\) 等于原来的 \(\theta_1\)。因此,如果你的参数已经处于局部最低点,那么梯度下降法更新其实什么都没做,它不会改变参数的值,这也正是你想要的,因为它使你的解始终保持在局部最优点。这也解释了为什么即使学习速率 \(\alpha\) 保持不变时,梯度下降也可以收敛到局部最低点。我想说的是这个意思,我们来看一个例子,这是代价函数 \(J(\theta)\),我想找到它的最小值。首先初始化我的梯度下降算法,在那个品红色的点初始化,如果我更新一步梯度下降,也许它会带我到这个点,因为这个点的导数是相当陡的。现在,在这个绿色的点,如果我再更新一步,你会发现我的导数,也即斜率,是没那么陡的,相比于在品红点,对吧?因为随着我接近最低点,我的导数越来越接近零。所以,梯度下降一步后,新的导数会变小一点点,然后我想再梯度下降一步,在这个绿点,我自然会用一个稍微跟刚才在那个品红点时比,再小一点的一步,现在到了新的点,红色点,更接近全局最低点了,因此这点的导数会比在绿点时更小。所以,我再进行一步梯度下降时,我的导数项是更小的,\(\theta_1\) 更新的幅度就会更小,所以你会移动更小的一步,像这样,随着梯度下降法的运行,你移动的幅度会自动变得越来越小,直到最终移动幅度非常小,你会发现,已经收敛到局部极小值。

所以回顾一下,在梯度下降法中,当我们接近局部最低点时,梯度下降法会自动采取更小的幅度。这是因为当我们接近局部最低点时,很显然在局部最低时导数等于零,所以当我们接近局部最低时,导数值会自动变得越来越小,所以梯度下降将自动采取较小的幅度,这就是梯度下降的做法,所以实际上没有必要再另外减小 \(\alpha\)。这就是梯度下降算法,你可以用它来最小化最小化任何代价函数 \(J\),不只是线性回归中的代价函数 \(J\)

在接下来的课程中,我们要用到代价函数 \(J\),回到它的本质,即线性回归中的代价函数,就是我们前面得出的平方误差函数。结合梯度下降法,以及平方代价函数,我们会得出第一个机器学习算法,即线性回归算法。

梯度下降的线性回归(Gradient Descent For Linear Regression)

在前面的课程中,我们讨论了梯度下降算法、线性回归模型和平方误差代价函数。在本节课中,我们要将梯度下降和代价函数结合。在后面的课程中,我们将用到此算法,并将其应用于具体的拟合直线的线性回归算法里。

这就是我们在之前的课程里所做的工作,这是梯度下降法,这个算法你应该很熟悉,这是线性回归模型,还有线性假设和平方误差代价函数。我们将要做的是用梯度下降的方法来最小化平方误差代价函数。为了使梯度下降,为了写这段代码,我们需要的关键项是这里这个微分项。所以,我们需要弄清楚这个偏导数项是什么,并结合这里的代价函数的定义,就是这样用梯度下降的方法,这个误差平方项,我这样做只是把定义好的代价函数插入了这个微分式。再简化一下,这等于是这一个求和项 \(\theta_0 + \theta_1 x^{(1)} - y^{(i)}\),这一项其实就是我的假设的定义。然后把这一项放进去,实际上我们需要弄清楚这两个偏导数项是什么,这两项分别是 \(j=0\)\(j=1\) 的情况。因此我们要弄清楚 \(\theta_0\)\(\theta_1\) 对应的偏导数项是什么,我只把答案写出来。事实上,第一项可简化为 1 / m 乘以求和式,对所有训练样本求和,求和项是 \(h(x^{(i)})-y^{(i)}\)。而这一项,对 \(\theta_1\) 的微分项,得到的是这样一项 \(h(x^{(i)})-y^{(i)} * x^{(i)}\),对吧?所以偏导数项,从这个等式到下面的等式。

计算这些偏导数项需要一些多元微积分,如果你掌握了微积分,然后你检查你的微分,你实际上会得到我给出的答案。但如果你不太熟悉微积分,别担心,你可以直接用这些已经算出来的结果,你不需要掌握微积分或者别的东西来完成作业,你只需要会用梯度下降就可以在定义这些以后,在我们算出这些微分项以后,这些微分项实际上就是代价函数 \(J\) 的斜率,现在可以将它们放回我们的梯度下降算法。所以这就是专用于线性回归的梯度下降,反复执行括号中的式子直到收敛,\(\theta_0\)\(\theta_1\) 不断被更新,都是加上一个 \(-\frac{\alpha}{m}\) 乘上后面的求和项,所以这就是我们的线性回归算法。事实上,第一项可简化,当然,这一项就是关于 \(\theta_0\) 的偏导数,在上一张幻灯片中推出的。而第二项,这一项是刚刚推导出的。

关于 \(\theta_1\) 的偏导数项,对 \(\theta_1\) 的微分项,提醒一下,在做梯度下降的时候,就是必须要同时更新 \(\theta_0\)\(\theta_1\)

所以,让我们来看看梯度下降是如何工作的?我们用梯度下降解决问题的一个原因是,它更容易得到局部最优值。当我第一次解释梯度下降时,我展示过这幅图,在表面上不断下降,并且我们知道了,根据你的初始化,你会得到不同的局部最优解。你知道,最后可能会到这里,到这里。但是事实证明,用于线性回归的代价函数,总是这样一个弓形的样子。这个函数的专业术语是凸函数(convex),我不打算在这门课中给出凸函数的定义。但不正式的说法是,它就是一个弓形的函数。因此,这个函数没有任何局部最优解,并且无论什么时候,你对这种代价函数使用线性回归,只有一个全局最优解,因为没有别的局部最优解。

我们在实际中来看这个算法,像往常一样,这里有假设函数和我们的成本函数 \(J\) 的图。我们假设将初始值定在这里,通常来说,初始化参数为零,\(\theta_0\)\(\theta_1\) 都在零。但为了展示需要,在这个梯度下降的实现中,我把 \(\theta_0\) 初始化为 -900,\(\theta_1\) 初始化为 -0.1,也就是 h(x) = -900 - 0.1x,这一行是代价函数。现在我们做梯度下降中的一步,我们从这里往下,到第二点这里,你注意到这条线有些变化,在我做梯度下降的另一步时,我左侧的线发生了变化是吧?我的代价函数也到了一个新的位置我做更多次梯度下降之后,我的代价下降了,我的参数遵循这样的轨迹如果你看左侧,这与假设对应,看起来与数据有更好的拟合。直到最后,我到了全局最小值的位置,对应这个假设的全局最小值,我就能得到与数据很好地拟合了。

这就是梯度下降,我们运行了它,与我的房价数据有了很好的拟合。你可以用它来预测,如果你的朋友有 1250 平方英尺的房子,你现在可以预测它的价值,并告诉他们,也许他们的房子能拿到 25 万美元。最后只是给它另一个名字,我们刚刚做的算法有时被称为批量梯度下降。原来在机器学习中,我不觉得我们机器学习的人们,并不总是擅长给算法起名字。但术语批处理梯度下降指的是一个事实,在梯度下降的每一步,我们都在看所有的训练例子,因此梯度下降中计算导数的时候,我们计算这个总和,因此任何步骤的梯度下降,我们最终计算这样的东西,我们 \(m\) 个训练例子的综合。所以术语批次梯度下降指的是,事实上,我们找的是整个批次的训练例子,这真的不是一个伟大的名字,这就是机器学习者的叫法。事实证明,有时有梯度下降的其他版本,不是成批处理的,它们不是去看整个训练集,而是每次去看训练集中的小子集。我们还将在本课程的后面讨论这些版本,但目前使用的算法,我们刚刚了解使用的批量梯度下降法。你现在知道如何在线性回归中实现梯度下降,这就是梯度下降的线性回归。如果你以前看过高等线性代数,你们中的一些人可能上了高等线性代数的课,你可能知道有一个解决方案,就是代价函数 \(J\) 的数值解法,不需要使用梯度下降这样的迭代法。在本课程的后面,我们将讨论该方法,就可以在求解代价函数最小值时不用梯度下降这么多步骤,另一种方法称为正规方程法。但万一你听说过这种方法,实际上梯度下降比它在大数据当中更好用。

现在我们知道了梯度下降法,我们可以将它用到不同情境当中,我们也会用到各类机器学习算法当中。

多变量线性回归(Linear Regression with Multiple Variables)

多维特征(Multiple Features)

在这节课中,我们将开始介绍一种新的、更为有效的线性回归形式,这种形式适用于多个变量或者多特征量的情况做矩阵乘法。

在之前,我们学习过的线性回归中,我们只有一个单一特征量,房屋面积 \(x\),我们希望用这个特征量来预测房子的价格,这就是我们的假设。但是想象一下,如果我们不仅有房屋面积作为预测房屋价格的特征量,或者变量,我们还知道卧室的数量,楼层的数量,以及房子的使用年限,这样就给了我们更多可以用来预测房屋价格的信息。

先简单介绍一下标记法,我们开始的时候就提到过,我要用 \(x\) 下标 1,\(x\) 下标 2 等等,来表示这种情况下的四个特征量,然后仍然用 \(Y\) 来表示我们所想要预测的输出变量。让我们来看看更多的表示方式,现在我们有四个特征量,我要用小写 \(n\) 来表示特征量的数目。因此在这个例子中,我们的 \(n\) 等于 4,因为你们看,我们有 1 2 3 4 共 4 个特征量,这里的 \(n\) 和我们之前使用的 \(m\) 不同,之前我们是用的 "m" 来表示样本的数量,所以如果你有 47 行,那么 \(m\) 就是这个表格里面的行数,或者说是训练样本数。然后我要用 \(x\) 上标 \((i)\) 来表示第 \(i\) 个训练样本的输入特征值。举个具体的例子来说,\(x\) 上标 \((2)\) 就是表示第二个训练样本的特征向量。因此这里 \(x^{(2)}\) 就是向量 [1416, 3, 2, 40],因为这四个数字对应了我用来预测房屋价格的第二个房子的四个特征量,因此在这种记法中这个上标 2 就是训练集的一个索引,而不是 \(x\) 的 2 次方,这个 2 就对应着你所看到的表格中的第二行,即我的第二个训练样本,\(x\) 上标 \((2)\) 这样表示就是一个四维向量。事实上更普遍地来说,这是 \(n\) 维的向量,用这种表示方法,\(x\) 上标 2 就是一个向量。因此,我用 \(x\) 上标 \((i)\),下标 \(j\) 来表示第 \(i\) 个训练样本的第 \(j\) 个特征量。因此,具体的来说 \(x\) 上标 \((2)\) 下标 3 代表着第 2 个训练样本里的第 3 个特征量,对吧?这个是 3,我写的不太好看,所以说 \(x\) 上标 \((2)\) 下标 3 就等于 2。

既然我们有了多个特征量,让我们继续讨论一下,我们的假设形式应该是怎样的。

这是我们之前使用的假设形式,\(x\) 就是我们唯一的特征量,但现在我们有了多个特征量,我们就不能再使用这种简单的表示方式了,取而代之的,我们将把线性回归的假设改成这样,\(\theta_0\) 加上 \(\theta_1\) 乘以 \(x_1\) 加上 \(\theta_2\) 乘以 \(x_2\) 加上 \(\theta_3\) 乘以 \(x_3\) 加上 \(\theta_4\) 乘以 \(x_4\),然后如果我们有 \(n\) 个特征量。那么我们要将所有的 \(n\) 个特征量相加,而不是四个特征量。举个具体的例子,在我们的设置的参数中,我们可能有 h(x) = 80 + 0.1 x 1 + 0.01 x 2 + 3 x 3 - 2 x 4,这就是一个假设的范例。别忘了,假设是为了预测大约以千刀为单位的房屋价格,就是说,一个房子的价格可以是 80 k 加上 0.1 乘以 1,也就是说每平方尺 100 美元,然后价格会随着楼层数的增加,再继续增长,乘 2 是楼层数,接着价格会继续增加,随着卧室数的增加,乘 3 是卧室的数量。但是呢,房子的价格会,随着使用年数的增加而贬值,这是重新改写过的假设的形式。接下来,我要来介绍一点简化这个等式的表示方式,为了表示方便,我要将 \(x\) 下标 0 的值设为 1。具体而言,这意味着,对于第 \(i\) 个样本,都有一个向量 \(x\) 上标 \((i)\),并且 \(x\) 上标 \((i)\) 下标 0 等于 1。你可以认为我们定义了一个额外的第 0 个特征量。因此,我过去有 \(n\) 个特征量,因为我们有 \(x_1\)\(x_2\) 直到 \(x_n\)。由于我另外定义了额外的第 0 个特征向量,并且它的取值总是 1,所以我现在的特征向量 \(x\) 是一个从 0 开始标记的 \(n+1\) 维的向量。同时,我也想把我的参数都看做一个向量,所以我们的参数就是,我们的 \(\theta_0\)\(\theta_1\)\(\theta_2\) 等等,直到 \(\theta_n\)。我们要把所有的参数都写成一个向量 \([\theta_0,\theta_2...\theta_n]\)。这里也有一个从 0 开始标记的矢量,下标从 0 开始,这是另外一个,所以我的假设现在可以写成 \(\theta_0 x_0+\theta_1 x_1+,...+\theta_n x_n\),这个等式和上面的等式是一样的,因为你看 \(x_0\) 等于 1。

下面我要把这种形式的假设等式写成 \(\theta\) 转置乘以 \(X\)。这取决于你对向量内积有多熟悉,如果你展开 \(\theta\) 转置乘以 \(X\),那么就得到 \([\theta_0,\theta_1,...,\theta_n]\),这个就是 \(\theta\) 转置。实际上,这就是一个 \(n+1\) 乘以 1 维的矩阵,也被称为行向量。用行向量与 \(X\) 向量相乘,\(X\) 向量是 \([x_0,x_1,...,x_n]\),因此内积就是 \(\theta\) 转置乘以 \(X\),就等于这个等式。这就为我们提供了一个表示假设的更加便利的形式,即用参数向量 \(\theta\) 以及特征向量 \(X\) 的内积,这就是改写以后的表示方法。这样的表示习惯,就让我们可以以这种紧凑的形式写出假设,这就是多特征量情况下的假设形式,起另一个名字,就是所谓的多元线性回归,多元一词也就是用来预测的多个特征量或者变量,就是一种更加好听的说法罢了。

多变量梯度下降(Gradient Descent for Multiple Variables)

在之前的课程中,我们谈到了一种线性回归的假设形式,这是一种有多特征或者是多变量的形式。在本节课中,我们将会谈到如何找到满足这一假设的参数,尤其是如何使用梯度下降法来解决多特征的线性回归问题。

为尽快让你理解,现假设现有多元线性回归,并约定 \(x_0=1\),该模型的参数是从 \(\theta_0\)\(\theta_n\),不要认为这是 \(n+1\) 个单独的参数,你可以把这 \(n+1\)\(\theta\) 参数想象成一个 \(n+1\) 维的向量。我们的代价函数是从 \(\theta_0\)\(\theta_n\) 的函数 \(J\),并给出了误差项平方的和。但同样地,不要把函数 \(J\) 想成是一个关于 \(n+1\) 个自变量的函数,而是看成带有一个 \(n+1\) 维向量的函数。

这就是梯度下降法,我们将会不停地用 \(\theta_j\) 减去 \(\alpha\) 倍的导数项,来替代 \(\theta_j\)。同样的方法,我们写出函数 \(J(\theta)\)。因此 \(\theta_j\) 被更新成 \(\theta_j\) 减去学习率 \(\alpha\) 与对应导数的乘积,就是代价函数对参数 \(\theta_j\) 的偏导数。当我们实现梯度下降法后,你可以仔细观察一下,尤其是它的偏导数项。下面是我们当特征 \(n=1\) 时,梯度下降的情况,我们有两条针对参数 \(\theta_0\)\(\theta_1\) 不同的更新规则。希望这些对你来说并不陌生,这一项是代价函数里部分求导的结果,就是代价函数相对于 \(\theta_0\) 的偏导数。同样,对参数 \(\theta_1\) 我们有另一个更新规则。仅有的一点区别是,当我们之前只有一个特征,我们称该特征为 \(x^{(i)}\),但现在我们在新符号里,我们会标记它为 \(x\) 上标 \((i)\) 下标 1 来表示我们的特征,以上就是当我们仅有一个特征时候的算法。

下面我们来讲讲当有一个以上特征时候的算法。现有数目远大于 1 的很多特征,我们的梯度下降更新规则变成了这样。有些同学可能知道微积分,如果你看看代价函数,代价函数 \(J\) 对参数 \(\theta_j\) 求偏导数,你会发现,求其偏导数的那一项,我已经用蓝线圈出来了。如果你实现了这一步,你将会得到多元线性回归的梯度下降算法。

最后,我想让你明白,为什么新旧两种算法实际上是一回事儿,或者说为什么这两个是类似的算法,为什么它们都是梯度下降算法。考虑这样一个情况,有两个或以上个数的特征,同时我们有对 \(\theta_1\)\(\theta_2\)\(\theta_3\) 的三条更新规则,当然可能还有其它参数。如果你观察 \(\theta_0\) 的更新规则,你会发现这跟之前 \(n=1\) 的情况相同。它们之所以是等价的,这是因为在我们的标记约定里有 \(x^{(i)}_0=1\),也就是我用品红色圈起来的两项是等价的。同样地,如果你观察 \(\theta_1\) 的更新规则,你会发现这里的这一项是和之前对参数 \(\theta_1\) 的更新项是等价的。在这里我们只是用了新的符号 \(x^{(i)}_1\) 来表示我们的第一个特征,现在我们有个更多的特征,那么就可以用与之前相同的更新规则,我们可以用同样的规则来处理 \(\theta_2\) 等其它参数。

梯度下降法实践 1 - 特征缩放(Gradient Descent in Practice I - Feature Scaling)

在本节课以及下节课中,我想告诉你一些关于梯度下降运算中的实用技巧。在本节课中,我会告诉你一个称为特征缩放 (feature scaling) 的方法。

如果你有一个机器学习问题,这个问题有多个特征,如果你能确保这些特征都处在一个相近的范围,我的意思是确保不同特征的取值在相近的范围内,这样梯度下降法就能更快地收敛。

具体地说,假如你有一个具有两个特征的问题,其中 \(x_1\) 是房屋面积大小,它的取值在 0 到 2000 之间。\(x_2\) 是卧室的数量,可能这个值取值范围在 1 到 5 之间。如果你画出代价函数 \(J(\theta)\) 的轮廓图,那么这个轮廓看起来应该是像这样的。\(J(\theta)\) 是一个关于参数 \(\theta_0\)\(\theta_1\)\(\theta_2\) 的函数。但我要忽略 \(\theta_0\),所以暂时不考虑 \(\theta_0\)。并假想一个函数的变量只有 \(\theta_1\)\(\theta_2\)。但如果 \(x_1\) 的取值范围远远大于 \(x_2\) 的取值范围的话,那么最终画出来的代价函数 \(J(\theta)\) 的轮廓图就会呈现出这样一种非常偏斜、并且椭圆的形状。2000 和 5 的比例会让这个椭圆更加瘦长。所以,这是一个又瘦又高的椭圆形轮廓图,就是这些非常高大细长的椭圆形构成了代价函数 \(J(\theta)\)。而如果你用这个代价函数来运行梯度下降的话,你要得到梯度值,最终可能需要花很长一段时间,并且可能会来回波动,然后会经过很长时间,最终才收敛到全局最小值。事实上,你可以想像,如果这些轮廓再被放大一些的话,如果你画的再夸张一些,把它画的更细更长,那么可能情况会更糟糕,梯度下降的过程,可能更加缓慢,需要花更长的时间,反复来回振荡,最终才找到一条正确通往全局最小值的路。在这样的情况下,一种有效的方法是进行特征缩放(feature scaling)。

具体来说,把特征 \(x_1\) 定义为房子的面积大小除以 2000 的话,并且把 \(x_2\) 定义为卧室的数量除以 5,那么这样的话,表示代价函数 \(J(\theta)\) 的轮廓图的形状就会变得偏移没那么严重,可能看起来更圆一些了。如果你用这样的代价函数来执行梯度下降的话,那么,梯度下降算法你可以从数学上来证明,梯度下降算法就会找到一条更捷径的路径通向全局最小,而不是像刚才那样,沿着一条让人摸不着头脑的路径,一条复杂得多的轨迹,来找到全局最小值。因此,通过特征缩放,通过 "消耗掉" 这些值的范围,在这个例子中,我们最终得到的两个特征 \(x_1\)\(x_2\) 都在 0 和 1 之间,这样你得到的梯度下降算法就会更快地收敛。更一般地,我们执行特征缩放时,我们通常的目的是将特征的取值约束到 -1 到 +1 的范围内。你的特征 \(x_0\) 是总是等于 1,因此,这已经是在这个范围内,但对其他的特征,你可能需要通过除以不同的数,来让它们处于同一范围内。-1 和 +1 这两个数字并不是太重要,所以,如果你有一个特征 \(x_1\),它的取值在 0 和 3 之间,这没问题。如果你有另外一个特征取值在 -2 到 +0.5 之间,这也没什么关系,这也非常接近,这些都可以。但如果你有另一个特征,比如叫 \(x_3\),假如它的范围在 -100 到 +100 之间,那么,这个范围跟 -1 到 +1 就有很大不同了。所以,这可能是一个不那么好的特征,类似地,如果你的特征在一个非常非常小的范围内,比如另外一个特征 \(x_4\),它的范围在 0.0001 和 +0.0001 之间,那么这同样是一个比 -1 到 +1 小得多的范围,因此,我同样会认为这个特征也不太好。所以,可能你认可的范围,也许可以大于或者小于 -1 到 +1,但是也别太大,只要大得不多就可以接受。比如 +100,或者也别太小,比如这里的 0.001。不同的人有不同的经验,但是我一般是这么考虑的,如果一个特征是在 -3 到 +3 的范围内,那么,你应该认为这个范围是可以接受的。但如果这个范围大于了 -3 到 +3 的范围,我可能就要开始注意了。如果它的取值在 -1/3 到 +1/3 的话,我觉得还不错,可以接受,或者是 0 到 1/3 或 -1/3 到 0,这些典型的范围,我都认为是可以接受的。但如果特征的范围取得很小的话,比如像这里的 \(x_4\),你就要开始考虑进行特征缩放了。因此,总的来说,不用过于担心你的特征是否在完全相同的范围或区间内,但是只要他们都只要它们足够接近的话,梯度下降法就会正常地工作。

除了在特征缩放中将特征除以最大值以外,有时候我们也会进行一个称为均值归一化的工作(mean normalization)。我的意思是这样的,如果你有一个特征 \(x_i\),你就用 \(xi - \mu i\) 来替换。通过这样做,让你的特征值具有为 0 的平均值。很明显,我们不需要把这一步应用到 \(x_0\) 中,因为 \(x_0\) 总是等于 1 的,所以它不可能有为 0 的的平均值。但是,对其他的特征来说,比如房子的大小取值介于 0 到 2000,并且假如房子面积的平均值是等于 1000 的,那么你可以用这个公式将 \(x_1\) 的值变为 \(\frac{x_1 - \mu_1}{2000}\)。类似地,如果你的房子有五间卧室,并且平均一套房子有两间卧室,那么你可以使用这个公式来归一化你的第二个特征 \(x_2\),在这两种情况下,你可以算出新的特征 \(x_1\)\(x_2\),这样它们的范围可以在 -0.5 和 +0.5 之间,当然这肯定不对,\(x_2\) 的值实际上肯定会大于 0.5,但很接近。更一般的规律是,你可以用这样的公式,你可以用
\(\frac{x_1-\mu_1}{S_1}\) 来替换原来的特征 \(x_1\)。其中定义 \(\mu_1\) 的意思是,在训练集中特征 \(x_1\) 的平均值,而 \(S_1\) 是该特征值的范围,我说的范围是指,最大值减去最小值,或者学过标准差的同学可以记住,也可以把 \(S_1\) 设为变量的标准差,但其实用最大值减最小值就可以了。类似地,对于第二个特征 \(x_2\),你也可以用同样的这个特征减去平均值,再除以范围来替换原特征,范围的意思依然是最大值减最小值。这类公式将把你的特征变成这样的范围,也许不是完全这样,但大概是这样的范围。顺便提一下,有些同学可能比较仔细,如果我们用最大值减最小值来表示范围的话,这里的 5 有可能应该是 4,如果最大值为 5 那么减去最小值 1,这个范围值就是 4。但不管咋说,这些取值都是非常近似的,只要将特征转换为相近似的范围就都是可以的。特征缩放其实并不需要太精确,只是为了让梯度下降能够运行得更快一点而已。

现在你知道了什么是特征缩放,通过使用这个简单的方法,你可以将梯度下降的速度变得更快,让梯度下降收敛所需的循环次数更少,这就是特征缩放。在接下来的课程中,我将介绍另一种技巧来使梯度下降在实践中工作地更好。

梯度下降法实践 2 - 学习率(Gradient Descent in Practice II - Learning Rate)

在本节课中,我想告诉大家一些关于梯度下降算法的实用技巧,我将集中讨论学习率 \(\alpha\)。具体来说,我想要告诉大家如何调试,或者说我们应该如何确定梯度下降是正常工作的。此外,我还想告诉大家如何选择学习率 \(\alpha\),也就是我平常如何选择这个参数。

我通常做的是确保梯度下降正常工作,梯度下降算法所做的事情就是为你找到一个 \(\theta\) 值,并希望它能够最小化代价函数 \(J(\theta)\)。我通常会在梯度下降算法运行时绘出代价函数 \(J(\theta)\) 的值,这里的 x 轴是表示梯度下降算法的迭代步数,你可能会得到这样一条曲线。注意这里的 x 轴是迭代步数,在我们以前看到的 \(J(\theta)\) 曲线中 x 轴,也就是横轴曾经用来表示参数 \(\theta\),但这里不是。具体来说,这一点的含义是这样的,当我运行完 100 步的梯度下降迭代之后,无论我得到什么 \(\theta\) 值,总之 100 步迭代之后。我将得到一个 \(\theta\) 值,根据 100 步迭代之后得到的这个 \(\theta\) 值 ,我将算出代价函数 \(J(\theta)\) 的值,而这个点的垂直高度就代表梯度下降算法 100 步迭代之后得到的 \(\theta\) 算出的 \(J(\theta)\) 值。而这个点则是梯度下降算法迭代 200 次之后得到的 \(\theta\) 算出的 \(J(\theta)\) 值。所以这条曲线显示的是,梯度下降算法迭代过程中,代价函数 \(J(\theta)\) 的值,如果梯度下降算法正常工作,那么每一步迭代之后 \(J(\theta)\) 都应该下降。这条曲线的一个用处在于,它可以告诉你,如果你看一下我画的这条曲线,当你达到 300 步迭代之后,也就是 300 步到 400 步迭代之间,也就是曲线的这一段,看起来 \(J(\theta)\) 并没有下降多少。所以当你到达 400 步迭代时,这条曲线看起来已经很平坦了,也就是说,在这里 400 步迭代的时候,梯度下降算法基本上已经收敛了,因为代价函数并没有继续下降。所以说,看这条曲线可以帮助你判断梯度下降算法是否已经收敛。顺便说一下对于每一个特定的问题,梯度下降算法所需的迭代次数,可以相差很大,也许对于某一个问题,梯度下降算法只需要 30 步迭代就可以收敛,然而换一个问题,也许梯度下降算法就需要 3000 步迭代。对于另一个机器学习问题,则可能需要三百万步迭代。实际上,我们很难提前判断梯度下降算法需要多少步迭代才能收敛。通常我们需要画出这类曲线,画出代价函数随迭代步数数增加的变化曲线,通常我会通过看这种曲线,来试着判断梯度下降算法是否已经收敛。另外,也可以进行一些自动的收敛测试,也就是说用一种算法,来告诉你梯度下降算法是否已经收敛,自动收敛测试。一个非常典型的例子是,如果代价函数 \(J(\theta)\) 的下降小于一个很小的值 \(\varepsilon\),那么就认为已经收敛。比如可以选择 1e-3,但我发现,通常要选择一个合适的阈值 \(\varepsilon\) 是相当困难的。因此,为了检查梯度下降算法是否收敛,我实际上还是通过看左边的这条曲线图,而不是依靠自动收敛测试。此外,这种曲线图,也可以在算法没有正常工作时 提前警告你。具体地说,如果你画出代价函数 \(J(\theta)\) 随迭代步数的变化曲线,看到图形是这个样子,\(J(\theta)\) 实际上在不断上升,这就表明梯度下降算法没有正常工作。而这样的曲线通常意味着你应该使用较小的学习率 \(\alpha\)。如果 \(J(\theta)\) 在上升,那么最常见的原因是,你在尝试最小化这样的一个函数,但如果你的学习率开始太大的话,如果你从这里开始,梯度下降算法可能会冲过最小值,到达这里,如果学习率太大可能会再次冲过最小值到达这里,一直这样下去。然而你真正想要的是,从这里开始慢慢的下降,但是如果学习率过大的话,梯度下降算法将会不断的冲过最小值,然后你将会得到越来越糟糕的结果,得到越来越大的代价函数 \(J(\theta)\) 的值,所以你得到了这样的一个曲线。如果你看到这样的曲线图,通常的解决方法是使用较小的 \(\alpha\) 值,当然也要确保你的代码中没有错误。通常最可能出现的问题是 \(\alpha\) 值过大。同样地,有时你可能看到这种形状的 \(J(\theta)\) 曲线,它先下降,再上升,接着又下降,然后又上升,如此往复。而解决这种情况的方法通常也是选择较小的 \(\alpha\) 值。我不打算在这里证明这一点,但在代价函数 \(J\) 的基本假设之下,该假设适用于线性回归,数学家已经证明,只要学习率 \(\alpha\) 足够小,那么每次迭代之后代价函数 \(J(\theta)\) 都会下降,因此如果代价函数没有下降,那可能是因为学习率过大,这时你就应该尝试一个较小的学习率。当然,你也不希望学习率太小,因为如果这样做的话,那么梯度下降算法可能收敛的很慢,如果学习率太小,你可能从这里开始,然后很慢很慢的向最低点移动,你需要迭代很多次,才能到达最低点。因此,如果学习率 \(\alpha\) 太小的话,梯度下降算法将会收敛的很慢。

总结一下,如果学习率 \(\alpha\) 太小的话,你会遇到收敛速度很慢的问题。而如果学习率 \(\alpha\) 太大的话,代价函数 \(J(\theta)\) 可能不会在每次迭代都下降,甚至可能不收敛。在某些情况下,如果学习率 \(\alpha\) 过大,也可能会出现收敛缓慢,但更常见的问题是,代价函数 \(J(\theta)\) 并不会在每次迭代之后都下降。所以为了调试所有的情况,通常绘制 \(J(\theta)\) 随迭代步数变化的曲线,可能帮你弄清楚到底发生了什么。具体来说,当我运行梯度下降算法时,我通常会尝试一些列 \(\alpha\) 值,比如 ..., 0.001,0.01,0.1,1,...,每隔 10 倍取一个值,然后对于这些不同的 \(\alpha\) 值,绘制 \(J(\theta)\) 随迭代步数变化的曲线,然后选择使得 \(J(\theta)\) 快速下降的一个 \(\alpha\) 值。事实上,我通常并不是隔 10 倍取一个值,我通常取的是这些 \(\alpha\) 值,..., 0.001,0.003,0.01,0.03,0.1,0.3,1,...,所以在梯度下降算法选择合适的学习率时,我大致是按 3 的倍数来取值的。所以我会尝试一些列的 \(\alpha\) 值,直到我找到一个最小的值和一个最大的值,然后我取最大的可能值,或者比最大的可能值略小一些的,比较合理的,我通常就可以得到一个不错的学习率。如果你也这样做的话,那么你也能够为你的梯度下降算法找到一个合适的学习率。

特征和多项式回归(Features and Polynomial Regression)

你现在了解了多变量的线性回归,在本节课中,我想告诉你一些用来选择特征的方法,以及如何得到不同的学习算法,当选择了合适的特征后,这些算法往往是非常有效的。另外,我也想给你们讲一讲多项式回归,它使得你们能够使用线性回归的方法来拟合非常复杂的函数,甚至是非线性函数。

以预测房价为例,假设你有两个特征,分别是房子临街的宽度和垂直宽度,这就是我们想要卖出的房子的图片,临街宽度被定义为这个距离,其实就是它的宽度,或者说是你拥有的土地的宽度,如果这块地都是你的的话。而这所房子的纵向深度就是你的房子的深度,这是正面的宽度,这是深度。我们称之为临街宽度和纵深。

你可能会像这样建立一个线性回归模型,其中临街宽度是你的第一个特征 \(x_1\),纵深是你的第二个特征 \(x_2\)。但当我们在运用线性回归时,你不一定非要直接用给出的 \(x_1\)\(x_2\) 作为特征,其实你可以自己创造新的特征。因此,如果我要预测房子的价格,我真正要需做的也许是确定真正能够决定我房子大小,或者说我土地大小的因素是什么。因此,我可能会创造一个新的特征,我称之为 \(x\),它是临街宽度与纵深的乘积,这是一个乘法符号,它是临街宽度与纵深的乘积,这得到的就是我拥有的土地的面积。然后,我可以把假设选择为使其只使用一个特征,也就是我的土地的面积,对吧?由于矩形面积的计算方法是矩形长和宽相乘,因此,这取决于你从什么样的角度去审视一个特定的问题,而不是只是直接去使用临街宽度和纵深,这两个我们只是碰巧在开始时使用的特征。有时,通过定义新的特征,你确实会得到一个更好的模型。

与选择特征的想法密切相关的一个概念,被称为多项式回归(polynomial regression)。比方说,你有这样一个住房价格的数据集,为了拟合它,可能会有多个不同的模型供选择。其中一个你可以选择的是像这样的二次模型,因为直线似乎并不能很好地拟合这些数据。因此,也许你会想到用这样的二次模型去拟合数据,你可能会考量关于价格的一个二次函数,也许这样做会给你一个像这样的拟合结果。但是,然后你可能会觉得二次函数的模型并不好用,因为一个二次函数最终会降回来,而我们并不认为房子的价格在高到一定程度后会下降回来。因此,也许我们会选择一个不同的多项式模型,并转而选择使用一个三次函数。在这里,现在我们有了一个三次的式子,我们用它进行拟合,我们可能得到这样的模型,也许这条绿色的线,对这个数据集拟合得更好,因为它不会在最后下降回来。

那么,我们到底应该如何将模型与我们的数据进行拟合呢?使用多元线性回归的方法,我们可以通过将我们的算法做一个非常简单的修改来实现它。按照我们以前假设的形式,我们知道如何对这样的模型进行拟合,其中 \(h\theta(x)=\theta_0+\theta_1 x_1+\theta_2 x_2+\theta_3 x_3\),那么,如果我们想拟合这个三次模型,就是我用绿色方框框起来的这个,现在我们讨论的是,为了预测一栋房子的价格,我们用 \(\theta_0\)\(\theta_1\) 乘以房子的面积,加上 \(\theta_2\) 乘以房子面积的平方。因此,这个式子与那个式子是相等的,然后再加 \(\theta_3\) 乘以房子面积的立方。为了将这两个定义互相对应起来,为了做到这一点,我们自然想到了将 \(x_1\) 特征设为房子的面积,将第二个特征 \(x_2\) 设为房屋面积的平方,将第三个特征 \(x_3\) 设为房子面积的立方。那么,仅仅通过将这三个特征这样设置,然后再应用线性回归的方法,我就可以拟合这个模型,并最终将一个三次函数拟合到我的数据上。

我还想再说一件事,那就是如果你像这样选择特征,那么特征的归一化就变得更重要了。因此,如果房子的大小范围在 1 到 1000 之间,那么,比如说从 1 到 1000 平方尺,那么,房子面积的平方的范围就是一到一百万,也就是 1000 的平方。而你的第三个特征 x 的立方,抱歉,你的第三个特征 \(x^3\) 它是房子面积的立方,范围会扩大到 1 到 \(10^9\)。因此,这三个特征的范围有很大的不同,因此,如果你使用梯度下降法,应用特征值的归一化是非常重要的,这样才能将他们的值的范围变得具有可比性。

最后,这里是最后一个例子,关于如何使你真正选择出要使用的特征,此前我们谈到一个像这样的二次模型,并不是理想的,因为你知道,也许一个二次模型能很好地拟合这个数据,但二次函数最后会下降,这是我们不希望的,就是住房价格往下走,像预测的那样,出现房价的下降。但是,除了转而建立一个三次模型以外,你也许有其他的选择特征的方法,这里有很多可能的选项。但是给你另外一个合理的选择的例子,另一种合理的选择可能是这样的,一套房子的价格是 \(\theta_0\)\(\theta_1\) 乘以房子的面积,然后加 \(\theta_2\) 乘以房子面积的平方根,可以吧?平方根函数是这样的一种函数,也许 \(\theta_1\)\(\theta_2\)\(\theta_3\) 中会有一些值,会捕捉到这个模型,从而使得这个曲线看起来是这样的,趋势是上升的,但慢慢变得平缓一些,而且永远不会下降回来。因此,通过深入地研究,在这里我们研究了平方根函数的形状,并且更深入地了解了选择不同特征时数据的形状,有时可以得到更好的模型。

在本节课中,我们探讨了多项式回归,也就是如何将一个多项式,如一个二次函数,或一个三次函数拟合到你的数据上。除了这个方面,我们还讨论了在使用特征时的选择性,例如,我们不使用房屋的临街宽度和纵深,也许你可以把它们乘在一起,从而得到房子的土地面积这个特征。实际上,这似乎有点 难以抉择,这里有这么多不同的特征选择,我该如何决定使用什么特征呢?在之后的课程中,我们将探讨一些算法,它们能够自动选择要使用什么特征,因此,你可以使用一个算法观察给出的数据,并自动为你选择到底应该选择一个二次函数,或者一个三次函数,还是别的函数。但是,在我们学到那种算法之前,现在我希望你知道,你需要选择使用什么特征,并且通过设计不同的特征,你能够用更复杂的函数去拟合你的数据,而不是只用一条直线去拟合,特别是,你也可以使用多项式函数,有时候,通过采取适当的角度来观察特征就可以得到一个更符合你的数据的模型。

正规方程(Normal Equation)

在本节课中,我们要讲正规方程 (Normal Equation) ,对于某些线性回归问题,它给出了一个更好的方法,求出参数 \(\theta\) 的最优解。

具体而言,到目前为止,我们一直在使用的线性回归的算法是梯度下降法。就是说,为了最小化代价函数 \(J(\theta)\),我们使用的迭代算法需要经过很多步,也就是说通过多次迭代来计算梯度下降,来收敛到全局最小值。相反地,正规方程法提供了一种求 \(\theta\) 的解析解法。所以与其使用迭代算法,我们可以直接一次性求解 \(\theta\) 的最优值,所以说基本上一步就可以得到优化值。正规方程法有一些优点,也有一些缺点,但是在我们讲解这个和何时使用标准方程之前,让我们先对这个算法有一个直观的理解。

我们举一个例子来解释这个问题,我们假设有一个非常简单的代价函数 \(J(\theta)\),它就是一个实数 \(\theta\) 的函数。所以现在假设 \(\theta\) 只是一个标量,或者说 \(\theta\) 只有一行,它是一个数字,不是向量。假设我们的代价函数 \(J\) 是这个实参数 \(\theta\) 的二次函数,所以 \(J(\theta)\) 看起来是这样的,那么如何最小化一个二次函数呢?对于那些了解一点微积分的同学来说,你可能知道,最小化的一个函数的方法是对它求导,并且将导数置零。所以对 \(J\) 求关于 \(\theta\) 的导数,我不打算推导那些公式,你把那个导数置零,这样你就可以求得使得 \(J(\theta)\) 最小的 \(\theta\) 值,这是数据为实数的,一个比较简单的例子。

在这个问题中,我们感兴趣的是 \(\theta\) 不是一个实数的情况,它是一个 \(n+1\) 维的参数向量,并且,代价函数 \(J\) 是这个向量的函数,也就是 \(\theta_0\)\(\theta_n\) 的函数。一个代价函数看起来是这样,像右边的这个平方代价函数,我们如何最小化这个代价函数 \(J\)?实际上,微积分告诉我们一种方法,对每个参数 \(\theta\)\(J\) 的偏导数,然后把它们全部置零,如果你这样做,并且求出 \(\theta_0\)\(\theta_1\) 一直到 \(\theta_n\) 的值,这样就能得到能够最小化代价函数 \(J\)\(\theta\) 值。如果你真的做完微积分和求解参数 \(\theta_0\)\(\theta_n\),你会发现这个偏微分最终可能很复杂。

接下来我们要做的,实际上不是遍历所有的偏微分,因为这样太久太费事。我只是想告诉你们想要实现这个过程所需要知道的内容,这样你就可以解出偏导数为 0 时 \(\theta\) 的值。换个方式说,或者等价地,这个 \(\theta\) 能够使得代价函数 \(J(\theta)\) 最小化。我发现可能只有熟悉微积分的同学,比较容易理解我的话。所以,如果你不了解,或者不那么了解微积分,也不必担心,我会告诉你要实现这个算法,并且使其正常运行你所需的必要知识。

举个例子,我想运行这样一个例子,假如说我有 \(m=4\) 个训练样本,为了实现正规方程法,我要这样做,看我的训练集,在这里就是这四个训练样本,在这种情况下,我们假设这四个训练样本就是我的所有数据。我所要做的是,在我的训练集中加上一列对应额外特征变量的 \(x_0\),就是那个取值永远是 1 的。接下来我要做的是,构建一个矩阵 \(X\),这个矩阵基本包含了训练样本的所有特征变量。所以具体地说,这里有我所有的特征变量,我们要把这些数字全部放到矩阵中 \(X\) 中,好吧?所以,只是每次复制一列的数据,我要对 \(y\) 做类似的事情,我要对我们将要预测的值构建一个向量,像这样的,并且称之为向量 \(y\)。所以 \(X\) 会是一个 \(m \times (n+1)\) 维矩阵,\(y\) 会是一个 \(m\) 维向量。其中 \(m\) 是训练样本数量,\(n\) 是特征变量数,\(n+1\) 是因为我加的这个额外的特征变量 \(x_0\)。最后,如​​果你用矩阵 \(X\) 和向量 \(y\) 来计算这个,\(\theta\) 等于 \(X\) 转置乘以 \(X\) 的逆,乘以 \(X\) 转置乘以 \(y\),这样就得到能够使得代价函数最小化的 \(\theta\)

幻灯片上的内容比较多,我讲解了这样一个数据组的一个例子,让我把这个写成更加通用的形式。在之后的课程中,我会仔细介绍这个方程,以防你不完全清楚要如何做。在一般情况下,假如我们有 \(m\) 个训练样本 \(x^{(1)}\)\(y^{(1)}\) 直到 \(x^{(m)}\)\(y^{(m)}\)\(n\) 个特征变量。所以每一个训练样本 \(x^{(i)}\) 可能看起来像一个向量,像这样一个 \(n+1\) 维特征向量。我要构建矩阵 \(X\) 的方法,也被称为设计矩阵。如下所示,每个训练样本给出一个这样的特征向量,也就是说,这样的 \(n+1\) 维向量,我构建我的设计矩阵 \(X\) 的方法,就是构建这样的矩阵。接下来我要做的是,取第一个训练样本,也就是一个向量,取它的转置,它最后是这样扁长的样子,让 \(x_1\) 转置作为我设计矩阵的第一行,然后我要把我的第二个训练样本 \(x_2\) 进行转置,让它作为 \(X\) 的第二行。以此类推,直到最后一个训练样本,取它的转置作为矩阵 \(X\) 的最后一行。这样矩阵 \(X\) 就是一个 \(m \times (n+1)\) 维矩阵。举个具体的例子,假如我只有一个特征变量,就是说除了 \(x_0\) 之外只有一个特征变量,而 \(x_0\) 始终为 1,所以如果我的特征向量 \(x^{(i)}\) 等于 1,也就是 \(x_0\) 和某个实际的特征变量 \(x^{(i)}\) 等于 1,比如说房屋大小,那么我的设计矩阵 \(X\) 会是这样,第一行就是这个的转置,所以最后得到 1,然后 \(x^{(1)}_2\) 对于第二行,我们得到 1,这样直到 \(x^{(1)}_m\),这就会是一个 \(m \times 2\) 维矩阵。所以,这就是如何构建矩阵 \(X\) 和向量 \(y\)。有时我可能会在上面画一个箭头,来表示这是一个向量,但很多时候,我就只写 \(y\) 是一样的。向量 \(y\) 是这样求得的,把所有标签,所有训练集中正确的房子价格放在一起,得到一个 \(m\) 维向量 \(y\),最后,构建完矩阵 \(X\) 和向量 \(y\)。我们就可以通过计算 \(X\) 转置乘以 \(X\) 的逆,再乘以 \(X\) 转置乘以 \(y\) 来得到 \(\theta\)

我现在就想确保你明白这个等式,并且知道如何实现它。所以具体来说,什么是 \(X\) 的转置乘以 X 的逆?\(X\) 的转置乘以 \(X\) 的逆,是 \(X\) 转置乘以 \(X\) 的逆矩阵。具体来说,如果你令 \(A\) 等于 \(X\) 转置乘以 \(X\)\(X\) 的转置是一个矩阵,\(X\) 的转置乘以 \(X\) 是另一个矩阵,我们把这个矩阵称为 \(A\)。那么 \(X\) 转置乘以 \(X\) 的逆,就是矩阵 \(A\) 的逆,也就是 1/A,这就是计算过程,先计算 \(X\) 转置乘以 \(X\),然后计算它的逆。

我们还没有谈到 Octave,我们将在之后的课程中谈到这个,但是在 Octave 编程语言,或者类似的 MATLAB 编程语言里,计算这个量的命令是基本相同的。\(X\) 转置乘以 \(X\) 的逆乘以 \(X\) 转置乘以 \(y\) 的代码命令如下所示,在 Octave 中 X' 表示 \(X\) 转置。这个用红色框起来的表达式,计算的是 \(X\) 转置乘以 \(X\)pinv 是用来计算逆矩阵的函数,所以这个计算 \(X\) 转置乘以 \(X\) 的逆,然后乘以 \(X\) 转置再乘以 \(y\),这样就算完了这个式子。我没有证明这个式子,尽管我并不打算这么做,但是数学上是可以证明的,这个式子会给出最优的 \(\theta\) 值。就是说如果你令 \(\theta\) 等于这个 \(\theta\) 值,那么这个 \(\theta\) 值会最小化这个线性回归的代价函数 \(J(\theta)\)

最后一点,在之前的课程中我提到特征变量归一化,和让特征变量在相似的范围内的想法,将所有的值归一化在类似范围内,如果你使用正规方程法,那么就不需要归一化特征变量。实际上这是没问题的,如果某个特征变量 \(x_1\) 在 0 到 1 的区间,某个特征变量 \(x_2\) 在 0 到 1000 的区间,某个特征变量 \(x_3\) 在 0 到 \(10^{-5}\) 的区间,然后如果使用正规方程法,这样就没有问题,不需要做特征变量归一化,但如果你使用梯度下降法,特征变量归一化就很重要。

最后,你何时应该使用梯度下降法,而何时应该使用正规方程法呢?这里列举了一些它们的优点和缺点。

假如你有 \(m\) 个训练样本和 \(n\) 个特征变量,梯度下降法的缺点之一就是,你需要选择学习速率 \(\alpha\),这通常表示需要运行多次尝试不同的学习速率 \(\alpha\),然后找到运行效果最好的那个。所以这是一种额外的工作和麻烦。梯度下降法的另一个缺点是,它需要更多次的迭代,因为一些细节 计算可能会更慢,我们一会儿会看到更多的东西。至于正规方程,你不需要选择学习速率 \(\alpha\),所以就非常方便,也容易实现,你只要运行一下通常这就够了,并且你也不需要迭代,所以不需要画出 \(J(\theta)\) 的曲线,来检查收敛性或者采取所有的额外步骤。

到目前为止,天平似乎倾向于正规方程法,这里列举一些正规方程法的缺点和梯度下降法的优点。梯度下降法在有很多特征变量的情况下也能运行地相当好,所以即使你有上百万的特征变量,你可以运行梯度下降法,并且通常很有效,它会正常的运行。相对地,正规方程法为了求解参数 \(\theta\) 需要求解这一项,我们需要计算这项,\(X\) 转置乘以 \(X\) 的逆,这个 \(X\) 转置乘以 \(X\) 矩阵是一个 \(n \times n\) 的矩阵,如果你有 \(n\) 个特征变量的话。因为如果你看一下 \(X\) 转置乘以 \(X\) 的维度,你可以发现他们的积的维度,\(X\) 转置乘以 \(X\) 是一个 \(n \times n\) 的矩阵。其中 \(n\) 是特征变量的数量。实现逆矩阵计算所需要的计算量,大致是矩阵维度的三次方,因此计算这个逆矩阵需要计算大致 \(n\) 的三次方,有时稍微比计算 \(n\) 的三次方快一些,但是对我们来说很接近。所以如果特征变量的数量 \(n\) 很大的话,那么计算这个量会很慢,实际上标准方程法会慢很多。因此如果 \(n\) 很大,我可能还是会使用梯度下降法,因为我们不想花费 \(n\) 的三次方的时间。但如果 \(n\) 比较小,那么标准方程法可能更好地求解参数 \(\theta\)

那么怎么叫大或者小呢?如果 \(n\) 是上百的,计算百位数乘百位数的矩阵,对于现代计算机来说没有问题。如果 \(n\) 是上千的,我还是会使用正规方程法,千位数乘千位数的矩阵做逆变换,对于现代计算机来说实际上是非常快的。但如果 \(n\) 上万,那么我可能会开始犹豫,上万乘上万维的矩阵作逆变换,会开始有点慢,此时我可能开始倾向于梯度下降法,但也不绝对,\(n\) 等于一万 你可以逆变换一个一万乘一万的矩阵。但如果 \(n\) 远大于此,我可能就会使用梯度下降法了。所以如果 \(n\) 等于 \(10^6\),有一百万个特征变量,那么做百万乘百万的矩阵的逆变换,就会变得非常费时间。在这种情况下我一定会使用梯度下降法,所以很难给出一个确定的值来决定何时该换成梯度下降法。但是,对我来说通常是在一万左右,我会开始考虑换成梯度下降法,或者我们将在以后讨论到的其他算法。

总结一下,只要特征变量的数目并不大,正规方程是一个很好的计算参数 \(\theta\) 的替代方法。具体地说,只要特征变量数量小于一万,我通常使用正规方程法,而不使用梯度下降法。

预告一下在之后的课程中我们要讲的,随着我们要讲的学习算法越来越复杂,例如,当我们讲到分类算法,像逻辑回归算法,我们会看到,实际上对于那些算法,并不能使用正规方程法,对于那些更复杂的学习算法,我们将不得不仍然使用梯度下降法。因此,梯度下降法是一个非常有用的算法,可以用在有大量特征变量的线性回归问题,或者我们以后在课程中会讲到的一些其他的算法。因为,标准方程法不适合或者不能用在它们上,但对于这个特定的线性回归模型,正规方程法是一个比梯度下降法更快的替代算法。所以,根据具体的问题,以及你的特征变量的数量,这两算法都是值得学习的。

正规方程及不可逆性(可选)[Normal Equation Noninvertibility (Optional)]

本节课,我想谈谈正规方程(normal equation)以及它们的不可逆性。

由于这是一种较为深入的概念,并且总有人问我有关这方面的问题,因此,我想在这里来讨论它。由于概念较为深入所以对这段可选材料大家放轻松吧,也许你可能会深入地探索下去,并且会觉得理解以后会非常有用,但即使你没有理解正规方程和线性回归的关系,也没有关系。

我们要讲的问题如下,你或许可能对线性代数比较熟悉,有些同学曾经问过我,当计算 \(\theta\) 等于 inv(X'X)X'y,那对于矩阵 X'X 的结果是不可逆的情况该怎么办呢?如果你懂一点线性代数的知识,你或许会知道,有些矩阵可逆,而有些矩阵不可逆。我们称那些不可逆矩阵为奇异或退化矩阵。问题的重点在于 X'X 的不可逆的问题很少发生。

在 Octave 里,如果你用它来实现 \(\theta\) 的计算,你将会得到一个正常的解,在这里我不想赘述。在 Octave 里,有两个函数可以求解矩阵的逆,一个被称为 pinv(),另一个是 inv(),这两者之间的差异是些许计算过程上的。一个是所谓的伪逆,另一个被称为逆。使用 pinv() 函数可以展现数学上的过程,这将计算出 \(\theta\)的值,即便矩阵 X'X 是不可逆的。在 pinv() 和 inv() 之间,又有哪些具体区别呢?其中 inv() 引入了先进的数值计算的概念,我真的不希望讲那些。

因此,我认为可以试着给你一点点直观的参考,关于矩阵 X'X 的不可逆的问题,如果你懂一点线性代数,或许你可能会感兴趣,我不会从数学的角度来证明它。

但如果矩阵 X'X 结果是不可逆的,通常有两种最常见的原因:

第一个原因是,如果不知何故,在你的学习问题你有多余的功能。例如,在预测住房价格时,如果 \(x_1\) 是以英尺为尺寸规格计算的房子,\(x_2\) 是以平方米为尺寸规格计算的房子,同时,你也知道 1 米等于 3.28 英尺(四舍五入到两位小数)。这样,你的这两个特征值将始终满足约束 \(x_1\) 等于 \(x_2\) 倍的 3.28 平方,并且你可以将这过程显示出来。讲到这里,可能或许对你来说有点难了,但如果你在线性代数上非常熟练,实际上,你可以用这样的一个线性方程来展示那两个相关联的特征值矩阵 X'X 将是不可逆的。

第二个原因是,在你想用大量的特征值尝试实践你的学习算法的时候,可能会导致矩阵 X'X 的结果是不可逆的。具体地说,在 \(m\) 小于或等于 \(n\) 的时候。例如,有 \(m\) 等于 10 个的训练样本,也有 \(n\) 等于 100 的特征数量,要找到适合的(\(n+1\))维参数矢量 \(\theta\),这是第 \(n+1\) 维。这将会变成一个 101 维的矢量,尝试从 10 个训练样本中找到满足 101 个参数的值,这工作可能会让你花上一阵子时间,但这并不总是一个好主意。因为,正如我们所看到,你只有 10 个样本,以适应这 100 或 101 个参数,数据还是有些少。稍后我们将看到,如何使用小数据样本以得到这 100 或 101 个参数。通常,我们会使用一种叫做正则化的线性代数方法,通过删除某些特征,或者是使用某些技术,来解决当 \(m\)\(n\) 小的时候的问题。这也是在本节课后面要讲到的内容,即使你有一个相对较小的训练集,也可使用很多的特征来找到很多合适的参数。

有关正规化的内容将是本节之后课程的话题,总之当你发现的矩阵 X'X 的结果是奇异矩阵,或者找到的其它矩阵是不可逆的,我会建议你这么做,首先,看特征值里是否有一些多余的特征,像这些 \(x_1\)\(x_2\) 是线性相关的,或像这样互为线性函数,同时,当有一些多余的特征时,可以删除这两个重复特征里的其中一个,无须两个特征同时保留,所以,发现多余的特征删除二者其一,将解决不可逆性的问题。因此,首先应该通过观察所有特征检查是否有多余的特征,如果有多余的就删除掉。

逻辑回归(Logistic Regression)

分类问题(Classification)

在这个以及接下来的几节课中,我们将开发一种叫做逻辑回归(Logistic Regression)的算法,这是当今最流行和最广泛使用的学习算法之一。

下面是分类问题的一些例子。此前,我们谈到的垃圾邮件分类就是一个分类问题,另一个例子是网上交易的分类问题。比如你有一个卖东西的网站,如果你想了解某一个实体的交易是不是欺诈,例如是否用盗取的信用卡,或者窃取用的密码,这是一种分类问题。我们前面也提到过,对肿瘤进行分类的例子,是恶性肿瘤或者良性肿瘤。在所有的这些问题中,我们要尝试预测的变量 \(y\) 都是可以有两个取值的变量,0 或 1。垃圾邮件或者非垃圾邮件,欺诈或不欺诈,恶性或良性。我们用 0 来表示负类(Negative Class),用 1 来表示正类(Positive Class)。所以 0 可以表示良性肿瘤,1 可以表示恶性肿瘤。两个类别中,例如垃圾邮件或非垃圾邮件,到底哪个是正类哪个是负类,或者哪个是 0 哪个是 1 是任意的,没有什么区别。但往往有这样的直觉,负类表示没有某样东西,例如没有恶性肿瘤。而 1 即正类表示具有我们要寻找的东西,但是哪个是正哪个是负,没有明确规定,也并不重要。现在我们要从只包含 0 和 1 两类的分类问题开始。稍后,我们将讨论多分类的问题,例如变量 \(y\) 可以选取 0,1,2,3 这几个值,这就是多分类问题。之后的几节课,让我们先从二分类或二元分类开始,我们稍后会考虑多分类。

我们如何开发一个分类算法呢?这个例子中的训练集是对肿瘤进行恶性或良性分类得到的数据,注意恶性与否只有两个值,0 - 否,1 - 是。所以我们可以做的是,对于这个给定的训练集,把我们学过的线性回归算法应用到这个数据集,用直线对数据进行拟合。如果你将训练集用直线取拟合它,或许你会得到这样的假设,所以这是我的假设 \(h(x)=\theta^T*X\)。如果你想做出预测,你可以将分类器输出的阈值设为 0.5,即纵坐标值为 0.5。如果假设输出一个大于等于 0.5,可以预测 \(y\) 为 1。如果小于 0.5 预测 \(y\) 等于 0。让我们来看结果,所以,让我们取 0.5 这就是阈值,因此使用线性回归后,在这个点的右边,我们将预测为正,因为纵轴上的输出值大于 0.5,而这一点的左边,我们将预测为负。在这个特定的例子中,似乎线性回归做的事情很合理。

但是,尝试改变一下问题,将横轴延长一点,假如我们有另一个训练样本,位于右边远处。注意这个额外的训练样本,在这里的这一个,它并没有改变什么,对不对?看着训练集,显然假设很好,所有在这个点右边的,我们应该预测为正,在左边的我们预测为负。因为从训练集看起来,这些肿瘤大于在这里的一定值即是恶性的,小于该值的所有肿瘤是良性的,至少在这个训练集里。但是我们在这里增加一个额外的例子,如果运行线性回归,你会得到另一条直线取拟合数据,看起来是这样的。现在如果你将阈值设为 0.5,你的阈值就在这里。所以在这个点的右侧,会被预测为正,在这个点的左侧,会被预测为负。而这似乎是一个相当差劲的线性回归了。因为这些是阳性样本,这些都是阴性样本,很显然我们应该在这个附近分成两类。但是,通过在右边远处添加了一个额外的样本,这个样本没有提供任何新信息。我的意思是,毫无疑问,算法会将这个样本判定为恶性,但不知何故,加了额外的一个样本之后,使得线性回归对数据的拟合直线从洋红色线这里变到蓝线这里,因此生成了一个更坏的假设。把线性回归应用于分类问题,通常并不是一个好主意。在第一个例子中,在我加这个额外的样本之前,之前的线性回归运气很好,我们得到了一个假设对这个例子效果还不错。但通常对数据集进行线性回归,有时候效果会好,但通常不是一个好的方法。所以我不推荐将线性回归用于分类问题。

另外一个有趣的事情是,如果对分类问题使用线性回归,会发生什么?对于分类,我们直到 \(y\) 是 0 或 1。如果你使用线性回归假设的输出值会远大于 1 或小于 0,即使所有的训练样本的标签都是 \(y\) 等于 0 或 1,这似乎有点怪。即使我们知道,标签应该是 0 或 1,但算法的输出值如果远大于 1 或者远小于 0,还是有点奇怪。

所以,接下来的几节课中,我们将开发一个名为 logistic 回归的算法,其特点在于,算法的输出或者说预测值一直介于 0 和 1 之间,并不会大于 1 或者小于 0。顺便说一下,我们把 logistic 回归视为一种分类算法,但因为名字中有 "回归" 二字,有时候可能会令人产生困惑,但 logistic 回归实际上是一种分类算法,它被命名为这个名字,只是由于历史原因,所以不要感到困惑,logistic 回归实际上是一种分类算法,用在标签 \(y\) 为离散值 0 或 1 的情况下。所以希望你现在知道为什么,对分类问题,使用线性回归不是一个好主意。在接下来的课程中,我们将探讨 logistic 回归算法的细节,

假设表示(Hypothesis Representation)

让我们开始谈谈逻辑回归,在本节课中,我要给你展示假设函数的表达式,也就是说,在分类问题中,要用什么样的函数来表示我们的假设。

此前我们说过,希望我们的分类器的输出值在 0 和 1 之间,因此,我们希望想出一个满足某个性质的假设函数,这个性质是它的预测值要在 0 和 1 之间。当我们使用线性回归的时候。这是一种假设函数的形式。其中 \(h(x)=\theta^Tx\)。对于逻辑回归来说,我要把这个稍微改一下,把假设函数改成 \(g(\theta^Tx)\)。其中,我将定义函数 \(g\) 如下:

\(z\) 是一个实数时,\(g(z)=\frac{1}{1+e^{-z}}\),这称为 S 型函数(sigmoid function)或逻辑函数,逻辑函数这个词就是逻辑回归名字的由来。顺便说一下,S 型函数和逻辑函数,基本上是同义词,意思是一样的。因此,这两个术语基本上是可互换的,哪一个术语都可以用来表示这个函数 \(g\)。如果我们把这两个方程合并到一起,这是我的假设的另一种写法,也就是说 \(h(x)=\frac{1}{1+e^{-(\theta^Tx)}}\)。我所做的是把这个变量 \(z\),这里 \(z\) 是一个实数,把 \(\theta^Tx\) 代入到这里,所以最后得到的是 \(\theta^Tx\) 代替了这里的 \(z\)

最后,我们看一下 S 型函数是什么样的。我们在这儿绘制这个图形 S 型函数 \(g(z)\) 也称为逻辑函数,看起来是这样的。它开始接近 0,然后上升,直到在原点处达到 0.5,然后它再次变平,像这样,所以这就是 S 型函数的样子。而且,你注意 S 型函数它随着 \(z\) 趋于负无穷,\(g(z)\) 趋近于 0,随着 \(z\) 趋于正无穷,\(g(z)\) 趋近于 1。因为 \(g(z)\) 的取值在 0 和 1 之间,我们就得到 \(h(x)\) 的值也必在 0 和 1 之间。

有了这个假设函数,我们需要做的是和之前一样,用参数 \(\theta\) 拟合我们的数据。所以拿到一个训练集,我们需要给参数 \(\theta\) 选定一个值,然后用这个假设函数做出预测。稍后我们将讨论一个用来拟合参数 \(\theta\) 的学习算法,但是首先让我们讨论一下这个模型的解释。这就是我对假设函数 \(h(x)\) 的输出的解释,当我的假设函数输出某个数,我会认为这个数是对于新输入样本 \(x\)\(y\) 等于 1 的概率的估计值。我的意思是这样的,下面举个例子,比方说,我们来看肿瘤分类的例子,我们有一个特征向量 \(x\),和平时一样 \(x_0\) 等于 1,然后我们的特征变量 \(x_1\) 是肿瘤的大小。假设我有一个病人来了,而且知道肿瘤的大小,把他们的特征向量 \(x\) 代入我的假设函数,假如假设函数的输出为 0.7,我将解释我的假设如下,我要说这个假设告诉我,对于一个特征为 \(x\) 的患者,y 等于 1 的概率是 0.7。换句话说,我要告诉我的病人,非常遗憾,肿瘤是恶性的可能性是 70% 或者说 0.7。要更加正式的写出来,或者说写成数学表达式,我的假设函数等于 P(y=1|x;\(\theta\))。对于熟悉概率的人,应该能看懂这个式子,如果你不太熟悉概率,可以这么看这个表达式,在给定 \(x\) 的条件下,\(y=1\) 的概率。给定的 \(x\) 就是我的病人的特征 \(x\),特征 \(x\) 代表了我的病人特定的肿瘤大小,这个概率的参数是 \(\theta\),所以,我基本上可以认为 假设函数给出的估计是 \(y=1\) 的概率。现在,因为这是一个分类的任务,我们知道 \(y\) 必须是 0 或 1,对不对?它们是 \(y\) 可能取到的仅有的两个值,无论是在训练集中,或是对走进我的办公室,或在未来进入医生办公室的新患者。因此,有了 \(h(x)\),我们也可以计算 \(y=0\) 的概率。具体地说,因为 \(y\) 必须是 0 或 1,我们知道 \(y=0\) 的概率,加上 \(y=1\) 的概率必须等于 1。这第一个方程看起来,有点复杂,基本上就是说,给定参数 \(\theta\) 对某个特征为 \(x\) 的病人 \(y=0\) 的概率和给定参数 \(\theta\) 时,对同一个特征为 \(x\) 的病人 \(y=1\) 的概率相加必须等于 1。如果觉得这个方程看起来有点儿复杂,可以想象它没有 \(x\)\(\theta\),这就是说 \(y=0\) 的概率加上 \(y=1\) 的概率必须等于 1。我们知道这是肯定的,因为 \(y\) 要么是 0,要么是 1,所以 \(y=0\) 的可能性和 \(y=1\) 的可能性,它们俩相加肯定等于 1。所以,如果你只是把这一项移到右边,你就会得到这个等式。就是说 \(y=0\) 的概率等于 1 减去 \(y=1\) 的概率。因此,我们的假设函数 \(h(x)\) 给出的是这一项,你可以简单地计算出这个概率,计算出 \(y=0\) 的概率的估计值。所以,你现在知道逻辑回归的假设函数的表达式是什么,我们看到了定义逻辑回归的假设函数的数学公式。在接下来的课程中,我想试着让你对假设函数是什么样子有一个更直观的认识,我想告诉你一个被称为判定边界的东西,我们会一起看一些可视化的东西,可以更好地理解逻辑回归的假设函数到底是什么样子。

判定边界(Decision Boundary)

在之前的课程中,我们谈到逻辑回归中假设函数的表示方法,现在,我想告诉大家一个叫做决策边界(decision boundary)的概念,这个概念能更好地帮助我们理解逻辑回归的假设函数在计算什么。

让我们回忆一下,这是我们上次写下的公式,当时我们说,假设函数可以表示为 \(h(x)=g(\theta^Tx)\),其中函数 \(g\) 被称为 S 形函数(sigmoid function),看起来是应该是这样的形状,它从零开始慢慢增加至 1,逐渐逼近 1。

现在让我们更进一步来理解,这个假设函数何时会将 \(y\) 预测为 1,什么时候又会将 \(y\) 预测为 0。让我们更好的理解,假设函数应该是怎样的,特别是当我们的数据有多个特征时。

具体地说,这个假设函数输出的是给定 \(x\)\(y=1\) 的概率。因此,如果我们想预测 \(y\) 等于 1 还是等于 0,我们可以这样做,只要该假设函数输出 \(y=1\) 的概率大于或等于 0.5,那么这表示 \(y\) 更有可能等于 1 而不是 0。在另一种情况下,如果,预测 \(y=1\) 的概率小于 0.5,那么我们应该预测 \(y=0\)。在这里,我选择大于等于,在这里我选择小于。如果 \(h(x)\) 的值正好等于 0.5,那么,我们可以预测为 1 也可以预测为 0。但是这里我选择了大于等于,因此我们默认如果 \(h(x)\) 等于 0.5 的话,预测选择为 1,这只是一个细节,不用太在意。

下面,我希望大家能够清晰地理解什么时候 \(h(x)\) 将大于或等于 0.5,从而,我们最终预测 \(y=1\)。如果我们看看 S 形函数的曲线图,我们会注意到 S 函数只要 \(z\) 大于或等于 0 时,\(g(z)\) 就将大于或等于 0.5。因此,在曲线图的这半边 \(g\) 的取值大于或等于 0.5,因为这个交点就是 0.5。因此,当 \(z\) 大于 0 时,\(g(z)\) 也就是这个 S 形函数,是大于或等于 0.5 的。由于逻辑回归的假设函数 \(h(x)=g(\theta^Tx)\),因此,函数值将会大于或等于 0.5,只要 \(\theta^Tx \geq 0\)。因此,我们看到,因为这里 \(\theta^Tx\) 取代了 \(z\) 的位置,所以我们看到,我们的假设函数将会预测 \(y=1\),只要 \(\theta^Tx \geq 0\)

现在让我们来考虑假设函数预测 \(y=0\) 的情况。类似的 \(h(\theta)\) 将会小于 0.5,只要 \(g(z)\) 小于 0.5,这是因为 \(z\) 的定义域上,导致 \(g(z)\) 取值小于 0.5 的部分是 \(z\) 小于 0 的部分,所以当 \(g(z)\) 小于 0.5 时,我们的假设函数将会预测 \(y=0\)。根据与之前类似的原因 \(h(x)=g(\theta^Tx)\),因此,只要 \(\theta^Tx < 0\),我们就预测 \(y\) 等于 0。

总结一下我们刚才所讲的,我们看到,如果我们要决定预测 \(y=1\),还是 \(y=0\) 取决于 \(y=1\) 的概率大于或等于 0.5 还是小于 0.5。这其实就等于说,我们将预测 \(y=1\),只需要 \(\theta^Tx \geq 0\)。另一方面我们将预测 \(y=0\) 只需要 \(\theta^Tx < 0\)。通过这些,我们能更好地理解如何利用逻辑回归的假设函数来进行预测。

现在假设我们有一个训练集,就像幻灯片上的这个,接下来我们假设我们的假设函数是 \(h(x)=g(\theta_0+\theta_1x_1+\theta_2x_2)\),目前我们还没有谈到如何拟合此模型中的参数,我们将在下节课中讨论这个问题,但是假设我们已经拟合好了参数,我们最终选择了如下值,比方说,我们选择 \(\theta_0=-3\)\(\theta_1=1\)\(\theta_2=1\),因此,这意味着我的参数向量将是 \(\theta=[-3, 1, 1]\)。这样,我们有了这样的一个参数选择,让我们试着找出假设函数何时将预测 \(y\) 等于 1,何时又将预测 \(y\) 等于 0。使用我们在上一张幻灯片上展示的公式,我们知道,\(y\) 更有可能是 1,或者说 \(y\) 等于 1 的概率大于 0.5,或者大于等于 0.5,只要 \(\theta^Tx \geq 0\)。我刚刚加了下划线的这个公式:\(-3+x_1+x_2\),当然就是 \(\theta^Tx\),这是当 \(\theta\) 等于我们选择的这个参数值时 \(\theta^Tx\) 的表达。因此,举例来说,对于任何样本,只要 \(x_1\)\(x_2\) 满足这个等式,也就是 \(-3+x_1+x_2 \geq 0\),我们的假设函数就会认为 \(y\) 等于 1 的可能性较大,或者说将预测 \(y=1\)。我们也可以将 -3 放到不等式右边,并改写为 \(x_1+x_2 \geq 3\),这样是等价的。我们发现,这一假设函数将预测 \(y=1\),只要 \(x_1+x_2 \geq 3\)

让我们来看看这在图上是什么意思。如果我写下等式 \(x_1+x_2=3\),这将定义一条直线。如果我画出这条直线,它将表示为这样一条线,它通过 \(x_1\) 轴上的 3 和 \(x_2\) 轴上的 3,因此,这部分的输入样本空间,这一部分的 \(x_1-X_2\) 平面对应 \(x_1+x_2 \geq 3\),这将是上面这个半平面,也就是所有上方和所有右侧的部分,相对我画的这条洋红色线来说。所以,我们的假设函数预测 \(y\) 等于 1 的区域就是这片区域,是这个巨大的区域,是右上方的这个半平面。让我把它写下来,我将称它为 \(y=1\) 区域。与此相对 \(x_1+x_2 < 3\),也就是我们预测 \(y\) 等于 0 的区域,是这一片区域,你看到这也是一个半平面,左侧的这个半平面是我们的假设函数预测 \(y\) 等于 0 的区域。我想给这条线一个名字,就是我刚刚画的这条洋红色线,这条线被称为决策边界(decision boundary)。具体地说,这条直线满足 \(x_1+x_2=3\),它对应一系列的点,它对应 \(h(x)=0.5\) 的区域,决策边界,也就是这条直线,将整个平面分成了两部分,其中一片区域假设函数预测 \(y\) 等于 1。而另一片区域,假设函数预测 \(y\) 等于 0。我想澄清一下,决策边界是假设函数的一个属性,它包括参数 \(\theta_0\)\(\theta_1\)\(\theta_2\)。在这幅图中,我画了一个训练集,我画了一组数据,让它更加可视化,但是,即使我们去掉这个数据集,这条决策边界和我们预测 \(y\) 等于 1,与 \(y\) 等于 0 的区域,它们都是假设函数的属性,决定于其参数,它不是数据集的属性。当然,我们后面还将讨论,如何拟合参数,那时,我们将使用训练集,使用我们的数据来确定参数的取值。但是,一旦我们有确定的参数取值,有确定的 \(\theta_0\)\(\theta_1\)\(\theta_2\),我们就将完全确定决策边界,这时,我们实际上并不需要在绘制决策边界的时候绘制训练集。

现在,让我们看一个更复杂的例子,和往常一样,我使用十字 (X) 表示我的正样本,圆圈 (O) 表示我的负样本。给定这样的一个训练集,我怎样才能使用逻辑回归拟合这些数据呢?早些时候,当我们谈论多项式回归或线性回归时,我们谈到可以添加额外的高阶多项式项。同样,我们也可以对逻辑回归使用相同的方法。具体地说,假如我的假设函数是这样的,我已经添加了两个额外的特征 \(x_1\) 平方和 \(x_2\) 平方。所以,我现在有 5 个参数 \(\theta_0\)\(\theta_4\)。之前讲过,我们会在下一节课中讨论如何自动选择参数 \(\theta_0\)\(\theta_4\) 的取值。但是,假设我已经使用了这个方法,我最终选择 \(\theta_0=-1\)\(\theta_1=0\)\(\theta_2=0\)\(\theta_3=1\)\(\theta_4=1\)。这意味着,在这个参数选择下,我的参数向量 \(\theta\) 将是 [-1, 0, 0, 1, 1]。根据我们前面的讨论,这意味着我的假设函数将预测 \(y=1\),只要 \(-1+{x_1}^2+{x_2}^2 \geq 0\),也就是 \(\theta^Tx \geq 0\) 的时候。如果我将 -1 放到不等式右侧,我可以说,我的假设函数将预测 \(y=1\),只要 \({x_1}^2+{x_2}^2 \geq 1\)

那么决策边界是什么样子的呢?好吧,如果我们绘制 \({x_1}^2+{x_2}^2=1\) 的曲线,你们有些人已经知道这个方程对应半径为 1,以原点为中心的圆。所以,这就是我们的决策边界。圆外面的一切,我将预测 \(y=1\)。所以这里就是 \(y\) 等于 1 的区域,我们在这里预测 \(y=1\),而在圆里面,我会预测 \(y=0\)。因此,通过增加这些复杂的多项式特征变量,我可以得到更复杂的决定边界,而不只是用直线分开正负样本。

在这个例子中,我可以得到一个圆形的决策边界。再次强调决策边界不是训练集的属性,而是假设本身及其参数的属性,只要我们给定了参数向量 \(\theta\),圆形的决定边界就确定了,我们不是用训练集来定义的决策边界,我们用训练集来拟合参数 \(\theta\)。以后我们将谈论如何做到这一点,但是,一旦你有参数 \(\theta\) 它就确定了决策边界,让我重新显示训练集,以方便可视化。

最后,让我们来看看一个更复杂的例子。我们可以得到更复杂的决策边界吗?如果我有高阶多项式特征变量,比如 \({x_1}^2\)\({x_1}^2x_2\)\({x_1}^2{x_2}^2\) 等等。如果我有更高阶多项式,那么可以证明,你将得到更复杂的决策边界。而逻辑回归可以用于找到决策边界,例如,这样一个椭圆,或者参数不同的椭圆,也许你,可以得到一个不同的决定边界。像这个样子一些有趣的形状,或者更为复杂的例子。你也可以得到决策边界,看起来这样,这样更复杂的形状,在这个区域,你预测 \(y=1\)。在这个区域外面你预测 \(y=0\)。因此,这些高阶多项式特征变量可以让你得到非常复杂的决策边界。因此,通过这些可视化图形,我希望告诉你什么范围的假设函数我们可以使用逻辑回归来表示,现在我们知道了 \(h(x)\) 表示什么。

在下节课中,我将介绍如何自动选择参数 \(\theta\),使我们能在给定一个训练集时,我们可以根据数据自动拟合参数。

代价函数(Cost Function)

在本节课中,我们要讲如何拟合 logistic 回归模型的参数 \(\theta\)。具体来说,我要定义用来拟合参数优化目标或者叫代价函数。

这便是监督学习问题中的 logistic 回归模型的拟合问题。我们有一个训练集,里面有 \(m\) 个训练样本,像以前一样,我们的每个样本,用 \(n+1\) 维的特征向量表示。同样和以前一样,\(x_0=1\),第一个特征,或者说第 0 个特征,它一直是 1。而且因为这是一个分类问题,我们的训练集具有这样的特征,所有的标签 \(y\) 不是 0 就是 1。这是假设函数,它的参数是这里的这个 \(\theta\)。我要说的问题是,对于这个给定的训练集,我们如何选择,或者说如何拟合参数 \(\theta\)。以前我们建立线性回归模型时,使用了这个代价函数,我把这个写成稍微有点儿不同的形式,不写原先的 \(\frac{1}{2m}\),而是把 \(\frac{1}{2}\) 放到求和符号的里面了。现在我想用另一种方法来写代价函数,这里不写这个平方误差项,而是写成 \(Cost(h_{\theta}(x^{(i)}),y)\),定义这一项等于这个 \(\frac{1}{2}\) 的平方误差项。现在我们能更清楚的看到,代价函数是 \(\frac{1}{m}\) 乘以这个 cost 项在训练集范围上的求和。然后稍微简化一下这个式子,去掉这些上标会显得方便一些,所以直接定义 \(Cost(h_{\theta}(x^{(i)}),y)=\frac{1}{2}\left(h_{\theta}(x)-y\right)^2\)。对这个代价函数的理解是这样的,它是在输出的预测值是 \(h(x)\),而实际标签是 \(y\) 的情况下,我们希望学习算法付出的代价,和往常一样,在线性回归中,代价值被定义为这个,这个代价值是 \(\frac{1}{2}\left(h_{\theta}(x)-y\right)^2\),这个代价函数在线性回归里很好用。但是我们现在要用在 logistic 回归里,如果我们可以最小化函数 \(J\) 里的这个代价函数,它也能工作。但实际上,如果我们使用这个代价函数,它会变成参数 \(\theta\) 的非凸函数。我说的非凸函数是这个意思,对于这样一个代价函数 \(J(\theta)\),对于 logistic 回归来说,这里的 \(h\) 函数是非线性的,对吧?因为 \(\frac{1}{1+e^{-\theta^Tx}}\) 是一个很复杂的非线性函数。如果你把这个 Sigmoid 函数代入这里,在把这个 Cost 项代入这里,画出 \(J(\theta)\) 的图像,你会发现 \(J(\theta)\) 可能是一个这样的函数,有很多局部最优值,称呼它的正式术语是,这是一个非凸函数。你大概可以发现,如果你把梯度下降算法用在一个这样的函数上,不能保证它会收敛到全局最小值。相应地,我们希望,我们的代价函数 \(J(\theta)\) 是一个凸函数,是一个单弓形函数,大概是这样。所以,如果对它使用梯度下降法,我们可以保证梯度下降法会收敛到该函数的全局最小值。但使用这个平方代价函数的问题是,因为中间的这个非常非线性的 Sigmoid 函数导致 \(J(\theta)\) 成为一个非凸函数,如果你用平方函数定义它的话。所以我们想做的是另外找一个不同的代价函数,它是凸函数,使得我们可以使用很好的算法,如梯度下降法,而且能保证找到全局最小值。这个代价函数就是我们要用在 logistic 回归上的,我们定义这个算法要付的代价或者惩罚。如果输出值是 \(h(x)\),假如说预测值 \(h(x)\) 是一个数,比如 0.7,而实际上,真实的标签值是 \(y\),那么代价值将等于 \(-log(h(x))\)\(y=1\) 时,以及 \(-log(1-h(x))\)\(y=0\) 时。这看起来是个非常复杂的函数,但是让我们画出这个函数,直观地感受一下它在做什么。

我们从 \(y=1\) 这个情况开始,如果 \(y=1\),那么这个代价函数是 \(-log(h(x))\),如果我们画出它,我们将 \(h(x)\) 画在横坐标上,我们知道假设函数的输出值是在 0 和 1 之间的,所以 \(h(x)\) 的值在 0 和 1 之间变化。如果你画出这个代价函数的样子,你会发现它看起来是这样的。理解这个函数为什么是这样的,一个方式是,如果你画出 \(log(z)\)\(z\) 在横轴上,它看起来会是这样,它趋近于负无穷,这是对数函数的样子。所以这里是 0,这里是 1。显然,这里的 \(z\) 就是代表 \(h(x)\) 的角色。\(-log(z)\) 看起来这样,就是翻转一下符号。我们所感兴趣的是,函数在 0 到 1 之间的这个区间,所以,忽略那些,所以,只剩下曲线的这部分,这就是左边这条曲线的样子。现在这个代价函数有一些有趣而且很好的性质,首先,你注意到,如果 \(y=1\) 而且 \(h(x)=1\),也就是说,如果假设函数预测值是 1,而且 \(y\) 刚好等于我预测的,那么这个代价值等于 0,对吧?这个曲线并不是平的,曲线还在继续走。首先,注意到如果 \(h(x)=1\),如果假设函数预测 \(y=1\),并且如果 \(y\) 确实等于 1,那么代价值等于 0,这对应于下面这个点,如果 \(h(x)=1\)。这里我们只需要考虑 \(y=1\) 的情况,如果 \(h(x)=1\),那么代价值等于 0。这是我们所希望的。因为如果我们正确预测了输出值 \(y\),那么代价值是 0。但是现在,同样注意到 \(h(x)\) 趋近于 0 时,当假设函数的输出趋近于 0 时,代价值激增,并且趋近于无穷,我们这样描述体现出了这样一种直观的感觉,那就是如果假设函数输出 0,相当于说,我们的假设函数说 \(y=1\) 的概率等于 0。这类似于我们对病人说,你有一个恶性肿瘤的概率,也就是说 \(y=1\) 的概率是 0,就是说你的肿瘤完全不可能是恶性的。然而如果结果病人的肿瘤确实是恶性的,即如果 \(y\) 最终等于 1,虽然我们告诉他,它发生的概率是 0,它完全不可能是恶性的,如果我么这样确定无疑地告诉他我们的预测,结果却发现我们是错的,那么,我们用非常非常大的代价值惩罚这个学习算法,它是被这样体现出来的,这个代价值趋近于无穷,如果 \(y=1\),而 \(h(x)\) 趋近于 0。

这是 \(y=1\) 时的情况,我们再来看看 \(y=0\) 时,代价函数是什么样。如果 \(y=0\),那么代价值是这个表达式,如果画出函数 \(-log(1-z)\),那么,你得到的代价函数实际上是这样的,它从 0 到 1,差不多这样,如果你画出 \(y=0\) 情况下的代价函数,你会发现大概是这样。这个曲线的特点是,在 \(h(x)\) 趋近于 1 时激增,趋近于正无穷,也就是说,如果最后发现 \(y\) 等于 0,而我们却几乎非常肯定地预测 \(y=1\) 的概率是 1,那么我们就要付出非常大的代价值。反过来,如果 \(h(x)=0\),而且 \(y=0\),那么假设函数预测对了,预测的是 \(y=0\),并且 \(y\) 就是等于 0,那么代价函数在这点上应该等于 0。

在本节课中,我们定义了单训练样本的代价函数,凸性分析的内容是超出这门课的范围的,但是可以证明我们所选的代价函数,会给我们一个凸优化问题,整体的代价函数 \(J(\theta)\) 会是一个凸函数,并且没有局部最优值。在下节课中,我们会把单训练样本的代价函数的这些理念,进一步发展,然后给出整个训练集的代价函数的定义,我们还会找到一种,比我们目前用的更简单的写法。基于以上,我们将使用梯度下降,从而得到 logistic 回归算法。

简化的成本函数和梯度下降(Simplified Cost Function and Gradient Descent)

在这节课中,我们将寻找一个更简洁的方法来表示代价函数,来代替之前的做法,然后我们将学会怎么去应用梯度下降法,来找到逻辑回归的参数。所以,在这本节课的结尾,你将会知道如何去实现一个可应用的逻辑回归函数。

这个是逻辑回归的代价函数,完整的代价函数是通过,将 \(m\) 个训练样本的代价函数求和获得的。每一个代价函数代表在不同的样本 \(y\) 上的预测误差。这个函数是我们之前的单个训练样本的代价函数,需要提醒一下,在分类问题中,我们的训练集所有的标签 \(y\) 的取值只包括 0 和 1 两种可能。这个是 \(y\) 的数学定义,由于 \(y\) 只能是 0 或者 1。在本节课中我们将寻找一个更简洁的方法来表示代价函数,值得一提的是,与其写出上述的代价函数(罚函数)以两种情况的形式,分别是 \(y=1\)\(y=0\) 的情况,不如我给你们展示一种如何将两行的公式,压缩到一个公式,这会有利于于简化罚函数的形式,以及梯度下降的推导。

具体而言,我们能像下面这样表述罚函数。我们假设 \(h(x)\)\(y\) 相关的罚函数,我会把这个罚函数写成 \(-y*log h(x)-(1-y)*log(1-h(x))\)。我将迅速向你展示这个表达式,这个公式是之前罚函数的等同表达式,或者说更加精简的表达式,用以表述我们关于罚函数的定义,我们来看这是为什么。我们知道只有两种可能的情况,\(y\) 必须为 0 或 1。让我们假设 \(y\) 等于 1。如果 \(y\) 等于 1,这就是说罚函数值等于 \(-y*log h(x)\), 因为 1 减去 \(y\) 将等于 0,对吧? 所以, 如果 \(y\) 等于 1,则 1 减去 \(y\) 就是 1 减去 1,因此是 0。所以第二项乘以 0 就消失了。所以我们这里只有第一项了,就是 \(-y*log h(x)\),这个等式正是我们之前罚函数表达式的第一种情况。另一个例子是 \(y=0\),如果是这样的话,那我们的罚函数就告诉我们,如果 \(y\) 等于 0,那么第一项就等于 0。而 1 减去 y 将等于 1,因为 1 减去 \(y\) 变成 1 减去 0,这是等于1。所以代价函数被简化成了这里的最后一项,对吧?因为这里的第一项乘以 0,所以它消失了。所以,这个式子只剩下最后一项,即 \(-log(1-h(x))\)。你可以证明这一项确实符合我们给出的这个式子,当 \(y\) 等于 0 的时候。所以这个新的代价函数的定义是更为简洁的形式,包括了 \(y=1\)\(y=0\) 这两种情况,并且用了一种只有一行,更加方便的形式。因此,我们可以将我们逻辑回归的代价函数写成这样,它是 \(m\) 分之一乘以这些代价函数的和,将之前我们得到的代价函数定义替换进式子里,最终我们得到了这个式子,我们把负号提取到式子外面。关于为什么我们要选择这个特殊的函数作为代价函数,尽管看起来我们可以选择其他的代价函数,在这节课上我没有时间来深入了解这一点。使用最大似然估计法,从统计数据中可以得出这个代价函数,这是统计学中的一种思想,即如何有效地为不同模型找到参数数据。这个代价函数有一个十分优秀的属性,即:凸性。所以这个代价函数是几乎每个人在逻辑回归模型中都会使用的。如果你不懂的话,我是指如果你不明白什么是最大似然估计的话,不用担心,但这只是一个更深层次的理由,在选择这个特殊的代价函数的理由,我有时间的话会在这个课上讲解,给出这个代价函数,是为了拟合参数。

我们接下来要做的事情是,尝试找到使 \(J\) 函数最小化的参数 \(\theta\)。所以,如果我们要尝试最小化函数 \(J\),它会给我们一个 \(\theta\) 的数据集。最后,如果给我们一个新的包含特征 \(x\) 集合的样本,我们能够得到拟合给出训练集的 \(\theta\),并输出像这样的预测函数。在这里提醒一下,我输出的预测函数可以这样理解,即 \(y\) 等于 1 的可能性。在给出输入 \(x\) 并且参数为 \(\theta\) 的情况下,你可以把这个看作我的假设函数,预测 \(y\) 等于 1 的概率。所以接下来要做的就是如何计算使函数 \(J\) 最小化的参数 \(\theta\),即我们能够得到拟合我们训练集的参数。我们最小化代价函数的方法是梯度下降法,这是我们的代价函数,如果我们想要把它最小化为 \(\theta\) 的函数,梯度下降法是我们常用的方法。我们反复更新参数 \(\theta\),令 \(\theta\) 等于 \(\theta\) 减去学习速率 \(\alpha\) 乘这一项的导数。如果你懂微积分,你可以比较轻松地计算这一项的导数,并且如果你可以化简它,你会得到和我一样的答案。但即使你不会微积分也不必担心,如果你真的计算了,那你会得到写在这里的这个方程,这是 \(i\) 从 1 到 \(m\) 项预测误差和 \(x^{(i)}\) 的第 \(j\) 项乘积之和。所以,如果你将这个偏导数项插回这里,之后我们可以把我们的梯度下降法写成以下这样,我做的就是把前一页幻灯片的导数项插在这里。所以,我们需要弄清楚,如果你有 \(n\) 个特征,你会有一个向量参数 \(\theta\),这个向量参数 \(\theta\) 包括 \(\theta_1\)\(\theta_2\)\(\theta_n\)。在你更新时,需要同步更新全部 \(\theta\) 值。现在,如果你采取这个更新规则,并将其与我们做的线性回归进行比较,你有可能惊奇地发现,这个方程就是我们我们在线性回归时用的。事实上,如果你看了之前的课程,如果你看了线性回归的梯度下降更新规则,会发现它和我在蓝框里写的式子一摸一样。所以,线性回归和逻辑回归是不同的算法吗?当然不同,观察逻辑回归的式子,预测函数 \(h_{\theta}(x)\) 的定义改变了。关于线性回归,我们有 \(h_{\theta}(x)=\theta^Tx\)。在逻辑回归中,\(h_{\theta}(x)\) 的定义改变了,现在是 \(h_{\theta}(x)=\frac{1}{1+e^{-\theta^Tx}}\)。所以,即使这个更新规则表面上看起来一样,但是因为 \(h_{\theta}(x)\) 的定义改变了,所以这个和线性回归的梯度下降法确实不同。

在前面的课程中,我们曾经讲过关于线性规划的梯度下降法,我们曾讲过怎样观测梯度下降,以便确定它是收敛的。对于逻辑回归,我通常使用相同的函数来观测梯度下降,以便确定它正确得收敛。当然我们希望,你可以想出,如何将这项技术应用到逻辑回归中。当使用梯度下降法实现逻辑回归时,我们有所有这些不同的参数值,从 \(\theta_1\)\(\theta_n\),这些我们需要使用这个表达式进行更新的参数值,我们可以采用一个 for 循环,for 循环 \(i\) 从 0 到 \(n\),或者 \(i\) 从1到 \(n+1\)。因此依次更新这些参数值中的每一个,当然比采用 for 循环更理想的方法是,我们可以采用向量化实现方法,所以一次向量化实现方法,可以更新全部的 \(n+1\) 个参数。

检查你自己的理解程度,你可以查看你是否能够指出,如何用这个算法做向量化实现。所以,你现在知道了如何实现逻辑回归的梯度下降法。最后,这还有一个我们之前讨论过的概念,在线性回归中的特征值缩放。我们看到在线性回归中,特征值缩放是如何帮助梯度下降法更快收敛,要使其最小化,我们需要用一个算法。特征值缩放同样适用于逻辑回归中的梯度下降法,逻辑回归的实际学习算法,当我们有特征值范围差异巨大时,应用特征值缩放同样可以使逻辑回归的梯度下降法更快收敛。就是如此,你现在知道了如何实现逻辑回归,这是一个十分强大,并且可能是世界上应用最广泛的分类算法,而你现在知道如何让它为你自己工作。

高级优化(Advanced Optimization)

在上节课中,用梯度下降的方法最小化逻辑回归中代价函数 \(J(\theta)\)。在本节课中,我们将学习一些高级优化算法和一些高级的优化概念。利用这些方法,我们就能够使通过梯度下降进行逻辑回归的速度大大提高,而这也将使算法更加适合解决大型的机器学习问题。

假设我们有数目庞大的特征量,现在我们换个角度来看什么是梯度下降。我们有个代价函数 \(J\),而我们想要使其最小化,那么我们需要做的是,我们需要编写代码,当输入参数 \(\theta\) 时,它们会计算出两样东西,\(J(\theta)\),以及 \(J\) 等于 0,1 直到 \(n\) 时的偏导数项。假设我们已经完成了可以实现这两件事的代码,那么梯度下降所做的就是,反复执行这些更新,生成了这个叫做 data 的对象,是吧?所以给出我们用于计算这些的偏导数的代码,梯度下降法就把它插入到这里,从而来更新参数 \(\theta\)。因此另一种考虑梯度下降的思路是,我们需要写出代码来计算 \(J(\theta)\) 这些偏导数,然后把这些插入到梯度下降中,然后它就可以为我们最小化这个函数。对于梯度下降来说,我认为,从技术上讲,你实际并不需要编写代码来计算代价函数 \(J(\theta)\)。你只需要编写代码来计算导数项,但是,如果你希望代码还要能够监控这些 \(J(\theta)\) 的收敛性,那么我们就需要自己编写代码来计算代价函数和偏导数项。所以,在写完能够计算这两者的代码之后,我们就可以使用梯度下降,但梯度下降并不是我们可以使用的唯一算法,还有其他一些算法,更高级,更复杂。如果我们能用这些方法来计算这两个项的话,那么这些算法就是为我们优化代价函数的不同方法,共轭梯度法 BFGS (变尺度法) 和 L-BFGS (限制变尺度法) 就是其中一些更高级的优化算法。它们需要有一种方法来计算 \(J(\theta)\),以及需要一种方法计算导数项,然后使用比梯度下降更复杂的算法来最小化代价函数,这三种算法的具体细节超出了本门课程的范畴。实际上你最后通常会花费很多天,或几周时间研究这些算法。你可以专门学一门课来提高数值计算能力,不过让我来告诉你他们的一些特性。这三种算法有许多优点,一个是使用这其中任何一个算法,你通常不需要手动选择学习率 \(\alpha\)。所以对于这些算法的一种思路是,给出计算导数项和代价函数的方法,你可以认为算法有一个智能的内部循环。而且,事实上,他们确实有一个智能的内部循环,称为线性搜索(line search)算法,它可以自动尝试不同的学习速率 \(\alpha\),并自动选择一个好的学习速率 \(\alpha\)。因此它甚至可以为每次迭代选择不同的学习速率。那么你就不需要自己选择这些。这些算法实际上在做更复杂的事情,而不仅仅是选择一个好的学习速率,所以它们往往最终收敛得远远快于梯度下降。不过,关于它们到底做什么的详细讨论,已经超过了本门课程的范围实际上。我过去使用这些算法,已经很长一段时间了,也许超过十年了,使用得相当频繁。而直到几年前,我才真正搞清楚共轭梯度法 BFGS 和 L-BFGS 的细节。因此,实际上,完全有可能成功使用这些算法,并应用于许多不同的学习问题,而不需要真正理解这些算法的内环间在做什么。如果说这些算法有缺点的话,那么我想说主要缺点是它们比梯度下降法复杂多了,特别是你最好不要尝试自己编写 L-BGFS 和 BFGS 这些算法,除非你是数值计算方面的专家。实际上,我不会建议你们编写自己的代码来计算数据的平方根或者计算逆矩阵,因为对于这些算法我还是会建议你直接使用一个软件库。所以,要求一个平方根,我们所能做的就是调用一些别人已经写好用来计算数字平方根的函数。

幸运的是有 Octave 和与它密切相关的 MATLAB 语言,我们将会用到它们。Octave 有一个非常理想的库,用于实现这些先进的优化算法。所以,如果你直接调用它自带的库,你就能得到不错的结果。我必须指出这些算法实现得好或不好是有区别的。因此,如果你正在你的机器学习程序中使用一种不同的语言,比如如果你正在使用 C,C++,Java 等等。你可能会想尝试一些不同的库,以确保你找到一个能很好实现这些算法的库。因为,在 L-BFGS 或者等高线梯度的实现上表现得好与不太好,是有差别的。因此,现在让我们来说明 如何使用这些算法,我打算举一个例子,比方说你有一个含两个参数的问题,这两个参数是 \(\theta_0\)\(\theta_1\),那么你的成本函数 \(J(\theta)\) 等于 \(\theta_1\) 减去 5 的平方再加上 \(\theta_2\) 减 5 的平方。因此,通过这个代价函数,你可以得到 \(\theta_1\)\(\theta_2\) 的值。如果你将 \(J(\theta)\) 最小化的话,那么它的最小值将是 \(\theta_1\) 等于 5,\(\theta_2\) 等于 5。我知道你们当中,有些人比别人微积分更好,但是你应该知道代价函数 \(J\) 的导数,推出来就是这两个表达式。我已经写在这儿了,那么你就可以应用高级优化算法里的一个来最小化代价函数 \(J\)。所以,如果我们不知道最小值是 5 和 5,但你想要代价函数找到这个最小值,是用比如梯度下降这些算法,但最好是用比它更高级的算法。你要做的就是运行一个像这样的 Octave 函数,那么我们运行一个函数,比如 costFunction 这个函数的作用就是,它会返回两个值,第一个是 jVal,它是我们计算的代价函数 \(J\)。所以说 jVal 等于 \(\theta_1\) 减 5 的平方加 \(\theta_2\) 减 5 的平方,这样就计算出这个代价函数。函数返回的第二个值是,梯度值,梯度值应该是一个 \(2 \times 1\) 的向量。梯度向量的两个元素对应这里的两个偏导数项,运行这个 costFunction 函数后,你就可以调用高级的优化函数这个函数叫 fminunc。它表示 Octave 里无约束最小化函数。调用它的方式如下,你要设置几个 options,这个 options 变量作为一个数据结构,可以存储你想要的 options。所以 GradObj 和 On 这里设置梯度目标参数为打开(on),这意味着你现在确实要给这个算法提供一个梯度,然后设置最大迭代次数,比方说 100。我们给出一个 \(\theta\) 的猜测初始值,它是一个 \(2 \times 1\) 的向量,那么这个命令就调用 @fminunc,这个 @ 符号表示指向我们刚刚定义的 costFunction 函数的指针,如果你调用它,它就会使用众多高级优化算法中的一个。当然你也可以把它当成梯度下降,只不过它能自动选择学习速率 \(\alpha\),你不需要自己来做。然后它会尝试使用这些高级的优化算法,就像加强版的梯度下降法,为你找到最佳的 \(\theta\) 值。让我告诉你它在 Octave 里什么样,所以我写了这个关于 \(\theta\) 的 costFunction 函数。跟前面幻灯片中一样,它计算出代价函数 jval 以及梯度 gradient gradient,有两个元素是代价函数对于 \(\theta_1\)\(\theta_2\) 这两个参数的偏导数。现在,让我们切换到 Octave 窗口,我把刚刚的命令敲进去 options = optimset,这是在我的优化算法的 options上设置参数的记号,这样就是 100 次迭代。我现在要给我的算法提供梯度值设置 \(\theta\) 的初始值是一个 \(2 \times 1\) 的零向量。这是我猜测的 \(\theta\) 初始值。现在我就可以写出三个返回值 [optTheta, functionVal, exitFlag],等于指向代价函数的指针 @costFunction,我猜测的初始值 initialTheta,还有options,如果我敲回车,这个就会运行优化算法它很快返回值。这个格式很有意思,因为我的代码是被缠住了,所以这个有点意思,完全是因为我的命令行被绕住了,不过这里只是数字上的一些问题,把它看成是加强版梯度下降,它们找到 \(\theta\) 的最优值是 \(\theta_1=5\)\(\theta_2=5\),这正是我们希望的 functionVal 的值。实际上是 10 的 -30 次幂。所以,这基本上就是 0,这也是我们所希望的。exitFlag 为 1,这说明它的状态是已经收敛了的。你也可以运行 help fminunc 命令去查阅相关资料,以理解 exitFlag 的作用。exitFlag 可以让你确定该算法是否已经收敛,这就是在 Octave 里运行这些算法的过程。哦,对了,这里我得指出,用 Octave 运行的时候,向量 \(\theta\) 的值,\(\theta\) 的参数向量必须是 d 维的,d 大于等于 2,所以 \(\theta\) 仅仅是一个实数。因此,如果它不是一个至少二维的向量或高于二维的向量,fminunc 就可能无法运算。因此如果你有一个一维的函数需要优化,你可以查找 Octave 里 fminuc 函数的资料,来得到更多的细节。这就是我们如何优化一个例子的过程,这是一个简单的二次代价函数,我们如果把它应用到逻辑回归中呢?

在逻辑回归中,我们有一个参数向量 \(\theta\),我要混合使用 Octave 记号和数学符号,我希望这个写法很明确。我们的参数 \(\theta\)\(\theta_0\)\(\theta_n\) 组成。因为在 Octave 的标号中,向量的标号是从 1 开始的。在 Octave 里 \(\theta_0\) 实际上写成 \(\theta_1\)。因此用 \(\theta_1\) 表示第一个参数 \(\theta_0\),然后有 \(\theta_2\),接下来写到 \(\theta_{n+1}\),对吧?这是因为 Octave 的记号是,向量从 1 开始的,而不是从 0 开始。因此,我们需要做的是写一个 costFunction 函数,它为逻辑回归求得代价函数。具体点说 costFunction 函数需要返回 jVal 值,因此需要一些代码来计算 \(J(\theta)\)。我们也需要给出梯度值 gradient,那么 \({gradient}_1\) 对应用来计算代价函数关于 \(\theta_0\) 的偏导数,接下去关于 \(\theta_1\) 的偏导数,依此类推。再次强调,这是 \({gradient}_1\)\({gradient}_2\) 等等,而不是 \({gradient}_0\)\({gradient}_1\)。因为 Octave 的标号是从 1 开始而不是从 0 开始的。我希望你们从这个幻灯片中学到的主要内容是,你所要做的是写一个函数,它能返回代价函数值,以及梯度值。因此,要把这个应用到逻辑回归或者甚至线性回归中,你也可以把这些优化算法用于线性回归,你需要做的就是输入合适的代码来计算这里的这些东西。

现在你已经知道如何使用这些高级的优化算法了,有了这些算法,你就可以使用一个复杂的优化库,它让算法使用起来更模糊一点 more opaque and so。因此,也许稍微有点难调试,不过由于这些算法的运行速度,通常远远超过梯度下降。因此当我有一个很大的机器学习问题时,我会选择这些高级算法,而不是梯度下降。有了这些概念,你就应该能将逻辑回归和线性回归应用于更大的问题中,这就是高级优化的概念。在下节课中,也就是逻辑回归这一部分的最后一节课中,我想要告诉你如何修改你已经知道的逻辑回归算法,然后使它在多类别分类问题中也能正常运行。

多类别分类:一对多(Multiclass Classification:One-vs-all)

在本节课中,我们将谈到如何使用逻辑回归(logistic regression)来解决多类别分类问题。具体来说,我想通过一个叫做 "一对多"(one-vs-all)的分类算法,让你了解什么是多类别分类问题。

先看这样一些例子,假如说你现在需要一个学习算法,能自动地将邮件归类到不同的文件夹里,或者说可以自动地加上标签。那么,你也许需要一些不同的文件夹,或者不同的标签来完成这件事。来区分开来自工作的邮件、来自朋友的邮件,来自家人的邮件或者是有关兴趣爱好的邮件。那么,我们就有了这样一个分类问题,其类别有四个,分别用 \(y=1\)\(y=2\)\(y=3\)\(y=4\) 来代表。另一个例子是有关药物诊断的,如果一个病人,因为鼻塞来到你的诊所,他可能并没有生病,用 \(y=1\) 这个类别来代表,或者患了感冒,用 \(y=2\) 来代表,或者得了流感 \(y=3\)。第三个例子,也是最后一个例子,如果你正在做有关天气的机器学习分类问题,那么你可能想要区分哪些天是晴天、多云、雨天、或者下雪天。

对上述所有的例子 \(y\) 可以取一个很小的数值,一个相对 "谨慎" 的数值,比如 1 到 3、1 到 4 或者其它数值。以上说的都是多类分类问题,顺便一提的是,对于下标是 0 1 2 3 还是 1 2 3 4 都不重要。我更喜欢将分类从 1 开始标而不是 0,其实怎样标注都不会影响最后的结果。然而对于之前的一个二元分类问题,我们的数据看起来可能是像这样,对于一个多类分类问题,我们的数据集或许看起来像这样。我用三种不同的符号来代表三个类别,问题就是,给出三个类型的数据集,这是一个类别中的样本,而这个样本是属于 另一个类别,而这个样本属于第三个类别,我们如何得到一个学习算法来进行分类呢?

我们现在已经知道如何进行二元分类,可以使用逻辑斯特回归,对于直线或许你也知道可以将数据集一分为二为正类和负类。用一对多的分类思想,我们可以将其用在多类分类问题上。

下面将介绍如何进行一对多的分类工作,有时这个方法也被称为 "一对余" 方法。现在我们有一个训练集,好比左边表示的有三个类别,我们用三角形表示 \(y=1\),方框表示 \(y=2\),叉叉表示 \(y=3\)。我们下面要做的就是,使用一个训练集,将其分成三个二元分类问题,所以我将它分成三个二元分类问题。我们先从用三角形代表的类别 1 开始,实际上我们可以创建一个新的 "伪" 训练集,类型 2 和类型 3,定为负类,类型 1 设定为正类。我们创建一个新的训练集,如右侧所示的那样,我们要拟合出一个合适的分类器,我们称其为 \(h_{\theta}^{(1)}(x)\),这里的三角形是正样本,而圆形代表负样本。可以这样想,设置三角形的值为 1,圆形的值为 0。下面我们来训练一个标准的逻辑回归分类器,这样我们就得到一个正边界,对吧?这里上标 (1) 表示类别 1,我们可以像这样对三角形类别这么做。下面,我们将为类别 2 做同样的工作,取这些方块样本,然后将这些方块作为正样本,设其它的为三角形和叉形类别为负样本。这样我们找到第二个合适的逻辑回归分类器,我们称为 \(h_{\theta}^{(2)}(x)\),其中上标 (2) 表示是类别 2,所以我们做的就是把方块类当做正样本,我们可能便会得到这样的一个分类器。最后,同样地,我们对第三个类别采用同样的方法,并找出第三个分类器 \(h_{\theta}^{(3)}(x)\)。或许这么做可以给出一个像这样的判别边界,或者说分类器能这样分开正负样本。总而言之,我们已经拟合出三个分类器对于 \(i\) 等于 1、2、3,我们都找到了一个分类器 \(h_{\theta}^{(i)}(x)\)。通过这样来尝试估计出给出 \(x\) 和先验 \(\theta\)\(y\) 的值等于 \(i\) 的概率,对么?在一开始,对于第一个在这里的分类器,完成了对三角形的识别,把三角形当做是正类别,所以 \(h^{(1)}\) 实际上是在计算给定 \(x\)\(\theta\) 为参数时 \(y\) 的值为 1 的概率是多少。同样地,这个也是这么处理矩形类型当做一个正类别,同样地,可以计算出 \(y=2\) 的概率和其它的概率值来。现在我们便有了三个分类器,且每个分类器都作为其中一种情况进行训练。总之,我们已经把要做的做完了,现在要做的就是训练这个逻辑回归分类器 \(h^{(i)}\),其中 \(i\) 对应每一个可能的 \(y=i\)。最后,为了做出预测,我们给出输入一个新的 \(x\) 值,用这个做预测,我们要做的就是,在我们三个分类器里面输入 $x4,然后,我们选择一个让 \(h\) 最大的 \(i\)。你现在知道了基本的挑选分类器的方法,选择出哪一个分类器是可信度最高,效果最好的,那么就可认为得到一个正确的分类。无论 \(i\) 值是多少,我们都有最高的概率值,我们预测 \(y\) 就是那个值。这就是多类别分类问题,以及一对多的方法,通过这个小方法,你现在也可以将逻辑回归分类器用在多类分类的问题上。

正则化(Regularization)

过拟合的问题(The Problem of Overfitting)

到目前为止,你已经了解了一些不同的学习算法,线性回归和逻辑回归,在很多问题上它们很有效。然而当你真正用这些算法去解决某些机器学习的实际应用时,它们可能会出现一种问题,称作为 "过度拟合",这会使得学习结果非常糟糕。我接下来要做的是对你解释 什么是 "过度拟合" 问题,并在接下来几节课中,我们将讨论一种技术叫做 正则化,它将允许我们改善或者减少 "过度拟合" 问题,并让这些学习算法更加有效的运行。

所以,什么是 "过度拟合" 呢?让我们继续用预测房子价格的例子,来自之前线性回归的介绍,去预测价格作为房子大小的功能。其中一种方法我们可以做的是,运用线性代数在这个数据上,如果我们这样做,我们可能会得到像这样一条直线来拟合这些数据。但是这并不是一个非常好的模型,仔细看这些数据,似乎非常清楚,当房子的面子增加的时候,房子的价格趋于 "高原态",或者趋于铺平,当我们向右移动后,所以这个算法不适合这次训练。我们称这样的问题为 "欠拟合"。另外一个原因是,这个算法有很高的偏差。上述两者 都意味着,这个算法并没有很好的拟合训练数据。偏差的存在,可能是历史或者技术上的原因,但有个想法是,如果用一直线来拟合数据,那么如果该算法含有很强的猜想,或者很强的偏见,那么房价会因它们的大小线性变动。尽管数据显示恰恰相反,尽管事实表明,相反地是,猜想仍然是偏见,仍然进一步阻碍了直线的拟合,这导致了对数据的拟合较差。现在,我们可以折衷地用二次函数来拟合,然后通过该数据集,我们拟合了二次函数,我们可能得到类似的曲线,它也拟合得很好。如果我们想要拟合得更好的话,可以给数据添加一个四次项,那么我们就有了五个参数 \(\theta_0\)\(\theta_4\)。通过这样的方式,我们实际上可以丰满一条曲线,使其贯穿全部五个训练样本,你应该会得到这样一条曲线,一方面看来,似乎对训练集拟合得非常好。而且,至少它经过了所有的数据,但是,这曲线依然很扭曲,对吧?它在那里上下起伏,我们实际上也不认为它是预测房价的好模型。那么,这个问题我们称之为过拟合。另一方面是,该算法方差较高,高方差是关于诸如历史或者技艺另外的原因了。但是直觉告诉我们,如果我们用这么高次幂的多项式来拟合,当然是可以拟合出假设函数来的,它基本上以可以拟合所有函数但。可能的假设函数量太多,它很多变,我们没有足够的数据来约束它来获得好的假设,这称之为 "过拟合"。在中间我将要写的这个,没有正式的名字,刚好吧,那是一个二次多项式,二次函数对于这数据来说似乎刚刚好,概括来说就是,过拟合的问题出现在存在过多的的变量的时侯。假设函数会对训练集拟合得很好,这样你的代价函数,会很接近零甚至就是零。但你最终只会得到那样一条曲线,你花费太多心思去迎合训练集,导致它不能推广到新的样本,也不能对新的案例进行价格预测。其中,这里的 "推广" 解释为假设函数对新案例的适用程度,这一点在房子数据的训练集上是体现不出来的。在这一页我们关注到了线性回归的过拟合,有相似的一点也能适用到逻辑回归上。这里是一个逻辑回归的例子,它有 \(x_1\)\(x_2\) 两个变量。我们可以做的是拟合逻辑回归,仅仅用这样一个简单的假设,我一般都用 G 代表 S 型函数,这样做之后得到一个假设函数,可能你想拿去用它就是一条分割在正轴和负轴上样本的直线,这似乎不是拟合得较好的假设。那么,我们再来一次,这是一个欠拟合的 \(y\) 例子,可能假设存在偏见。相反地,如果你向你的变量增加些二次项,那么,你会得到一个决策边界,就像这样的,你能看得出来它对数据拟合得很好,可能在训练集上我们已经做到极致了。最后讨论另一个极端,假如你要拟合一个很高阶的多项式,就是如果你想要加入许多高次项,逻辑回归会产生扭曲,它会很努力去寻找匹配训练集的决策边界,或者说把自己扭曲得长长的去把每一个训练样本拟合得严丝合缝。如果变量 \(x_1\) 和变量 \(x_2\) 作为预测依据,分别是恶性肿瘤和良性乳瘤,这看起来真的不是应用于预测的好假设函数。同样地再看这个,这是过拟合的一个实例,这个假设函数有较高的方差,并不能很好地适用于新的样本。稍后,这节课中当我们谈论关于学习算法出错时的调试和诊断,我们会提供对应的工具去识别,当过拟合和欠拟合发生的时候。现在让我们讨论当过拟合这问题发生的情况,我们该如何解决它?在之前的例子中,我们有一到两个维度的数据,我们才可以画出假设函数来观察其发生过程,并且选择合适幂次的多项式,所以早先对于房价的例子,我们可以画出该假设,可以看到它在拟合某种非常扭曲的预测房价函数,它经过了所有点。我们可以使用这样的图像来挑选合适幂次的多项式,把假设函数画出来是决定使用哪种幂次多项式的一种方式,但是这并不是总是有用的。实际上我们更多地在变量很多的时候遇到了训练的问题,也不仅仅是选择多少次幂的多项式的问题。实际上,当我们有过多的变量时,就变得越来越难在图上标出,数据也变得更难地使它可视化,从而决定保留哪些变量。具体来说,如果我们试图预测房价可能存在大量的变量,全部的变量当中都可能有点用。但是如果存在很多变量,又非常少量的训练集,那么过拟合这问题就会出现了。为了解决过拟合 的问题,我们主要有两种解决途径。第一种是,尝试减少变量的数量。具体地说,我们可以人为观察变量集,继而决定哪些变量更重要,我们因此可以知道哪些变量应该保留,哪些变量应该被剔除。这节课的稍后部分,也会讨论模型选择算法,这算法它可以自动决定要保留的变量和要剔除的变量。这种减少变量数量的思路是行得通的,可以减轻过拟合的问题。当我们谈及模型选择,我们会作更有深度的探讨,但是,其缺点是,剔除掉一部分变量时,同时也除掉了一部分关于主题的信息。举个例子,可能所有变量实际上都是对,预测房价有用的,那么我们当然不想除掉这部分信息和变量。第二种做法,我们会在下几节课中讲到,就是正则化。这种方法中,我们将会保留所用的变量,但我们会减少参数 \(\theta\) 的大小值,我们将会看到这种方法效果很好。当存在大量的变量时,每一个变量都为预测 \(y\) 的值做出了一点贡献。就像我们在预测房价的例子中看到的那样,当存在大量的变量时,其中的每一个变量多少都是有点用的,我们舍不得把他们扔掉。就这样,以上概括了正则化的思路,我也知道你们可能还没有明白其中的所有细节,但是在下节课当中,我们会开始精确地阐述,如何去应用正则化和正则化的含义。接着我们会开始指出如何使用它,使学习算法的效果更好并且避免过拟合的问题。

代价函数(Cost Function)

在本节课中,我将传达给你一个直观的感受,告诉你正规化是如何进行的,而且我们还要写出,我们使用正规化时需要使用的代价函数。

根据我们幻灯片上的这些例子,我想我可以给你一个直观的感受,但是一个更好的让你自己去理解正规化如何工作的方法是,你自己亲自去实现它,并且看看它是如何工作的。如果在这节课后,你进行一些适当的练习,你就有机会亲自体验一下正规化到底是怎么工作的,那么这里就是一些直观解释。在前面的课程中,我们看到了,如果说我们要用一个二次函数来拟合这些数据,它给了我们一个对数据很好的拟合。然而,如果我们用一个更高次的多项式去拟合,我们最终可能得到一个曲线,能非常好地拟合训练集,但是这真的不是一个好的结果,它过度拟合了数据,因此,一般性并不是很好。让我们考虑下面的假设,我们想要加上惩罚项,从而使参数 \(\theta_3\)\(\theta_4\) 足够的小。这里我的意思就是,这是我们的优化目标,或者客观的说,这就是我们需要优化的问题,我们需要尽量减少代价函数的均方误差,对于这个函数,我们对它进行一些添加一些项,加上 \(1000 * {\theta_3}^2+1000*{\theta_4}^2\),1000 只是我随便写的某个较大的数字而已。现在,如果我们要最小化这个函数,为了使这个新的代价函数最小化,我们要让 \(\theta_3\)\(\theta_4\) 尽可能小,对吧?因为,如果你有 \(1000 * \theta_3\),这个新的代价函数将会是很大的。所以,当我们最小化这个新的函数时,我们将使 \(\theta_3\) 的值接近于 0,\(\theta_4\) 的值也接近于 0,就像我们忽略了这两个值一样。如果我们做到这一点,如果 \(\theta_3\)\(\theta_4\) 接近 0,那么我们将得到一个近似的二次函数,所以,我们最终恰当地拟合了数据。你知道,二次函数加上一些项,这些很小的项,贡献很小,因为 \(\theta_3\) \(\theta_4\) 它们是非常接近于 0 的。所以我们最终得到了,实际上很好的一个二次函数,因为这是一个更好的假设。在这个具体的例子中,我们看到了惩罚这两个大的参数值的效果。更一般地,这里给出了正规化背后的思路,这种思路就是,如果我们的参数值对应一个较小值的话,就是说参数值比较小,那么往往我们会得到一个 形式更简单的假设。所以,我们最后一个例子中,我们惩罚的只是 \(\theta_3\)\(\theta_4\),使这两个值均接近于零,我们得到了一个更简单的假设,也即这个假设大抵上是一个二次函数。但更一般地说,如果我们就像这样惩罚的其它参数,通常我们可以把它们都想成是得到一个更简单的假设。因为你知道,当这些参数越接近这个例子时,假设的结果越接近一个二次函数。但更一般地,可以表明这些参数的值越小,通常对应于越光滑的函数,也就是更加简单的函数,因此,就不易发生过拟合的问题。我知道为什么要所有的部分参数变小的这些原因,为什么越小的参数对应于一个简单的假设,我知道这些原因对你来说现在不一定完全理解,但现在解释起来确实比较困难,除非你自己实现一下,自己亲自运行了这部分。但是我希望这个例子中,使 \(\theta_3\)\(\theta_4\) 很小,并且这样做 能给我们一个更加简单的假设。我希望这个例子有助于解释原因,至少给了我们一些直观感受,为什么这应该是这样的,来让我们看看具体的例子。对于房屋价格预测我们可能有上百种特征,我们谈到了一些可能的特征,比如说 \(x_1\) 是房屋的尺寸,\(x_2\) 是卧室的数目,\(x_3\) 是房屋的层数等等,那么我们可能就有一百个特征。跟前面的多项式例子不同,我们是不知道的,对吧?我们不知道 \(\theta_3\)\(\theta_4\) 是高阶多项式的项,所以如果我们有一个袋子,如果我们有一百个特征,在这个袋子里,我们是很难提前选出那些关联度更小的特征的。也就是说如果我们有一百或一百零一个参数,我们不知道挑选哪一个,我们并不知道如何选择参数,如何缩小参数的数目。因此在正规化里,我们要做的事情就是把我们的代价函数,这里就是线性回归的代价函数,接下来我度量来修改这个代价函数,从而缩小我所有的参数值,因为你知道,我不知道是哪个,哪一个或两个要去缩小,所以我就修改我的代价函数,在这后面添加一项,就像我们在方括号里的这项。当我添加一个额外的正则化项的时候,我们收缩了每个参数,并且因此,我们会使我们所有的参数 \(\theta_1\)\(\theta_2\)\(\theta_3\) 直到 \(\theta_100\) 的值变小。顺便说一下,按照惯例来讲,我们从第一个这里开始,所以我实际上没有去惩罚 \(\theta_0\),因此 \(\theta_0\) 的值是大的,这就是一个约定,从 1 到 \(n\) 的求和,而不是从 0 到 \(n\) 的求和。但其实在实践中,这只会有非常小的差异,无论你是否包括这项,就是 \(\theta_0\) 这项。实际上,结果只有非常小的差异,但是按照惯例,通常情况下我们还是只从 \(\theta_1\)\(\theta_{100}\) 进行正规化。这里我们写下来,我们的正规化优化目标,我们的正规化后的代价函数,就是这样的 \(J(\theta)\) 这个项,右边的这项就是一个正则化项,并且 \(\lambda\) 在这里我们称做正规化参数。\(\lambda\) 要做的就是控制在两个不同的目标中的一个平衡关系。第一个目标,第一个需要抓住的目标,就是我们想要训练使假设更好地拟合训练数据,我们希望假设能够很好的适应训练集。而第二个目标,是我们想要保持参数值较小,这就是第二项的目标,通过正则化目标函数,这就是 \(\lambda\) 这个正则化参数需要控制的,它会这两者之间的平衡,目标就是平衡拟合训练的目的和保持参数值较小的目的,从而来保持假设的形式相对简单,来避免过度的拟合。对于我们的房屋价格预测来说,这个例子,尽管之前我们已经用非常高的高阶多项式来拟合,我们将会得到一个非常弯曲和复杂的曲线函数,就像这个,如果你还是用高阶多项式拟合,就是用这里所有的多项式特征来拟合的话。但现在我们不这样了,你只需要确保使用了正规化目标的方法,那么你就可以得到实际上是一个曲线,但这个曲线不是一个真正的二次函数,而是更加的流畅和简单,也许就像这条紫红色的曲线一样。那么,你知道的,这样就得到了对于这个数据更好的假设。再一次说明下,我了解这部分有点难以明白,为什么加上参数的影响可以具有这种效果,但如果你亲自实现了正规化,你将能够看到这种影响的最直观的感受。

在正规化线性回归中,如果正规化参数值被设定为非常大,那么将会发生什么呢?我们将会非常大地惩罚参数 \(\theta_1\)\(\theta_2\)\(\theta_3\)\(\theta_4\)。也就是说,如果我们的假设是底下的这个,如果我们最终惩罚 \(\theta_1\)\(\theta_2\)\(\theta_3\)\(\theta_4\) 在一个非常大的程度,那么我们会使所有这些参数接近于 0 的,对不对?\(\theta_1\) 将接近 0,\(\theta_2\) 将接近 0,\(\theta_3\)\(\theta_4\) 最终也会接近于 0。如果我们这么做,那么就是我们的假设中,相当于去掉了这些项,并且使我们只是留下了一个简单的假设,这个假设只能表明,那就是房屋价格就等于 \(\theta_0\) 的值,那就是类似于拟合了一条水平直线。对于数据来说,这就是一个欠拟合(underfitting),这种情况下,这一假设它是条失败的直线,对于训练集来说,这只是一条平滑直线,它没有任何趋势,它不会去趋向大部分训练样本的任何值。这句话的另​​一种方式来表达就是,这种假设有过于强烈的 "偏见" 或者过高的偏差(bais),认为预测的价格只是等于 \(\theta_0\)。并且,尽管我们的数据集选择去拟合一条扁平的直线,仅仅是一条扁平的水平线,我画得不好,对于数据来说,这只是一条水平线。因此,为了使正则化运作良好,我们应当注意一些方面,应该去选择一个不错的正则化参数 \(\lambda\),并且当我们以后讲到多重选择时,在后面的课程中,我们将讨论一种方法,一系列的方法来自动选择正则化参数 \(\lambda\)。所以,这就是高度正则化的思路,回顾一下代价函数,为了使用正则化,在接下来的两节课中,让我们把这些概念应用到线性回归和逻辑回归中去,那么我们就可以让他们避免过度拟合了。

正则化线性回归(Regularized Linear Regression)

对于线性回归的求解,我们之前推导了两种学习算法,一种基于梯度下降,一种基于正规方程。在本节课中,我们将继续学习这两个算法,并把它们推广到正则化线性回归中去。

这是我们上节课推导出的正则化线性回归的优化目标,前面的第一部分是,一般线性回归的目标函数,而现在我们有这个额外的正则化项,其中 \(\lambda\) 是正则化参数。我们想找到参数 \(\theta\),能最小化代价函数,即这个正则化代价函​​数 \(J(\theta)\)。之前,我们使用梯度下降求解原来没有正则项的代价函数,我们用下面的算法求解常规的没有正则项的线性回归,我们会如此反复更新参数 \(\theta_j\),其中 \(j=0, 1, 2...n\)。让我照这个把 \(j=0\),即 \(\theta_0\) 的情况单独写出来,我只是把 \(\theta_0\) 的更新分离出来,剩下的这些参数 \(\theta_1\), \(\theta_2\)\(\theta_n\) 的更新作为另一部分。所以,这样做其实没有什么变化,对吧?这只是把 \(\theta_0\) 的更新和 \(\theta_1\)\(\theta_2\)\(\theta_n\) 的更新分离开来。我这样做的原因是,你可能还记得,对于正则化的线性回归,我们惩罚参数 \(\theta_1\)\(\theta_2\) 一直到 \(\theta_n\),但是我们不惩罚 \(\theta_0\)。所以,当我们修改这个正则化线性回归的算法时,我们将对 \(\theta_0\) 的方式将有所不同。具体地说,如果我们要对这个算法进行修改,并用它求解正则化的目标函数,我们需要做的是,把下边的这一项做如下的修改。我们要在这一项上添加一项:\(\frac{\lambda}{m} * \theta_j\),如果这样做的话,那么你就有了用于最小化正则化代价函数 \(J(\theta)\) 的梯度下降算法。我不打算用微积分来证明这一点,但如果你看这一项,方括号里的这一项,如果你知道微积分,应该不难证明它是 \(J(\theta)\)\(\theta_j\) 的偏导数,这里的 \(J(\theta)\) 是用的新定义的形式,它的定义中包含正则化项。而另一项上面的这一项,我用青色的方框圈出来的这一项,这也一个是偏导数,是 \(J(\theta)\)\(\theta_0\) 的偏导数。如果你仔细看 \(\theta_j\) 的更新,你会发现一些有趣的东西。具体来说 \(\theta_j\) 的每次更新都是 \(\theta_j\) 自己减去 \(\alpha\) 乘以原来的无正则项。然后还有这另外的一项,这一项的大小也取决于 \(\theta_j\),所以如果你把所有这些取决于 \(\theta_j\) 的合在一起的话,可以证明这个更新可以等价地写为如下的形式。具体来讲,上面的 \(\theta_j\) 对应下面的 \(\theta_j\) 乘以括号里的 1,而这一项是 \(\lambda\) 除以 \(m\) 还有一个 \(\alpha\),把它们合在一起,所以你最终得到 \(\alpha\) 乘以 \(\lambda\) 再除以 \(m\),然后合在一起乘以 \(\theta_j\),而这一项 1 减去 \(\alpha\) 乘以 \(\lambda\) 除以 \(m\),这一项很有意思,具体来说,这一项 1 减去 \(\alpha\) 乘以 \(\lambda\) 除以 \(m\) 这一项的值,通常是一个具体的实数,而且小于 1,对吧?由于 \(\alpha\) 乘以 \(\lambda\) 除以 \(m\) 通常情况下是正的,如果你的学习速率小,而 \(m\) 很大的话,\((1-\frac{\alpha\lambda}{m})\) 这一项通常是很小的,所以这里的一项,一般来说将是一个比 1 小一点点的值,所以我们可以把它想成一个像 0.99 一样的数字。所以,对 \(\theta_j\) 更新的结果,我们可以看作是被替换为 \(\theta_j\) 的 0.99 倍,也就是 \(\theta_j\) 乘以 0.99,把 \(\theta_j\) 向 0 压缩了一点点,所以这使得 \(\theta_j\) 小了一点。更正式地说,\(\theta_j\) 的平方范数更小了。另外,这一项后边的第二项,这实际上与我们原来的梯度下降更新完全一样,跟我们加入了正则项之前一样。好的,现在你应该对这个梯度下降的更新没有疑问了。当我们使用正则化线性回归时,我们需要做的就是在每一个被正规化的参数 \(\theta_j\) 上乘以了一个比 1 小一点点的数字,也就是把参数压缩了一点,然后我们执行跟以前一样的更新当然。这仅仅是从直观上认识,这个更新在做什么,从数学上讲,它就是带有正则化项的 \(J(\theta)\) 的梯度下降算法。我们在之前的幻灯片给出了定义,梯度下降只是我们拟合线性回归模型的两种算法的其中一个,第二种算法是使用正规方程,我们的做法是建立这个设计矩阵 X,其中每一行对应于一个单独的训练样本,然后创建了一个向量 \(y\) 向量,\(y\) 是一个 \(m\) 维的向量,包含了所有训练集里的标签,所以 X 是一个 \(m \times (n+1)\) 维矩阵,\(y\) 是一个\(m\)维向量。为了最小化代价函数 \(J\),我们发现一个办法就是 \(\theta\) 等于这个式子,即 X 的转置乘以 X 再对结果取逆再乘以 X 的转置乘以 Y,我在这里留点空间,等下再填满。这个 \(\theta\) 的值其实就是最小化代价函数 \(J(\theta)\)\(\theta\) 值,这时的代价函数 \(J(\theta)\) 没有正则项。现在如果我们用了是正则化,我们想要得到最小值,我们来看看应该怎么得到。推导的方法是,取 \(J\) 关于各个参数的偏导数,并令它们等于 0,然后做些数学推导你可以得到这样的一个式子,它使得代价函数最小。具体的说,如果你使用正则化,那么公式要做如下改变,括号里结尾添这样一个矩阵 0 1 1 1 等等,直到最后一行。所以这个东西在这里是一个矩阵,它的左上角的元素是 0,其余对角线元素都是 1,剩下的元素也都是 0,我画的比较随意。可以举一个例子,如果 \(n\) 等于 2,那么这个矩阵将是一个 \(3 \times 3\) 矩阵。更一般地情况,该矩阵是一个 \((n+1) \times (n+1)\) 维的矩阵,因此 \(n\) 等于 2 时,矩阵看起来会像这样,左上角是 0,然后其他对角线上是 1,其余部分都是 0。同样地,我不打算对这些作数学推导,坦白说这有点费时耗力,但可以证明,如果你采用新定义的 \(J(\theta)\),包含正则项的目标函数,那么这个计算 \(\theta\) 的式子能使你的 \(J(\theta)\) 达到全局最小值。所以最后,我想快速地谈一下不可逆性的问题,这部分是比较高阶的内容,所以这一部分还是作为选学,你可以跳过去,或者你也可以听听,如果听不懂的话,也没有关系。之前当我讲正规方程的时候,我们也有一段选学课程,讲不可逆的问题,所以这是另一个选学内容,可以作为上次课程的补充。现在考虑 \(m\) 即样本总数小于或等于特征数量 \(n\),如果你的样本数量比特征数量小的话,那么这个矩阵 X 转置乘以 X 将是不可逆或奇异的(singluar),或者用另一种说法是这个矩阵是退化(degenerate)的。如果你在 Octave 里运行它,无论如何你用函数 pinv 取伪逆矩阵,这样计算理论上方法是正确的,但实际上,你不会得到一个很好的假设,尽管 Ocatve 会用 pinv 函数给你一个数值解,看起来还不错。但是,如果你是在一个不同的编程语言中,如果在 Octave 中你用 inv 来取常规逆,也就是我们要对 X 转置乘以 X 取常规逆,然后在这样的情况下,你会发现 X 转置乘以 X 是奇异的,是不可逆的,即使你在不同的编程语言里计算,并使用一些线性代数库,试图计算这个矩阵的逆矩阵,都是不可行的,因为这个矩阵是不可逆的或奇异的。幸运的是,正规化也为我们解决了这个问题。具体地说,只要正则参数是严格大于 0 的,实际上,可以证明该矩阵 X 转置 乘以 X 加上 \(\lambda\) 乘以这里这个矩阵,可以证明这个矩阵将不是奇异的,即该矩阵将是可逆的。因此,使用正则化还可以照顾一些 X 转置乘以 X 不可逆的问题。好的,你现在知道了如何实现正则化线性回归,利用它你就可以避免过度拟合,即使你在一个相对较小的训练集里有很多特征,这应该可以让你在很多问题上更好地运用线性回归。在接下来的课程中,我们将把这种正则化的想法应用到逻辑回归,这样你就可以让逻辑回归也避免过度拟合,并让它表现的更好。

正则化的逻辑回归模型(Regularized Logistic Regression)

针对逻辑回归问题,我们在之前的课程已经学习过两种优化算法。我们首先学习了使用梯度下降法来优化代价函数 \(J(\theta)\),接下来学习了正则化技术。这些高级优化算法需要你自己设计代价函数 \(J(\theta)\),自己计算导数。在本节课中,我们将展示如何改进梯度下降法和高级优化算法,使其能够应用于正则化的逻辑回归,接下来我们来学习其中的原理。

在之前的课程中我们注意到,对于逻辑回归问题,有可能会出现过拟合的现象,如果你使用了类似这样的高阶多项式 g 是 S 型函数。具体来说,最后你会得到这样的结果,分类边界看起来是一个过于复杂并且十分扭曲的函数。针对这个训练点集,这显然不是一个好的结果。通常情况下,如果要解决的逻辑回归问题有很多参数,并且又用了过多的多项式项,这些项大部分都是没有必要的,最终都可能出现过拟合的现象。这是逻辑回归问题的代价函数,为了将其修改为正则化形式,我们只需要在后面增加一项,加上 \(\frac{\lambda}{2m}\),再跟过去一样,这个求和将 \(j\) 从 1 开始,而不是从 0 开始,累积 \(\theta_j\) 的平方,增加的这一项,将惩罚参数 \(\theta_1\), \(\theta_2\) 等等,一直到 \(\theta_n\)。防止这些参数取值过大,增加了这一项之后产生的效果是,即使用有很多参数的 高阶多项式来拟合,只要使用了正则化方法约束这些参数使其取值很小,你仍有可能得到一条看起来是这样的分类边界。显然,这条边界更合理地分开了正样本和负样本。因此,在使用了正则化方法以后即使你的问题有很多参数,正则化方法可以帮你避免过拟合的现象。

这到底是怎样实现的呢?首先看看以前学过的梯度下降法,这是我们之前得到的更新式,我们利用这个式子迭代更新 \(\theta_j\)。这一页幻灯片看起来和上一节课的线性回归问题很像,但是这里我将 \(\theta_0\) 的更新公式单独写出来,第一行用来更新 \(\theta_0\),第二行用来更新 \(\theta_1\)\(\theta_n\),将 \(\theta_0\) 单独处理。为了按照正则化代价函数的形式来修改算法,接下来的推导非常类似于上一节学习过的正则化线性回归,只需要将第二个式子修改成这样。我们又一次发现,修改后的式子表面上看起来与上一节的线性回归问题很相似,但是实质上这与我们上节学过的算法并不一样,因为现在的假设 \(h(x)\) 是按照这个式子定义的,这与上一节正则化线性回归算法中的定义并不一样。由于假设的不同,我写下的迭代公式,只是表面上看起来很像上一节学过的 正则化线性回归问题中的梯度下降算法。

总结一下,方括号中的这一项是新的代价函数 \(J(\theta)\) 关于 \(\theta_j\) 的偏导数,这里的 \(J(\theta)\) 是我们在上一页幻灯片中定义的使用了正则化的代价函数,以上就是正则化逻辑回归问题的梯度下降算法。

接下来我们讨论如何在更高级的优化算法中使用同样的正则化技术,提醒一下,对于这些高级算法,我们需要自己定义 costFuntion 函数,这个函数有一个输入参数向量 \(\theta\)\(\theta\) 的内容是这样的,我们的参数索引依然从 0 开始,即 \(\theta_0\)\(\theta_n\),但是由于 Octave 中,向量索引是从 1 开始,我们的参数是从 \(\theta_0\)\(\theta_n\),在 Octave 里,是从 \(\theta_1\) 开始标号的,而 \(\theta_1\) 将被记为 \(\theta_2\),以此类推,直到 \(\theta_n\) 被记为 \(\theta_{n+1}\)。而我们需要做的,就是将这个自定义代价函数 costFunction 代入到我们之前学过的 fminunc 函数中,括号里面是 @costFunction,将 @costFunction 作为参数代进去等等。fminunc 返回的是函数 costFunction 在无约束条件下的最小值。因此,这个式子将求得代价函数的最小值。因此 costFunction 函数 有两个返回值,第一个是 jVal,为此,我们要在这里补充代码来计算代价函数 \(J(\theta)\)。由于我们在这使用的是正则化逻辑回归,因此代价函数 \(J(\theta)\) 也相应需要改变。具体来说代价函数需要增加这一正则化项,因此,当你在计算 \(J(\theta)\) 时,需要确保包含了最后这一项。另外,代价函数的另一项返回值是对应的梯度导数,梯度的第一个元素 \({gradient}_1\) 就等于 \(J(\theta)\) 关于 \(\theta_0\) 的偏导数,梯度的第二个元素按照这个式子计算,剩余元素以此类推。再次强调,向量元素索引是从 1 开始,这是因为 Octave 的向量索引就是从 1 开始的。

再来总结一下,首先看第一个公式,在之前的课程中,我们已经计算过它等于这个式子,这个式子没有变化,因为相比没有正则化的版本 \(J(\theta)\) 关于 \(\theta_0\) 的偏导数不会改变。但是其他的公式确实有变化,以 \(\theta_1\) 的偏导数为例,在之前的课程里我们也计算过这一项,它等于这个式子,减去 \(\lambda\) 除以 \(m\) (这里应为加 校对者注) 再乘以 \(\theta_1\),注意要确保这段代码编写正确,建议在这里添加括号,防止求和符号的作用域扩大。与此类似,再来看这个式子,相比于之前的幻灯片,这里多了额外的一项,这就是正则化后的梯度计算方法。当你自己定义了 costFunction 函数,并将其传递到 fminuc 或者其他类似的高级优化函数中,就可以求出这个新的正则化代价函数的极小值,而返回的参数值,即是对应的逻辑回归问题的正则化解好的。现在你知道了解决正则化逻辑回归问题的方法,你知道吗?我住在硅谷,当我在硅谷晃悠时,我看到许多工程师运用机器学习算法给他们公司挣来了很多金子,课讲到这里,大家对机器学习算法可能还只是略懂,但是一旦你精通了线性回归、高级优化算法和正则化技术,坦率地说,你对机器学习的理解,可能已经比许多工程师深入了。现在,你已经有了丰富的机器学习知识,目测比那些硅谷工程师还厉害,而那些工程师都混得还不错,给他们公司挣了大钱。你懂的,或者用机器学习算法来做产品,所以,恭喜你你已经历练得差不多了,已经具备足够的知识,足够将这些算法用于解决实际问题,所以你可以小小的骄傲一下了。但是,我还是有很多可以教你们的,接下来的课程中,我们将学习一个非常强大的非线性分类器,无论是线性回归问题,还是逻辑回归问题,都可以构造多项式来解决。但是,你将逐渐发现还有更强大的非线性分类器,可以用来解决多项式回归问题。在下一节课,我将向大家介绍它们,你将学会比你现在解决问题的方法强大 N 倍的学习算法。

神经网络:表述(Neural Networks: Representation)

非线性假设(Non-linear Hypotheses)

在这节课和接下来的课程中,我将给大家介绍一种叫 "神经网络"(Neural Network)的机器学习算法,我们将首先讨论神经网络的表层结构,在后续课程中再来具体讨论的学习算法。

神经网络实际上是一个相对古老的算法,并且后来沉寂了一段时间,不过到了现在,它又成为许多机器学习问题的首选技术,不过我们为什么还需要这个学习算法?我们已经有线性回归和逻辑回归算法了,为什么还要研究神经网络?

为了阐述研究神经网络算法的目的,我们首先来看几个机器学习问题,作为例子,这几个问题的解决都依赖于研究复杂的非线性分类器。考虑这个监督学习分类的问题,我们已经有了对应的训练集,如果利用逻辑回归算法来解决这个问题,首先需要构造,一个包含很多非线性项的逻辑回归函数,这里 g 仍是 s 型函数(即 \(f(x)=\frac{1}{1+e^{-x}}\),我们能让函数,包含很多像这样的多项式项。事实上,当多项式项数足够多时,那么可能你能够得到一个分开正样本和负样本的分界线。当只有两项时,比如 \(x_1\)\(x_2\),这种方法确实能得到不错的结果。因为你可以把 \(x_1\)\(x_2\) 的所有组合都包含到多项式中。但是对于许多复杂的机器学习问题,涉及的项往往多于两项。我们之前已经讨论过房价预测的问题,假设现在要处理的是关于住房的分类问题,而不是一个回归问题,假设你对一栋房子的多方面特点都有所了解,你想预测房子在未来半年内能被卖出去的概率,这是一个分类问题我们可以想出很多特征,对于不同的房子有可能就有上百个特征。对于这类问题,如果要包含所有的二次项,即使只包含二项式或多项式的计算,最终的多项式也可能有很多项。比如 \(x_1^2, x_1x_2, x_1x_3, x_1x_4,...x_1x_{100}\),还有 \(x_2^2\)\(x_2x_3\) 等等很多项。因此,即使只考虑二阶项,也就是说两个项的乘积 \(x_1\) 乘以 \(x_1\) 等等,类似于此的项,那么,在 \(n=100\) 的情况下最终也有 5000 个二次项,而且渐渐地,随着特征个数 \(n\) 的增加,二次项的个数大约以 \(n^2\) 的量级增长,其中 \(n\) 是原始项的个数,即我们之前说过的 \(x_1\)\(x_{100}\) 这些项。事实上,二次项的个数大约是 \((n^2)/2\),因此要包含所有的二次项是很困难的。所以这可能不是一个好的做法,而且由于项数过多,最后的结果很有可能是过拟合的。此外,在处理这么多项时也存在运算量过大的问题。当然,你也可以试试只包含上边这些二次项的子集,例如,我们只考虑 \(x_1^2, x_2^2, x_3^2,..., x_{100}^2\) 这些项,这样就可以将二次项的数量大幅度减少,减少到只有 100 个二次项,但是由于忽略了太多相关项,在处理类似左上角的数据时,不可能得到理想的结果。实际上,如果只考虑 \(x_1\) 的平方,到 \(x_{100}\) 的平方,这一百个二次项,那么你可能会拟合出一些特别的假设,比如可能拟合出一个椭圆状的曲线,但是肯定不能拟合出像左上角这个数据集的分界线。所以 5000 个二次项看起来已经很多了,而现在假设包括三次项或者三阶项,例如 \(x_1x_2x_3, x_1^2x_2, ... , x_{10}x_{11}x_{17}\) 等等,类似的三次项有很多很多。事实上,三次项的个数是以 \(n^3\) 的量级增加。当 \(n=100\) 时,可以计算出来,最后能得到大概 17000 个三次项。所以,当初始特征个数 \(n\) 增大时,这些高阶多项式项数,将以几何级数递增,特征空间也随之急剧膨胀。当特征个数 \(n\) 很大时,如果找出附加项来建立一些分类器,这并不是一个好做法。对于许多实际的机器学习问题,特征个数 \(n\) 是很大的。举个例子关于计算机视觉中的一个问题,假设你想要使用机器学习算法来训练一个分类器,使它检测一个图像来判断图像是否为一辆汽车。很多人可能会好奇,这对计算机视觉来说有什么难的,当我们自己看这幅图像时,里面有什么是一目了然的事情,你肯定会很奇怪,为什么学习算法竟可能会不知道图像是什么。为了解答这个疑问,我们取出这幅图片中的一小部分,将其放大,比如图中这个红色方框内的部分。结果表明,当人眼看到一辆汽车时,计算机实际上看到的却是这个,一个数据矩阵或像这种格网,它们表示了像素强度值,告诉我们图像中每个像素的亮度值。因此,对于计算机视觉来说,问题就变成了根据这个像素点亮度矩阵,来告诉我们这些数值代表一个汽车门把手。具体而言,当用机器学习算法构造一个汽车识别器时,我们要想出一个带标签的样本集,其中一些样本是各类汽车,另一部分样本是其他任何东西,将这个样本集输入给学习算法,以训练出一个分类器。训练完毕后,我们输入一幅新的图片让分类器判定 "这是什么东西"?理想情况下,分类器能识别出这是一辆汽车。为了理解引入非线性分类器的必要性,我们从学习算法的训练样本中挑出一些汽车图片和一些非汽车图片。让我们从其中每幅图片中挑出一组像素点,这是像素点 1 的位置,这是像素点 2 的位置,在坐标系中标出这幅汽车的位置。在某一点上,车的位置取决于像素点 1 和像素点 2 的亮度。让我们用同样的方法标出其他图片中汽车的位置,然后我们再举一个关于汽车的不同的例子,观察这两个相同的像素位置。这幅图片中像素 1 有一个像素强度,像素 2 也有一个不同的像素强度,所以在这幅图中它们两个处于不同的位置。我们继续画上两个非汽车样本,这个不是汽车,这个也不是汽车,然后我们继续在坐标系中画上更多的新样本,用 "+" 表示汽车图片,用 "-" 表示非汽车图片。我们将发现,汽车样本和非汽车样本,分布在坐标系中的不同区域。因此,我们现在需要一个非线性分类器来尽量分开这两类样本,这个分类问题中特征空间的维数是多少?假设我们用 50*50 像素的图片,我们的图片已经很小了,长宽只各有 50 个像素,但这依然是 2500 个像素点。因此,我们的特征向量的元素数量 \(n=2500\),特征向量 X 包含了所有像素点的亮度值,这是像素点 1 的亮度,这是像素点 2 的亮度,如此类推,直到最后一个像素点的亮度。对于典型的计算机图片表示方法,如果存储的是每个像素点的灰度值(色彩的强烈程度),那么每个元素的值应该在 0 到 255 之间,因此,这个问题中 \(n=2500\),但这只是使用灰度图片的情况,如果我们用的是 RGB 彩色图像,每个像素点包含红、绿、蓝三个子像素,那么 \(n=7500\)。因此,如果我们非要通过包含所有的二次项来解决这个非线性问题,那么,这就是式子中的所有条件 \(x_i*x_j\),连同开始的 2500 像素,总共大约有 300 万个,这数字大得有点离谱了。对于每个样本来说,要发现并表示所有这 300 万个项,这计算成本太高了。因此,只是简单的增加二次项或者三次项之类的逻辑回归算法,并不是一个解决复杂非线性问题的好办法。因为当 \(n\) 很大时,将会产生非常多的特征项。

在接下来的课程中,我将为大家讲解神经网络,它在解决复杂的非线性分类问题上,被证明是是一种好得多的算法,即使你输入特征空间或输入的特征维数 \(n\) 很大,也能轻松搞定。在后面的课程中,我将给大家展示一些有趣的视频,视频中讲述了神经网络在历史上的重要应用我也希望这些我们即将看到的视频,能给你的学习过程带来一些乐趣。

神经元和大脑(Neurons and the Brain)

神经网络是一种很古老的算法,它最初产生的目的是制造能模拟大脑的机器。在这门课中,我将向你们介绍神经网络,因为它能很好地解决不同的机器学习问题,而不只因为它们在逻辑上行得通。在本节课中,告诉你们一些神经网络的背景知识,由此我们能知道可以用它们来做什么,不管是将其应用到现代的机器学习问题上,还是应用到那些你可能会感兴趣的问题中。也许,这一伟大的人工智能梦想在未来能制造出真正的智能机器。另外,我们还将讲解神经网络是怎么涉及这些问题的。

神经网络产生的原因,是人们想尝试设计出模仿大脑的算法。从某种意义上说,如果我们想要建立学习系统,那为什么不去模仿我们所认识的最神奇的学习机器 ———— 人类的大脑呢?神经网络逐渐兴起于二十世纪八九十年代,应用得非常广泛,但由于各种原因,在 90 年代的后期应用减少了。但是,最近神经网络又东山再起了,其中一个原因是神经网络是计算量有些偏大的算法,然而,大概由于近些年计算机的运行速度变快,才足以真正运行起大规模的神经网络。正是由于这个原因,和其他一些我们后面会讨论到的技术因素,如今的神经网络对于许多应用来说是最先进的技术。

当你想模拟大脑时,是指想制造出与人类大脑作用效果相同的机器,对吧?大脑可以学会去以看而不是听的方式处理图像,学会处理我们的触觉,我们能学习数学,学着做微积分,而且大脑能处理各种不同的令人惊奇的事情。似乎如果你想要模仿它,你得写很多不同的软件,来模拟所有大脑告诉我们的这些五花八门的奇妙的事情。不过能不能假设大脑做所有这些不同事情的方法,不需要用上千个不同的程序去实现。相反的,大脑处理的方法只需要一个单一的学习算法就可以了?尽管这只是一个假设,不过让我和你分享一些这方面的证据。大脑的这一部分,这一小片红色区域是你的听觉皮层,你现在正在理解我的话,这靠的是耳朵,耳朵接收到声音信号,并把声音信号传递给你的听觉皮层,正因如此,你才能明白我的话。神经系统科学家做了下面这个有趣的实验,把耳朵到听觉皮层的神经切断,在这种情况下,将其重新接到一个动物的大脑上,这样从眼睛到视神经的信号最终将传到听觉皮层。如果这样做了,那么结果表明,听觉皮层将会学会 "看",这里 "看" 代表了我们所知道的每层含义。所以,如果你对动物这样做,那么动物就可以完成视觉辨别任务,它们可以看图像并根据图像做出适当的决定,它们正是通过脑组织中的这个部分完成的。

来看另一个例子,这块红色的脑组织是你的躯体感觉皮层,这是你用来处理触觉的。如果你做一个和刚才类似的重接实验,那么躯体感觉皮层也能学会 "看",这个实验和其它一些类似的实验被称为神经重接实验。从这个意义上说,如果人体有同一块脑组织可以处理光、 声或触觉信号,那么也许存在一种学习算法,可以同时处理视觉、听觉和触觉,而不是需要运行上千个不同的程序,或者上千个不同的算法,来做这些。大脑所完成的成千上万的美好事情,也许我们需要做的就是找出一些近似的或实际的大脑学习算法,然后实现它。大脑通过自学掌握如何处理这些不同类型的数据,在很大的程度上可以猜想,如果我们把几乎任何一种传感器接入到大脑的几乎任何一个部位的话,大脑就会学会处理它。

下面再举几个例子,左上角的这张图是用舌头学会 "看" 的一个例子,它的原理是,这实际上是一个名为 BrainPort 的系统,它现在正在 FDA(美国食品和药物管理局)的临床试验阶段,它能帮助失明人士看见事物。它的原理是,你在前额上带一个灰度摄像头,面朝前,它就能获取你面前事物的低分辨率的灰度图像,你连一根线到舌头上安装的电极阵列上,那么每个像素都被映射到你舌头的某个位置上,可能电压值高的点对应一个暗像素,电压值低的点对应于亮像素。即使依靠它现在的功能,使用这种系统就能让你我在几十分钟里就学会用我们的舌头 "看" 东西,这是第二个例子。

关于人体回声定位或者说人体声纳,你有两种方法可以实现,你可以弹响指或者咂舌头,这个我做不好。不过现在有失明人士确实在学校里接受这样的培训,并学会解读从环境反弹回来的声波模式,这就是声纳。如果你搜索 YouTube 之后,就会发现,有些视频讲述了一个令人称奇的孩子,他因为癌症眼球惨遭移除,虽然失去了眼球,但是通过打响指,他可以四处走动而不撞到任何东西,他能滑滑板,他可以将篮球投入篮框中,注意这是一个没有眼球的孩子。

第三个例子是触觉皮带,如果你把它戴在腰上,蜂鸣器会响,而且总是朝向北时发出嗡嗡声,它可以使人拥有方向感,用类似于鸟类感知方向的方式。还有一些离奇的例子,如果你在青蛙身上插入第三只眼,青蛙也能学会使用那只眼睛。因此,这将会非常令人惊奇,如果你能把几乎任何传感器接入到大脑中,大脑的学习算法就能找出学习数据的方法,并处理这些数据。从某种意义上来说,如果我们能找出大脑的学习算法,然后在计算机上执行,大脑学习算法或与之相似的算法,也许这将是我们向人工智能迈进做出的最好的尝试。人工智能的梦想就是有一天能制造出真正的智能机器,当然我不是教神经网络的,介绍它只因为它可能为我们打开一扇进入遥远的人工智能梦的窗户。对于我个人来说,它也是我研究生涯中致力于的一个项目,但我在这节课中,讲授神经网络的原因主要是对于现代机器学习应用,它是最有效的技术方法。

因此在接下来的一些课程中,我们将开始深入到神经网络的技术细节,那么你就可以将它们应用到现代机器学习的应用中,并利用它们很好地解决问题。但对我来说,使我兴奋的原因之一,就是它或许能给我们一些启示,让我们知道,当我们在思考未来有什么样的算法 能以与人类相似的方式学习时,我们能做些什么。

模型表示 1(Model Representation I)

在本节课中,我想开始向你介绍我们该如何表示神经网络,换句话说,当我们在运用神经网络时,我们该如何表示我们的假设或模型。

神经网络是在模仿大脑中的神经元或者神经网络时发明的。因此,要解释如何表示模型假设,我们先来看单个神经元在大脑中是什么样的。我们的大脑中充满了这样的神经元,神经元是大脑中的细胞。其中有两点值得我们注意,一是神经元有像这样的细胞主体,二是神经元有一定数量的输入神经。这些输入神经叫做树突,可以把它们想象成输入电线,它们接收来自其他神经元的信息。神经元的输出神经叫做轴突,这些输出神经是用来给其他神经元传递信号,或者传送信息的。简而言之,神经元是一个计算单元,它从输入神经接受一定数目的信息,并做一些计算然后将结果通过它的轴突传送到其他节点,或者大脑中的其他神经元。

下面是一组神经元的示意图,神经元利用微弱的电流进行沟通,这些弱电流也称作动作电位,其实就是一些微弱的电流。所以,如果神经元想要传递一个消息,它就会就通过它的轴突发送一段微弱电流给其他神经元,这就是轴突,这里是一条连接到输入神经,或者连接另一个神经元树突的神经。接下来这个神经元接收这条消息,做一些计算,它有可能会反过来将在轴突上的自己的消息传给其他神经元。这就是所有人类思考的模型:我们的神经元把自己的收到的消息进行计算,并向其他神经元传递消息。顺便说一下,这也是我们的感觉和肌肉运转的原理,如果你想活动一块肌肉,就会触发一个神经元给你的肌肉发送脉冲,并引起你的肌肉收缩。如果一些感官,比如说眼睛想要给大脑传递一个消息,那么它就像这样发送电脉冲给大脑的。

在一个神经网络里,或者说在我们在电脑上实现的人工神经网络里,我们将使用一个非常简单的模型来模拟神经元的工作,我们将神经元模拟成一个逻辑单元。当我画一个这样的黄色圆圈时,你应该把它想象成作用类似于神经元的东西,然后我们通过它的树突或者说它的输入神经传递给它一些信息,然后神经元做一些计算并通过它的输出神经,即它的轴突,输出计算结果。当我画一个像这样的图表时,就表示对 \(h(x)\) 的计算。\(h(x)=\frac{1}{1+e^{-{\theta}^Tx}}\),通常 \(x\)\(\theta\) 是我们的参数向量。这是一个简单的模型,甚至说是一个过于简单的模拟神经元的模型,它被输入 \(x_1\)\(x_2\)\(x3\),然后输出一些类似这样的结果。当我绘制一个神经网络时,通常我只绘制输入节点 \(x_1\)\(x_2\)\(x_3\),但有时也可以这样做:我增加一个额外的节点 \(x_0\),这个 \(x_0\) 节点有时也被称作偏置单位或偏置神经元,但因为 \(x_0\) 总是等于 1,所以有时候我会画出它,有时我不会画出,这取决于它是否对例子有利。

现在来讨论最后一个关于神经网络的术语,有时我们会说这是一个神经元,一个有 s 型函数或者逻辑函数作为激励函数的人工神经元。在神经网络术语中,激励函数只是对类似非线性函数 \(g(z)\) 的另一个术语称呼。\(g(z)=\frac{1}{1+e^{-z}}\)

到目前为止,我一直称 \(\theta\) 为模型的参数,以后大概会继续将这个术语与 "参数" 相对应。在关于神经网络的文献里,有时你可能会看到人们谈论一个模型的权重,权重其实和模型的参数是一样的东西,在本课程中我会继续使用 "参数" 这个术语,但有时你可能听到别人用 "权重" 这个术语。这个小圈代表一个单一的神经元,神经网络其实就是这些不同的神经元组合在一起的集合。具体来说,这里是我们的输入单元 \(x_1\)\(x_2\)\(x_3\)。再说一次,有时也可以画上额外的节点 \(x_0\),我把 \(x_0\) 画在这了,这里有 3 个神经元,我在里面写了 \(a^{(2)}_1\)\(a^{(2)}_2\)\(a^{(2)}_3\),然后再次说明,我们可以在这里添加一个 \(a_0\) 和一个额外的偏度单元它的值永远是 1。

最后,我们在最后一层有第三个节点,正是这第三个节点输出假设函数 \(h(x)\) 计算的结果。再多说一点关于神经网络的术语,网络中的第一层也被称为输入层,因为我们在这一层输入我们的特征项 \(x_1\)\(x_2\)\(x_3\)。最后一层,也称为输出层,因为这一层的神经元输出假设的最终计算结果。中间的两层也被称作隐藏层,隐藏层不是一个很合适的术语,但是,直觉上我们知道,在监督学习中,你能看到输入也能看到正确的输出,而隐藏层的值你在训练集里是看不到的,它的值不是 x 也不是 y,所以我们叫它隐藏层。稍后我们会看到神经网络可以有不止一个的隐藏层,但这个例子中,我们有一个输入层(第 1 层),一个隐藏层(第 2 层)和一个输出层(第 3 层),但实际上,任何非输入层或非输出层的层就被称为隐藏层。

接下来,我希望你们明白神经网络究竟在做什么,让我们逐步分析这个图表所呈现的计算步骤,为了解释这个神经网络具体的计算步骤,这里还有些记号要解释。

我要使用 a 上标 (j) 下标 i 表示第 j 层的第 i 个神经元或单元。具体来说,这里 a 上标 (2) 下标 1 表示第 2 层的第 1 个激活项,即隐藏层的第一个激活项。所谓激活项(activation)是指,由一个具体神经元读入计算并输出的值。此外,我们的神经网络被这些矩阵参数化 \(\theta\) 上标 (j),它将成为一个被矩阵控制着,从一层,比如说从第一层到第二层,或者第二层到第三层的作用。所以,这就是这张图所表示的计算,这里的第一个隐藏单元是这样计算它的值的:\(a^{(2)}_1\) 等于 s 函数,或者说 s 激励函数,也叫做逻辑激励函数作用在这种输入的线性组合上的结果,第二个隐藏单元等于 s 函数作用在这个线性组合上的值。同样,对于第三个隐藏的单元,它是通过这个公式计算的。在这里,我们有三个输入单元和三个隐藏单元,这样一来,参数矩阵控制了我们来自三个输入单元,三个隐藏单元的映射。因此 \(\theta_1\) 的维数将变成 3,\(\theta_1\) 将变成一个 \(3 \times 4\) 维的矩阵。更一般的,如果一个网络在第 \(j\) 层有 \(s_j\) 个单元,在 \(j+1\) 层有 \(s_{j+1}\) 个单元,那么矩阵 \(\theta(j)\) 即控制第 \(j\) 层到第 \(j+1\) 层映射的矩阵,维度为 \(s_{j+1} \times s_{j+1}\)。这里要搞清楚,这个是 s 下标 j+1,而这个是 s 下标 j,然后整体加上 1,整体加 1,明白了吗?所以 \(\theta(j)\) 的维度是 \(s_{j+1}\)\(s_{j+1}\) 列,这里 \(s_{j+1}\) 当中的 1 不是下标的一部分。

以上我们讨论了三个隐藏单位是怎么计算它们的值,最后在输出层,我们还有一个单元,它计算 \(h(x)\),这个也可以写成 \(a^{(3)}_1\),就等于后面这块。注意到我这里写了个上标 2,因为 \(\theta\) 上标 2 是参数矩阵,或着说是权重矩阵,该矩阵控制从第二层,即隐藏层的 3 个单位到第三层的一个单元,即输出单元的映射。总之,以上我们展示了像这样一张图是怎样定义一个人工神经网络的,这个神经网络定义了函数 \(h\):从输入 \(x\) 到输出 \(y\) 的映射,我将这些假设的参数,记为大写的 \(\theta\),这样一来,不同的 \(\theta\) 对应了不同的假设,所以我们有不同的函数,比如说从 \(x\)\(y\) 的映射,以上就是我们怎么从数学上定义神经网络的假设。

在接下来的课程中,我想要做的就是让你对这些假设的作用有更深入的理解,并且讲解几个例子,然后谈谈如何有效的计算它们。

模型表示 2(Model Representation II)

在前面的课程里,我们解释了怎样用数学来定义或者计算神经网络算法的假设,在这本节课中,我想告诉你如何高效地进行计算,并展示一个向量化的实现方法。更重要的是,我想让你们明白为什么这样表示神经网络是一个好的方法,并且明白它们怎样帮助我们学习复杂的非线性假设。

以这个神经网络为例,以前我们说计算出假设输出的步骤,是左边的这些方程,通过这些方程,我们计算出三个隐藏单元的激励值,然后利用这些值来计算假设 \(h(x)\) 的最终输出。接下来,我要定义一些额外的项,因此,这里我画线的项,把它定义为 \(z\) 上标 (2) 下标 1,这样一来,就有了 \(a^{(2)}_1=g(z^{(2)}_1)\)。另外顺便提一下,这些上标 2 的意思是 在 \(z^{(2)}\)\(a^{(2)}\) 中,括号中的 2 表示这些值与第二层相关,即与神经网络中的隐藏层有关。接下来,这里的项,我将同样定义为 \(z^{(2)}_2\)。最后这个,我画线的项,我把它定义为 \(z^{(2)}_3\)。这样,我们有 \(a^{(2)}_3=g(z^{(2)}_3)\),所以这些 \(z\) 值都是一个线性组合,是输入值 \(x_0\)\(x_1\)\(x_2\)\(x_3\) 的加权线性组合,它将会进入一个特定的神经元。现在,看一下这一堆数字,你可能会注意到这块对应了矩阵向量运算,类似于矩阵向量乘法 \(x_1\) 乘以向量 \(x\)。观察到一点,我们就能将神经网络的计算向量化了。具体而言,我们定义特征向量 \(x\)\(x_0\)\(x_1\)\(x_2\)\(x_3\) 组成的向量,其中 \(x_0\) 仍然等于 1。并定义 \(z^{(2)}\) 为这些 \(z\) 值组成的向量,即 \(z^{(2)}_1\)\(z^{(2)}_2\)\(z^{(2)}_3\)。注意,在这里 \(z^{(2)}\) 是一个三维向量。

下面,我们可以这样向量化 \(z^{(2)}_1\)\(z^{(2)}_2\)\(z^{(2)}_3\) 的计算,我们只用两个步骤 \(z^{(2)}=\theta^{(1)}x\),这样就有了向量 \(z^{(2)}\),然后 \(a^{(2)}=g(z^{(2)})\),需要明白,这里的 \(z^{(2)}\) 是三维向量,并且 \(a^{(2)}\) 也是一个三维向量。因此,这里的激励 g 将 s 函数逐元素作用于 \(z^{(2)}\) 中的每个元素。顺便说一下,为了让我们的符号和接下来的工作相一致,在输入层,虽然我们有输入 \(x\),但我们还可以把这些想成是第一层的激励,所以,我可以定义 \(a^{(1)}\) 等于\(x\),因此 \(a^{(1)}\) 就是一个向量了。我就可以把这里的 \(x\) 替换成 \(a^{(1)}\)\(z^{(2)}={\theta}^{(1)} a^{(1)}\),这都是通过在输入层定义 \(a^{(1)}\) 做到的。现在,就我目前所写的,我得到了 \(a_1\)\(a_2\)\(a_3\) 的值,并且,我应该把上标加上去,但我还需要一个值,我同样需要这个 \(a^{(2)}_0\),它对应于隐藏层的得到这个输出的偏置单元,当然,这里也有一个偏置单元,我只是没有画出来。为了注意这额外的偏置单元,接下来我们要额外加上一个 \(a_0^{(2)}=1\),这样一来,现在 \(a^{(2)}\) 就是一个四维的特征向量,因为我们刚添加了这个额外的 \(a_0\) 它等于 1,并且它是隐藏层的一个偏置单元。最后为了计算假设的实际输出值,我们只需要计算 \(z^{(3)}\)\(z^{(3)}\) 等于这里我画线的项,这个方框里的项就是 \(z^{(3)}\)\(z^{(3)}\) 等于 \(\theta^{(2)}\) 乘以 \(a^{(2)}\)。最后,假设输出为 \(h(x)\),它等于 \(a^{(3)}\)\(a^{(3)}\) 是输出层唯一的单元,它是一个实数,你可以写成 \(a^{(3)}\)\(a^{(3)}_1\)。这就是 \(g(z^{(3)})\) 这个计算 \(h(x)\) 的过程,也称为前向传播(forward propagation)。这样命名是因为我们从输入层的激励开始,然后进行前向传播给隐藏层并计算隐藏层的激励,然后我们继续前向传播,并计算输出层的激励。这个从输入层到隐藏层再到输出层依次计算激励的过程叫前向传播。我们刚刚得到了这一过程的向量化实现方法,如果你使用右边这些公式实现它,就会得到一个有效的计算 \(h(x)\) 的方法,这种前向传播的角度也可以帮助我们了解神经网络的原理,和它为什么能够帮助我们学习非线性假设。看一下这个神经网络,我会暂时盖住图片的左边部分,如果你观察图中剩下的部分,这看起来很像逻辑回归。在逻辑回归中,我们用这个节点,即这个逻辑回归单元来预测 \(h(x)\) 的值。具体来说,假设输出的 \(h(x)\) 将等于 s 型激励函数 \(g(\theta_0a_0 +\theta_1a_1+\theta_2a_2 +\theta_3a_3)\),其中 \(a_1\)\(a_2\)\(a_3\) 由这三个单元给出。为了和我之前的定义保持一致,需要在这里,还有这些地方都填上上标 (2),同样还要加上这些下标 1,因为我只有一个输出单元。但如果你只观察蓝色的部分,这看起来非常像标准的逻辑回归模型,不同之处在于,我现在用的是大写的 \(\theta\),而不是小写的 \(\theta\)。这样做完,我们只得到了逻辑回归,但是,逻辑回归的输入特征值是通过隐藏层计算的。再说一遍,神经网络所做的就像逻辑回归,但是它不是使用 \(x_1\)\(x_2\)\(x_3\) 作为输入特征,而是用 \(a_1\)\(a_2\)\(a_3\) 作为新的输入特征。同样,我们需要把上标加上来和之前的记号保持一致。有趣的是,特征项 \(a_1\)\(a_2\)\(a_3\),它们是作为输入的函数来学习的。具体来说,就是从第一层映射到第二层的函数,这个函数由其他一组参数 \(\theta^{(1)}\) 决定,所以在神经网络中,它没有用输入特征 \(x_1\)\(x_2\)\(x_3\) 来训练逻辑回归,而是自己训练逻辑回归的输入 \(a_1\)\(a_2\)\(a_3\)。可以想象,如果在 \(\theta_1\) 中选择不同的参数,有时可以学习到一些很有趣和复杂的特征,就可以得到一个更好的假设,比使用原始输入 \(x_1\)\(x_2\)\(x_3\) 时得到的假设更好。你也可以选择多项式项 \(x_1\)\(x_2\)\(x_3\) 等作为输入项,但这个算法可以灵活地快速学习任意的特征项,把这些 \(a_1\)\(a_2\)\(a_3\) 输入这个最后的单元,实际上它是逻辑回归,我觉得现在描述的这个例子有点高端,所以,我不知道你是否能理解这个具有更复杂特征项的神经网络。但是如果你没理解,在接下来的两节课里,我会讲解一个具体的例子,它描述了怎样用神经网络,如何利用这个隐藏层计算更复杂的特征,并输入到最后的输出层,以及为什么这样就可以学习更复杂的假设。所以,如果我现在讲的你没理解,请继续学习接下来的两节课,希望它们提供的例子能够让你更加理解神经网络。但有一点,你还可以用其他类型的图来表示神经网络,神经网络中神经元相连接的方式称为神经网络的架构,所以说,架构是指不同的神经元是如何相互连接的。这里有一个不同的神经网络架构的例子,你可以意识到这个第二层是如何工作的,在这里我们有三个隐藏单元,它们根据输入层计算一个复杂的函数,然后第三层可以将第二层训练出的特征项作为输入,并在第三层计算一些更复杂的函数,这样,在你到达输出层之前,即第四层,就可以利用第三层训练出的更复杂的特征项作为输入,以此得到非常有趣的非线性假设。顺便说一下,在这样的网络里,第一层被称为输入层,第四层仍然是我们的输出层。这个网络有两个隐藏层,所以,任何一个不是输入层或输出层的都被称为隐藏层。我希望从这节课中,你已经大致理解前向传播在神经网络里的工作原理:从输入层的激励开始,向前传播到第一隐藏层,然后传播到第二隐藏层,最终到达输出层,并且你也知道了如何向量化这些计算。我发现,这节课里我讲了某些层是如何计算前面层的复杂特征项,我意识到这可能仍然有点抽象,显得比较高端,所以我将在接下来的两个节课中讨论具体的例子,它描述了怎样用神经网络来计算输入的非线性函数,希望能使你更好的理解从神经网络中得到的复杂非线性假设。

例子和直观理解 1(Examples and Intuitions I)

在接下来两节课中,我要通过讲解一个具体的例子,来解释神经网络是如何计算关于输入的复杂的非线性函数,希望这个例子可以让你了解为什么神经网络可以用来学习复杂的非线性假设。

考虑下面的问题,我们有二进制的输入特征 \(x_1\) \(x_2\),要么取 0 要么取 1,所以 \(x_1\)\(x_2\) 只能有两种取值。在这个例子中,我只画出了两个正样本和两个负样本,但你可以认为这是一个更复杂的学习问题的简化版本。在这个复杂问题中,我们可能在右上角有一堆正样本,在左下方有一堆用圆圈表示的负样本,我们想要学习一种非线性的决策边界来区分正负样本。那么,神经网络是如何做到的呢?为了描述方便,我不用右边这个例子,我用左边这个例子,这样更容易说明。具体来讲,这里需要计算的是目标函数 \(y\) 等于 \(x_1\) 异或 \(x_2\),或者 \(y\) 也可以等于 \(x_1\) 异或非 \(x_2\),其中异或非表示 \(x_1\) 异或 \(x_2\) 后取反,\(x_1\) 异或 \(x_2\) 为真,当且仅当这两个值 \(x_1\) 或者 \(x_2\) 中有且仅有一个为 1。如果我用 \(x_{nOR}\) 作为例子,比用 NOT 作为例子结果会好一些,但这两个其实是相同的,这就意味着在 \(x_1\) 异或 \(x_2\) 后再取反,即当它们同时为真,或者同时为假的时候,我们将获得 \(y\) 等于 1。\(y\) 为 0 的结果,如果它们中仅有一个为真 \(y\) 则为 0。我们想要知道是否能找到一个神经网络模型来拟合这种训练集,为了建立能拟合 \(x_{nOR}\) 运算的神经网络,我们先讲解一个稍微简单的神经网络,它拟合了 "且运算"。假设我们有输入 \(x_1\)\(x_2\),并且都是二进制,即要么为 0 要么为 1。我们的目标函数 \(y\) 正如你所知道的,等于 \(x_1\)\(x_2\),这是一个逻辑与,那么,我们怎样得到一个具有单个神经元的神经网络,来计算这个逻辑与呢?为了做到这一点,我也需要画出偏置单元,即这个里面有个 +1 的单元。现在,让我给这个网络分配一些权重或参数,我在图上写出这些参数,这里是 -30 正 20 正 20,即我给 \(x_0\) 前面的系数赋值为 -30。这个正 1 会作为这个单元的值,关于 20 的参数值,且 \(x_1\) 乘以 +20 以及 \(x_2\) 乘以 +20,都是这个单元的输入。所以,我的假设 \(ħ(x)\) 等于 \(g(-30 + 20x_1 + 20x_2)\)。在图上画出这些参数和权重是很方便很直观的。其实,在这幅神经网络图中,这个 -30 其实是 \(\theta^{(1)}10\),这个是 \(\theta^{(1)}11\),这是 \(\theta^{(1)}12\),但把它想成这些边的权重会更容易理解。让我们来看看这个小神经元是怎样计算的,回忆一下 s 型激励函数 \(g(z)\) 看起来是这样的,它从 0 开始,光滑上升穿过 0.5,渐进到 1。我们给出一些坐标,如果横轴值 \(z\) 等于 4.6,则 S 形函数等于 0.99,这是非常接近 1 的,并且由于对称性,如果 \(z\) 为 -4.6,S 形函数等于 0.01,非常接近 0。让我们来看看四种可能的输入值 \(x_1\)\(x_2\) 的四种可能输入,看看我们的假设在各种情况下的输出。如果 \(x_1\)\(x_2\) 均为 0,那么你看看这个,如果 \(x_1\)\(x_2\) 都等于 0,则假设会输出 \(g(-30)\)\(g(-30)\) 在图的很左边的地方,非常接近于 0。如果 \(x_1\) 等于 0 且 \(x_2\) 等于 1,那么,此公式等于 g。关于 -10 取值也在很左边的位置,所以,也是非常接近 0,这个也是 \(g(-10)\),也就是说,如果 \(x_1\) 等于 1 并且 \(x_2\) 等于 0,这就是 -30 加 20 等于 -10。最后,如​​果 \(x_1\) 等于 1,\(x_2\) 等于 1,那么这等于 -30 +20 +20,所以这是取 +10 时,非常接近 1。如果你看看在这一列,这就是逻辑 "与" 的计算结果,所以,这里得到的 \(h\)\(h\) 关于 \(x\) 取值近似等于 \(x_1\)\(x_2\) 的与运算的值。换句话说,假设输出 1 当且仅当 \(x_1\) \(x_2\) 都等于 1,所以通过写出这张真值表,我们就弄清楚了神经网络计算出的逻辑函数。这里的神经网络实现了或函数的功能,接下来我告诉你是怎么看出来的,如果你把假设写出来会发现它等于 g 关于 -10 +20 \(x_1\) +20\(x_2\) 的取值,如果把这些值都填上,会发现这是 \(g(-10)\) 约等于 0,这是 \(g(10)\) 约等于 1,这个也约等于 1。这些数字本质上就是逻辑或运算得到的值,所以,我希望通过这个例子,你现在明白了神经网络里单个的神经元在计算,如 AND 和 OR 逻辑运算时,是怎样发挥作用的。在接下来的课程中,我们将继续讲解一个更复杂的例子,我们将告诉你一个多层的神经网络怎样被用于计算更复杂的函数,如 XOR 函数或 \(x_{nOR}\) 函数。

例子和直观理解 2(Examples and Intuitions II)

在这节课中,我想通过例子来向大家展示一个神经网络是怎样计算非线性的假设函数。

在上节课中,我们学习了怎样运用神经网络来计算 \(x_1\)\(x_2\) 的与运算,以及 \(x_1\)\(x_2\) 的或运算。其中 \(x_1\)\(x_2\) 都是二进制数,也就是说,它们的值只能为 0 或 1。同时,我们也学习了怎样进行逻辑非运算,也就是计算 "非\(x_1\)"。我先写出这个神经网络中相连接的各权值,这里我们只有一个输入量 \(x_1\),在这里我们也加上了表示偏差的单位元 +1。如果我将输入单元和两个权数相连,也就是 +10 和 -20,则可用以下假设方程来计算 \(h(x)=g(10-20x_1)\),其中 g 是一个 S 型函数。那么,当 \(x_1=0\) 时,计算出假设函数 \(g(10-20*0)\) 也就是 \(g(10)\),这个值近似的等于 1。而当 \(x\) 等于 1 时,计算出的假设函数则变成 \(g(-10)\) 也就是约等于 0。如果你观察这两个值,你会发现这实际上计算的就是 "非\(x_1\)" 函数,所以要计算逻辑非运算,总体思路是在你希望取非运算的变量前面放上一个绝对值大的负数作为权值。因此,如果放一个 -20,那么和 \(x_1\) 相乘,很显然,最终的结果就得到了对 \(x_1\) 进行非运算的效果。另外,我再给出一个例子计算这样一个函数 (非\(x_1\)) 与 (非\(x_2\))。我希望大家思考一下,自己动手算一算,你大概应该知道,至少应该在 \(x_1\)\(x_2\) 前面放一个绝对值比较大的负数作为权值。不过,还有一种可行的方法是建立一个神经网络来计算,用只有一个输出单元的神经网络,没问题吧?,因此,这个看起来很长的逻辑函数 "(非\(x_1\)) 与 (非\(x_2\))" 的值将等于 1,当且仅当 \(x_1\) 等于 \(x_2\) 等于 0。所以,这是个逻辑函数,这里是非 \(x_1\),也就是说 \(x_1\) 必为 0,然后是非 \(x_2\),这表示 \(x_2\) 也必为 0。因此这个逻辑函数等于 1,当且仅当 \(x_1\)\(x_2\) 的值都为 0 时成立。现在你应该也清楚了怎样建立一个小规模的神经网络,来计算这个逻辑函数的值,把以上我们介绍的这三个部分内容放在一起 "\(x_1\)\(x_2\)" 与运算的网络,以及计算 "(非\(x_1\)) 与 (非\(x_2\))" 的网络。还有最后一个是 "\(x_1\)\(x_2\)" 的或运算网络,把这三个网络放在一起,我们就应该能计算 "\(x_1\) \(x_{nOR}\) \(x_2\)",也就是同或门运算。提醒一下,如果这是 \(x_1\) \(x_2\),那么我们想要计算的这个函数,在这里和这里是负样本,而在这里和这里函数有正样本值,那么很显然,为了分隔开正样本和负样本,我们需要一个非线性的判别边界。这里我们用以下这个网络来解决,取输入单元 +1 \(x_1\)\(x_2\) 建立第一个隐藏层单元,我们称其为 \(a^{(2)}_1\),因为它是第一个隐藏单元。接下来我要从红色的网络,也就是 "\(x_1\)\(x_2\)" 这个网络复制出权值,也就是 -30 20 20。接下来,我再建立第二个隐藏单元,我们称之为 \(a^{(2)}_2\),它是第二层的第二个隐藏单元,然后再从中间的青色网络中复制出权值,这样我们就有了 10 -20 -20 这样三个权值。因此,我们来看一下真值表中的值,对于红色的这个网络,我们知道是 \(x_1\)\(x_2\) 的与运算,所以,这里的值大概等于 0 0 0 1,这取决于 \(x_1\)\(x_2\) 的具体取值。对于 \(a^{(2)}_2\),也就是青色的网络,我们知道这是 "(非\(x_1\)) 与 (非\(x_2\))" 的运算,那么对于 \(x_1\)\(x_2\) 的四种取值,其结果将为 1 0 0 0。最后,建立输出节点,也就是输出单元 \(a^{(3)}_1\),这也是等于输出值 \(h(x)\),然后复制一个或运算网络,同时,我需要一个 +1 作为偏差单元,将其添加进来,然后从绿色的网络中复制出所有的权值,也就是 -10 20 20。我们之前已经知道这是一个或运算函数,那么我们继续看真值表的值,第一行的值是 0 和 1 的或运算,其结果为 1,然后是 0 和 0 的或运算,其结果为 0,0 和 0 的或运算,结果还是 0, 1 和 0 的或运算,其结果为 1。因此 \(h(x)\) 的值等于 1,当 \(x_1\)\(x_2\) 都为 0,或者 \(x_1\)\(x_2\) 都为 1 的时候成立。具体来说,在这两种情况时 \(h(x)\) 输出 1,在另两种情况时 \(h(x)\) 输出 0,那么对于这样一个神经网络,有一个输入层,一个隐藏层和一个输出层,我们最终得到了计算 \(x_{nOR}\) 函数的非线性判别边界。更一般的理解是,在输入层中,我们只有原始输入值,然后我们建立了一个隐藏层,用来计算稍微复杂一些的输入量的函数。如图所示,这些都是稍微复杂一些的函数,然后,通过添加另一个层,我们得到了一个更复杂一点的函数。

这就是关于神经网络可以计算较复杂函数的某种直观解释,我们知道当层数很多的时候,你有一个相对简单的输入量的函数作为第二层,而第三层可以建立在此基础上来计算更加复杂一些的函数,然后再下一层又可以计算再复杂一些的函数。

在本节课的最后,我想给大家展示一个有趣的例子,这是一个神经网络通过运用更深的层数来计算更加复杂函数的例子。我将要展示的这段视频来源于我的一个好朋友阳乐昆 (Yann LeCun),yann 是一名教授,供职于纽约大学,他也是神经网络研究早期的奠基者之一, 也是这一领域的大牛,他的很多理论和想法现在都已经被应用于各种各样的产品和应用中,遍布于全世界。所以我想向大家展示一段他早期工作中的视频,这段视频中他使用神经网络的算法进行手写数字的辨识。你也许记得,在这门课刚开始的时候,我说过关于神经网络的一个早期成就,就是应用神经网络读取邮政编码,以帮助我们进行邮递,那么这便是其中一种尝试,这就是为了解决这个问题而尝试采用的一种算法。在视频中,这个区域是输入区域,表示的是手写字符,它们将被传递给神经网络,这一列数字表示通过该网络第一个隐藏层运算后,特征量的可视化结果。因此通过第一个隐藏层可视化结果,显示的是探测出的不同特征,不同边缘和边线,这是下一个隐藏层的可视化结果,似乎很难看出怎样理解更深的隐藏层以及下一个隐藏层计算的可视化结果,可能你如果要想看出到底在进行怎样的运算,还是比较困难的,最终远远超出了第一个隐藏层的效果。但不管怎样,最终这些学习后的特征量将被送到最后一层,也就是输出层,并且在最后作为结果显示出来,最终预测到的结果就是这个神经网络辨识出的手写数字的值。

下面我们来观看这段视频,我希望你喜欢这段视频,也希望这段视频能给你一些直观的感受,关于神经网络可以学习的较为复杂一些的函数。在这个过程中,它使用的输入是不同的图像,或者说就是一些原始的像素点,第一层计算出一些特征,然后下一层再计算出一些稍复杂的特征,然后是更复杂的特征,然后这些特征实际上被最终传递给最后一层逻辑回归分类器上,使其准确地预测出神经网络 "看" 到的数字。

多类分类(Multiclass Classification)

在这节课中,我想和大家谈谈如何用神经网络做多类别分类。

在多类别分类中,通常有不止一个类别需要我们去区分,在上节课最后,我们提到了有关手写数字辨识的问题,这实际上正是一个多类别分类的问题,因为辨识数字从 0 到 9,正好是 10 个类别。因此你也许已经想问,究竟应该怎样处理这个问题。

我们处理多类别分类的方法实际上是基于一对多神经网络算法而延伸出来的,让我们来看这样一个例子,还是有关计算机视觉的例子,就像我之前介绍过的识别汽车的例子,但与之不同的是,现在我们希望处理的是四个类别的分类问题。给出一幅图片,我们需要确定图上是什么,是一个行人,一辆汽车还是一辆摩托车,亦或是一辆卡车。对于这样一个问题,我们的做法是建立一个具有四个输出单元的神经网络,也就是说,此时神经网络的输出是一个四维向量。因此,现在的输出需要用一个向量来表示,这个向量中有四个元素,而我们要做的是对第一个输出元素进行分辨,图上是不是一个行人,然后对第二个元素分辨它是不是一辆汽车,同样,第三个元素是不是摩托车,第四个元素是不是一辆卡车。因此,当图片上是一个行人时,我们希望这个神经网络输出 1 0 0 0,当图片是一辆轿车时,我们希望输出是 0 1 0 0,当图片是一辆摩托车时,我们希望结果是 0 0 1 0,以此类推。所以,这和我们介绍逻辑回归时讨论过的一对多方法,其实是一样的,只不过现在我们有四个逻辑回归的分类器,而我们需要对四个分类器中每一个都分别进行识别分类。因此,重新整理一下这页讲义,这是我们的神经网络结构有四个输出单元,这是针对不同的图片我们 \(h(x)\) 的表达式。此时,我们需要用如下的方法来表示训练集,在这个例子中,当我们要表征一个具有行人,汽车摩托车和卡车,这样四个不同图片作为元素的训练集时,我们应该怎么做呢?之前,我们把标签写作一个整数用 \(y\) 来表示 1 2 3 4,现在我们不这样表示 \(y\),而是用以下的方法来代表 \(y\)。那就是 \(y^{(i)}\) 表示 1 0 0 0,或者 0 1 0 0 或者 0 0 1 0 或者 0 0 0 1,根据相对于的图片 \(x^{(i)}\) 来决定,这样,我们的训练样本将成为 \(x^{(i)}\) \(y^{(i)}\) 这一对数,其中 \(x^{(i)}\) 表示我们已知的四种物体图像中的一个,而 \(y^{(i)}\) 是这四个向量中的某一个。我们希望能够找到某种方法,让我们的神经网络输出某个值,因此 \(h(x)\) 近似约等于 \(y\)。在我们的例子中 \(h(x)\)\(y^{(i)}\) 它们都应该是四维向量,因为我们有四个类别,当前时间是 9 月 4 日星期三,还有时间,以及 2013 年,这就是使用神经网络进行多类别分类的方法。这样我们就讨论了怎样基于我们的假设表达式来表征神经网络。在接下来几节课中,我们会开始讨论怎样得到训练集,以及怎样自动学习神经网络的参数。

神经网络的学习(Neural Networks: Learning)

代价函数(Cost Function)

神经网络是当今最强大的学习算法之一,在本节课和后面几次课程中,我将开始讲述一种在给定训练集下,为神经网络拟合参数的学习算法。

正如我们讨论大多数学习算法一样,我们准备从拟合神经网络参数的代价函数开始讲起。我准备重点讲解神经网络在分类问题中的应用,假设我们有一个如左边所示的神经网络结构,然后假设我们有一个像这样的训练集,\(m\) 个训练样本 \(x^{(i)}\) \(y^{(i)}\),我用大写字母 \(L\) 来表示这个神经网络结构的总层数。所以,对于左边的网络结构,我们得到 \(L\) 等于 4。然后我准备用 \(s_l\) 表示第 \(l\) 层的单元的数量,也就是神经元的数量。这其中不包括 \(l\) 层的偏差单元,比如说,我们得到 \(s_1\),也就是输入层是等于 3 的单元,\(s_2\) 在这个例子里等于 5 个单位,然后输出层 \(s_4\) 也就是 \(s_L\),因为 \(L\) 本身等于 4,在左边这个例子中,输出层有 4 个单位。我们将会讨论两种分类问题,第一种是二元分类,在这里 \(y\) 只能等于 0 或 1,在这个例子中,我们有一个输出单元,上面这个神经网络的有四个输出单元,但是如果我们用二元分类的话,我们就只能有一个输出结果,也就是计算出来的 \(h(x)\) 神经网络的输出结果,\(h(x)\) 就会是一个实数。在这类问题里,输出单元的个数 \(s_L\)\(L\) 同样代表最后一层的序号,因为这就是我们在这个网络结构中的层数,所以我们在输出层的单元数目就将是 1。在这类问题里,为了简化记法,我会把 K 设为 1,这样你可以把 K 看作输出层的单元数目,我们要考虑的第二类分类问题就是多类别的分类问题,也就是会有 K 个不同的类。比如说,如果我们有四类的话,我们就用这样的表达形式来代表 \(y\)。在这类问题里,我们就会有 K 个输出单元,我们的假设输出就是一个 K 维向量,输出单元的个数就等于 K。通常这类问题里,我们都有 K 大于或等于 3。因为如果只有两个类别,我们就不需要使用这种一对多的方法,我们只有在 K 大于或者等于 3 个类的时候才会使用这种一对多的方法。因为如果只有两个类别,我们就只需要一个输出单元就可以了。现在我们来为神经网络定义代价函数,我们在神经网络里使用的代价函数应该是逻辑回归里使用的代价函数的一般化形式。对于逻辑回归而言,我们通常使代价函数 \(J(\theta)\) 最小化,也就是 -1/m 乘以后面这个代价函数,然后再加上这个额外正则化项,这里是一个 \(j\) 从 1 到 n 的求和形式,因为我们并没有把偏差项 0 正则化。对于一个神经网络来说,我们的代价函数是这个式子的一般化形式,这里不再是仅有一个逻辑回归输出单元,取而代之的是 K 个,所以这是我们的代价函数,神经网络现在输出了 K 维的向量,这里 K 可以取到 1,也就是原来的二元分类问题。我准备用这样一个记法 \(h(x)\) 带下标 i 来表示第 i 个输出,也就是 \(h(x)\) 是一个 K 维向量,下标 \(i\) 表示选择了神经网络输出向量的第 i 个元素,我的代价函数 \(J(\theta)\) 将成为下面这样的形式,-1/m 乘以一个类似于我们在逻辑回归里所用的求和项,除了这里我们求的是 k 从 1 到 K 的所有和,这个求和项主要是 K 个输出单元的求和,所以如果我有四个输出单元,也就是我的神经网络最后一层有四个输出单元,那么这个求和就是求 k 等于从 1 到 4 的每一个的逻辑回归算法的代价函数,然后按四次输出的顺序依次把这些代价函数加起来,所以你会特别注意到这个求和符号应用于 \(y_k\)\(h_k\),因为,我们主要是讨论 K 个输出单元,并且把它和 \(y_k\) 的值相比,\(y_k\) 的值就是这些向量里表示,它应当属于哪个类别的量。最后,这里的第二项,这就是类似于我们在逻辑回归里所用的正则化项,这个求和项看起来确实非常复杂,它所做的就是把这些项全部相加,也就是对所有 i,j 和 l 的 \(\theta_{ji}\) 的值都相加,正如我们在逻辑回归里一样,这里要除去那些对应于偏差值的项,那些项我们是不加进去的。具体地说,我们不把那些对于 i 等于 0 的项加入其中,这是因为,当我们计算神经元的激励值时,我们会有这些项 \(\theta_0\) 加上 \(\theta_1\) 乘以 \(x_1\),再加上等等等等。这里我认为,我们可以加上 2 的上标,如果这是第一个隐含层的话,所以这些带 0 的项对应于乘进去了 \(x_0\),或者是 \(a_0\) 什么的,这就是一个类似于偏差单元的项,类比于我们在做逻辑回归的时候,我们就不应该把这些项加入到正规化项里去,因为我们并不想正规化这些项,并把这些项设定为 0。但这只是一个合理的规定,即使我们真的把他们加进去了,也就是 i 从 0 加到 \(s_l\),这依然成立,并且不会有大的差异,但是这个 "不把偏差项正规化" 的规定可能只是会更常见一些。好了,这就是我们准备应用于神经网络的代价函数。在下节课中,我会开始讲解一个算法来最优化这个代价函数。

反向传播算法(Backpropagation Algorithm)

在上节课里,我们讲解了神经网络的代价函数,在本节课里,让我们来说说,让代价函数最小化的算法,具体来说,我们将主要讲解反向传播算法。

这个就是我们上一个视频里写好的 代价函数 我们要做的就是 设法找到参数 使得J(\theta)取到最小值 为了使用梯度下降法或者 其他某种高级优化算法 我们需要做的就是 写好一个可以通过输入 参数 \theta 然后计算 J(\theta) 和这些 偏导数项的代码 记住 这些神经网络里 对应的参数 也就是 \theta 上标 (l) 下标 ij 的参数 这些都是实数 所以这些都是我们需要计算的 偏导数项 为了计算代价函数 J(\theta) 我们就是用上面这个公式 所以我们在本节视频里大部分时间 想要做的都是 重点关注 如何计算这些 偏导数项 我们从只有一个 训练样本的情况 开始说起 假设 我们整个训练集 只包含一个训练样本 也就是实数对 我这里不写成x(1) y(1) 就写成这样 把这一个训练样本记为 (x, y) 让我们粗看一遍 使用这一个训练样本 来计算的顺序首先我们 应用前向传播方法来 计算一下在给定输入的时候 假设函数是否会真的输出结果 具体地说 这里的 a(1) 就是第一层的激励值 也就是输入层在的地方 所以我准备设定他为 然后我们来计算 z(2) 等于 \theta(1) 乘以 a(1) 然后 a(2) 就等于 g(z(2)) 函数 其中g是一个S型激励函数 这就会计算出第一个 隐藏层的激励值 也就是神经网络的第二层 我们还增加这个偏差项 接下来我们再用2次 前向传播 来计算出 a(3) 和 最后的 a(4) 同样也就是假设函数 h(x) 的输出 所以这里我们实现了把前向传播 向量化 这使得我们可以计算 神经网络结构里的 每一个神经元的 激励值接下来 为了计算导数项 我们将 采用一种叫做反向传播(Backpropagation)的算法反向传播算法从直观上说 就是对每一个结点 我们计算这样一项 δ下标 j 上标(l) 这就用某种形式 代表了第 l 层的第 j 个结点的 误差 我们还记得 a 上标 (l) 下标 j 表示的是第 l 层第 j 个单元的 激励值 所以这个 δ 项 在某种程度上 就捕捉到了我们 在这个神经节点的激励值的误差 所以我们可能希望这个节点的 激励值稍微不一样 具体地讲 我们用 右边这个有四层 的神经网络结构做例子 所以这里大写 L 等于4 对于每一个输出单元 我们准备计算δ项 所以第四层的第j个单元的δ就等于这个单元的激励值 减去训练样本里的 真实值0所以这一项可以 同样可以写成 h(x) 下标 j 所以 δ 这一项就是 假设输出 和训练集y值 之间的差 这里 y 下标 j 就是 我们标记训练集里向量 的第j个元素的值顺便说一下 如果你把 δ a 和 y 这三个 都看做向量 那么你可以同样这样写 向量化地实现 也就是 δ(4)等于 a(4) 减去 y 这里 每一个变量 也就是 δ(4) a(4) 和 y 都是一个向量 并且向量维数等于 输出单元的数目所以现在我们计算出 网络结构的 误差项 δ(4)我们下一步就是计算 网络中前面几层的误差项 δ 这个就是计算 δ(3) 的公式 δ(3) 等于 \theta(3) 的转置乘以 δ(4) 然后这里的点乘 这是我们从 MATLAB 里知道的对 y 元素的乘法操作 所以 \theta(3) 转置乘以 δ(4) 这是一个向量 g'(z(3)) 同样也是一个向量 所以点乘就是 两个向量的元素间对应相乘其中这一项 g'(z(3)) 其实是对激励函数 g 在输入值为 z(3) 的时候 所求的 导数 如果你掌握微积分的话 你可以试着自己解出来 然后可以简化得到我这里的结果 但是我只是从实际角度告诉你这是什么意思 你计算这个 g' 这个导数项其实是 a(3) 点乘 (1-a(3)) 这里a(3)是 激励向量 1是以1为元素的向量 a(3) 又是 一个对那一层的 激励向量 接下来你应用一个相似的公式 来计算 δ(2) 同样这里可以利用一个 相似的公式只是在这里 是 a(2) 这里我并没有证明 但是如果你懂微积分的话 证明是完全可以做到的 那么这个表达式从数学上讲 就等于激励函数 g函数的偏导数 这里我用 g‘来表示 最后 就到这儿结束了 这里没有 δ(1) 项 因为 第一次对应输入层 那只是表示 我们在训练集观察到的 所以不会存在误差 这就是说 我们是不想改变这些值的 所以这个例子中我们的 δ 项就只有 第2层和第3层反向传播法这个名字 源于我们从 输出层开始计算 δ项 然后我们返回到上一层 计算第三隐藏层的 δ项 接着我们 再往前一步来计算 δ(2) 所以说 我们是类似于把输出层的误差 反向传播给了第3层 然后是再传到第二层 这就是反向传播的意思最后 这个推导过程是出奇的麻烦的 出奇的复杂 但是如果你按照 这样几个步骤计算 就有可能简单直接地完成 复杂的数学证明 如果你忽略标准化所产生的项 我们可以证明 我们要求的偏导数项恰好就等于 激励函数和这些 δ 项 这里我们忽略了 \lambda 或者说 标准化项\lambda 是等于 0 我们将在之后完善这一个 关于正则化项 所以到现在 我们通过 反向传播 计算这些δ项 可以非常快速的计算出 所有参数的 偏导数项 好了 现在讲了很多细节了 现在让我们把所有内容整合在一起 然后说说 如何实现反向传播算法来计算关于这些参数的偏导数当我们有 一个非常大的训练样本时 而不是像我们例子里这样的一个训练样本 我们是这样做的 假设我们有 m 个样本的训练集 正如此处所写 我要做的第一件事就是 固定这些 带下标 i j 的 Δ 这其实是 大写的希腊字母 δ 我们之前写的那个是小写 这个三角形是大写的 Δ 我们将对每一个i 和 j 对应的 Δ 等于0 实际上 这些大写 Δij 会被用来计算偏导数项 就是 J(\theta) 关于 \theta 上标(l) 下标 i j 的 偏导数所以 正如我们接下来看到的 这些 δ 会被作为累加项 慢慢地增加 以算出这些偏导数接下来我们将遍历我们的训练集 我们这样写 写成 For i = 1 to m 对于第 i 个循环而言 我们将取训练样本 (x(i), y(i))我把1999年的值画在一列里 我们要做的第一件事是 设定a(1) 也就是 输入层的激励函数 设定它等于 x(i) x(i) 是我们第 i 个训练样本的 输入值 接下来我们运用正向传播 来计算第二层的激励值 然后是第三层 第四层 一直这样 到最后一层 L层 接下来 我们将用 我们这个样本的 输出值 y(i) 来计算这个输出值 所对应的误差项 δ(L) 所以 δ(L) 就是 假设输出减去 目标输出接下来 我们将 运用反向传播算法 来计算 δ(L-1) δ(L-2) 一直这样直到 δ(2) 再强调一下 这里没有 δ(1) 因为我们不需要对输入层考虑误差项最后我们将用 这些大写的 Δ 来累积我们在前面写好的 偏导数项顺便说一下 如果你再看下这个表达式 你可以把它写成向量形式 具体地说 如果你把 δij 看作一个矩阵 i j代表矩阵中的位置那么 如果 δ(L) 是一个矩阵 我们就可以写成 Δ(l) 等于 Δ(l) 加上小写的 δ(l+1) 乘以 a(l) 的转置 这就是用向量化的形式 实现了对所有 i 和 j 的自动更新值 最后 执行这个 for 循环体之后 我们跳出这个 for 循环 然后计算下面这些式子 我们按照如下公式计算 大写 我们对于 j=0 和 j≠0 分两种情况讨论在 j=0 的情况下 对应偏差项 所以当 j=0 的时候 这就是为什么 我们没有写额外的标准化项最后 尽管严格的证明对于 你来说太复杂 你现在可以说明的是 一旦你计算出来了这些 这就正好是 代价函数对 每一个参数的偏导数 所以你可以把他们用在 梯度下降法 或者其他一种更高级的优化算法上这就是反向传播算法 以及你如何计算 神经网络代价函数的 偏导数 我知道这个里面 细节琐碎 步骤繁多 但是在后面的编程作业 和后续的视频里 我都会给你一个 清晰的总结 这样我们就可以把算法的所有细节 拼合到一起 这样 当你想运用反向传播算法 来计算你的神经网络的代价函数 关于这些参数的偏导数的时候 你就会清晰地知道 你要的是什么

反向传播算法的直观理解(Backpropagation Intuition)

在之前的视频里,我们介绍了反向传播算法 对许多人来说, 第一次看到它的印象是,这是一个非常复杂的算法 并且这里有很多步骤,人们很难搞清楚是怎么统一起来 看起来像是一个复杂的黑箱 如果你也是这么觉得,其实很正常 反向传播,很大程度上数学步骤比较复杂 并不是一个简单的算法 比起线性回归和逻辑回归而言。 我实际上使用反向传播算法许多年, 也很成功。 但即使是今天,有时候我还是感觉不太好把握, 或者忽然觉得迷茫。 因此,对于即将做编程的同学, 你们不用担心,我们会有数学的具体步骤, 它将帮助你来一步一步完成。 所以,你将能够自主独立实现。 在这个视频,我要做的, 是再一步一步介绍这个算法,让你更有体会。 这些机械的步骤,将使你信服, 让你认为这是一个非常合理的算法。如果这个视频之后, 你还是觉得这个算法非常复杂, 其实也没有太大关系。 正如之前所说,对我而言有时候也很难。 但,希望这个视频可以有所帮助。 为了更好地理解反向传播算法, 我们来看看正向传播 这个神经网络有两个输入层单元,当然不算上偏置单元 两个隐层单元,有两层 还有一个输出单元 当然,我们都不算偏置单元 为了更好地展示前向传播 我这次要用另外一种画法特别地,我要把每个神经元 画的更扁平一些,所以我可以在里面写字 当进行前向传播算法的时候,我们可能有一些特别的例子 比如,xi,yi 我们将把它输入到这个网络当中 所以,xi1和xi2将是我们对输入层的设置 当我们进入第一个隐层, 我们会计算z(2)1和z(2)2 那么,这些是我们要的值 然后我们来用冲击函数计算 它作用与z值 这里是激励值 所以我们有a(2)1和a(2)2 之后我们把这些值赋予给z(3)1 然后使用sigmoid函数 我们会得到a(3)1 类似的,我们一直得到z(4)1 再次计算, 我们有a(4)1,这是最后的结果我们擦掉这些箭头,来得到更多空间 如果你仔细看我们的计算过程, 我们可以说, 我们要加上这个权重 (2)1 0,这里的编号不重要 这个方向,我用红色高亮 是theta(2)11以及权重 这里用青色标注theta(2)12 所以,z(3)1是 z(3)1等于这个值 所以我们有(2)10x_1 然后加上红色标注的权值 得到theta(2)11乘以a(2)1 最后我们再用青色来乘 也就是加上theta(2)12乘以a(2)1 那么这就是前向传播 这我们之前看到过 而反向传播做的很类似 除了这些计算从左到右, 现在是从右到左 同时计算流程相似 我用两页PPT来描述这个过程 首先来看其支付函数 这是只有一个输出单元时候的支付函数 如果有多个 那就需要编号并且求和 如果只有一个,用这个函数就行 我们在一个例子里做前向和后向传播 来关注一个例子x(i)和y(i) 并且来看输出值 所以y(i)是一个实数 我们现在不考虑标准化,所以lambda为0 所以最后一项去掉 如果你来看这个求和公式 你会发现,这个支付项 和我们的训练数据x(i)和y(i)有关 这由我们的表达式给出 所以,正如下述所写的 支付函数所做的和这个箭头相似 我们不看这个复杂的表达式 如果你考虑支付, 这里就是我们的插值 和之前逻辑回归很像, 我们用了Log 但,从直觉上来说, 这其实就是平方误差函数 所以cost(i)描述了 这个网络的表现,对于特定的结果i 那么到底这个计算结果和真实值y(i)多接近呢 我们来看反向传播在做什么 一个很有用的例子就是反向传播 计算了deltai下标j 这是我们的理解方法, 我们在l层得到单元j正式一点说, 这个对于熟悉微积分的人来说更恰当 所以,这就是delta项 它就是一个偏微分,针对z,l,j 这是权重, 针对这些量的偏微分,所得到的支付函数所以,具体来说, 这个h x输出值, 如果我们走进这个神经网络, 并且只稍微改变一下zl j值 那么这就会改变我们的输出 也会改变我们的支付函数 同样,还是针对那些微积分比较好的同学 如果你适应偏微分 这些就是对支付函数的偏微分, 针对中间变量并且,他们衡量了我们要如果改变网络的权值 当然,这是为了影响我们的计算结果 所以,为了改变计算结果h(x) 以及对整个支付函数的影响 上下的这个偏微分的理解, 如果你不能理解 不要太担心 我们可以撇开它来谈 我们就来看看到底反向传播算法做了什么 首先,设置这个delta项 delta(4) 1正如y(i)我们对前向传播算法 和后向传播对训练数据i的做法一样。 这表达的是y(i)减去a(4)1 所以就是误差,对吧 这就是真实结果和 我们预测结果的误差,所以我们结算delta(4)1 接下来,我们来把这些值反向传播回去 我会马上解释, 这最后就是计算前向的结果 我们会得到delta(3)1 delta3(2) 然后,我们进一步往前, 得到delta(2)1和delta(2)2 现在 看起来就像是又重演前向传播 只不过我们现在反过来做了,这就是我之前所说的 我们来看看最后我们如何得到delta(2)2 所以我们得到delta(2)2 和前向传播类似, 这个权值,我用青色来表示 加入它是theta(2)12 然后,我用红色来高亮 这个我们说是theta(2) 22 如果,我们来看delta(2)2 如何计算。 结果,我们发现 我们就把这个值乘以它权值,并加上这个值乘以权值 所以,就是一个加权求和 权值是每一条边的强度 所以,我们来看delta(2)2 theta(2)12是delta(3)1 加上 我们红色标注的东西 theta(2)2乘以delta(3)2 所以,这个红色值乘以这个值 加上品红色的权值 恩, 另一个例子,我们来看这个值怎么求 如果得到呢 恩,一样的步骤 如果这个权值,我用绿色来描述 它等于delta(3)12 然后我们有delta(3)2将等于它的绿色权值 theta(3)12乘以delta(4)1 顺便一提,我只写隐层单元 忽略了偏置单元 这要看你如何定义算法 或者你如何应用 你也可能要用这些单元 这些偏置单元总是为1 所以他们就是1,我们不会改变他们 所以,要看你的应用思路 以及使用方法 我们计算完了这些值 我们扔掉它, 因为我们最后得到的不过是 计算导数的一个部分 希望这就可以给一个更好的直观体会 关于反向传播算法 如果仍然感觉很迷茫, 像是黑箱,在下一个视频 我会再把他们总结起来 但,这是一个很难讲解的算法 难以可视化 但, 幸运的是很多人都在成功使用它 如果你使用这个算法 它将是非常有效的,尽管它内部的机制很难可视化。

实现注意:展开参数(Implementation Note:Unrolling Parameters)

在之前的视频中,我们谈到了 如何使用反向传播以计算损失函数的导数 在这个视频中 我想快速地告诉你们一个 关于把系数从矩阵 展开到向量的实现细节 我们需要它实现高级的优化具体来说 假设你实现了一个损失函数 它的输入是这些参数theta 然后返回损失函数和导数接着你可以把它 传递给一个高级的优化算法fminunc 顺便说一下 fminunc不是唯一的方法 也有其它的高级优化算法但所有这些算法做的 都是把这些输入 包括损失函数的指针 和theta的初始值另外呢 这些做法假设 theta的初始值 是系数向量 也许是Rn或者Rn+1 但这些是向量 它也假设 这些代价函数会返回 第二个返回值 这个梯度 它也是Rn或者Rn+1 也是向量 我们在做逻辑回归时 它很有效 但我们在使用神经网络 我们的系数 不再是向量了 而是矩阵 对于一个完全的神经网络 它有这些系数矩阵theta1 theta_2 theta3 我们在Octave中会写成 这些矩阵theta1 theta_2 theta3 相似地 我们期待它返回的梯度项 嗯我们在之前的视频中 展示了如何去计算 这些梯度矩阵 也就是D1 D2 D3 我们在octave中可以写成 矩阵D1 D2 D3在这个视频中 我想快速地告诉你们 如何展开这些矩阵 把它们展开成向量 所以它们最后 能变成一个 适合作为这里的theta输入 以得到梯度的格式具体来说 假设我们有一个神经网络 它有一个有10个单元的输入层 10个单元的隐藏层 一个只有1个单元的 输出层 所以s1是第一层的单元数 s2是 第二层的单元数 s3是第三层的单元数 在这个例子里 矩阵theta D的 尺寸 会由这些表达式给出 举个例子 theta是一个1011的矩阵 以此类推所以在octave中 如果你想 转化为向量 你可以做的是 把theta 1 theta 2 theta 3 写成这样 它会把你这三个矩阵的 所有元素 把theta1 theta_2 theta3的所有元素 都提取出来 然后展开 把所有元素放进一个很长的向量就是thetavec同样地 第二个命令 会把所有的D矩阵 展开成 一个长向量 称为DVec 最后如果你想 由向量转换成矩阵假设你想 重新得到theta1 你可以从thetavec中 提出前110个元素 所以theta1有 110个元素 因为它是1011的矩阵 所以这样提出前110个元素 然后你就可以 使用reshape命令把它重新变成theta1 相似地 要得到theta_2 你提出接下来的110个元素 然后重塑它 对于theta3 你提出最后11个元素 然后运行reshape以得到theta3这是整个流程的octave演示代码 所以在这个例子里 把theta1设置成 1011矩阵 元素是1 所以它是一个全是1的矩阵 为了看起来更方便 把theta_2设成 2乘上1011全1矩阵 也把theta3 设置成 3乘111全1矩阵 所以这是 3个不同的矩阵 theta1 theta_2 theta3 我想把它们变成向量 thetavec等于 theta1 theta_2theta3 好了 这中间有一个分号 就像这样现在thetavec 是一个很长的向量 它有231个元素如果我展示它 我会发现这是一个很长的向量 它包含第一个矩阵的所有元素 第二个矩阵的所有元素 第三个矩阵的所有元素如果我想重新得到 最初的矩阵 我可以reshape thetavec让我们提出前面的110个元素 然后重塑成1011的矩阵这就是theta1 如果我再 拿出接下来110个元素 所以标号是111到220 我得到了所有的2如果我再从221到最后一个元素 也就是 地231个元素 然后重塑成1*11 我得到theta3为了让这个过程很清晰 我介绍一下我们是如何 用这个展开的方法实现学习算法的假设你有一些 系数的初始值 theta1 theta_2 theta3 我们要做的是 把它们展开 变成一个长向量 我们会把这些初始的theta 传递给fminunc 作为这些theta的初始值我们还需要做的是 实现损失函数这里是我的实现损失函数会 需要输入thetavec 它就是一个 被展开的向量 包含了所有的系数向量所以首先我会 我会用thetavec 然后用reshape函数 我从thetavec中 提取出元素 然后用reshape 以得到 最初的系数矩阵theta1 theta_2 theta3 所以我得到的是矩阵 所以这是一个 更方便的形式 以使用这些矩阵 所以我可以计算前向传播 以及反向传播 以计算导数和损失函数最终 我可以把导数展开 以保持元素 和展开theta时顺序一致 但我会展开d1 d2 d3 以得到gradientvec 这是损失函数返回的 它返回的是这些导数的向量所以我希望 你们现在能明白如果 来回地转换 矩阵形式的 系数和向量形式的系数矩阵形式的 优点在于 当你的系数以矩阵形式存储时 计算前向传播和反向传播 会更方便 当你使用 某种向量化的实现时 使用矩阵形式 会更简单相对的是 向量形式的优点 类似thetavec dvec 是当你使用高级的优化算法时 这些算法倾向于 假设 你的所有系数展开在了一个长向量中 这样的话 就像我们刚做的 希望你也能在二者之间转换

梯度检验(Gradient Checking)

在之前几个视频里,我们讨论了如何进行前向传播 以及后向传播,从而计算导数 但,后向传播有很多细节, 这些细节有点复杂 有一个不幸的消息是, 它们有很多细节会导致一些BUG 如果你用梯度下降来计算, 你会发现表面上它可以工作 实际上, J 虽然每次迭代都在下降 但是可能, 仍然你的代码有很多BUG 所以,表面上关于theta的函数J在减小 但是你可能最后得到的结果 实际上有很大的误差 你这时候可能知道,有一些小的BUG导致 这种不好的算法性能表现 所以,怎么办呢 有一个想法叫梯度检验 Gradient Checking 它能减少这种错误的概率 就我个人而言,每次我使用后向传播 我都会[]用这种方法 即使是其他比较复杂的模型,我都会做这种检查 如果你这么做,你会对你的模型更有自信 这样,你会更加确信的模型是100%正确的 从我看到的情况,这种方法, 很大程度可以减少错误的可能性 在之前的视频里,我让你们相信 我给你们的公式是正确的, 我还让你们相信,这就是支付函数的梯度值 但,一旦你使用梯度检验, 也就是我们这个视频的主题,你会证明你的代码 实际上就是梯度函数所以,这就是我们的想法,来看一个例子 假设我们有一个关于theta的函数H 我现在有它的一个值,假设是实数 我们说,我想要预测它的倒数, 所以倒数是等于这里的斜度现在我用这种方法来接近, 我们不采用数值的计算倒数, 这里我用epsilon, 同样也有一个减去epsilon的值 然后把他们链接起来我将得到一条直线 我用这个红色线来近似我的导数 恩,真正的斜率是蓝色的线。 所以,你可以看到这是一个很好的近似。数学上,这里的红线垂直高度 除以这个水平宽度,就是我们的斜率 所以,这个点,就是J() 这个点,(theta减掉epsilon) 我们有一个垂直的差值()减去 这两个点的差值,以及水平宽度2epsilon所以我们可以近似来表示 这是近似的值, 它等于J加上epsilon减去J减去epsilon对应的函数值,除以2倍的epsilon通常, 这个epsilon非常小,可能就是10的-4次方 而误差值往往很大, 所以近似效果很好。实际上 如果让epsilon无穷小,这就是导数的定义 恩,它就是导数。 所以, 但我们不希望epsilon太小,否则会有计算上的问题 一般来说在10的-4次方比较合适 通常,你可能见到这个类似的公式 恩。所以,右边的叫做单边导数 左边的叫做双边导数 后者的精确度更高, 当然,一般我们用后者所以,具体来说,当你用octave, 你计算近似梯度时候, 我们用的是这个公式。 恩。。就是红色标注的双边导数近似公式,除以的是2倍 所以,我们有一个近似的值 在这个例子,它看起来非常好地近似我们的结果在之前的PPT里 我们考虑了theta是一个向量 现在,我们来看一般的情况 我们说theta是一个矩阵 我们有一个舒展的参数版本, 所以,这里theta是从1到n的向量 我们, 可以用近似的方式来进行计算 可以看到,我们列出各个近似的求导公式 theta 1套前面的公式是这样, 如此种种。 恩。。 这里都是偏导数。 只改变theta 1的值,其他的值固定 分母一样,还是2 epsilon 我们现在可以得到我们想要的近似结果 恩,所以这个公式组给出了近似的方法 对于任意一个theta我们都有完整地,你可以这样应用。我们用octave来数值计算, 比如, 对于i=1:n,其中n是我们参数的个数 一般我们习惯是舒展的向量而不是矩阵 所以theta是长长的参数清单 这里设置thetaPlus = theta 之后增加(i)项epsilon 恩,这就等于我们 thetaPlus(i), theta1, theta_2如此种种 thetal ,一直到N 所以,这是thetaPlus的含义 类似的 我们现在也有l 减去epsilon最后你会使用这个gradApprox(i) 并且能够给你一个偏微分单数 对于i这就是我们使用的方法 我们可以用一个循环来写 来检验这个近似计算的结果是不是等于我们的计算结果 也就是反向传播算法计算的梯度 Dvec就是我们得到的导数 好的, 反向传播是一个非常高效的算法, 针对所有的参数 我们通常做的是数值计算的结果 也就是刚才所做的 确信这是相等的, 应该说非常接近 所以DVec,我们从反向传播得到, 如果得到同一个结果 或者相近的结果,只相差一些小数位 我们很确信这个反向传播的算法是正确的 如果我代入梯度计算 一些高级的算法 我们会更加确信我们的导数计算是正确的 因此,我们的代码不仅正确,而且在优化上性能很好最后,我想总结一下 告诉你梯度检验的相关内容 这是我通常做的事情 首先,使用反向传播来计算,它是很好的算法 这里就是前面介绍的流程 这里的参数我们把矩阵展开成向量 然后 我们使用数值的梯度来检验 这是刚刚介绍的内容我们要确信这两个方法算出来结果一致 你知道,就差一点最后,也是最重要的步骤 就是在你开始学习之前, 一定要关掉我们的梯度检验, 也就是我们讨论的数值计算方法原因是这个计算过程, 实际上代价更高,复杂度也很高 这不是一个很好的计算导数的方法 相反,我们前面讨论的反向传播算法 很早以前介绍的内容 你知道D1 D2 D3对于DVEC 相对来说非常高效。 恩所以,一旦你检验证明你的算法没有错误 就要把梯度检验关掉 所以,你一定要关掉 在你开始迭代训练之前 对于其他很多优化算法也一样 为了训练你的分类器 具体来说,如果你一定要用数值方法 来计算梯度, 那么你的算法会非常慢。 在你的支付函数的循环过程当中 因为,正如前面所说 我们再重复一下...它很慢 记得,我们这里计算(4)(3)(2)等等 这是我们的反向传播算法 它快得多 所以,再说一遍...检验完了后向传播没有问题 关掉梯度检验,重要的事情说三遍 当你在训练你的算法的时候,所以数值的计算, 这是你的检验方法而已。 对我而言,每当我要使用梯度算法,比如后向传播 我都会用梯度检验一下这个算法是否正确 这会让我更加自信我的算法是正确的。

随机初始化(Random Initialization)

在之前的课程里,我们总结了所有内容来帮助你应用,这是最后一个课程,关于随机初始化。

当你使用梯度下降算法,或者其他高级的优化算法,我们需要设置初始值。所以,对于高级的优化算法,假设你是有一个初始值,现在我们假设就是梯度下降。为此,通过初值,我们之后一步步通过梯度下降走到山坡底部。当然,这里就是求最小值,所以,我们怎么设置呢?能不能就全部是零呢?这在之前的逻辑回归里可行,全部为零是可以的。假设我们现在有这么一个网络,假设全部参数为 0,如果你这么做,可以看到蓝色的权值,全是 0,我用红色标记的,等于这个权值,用绿色标记的也等于它。所以,对于 A1 和 A2 隐层单元 将会用同一个函数计算。结果,A21 等于 A22,此外,因为这输出的权值,你可以发现他们的误差值也一样,所以,结果 delta11 delta21 等于 delta22,所以,如果继续下去,我们可以发现他满足下述情况,即所有的偏导数,就编程这两条蓝色的波浪线,你会发现他们都一样。也就是说,你会发现,更新的时候,通过计算梯度,更新的结果,这两个参数是一样。所以,会得到非零的值,但这个值会相等。相似的,即使是通过梯度下降算法,结果也是相等,可能有一些非零的结果,就是红色的箱单,类似绿色也相等,他们都改变结果,但是结果都是一样的。所以每一次更新,参数对应的结果都是完全一致,这和前面所说的一样,红色、绿色、蓝色都一样,这意味着什么呢?你会发现,两个单元仍然计算同样的结果,你仍然有 a1(2)=a2(2) 回到原点。所以,你不断计算,不断计算,都是一样。红色的情况也是,绿色的也是。所以,你的神经网络实际上进入很有意思的情况。相信,你不仅有两个隐层,二是有很多很多层。那么,这将是同样的特性。所有你的隐层的结果都一样,这是非常冗余的。因为,你发现是逻辑回归本质上只有一个特征,这就使得你的神经网络性能下降,无法进行更有意义的功能,所以我们需要随机初始化。具体来说,我们之前看到的问题叫做对称现象。所以,初始化也被称作打破对称,所以我们进行初始化的操作目的就是打破对称,而初始区间就是在特定范围内,这是一种我们用的标记。所以,我的权值参数将会在这个范围内生成。这是我们写代码采用的方式 1,rand10 通过 11,这是你如何计算随机的 10 乘 11 矩阵,所有的值都在 0 到 1,这是连续的 0 到 1 的值。所以,你再乘以这两个参数,你会得到最后满足区间要求的结果。这是生成特定区间随机数常用的计算操作,这里的 epsilon 和梯度检验的 epsilon 是两码事情,不要混淆,这只是一个符号数字而已。完全没有关联。只是喜欢用 epsilon 来表示而已,这里我们可以区别他们。类似的,如果你想要初始化 theta_2 为一个 1 乘 11 的矩阵,你可以用这个代码原理是一样的,不再赘述 -epsilon 到 +epsilon 范围,然后你再使用反向传播,使用梯度检验,1b 在 () 从头开始进行计算,随机初始化结果,也就是打破对称。希望,这个梯度下降算法或者更高级的优化算法能够找到这个理想的 theta 值。

综合起来(Putting It Together)

我们已经用了 几节视频的内容 来介绍神经网络算法在这段视频中 我想结合我们所讲的 所有这些内容 来做一个总体的回顾 看看这些零散的内容 相互之间有怎样的联系 以及神经网络学习算法的 总体实现过程当我们在训练一个神经网络时 我们要做的第一件事 就是搭建网络的大体框架 这里我说的框架 意思是 神经元之间的连接模式 我们可能会从以下几种结构中选择 第一种神经网络的结构是 包含三个输入单元 五个隐藏单元 和四个输出单元 第二种结构是 三个输入单元作为输入层 两组五个隐藏单元作为隐藏层 四个输出单元的输出层 然后第三种是3 5 5 5 其中每个隐藏层包含五个单元 然后是四个输出单元 这些就是可能选择的结构 每一层可以选择 多少个隐藏单元 以及可以选择多少个隐藏层 这些都是你构建时的选择 那么我们该如何做出选择呢?首先 我们知道 我们已经定义了输入单元的数量 一旦你确定了特征集x 对应的输入单元数目 也就确定了 也就是等于特征x{i}的维度 输入单元数目将会由此确定 如果你正在进行 多类别分类 那么输出层的单元数目 将会由你分类问题中 所要区分的类别个数确定 值得提醒的是 如果你的多元分类问题 y的取值范围是在1到10之间 那么你就有10个可能的分类别忘了把你的y 重新写成向量的形式 所以现在我们的y不是一个数了 我们重新把y写成 这种形式的向量 第二个分类我们可以写成这样的向量 所以 比如说 如果要表达 第五个分类 也就是说y等于5 那么在你的神经网络中 就不能直接用 数值5来表达 因为这里的输出层 有十个输出单元 你应该用一个向量 来表示这个向量的第五个位置值是1 其它的都是0 所以对于输入单元 和输出单元数目的选择 还是比较容易理解的而对于隐藏单元的个数 单元的个数 以及隐藏层的数目 我们有一个默认的规则 那就是只使用单个隐藏层 所以最左边所示的 这种只有一个隐藏层的神经网络 一般来说是最普遍的或者如果你使用 不止一个隐藏层的话 同样我们也有一个默认规则 那就是每一个隐藏层 通常都应有相同的单元数 所以对于这个结构 我们有两个隐藏层 每个隐藏层都有相同的单元数 都是5个隐藏单元 这里也是一样 我们有三个隐藏层 每个隐藏层有相同的单元数 都是5个隐藏单元但实际上通常来说 左边这个结构是较为合理的默认结构而对于隐藏单元的个数 通常情况下 隐藏单元越多越好 不过 我们需要注意的是 如果有大量隐藏单元 计算量一般会比较大 当然 一般来说隐藏单元还是越多越好并且一般来说 每个隐藏层 所包含的单元数量 还应该和输入x 的维度相匹配 也要和特征的数目匹配 可能隐藏单元的数目 和输入特征的数量相同 或者是它的二倍 或者三倍 四倍 因此 隐藏单元的数目需要和其他参数相匹配 一般来说 隐藏单元的数目取为稍大于 输入特征数目 都是可以接受的 希望这些能够给你 在选择神经网络结构时 提供一些有用的建议和选择的参考 如果你遵循了这些建议 你一般会得到比较好的模型结构 但是 在以后的一系列视频中 特别是在我谈到 学习算法的应用时 我还会更详细地介绍 如何选择神经网络的结构 后面的视频中 我还会着重介绍 怎样正确地选择隐藏层的个数 以及隐藏单元的数目 等等下面我们就来具体介绍 如何实现神经网络的 训练过程 这里一共有六个步骤 这页幻灯片中罗列了前四步 剩下的两步 放在下一张幻灯片中 首先 第一步是构建一个 神经网络 然后随机初始化权值 通常我们把权值 初始化为很小的值 接近于零然后我们执行前向传播算法 也就是 对于该神经网络的 任意一个输入x(i) 计算出对应的h(x)值 也就是一个输出值y的向量接下来我们通过代码 计算出代价函数J(\theta)然后我们执行 反向传播算法来算出这些偏导数 或偏微分项 也就是 J(\theta)关于参数\theta的偏微分 具体来说 我们要对所有训练集数据 使用一个for循环进行遍历可能有部分同学之前听说过 一些比较先进的分解方法 可能不需要像这里一样使用 for循环来对所有 m个训练样本进行遍历 但是 这是你第一次进行反向传播算法 所以我建议你最好还是 使用一个for循环来完成程序 对每一个训练样本进行迭代 从x(1) y(1)开始 我们对第一个样本进行 前向传播运算和反向传播运算 然后在第二次循环中 同样地对第二个样本 执行前向传播和反向传播算法 以此类推 直到最后一个样本 因此 在你第一次做反向传播的时候 你还是应该用这样的for循环 来实现这个过程 其实实际上 有复杂的方法可以实现 并不一定要使用for循环 但我非常不推荐 在第一次实现反向传播算法的时候 使用更复杂更高级的方法所以具体来讲 我们对所有的 m个训练样本上使用了for循环遍历在这个for循环里 我们对每个样本执行 前向和反向算法具体来说就是 我们把x(i) 传到输入层 然后执行前向传播和反向传播这样我们就能得到 该神经网络中 每一层中每一个单元对应的 所有这些激励值a(l) 和delta项 接下来 还是在for循环中 让我画一个大括号 来标明这个 for循环的范围当然这些是octave的代码 括号里是for循环的循环体 我们要计算出这些delta值 也就是用我们之前给出的公式加上 delta(l+1)a(l)的转置矩阵 最后 外面的部分 计算出的这些delta值 这些累加项 我们将用别的程序 来计算出 这些偏导数项 那么这些偏导数项 也应该考虑使用 正则化项lambda值 这些公式在前面的视频中已经给出那么 搞定所有这些内容 现在你就应该已经得到了 计算这些偏导数项的程序了下面就是第五步了 我要做的就是使用梯度检查 来比较这些 已经计算得到的偏导数项 把用反向传播算法 得到的偏导数值 与用数值方法得到的估计值进行比较 因此 通过进行梯度检查来 确保两种方法得到基本接近的两个值通过梯度检查我们能确保 我们的反向传播算法 得到的结果是正确的 但必须要说明的一点是 我们需要去掉梯度检查的代码 因为梯度检查的计算非常慢最后 我们就可以 使用一个最优化算法 比如说梯度下降算法 或者说是更加高级的优化方法 比如说BFGS算法 共轭梯度法 或者其他一些已经内置到fminunc函数中的方法 将所有这些优化方法 和反向传播算法相结合 这样我们就能计算出 这些偏导数项的值到现在 我们已经知道了 如何去计算代价函数 我们知道了如何使用 反向传播算法来计算偏导数 那么 我们就能使用某个最优化方法 来最小化关于theta的函数值 代价函数J(\theta) 另外顺便提一下 对于神经网络 代价函数 J(\theta)是一个非凸函数 就是说不是凸函数 因此理论上是能够停留在 局部最小值的位置 实际上 梯度下降算法 和其他一些高级优化方法 理论上都能收敛于局部最小值但一般来讲 这个问题其实 并不是什么要紧的事 尽管我们不能保证 这些优化算法一定会得到 全局最优值 但通常来讲 像梯度下降这类的算法 在最小化代价函数 J(\theta)的过程中 还是表现得很不错的 通常能够得到一个很小的局部最小值 尽管这可能不一定是全局最优值 最后 梯度下降算法 似乎对于神经网络来说还是比较神秘 希望下面这幅图 能让你对梯度下降法在神经网络中的应用 产生一个更直观的理解这实际上有点类似 我们早先时候解释梯度下降时的思路 我们有某个代价函数 并且在我们的神经网络中 有一系列参数值 这里我只写下了两个参数值 当然实际上 在神经网络里 我们可以有很多的参数值 theta1 theta_2 等等 所有的这些都是矩阵 是吧 因此我们参数的维度就会很高了 由于绘图所限 我们不能绘出 更高维度情况的图像 所以这里我们假设 这个神经网络中只有两个参数值 实际上应该有更多参数那么 代价函数J(\theta) 度量的就是这个神经网络 对训练数据的拟合情况所以 如果你取某个参数 比如说这个 下面这点在这个点上 J(\theta) 的值是非常小的 这一点的位置所对应的 参数theta的情况是 对于大部分 的训练集数据我的假设函数的输出 会非常接近于y(i) 那么如果是这样的话 那么我们的代价函数值就会很小而反过来 如果我们 取这个值 也就是这个点对应的值 那么对于大部分的训练集样本 该神经网络的输出 应该是远离 y(i)的实际值的 也就是我们在训练集观测到的输出值 因此 像这样的点 右边的这个点 对应的假设就是 神经网络的输出值 在这个训练集上的测试值 应该是远离y(i)的 因此这一点对应着对训练集拟合得不好的情况 而像这些点 代价函数值很小的点 对应的J(\theta)值 是很小的 因此对应的是 神经网络对训练集数据 拟合得比较好的情况 我想表达的是 如果是这种情况的话 那么J(\theta)的值应该是比较小的因此梯度下降算法的原理是 我们从某个随机的 初始点开始 比如这一点 它将会不停的往下下降那么反向传播算法 的目的就是算出 梯度下降的方向 而梯度下降的过程 就是沿着这个方向 一点点的下降 一直到我们希望得到的点 在这里我们希望找到的就是局部最优点所以 当你在执行反向传播算法 并且使用梯度下降 或者 更高级的优化方法时 这幅图片很好地帮你解释了基本的原理 也就是 试图找到某个最优的参数值 这个值使得 我们神经网络的输出值 与y(i)的实际值 也就是训练集的输出观测值 尽可能的接近 希望这节课的内容能让你对 这些零散的神经网络知识 如何有机地结合起来 能有一个更直观的认识但可能你即使看了这段视频 你可能还是觉得 有许多的细节 不能完全明白 为什么这么做 或者说是这些是如何 联系在一起的 没关系神经网络和反向传播算法本身就是非常复杂的算法尽管我已经完全理解了 反向传播算法背后的数学原理 尽管我使用反向传播已经很多年了 我认为 这么多年的使用还算是成功的 但尽管如此 到现在我还是觉得 我自己也并不是总能 很好地理解反向传播到底在做什么 以及最优化过程是如何 使J(\theta)值达到最小值的 因为这本身的确是一个很难的算法 很难让你感觉到 自己已经完全理解 它不像线性回归 或者逻辑回归那样数学上和概念上都很简单 反向传播算法不是那样的直观如果你也有同感 那么完全不必担心 但如果你自己动手 完成一次反向传播算法 你一定会发现 这的确是一个很强大的 学习算法 如果你 执行一下这个算法 执行反向传播 执行其中的优化方法 你一定会发现 反向传播算法能够很好的 让更复杂 维度更大的 非线性的 函数模型跟你的数据很好地拟合 因此它的确是一种 最为高效的学习算法

自主驾驶(Autonomous Driving)

在本节课中,我想给你展示一个有趣而且有重要历史意义的利用神经网络进行自动驾驶的神经网络学习的例子,就是让汽车学会自己开车。

接下来我要展示的这个视频,是我从前同事 Dean Pomerleau 那里得到的。他现在美国东岸卡内基梅隆大学。在开始视频之前,我想告诉你视觉图像的样子。下面这里的左下方是汽车看到的在它前面的景象,在这里,你大约看到一条路,可能会有点向左,然后又有一点向右。在上面这里,这个第一个水平条,显示了由人工驾驶选择的方向。在这个位置,这个明亮的白色带,显示了人工驾驶的驾驶方向,你知道,这里,远远的左边,对应着用力向左转方向盘;而这里,对应用力向右转方向盘。所以在这个一点点向左,在中心左侧一点的位置,意味着在这一点上,人工驾驶在稍微向左边转方向盘。在这里,这第二个亮带,对应着机器学习算法选择的方向。这种白色带的位置意味着神经网络在此选择稍微向左的驾驶方向。事实上,在神经网络开始学习之前,你可以看到, 网络输出一个灰色带,像一个均匀的灰色带,充满整个区域的一种灰色绒,这对应于随机初始化的神经网络。也就是说,起初不知道如何驾驶汽车,或者起初不知道要向什么方向驾驶。只有在它学习了一段时间后,它才会在只是一小段区间输出一道实心的白色亮带,这对应着选择一个特定的驾驶方向。这对应于当神经网络在一个特定的位置选择一条带时更加自信,不是输出一种浅灰色的绒状带,而是输出一条白色带,也就是不断地选择自己的驾驶方向。

ALVINN 是一种人工神经网络系统,它通过看人驾驶学习驾驶。ALVINN 是用来控制 NAVLAB 2 的,NAVLAB 2 是改装过的军用悍马,它把传感器,电脑以及驱动器用于自主导航的实验。配置 ALVINN 的最初步骤是在这里建立一个网络。在训练期间,一个人驾驶汽车,而 ALVINN 在观看。每两秒钟,ALVINN 将前方道路的视频图像数字化,并记录此人的转向方向。这个培训图像的分辨率被降低到像素为 30 乘 32,并提供给 ALVINN 的三层网络作为输入。利用反向传播学习算法,ALVINN 正在训练,以输出与人驾驶相同的转向方向。最初,网络转向的反应是随机的,经过大约两分钟的训练后,网络学会了准确模仿人类驾驶员的转向反应。同样的训练步鄹被重复到其他类型的路上。在网络被训练好之后,操作员按下运行开关,然后 ALVINN 开始开车。每一秒钟,ALVINN 进行十二次图像数字化,并输入到它的神经网络层。每一个网络,并行运行,产生一个转向方向,并衡量其对其反应的信心。从最自信的网络中得到的转向方向,这里该网络是在单车道上训练的网络,被用来控制车辆。突然一个十字路口出现在车的前面。当车辆接近十字路口时,单车道网络的置信度在降低。当它穿行十字路口,前方两条车道的道路进入视线时,双车道网络的信心上升。当它的信心上升后,双车道网络被选择进行驾驶。安全地引导车辆进入两条车道中它应该行驶的车道。这就是使用神经网络进行自动驾驶。当然,现在有更多,更现代的自动驾驶的尝试。在美国,欧洲,还有其他地区,有比这更强大的驾驶控制器,但我认为,经过反向传播训练的神经网络可以学习并较好地驾驶汽车,还是相当显著相当惊人的。

posted @ 2019-12-08 13:56  KerShaw  阅读(662)  评论(0编辑  收藏  举报