通过上一篇文章,我们学会了一个简单的感知器,了解了阶跃函数(更喜欢叫二分类,简单明了哈哈),还有训练感知器的感知器规则。在这里学习另一种感知器——线性单元,通过此线性单元来了解机器学习的一些基本概念, 比如模型,目标函数,算法优化等。以此来简单了解机器学习。
一、线性单元
对与上一节说讲的感知器,在对线性不可分的数据集,之前的感知器规则是无法收敛的,在此时是无法来训练感知器的,所以在为了解决这个问题时,找到了一个可导的线性函数来替代感知器的阶跃函数,这种感知器就叫线性单元。线性单元在面对线性不可分的数据集时,会收敛到一个最佳的近似值。
在这里我们假设一个简单的线性单元的激活函数f: f(x) = x
该线性单元表示如下:
对比上一节的:
替换了激活函数f之后, 线性单元返回的就是一个实数值了,而不是二分类0,1了,所以线性单元是用来解决回归问题而不是分类的。
二、线性单元模型
说的是模型其实就是函数(ps: 我感觉是这样,模型说起来高大上一点~~哈哈)。
在实际的现实生活中,我们根据的输入的x值来预测输出y的算法。比如,x可以是一个人的工作年限, y是他的月薪, 我们可以根据某种算法来根据一个人的工作年限来预测他的收入。比如:y = h(x) = w*x +b
函数 h(x) 为假设, 而w, b 是他的参数。 假设w = 1000, b= 500, x为一个人的工作年限,代入上面的模型,预测出他的月薪为5500。这样的模型有点不靠谱,,因为没考虑其他的因素,考虑的只是工作年限,当把工作年限,行业,公司,职级这些信息,称之为特征。对于一个工作了3年的,在IT行业,阿里工作,职级T3的人, 可以用特征向量来表示
X = (3, IT, 阿里,T3)
此时的输入X变成了一个具备四个特征的向量,相对的,只有一个参数w就不可以了,还需要3个参数,就一共4个参数(w1, w2,w3,w4)数字是下标,每个特征对应一个参数。此时的模型就成了:
y = h(x) = w1 * x1+ w2 *x2 + w3 * x3 + w4 * x4 + b
x1: 工作年限 x2: 对应的行业
x3: 对应的公司 x4: 对应职级
此时,令w0等于b, w0对应特征x0, 因为x0并不存在, 我们可以令x0 = 1,即:
b = w0 * x0 其中 x0 = 1
这样上面的公式就变成下面的了:
y = h(x) = w1 * x1+ w2 *x2 + w3 * x3 + w4 * x4 + b (1)
=w0 * x0 + w1 * x1+ w2 *x2 + w3 * x3 + w4 * x4 (2)
写成向量的模式:
上面的式子,函数模型就称为线性模型, 输出y就是输入特征x1, x2, x3,...的线性组合。
三、监督学习和无监督学习
有了模型了, 但是如何训练该模型??,参数w到底该如何选取??
监督学习:它是机器学习的一类学习方法,它是为了训练一个模型,提供了一大堆的样本,这些样本包括输入的特征X,也包应的输出y(y也叫做标记, label)。也就是说,我们要知道很多人的数据,他们都有这些特征:工作年限,行业,公司,职级,以及他们的收入。我们用这些样本来训练模型, 让模型知道每个输入的特征(X), 也知道对应问题的答案(标记y)。模型通过这些样本(足够多),来总结规律,然后来预测那些没有看到过的输入(X),所对应的答案。
无监督学习:这种方法的训练样本中只有X没有y, 模型可以总结出特征x的一些规律,但是无法知道其对应的答案y。(即你给出输入x, 会有一个输出y, 但是你不知道这个y的值是不是对的)
很多时候,有x又有y的样本很少的, 大部分样本只有x。比如在语音到文本(STT)的识别任务中, x是语音, y是该段语音对应的文本。语音我们可以获取大量的数据,但是把语音转化为文本,并标注上对应的文字则是非常费时间的。此时为了弥补标注样本的不足, 我们可以用无监督学习方法先做一些聚类,让模型总结出哪些音节是相似的,然后在用少量的带标注的训练样本,告诉模型其中一些音节对应的文字。此时模型就可以把相似的音节都对应到相似的文字上,完成模型的训练。
四、线性单元的目标函数
只考虑监督学习:
在监督学习下, 对与一个样本,我们知道它的特征X,以及标记y。同时根据模型h(x)计算得到输出
。这里的y表示的是训练样本里面的标记,也就是实际值;带上划线的
表示模型计算出来的预测值。如果y和
的值特别接近,则该模型就很好了。那么如何来表示
和y的值相近,我们可以用
和y的差的平凡和的1/2来表示:
e: 单个样本的误差(1/2方便计算)
训练数据中会有很多样本,当有N个时,我们可以用训练样本中所有样本的误差的和,来表示模型的误差E,如下:
上面的
表示第一个样本的误差,后续表示第二个,一直到最后一个。。。。。
写成和的形式:
上式2中,
表示第i个训练样本的特征,
表示第i个样本的标记,在这里可以用元组
表示第i个训练样本
则是模型对第i个样本的预测值。对于一个训练集数据来说,当误差越小的时候,模型越好,对于特定的训练数据集来说,
的值都是已知的, 所以对于式子2来说就变成了参数w的函数。
综上所述,模型的训练,实际上就是取到合适的w,使得式子2的值最小。取最小值,就变成了数学上的优化问题,而E(w)就是优化目标,为我们的目标函数。
四、梯度下降优化算法
在学数学的时候,我们通过求函数的极值。就y=f(x) 的极值点,就是求它的导数
的那个店。所以我们可以通过解方程
,来得到函数的极值点
。
对于计算机来说,它通过自己的计算来把极值点找出来。如下:
首先我们随便选择一个点,假设改点为x0点,接下来每次迭代修改x为x1, x2, x3, ......经过很多次的迭代,到达函数的最小值点。
我们每次修改x的值,都需要往函数最小值的方向前进,就需要向函数y = f(x)的梯度的相反方向来修改x。 梯度:是一个向量,它指向函数值上升最快的方向。所以梯度的反方向就是函数值下降最快的方向。所以每次沿着梯度反方向去修改x的值,就可以走到函数的最小值附近,之所以是最小值附近而不是最小值点,是因为每次移动的步长不会会恰到好处,有可能最后一次迭代走远了直接越过了最小值点。步长的选取:选择小了,那么就会迭代很多轮才能走到最小值附近;如果选择大了,那可能就会越过最小值很远,收敛不到一个好的点上。
给出梯度下降算法:
:梯度算子
:指的是f(x)的梯度
:步长(学习速率)
对应的上面的目标函数(式子2)可以改写成:
梯度下降算法可改写成:
同时如果求取最大值, 就可以使用梯度上升算法,它的参数修改规则如下:
此时需要求取
然后代入
得到线性单元的参数规则。
求取到的目标函数
的梯度是:
最终的线性单元的参数修改规则如下:
此时就可以用该函数来写出训练线性单元的代码了。
需要说明的是,如果每个样本有M个特征,则上式中x, w的都是M+1维向量(因为我们加上了一个恒为1的虚拟特征x0,参考前面的内容),而y是标量。用数学符号表示,就是
也即, w, x是M+1维列向量,式子3可以写成
五、目标函数
的推导
学过数学的同志,知道的不知道的,在这里告诉大家, 函数的梯度的定义就是相对于各个变量的偏导数,
如下:
下来求解11, 首先导数的和就等于和的导数(细节不说了,自行百度,累死快~~),所以先把求和符号
里面的导数求出来,在相加如下:
求导,如下:
通过上面的我们知道,y是与w无关的常数,而
通过连式法则来求导(复合函数的求导):
分别计算上式等号右边的两个偏导数
代入,求和
里面的偏导数是:
mamaya~~终于完了,leiskr个。
六、随机梯度下降算法(Stochastic Gradient Descent, SGD)
如果更具第四节中的式子3来训练模型(DGD),在每次迭代W时, 要遍历数据中的所有样本,称这种叫做批梯度下降(Batch Gradient Descent)。
但是当样本特别特别大的时候,数据量达到百万到数亿的时候,常常用的是SDG算法。在SGD算法中,每次更新w的迭代,只计算一个样本。这样对于一个具有数百万样本的训练数据,完成一次遍历就会对w更新数百万次,效率大大提升。由于样本的噪音和随机性,每次更新w并不一定按照减少E的方向。然而,虽然存在一定随机性,大量的更新总体上沿着减少E的方向前进的,因此最后也能收敛到最小值附近。下图展示了SGD和BGD的区别:
如上图, 椭圆表示的是函数值的等高线,椭圆中心是函数的最小值点。红色是BGD的逼近曲线,而紫色是SGD的逼近曲线。我们可以看到BGD是一种向着最低点前进的, 虽然SDG波动较大,但最终在总体上任然是向着最低点逼近的。
最后需要说明的是,SGD不仅仅效率高,而且随机性有时候反而是好事。今天的目标函数是一个『凸函数』,沿着梯度反方向就能找到全局唯一的最小值。然而对于非凸函数来说,存在许多局部最小值。随机性有助于我们逃离某些很糟糕的局部最小值,从而获得一个更好的模型。
七、实现线性单元
对比之前的感知器模型:
通过上图比较,发现除了激活函数f不同之外,两者的模型和训练规则是一样的(在上表中,线性单元的优化算法是SDG算法)。所以此时我们只需要把感知器的激活函数进行替换即可。
通过继承上节的Perceptron,来实现线性单元:
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2019/4/29 15:23
# @Author : xhh
# @Desc :
# @File : test_linearModel.py
# @Software: PyCharm
from test_perceptorn import Perceptron
# 定义激活函数
f = lambda x: x
class LinearUnit(Perceptron):
def __init__(self, input_num):
"""
初始化线性单元,设置输入参数的个数
:param input_num:
"""
Perceptron.__init__(self, input_num,f)
模拟一些数据,来测试:
def get_training_dataset():
"""
假设5个人的收入数据
:return:
"""
# 构建训练数据
# 输入向量列表,每一项都是工作年限
input_vecs = [[5],[3],[8],[1.4],[10.1]]
# 期望的输出列表,月薪,注意要与输入一一对应
labels = [5500, 2300, 7600,1800,11400]
return input_vecs, labels
def train_linear_unit():
"""
使用数据训练线性单元
:return:
"""
# 创建感知器,输入参数的特征为1(工作年限)
lu = LinearUnit(1)
# 训练,迭代10轮,学习速率为0.01
input_vecs, labels = get_training_dataset()
lu.train(input_vecs, labels, 10, 0.01)
# 返回训练好的线性单元
return lu
def plot(linear_unit):
import matplotlib.pyplot as plt
input_vecs, labels = get_training_dataset()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(map(lambda x:x[0], input_vecs), labels)
weights = linear_unit.weight
bias = linear_unit.bias
x = range(0, 12, 1)
y = map(lambda x:weights[0] * x + bias, x)
ax.plot(x, y)
plt.show()
if __name__ == '__main__':
"""
训练线性单元
"""
linear_unit = train_linear_unit()
# 打印训练获得的权重
print(linear_unit)
# 测试
print('工作3.6年,月收入 = %.2f'% linear_unit.predict([3.4]))
print('工作10年,月收入 = %.2f'% linear_unit.predict([10]))
print('工作6.3年,月收入 = %.2f'% linear_unit.predict([6.3]))
plot(linear_unit)
运行结果如下:
拟合的直线如下图:
总结:
通过上面所写的,得出机器学习算法其实只要两部分:
1、模型 从输入特征x预测输出y的函数h(x)
2、目标函数 目标函数取最小(最大)值时所对应的参数值,就是模型的参数的最优值。但通常我们只能获取得到目标函数的局部最小(最大)值,因此我们只能得到模型参数的局部最优值。
3、接下来,用优化算法去求取目标函数的最小(最大)值、【随机】梯度{下降|上升}算法就是一个优化算法。针对一个目标函数,不同的优化算法会推出不同的训练规则。
参考资料:
https://www.zybuluo.com/hanbingtao/note/448086
大家可以关注我和我小伙伴的公众号~~~这里有我和我的小伙伴不定时的更新一些python技术资料哦!!大家也可以留言,讨论一下技术问题,希望大家多多支持,关注一下啦,谢谢大家啦~~
本文分享自 Python爬虫scrapy 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!