十二、深度学习入门
12.1 神经网络
其实就是让模型学习人类的思考方式来进行学习以及解决问题
那么就用圆来代表神经元,用线来代表神经流动方向,从而形成如下结构:
像这样的结构在人体中有超级多个,而一次学习所调用的盛景园越多,那么就越能够处理信息。在神经网络算法中亦是如此。所以,经常会看到下面这样的结构:
核心问题:要用多少的点和线来构造这个神经网络?
但是sklearn只是一个机器学习的库,所以不会涉及特别深,一共也就包含下面三个模型:
12.2 单层神经网络
12.2.1 回归单层神经网络:线性回归
- 多元线性回归:一个样本有多个特征的线性回归问题。假设有n个特征的样本i,那么对应的方程就是:
w和b是参数,其中b是截距/偏差,wi是回归系数/权重
现在假设我们的方程只有x1和x2,如下所示:
此时,我们就只用输入x1和x2的值,就可以得到对应的预测值z^ 。相应的,用神经网络来代表上面的方差就可以得到如下所示的结构:
这就是最简单的一个神经网络的表示图;输入层永远只有一层,而且每个神经元只能承受一个常/变量;而输出层可以是输入层的加和也可以是其他的计算方式。在这里的表达就是神经元*连接线上的参数,如果参数越大,那么其所能表达的信息量也就越大;
- 单层神经网络:有一个输入层和一个输出层的伸进网络(因为输入层一定存在且唯一,所以不考虑进去了);
现在用代码来实现下面这组数据的神经网络:
#先用numpy来构造数组
import numpy as np
x = np.array([[0,0],[1,0],[0,1],[1,1]])
z_reg = np.array([-0.02,-0.05,-0.05,0.1])
x
#array([[0, 0],
# [1, 0],
# [0, 1],
# [1, 1]])
x.shape
#(4, 2)
z_reg
#array([-0.02, -0.05, -0.05, 0.1 ])
#定义实现简单线性回归的函数
def LinearR(x1,x2):
#给定一组系数w和b
w1,w2,b = 0.15,0.15, -0.2
#z是系数*特征后的计算结果
z = x1*w1 + x2*w2 + b
return z
LinearR(x[:,0],x[:,1])
#array([-0.2 , -0.05, -0.05, 0.1 ])
12.2.2 二分类单层神经网络:sigmoid与跃阶函数
回归模型加上个sigmoid函数就成了分类函数
z通常是指各类模型返回的值,这里就是线性回归返回的结果;
通常使用阈值0.5来转化分类
这样一来,上面那个回归模型只用加上一个sigmoid函数就可以转化为分类模型,对应的数据如下所示:
这样的数据称为与门,与表示特征一与特征二都是1的含义,也就是向量的与操作*;
#二分类单层神经网络
y_and = np.array([0,0,0,1])
#根据sigmoid函数公式定义sigmoid函数
def sigmoid(z):
import numpy as np
return 1/(1 + np.exp(-z))
def AND_sigmoid(x1,x2):
#给定一组系数w和b
w1,w2,b = 0.15,0.15, -0.2
#z是系数*特征后的计算结果
z = x1*w1 + x2*w2 + b
#用sigmoid函数将z转化到(0,1)之间
o = sigmoid(z)
#根据阈值,将(0,1)之间的值转为0,1分类
y = [int(x) for x in o >= 0.5]
return o,y
o,y = AND_sigmoid(x[:,0],x[:,1])
o
#array([0.450166 , 0.4875026 , 0.4875026 , 0.52497919])
y
#[0, 0, 0, 1]
使用神经元,我们可以把它表示为:
- 另一种在连续性数据上进行分割的函数:符号函数sign,其图像如下所示:
其对应的表达式就是:
而符号函数通常被称为跃阶函数,因为它是在三个值之间跳来跳去。又因为z=0的情况很少,所以通常会简化为二分类:
我们可以对上面的不等式作如下转换:
这里的-b就是我们自己设定的阈值
#二分类单层神经网络:s跃阶函数
def AND(x1,x2):
w1,w2,b = 0.15,0.15, -0.23
z = x1*w1 + x2*w2 + b
y = [int(x) for x in z >= 0]
return y
AND(x[:,0],x[:,1])
#[0, 0, 0, 1]
要注意:在sklearn中,一旦要用二分类,那么就一定是用sigmoid函数。除非调整源码;
12.2.3 多分类单层神经网络:softmax回归
逻辑回归通过多对多以及一对多的方式进行多酚类。
- 一对多OvR:将多个标签类别中的一类作为类别1,其他所有类别作为类别0,分别建立多个二分类模型,综合得出多分类结果的方法;
- 多对多MvM:把好几个标签类作为1,剩下的都是0,同样分别建立多个二分类模型来得出多分类结果的方法;
但是这两种方法对于神经网络不太行,因为:
- 逻辑回归是一种快速的算法,在使用上面这两种方法时,运算速度不会成为大问题。但是神经网络本身计算量就很大,建一个模型就很累了;
- 可以用softmax回归来解决问题;
Softmax函数是神经网络进行多分类时,默认放在输出层中处理数据的函数。假设现在神经网络用于三分类数据,序号分别为分类1/2/3。则使用softmax函数神经网络结构如下图所示:
在多分类中,神经元的个数与标签类别的个数是一致的。此时,**样本的预测概率就是所有输出的概率中最大的那个概率所对应的类别;
Softmax公式如下所示:
其中z表示回归类算法的结果,K表示标签类别的数量,k表示标签类别k类,i表示总共K个类别中的第i个类别。
不难看出,函数的分子是多分类状况下某一个标签类别的回归结果的自然对数,分母则是多分类状况下所有标签类别的回归结果的自然对数之和。因此Softmax函数的结果代表了样本的结果为k的概率;
为了避免混淆上面公式中z的下标的含义,所以数字组最好从1开始标号,如下所示:
- softmax函数的缺陷:
如上图所示,e10就已经很大了,而回归结果z完全可能是一个很大的数字,这意味着其对应的e的阶乘数就会超出计算机处理的有限数据宽度,这种数据无法被计算机运算和表示——该现象称为溢出,当计算机返回“内存不足”/python服务器断开的时候就可能出现了这个问题:
#溢出现象
#假定一组巨大的z
z = np.array([1010,1000,990])
#softmax函数运算
np.exp(z) / np.sum([np.exp(z)])
为了解决该问题,我们只需要在分子/母同时乘上常数C并放入到对数中去:
只需让C’的符号为负号,再让其大小接近zk中的最大值就可以了:
#定义softmax函数
def softmax(z):
c = np.max(z)
#溢出对策
exp_z = np.exp(z - c)
sum_exp_z = np.sum(exp_z)
o = exp_z / sum_exp_z
return o
softmax(z)
#array([9.99954600e-01, 4.53978686e-05, 2.06106005e-09])
如果我们不需要知道概率结果,只需要一个分类结果,那么就可以不用softmax函数了;
但是在实际中,训练神经网络时一般都会用softmax函数,但是在就不再用softmax函数,而是直接读最大的z对应的类型就行了。
12.2.4 回归、二分类,多分类
多分类是在同一个标签下的不同类别,并非多个不同的标签;
- 根本区别:体现在g(z)上,不同的模型有着不同的表达式;