• python: MNIST-神经网络的自主学习


    问题:如何实现数字“5”的识别?O(∩_∩)O~

                                     手写数字“5”的例子:写法因人而异,五花八门

    方案: 从图像中提取特征量-----用及其学习技术学习这些特征量的模式

    神经网络的学习中所用到的指标称为损失函数

    可以用作损失函数的函数很多,最有名的是均方误差(mean squared error)。

      均方误差的表达式:

        

        yk  -----------神经网络输出

        tk  -----------监督数据,one-hot表示

      这里的神经网络的输出y是softmax函数的输出。softmax函数的输出可以理解为概率

      用python实现均方误差:   

    def mean_squared_error(y-t):
        return 0.5*np.sum((y-t)**2)

    除了均方误差,交叉熵误差(cross entropy error)也经常被用作损失函数。
      交叉熵误差的表达式:

        

        比如,假设正确解标签的索引是“2”,与之对应的神经网络的输出是 0.6,则交叉熵误差是 -log 0.6 = 0.51;若“2”对应的输出是 0.1,则交叉熵误差为 -log 0.1 = 2.30。也就是说,交叉熵误差的值是由正确解标签所对应的输出结果决定的

    自然对数的图像如图所示:

     1 import matplotlib.pyplot as plt
     2 import numpy as np
     3 
     4 #生成数据
     5 x=np.arange(0.01,1.01,0.01)
     6 y=np.log(x)
     7 
     8 #绘制图像
     9 plt.plot(x,y)
    10 plt.xlabel('x')
    11 plt.ylabel('y')
    12 plt.show()

    代码实现交叉熵误差:

    def cross_entropy_error(y,t):
        delta=1e-7
        return -np.sum(t*np.log(y+delta))

     

    如果计算所有训练数据的损失函数的综合,则公式为:

      

    上述的损失函数都是针对单个数据,加入训练数据一共有6000个,那我们每次拿出100个当做是6000的近似计算一次,这样计算得到的结果就是mini-batch学习的结果。

    在之前的笔记中已经知道了读入MNIST数据集的代码,即:

    import sys, os
    sys.path.append(os.pardir)
    import numpy as np
    from dataset.mnist import load_mnist
    
    (x_train, t_train), (x_test, t_test) = 
        load_mnist(normalize=True, one_hot_label=True)
    
    print(x_train.shape) # (60000, 784)
    print(t_train.shape) # (60000, 10)

    mnist数据下载的代码mnist.py如下:

      1 # coding: utf-8
      2 try:
      3     import urllib.request
      4 except ImportError:
      5     raise ImportError('You should use Python 3.x')
      6 import os.path
      7 import gzip
      8 import pickle
      9 import os
     10 import numpy as np
     11 
     12 
     13 url_base = 'http://yann.lecun.com/exdb/mnist/'
     14 key_file = {
     15     'train_img':'train-images-idx3-ubyte.gz',
     16     'train_label':'train-labels-idx1-ubyte.gz',
     17     'test_img':'t10k-images-idx3-ubyte.gz',
     18     'test_label':'t10k-labels-idx1-ubyte.gz'
     19 }
     20 
     21 dataset_dir = os.path.dirname(os.path.abspath(__file__))
     22 save_file = dataset_dir + "/mnist.pkl"
     23 
     24 train_num = 60000
     25 test_num = 10000
     26 img_dim = (1, 28, 28)
     27 img_size = 784
     28 
     29 
     30 def _download(file_name):
     31     file_path = dataset_dir + "/" + file_name
     32     
     33     if os.path.exists(file_path):
     34         return
     35 
     36     print("Downloading " + file_name + " ... ")
     37     urllib.request.urlretrieve(url_base + file_name, file_path)
     38     print("Done")
     39     
     40 def download_mnist():
     41     for v in key_file.values():
     42        _download(v)
     43         
     44 def _load_label(file_name):
     45     file_path = dataset_dir + "/" + file_name
     46     
     47     print("Converting " + file_name + " to NumPy Array ...")
     48     with gzip.open(file_path, 'rb') as f:
     49             labels = np.frombuffer(f.read(), np.uint8, offset=8)
     50     print("Done")
     51     
     52     return labels
     53 
     54 def _load_img(file_name):
     55     file_path = dataset_dir + "/" + file_name
     56     
     57     print("Converting " + file_name + " to NumPy Array ...")    
     58     with gzip.open(file_path, 'rb') as f:
     59             data = np.frombuffer(f.read(), np.uint8, offset=16)
     60     data = data.reshape(-1, img_size)
     61     print("Done")
     62     
     63     return data
     64     
     65 def _convert_numpy():
     66     dataset = {}
     67     dataset['train_img'] =  _load_img(key_file['train_img'])
     68     dataset['train_label'] = _load_label(key_file['train_label'])    
     69     dataset['test_img'] = _load_img(key_file['test_img'])
     70     dataset['test_label'] = _load_label(key_file['test_label'])
     71     
     72     return dataset
     73 
     74 def init_mnist():
     75     download_mnist()
     76     dataset = _convert_numpy()
     77     print("Creating pickle file ...")
     78     with open(save_file, 'wb') as f:
     79         pickle.dump(dataset, f, -1)
     80     print("Done!")
     81 
     82 def _change_one_hot_label(X):
     83     T = np.zeros((X.size, 10))
     84     for idx, row in enumerate(T):
     85         row[X[idx]] = 1
     86         
     87     return T
     88     
     89 
     90 def load_mnist(normalize=True, flatten=True, one_hot_label=False):
     91     """读入MNIST数据集
     92     
     93     Parameters
     94     ----------
     95     normalize : 将图像的像素值正规化为0.0~1.0
     96     one_hot_label : 
     97         one_hot_label为True的情况下,标签作为one-hot数组返回
     98         one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组
     99     flatten : 是否将图像展开为一维数组
    100     
    101     Returns
    102     -------
    103     (训练图像, 训练标签), (测试图像, 测试标签)
    104     """
    105     if not os.path.exists(save_file):
    106         init_mnist()
    107         
    108     with open(save_file, 'rb') as f:
    109         dataset = pickle.load(f)
    110     
    111     if normalize:
    112         for key in ('train_img', 'test_img'):
    113             dataset[key] = dataset[key].astype(np.float32)
    114             dataset[key] /= 255.0
    115             
    116     if one_hot_label:
    117         dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
    118         dataset['test_label'] = _change_one_hot_label(dataset['test_label'])
    119     
    120     if not flatten:
    121          for key in ('train_img', 'test_img'):
    122             dataset[key] = dataset[key].reshape(-1, 1, 28, 28)
    123 
    124     return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label']) 
    125 
    126 
    127 if __name__ == '__main__':
    128     init_mnist()

    minst.py在文件夹dataset中,数据在dataset下的mnist.pkl文件中。

    目前我还是自己写不出来这样的代码,还是得分析透才能学会,这里先留一下,下次来分析......

    那么,如何从训练数据中随机抽取10笔数据呢?可以使用NumPy的no.random.choice(),携程如下形式:

    train_size=x_train.shape[0]
    batch_size=10
    batch_mask=np.random.choice(train_size,batch_size)
    x_batch=x_train[batch_mask]
    t_batch=t_train[batch_mask]


    mini_batch交叉熵的实现:

    def cross_entropy_error(y,t):
        if y.ndim==1:
            t=t.reshape(1,t.size)
            y=y.reshape(1,y.size)
            
        batch_size=y.shape[0]
        return -np.sum(t*np.log(y+1e-7))/batch_size

    这里,y 是神经网络的输出,t 是监督数据。y 的维度为 1 时,即求单个数据的交叉熵误差时,需要改变数据的形状。并且,当输入为 mini-batch 时,要用 batch 的个数进行正规化,计算单个数据的平均交叉熵误差。

    当监督数据是标签形式而不是one-hot表示时,交叉熵代码如下:

    def cross_entropy_error(y,t):
        if y.ndim==1:
            t=t.reshape(1,t.size)
            y=y.reshape(1,y.size)
            
        batch_size=y.shape[0]
        return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size

    实现的要点是,由于 one-hot 表示中 t 为 0 的元素的交叉熵误差也为 0,因此针对这些元素的计算可以忽略。换言之,如果可以获得神经网络在正确解标签处的输出,就可以计算交叉熵误差。因此,t 为 one-hot 表示时通过 t * np.log(y) 计算的地方,在 t 为标签形式时,可用 np.log( y[np.arange (batch_size), t] ) 实现相同的处理(为了便于观察,这里省略了微小值1e-7)。

    作为参考,简单介绍一下np.log( y[np.arange(batch_size), t] )np.arange (batch_size) 会生成一个从 0 到 batch_size-1 的数组。比如当 batch_size 为 5 时,np.arange(batch_size) 会生成一个 NumPy 数组 [0, 1, 2, 3, 4]。因为 t 中标签是以 [2, 7, 0, 9, 4] 的形式存储的,所以 y[np.arange(batch_size), t] 能抽出各个数据的正确解标签对应的神经网络的输出(在这个例子中,y[np.arange(batch_size), t] 会生成 NumPy 数组 [y[0,2], y[1,7], y[2,0], y[3,9], y[4,4]])。

    这部分理解起来并不是很容易,还是得多回顾才能真正掌握。均方误差、交叉熵误差以及下载mnist数据集,这些里面后两部分还得在后续的学习中继续补充。

    一定要加油啊,向目标前进~~~

    我的前方是万里征途,星辰大海!!
  • 相关阅读:
    还敢说你是程序员?一律师闲着没事写了个app,用户量600万
    cnentos中进行bond网卡配置,一切配置无问题,就是ping不通宿主机
    他曾被腾讯、百度、金山、遨游等联合封杀,如今他发展的却更好
    百度命不久矣?他为什么这么说?
    html实现下拉框、switch开关、复选框效果
    javascript拖拽滑动条
    行内元素默认间距的4种解决办法
    Html5 video用法详解
    npm装包时-S和-D的区别
    css3实现背景模糊的三种方式
  • 原文地址:https://www.cnblogs.com/taoyuxin/p/11441692.html
Copyright © 2020-2023  润新知