精华内容
下载资源
问答
  • 一只手能表示的最大的是多少?

    千次阅读 2018-10-28 09:40:20
    一只手有5手指头,每代表1,最大能表示5 ...如果每指节代表不同的,一只手有的指节3*4+2=14,能代表的2^14-1=16383, 如果正面和反面代表不同,再乘2 如果加上上下颠倒维度,可以再乘2!...

    一只手有5个手指头,每个代表1,最大能表示5
    如果规定小指头代表1,大拇指代表5,每个指头分别代表12345,那么1+2+3+4+5=15,一只手能代表15
    如果规定五个指头分别代表1,2,4,8,16,那么一只手能代表31
    如果每个指节代表不同的数,一只手有的指节数3*4+2=14,能代表的数2^14-1=16383,
    如果正面和反面代表不同,再乘2
    如果加上上下颠倒维度,可以再乘2!
    如果侧面也算不同,就要再乘2!
    如果仅仅计算以上维度,我们就可以算出一只手能表示的最大值是217-1,总共217个数,这个数是多少呢?131072,十几万!

    有人质疑这是理论值,有些数值可能并不好表示出来,因为手指并没有那么灵活,比如小指和无名指的配合.但是别忘了我们还有其他维度可以用,比如手势.
    (以后我再想写的时候给可以献上手势照片)
    我们需要一些冗余的维度来保证我们的理论值可以实施. 很多时候的理论值达不到就是因为弓拉的太满.而此处,我的维度还没拉满,所以一只手表示十几万是可以的!

    那么接下来的问题是,两只手能表示的最大数是多少呢?
    不是131072+131072,而是131072*131072,不同维度的叠加都是幂次方!(当然这是指的多维度同时演绎,一个静态的画面,如果加上时间维度,那么一个手能表示无穷大的数了!)
    那么咱们再反过来推一下我们的131072, 它由四个维度构成,我们是直接乘的,其实我们应该幂运算,那么也就是
    8.7112285931760246646623899502533e+40

    这样算来,两只手能表示的最大数就是
    7.5885503602567541832791480735294e+81

    不管你信不信,反正我吓一跳

    展开全文
  • 1) 如果十个手指每一表示一个数【就像幼儿园老师一开始教的那样】,一手指都不伸出表示0,伸出第一手指表示1,第二表示2,......,可以出11种(0..10) 2) 如果稍微改一下,两只手一只表示一位,...

    复习微机原理实在无聊。。。想到了这个奇怪的问题

     

    举几个栗子:

    1)  如果十个手指每一个表示一个数【就像幼儿园老师一开始教的那样】,一个手指都不伸出表示0,伸出第一个手指表示1,第二个表示2,......,可以数出11种数(0..10)

    2)  如果稍微改一下,两只手每一只表示一位,那么对于每只手,就有:

    手势表示的数字
    一个手指都不伸0
    伸出第一个手指1
    第二个2
    第三个3
    第四个4
    第五个5

       这样一只手可以表示6种信息。两只手加起来呢?由乘法原理,可以数出6*6=36种

       【原来幼儿园老师在骗我 Σ(っ °Д °;)っ

    3)  如果每个手指表示一位呢?对于每个手指,伸出表示1,不伸出表示0

       那么两只手就构成了一个十位的二进制数,范围从0(0000000000)到1023(1111111111),能数1024种

       【二进制的威力果然无穷 _(:з」∠)_

     

    从上面来看好像第三种最厉害的样子。。那么能否证明呢?

    首先我们引出第一个概念:信息量

    设一个信息由n个符号表示,第k个符号出现的概率是Pk,那么

    $H=- \sum ^{n}_{k=1}p_{k}\log_{2}p_{k}$

    在我们的数数问题中,每种符号(0....X中每个数)的出现概率可以认为是相等的,那么即

    $H=\log _{2}n$

    设把十只手指头分成X位,每一位用Y个手指表示,那么X*Y=10,而且总信息量为

    $H=X\cdot \log _{2}(Y+1)$      //Y+1是因为还要考虑到0的情况

    那么上面的问题就转化成了求这个函数的极值的问题。

    这是个减函数,而我们的Y的取值又是离散的[1..10],所以当Y=1的时候信息量H最大,也就是用二进制表示。

    如果换种方式呢?比如3、2、3、2(分四位,每一位的手指头数分别是3,2,3,2),那么H=log2(3)+log2(2)+log2(3)+log2(2)≈7.17,还是不如二进制。蛤蛤

     

    由这个奇怪的问题可以接着扩展出信息熵的概念:信息熵可以理解为事件整体的信息量的数学期望值。

    下面的柿子中,Pk表示第k种可能事件的概率,log2(1/Pk)即这种可能事件的信息量

    事件的不确定性越大,那么它的其中一种可能性的信息量就越大,总体的信息也越大。

    如果一个事件是确定的(即概率为1),那么信息熵就是0了。

     

     

     另外还发现RuanYifeng大神一篇好玩的小文章:http://www.ruanyifeng.com/blog/2014/09/information-entropy.html

     

    //Reference: https://zh.wikipedia.org/wiki/%E4%BF%A1%E6%81%AF%E8%AE%BA

     

    转载于:https://www.cnblogs.com/pdev/p/4638523.html

    展开全文
  • 亿数字里面最小的10个数字

    万次阅读 2017-04-14 22:18:12
    * 首先建立节点个数10的最大堆,然后考虑每一个新的值,让他和堆顶比较,堆顶大的元素直接抛弃,如果堆顶小的数字,让他替换堆顶,然后调整堆。 */ public class MaxTenNumber { public static void main
    package com.yuzhiyun;
    
    import java.util.Arrays;
    
    /**
     * 求一亿个数里面最小的10个数
     * 首先建立节点个数为10的最大堆,然后考虑每一个新的值,让他和堆顶比较,比堆顶大的元素直接抛弃,如果比堆顶小的数字,让他替换堆顶,然后调整堆。
     */
    public class MaxTenNumber {
        public static void main(String[] args) {
            /**第一个元素0不参与,只是用于占位置,这样的话,只要array[k]>array[2k] && array[k]>array[2k+1]那就是最大堆了,
             * 此外,这里暂时用20个数代替1亿个
             */
            int[] array={0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20,6,5};
            //建立建立节点个数为10的最大堆
            for(int i=10/2;i>=1;i--){
                adjustHeap(array, i, 10);
            }
            //System.out.println(Arrays.toString(array));
            for(int i=11;i<array.length;i++){
                //如果这个元素小于堆顶,和堆顶交换,然后重新调整堆
                if(array[i]<array[1]){
                    swap(array, i, 1);
                    adjustHeap(array, 1, 10);
                }
    
            }
            System.out.println(Arrays.toString(array));
            System.out.println("最小的10个数字为:");
            for(int i=1;i<=10;i++){
                System.out.print(array[i]+" ");
            }
        }
    
        /**
         * 交换
         * @param array
         * @param i
         * @param j
         */
        private static void swap(int[] array, int i, int j) {
            int tem=array[i];
            array[i]=array[j];
            array[j]=tem;
        }
    
        /**
         * 在以array[head]为根的左右子树是最大堆的前提下把以array[head]为根的树调整为最大堆
         * @param array
         * @param head
         * @param tail
         */
        static void adjustHeap(int[] array,int head,int tail){
            int root=array[head];
            int i=2*head;
            while(i<=tail){
                int max=array[i];
                if(i+1<=tail)
                    if(array[i+1]>array[i]){
                        max=array[i+1];
                        i++;
                    }
                if(root>max)
                    //别手抖写成了return;
                    break;
                else{
                    array[i/2]=array[i];        
                }
                i*=2;
            }
            array[i/2]=root;
        }
    }
    
    展开全文
  • 作者: 龙心尘&&寒小阳 时间:2015年12月。 出处: ...声明:版权所有,转载请联系作者并注明出处,谢谢。...就像刚开始学游泳,你在在岸上比划堆规定动作还不如先跳到水里熟悉水性学习来得快。以我们学习“机

    作者: 龙心尘&&寒小阳
    时间:2015年12月。
    出处:
    http://blog.csdn.net/longxinchen_ml/article/details/50281247
    http://blog.csdn.net/han_xiaoyang/article/details/50282141
    声明:版权所有,转载请联系作者并注明出处,谢谢。

    1、 引言:不要站在岸上学游泳

    “机器学习”是一个很实践的过程。就像刚开始学游泳,你在只在岸上比划一堆规定动作还不如先跳到水里熟悉水性学习来得快。以我们学习“机器学习”的经验来看,很多高大上的概念刚开始不懂也没关系,先写个东西来跑跑,有个感觉了之后再学习那些概念和理论就快多了。如果别人已经做好了轮子,直接拿过来用则更快。因此,本文直接用Michael Nielsen先生的代码(github地址压缩包地址)作为例子,给大家展现神经网络分析的普遍过程:导入数据,训练模型,优化模型,启发式理解等

    本文假设大家已经了解python的基本语法,并在自己机器上运行过简单python脚本。

    2、 我们要解决的问题:手写数字识别

    手写数字识别是机器学习领域中一个经典的问题,是一个看似对人类很简单却对程序十分复杂的问题。很多早期的验证码就是利用这个特点来区分人类和程序行为的,当然此处就不提12306近乎反人类的奇葩验证码了。


    验证码图

    回到手写数字识别,比如我们要识别出一个手写的“9”,人类可能通过识别“上半部分一个圆圈,右下方引出一条竖线”就能进行判断。但用程序表达就似乎很困难了,你需要考虑非常多的描述方式,考虑非常多的特殊情况,最终发现程序写得非常复杂而且效果不好。

    而用(机器学习)神经网络的方法,则提供了另一个思路:获取大量的手写数字的图像,并且已知它们表示的是哪个数字,以此为训练样本集合,自动生成一套模型(如神经网络的对应程序),依靠它来识别新的手写数字。


    手写数字

    本文中采用的数据集就是 著名的“MNIST数据集”。它的收集者之一是人工智能领域著名的科学家——Yann LeCu。这个数据集有60000个训练样本数据集和10000个测试用例。运用本文展示的单隐层神经网络,就可以达到96%的正确率。

    3、图解:解决问题的思路

    我们可以用下图展示上面的粗略思路。


    粗略思路

    但是如何由“训练集”来“生成模型”呢?

    在这里我们使用反复推荐的逆推法——假设这个模型已经生成了,它应该满足什么样的特性,再以此特性为条件反过来求出模型。

    可以推想而知,被生成的模型应该对于训练集的区分效果非常好,也就是相应的训练误差非常低。比如有一个未知其相应权重和偏移的神经网络,而训练神经网络的过程就是逐步确定这些未知参数的过程,最终使得这些参数确定的模型在训练集上的误差达到最小值。我们将会设计一个数量指标衡量这个误差,如果训练误差没有达到最小,我们将继续调整参数,直到这个指标达到最小。但这样训练出来的模型我们仍无法保证它面对新的数据仍会有这样好的识别效果,就需要用测试集对模型进行考核,得出的测试结果作为对模型的评价。因此,上图就可以细化成下图:


    细化成下图

    但是, 如果我们已经生成了多个模型,怎么从中选出最好的模型?一个自然的思路就是通过比较不同模型在测试集上的误差,挑选出误差最小的模型。这个想法看似没什么问题,但是随着你测试的模型增多,你会觉得用测试集筛选出来的模型也不那么可信。比如我们增加一个神经网络的隐藏层节点,就会产生新的对应权重,产生一个新的模型。但是我也不知道增加多少个节点是合适的,所以比较全面的想法就是尝试测试不同的节点数x∈(1,2,3,4,…,100), 来观察这些不同模型的测试误差,并挑出误差最小的模型。 这时我们发现我们的模型其实多出来了一个参数x, 我们挑选模型的过程就是确定最优化的参数x 的过程。这个分析过程与上面训练参数的思路如出一辙!只是这个过程是基于同一个测试集,而不训练集。那么,不同的神经网络的层数是不是也是一个新的参数y∈(1,2,3,4,…,100), 也要经过这么个过程来“训练”?

    我们会发现我们之前生成模型过程中很多不变的部分其实都是可以变换调节的,这些也是新的参数,比如训练次数、梯度下降过程的步长、规范化参数、学习回合数、minibatch 值等等,我们把他们叫做超参数。超参数是影响所求参数最终取值的参数,是机器学习模型里面的框架参数,可以理解成参数的参数,它们通常是手工设定,不断试错调整的,或者对一系列穷举出来的参数组合一通进行枚举(网格搜索)来确定。但无论如何,这也是基于同样一个数据集反复验证优化的结果。在这个数据集上最后的结果并不一定在新的数据继续有效。所以为了评估这个模型的识别效果,就需要用新的测试集对模型进行考核,得出的测试结果作为对模型的评价。这个新的测试集我们就直接叫“测试集”,之前那个用于筛选超参数的测试集,我们就叫做“交叉验证集”。筛选模型的过程其实就是交叉验证的过程。

    所以,规范的方法的是将数据集拆分成三个集合:训练集、交叉验证集、测试集,然后依次训练参数、超参数,最终得到最优的模型。

    因此,上图可以进一步细化成下图:


    进一步细化成下图

    或者下图:

    进一步细化成下图2

    可见机器学习过程 是一个反复迭代不断优化的过程。其中很大一部分工作是在调整参数和超参数。

    4、先跑跑再说:初步运行代码

    Michael Nielsen的代码封装得很好,只需以下5行命令就可以生成神经网络并测试结果,并达到94.76%的正确率!。

    import mnist_loader
    import network
    # 将数据集拆分成三个集合:训练集、交叉验证集、测试集
    training_data, validation_data, test_data = mnist_loader.load_data_wrapper()
    # 生成神经网络对象,神经网络结构为三层,每层节点数依次为(784, 30, 10)
    net = network.Network([784, 30, 10])
    # 用(mini-batch)梯度下降法训练神经网络(权重与偏移),并生成测试结果。
    # 训练回合数=30, 用于随机梯度下降法的最小样本数=10,学习率=3.0
    net.SGD(training_data, 30, 10, 3.0, test_data=test_data)
    • 第一个命令的功能是:将数据集拆分成三个集合:训练集、交叉验证集、测试集。

    • 第二个命令的功能是:生成神经网络对象,神经网络结构为三层,每层节点数依次为(784, 30, 10)。

    • 第三个命令的功能是:用(mini-batch)梯度下降法训练神经网络(权重与偏移),并生成测试结果。

    • 该命令设定了三个超参数:训练回合数=30, 用于随机梯度下降法的最小样本数(mini-batch-size)=10,步长=3.0。

    本文并不打算详细解释随机梯度下降法的细节,感兴趣的同学请阅读前文《深度学习与计算机视觉系列(4)_最优化与随机梯度下降》

    总共的输出结果如下:

    Epoch 0: 9045 / 10000
    Epoch 1: 9207 / 10000
    Epoch 2: 9273 / 10000
    Epoch 3: 9302 / 10000
    Epoch 4: 9320 / 10000
    Epoch 5: 9320 / 10000
    Epoch 6: 9366 / 10000
    Epoch 7: 9387 / 10000
    Epoch 8: 9427 / 10000
    Epoch 9: 9402 / 10000
    Epoch 10: 9400 / 10000
    Epoch 11: 9442 / 10000
    Epoch 12: 9448 / 10000
    Epoch 13: 9441 / 10000
    Epoch 14: 9443 / 10000
    Epoch 15: 9479 / 10000
    Epoch 16: 9459 / 10000
    Epoch 17: 9446 / 10000
    Epoch 18: 9467 / 10000
    Epoch 19: 9470 / 10000
    Epoch 20: 9459 / 10000
    Epoch 21: 9484 / 10000
    Epoch 22: 9479 / 10000
    Epoch 23: 9475 / 10000
    Epoch 24: 9482 / 10000
    Epoch 25: 9489 / 10000
    Epoch 26: 9489 / 10000
    Epoch 27: 9478 / 10000
    Epoch 28: 9480 / 10000
    Epoch 29: 9476 / 10000

    5、神经网络如何识别手写数字:启发式理解

    首先,我们解释一下神经网络每层的功能。


    神经网络每层

    第一层是输入层。因为mnist数据集中每一个手写数字样本是一个28*28像素的图像,因此对于每一个样本,其输入的信息就是每一个像素对应的灰度, 总共有28*28=784个像素,故这一层有784个节点

    第三层是输出层。因为阿拉伯数字总共有10个,我们就要将样本分成10个类别,因此输出层我们采用10个节点。当样本属于某一类(某个数字)的时候,则该类(该数字)对应的节点为1,而剩下9个节点为0,如[0,0,0,1,0,0,0,0,0,0]。

    因此,我们每一个样本(手写数字的图像)可以用一个超长的784维的向量表示其特征,而用一个10维向量表示该样本所属的类别(代表的真实数字),或者叫做标签。

    mnist的数据就是这样表示的。所以,如果你想看训练集中第n个样本的784维特征向量,直接看training_data[n][0]就可以找到,而要看其所属的标签,看training_data[n][1]就够了。

    那么,第二层神经网络所代表的意义怎么理解?这其实是很难的。但是我们可以有一个启发式地理解,比如用中间层的某一个节点表示图像中的某一个小区域的特定图像。这样,我们可以假设中间层的头4个节点依次用来识别图像左上、右上、左下、右下4个区域是否存在这样的特征的。

    左上右上、左下、右下

    如果这四个节点的值都很高,说明这四个区域同时满足这些特征。将以上的四个部分拼接起来,我们会发现,输入样本很可能就是一个手写“0”!


    0

    因此, 同一层的几个神经元同时被激活了意味着输入样本很可能是某个数字。

    当然,这只是对神经网络作用机制的一个启发式理解。真实的过程却并不一定是这样。但通过启发式理解,我们可以对神经网络作用机制有一个更加直观的认识。

    由此可见,神经网络能够识别手写数字的关键是它有能够对特定的图像激发特定的节点。而神经网络之所以能够针对性地激发这些节点,关键是它具有能够适应相关问题场景的权重和偏移。那这些权重和偏移如何训练呢?

    6、神经网络如何训练:进一步阅读代码

    上文已经图解的方式介绍了机器学习解决问题的一般思路,但是具体到神经网络将是如何训练呢?

    其实最快的方式是直接阅读代码。我们将代码的结构用下图展示出来,运用其内置函数名表示基本过程,发现与我们上文分析的思路一模一样


    分析思路

    简单解释一下,在神经网络模型中:

    • 所需要求的关键参数就是:神经网络的权重(self.weights)和偏移(self.biases)。
    • 超参数是:隐藏层的节点数=30,训练回合数(epochs)=30, 用于随机梯度下降法的最小样本数(mini_batch_size)=10,步长(eta)=3.0。
    • 用随机梯度下降法调整参数: 梯度下降
    • 用反向传播法求出随机梯度下降法所需要的梯度(偏导数): backprop()
    • 用输出向量减去标签向量衡量训练误差:cost_derivative() = output_activations-y

    全部代码如下(去掉注释之后,只有74行):

    """
    network.py
    ~~~~~~~~~~
    
    A module to implement the stochastic gradient descent learning
    algorithm for a feedforward neural network.  Gradients are calculated
    using backpropagation.  Note that I have focused on making the code
    simple, easily readable, and easily modifiable.  It is not optimized,
    and omits many desirable features.
    """
    
    #### Libraries
    # Standard library
    import random
    
    # Third-party libraries
    import numpy as np
    
    class Network(object):
    
        def __init__(self, sizes):
            """The list ``sizes`` contains the number of neurons in the
            respective layers of the network.  For example, if the list
            was [2, 3, 1] then it would be a three-layer network, with the
            first layer containing 2 neurons, the second layer 3 neurons,
            and the third layer 1 neuron.  The biases and weights for the
            network are initialized randomly, using a Gaussian
            distribution with mean 0, and variance 1.  Note that the first
            layer is assumed to be an input layer, and by convention we
            won't set any biases for those neurons, since biases are only
            ever used in computing the outputs from later layers."""
            self.num_layers = len(sizes)
            self.sizes = sizes
            self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
            self.weights = [np.random.randn(y, x)
                            for x, y in zip(sizes[:-1], sizes[1:])]
    
        def feedforward(self, a):
            """Return the output of the network if ``a`` is input."""
            for b, w in zip(self.biases, self.weights):
                a = sigmoid(np.dot(w, a)+b)
            return a
    
        def SGD(self, training_data, epochs, mini_batch_size, eta,
                test_data=None):
            """Train the neural network using mini-batch stochastic
            gradient descent.  The ``training_data`` is a list of tuples
            ``(x, y)`` representing the training inputs and the desired
            outputs.  The other non-optional parameters are
            self-explanatory.  If ``test_data`` is provided then the
            network will be evaluated against the test data after each
            epoch, and partial progress printed out.  This is useful for
            tracking progress, but slows things down substantially."""
            if test_data: n_test = len(test_data)
            n = len(training_data)
            for j in xrange(epochs):
                random.shuffle(training_data)
                mini_batches = [
                    training_data[k:k+mini_batch_size]
                    for k in xrange(0, n, mini_batch_size)]
                for mini_batch in mini_batches:
                    self.update_mini_batch(mini_batch, eta)
                if test_data:
                    print "Epoch {0}: {1} / {2}".format(
                        j, self.evaluate(test_data), n_test)
                else:
                    print "Epoch {0} complete".format(j)
    
        def update_mini_batch(self, mini_batch, eta):
            """Update the network's weights and biases by applying
            gradient descent using backpropagation to a single mini batch.
            The ``mini_batch`` is a list of tuples ``(x, y)``, and ``eta``
            is the learning rate."""
            nabla_b = [np.zeros(b.shape) for b in self.biases]
            nabla_w = [np.zeros(w.shape) for w in self.weights]
            for x, y in mini_batch:
                delta_nabla_b, delta_nabla_w = self.backprop(x, y)
                nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
                nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
            self.weights = [w-(eta/len(mini_batch))*nw
                            for w, nw in zip(self.weights, nabla_w)]
            self.biases = [b-(eta/len(mini_batch))*nb
                           for b, nb in zip(self.biases, nabla_b)]
    
        def backprop(self, x, y):
            """Return a tuple ``(nabla_b, nabla_w)`` representing the
            gradient for the cost function C_x.  ``nabla_b`` and
            ``nabla_w`` are layer-by-layer lists of numpy arrays, similar
            to ``self.biases`` and ``self.weights``."""
            nabla_b = [np.zeros(b.shape) for b in self.biases]
            nabla_w = [np.zeros(w.shape) for w in self.weights]
            # feedforward
            activation = x
            activations = [x] # list to store all the activations, layer by layer
            zs = [] # list to store all the z vectors, layer by layer
            for b, w in zip(self.biases, self.weights):
                z = np.dot(w, activation)+b
                zs.append(z)
                activation = sigmoid(z)
                activations.append(activation)
            # backward pass
            delta = self.cost_derivative(activations[-1], y) * \
                sigmoid_prime(zs[-1])
            nabla_b[-1] = delta
            nabla_w[-1] = np.dot(delta, activations[-2].transpose())
            # Note that the variable l in the loop below is used a little
            # differently to the notation in Chapter 2 of the book.  Here,
            # l = 1 means the last layer of neurons, l = 2 is the
            # second-last layer, and so on.  It's a renumbering of the
            # scheme in the book, used here to take advantage of the fact
            # that Python can use negative indices in lists.
            for l in xrange(2, self.num_layers):
                z = zs[-l]
                sp = sigmoid_prime(z)
                delta = np.dot(self.weights[-l+1].transpose(), delta) * sp
                nabla_b[-l] = delta
                nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
            return (nabla_b, nabla_w)
    
        def evaluate(self, test_data):
            """Return the number of test inputs for which the neural
            network outputs the correct result. Note that the neural
            network's output is assumed to be the index of whichever
            neuron in the final layer has the highest activation."""
            test_results = [(np.argmax(self.feedforward(x)), y)
                            for (x, y) in test_data]
            return sum(int(x == y) for (x, y) in test_results)
    
        def cost_derivative(self, output_activations, y):
            """Return the vector of partial derivatives \partial C_x /
            \partial a for the output activations."""
            return (output_activations-y)
    
    #### Miscellaneous functions
    def sigmoid(z):
        """The sigmoid function."""
        return 1.0/(1.0+np.exp(-z))
    
    def sigmoid_prime(z):
        """Derivative of the sigmoid function."""
        return sigmoid(z)*(1-sigmoid(z))

    7、神经网络如何优化:训练超参数与多种模型对比

    由以上分析可知,神经网络只需要74行代码就可以完成编程,可见机器学习真正困难的地方并不在编程,而在你对数学过程本身,和对它与现实问题的对应关系有深入的理解。理解深入后,你才能写出这样的程序,并对其进行精微的调优

    我们初步的结果已经是94.76%的正确率了。但如果要将准确率提得更高怎么办?

    这其实是一个开放的问题,有许多方法都可以尝试。我们这里仅仅是抛砖引玉。

    首先,隐藏层只有30个节点。由我们之前对隐藏层的启发式理解可以猜测,神经网络的识别能力其实与隐藏层对一些细节的识别能力正相关。如果隐藏层的节点更多的话,其识别能力应该会更强的。那么我们设定100个隐藏层节点试试?

    net = network.Network([784, 100, 10])
    net.SGD(training_data, 30, 10, 3.0, test_data=test_data)

    发现结果如下:

    Epoch 0: 6669 / 10000
    Epoch 1: 6755 / 10000
    Epoch 2: 6844 / 10000
    Epoch 3: 6833 / 10000
    Epoch 4: 6887 / 10000
    Epoch 5: 7744 / 10000
    Epoch 6: 7778 / 10000
    Epoch 7: 7876 / 10000
    Epoch 8: 8601 / 10000
    Epoch 9: 8643 / 10000
    Epoch 10: 8659 / 10000
    Epoch 11: 8665 / 10000
    Epoch 12: 8683 / 10000
    Epoch 13: 8700 / 10000
    Epoch 14: 8694 / 10000
    Epoch 15: 8699 / 10000
    Epoch 16: 8715 / 10000
    Epoch 17: 8770 / 10000
    Epoch 18: 9611 / 10000
    Epoch 19: 9632 / 10000
    Epoch 20: 9625 / 10000
    Epoch 21: 9632 / 10000
    Epoch 22: 9651 / 10000
    Epoch 23: 9655 / 10000
    Epoch 24: 9653 / 10000
    Epoch 25: 9658 / 10000
    Epoch 26: 9653 / 10000
    Epoch 27: 9664 / 10000
    Epoch 28: 9655 / 10000
    Epoch 29: 9672 / 10000

    发现,我们只是改了一个超参数,准确率就从94.76%提升到96.72%!

    这里强调一下,更加规范的模型调优方法是将多个模型用交叉验证集的结果来横向比较,选出最优模型后再用一个新的测试集来最终评估该模型。本文为了与之前的结果比较,才采用了测试集而不是交叉验证集。读者千万不要学博主这样做哈,因为这很有可能会过拟合。这是工程实践中数据挖掘人员经常犯的错误,我们之后会专门写篇博文探讨

    我们现在回来继续调优我们的模型。那么还有其他的隐藏节点数更合适吗?这个我们也不知道。常见的方法是用几何级数增长的数列(如:10,100,1000,……)去尝试,然后不断确定合适的区间,最终确定一个相对最优的值。

    但是即便如此,我们也只尝试了一个超参数,还有其他的超参数没有调优呢。我们于是尝试另一个超参数:步长。之前的步长是3.0,但是我们可能觉得学习速率太慢了。那么尝试一个更大的步长试试?比如100?

    net = network.Network([784, 30, 10])
    net.SGD(training_data, 30, 10, 100.0, test_data=test_data)

    发现结果如下:

    Epoch 0: 1002 / 10000
    Epoch 1: 1002 / 10000
    Epoch 2: 1002 / 10000
    Epoch 3: 1002 / 10000
    Epoch 4: 1002 / 10000
    Epoch 5: 1002 / 10000
    Epoch 6: 1002 / 10000
    Epoch 7: 1002 / 10000
    Epoch 8: 1002 / 10000
    Epoch 9: 1002 / 10000
    Epoch 10: 1002 / 10000
    Epoch 11: 1002 / 10000
    Epoch 12: 1001 / 10000
    Epoch 13: 1001 / 10000
    Epoch 14: 1001 / 10000
    Epoch 15: 1001 / 10000
    Epoch 16: 1001 / 10000
    Epoch 17: 1001 / 10000
    Epoch 18: 1001 / 10000
    Epoch 19: 1001 / 10000
    Epoch 20: 1000 / 10000
    Epoch 21: 1000 / 10000
    Epoch 22: 999 / 10000
    Epoch 23: 999 / 10000
    Epoch 24: 999 / 10000
    Epoch 25: 999 / 10000
    Epoch 26: 999 / 10000
    Epoch 27: 999 / 10000
    Epoch 28: 999 / 10000
    Epoch 29: 999 / 10000

    发现准确率低得不忍直视,看来步长设得太长了。根本跑不到最低点。那么我们设定一个小的步长试试?比如0.01。

    net = network.Network([784, 100, 10])
    net.SGD(training_data, 30, 10, 0.001, test_data=test_data)

    结果如下:

    Epoch 0: 790 / 10000
    Epoch 1: 846 / 10000
    Epoch 2: 854 / 10000
    Epoch 3: 904 / 10000
    Epoch 4: 944 / 10000
    Epoch 5: 975 / 10000
    Epoch 6: 975 / 10000
    Epoch 7: 975 / 10000
    Epoch 8: 975 / 10000
    Epoch 9: 974 / 10000
    Epoch 10: 974 / 10000
    Epoch 11: 974 / 10000
    Epoch 12: 974 / 10000
    Epoch 13: 974 / 10000
    Epoch 14: 974 / 10000
    Epoch 15: 974 / 10000
    Epoch 16: 974 / 10000
    Epoch 17: 974 / 10000
    Epoch 18: 974 / 10000
    Epoch 19: 976 / 10000
    Epoch 20: 979 / 10000
    Epoch 21: 981 / 10000
    Epoch 22: 1004 / 10000
    Epoch 23: 1157 / 10000
    Epoch 24: 1275 / 10000
    Epoch 25: 1323 / 10000
    Epoch 26: 1369 / 10000
    Epoch 27: 1403 / 10000
    Epoch 28: 1429 / 10000
    Epoch 29: 1451 / 10000

    呃,发现准确率同样低得不忍直视。但是有一个优点,准确率是稳步提升的。说明模型在大方向上应该还是对的。如果在调试模型的时候忽视了这个细节,你可能真的找不到合适的参数。

    可见,我们第一次尝试的神经网络结构的超参数设定还是比较不错的。但是真实的应用场景中,基本没有这样好的运气,很可能刚开始测试出来的结果全是奇葩生物,长得违反常理,就像来自另一个次元似的。这是数据挖掘工程师常见的情况。此时最应该做的,就是遏制住心中数万草泥马的咆哮奔腾,静静地观察测试结果的分布规律,尝试找到些原因,再继续将模型试着调优下去,与此同时,做好从一个坑跳入下一个坑的心理准备。当然,在机器学习工程师前赴后继的填坑过程中,还是总结出了一些调优规律。我们会在接下来专门写博文分析。

    当然,以上的调优都没有逃出神经网络模型本身的范围。但是可不可能其他的模型效果更好?比如传说中的支持向量机?关于支持向量机的解读已经超越了本文的篇幅,我们也考虑专门撰写博文分析。但是在这里我们只是引用一下在scikit-learn中提供好的接口,底层是用性能更好的C语言封装的著名的LIBSVM

    相关代码也在Michael Nielsen的文件中。直接引入,并运行一个方法即可。

    import mnist_svm
    mnist_svm.svm_baseline()

    我们看看结果:

    Baseline classifier using an SVM.
    9435 of 10000 values correct.

    94.35%,好像比我们的神经网络低一点啊。看来我们的神经网络模型还是更优秀一些?

    然而,实际情况并非如此。因为我们用的只是scikit-learn给支持向量机的设好的默认参数。支持向量机同样有一大堆可调的超参数,以提升模型的效果。 跟据 Andreas Mueller这篇博文,调整好超参数的支持向量机能够达到98.5%的准确度!比我们刚才最好的神经网络提高了1.8个百分点!

    然而,故事并没有结束。2013年,通过深度神经网络,研究者可以达到99.79%的准确度!而且,他们并没有运用很多高深的技术。很多技术在我们接下来的博文中都可以继续介绍。

    所以,从目前的准确度来看:

    简单的支持向量机<浅层神经网络<调优的支持向量机<深度神经网络

    但还是要提醒一下,炫酷的算法固然重要,但是良好的数据集有时候比算法更重要。Michael Nielsen专门写了一个公式来来表达他们的关系:

    精致的算法 ≤ 简单的算法 + 良好的训练数据
    sophisticated algorithm ≤ simple learning algorithm + good training data.

    所以为了调优模型,往往要溯源到数据本身,好的数据真的会有好的结果。

    8、小结与下期预告

    以上我们只是粗略地展示了用神经网络分析问题的基本过程,很多深入的内容并没有展开。我们将会在接下来的博文中进行深入探讨。

    在该系列下一篇博文中,我们试图直接探讨深度神经网络的表现能力,并提供一个启发式理解。敬请关注。

    展开全文
  • 问题描述: 将1-9的9数字不重复的填入[ ][ ][ ] + [ ][ ][ ] = [ ]...将9不重复数字填入到9位置并且满足等式成立条件,可以看做求9数组的全排列,只要全排列满足 前3数字 + 中间3数字 = 最后3数字即可...
  • plt.xticks(range(0,30,3)) #个数 这里是三一个间隔 共10个 和下面的一样 ax2.set_xticklabels(data.index[::3]) #显示日期 否则就是显示整数 以三天为一个间隔 # 创建差值折线图 plt.show()  
  • 入门学习Linux常用必会60命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    然后需按“Alt+ F1”键,就可以回到第一个虚拟控制台。一个新安装的Linux系统允许用户使用“Alt+F1”到“Alt+F6”键来访问前六虚拟控制台。虚拟控制台最有用的是,当一个程序出错造成系统死锁时,可以切换到其它...
  •  System.out.println("请输入一个"+start+"到"+end+"的:");  N=reader.nextInt();  if(N>end||N) {  System.out.println("输入数字非法。");  }  else if(N>x){  System.out.println("输入数字大了。...
  • CNN实现MNIST手写数字识别

    万次阅读 多人点赞 2017-10-28 20:44:35
    关键词:CNN、TensorFlow、卷积、池化、特征图 . 前言本文用TensorFlow实现了...数据来源自MNIST, 为了方便起见,已经准备了一个脚本来自动下载和导入MNIST数据集。它会自动创建一个’MNIST_data’的目录来存储数据。
  • 题目:10层的二叉树,最多包含多少结点? 10层的二叉树,最多包含多少结点?  注意当棵二叉树只有一个结点时为层。 答案提交  这是一道结果填空的题,你需要算出结果后提交即可。本题的结果为...
  • MNIST手写数字数据集读取方法

    万次阅读 多人点赞 2018-08-16 10:22:37
    MNIST是一个非常有名的手写体数字识别数据集,在很多资料中,这数据集都会被用作深度学习的入门样例。 数据集下载网址:http://yann.lecun.com/exdb/mnist/ 数据集简介: 1、共有4数据集,下载之后并将其解压...
  • 酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚杯酒。两人同赢或两人同输则继续下轮,直到唯一的赢家出现。 下面给...
  • win10自动修复重启失败,无法进入桌面,解决办法

    万次阅读 多人点赞 2019-05-20 00:08:19
    本来在搞虚拟机,作死的开了三台,就蓝屏了,然后重启一直显示自动修复失败之类的,打电话给技术支持就知道说重装,搞了晚上,终于弄好了,将我的方法分享一下: 1.选择高级选项 2.后面忘了拍照片,就找到...
  • CNN卷积神经网络手写数字识别实例及代码详解

    万次阅读 多人点赞 2016-12-30 22:57:34
    本文的代码来自githup的Deep Learning的toolbox,是用Matlab实现的。感谢该toolbox的作者付出和分享。 我在应该该代码进行训练...本文mnist_uint8.mat的获取可以参照我的另篇博客:MNIST数据库处理--matlab生成mnist_
  • 前言: 本文将介绍种经典的卷积神经网络的网络结构——LeNet-5模型,并给出一个完整的TensorFlow程序来实现LeNet-5模型。通过这模型,我们可以得到卷积网络结构设计的一个通用模式。、卷积神经网络简介 在这...
  • 写在前面这段的内容可以说是最难的部分之了,因为是识别图像,所以涉及到的算法会相比之前的来说比较困难,所以我尽量会讲得清楚一点。而且因为在编写的过程中,把前面的一些逻辑也修改了一些,将其变得更完善...
  • 那么我们再来看一个例子,就知道为何要用先获取一个很大的了: 首先,第一个字符串是 bcd,每字符的Unicode 编码分别为 98 、99 、100,加起来等于297,297 % 10 = 7,所以字符串 bcd 在数组中的下标值就为7;...
  • 1. 这本书对Python的知识点的描述很详细,而且排版看的很舒服. 2. 几例题:假装自己从零开始学,将一些有代表性、有意思的例题抽取出来. 3. 还有自己对部分课后复习题,全部课后上机实践题的解题思路
  • 本篇文章将开始讲解树结构。...那么本文就从零开始学习一下树结构,并且也会封装一个二叉查找树,本文 3万+ 的详细教程,希望大家耐心观看,我是以一个纯小白的角度来写的这篇文章,相信大家认真看一定都能看懂的
  • CNN参数个数和连接个数计算详解

    万次阅读 2017-09-18 15:29:31
    之前所讲的图像处理都是小 patchs ,比如28*28或者36*36之类,考虑如下情形,对于副1000*1000的图像,即106,当隐层也有106节点时,那么W(1)的数量将达到1012级别,为了减少参数规模,加快训练速度,CNN应运而生。...
  • RocketMQ

    万次阅读 多人点赞 2019-07-31 19:17:34
    、RocketMQ简介 1.1、介绍 RocketMQ是款分布式、队列模型的消息中间件,由Metaq3.X版本改名而来,RocketMQ并不遵循包括JMS规范在内的任何规范,但是参考了各种规范不同类产品的设计思想,自己有套...
  • 一只猴子把这堆桃子凭据分为五份,多了 一,这只猴子把多的一扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分 成五份,又多了一,它同样把多的一扔入海中,拿走了一份,第三、第四、第五只 猴子都...
  • PTA 7-2 求素数个数 (30分)

    千次阅读 热门讨论 2020-10-11 11:31:48
    本题要求编写一个程序,求1~n的素数个数。 要求至少给出两种解法,对于相同的n,给出这两种解法的结果,通过相关数据进行测试,目的是通过对比同一问题不同解法的绝对执行时间体会如何设计“好”的算法。 输入格式: ...
  • hive控制文件生成个数

    万次阅读 2017-02-27 12:58:01
    在有些时候,想要控制hql执行的mapper,reducer个数,reducer设置过少,会导致每reducer要处理的数据过多,这样可能会导致OOM异常,如果reducer设置过多,则会导致产生很多小文件,这样对任务的执行以及集群都不太好...
  • 三、70044与113148的最大公约数要点答案手写代码四、10层的二叉树,最多包含多少结点?要点答案手写代码五、洁净要点代码六、递增序列要点代码七、最大的元素距离要点代码八、元音字母辅音字母的数量要点...
  • 现在趁着有点空闲,随手记录一点以前学过的,或者正在学习的知识点,相当于一个备忘录。 ** 2.卷积神经网络模型概览 ** 从开始的LeNet到后来的VGGNet,再到google的Inception系列,再到ResNet系列,每种神经...
  • 看到有些答案是刚开始随机初始化卷积核大小,卷积层和map个数是根据经验来设定的,但这里面应该是有深层次原因吧,比如下面的手写字卷积神经网络结构图1,最后输出为什么是12map,即输出12特征?然后图2又是...
  • 题目:群人围成圈从123报,如果报到3就退出该圈中,直到最后一个人留下来!问留下这人的位置是多少? 这是一个典型的约瑟夫环问题,接下来我只用Java的数组去实现,为什么用数组我觉得数组相对来说好理解还很...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 497,622
精华内容 199,048
关键字:

一只手比十个数