python机器学:6:神经网络

1.神经网络的原理和非线性矫正

1.神经网络的原理:

在介绍神经网络的原理之前先回顾一下线性回归模型的一般公式:
\vec{y}=w[0]x[0]+w[1]x[1]+...+w[p]x[p]+b
其中,\vec{y}表示y的估计值,x[0],到x[p]是样本特征值,w表示每个特征值的权重,y_hat可以看成是所有特征值的加权求和,可以用如下图所示表示这个过程:

线性回归的图像表示

分析:在图中, 输入的特征和预测的结果用节点进行表示,系数w用来连接这些节点。
再来说神经网络的原理,神经网络的原理,就是在上述算法过程里添加了隐藏层(Hidden Layers),然后在隐藏层重复进行上述加权求和计算,最后再把隐藏层所计算的结果用来生成最终结果。如下图所示:
带一个隐藏层的MLP模型

这样一来,模型要学习的特征系数,或者说权重,就会有很多了。
可以看到,在第一个输入的特征和隐藏单元之间,都有一个系数,这一步也是为了生成隐藏单元。而每个隐藏单元到最终结果之间,也都有一个系数。而计算一系列的加权求和和计算单一的加权求和。

2.神经网络的非线性矫正:

非线性矫正处理方法:
在生成隐藏层之后,我们要对结果进行非线性矫正,简称relu或者进行双曲正切处理,简称tanh。通过这两种方法处理后的结果用来计算最终结果y。
用图像直观展示:

#导入numpy
import numpy as np
#导入画图工具
import matplotlib.pyplot as plt
#生成一个等差数列
line = np.linspace(-5,5,200)
#画出非线性矫正的图形表示
plt.plot(line,np.tanh(line),label='tanh')
plt.plot(line,np.maximum(line,0),label='relu')

#设置图注位置
plt.legend(loc='best')
plt.xlabel('x')
plt.ylabel('relu(x) and tanh(x)')
plt.show()

运行代码,如下图所示:

对特征进行tanh和relu处理

结果分析:
从图中可以看出,tanh函数把特征x的值压缩到-1到1区间内,-1代表的是x中较小的值,而1代表的是x中较大的值。relu函数则索性把小于0的x值全部去掉,用0代替。这两种非线性处理的方法,都是为了降低样本特征进行简化,从而使神经网络可以对复杂的非线性模型数据集进行学习。
那么这样一来,我们刚才看到的公式:

经过tanh处理后,就会变成下面的样子:




在权重系数w之外,我们又多了一个权重系数v,用来通过隐藏层h来计算y-hat的结果。在模型中,w和v都是通过对数据的学习所得出的。而用户所要设置的参数,就是隐藏层中节点的数量。
如何设置节点数量:
一般来讲,对于小规模数据集或者简单数据集,节点数量设置为10就已经足够了,但是对于大规模数据集或者复杂数据集来说,有两种方式可供选择:
1.增加隐藏层中的节点数量,比如增加到1万个
2.添加更多隐藏层,如下图:
对模型添加新的隐藏层

在大型神经网络当中,往往有很多这样的隐藏层,这也是“深度学习”中“深度”二字的来源。

2.神经网络的模型参数调节

下面我们就以MLP算法中的MLP分类器为例,研究一下MLP分类器模型的使用方法。这次还是使用熟悉的酒的数据集。

#导入MLP神经网络
from sklearn.neural_network import MLPClassifier
#导入红酒数据集
from sklearn.datasets import load_wine
#导入数据集拆分工具
from sklearn.model_selection import train_test_split
wine = load_wine()
X = wine.data[:,:2]
y = wine.target
#下面我们拆分数据集
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=0)
#接下来定义分类器
mlp = MLPClassifier(solver='lbfgs')
mlp.fit(X_train,y_train)

运行代码,得到如下图所示:


MLP神经网络模型的参数

参数含义:
activation:将隐藏单元进行非线性化的方法,一共四种:
“identity” “logistic” “tanh” “relu”,默认值是“relu”
alpha:和线性模型的alpha值是一样的,是一个L2惩罚项,用来控制正则化的程度,默认0.0001
hidden_layer_sizes:着重讲一下这个参数,默认情况下,hidden_layer_sizes的值是[100,]这意味着模型中只有一个隐藏层,而隐藏层中的节点数是100.如果我们给hidden_layer_sizes定义为[10,10],那就意味着模型中有两个隐藏层,每层有10个节点。
用图像展示MLP分类情况:

#导入画图工具
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
#使用不同色块表示不同分类
cmap_light = ListedColormap(['#FFAAAA','#AAFFAA','#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000','#00FF00','#0000FF'])
x_min,x_max = X_train[:,0].min()-1,X_train[:,0].max()+1
y_min,y_max = X_train[:,1].min()-1,X_train[:,1].max()+1
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))
Z = mlp.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
#将数据特征用散点图表示出来
plt.scatter(X[:,0],X[:,1],c=y,edgecolor='k',s=60)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
#设定图题
plt.title("MLPClassifier:solver=lbfgs")
#显示图形
plt.show()

运行代码,如下图所示:


隐藏层节点数为100时的MLP分类器

调节参数:将隐藏层的节点数变少,减少至10个:

#设定隐藏层中的节点数为10
mlp_20 = MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10])
mlp_20.fit(X_train,y_train)
Z1 = mlp_20.predict(np.c_[xx.ravel(),yy.ravel()])
Z1 = Z1.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z1,cmap=cmap_light)
#使用散点图画出X
plt.scatter(X[:,0],X[:,1],c=y,edgecolor='k',s=60)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title('MLPClassifier:nodes=10')
plt.show()

运行代码,如下图所示:


隐藏层节点数为10时的MLP分类器

结果分析:
将前两张图进行对比,发现分类器生成的决定边界看起来很不一样了:
节点数为10的时候,决定边界丢失了很多细节。我们可以这样理解,在每一个隐藏层当中,节点数就代表了决定边界中最大的直线数,这个数值越大,则决定边界看起来越平滑。
当然,除了增加单个隐藏层中的节点数之外,还有两种方法可以让决定边界更细腻:
一个是增加隐藏层的数量;另一个是把activation参数改为tanh。

调节参数:增加隐藏层的数量

#设定隐藏层中的节点数为10
mlp_2L = MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10,10])
mlp_2L.fit(X_train,y_train)
Z1 = mlp_2L.predict(np.c_[xx.ravel(),yy.ravel()])
Z1 = Z1.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z1,cmap=cmap_light)
#使用散点图画出X
plt.scatter(X[:,0],X[:,1],c=y,edgecolor='k',s=60)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title('MLPClassifier : 2 layers')
plt.show()
两个隐藏层节点数为10时的MLP分类器

结果分析:
和上一个图对比,能够看到隐藏层带来的结果就是决定边界看起来更加细腻。

调节参数:把activation参数改为tanh。

#设定隐藏层中的节点数为10
mlp_tanh = MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10,10],activation='tanh')
mlp_tanh.fit(X_train,y_train)
Z2 = mlp_tanh.predict(np.c_[xx.ravel(),yy.ravel()])
Z2 = Z2.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z2,cmap=cmap_light)
#使用散点图画出X
plt.scatter(X[:,0],X[:,1],c=y,edgecolor='k',s=60)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title('MLPClassifier : 2 layers with tanh')
plt.show()
两个节点为10的隐藏层,activation为tanh的MLP分类器

结果分析:将activation参数修改为tanh后,分类器的决定边界完全变成了平滑的曲线。这就是我们对样本特征进行双曲线正切化后的结果。
除了上述方法,还可以通过调节alpha值来进行模型复杂度控制,默认的alpha值是0.0001。

调节参数:alpha增加到1

#修改模型的alpha参数
mlp_alpha = MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10,10],activation='tanh',alpha=1)
mlp_alpha.fit(X_train,y_train)
Z3 = mlp_alpha.predict(np.c_[xx.ravel(),yy.ravel()])
Z3 = Z3.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx,yy,Z3,cmap=cmap_light)
#使用散点图画出X
plt.scatter(X[:,0],X[:,1],c=y,edgecolor='k',s=60)
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title('MLPClassifier : 2 layers with tanh')
plt.show()
将alpha值增加到1之后的决定边界

jie
结果分析:
从图中可以看出,增加alpha参数的值,会加大模型正则化的程度,让模型更加简单。目前四种方法调整参数:
1.隐藏层的节点数
2.隐藏层的层数
3.activation
4.alpha

3.使用神经网络训练手写数字识别模型

数据集准备

使用MNIST数据集:
MNIST数据集是一个专门用来训练各种图像处理系统的庞大数据集,包含70000多个手写数字图像,60000个训练数据,10000个测试数据。改数据被广泛应用于魔性的训练和测试。目前有大量的学术论文都在试图把模型对MNIST数据集的识别错误率不断降低,目前识别错误率最低的一篇论文使用的是卷积神经网络,成功地把错误率降到了0.23%。而最早创造这个数据集的学者,在他们最早的论文中使用了支持向量机算法,使模型的错误率到达了0.8%。
获取MNIST数据集:

from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original',data_home='./datasets')
mnist

运行代码,得到如下图所示:


mnist数据集中的键

结果分析:从结果看出,MNIST数据集包含两个部分:
一个是分类标签;另一个是数据本身。
data的类型是无符号的8位整型np数组,而target是从0-9
接下来,检查一下数据集中的样本数量和样本特征数量:

from sklearn.model_selection import train_test_split
X = mnist.data/255
y = mnist.target
X_train,X_test,y_train,y_test = train_test_split(X,y,train_size=5000,test_size=1000,random_state=0)

运行代码,如下:
样本数量:70000,样本特征数:784
从结果看出,数据集有70000个样本,每个样本784个特征。这是因为,数据集中存储的样本是2828像素的手写数字图片的像素信息,因此特征数为2828=784个。
在开始训练MLP之前,需要对数据进行预处理,由于样本特征是从0~255的灰度值,为了让特征的数值更利于建模,我们把特征向量的值全部除以255,这样全部数值都会在0和1之间,再用我们非常熟悉的train_test_split函数将数据集分为训练集合测试集并训练神经网络:

from sklearn.model_selection import train_test_split
X = mnist.data/255
y = mnist.target
X_train,X_test,y_train,y_test = train_test_split(X,y,train_size=5000,test_size=1000,random_state=0)
#设置神经网络有2个100节点的隐藏层
mlp_hw = MLPClassifier(solver='lbfgs',hidden_layer_sizes=[100,100],activation='relu',alpha=1e-5,random_state=62)
#训练模型
mlp_hw.fit(X_train,y_train)
print('测试数据集得分:{:.2f}%'.format(mlp_hw.score(X_test,y_test)*100))

运行代码,得到如下结果:
测试数据集得分:93.90%
结果分析:从结果中可以看到,可以说是一个非常不错的分数了。

使用模型进行数字识别

准备图片:


image.png

将上面的测试图像转化为模型可以读取的numpy数组并进行测试:

#导入图像处理工具
from PIL import Image
#打开图像
image = Image.open('mlp_test.jpg').convert('F')
#调整图像的大小
image = image.resize((28,28))
arr = []
#将图像中的像素作为预测数据点的特征
for i in range(28):
    for j in range(28):
        pixel = 1.0 - float(image.getpixel((j,i)))/255
        arr.append(pixel)
#由于只有一个样本,所以需要进行reshape
arr1 = np.array(arr).reshape(1,-1)
#进行图像识别
print('图片中的数字是:{:.0f}'.format(mlp_hw.predict(arr1)[0]))

运行代码,得到如下结果:
图片中的数字是:4
结果分析:从结果中可以看到,神经网络正确地识别出了图片中的数字4,效果还是很不错的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容