Kaggle-MNIST上手

作者: Yung968 | 来源:发表于2019-02-07 23:11 被阅读13次

    想学深度学习很久了,tensorflow实战框架也买回来了一段时间了,但是由于一直在学其他的东西,就没能学成。恰巧,最近逛各种社区,想着开拓一下思路。于是发现了Kaggle,好似终于找到了把我所正在学的东西和深度学习结合起来的机会。
    这篇文章其实是一片随手笔记,是阅读@量化大司马3零基础用TensorFlow玩转Kaggle的“手写识别”的内容随手写下的东西。当然也顺手把代码补全了(敲了好久)。作为这个领域的菜鸟中的菜鸟,希望以后能继续向大佬们学习kaggle和深度学习。
    文章还没写完,今天刚把小半部分代码理解完了,但是还有后半部分重要代码还没理解。又是深夜,睡觉去了。明日补。
    以下是正文。


    概述

    MNIST是tensorflow的hello world(简单的Demo)。

    Kaggle中的hello world是Digit Recognizer(手写图片识别)。

    使用上述两者,上手时间tensorflow和Kaggle是一个不错的选择。

    手写图片识别分别的实现分为三步:

    • 数据准备

    • 模型设计

    • 代码实现

    数据有Kaggle官方数据,模型使用MNIST Demo中设计的思路。


    数据

    下载源。

    Test——测试数据

    28000条数据。每条数据是一个784大小的一维数组。是把一个28*28的图片给扁平化了。

    Train——训练数据 + 验证数据

    42000条数据。同样每一条数据都是一个一维数组,不过大小是784+1。加的那个1是label。(有监督学习)


    一个好的算法都会利用其二维信息,但是鉴于这是一个上手,就先用一维结构进行分析。

    显然这个数据集和相似度识别一样都存在同样的问题:采样率不一或者“速度”不一造成的尺度缩放问题。

    但是没有噪声和local time shfting(比如缺失点和相等的时间平移)。


    模型的设计

    模型的组成是这样的:

    • 使用一个最简单的单层神经网络进行学习

    • 使用SoftMax来作为激活函数

    • 使用交叉熵来作为损失函数

    • 使用梯度下降来做优化方式

    学习模型、激活函数、损失函数、学习方式这几个要素都是必要的,而这几个要素的实现都选择的最简单的形式。

    神经网络

    由多个神经元组成。每一个神经元都接收很多的输入:[x1, x2, x3, ..., xn],加权(a),加偏移(b)之后看看是不是超过了某个阈值,超过了发出1,没超过发出0。

    单个神经元

    由很多个神经元互相连接,形成了神经网络。


    单个神经元

    激活函数

    每个神经元都会输出一个数值,一个神经网络有这么多神经元,最终决定输出那个呢?需要的就是激活函数。其实每一个源的输入都是一个函数,而最终的激活函数就是在做一个规划以达到最好函数:

    线性的模型是这样的:


    线性模型

    非线性的是这样的:

    非线性模型

    显然,规划就是一个非常重要的课题。在经典教材《算法》中,没有提及规划算法,令很多人感到惋惜,现在终于可以理解原因了。

    目前主流的几个激活函数是:sigmoid,tanh,ReLU。

    sigmoid:采用S形函数,取值范围[0,1]

    tanh:双切正切函数,取值范围[-1,1]

    ReLU:简单而粗暴,大于0的留下,否则一律为0。

    SoftMax

    我们知道max(A,B),�是指A和B里哪个大就取哪个值,但我们有时候希望比较小的那个也有一定概率取到,怎么办呢?我们就按照两个值的大小,计算出概率,按照这个概率来取A或者B。比如A=9,B=1,那取A的概率是90%,取B的概率是10%。

    这个看起来比max(A,B)这样粗暴的方式柔和一些,所以叫SoftMax(名字解释纯属个人瞎掰😑大家能理解概念就好)

    损失函数

    在各种学习算法中,必然要着重讲的就是损失函数和优化方式。

    损失函数也相当于相似度预测时候的相似度:表征对数据拟合程度的反映,拟合的越好、损失应该越少。然后我们根据损失函数进行调整。

    交叉熵:交叉熵通俗讲就是训练程度和圆满之间的差距,我们希望距离越小越好(= =没看很懂)

    优化方式

    训练过程是一个逐渐达到收敛的过程,必然需要一个优化方式(要不要损失函数干什么)。

    这个概念可以这样理解,我们要解决的问题是一座山,答案在山底,我们从山顶到山底的过程就是解决问题的过程。

    在山顶,想找到最快的下山的路。这个时候,我们的做法是什么呢?在每次选择道路的时候,选最陡的那条路。梯度是改变率或者斜度的另一个称呼,用数学的语言解释是导数。对于求损失函数最小值这样的问题,朝着梯度下降的方向走,就能找到最优值了。

    梯度下降

    代码实现

    ##############################################
    # 载入数据,并对数据进行处理                     #
    ##############################################
    
    import tensorflow as tf
    import pandas as pd
    import numpy as np
    
    # 1 加载数据集,把对输入和结果进行分开
    filePath = "~/Downloads/"
    train = pd.read_csv(filePath + "train.csv")  # train中是仍然包含表头的
    images = train.iloc[:, 1:].values  # 删除表头,images是numpy.ndarray
    labels_flat = train[["label"]].values.ravel()  # 获取label
    
    # 2 对输出进行处理
    images = images.astype(np.float)
    images = np.multiply(images, 1.0 / 255.0)  # 转化到256阶的灰度
    print('输入数据的数量:(%g, %g)' % images.shape)  # ndarray.shape返回其维度
    
    image_size = images.shape[1]
    print('输入数据的纬度 => {0}'.format(image_size))
    
    image_width = image_height = np.ceil(np.sqrt(image_size).astype(np.uint8))
    print('图片的长 => {0}\n图片的高 => {1}'.format(image_width, image_height))
    
    x = tf.placeholder('float', shape=[None, image_size])
    
    # 3 对结果进行处理
    labels_count = np.unique(labels_flat).shape[0]  # 获取label中不重复的个数,显然是10个:0-9
    print('结果的种类 => {0}'.format(labels_count))
    
    
    # 进行One-hot编码
    def dense_to_one_hot(labels_dense, num_classes):
        num_labels = labels_dense.shape[0]
        index_offset = np.arange(num_labels) * num_classes
        labels_one_hot = np.zeros((num_labels, num_classes))
        labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
        return labels_one_hot
    
    
    labels = dense_to_one_hot(labels_flat, labels_count)
    labels = labels.astype(np.uint8)
    print(type(labels.shape))
    print('结果的数量:({0[0]}, {0[1]})'.format(labels.shape))
    
    y = tf.placeholder('float', shape=[None, labels_count])
    
    # 4 把输入数据划分训练集和验证集
    # 把40000个数据作为训练集,2000个数据作为验证集
    VALIDATION_SIZE = 2000
    
    validation_images = images[:VALIDATION_SIZE]
    validation_labels = labels[:VALIDATION_SIZE]
    
    train_images = images[VALIDATION_SIZE:]
    train_labels = labels[VALIDATION_SIZE:]
    
    # 5 对训练集进行分批
    batch_size = 100
    n_batch = len(train_images)/batch_size
    print(n_batch)
    
    ##############################################
    # 建立神经网路、设置损失函数、设置梯度下降的优化参数 #
    ##############################################
    
    # 6 设置一个简单的神经网络来对图片进行识别
    weight = tf.Variable(tf.zeros([784, 10]))
    biases = tf.Variable(tf.zeros([10]))
    result = tf.matmul(x, weight) + biases
    prediction = tf.nn.softmax(result)
    
    # 7 创建损失函数、以交叉熵的平均值为衡量
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=prediction))
    
    # 8 用梯度下降发优化参数
    train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
    
    #################################################
    # 初始化变量,设置好准确度的计算方法,在Session中运行  #
    #################################################
    
    # 9 初始化变量
    init = tf.global_variables_initializer()
    
    # 10 计算准确度
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    
    with tf.Session() as sess:
        # 初始化
        sess.run(init)
        # 循环50轮
        for epoch in range(50):
            for batch in range(int(n_batch)):
                # 按照分片取出数据
                batch_x = train_images[batch * batch_size:(batch + 1)*batch_size]
                batch_y = train_labels[batch * batch_size:(batch + 1) * batch_size]
                # 进行训练
                sess.run(train_step, feed_dict={x:batch_x, y:batch_y})
            # 每一轮计算一次准确度
            accuracy_n = sess.run(accuracy, feed_dict={x:validation_images, y:validation_labels})
            print('第' + str(epoch + 1) + "轮,准确度为:" + str(accuracy_n))
    

    输出:

    第1轮,准确度为:0.7925
    第2轮,准确度为:0.808
    第3轮,准确度为:0.8155
    第4轮,准确度为:0.8535
    第5轮,准确度为:0.876
    第6轮,准确度为:0.8875
    第7轮,准确度为:0.8915
    第8轮,准确度为:0.895
    第9轮,准确度为:0.897
    第10轮,准确度为:0.897
    第11轮,准确度为:0.899
    第12轮,准确度为:0.9005
    第13轮,准确度为:0.901
    第14轮,准确度为:0.9035
    第15轮,准确度为:0.9065
    第16轮,准确度为:0.9075
    第17轮,准确度为:0.908
    第18轮,准确度为:0.909
    第19轮,准确度为:0.9105
    第20轮,准确度为:0.9105
    第21轮,准确度为:0.911
    第22轮,准确度为:0.911
    第23轮,准确度为:0.9115
    第24轮,准确度为:0.912
    第25轮,准确度为:0.9125
    第26轮,准确度为:0.9135
    第27轮,准确度为:0.9135
    第28轮,准确度为:0.9135
    第29轮,准确度为:0.9135
    第30轮,准确度为:0.914
    第31轮,准确度为:0.9145
    第32轮,准确度为:0.915
    第33轮,准确度为:0.915
    第34轮,准确度为:0.915
    第35轮,准确度为:0.916
    第36轮,准确度为:0.917
    第37轮,准确度为:0.918
    第38轮,准确度为:0.919
    第39轮,准确度为:0.919
    第40轮,准确度为:0.9195
    第41轮,准确度为:0.9195
    第42轮,准确度为:0.9195
    第43轮,准确度为:0.919
    第44轮,准确度为:0.9195
    第45轮,准确度为:0.9185
    第46轮,准确度为:0.919
    第47轮,准确度为:0.919
    第48轮,准确度为:0.919
    第49轮,准确度为:0.919
    第50轮,准确度为:0.9195
    
    Process finished with exit code 0
    

    我们这个网络识别的准确度是92%左右,这个成绩比较差,然而这只是我们最简单的模型而已

    相关文章

      网友评论

        本文标题:Kaggle-MNIST上手

        本文链接:https://www.haomeiwen.com/subject/ipxisqtx.html