标签 人工智能 下的文章

前言

在我们介绍人工神经元的时候提到了人工神经元模型是模仿生物体的神经元进行设计的模型。在那一篇文章中我们了解到生物神经元中的电信号在达到阈值时才会输出电信号给下一个神经元。人工神经元为了模仿生物神经元这一特征在人工神经元中加入了激活函数(Activation functions)

这篇文章你将会了解:

  • 什么是激活函数
  • 常用的激活函数
  • 使用python编写带有激活函数的神经元完成非线性回归

什么是激活函数

由于我们之前的神经元只有一段线性函数y=wx+b,没有激活函数的神经网络实质上是一个线性回归模型,只能解决线性可分的问题,而对于线性不可分的任务我们之前的神经元就无能为力了,这时候我们就引入了激活函数,使得我们的函数变得不线性也就是变成非线性函数,这可以增加模型泛化能力。

例如我们不可能用一条直线去拟合这种分布的数据:

而曲线可以

所以激活函数能够帮助你的神经元完成更加复杂的工作。

并且我们人类思考问题的过程并不是完美的拟合,而是离散的分类,我们会给食物能否吃饱分成多类:能吃饱,不能吃饱,能吃几分饱(这也是我们根据经验得出的新类),而我们并不会去使用一个食物的大小和饱腹程度的函数去判断是否能吃饱。

我们把之前线性函数的输出放入激活函数中计算后的值做出最后的输出

常见的激活函数

sigmoid

$$ sigmoid(x) = \frac{1}{1+e^{-x} } $$

sigmoid激活函数特点:

  • 把(−∞,+∞)的数映射到(0,1)之间,因此它对每个神经元的输出进行了归一化;
  • Sigmoid 函数非常合适用于将预测概率作为输出的模型。因为概率的取值范围是 0 到 1。
  • 函数处处可导。
  • 函数很快逼近y=0和y=1,导数无限小,这会导致权重更新的非常慢
  • 一般用于二分类的输出层

sigmoid的导函数

$$ \frac{\partial sigmoid(x)}{\partial x} = sigmoid(x)(1-sigmoid(x)) $$

Tanh

$$ Tanh(x) = \frac{e^{x}-e^{-x}}{e^{x}+e^{-x} } $$

Tanh激活函数特点:

  • 函数是将取值为 (−∞,+∞) 的数映射到(−1,1) 之间;
  • 在0附近的导数相比sigmoid更大,收敛速度比sigmoid快
  • 函数处处可导。
  • 函数很快逼近y=0和y=1,导数无限小,这会导致权重更新的非常慢

Tanh的导函数

$$ \frac{\partial Tanh(x)}{\partial x} = 1-Tanh(x)^{2} $$

ReLU

$$ ReLU(x) = \begin{cases} 0 & x\leqslant 0 \\ x & x>0 \end{cases} $$

ReLU激活函数特点:

  • 计算简单高效,相比sigmoid、tanh没有指数运算
  • 相比sigmoid、tanh更符合生物学神经激活机制
  • 收敛速度较快,大约是 sigmoid、tanh 的 6 倍
  • 在x<0时导数为0,这会导致权重参数无法得到更新,这被称为神经元死亡,或者梯度消失

ReLU的导函数

$$ \frac{\partial ReLU(x)}{\partial x} = \begin{cases} 0 & x\leqslant 0 \\ 1 & x>0 \end{cases} $$

使用python编写带有激活函数的神经元完成非线性回归

只使用Sigmoid完成

# 导入numpy库
import numpy as np
from matplotlib import pyplot as plt


def sigmoid(x):
    return 1/(1+np.exp(-x))


def sigmoid_deriv(a):
    return a*(1-a)


def getdata(count):
    """获取指定数量的数据"""
    xs = np.random.rand(count)
    xs = np.sort(xs)
    ys = np.zeros(count)
    for i in range(count):
        x = xs[i]
        yi = 0.7*x+(0.5-np.random.rand())/50+0.5
        if yi > 0.8:
            ys[i] = 1
    return xs, ys


data = getdata(100)
xs = data[0]
ys = data[1]

w = np.random.rand(1)
b = np.random.rand(1)
z = w*xs+b
a = sigmoid(z)

plt.xlim(-0.1, 1)
plt.ylim(-0.1, 3)
plt.scatter(xs, ys)
plt.plot(xs, a)
plt.show()

for j in range(1000):
    for i in range(len(xs)):
        x = xs[i]
        y = ys[i]
        # 前向传播
        z = w*x+b
        a = sigmoid(z)#加入激活函数
        e = (y - a)**2

        alpha = 0.05

        # 反向传播
        deda = -2*(y-a)
        dadz = sigmoid_deriv(a)#加入激活函数后本质还是复合函数求导
        dzdw = x
        dzdb = 1

        dedw = deda*dadz*dzdw
        w = w - alpha*dedw
        dedb = deda*dadz*dzdb
        b = b - alpha*dedb

z = w*xs+b
a = sigmoid(z)
plt.xlim(0, 1)
plt.ylim(0, 3)
plt.scatter(xs, ys)
plt.plot(xs, a)
plt.show()

在上一篇文章中我们使用了化简后的Rosenblatt感知器进行回归预测,在这篇文章中我们将了解损失函数、梯度下降算法以及梯度下降算法的的实现,且加入偏置项系数b。

损失函数

损失函数(Loss Function):定义在单个样本上,算的是一个样本的误差.

代价函数(Cost Function):定义在整个训练集上,算的是所有样本的误差,也就是损失函数的平均。

机器学习中几乎所有的模型都会有损失函数,损失函数描述的是:

预测值和样本数据的实际目标值之间的误差与预测函数的系数之间的关系

均方误差

均方误差代价函数其表达式如下:

$$ e(w,b) = \frac{1}{n}\sum_{i=0}^{n}(y_{i}-(wx_{i}+b))^2 $$

其中y_i表示样本数据的实际目标值表示wx_i+b预测值根据样本数据x_i计算出的预测值。

我们可以发现这个图像是一个开口向上的二元二次函数图像,既然是一个开口向上的二元二次函数,那么我们是不是可以找到一个wb使得整体误差最小(全局最优解)呢?是的在机器学习中正是这样。

寻找最低点的方法有

  • 正规方程

    $$ w=\frac{\sum_{i=0}^{n}(x_{i}y_{i})}{\sum_{i=0}^{n}x_{i}^2} $$

    推导过程是使用了二元一次函数的顶点坐标公式

  • 梯度下降

梯度下降

梯度下降(Gradient descent)的可以类比为一个下山的过程,如图所示函数看似为一座山,山中全是雾,有一个人在山上任意一个位置想要快速找到水,由于山上全是雾,人只能看见脚下的路,那么人可以判断脚下土地的坡度判断自己是否为下坡路,每走一步调整自己的方向,每次向坡度最大的方向走,就走到最低点的位置喝到水。

数学中实现

在数学中具有一个概念叫做梯度,梯度描述的就是一个面上某个点的瞬时变化率。和斜率类似,其实梯度就是斜率更广的说法。

既然描述的是面上某个点的瞬时变化率,那么我们就可以对他进行求导。我们要得到w最小同时b最小的一个点,我们只需要分别对w和b求偏导,当某个点的梯度大于零,对应的偏导数大于零我们只需要让对应的值减去alpha(alpha>0)倍的偏导数,偏导数为正,对应值往小的调整;当某个点的梯度小于零,对应的偏导数小于零我们只需要让对应的值减去alpha(alpha>0)倍的偏导数,偏导数为负,对应值往大的调整。

  • 为什么要在偏导数上乘以一个alpha

    alpha叫做学习率,在上一篇文章中遇到过。在调整w和b的过程中如果没有学习率alpha它将可能无法或者很慢的回到最低点,乘以一个alpha可以加快或者调慢速度

$$ \xi =\xi -\alpha \times \frac{\partial f(\xi )}{\partial \xi } $$

随机梯度下降算法

随机梯度下降算法(SGD)取出其中一个样本的数据依次进行梯度下降

反向传播

我们已经知道了梯度下降算法,但是我们如何获得求得损失函数中w和b的偏导呢。其实高中数学足以

观察公式:

$$ e(w,b) = (y_{i}-(wx_{i}+b))^2 $$

使用复合函数的求导法则:

$$ \frac{\partial e}{\partial w}=2(y_{i}-b-wx_{i})\cdot (-x_{i}) $$

$$ \frac{\partial e}{\partial b}=2(y_{i}-b-wx_{i})\cdot (-1) $$

调整w和b

$$ w =w -\alpha \times \frac{\partial e}{\partial w } $$

$$ b =b -\alpha \times \frac{\partial e}{\partial b } $$

代码实现

将使用SGD实现

首先先引入需要用到的库

import numpy
from matplotlib import pyplot as plt

引入numpy数学库以方便我们的数学计算

引入matplotlib中的pyplot模块进行画图操作

生成数据以便进行训练

def getdata(count):
    """获取指定数量的数据"""
    x = np.random.rand(count)  # 生成区间[0,1)的随机数
    x = np.sort(x)  # 进行从小到大排序
    y = [-1.5*xx+np.random.rand()/3+1 for xx in x]  # 使用列表推导式生成对应的值
    return x, y

创建一个名为getdata的函数随机生成有共同特征的数据,有一个参数count来接收获取数据的数量

获取100个数据

data = getdata(100)
xs = data[0]
ys = data[1]

编写预测函数

w = np.random.rand(1)
b = np.random.rand(1)
z = w*xs+b

绘制图像

plt.xlim(0, 1)
plt.ylim(0, 3)
plt.scatter(xs, ys)
plt.plot(xs, z)
plt.show()

随机梯度下降算法和反向传播

for j in range(500):
    for i in range(len(xs)):
        x = xs[i]
        y = ys[i]

        z = w*x+b
        e = (y - z)**2#损失函数
        alpha = 0.05
        
        #反向传播和随机梯度下降
        dedz = -2*(y-z)
        dzdw = x
        dzdb = 1
        dedw = dedz*dzdw
        w = w - alpha*dedw
        dedb = dedz*dzdb
        b = b - alpha*dedb
        
        """
        你也可以这么写
        dedw = -2*(y-z)*x
        w = w - alpha*dedw
        dedb = -2*(y-z)*1
        b = b - alpha*dedb
        """

再次绘制拟合后的图像

z = w*xs+b
plt.xlim(0, 1)
plt.ylim(0, 3)
plt.scatter(xs, ys)
plt.plot(xs, z)
plt.show()

可以看到已经完美拟合

完整代码

# 导入numpy库
import numpy as np
from matplotlib import pyplot as plt


def getdata(count):
    """获取指定数量的数据"""
    x = np.random.rand(count)  # 生成区间[0,1)的随机数
    x = np.sort(x)  # 进行从小到大排序
    y = [-1.5*xx+np.random.rand()/3+1 for xx in x]  # 使用列表推导式生成对应的值
    return x, y


data = getdata(100)
xs = data[0]
ys = data[1]

w = np.random.rand(1)
b = np.random.rand(1)
z = w*xs+b

plt.xlim(0, 1)
plt.ylim(0, 3)
plt.scatter(xs, ys)
plt.plot(xs, z)
plt.show()

for j in range(500):
    for i in range(len(xs)):
        x = xs[i]
        y = ys[i]

        z = w*x+b
        e = (y - z)**2
        alpha = 0.05

        dedz = -2*(y-z)
        dzdw = x
        dzdb = 1

        dedw = dedz*dzdw
        w = w - alpha*dedw
        dedb = dedz*dzdb
        b = b - alpha*dedb
        """
        你也可以这么写
        dedw = -2*(y-z)*x
        w = w - alpha*dedw
        dedb = -2*(y-z)*1
        b = b - alpha*dedb
        """

z = w*xs+b
plt.xlim(0, 1)
plt.ylim(0, 3)
plt.scatter(xs, ys)
plt.plot(xs, z)
plt.show()

Rosenblatt感知器,感知器也叫预测机

那么感知器有什么用呢?感知器可以拟合任何的线性函数,任何线性分类或线性回归问题都可以用感知器来解决。

使用python实现Rosenblatt感知器

pass:此次python实验的预测函数不含偏置项系数,所以函数图像过原点,只能拟合因果是成正比的数据或只能完成可被过原点的直线分类的数据

算法图

Rosenblatt_predictor_flow_chart

线性回归问题

  1. 首先先引入需要用到的库

    import numpy
    from matplotlib import pypolt 

    引入numpy数学库以方便我们的数学计算

    引入matplotlib中的pyplot模块进行画图操作

    numpy使用手册:https://www.numpy.org.cn/

    matplotlib使用手册:https://www.matplotlib.org.cn/

  2. 获取数据以便进行训练

    def getdata(count):
        """获取指定数量的数据"""
        x = np.random.rand(count)#生成区间[0,1)的随机数
        x = np.sort(x)#进行从小到大排序
        y = [1.5*xx+np.random.rand()/3 for xx in x]#使用列表推导式生成对应的值
        return x,y

    创建一个名为getdata的函数随机生成有共同特征的数据,有一个参数count来接收获取数据的数量

  3. 获取100个数据

    xs,ys = getdata(100)#获取100个数据
  4. 编写预测函数

    w = float("%.2f"%np.random.uniform(0,1))#随机生成权重参数
    alpha = 0.05#设置学习率
    y_predict =  w*xs#简单的预测函数
  5. 绘制图像以便我们观察

    plt.scatter(xs,ys)#绘制散点图
    plt.plot(xs,y_predict)#绘制预测函数的图像
    plt.show()#显示图像

    initial_predict

  6. 算法的实现

    for i in range(100):#对每个数据进行一次权重调整
            x = xs[i]
            y = ys[i]
            #取出一个数据
            y_predict =  w*x#计算相应数据的预测值
            e = y - y_predict#计算相应数据的预测值与实际值的误差(使用差值评估误差)
            w = w + alpha*e*xs#根据误差调整权重参数
            y_predict = w * xs#重新配置预测函数
  7. 多次训练

    why:因为学习率的存在,我们的预测函数只进行了一次在总体上的调整,无法完美的拟合。但是如果学习率设置太大会造成预测曲线不能收敛

    for _ in range(100):#进行100次训练
        for i in range(100):#对每个数据进行一次权重调整
            x = xs[i]
            y = ys[i]
            #取出一个数据
            y_predict =  w*x#计算相应数据的预测值
            e = y - y_predict#计算相应数据的预测值与实际值的误差(使用差值评估误差)
            w = w + alpha*e*xs#根据误差调整权重参数
            y_predict = w * xs#重新配置预测函数
  8. 再次画出预测曲线

    plt.plot(xs,y_predict)#绘制预测函数的图像
    plt.show()#显示图像

    simple_predictor

    可以看到完美的拟合了数据

线性回归问题代码

import numpy as np#引入numpy数学计算库
from matplotlib import pyplot as plt#引入matplotlib画图库

def getdata(count):
    """获取指定数量的数据"""
    x = np.random.rand(count)
    x = np.sort(x)
    y = [1.5*xx+np.random.rand()/3 for xx in x]
    return x,y

xs,ys = getdata(100)#获取100个数据

w = float("%.2f"%np.random.uniform(0,1))#随机生成权重参数
alpha = 0.05#设置学习率
y_predict =  w*xs#简单的预测函数

plt.scatter(xs,ys)#绘制散点图
plt.plot(xs,y_predict)#绘制预测函数的图像
plt.show()

for _ in range(100):#进行100次训练
    for i in range(100):#对每个数据进行一次权重调整
        x = xs[i]
        y = ys[i]
        #取出一个数据
        y_predict =  w*x#计算相应数据的预测值
        e = y - y_predict#计算相应数据的预测值与实际值的误差(使用差值评估误差)
        w = w + alpha*e*xs#根据误差调整权重参数
        y_predict = w * xs#重新配置预测函数
    #画图
    plt.clf()
    plt.xlim(0,1.1)
    plt.ylim(0,1.85)
    plt.scatter(xs,ys)
    plt.plot(xs,y_predict)
    plt.pause(0.01)
   
plt.show()

“人工” “智能”,人工究竟如何创造智能。

人工神经元

在1943年麦卡洛克和皮茨(McCullouch and Pitts)提出了“人工神经元”模型(麦卡洛克-皮茨神经元模型简称MP模型),是第一次模仿生物体的神经元进行设计的模型。

MP_model

MP_model_surface

麦卡洛克是当时非常著名的生物学家它和当时的数学家皮茨一起工作,模仿生物神经元的树突、轴突、细胞核制作出了人工神经元模型。生物获取多个电信号经过树突的正确处理后来到细胞核,大量电信号经整合电信号发生总和达到阈值时输出,通过轴突传导下一个神经元;人工神经元获取多个数据(x1、x2、x3....xn)经过权重参数(w11、w12、w13.....w1n)来到求和函数,通过激活书函数激活达到阈值后输出。可以看这是非常的相似的。

Rosenblatt感知器

可是MP模型的权重参数w需要手动调整,在处理相应的问题的时候需要我们人自己去根据事物的特征去寻找w,如果不调整神经元的权重参数将会输出错误的信号,这未免太不智能了吧。

在1958年,心理学家弗兰克·罗森布拉特(Flank Rosenblatt)提出了感知机模型(Rosenblatt感知器),Rosenblatt感知器是根据MP模型的单层“神经网络”,是历史上首个根据样本数据来学习到正确的权重参数的模型。Rosenblatt_predictor_flow_chart

对于线性可分为两类的数据,按照Rosenblatt感知机的误差修正算法,可以根据样本数据经过多次迭代运算,最终实现运算收敛,确定每个输入x对应的权重W。我们把迭代运算的过程称为“神经网络的训练”,最终训练好的神经网络可以对新的数据作分类预测。这就是最简单的“机器学习”的过程。

Rosenblatt感知器为之后的人工智能的研究提供了灵感,人工智能也就开始了蓬勃发展。

参考文献

https://www.51cto.com/article/656216.html

https://baike.sogou.com/kexue/d10261.htm?ch=fromsearch