机器学习模型的确立过程中有两个主要环节。

(1)确定选用什么类型的模型。

(2)确定模型的具体参数。

先聚焦于第一个问题。

3.3.1 确定线性回归模型

对于这个案例,使用什么模型我们早就心中有数了。虽然上图中的函数直线并未精确无误地穿过每个点,但已经能够反映出特征(也就是微信公众号广告投放金额)和标签(也就是商品销售额)之间的关系,拟合程度还是挺不错的。

这个简单的模型就是一元线性函数(如右图所示):

一元线性函数

y=ax+b

其中,参数a的数学含义是直线的斜率(陡峭程度),b则是截距(与y轴相交的位置)。

在机器学习中,会稍微修改一下参数的代号,把模型表述为:

y=wx+b

此处,方程式中的a变成了w,在机器学习中,这个参数代表权重。因为在多元变量(多特征)的情况下,一个特征对应的w参数值越大,就表示权重越大。而参数b,在机器学习中称为偏置。

不要小看这个简单的线性函数,在后续的机器学习过程中,此函数会作为一个基本运算单元反复地发挥威力。

咖哥发言

小冰提问:“咖哥,说到模型的参数,我也看过一些文档,经常听见有人说西塔、西塔(θ)什么的,这是怎么一回事儿?”

咖哥解释:“有些机器学习教程中,用θ(读作theta)表示机器学习的参数,也会使用θ0θ1来代表此处的wb,还有用其他字母表示机器学习参数的情况。我觉得此处使用wb来表示这些参数会使它们的意义更清晰一些:weight是权重,bias是偏置,各取首字母。你们看其他机器学习资料的时候,要懂得θ0θ1和这里的wb其实是一回事儿。”

3.3.2 假设(预测)函数——h(x)

确定以线性函数作为机器学习模型之后,我们接着介绍假设函数的概念。先来看一个与线性函数稍有差别的方程式:

y'=wx+b

也可以写成:

hx)=wx+b

其中,需要注意以下两点。

y'指的是所预测出的标签,读作y帽(y-hat)或y撇。

hx)就是机器学习所得到的函数模型,它能根据输入的特征进行标签的预测。

我们把它称为假设函数,英文是hypothesis function(所以选用首字母h作为函数符号)。

小冰疑惑了:“这不就是线性函数吗?为什么又要叫假设函数hx)?”

咖哥笑答:“这的确就是线性函数。不过,机器学习的过程,是一个不断假设、探寻、优化的过程,在找到最佳的函数fx)之前,现有的函数模型不一定是很准确的。它只是很多种可能的模型之中的一种—因此我们强调,假设函数得出的结果是y',而不是y本身。所以假设函数有时也被叫作预测函数(predication function)。在机器学习中看到hx)、fx)或者px),基本上它们所要做的都是一回事,就是根据微信公众号广告投放金额x推断(或预测)销售额y'。”

所以,机器学习的具体目标就是确定假设函数hx)。

■确定b,也就是y轴截距,这里称为偏置有些机器学习文档中,称它为w0(或θ0)。

■确定w,也就是斜率,这里称为特征x的权重,有些机器学习文档中,称它为w1(或θ1)。

一旦找到了参数wb的值,整个函数模型也就被确定了。那么这些参数wb的具体值怎么得到呢?

3.3.3  损失(误差)函数——L(w,b)

在继续寻找最优参数之前,需要先介绍损失和损失函数。

如果现在已经有了一个假设函数,就可以进行标签的预测了。那么,怎样才能够量化这个模型是不是足够好?比如,一个模型是3x+5,另一个是100x+1,怎样评估哪一个更好?

这里就需要引入损失(loss)这个概念。

损失,是对糟糕预测的惩罚。损失也就是误差,也称为成本(cost)或代价。名字虽多,但都是一个意思,也就是当前预测值和真实值之间的差距的体现。它是一个数值,表示对于单个样本而言模型预测的准确程度。如果模型的预测完全准确,则损失为0;如果不准确,就有损失。在机器学习中,我们追求的当然是比较小的损失。

不过,模型好不好还不能仅看单个样本,而是要针对所有数据样本找到一组平均损失“较小”的函数模型。样本的损失的大小,从几何意义上基本上可以理解为yy'之间的几何距离。平均距离越大,说明误差越大,模型越离谱。如右图所示,左边模型所有数据点的平均损失很明显大过右边模型。

左边是平均损失较大的模型,右边是平均损失较小的模型

因此,针对每一组不同的参数,机器都会针对样本数据集算一次平均损失。计算平均损失是每一个机器学习项目的必要环节。

损失函数(loss function)Lwb)就是用来计算平均损失的。

咖哥发言

有些地方把损失函数记作Jθ),也叫代价函数成本函数(cost function)。刚才说过, θ就是wbJθ)就是Lwb),符号有别,但意思相同。

这里要强调一下:损失函数L是参数wb的函数,不是针对x的函数。我们会有一种思维定势,总觉得函数一定是表示xy之间的关系。现在需要大家换一个角度去思考问题,暂时忘掉xy,聚焦于参数。对于一个给定的数据集来说,所有的特征和标签都是已经确定的,那么此时损失值的大小就只随着参数wb而变。也就是说,现在xy不再是变量,而是定值,而wb在损失函数中成为了变量

“这里有点不好理解,大家能听得懂吗?”咖哥问。

其中一位同学思考了一下,说:“大概还跟得上你的思路,接着讲吧。”

计算数据集的平均损失非常重要,简而言之就是:如果平均损失小,参数就好;如果平均损失大,模型或者参数就还要继续调整。

这个计算当前假设函数所造成的损失的过程,就是前面提到过的模型内部参数的评估的过程。

机器学习中的损失函数很多,主要包括以下几种。

■用于回归的损失函数。

□均方误差(Mean Square Error,MSE)函数,也叫平方损失或L2损失函数。

□平均绝对误差(Mean Absolute Error,MAE)函数,也叫L1损失函数。

□平均偏差误差(mean bias error)函数。

■用于分类的损失函数。

□交叉熵损失(cross-entropy loss)函数。

□多分类SVM损失(hinge loss)函数。

一般来说,选择最常用的损失函数就可以达到评估参数的目的。下面给出线性回归模型的常用损失函数—均方误差函数的实现过程。

■首先,对于每一个样本,其预测值和真实值的差异为(yy'),而y'=wx+b,所以损失值与参数wb有关。

■如果将损失值(yy')夸张一下,进行平方(平方之后原来有正有负的数值就都变成正数),就变成(yy'2。我们把这个值叫作单个样本的平方损失。

■然后,需要把所有样本(如本章示例一共记录了200周的数据,即200个样本)的平方损失都相加,即(yx(1))−y'x(1)))2+(yx(2))−y'x(2)))2+…+(yx(200)))−y'x(200)))2

写成求和的形式就是:

咖哥发言

同学们注意一下,此处公式里带小括号的上标x(1),代表样本的维度索引,即整个数据集中的第几个样本。那么大家是否还记得x1中的下标代表什么?那是标签的维度索引,即第几个标签。这个例子中目前只有一个标签,因此省略了下标。

■最后,根据样本的数量求平均值,则损失函数L为:

关于以上公式,说明以下几点。

■(xy)为样本,x是特征(微信公众号广告投放金额),y是标签(销售额)。

hx)是假设函数wx+b,也就是y'

D指的是包含多个样本的数据集。

N指的是样本数量(此例为200)。N前面还有常量2,是为了在求梯度的时候,抵消二次方后产生的系数,方便后续进行计算,同时增加的这个常量并不影响梯度下降的最效结果。

■而L呢,对于一个给定的训练样本集而言,它是权重w和偏置b的函数,它的大小随着wb的变化而变

下面用Python定义一个MSE函数,并将其封装起来,以后会调用它。

咖哥发言

其实,MSE函数也不需要我们自己写代码来实现,直接调用Python数学库函数也是可以的,但这是我们的第一个项目,多练练手吧。

还有一点要告诉大家的,使用MSE函数做损失函数的线性回归算法,有时被称为最小二乘法

下面是本例的核心代码段之一:

def loss_function(X, y, weight, bias): # 手工定义一个均方误差函数

y_hat = weight*X + bias # 这是假设函数, 其中已经应用了Python的广播功能

loss = y_hat-y # 求出每一个y'和训练集中真实的y之间的差异

cost = np.sum(loss**2)/2*len(X) # 这是均方误差函数的代码实现

return cost # 返回当前模型的均方误差值

其中,利用了Python的广播功能以及向量化运算。下面是代码中涉及的内容。

■在weight*X + bias中,X是一个2D张量,共200行,1列,但是此处X可以直接与标量weight相乘,并与标量bias相加,之后仍然得到形状为(200,1)的2D张量。在运行期间weight和bias自动复制自身,形成X形状匹配的张量。这就是上一课中讲过的广播。

y_hat是上面广播计算的结果,形状与标签集y相同。同学们如果对当前张量形状有疑惑,可以通过shape方法输出其形状。y_hat可以和y进行直接的向量化的加减运算,不需要任何for循环参与。这种向量化运算既减少了代码量,又提高了运算效率。

■损失函数代码中的loss或者cost,都代表当前模型的误差(或称为损失、成本) 值。

np.sum(loss**2)/2*len(X)是MSE函数的实现,其中包含以下内容。

■loss**2代表对误差值进行平方。

■sum(loss**2)是对张量所有元素求和。

■len(X)则返回数据集大小,例如200。

有了这个损失函数,我们就可以判断不同参数的优与劣了。MSE函数值越小越好,越大就说明误差越大。

下面随便设定了两组参数,看看其均方误差大小:

print ("当权重为5, 偏置为3时, 损失为:",

loss_function(X_train, y_train, weight=5, bias=3))

print ("当权重为100, 偏置为1时, 损失为:",

loss_function(X_train, y_train, weight=100, bias=1))

调用刚才定义好的损失函数,运行后结果如下:

当权重为5,偏置为3时,损失为:25.592781941560116

当权重为100,偏置为1时,损失为:3155.918523006111

因此,线性函数y=3x+5相对于线性函数y=100x+1而言是更优的模型。

同学们纷纷表示基本理解了损失函数的重要性。但小冰提出一个疑问:“这个MSE函数,为什么非要平方呢?yy'就是预测误差,取个绝对值之后直接相加不就行了吗?”

咖哥表扬道:“好问题,这个疑惑我以前也曾经有过。均方损失函数,并不是唯一可用的损失函数。为什么这里要选用它呢?如果目的仅是计算损失,把误差的绝对值加起来取平均值就足够了(即平均绝对误差函数)。但是之所以还要平方,是为了让Lwb)形成相对于wb而言的凸函数,从而实现梯度下降。下面马上就要讲到这个关键之处了。”