ML–神经网络
主要涉及的知识点有:node
- 神经网络的前世此生
- 神经网络的原理和非线性矫正
- 神经网络的模型参数调节
- 使用神经网络训练手写数字识别模型
一.神经网络的前世此生
其实神经网络并非什么新鲜事物了,早在1943年,美国神经解剖家沃伦.麦克洛奇(Warren McCulloch)和数学家沃尔特.皮茨(Walter Pitts)就提出了第一个脑神经元的抽象模型,被称为M-P模型(McCulloch-Pitts neuron,MCP)
python
1.神经网络的起源
神经元是大脑中相互链接的神经细胞,它能够处理和传递化学和电信号。有意思的是,神经元具备两种常规工做状态:兴畚和抑制,这和计算机中的"1"和"0"原理几乎彻底同样。因此将神经元描述为一个具有二进制输出的逻辑门:当传入的神经冲动使细胞膜电位升高超过阈值时,细胞进入兴畚状态,产生神经冲动并由轴突输出;反之当传入的冲动使细胞膜电位降低低于阈值时,细胞进入抑制状态,便没有神经冲动输出程序员
2.神经网络之父–杰弗瑞.欣顿
杰弗瑞.欣顿等人提出了反向传播算法(Back propagation,BP)
,解决了两层神经网络所须要的复杂计算问题,从新带动业界的热潮算法
二.神经网络的原理及使用
1.神经网络中的非线性矫正
从数学的角度来讲,若是每个隐藏层只是进行加权求和,获得的结果和普通的线性模型不会有什么不一样。因此为了让模型可以比普通线性模型更强大一些,咱们还须要进行一点处理网络
这种处理方法是:在生成隐藏层以后,咱们要对结果进行非线性矫正(rectifying nonlinearity)
,简称为relu(rectified linear unit)
或者是进行双曲正切处理(tangens hyperbolicus)
,简称为tanh
。咱们用图像来进行直观展现app
# 导入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
函数把特征x的值压缩进-1到1的区间内,-1表明的是x中较小的数值,而1表明x中较大的数值。relu
函数则索性把小于0的x值所有去掉,用0来代替。这两种非线性处理的方法,都是为了将样本特征进行简化,从而使神经网络能够对复杂的非线性数据集进行学习dom
2.神经网络的参数设置
# 导入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)
MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9, beta_2=0.999, early_stopping=False, epsilon=1e-08, hidden_layer_sizes=(100,), learning_rate='constant', learning_rate_init=0.001, max_iter=200, momentum=0.9, n_iter_no_change=10, nesterovs_momentum=True, power_t=0.5, random_state=None, shuffle=True, solver='lbfgs', tol=0.0001, validation_fraction=0.1, verbose=False, warm_start=False)
下面咱们重点看一下各个参数的含义:
alpha
值和线性模型的alpha
值是同样的,是一个L2
惩罚项,用来控制正则化的程度,默认的数值是0.0001
hidden_layer,sizes
参数,默认状况下,hidden_layer_sizes
的值是[100,],这意味着模型中只有一个隐藏层,而隐藏层中的节点数是100.若是咱们给hidden_layer_sizes
定义为[10,10],那就意味着模型中有两个隐藏层,每层有10个节点机器学习
# 导入画图工具 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()
下面咱们试试吧隐藏层的节点数变少,如减小至10个,看会发生什么socket
# 设定隐藏层中的节点数为10 mlp_10=MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10]) mlp_10.fit(X_train,y_train) Z10=mlp_10.predict(np.c_[xx.ravel(),yy.ravel()]) Z10=Z10.reshape(xx.shape) plt.figure() plt.pcolormesh(xx,yy,Z10,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()
[结果分析] 在每个隐藏层当中,节点数就表明了决定边界中最大的直线数,这个数值越大,则决定边界看起来越平滑。固然,除了增长单个隐藏层中的节点数以外,还有两种方法可让边界看起来更细腻:一个是增长隐藏层的数量;另外一个是把activation
参数改成tanh
函数
如今咱们试着给MLP
分类器增长隐藏层数量,如增长到2层
# 设置神经网络有两个节点数为10的隐藏层 mlp_2L=MLPClassifier(solver='lbfgs',hidden_layer_sizes=[10,10]) mlp_2L.fit(X_train,y_train) Z2L=mlp_2L.predict(np.c_[xx.ravel(),yy.ravel()]) Z2L=Z2L.reshape(xx.shape) plt.figure() plt.pcolormesh(xx,yy,Z2L,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:layers=2") plt.show()
下面使用activation=tanh
实验一下
# 设置激活函数为tanh 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:layers=2 with tanh") plt.show()
调节alpha
值来进行模型复杂度控制
# 修改模型的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:alpha=1") plt.show()
到目前为止,我么有四种方法能够调节模型的复杂程度了,第1种是跳转神经网络每个隐藏层上的节点数,第2种是调节神经网络隐藏层的层数,第3种是调节activation
的方式,第4种是经过调整alpha
值来改变模型正则化的程度
[注意] 因为神经网络算法中,样本特征的权重是在模型开始学习以前,就已经随机生成了。而随机生成的权重会致使模型的形态也彻底不同。因此若是咱们不指定random_state
的话,即使模型全部的参数都是相同的,生成的决定边界也不同。因此若是从新运行咱们以前的代码,,也会获得不一样的结果。不过不用担忧,只要模型的复杂度不变,其预测结果的准确率不会受什么影响
三.神经网络实例–手写识别
在神经网络的学习中,使用MNIST
数据集训练图像识别,就如同程序员刚入门时要写"hello world"同样,是很是基础的必修课
1.使用MNIST数据集
MNIST
数据集是一个专门用来训练各类图形处理系统的庞大数据集,它包含70000个手写数字图像,其中60000个是训练数据,另外10000个是测试数据。而在机器学习领域,该数据集也被普遍用于模型的训练和测试。MNIST
数据集其实是从NIST
原始数据集中提取的,其训练集和测试集有一半是来自NIST
数据集的训练集,而另外一半是来自NIST
的测试集
接下来咱们就用scikit-learn
的fetch_mldata
来获取MNIST
数据集,输入代码以下:
# 导入数据集获取工具 from sklearn.datasets import fetch_mldata # 加载MNIST手写数字数据集 mnist=fetch_mldata('MNIST original') mnist
E:\Anaconda\envs\mytensorflow\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function fetch_mldata is deprecated; fetch_mldata was deprecated in version 0.20 and will be removed in version 0.22 warnings.warn(msg, category=DeprecationWarning) E:\Anaconda\envs\mytensorflow\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function mldata_filename is deprecated; mldata_filename was deprecated in version 0.20 and will be removed in version 0.22 warnings.warn(msg, category=DeprecationWarning) --------------------------------------------------------------------------- TimeoutError Traceback (most recent call last) <ipython-input-25-c42d12ebe31a> in <module>() 3 4 # 加载MNIST手写数字数据集 ----> 5 mnist=fetch_mldata('MNIST original') 6 mnist E:\Anaconda\envs\mytensorflow\lib\site-packages\sklearn\utils\deprecation.py in wrapped(*args, **kwargs) 76 def wrapped(*args, **kwargs): 77 warnings.warn(msg, category=DeprecationWarning) ---> 78 return fun(*args, **kwargs) 79 80 wrapped.__doc__ = self._update_doc(wrapped.__doc__) E:\Anaconda\envs\mytensorflow\lib\site-packages\sklearn\datasets\mldata.py in fetch_mldata(dataname, target_name, data_name, transpose_data, data_home) 131 urlname = MLDATA_BASE_URL % quote(dataname) 132 try: --> 133 mldata_url = urlopen(urlname) 134 except HTTPError as e: 135 if e.code == 404: E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context) 221 else: 222 opener = _opener --> 223 return opener.open(url, data, timeout) 224 225 def install_opener(opener): E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in open(self, fullurl, data, timeout) 524 req = meth(req) 525 --> 526 response = self._open(req, data) 527 528 # post-process response E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in _open(self, req, data) 542 protocol = req.type 543 result = self._call_chain(self.handle_open, protocol, protocol + --> 544 '_open', req) 545 if result: 546 return result E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in _call_chain(self, chain, kind, meth_name, *args) 502 for handler in handlers: 503 func = getattr(handler, meth_name) --> 504 result = func(*args) 505 if result is not None: 506 return result E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in http_open(self, req) 1344 1345 def http_open(self, req): -> 1346 return self.do_open(http.client.HTTPConnection, req) 1347 1348 http_request = AbstractHTTPHandler.do_request_ E:\Anaconda\envs\mytensorflow\lib\urllib\request.py in do_open(self, http_class, req, **http_conn_args) 1319 except OSError as err: # timeout error 1320 raise URLError(err) -> 1321 r = h.getresponse() 1322 except: 1323 h.close() E:\Anaconda\envs\mytensorflow\lib\http\client.py in getresponse(self) 1329 try: 1330 try: -> 1331 response.begin() 1332 except ConnectionError: 1333 self.close() E:\Anaconda\envs\mytensorflow\lib\http\client.py in begin(self) 295 # read until we get a non-100 response 296 while True: --> 297 version, status, reason = self._read_status() 298 if status != CONTINUE: 299 break E:\Anaconda\envs\mytensorflow\lib\http\client.py in _read_status(self) 256 257 def _read_status(self): --> 258 line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") 259 if len(line) > _MAXLINE: 260 raise LineTooLong("status line") E:\Anaconda\envs\mytensorflow\lib\socket.py in readinto(self, b) 584 while True: 585 try: --> 586 return self._sock.recv_into(b) 587 except timeout: 588 self._timeout_occurred = True TimeoutError: [WinError 10060] 因为链接方在一段时间后没有正确答复或链接的主机没有反应,链接尝试失败。
使用fetch_mldata加载MNIST数据集时,能够出现下列错误,能够参考:参考文档
从新运行代码以下:
# 导入数据集获取工具 from sklearn.datasets import fetch_mldata # 加载MNIST手写数字数据集 mnist=fetch_mldata('MNIST original') mnist
{'COL_NAMES': ['label', 'data'], 'DESCR': 'mldata.org dataset: mnist-original', 'data': array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=uint8), 'target': array([ 0., 0., 0., ..., 9., 9., 9.])}
print("样本数量:{},样本特征数:{}".format(mnist.data.shape[0],mnist.data.shape[1]))
样本数量:70000,样本特征数:784
[结果分析] 数据集中有70000个样本,每一个样本有784个特征。这是由于,数据集中存储的样本是28x28像素的手写数字图片的像素信息,所以特征数为28x28=784个
在开始训练MLP
神经网络以前,咱们还须要将数据进行一些预处理,因为样本特征是从0–255的灰度值,为了让特征的数值更利于建模,咱们把特征向量的值所有除以255,这样所有数值就会在0和1之间,再用咱们熟悉的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=62)
为了控制神经网络的训练时长,咱们只选5000个样本做为训练数据集,选取1000个数据做为测试数据集。同时为了每次选取的数据保持一致,咱们指定random_state
为62
2.训练MLP神经网络
# 设置神经网络有两个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.60%
3.使用模型进行数字识别
注意 由于图像是28x28像素,因此放大后看起来会不够清晰
# 导入图像处理工具 from PIL import Image # 打开图像 image=Image.open('8.png').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]))
图片中的数字是:8
Image.convert
功能将图片转化为32位浮点灰色图像,也就是说它的每一个像素用32个bit来表示,0表明黑,255表明白。然后将每一个像素的数值都进行除以255的处理,以保持和数据集一致