zoukankan      html  css  js  c++  java
  • ML--神经网络

    ML–神经网络

    主要涉及的知识点有:

    • 神经网络的前世今生
    • 神经网络的原理和非线性矫正
    • 神经网络的模型参数调节
    • 使用神经网络训练手写数字识别模型

    一.神经网络的前世今生

    其实神经网络并不是什么新鲜事物了,早在1943年,美国神经解剖家沃伦.麦克洛奇(Warren McCulloch)和数学家沃尔特.皮茨(Walter Pitts)就提出了第一个脑神经元的抽象模型,被称为M-P模型(McCulloch-Pitts neuron,MCP)

    1.神经网络的起源

    神经元是大脑中相互连接的神经细胞,它可以处理和传递化学和电信号。有意思的是,神经元具有两种常规工作状态:兴畚和抑制,这和计算机中的"1"和"0"原理几乎完全一样。所以将神经元描述为一个具备二进制输出的逻辑门:当传入的神经冲动使细胞膜电位升高超过阈值时,细胞进入兴畚状态,产生神经冲动并由轴突输出;反之当传入的冲动使细胞膜电位下降低于阈值时,细胞进入抑制状态,便没有神经冲动输出

    2.神经网络之父–杰弗瑞.欣顿

    杰弗瑞.欣顿等人提出了反向传播算法(Back propagation,BP),解决了两层神经网络所需要的复杂计算问题,重新带动业界的热潮

    二.神经网络的原理及使用

    1.神经网络中的非线性矫正

    从数学的角度来说,如果每一个隐藏层只是进行加权求和,得到的结果和普通的线性模型不会有什么不同。所以为了让模型能够比普通线性模型更强大一些,我们还需要进行一点处理

    这种处理方法是:在生成隐藏层之后,我们要对结果进行非线性矫正(rectifying nonlinearity),简称为relu(rectified linear unit)或者是进行双曲正切处理(tangens hyperbolicus),简称为tanh。我们用图像来进行直观展示

    # 导入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()
    

    output_12_0.png

    [结果分析] tanh函数把特征x的值压缩进-1到1的区间内,-1代表的是x中较小的数值,而1代表x中较大的数值。relu函数则索性把小于0的x值全部去掉,用0来代替。这两种非线性处理的方法,都是为了将样本特征进行简化,从而使神经网络可以对复杂的非线性数据集进行学习

    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()
    

    output_17_0.png

    下面我们试试吧隐藏层的节点数变少,如减少至10个,看会发生什么

    # 设定隐藏层中的节点数为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()
    

    output_19_0.png

    [结果分析] 在每一个隐藏层当中,节点数就代表了决定边界中最大的直线数,这个数值越大,则决定边界看起来越平滑。当然,除了增加单个隐藏层中的节点数之外,还有两种方法可以让边界看起来更细腻:一个是增加隐藏层的数量;另一个是把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()
    

    output_22_0.png

    下面使用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()
    

    output_24_0.png

    调节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()
    

    output_26_0.png

    到目前为止,我么有四种方法可以调节模型的复杂程度了,第1种是跳转神经网络每一个隐藏层上的节点数,第2种是调节神经网络隐藏层的层数,第3种是调节activation的方式,第4种是通过调整alpha值来改变模型正则化的程度

    [注意] 由于神经网络算法中,样本特征的权重是在模型开始学习之前,就已经随机生成了。而随机生成的权重会导致模型的形态也完全不一样。所以如果我们不指定random_state的话,即便模型所有的参数都是相同的,生成的决定边界也不一样。所以如果重新运行我们之前的代码,,也会得到不同的结果。不过不用担心,只要模型的复杂度不变,其预测结果的准确率不会受什么影响

    三.神经网络实例–手写识别

    在神经网络的学习中,使用MNIST数据集训练图像识别,就如同程序员刚入门时要写"hello world"一样,是非常基础的必修课

    1.使用MNIST数据集

    MNIST数据集是一个专门用来训练各种图形处理系统的庞大数据集,它包含70000个手写数字图像,其中60000个是训练数据,另外10000个是测试数据。而在机器学习领域,该数据集也被广泛用于模型的训练和测试。MNIST数据集实际上是从NIST原始数据集中提取的,其训练集和测试集有一半是来自NIST数据集的训练集,而另一半是来自NIST的测试集

    接下来我们就用scikit-learnfetch_mldata来获取MNIST数据集,输入代码如下:

    # 导入数据集获取工具
    from sklearn.datasets import fetch_mldata
    
    # 加载MNIST手写数字数据集
    mnist=fetch_mldata('MNIST original')
    mnist
    
    E:Anacondaenvsmytensorflowlibsite-packagessklearnutilsdeprecation.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:Anacondaenvsmytensorflowlibsite-packagessklearnutilsdeprecation.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:Anacondaenvsmytensorflowlibsite-packagessklearnutilsdeprecation.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:Anacondaenvsmytensorflowlibsite-packagessklearndatasetsmldata.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:Anacondaenvsmytensorflowliburllib
    equest.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:Anacondaenvsmytensorflowliburllib
    equest.py in open(self, fullurl, data, timeout)
        524             req = meth(req)
        525 
    --> 526         response = self._open(req, data)
        527 
        528         # post-process response
    
    
    E:Anacondaenvsmytensorflowliburllib
    equest.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:Anacondaenvsmytensorflowliburllib
    equest.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:Anacondaenvsmytensorflowliburllib
    equest.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:Anacondaenvsmytensorflowliburllib
    equest.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:Anacondaenvsmytensorflowlibhttpclient.py in getresponse(self)
       1329         try:
       1330             try:
    -> 1331                 response.begin()
       1332             except ConnectionError:
       1333                 self.close()
    
    
    E:Anacondaenvsmytensorflowlibhttpclient.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:Anacondaenvsmytensorflowlibhttpclient.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:Anacondaenvsmytensorflowlibsocket.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.使用模型进行数字识别

    8.png
    注意 因为图像是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的处理,以保持和数据集一致

  • 相关阅读:
    Python List+Tuple+Dict+Set小结
    小命要紧~风热风寒感冒
    IDEA忽略编译报错
    IDEA新建一个Spring Boot项目
    ip2region.jar实现ip转地址
    IDEA控制台中文乱码问题
    IDEA报错Plugin "XXX" was not loaded: required plugin "Java EE: EJB, JPA, Servlets" is disabled.
    IDEA Error:java: Compilation failed: internal java compiler error
    Failed to start component [StandardEngine[Catalina].StandardHost[localhost]
    浏览网页隐藏服务器IP
  • 原文地址:https://www.cnblogs.com/LQ6H/p/10421918.html
Copyright © 2011-2022 走看看