zoukankan      html  css  js  c++  java
  • Three-layer network on MNIST (Grokking 第八章学习笔记)

    之前在MNIST上做的分类器都是调用现有的包,这次我们尝试手写构建一个含有隐藏层的神经网络来预测手写数字

    因为构建的神经网络只有三层所以代码非常简单(但是Grokking上的代码,有几个非常明显的错误),效果也算过的去,具体就看代码吧,注释的很详细了。

    # 调用包的版本判断
    import sys
    assert sys.version_info >= (3, 5)
    
    
    import sklearn
    assert sklearn.__version__ >= "0.20"
    
    
    import numpy as np
    import os
    
    # 图像生成的相关参数
    %matplotlib inline
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    mpl.rc('axes', labelsize=14)
    mpl.rc('xtick', labelsize=12)
    mpl.rc('ytick', labelsize=12)
    
    # 图像保存位置
    PROJECT_ROOT_DIR = "."
    CHAPTER_ID = "classification"
    IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID)
    os.makedirs(IMAGES_PATH, exist_ok=True)
    
    def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
        path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
        print("get image:", fig_id)
        if tight_layout:
            plt.tight_layout()
        plt.savefig(path, format=fig_extension, dpi=resolution)
    
    from sklearn.datasets import fetch_openml
    
    #使用sklearn自带的 fatch_openml加载数据集
    #加载的数据集是一个key-value的字典结构
    #DESCR 用于描述数据集;data 实例为行 特征为列
    mnist = fetch_openml('mnist_784', version=1)        
    mnist.keys()
    
    #划分训练集与测试集
    X, y = mnist["data"], mnist["target"]
    x_train, x_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
    
    images, labels = (x_train[0:60000].reshape(60000,28*28)/255, y_train[0:60000])
    
    one_hot_labels = np.zeros((len(labels),10))                   #将图像的标签用0-1串表示例如'1'的one_hot_labels应该是[0,1,0,0,0,0,0,0,0,0]
    for i in range(len(labels)):
        one_hot_labels[i][int(labels[i])] = 1
    labels = one_hot_labels
    
    test_images = x_test.reshape(len(x_test),28*28)/255          #像素为闭区间[0,255]的整数,这里将像素值压缩至闭区间[0,1]之间
    test_one_hot_labels = np.zeros((len(y_test),10))
    for j in range(len(test_one_hot_labels)):
        test_one_hot_labels[j][int(y_test[j])] = 1
    test_labels = test_one_hot_labels
    
    #设置激活函数、学习率等参数
    np.random.seed(1)
    relu = lambda x:(x>=0) * x 
    relu2deriv = lambda x: x>=0 
    
    #依次设置:学习率、迭代次数、隐藏层神经元、像素数、输出层神经元数目
    alpha, iterations, hidden_size, pixels_per_image, num_labels = (0.005, 350, 40, 784, 10)
    
    #构建神经网络的权重
    weights_0_1 = 0.2*np.random.random((pixels_per_image,hidden_size)) - 0.1    #输入层-》隐藏层   大小为[784 x 40]
    weights_1_2 = 0.2*np.random.random((hidden_size,num_labels)) - 0.1        #隐藏层-》输出层   大小为[40 x 10]
    print(weights_0_1.shape)
    print(weights_1_2.shape)
    #print(weights_0_1)
    #print(weights_1_2)
    for j in range(iterations):
        error, correct_cnt = (0.0, 0)    
        for i in range(len(images)):
            error = 0.0
            layer_0 = images[i:i+1]
            layer_1 = relu(np.dot(layer_0,weights_0_1))   #将输入层的784个神经元与权重点乘后映射到隐藏层神经元上
            layer_2 = np.dot(layer_1,weights_1_2)         #将隐藏层40个神经原与权重点乘后映射到输出层神经元上
            error += np.sum((labels[i:i+1] - layer_2) ** 2)        #计算预测结果与实际结果之间的误差
            correct_cnt += int(np.argmax(layer_2) == np.argmax(labels[i:i+1]))    #若预测结果与实际标签结果相同,则正确数加一
            layer_2_delta = (labels[i:i+1] - layer_2)                             #隐藏层到输出层之间的误差
            layer_1_delta = layer_2_delta.dot(weights_1_2.T) * relu2deriv(layer_1)#输入层到隐藏层之间的误差
            
            #调整权重
            weights_1_2 += (alpha * layer_1.T.dot(layer_2_delta))                 
            weights_0_1 += (alpha * layer_0.T.dot(layer_1_delta)) 
        print(correct_cnt)
    
    #使用test数据集进行检测
    for i in range(100):
        layer_0 = test_images[i]
        layer_1 = relu(np.dot(layer_0,weights_0_1))   #将输入层的784个神经元与权重点乘后映射到隐藏层神经元上
        layer_2 = np.dot(layer_1,weights_1_2)
        print(np.argmax(layer_2), y_test[i])

     可以看到,随着迭代次数的增加,神经网络在训练数据集上的表现会越来越好,但在测试集中,神经网络的预测结果不理想,精确率只有60%左右。

    这是因为在训练神经网络的过程中,发生了过度拟合。

    所谓过拟合是指,在训练神经网络的过程中,过多的学习了【噪音】

    一个解决过拟合的,比较简单的方案是,在神经网络发生过拟合前终止对神经网络的训练

    另一个比较简单的方法是,在训练神经网络的过程中,随机的使某些神经元变为0,这种方法称为【Dropout】

    具体操作是在训练神经网络中加入以下语句:

              dropout_mask = np.random.randint(2,size=layer_1.shape)                     #随机的确定被置为0的神经元
              layer_1 *= dropout_mask*2

    同时在反向传播中也要考虑到Dropout,即:

        ayer_1_delta *= dropout_mask

    通过Dropout可以看出,在训练集中神经网络的预测精度会稍稍下降。但是神经网络在测试集中的预测精度会有较大幅度的提升。

    夜里睡觉时脑子跟电影院一样全是过去的画面,

    想了四天,觉得导致现在这个局面的主要原因还是自己太菜,以后要更加努力才行

    另一方面,我觉得不是因为不爱才导致某些问题,而是因为某些问题才导致不爱了。我还在反思,但我一定要去着手解决这些问题了。

    不管怎样,把自己变得更好才是正路。Good Night

  • 相关阅读:
    elasticsearch中多个字段聚合及java实现
    elasticsearch中must和should组合查询
    Hash(哈希/散列)表中冲突处理及命中计算
    PHP代码审计理解(一)----Metinfo5.0变量覆盖
    SSL 3.0 POODLE攻击信息泄露漏洞_CVE-2014-3566
    菜鸡试飞----SRCの信息收集手册
    python3-邮件发送-不同格式
    windows下常用快捷指令记忆
    杂记
    偶然碰到的编码转换技巧--叮!
  • 原文地址:https://www.cnblogs.com/alan-W/p/13742501.html
Copyright © 2011-2022 走看看