美文网首页Tensorflow从入门到精通我爱编程互联网科技
3零基础用TensorFlow玩转Kaggle的“手写识别”

3零基础用TensorFlow玩转Kaggle的“手写识别”

作者: 西瓜量化 | 来源:发表于2017-09-24 15:38 被阅读7638次

     这是一个TensorFlow的系列文章,本文是第二篇,在这个系列中,你讲了解到机器学习的一些基本概念、TensorFlow的使用,并能实际完成手写数字识别、图像分类、风格迁移等实战项目。

    文章将尽量用平实的语言描述、少用公式、多用代码截图,总之这将是一份很赞的入门指南。欢迎分享/关注。

    今天将用TensorFlow实现一个手写数字识别功能,来展示TensorFlow如何用神经网络实现对图片的识别。google也为入门者提供了一个这样的例子,也就是TensorFlow里的“hello world”,这个例子的名字叫“MNIST”。

    官方已经有了相应的文档,这里不是简单的翻译,而是以更通俗的语言来解释,为了让没有基础的同学也能看得懂,特别用简单的表述解释了一些专业名词,希望能有更多的人能接触到深度学习这个领域。

    如果想看中文版本:MNIST机器学习入门,可以点下面的链接进行查看

    http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_beginners.html

    如果是简单重复这个例子,就没什么意思了。正好“手写识别”在Kaggle上也有竞赛,我们使用Kaggle的数据进行识别和测试,这样和Google官方的例子虽然差不多,但又有不同。

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

    一、数据的准备

    二、模型的设计

    三、代码实现

    一、数据的准备

    Kaggle里包含了42000份训练数据和28000份测试数据(和谷歌准备的MNIST数据,在数量上有所不同)。训练和测试数据的下载地址可以百度也可以点这里。下载下来是两个CVS文件。

    Kaggle的数据都是表格形式的,和MNIST给的图片不一样。但实际上只是对图片的信息进行了处理,把一个28*28的图片信息,变成了28*28=784的一行数据。

    为了便于理解,我们先来看MNIST的图片信息:

    它每份的图片都是被规范处理过的,是一张被放在中间部位的灰度图。

    MNIST的图片集

    类似这样的,每一个图片均为28×28像素,我们可以将其理解为一个二维数组的结构:

    MNIST的图片解释

    28*28 = 784,也就是说,这个二维数组可以转为一个784个数字组成的一维数组。

    扁平化会丢失图片的二维结构信息,好的图形结构算法都会利用二维结构信息,但是为了简化过程便于理解,这里先使用这种一维结构来进行分析。

    这样,上面的训练数据和测试数据,都可以分别转化为[42000,769]和[28000,768]的数组。

    为什么训练数据会多一列呢?因为有一列存的是这个图片的结果。好我们继续来看图片:

    Kaggle训练集的截图

    这个图片上我们可以看出来,第一列是存的结果,后面784列存的是图片的像素信息,到这里,数据就准备好了。

    下面我们进行模型的设计。

    二、模型的设计

    不想看理论的可以跳过这一步,直接进入代码环节

    这个模型,组成是这样的:

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

    2)用SoftMax来做为激活函数

    3)用交叉熵来做损失函数

    4)用梯度下降来做优化方式

    这里有几个新的名词,神经网络、激活函数、SoftMax、损失函数、交叉熵、梯度下降,我们挨个解释一下。

    神经网络:由很多个神经元组成,每个神经元接收很多个输入:[X1,X2....Xn],加权相加然后加上偏移量后,看是不是超过了某个阀值,超过了发出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(名字解释纯属个人瞎掰😑大家能理解概念就好)

    损失函数:损失函数是模型对数据拟合程度的反映,拟合得越好损失应该越小,拟合越差损失应该越大,然后我们根据损失函数的结果对模型进行调整。

    交叉熵:这个概念要解释的简单,那就不准确,如果要准确,那可能一千字都打不住。这里说一个简单但不一定准确的解释吧。

    比如,你想把乾坤大挪移练到第七层大圆满,你现在是第五层,那你还差两层,这个两层就是你和大圆满之间的距离。交叉熵通俗的讲就是现在的训练程度和圆满之间的距离,我们希望距离越小越好,所以交叉熵可以作为一个损失函数,来衡量和目标之间的距离。

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

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

    梯度下降

    生僻的名词解释完了,咱们进入编程环节。

    三、代码实现

    1 载入数据,并对数据进行处理

    在写代码的过程中,数据的预处理是最大的一块工作,做一个项目,60%以上的代码在做数据预处理。

    这个项目的预处理,分为5步:

    1)把输入和结果分开

    2)对输入进行处理:把一维的输入变成28*28的矩阵

    3)对结果进行处理:把结果进行One-Hot编码

    4)把训练数据划分训练集和验证集

    5)对训练集进行分批

    处理完毕后,打印的结果是:

    数据预处理的结果

    数据预处理好了,如果不需要显示结果,可以把Print语句都去掉,不影响建模。

    2 建立神经网络,设置损失函数,设置梯度下降的优化参数

    这里只是最简单的一个实现,下篇文章我们会继续对网络进行优化

    3 初始化变量,设置好准确度的计算方法,在Session中运行

    训练模型

    最后我们得到运行完50轮后的结果:

    运行结果

    我们这个网络识别的准确度是92%左右,这个成绩比较差,然而这只是我们最简单的模型而已,后面我会和大家对模型持续进行优化。

    对于安装TensorFlow和基础操作不了解的同学可以看我第一篇文章:

    五分钟带你入门TensorFlow

    最后,重点来了:

    下一篇文章,我们的目标是把模型的准确度提升到99%以上,并提交到Kaggle。

    想第一时间看到下一篇优化模型的文章?抓紧,喜欢和关注吧~~~

    相关文章

      网友评论

      • db8f97ab1c68:代码都是图片,有源码吗...
      • 27efec53a72d:大司马前辈,上传一下完整的代码吧,我是零基础,想通过您的这篇文章好好学习,但是代码报错:TypeError: Expected bool for argument 'use_locking' not 1.
      • ccb000807e6f:y未定义....这一段代码你应该时遗漏了吗 求这一段代码和位置...
      • 南宫慕言:tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y, logits = prediction ))

        NameError: name 'y' is not defined

        这个损失函数里 的y么定义 咋解决啊
        ccb000807e6f:@丿偐偐憮语乄 同时这个问题
        ................请问怎么解决啊....
        dbb2ab2275b4:@南宫慕言 哥们你这个问题解决了吗,我也遇到了一样的问题
        南宫慕言:解决方式加了一段
        y = tf.placeholder('float', shape=[None, image_size])
        可是又出现了新的问题
        Expected bool for argument 'use_locking' not 1.
      • 暴走的狐狸:Kaggle那个鬼东西,我注册了一直发邮件让我确认激活,激活了依然不能登录,重复发邮件给我。导致数据没法下载。兄弟有没有数据的下载地址给我一个呀?
        8ebe877daae6:@暴走的狐狸 直接下载到本地也可以
        暴走的狐狸:@太平洋4203 后来发现需要翻墙,翻墙之后就没问题了。
        8ebe877daae6:同样的问题,吐血了。
      • 9ee3d962d07f:for batch in range(n_batch) : #n_batch从0到39999, batch_size=100 这样的话,不是越界了吗 ?
      • be8892b45b54:请问楼主,weights和biases的初始值为零不作调整么?看到CNN的代码里初始值用的是正态分布。
        西瓜量化:@MagicHiggs 可以用正态分布做初始化,这只是示例,没有把所有的功能加入进来。新人能把这些掌握,就ok了:smile:
      • 45c172d52b84:计算数据输入量为啥要除以255?
      • decda25ade9f:为啥我报这个错。。?
        4 train = pd.read_csv("train.csv")
        5 images = train.iloc[:,1:].values
        ----> 6 labels_flat = train[[0]].values.ravel()

        KeyError: '[0] not in index'
        decda25ade9f:改成这个了:train['label']
        估计是pandas的版本不一样
        我的是:padas version:0.22.0
      • daocaowe:lz 可以把代码传到github吗 ?
        西瓜量化:@daocaowe 这个只是一个简单的例子,正确率并不代表什么的:smile:掌握建模流程就可以了
        daocaowe:我循环了300次 可以达到0.927 估计3000次可以达到99%
      • 440505fd2cb9:出现错误 InvalidArgumentError
        E:\Program\Anaconda3\lib\site-packages\tensorflow\python\client\session.py in _do_call(self, fn, *args)
        1360 try:
        -> 1361 return fn(*args)
        1362 except errors.OpError as e:
        请问楼主这各是什么引起的 前面的输出是正常的 出错在最后的for循环
        440505fd2cb9:不好意思,我自己来回答一下:第4步有一个语句写成了
        validation_labels = labels = labels[:VALIDATION_SIZE] 造成了这个问题
      • 程序员Fox:sess.run(train_step,feed_dict={x:batch_x,y:batch_y}) 这里执行报错:
        ValueError: Cannot feed value of shape (100, 784) for Tensor 'Placeholder_23:0', which has shape '(?, 10)'
        0c991f649ce4:我也遇到了这个错误,求解决方法
        fb31f742886f:我这里也是报错:
        ValueError: Cannot feed value of shape (100, 784) for Tensor u'Placeholder_1:0', which has shape '(?, 10)
        请问怎么解决?
        5195727ec662:我也遇到了和你一样的问题,请问你解决了没?
      • 28992f16ba39:为什么我的准确度只有百分之四十几?
        52a553e8605e:@一虎笔记 我也是 50轮 46%
        28992f16ba39:@一虎笔记 一样的,50轮,我还换了换参数也不行。
        西瓜量化:@溪tt 跑了模型参数设置一样么?多少轮?
      • 76b03488070d:第一步就不行啊为什么NameError: name 'pd' is not defined
        sunblog:import numpy as np
        import pandas as pd
        import tensorflow as tf
      • HBU_DAVID:受益颇多,感谢
      • 康恺:one hot那里其实可以直接使用tf.one_hot(label,10)(10是类别数),一下就能出来~
        西瓜量化:@康恺 :+1::+1:
        ead4c03df9ec:如果采用这种方法报错 在feed前将 train_labels 与 validation_labels 转为 numpy.ndarray 形式即可, train_labels = train_labels.eval()
        西瓜量化:@康恺 是的,代码的优雅是无止境的:smile:
      • 轻听雨:请问楼主,都不贴所加载的包吗?程序里直接用简写,不太清楚哪些包……
        HBU_DAVID:import pandas as pd
        import numpy as np
        import tensorflow as tf
        西瓜量化:@轻听雨 主要用了pandas,tensorflow,keras
      • 简书没有名字:请问楼主,接下来如何对测试集预测,并生成.cvs结果
        西瓜量化:@简书没有名字 您可以看我后面有一篇99%达成的文章,有生成预测结果的代码
      • 368a241de7f7:请问楼主,labels_flat = train[[0]].values.ravel() 报错,提示“ [0] not in index” 是什么原因
        西瓜量化:@旧梦已逝逝逝逝_ :+1::+1:
        368a241de7f7:换了一个语法就可以了,labels_flat = train.iloc[:,0].values.ravel()
      • tynbl:请问楼主,代码第7大步的 y 如何定义的?
        西瓜量化:@凌剑微博 应该是截图的时候没截进去,谢谢您发现了:smile:
        tynbl:@多隆笔记 根据楼主的提醒,我依照 x 的占位符定义,增加了一行 y 的占位符定义,运行成功:
        y = tf.placeholder('float', shape=[None, labels_count])

        不加这行,程序运行报错:NameError: name 'y' is not defined
        西瓜量化:您好,请看最后sess里运行时,feed_dict中的赋值

      本文标题:3零基础用TensorFlow玩转Kaggle的“手写识别”

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