精华内容
下载资源
问答
  • 对IOC的相关理解总结

    万次阅读 多人点赞 2020-04-20 13:54:07
    (一)理解IoC,即“控制反转” (二)IoC具体做什么? (三)理解IoC和DI的关系 二、对IOC容器初始化的理解 四、对DI依赖注入的理解(主要是) 参考书籍、文献和资料 一、对IOC和DI的基本认识 (一)理解IoC...

    目录

    当前没有去添加对应的源码,只是自己的一些总结,可能理解有错误或不到位,还请指出。

    一、对IOC和DI的基本认识

    (一)理解IoC,即“控制反转”

    (二)IoC具体做什么?

    (三)理解IoC和DI的关系

    二、对IOC容器初始化的理解

    三、对DI依赖注入的理解

    参考书籍、文献和资料


    当前没有去添加对应的源码,只是自己的一些总结,可能理解有错误或不到位,还请指出。

    一、对IOC和DI的基本认识

    (一)理解IoC,即“控制反转”

    在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

    谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建以及外部资源获取(不只是对象包括比如文件等)

    为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转,依赖对象的获取被反转了

    (二)IoC具体做什么?

    IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。

    • 传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;
    • 有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
    • IoC对编程实现由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找

    (三)理解IoC和DI的关系

    DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

    理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

    谁依赖于谁:当然是应用程序依赖于IoC容器;

    为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;

    谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;

    ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

    IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”

    二、对IOC容器初始化的理解

    IOC容器初始化的基本步骤主要是两个方面:

    • 初始化的入口由容器实现中的refresh()方法调用来完成。
    • 对Bean定义载入IOC容器使用的方法是loadBeanDefinition()。

    大致过程如下:

    • 通过ReasourceLoader来完成资源文件的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以通过类路径、文件系统、URL等方式来定位资源
    • 如果XmlBeanFactory作为IOC容器,那么需要为它指定Bean定义的资源,也就是说Bean定义文件是通过抽象成Resource来被IOC容器处理,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用XmlBeanDefinitionReader来解析Bean的XML定义文件---实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到Bean的定义信息,这些信息在Spring中使用BeanDefinition来表示(这个名字可以让我们想到loadBeanDefinition()、registerBeanDefinition()这些相关的方法,他们都是为处理BeanDefinition服务的)。
    • 解析得到BeanDefinition以后,需要在IOC容器中注册,这由IOC实现BeanDefinitionRegister接口来实现,注册过程就是在IOC容器内容维护一个HashMap来保存得到的BeanDefinition的过程,这个HashMap是IOC容器持有Bean信息的场所,以后Bean的操作都是围绕这个HashMap来实现
    • 之后我们通过BeanFactory和ApplicationContext来享受Spring IOC的服务了,在使用IOC容器的时候我们注意到,除了少量粘合代码,绝大多数以正确IOC风格编写的应用程序代码完全不关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在了一起,基本的策略是把工厂放到已知的地方,最好放在对预期使用的上下文有意义的地方,以及代码要实际访问工厂的地方。
    • Spring本身提供了对声明式载入Web应用程序用法的应用程序上下文,并将其存储在ServletContext的框架实现中

    三、对DI依赖注入的理解

    当Spring IOC容器完成了Bean定义资源的定位、载入和解析注册,IOC容器就可以管理Bean定义的相关数据了,但是此时IOC容器还没有对所管理的Bean进行依赖注入,依赖注入 在以下两种情况下发生:

    • 用户第一次调用getBean()方法时,IOC容器触发依赖注入。
    • 当用户在配置文件中将<bean>元素配置了lazy-init=false属性时,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。

    Beanfactory接口定义了Spring IOC容器的基本功能规范,是Spring IOC容器所应遵守的最低层和最基本的编程规范。BeanFactory接口中定义了几个getBean()方法,用于用户向IOC容器索取被管理的Bean的方法,通过分析其子类的具体实现来理解Spring IOC容器在用户索取Bean时如何完成依赖注入

    • getBean方法肯定不陌生,必经之路,然后调用doGetBean,进来以后首先会执行transformedBeanName找别名,看你的Bean上面是否起了别名。然后进行很重要的一步,getSingleton,这段代码就是从你的单例缓存池中获取Bean的实例。那么你第一次进来肯定是没有的,缓存里肯定是拿不到的。也就是一级缓存里是没有的。那么它怎么办呢?他会尝试去二级缓存中去拿,但是去二级缓存中拿并不是无条件的,首先要判断isSingletonCurrentlyInCreation(beanName)他要看你这个对象是否正在创建当中,如果不是直接就退出该方法,如果是的话,他就会去二级缓存earlySingletonObjects里面取,如果没拿到,它还接着判断allowEarlyReference这个东西是否为true。它的意思是说,是否允许让你从单例工厂对象缓存中去拿对象。默认为true。好了,此时如果进来那么就会通过singletonFactory.getObject()去单例工厂缓存中去拿。然后将缓存级别提升至二级缓存也就早期暴露的缓存。
    • getSingleton执行完以后会走dependsOn方法,判断是否有dependsOn标记的循环引用,有的话直接卡死,抛出异常。比如说A依赖于B,B依赖于A 通过dependsOn注解去指定。此时执行到这里就会抛出异常。这里所指并非是构造函数的循环依赖。
    • beforeSingletonCreation在这里方法里,就把你的对象标记为了早期暴露的对象,提前暴露对象用于创建Bean的实例
    • 紧接着就走创建Bean的流程开始。在创建Bean之前执行了一下resolveBeforeInstantiation。它的意思是说,代理AOPBean定义注册信息但是这里并不是实际去代理你的对象,因为对象还没有被创建。只是代理了Bean定义信息,还没有被实例化把Bean定义信息放进缓存,以便我想代理真正的目标对象的时候,直接去缓存里去拿。
    • 接下来就真正的走创建Bean流程,首先走进真正做事儿的方法doCreateBean然后找到createBeanInstance这个方法,在这里面它将为你创建你的Bean实例信息(Bean的实例)。如果说创建成功了,那么就把你的对象放入缓存中去(将创建好的提前曝光的对象放入singletonFactories三级缓存中)将对象从二级缓存中移除因为它已经不是提前暴露的对象了。但是。如果说在createBeanInstance这个方法中在创建Bean的时候它会去检测你的依赖关系,会去检测你的构造器。然后,如果说它在创建A对象的时候,发现了构造器里依赖了B,然后它又会重新走getBean的这个流程,当在走到这里的时候,又发现依赖了A此时就会抛出异常。为什么会抛出异常,因为,走getBean的时候他会去从你的单例缓存池中去拿,因为你这里的Bean还没有被创建好。自然不会被放进缓存中,所以它是在缓存中拿不到B对象的。反过来也是拿不到A对象的。造成了死循环故此直接抛异常。这就是为什么Spring IOC不能解决构造器循环依赖的原因因为你还没来的急放入缓存你的对象是不存在的。所以不能创建。同理@Bean标注的循环依赖方法也是不能解决的,跟这个同理。那么多例就更不能解决了。为什么?因为在走createBeanInstance的时候,会判断是否是单例的Bean定义信息mbd.isSingleton();如果是才会进来。所以多例的Bean压根就不会走进来,而是走了另一段逻辑,这里不做介绍。至此,构造器循环依赖和@Bean的循环依赖还有多例Bean的循环依赖为什么不能解决已经解释清楚。然后如果说,Bean创建成功了。那么会走后面的逻辑。
    • 将创建好的Bean放入缓存,addSingletonFactory方法就是将你创建好的Bean放入三级缓存中,并且移除早期暴露的对象。
    • 通过populateBean给属性赋值,我们知道,创建好的对象,并不是一个完整的对象,里面的属性还没有被赋值。所以这个方法就是为创建好的Bean为它的属性赋值。并且调用了我们实现的的XXXAware接口进行回调初始化,然后调用我们实现的Bean的后置处理器,给我们最后一次机会去修改Bean的属性

    参考书籍、文献和资料

    1.https://www.iteye.com/blog/jinnianshilongnian-1413846

    2.《Sring 5 核心原理与30个类手写实战》,谭勇徳,中国公信出版社,2019.

    展开全文
  • 语义理解/口语理解,项目包含有词法分析:中文分词、词性标注、命名实体识别;口语理解:领域分类、槽填充、意图识别。
  • jdk:JDK8原始码,包含个人理解的注释
  • 关于包含块(containing block)的理解

    千次阅读 2015-04-22 15:25:49
    概念:元素的尺寸和位置的计算往往是由该元素...(为便与理解,个人做了简单的描述,不一定是标准解释)。包含块:1、在HTML中,html元素就是一个包含块(即初始包含块)。2、如果元素的定位(position)为:relativ...

    概念:

    元素的尺寸和位置的计算往往是由该元素所在的包含块决定的,包含块就是为它里面包含的元素定位提供一个初始位置,它是一片长方形的区域。一般元素用到position定位时,因需要确定定位的初始位置,就需要清楚什么是包含块。(为便与理解,个人做了简单的描述,不一定是标准解释)。

    包含块:

    1、在HTML中,html元素就是一个包含块(即初始包含块)。

    2、如果元素的定位(position)为:relative或static(默认静态定位)。

    它的包含块就是由它最近的块级(或含块属性)祖先元素创建。

    3、如果元素的定位(position)为:fixed,它的包含块由窗口创建,

    定位起始位置为窗口左上角

    4、如果元素的定位(position)为:absolute,它的包含块由最近的position为:

    relative、absolute、fixed的祖先元素创建。

    其中的祖先元素尽量是块级元素,行内元素会产生一些兼容问题。

    更具体可参考包含块文档:点击打开链接





    展开全文
  • CNN笔记:通俗理解卷积神经网络

    万次阅读 多人点赞 2016-07-02 22:14:50
    通俗理解卷积神经网络(cs231n与5月dl班课程笔记) 1 前言 2012年我在北京组织过8期machine learning读书会,那时“机器学习”非常火,很多人都对其抱有巨大的热情。当我2013年再次来到北京时,有...

                   通俗理解卷积神经网络(cs231n与5月dl班课程笔记)

    1 前言

        2012年我在北京组织过8期machine learning读书会,那时“机器学习”非常火,很多人都对其抱有巨大的热情。当我2013年再次来到北京时,有一个词似乎比“机器学习”更火,那就是“深度学习”。

        本博客内写过一些机器学习相关的文章,但上一篇技术文章“LDA主题模型”还是写于2014年11月份,毕竟自2015年开始创业做在线教育后,太多的杂事、琐碎事,让我一直想再写点技术性文章但每每恨时间抽不开。然由于公司在不断开机器学习、深度学习等相关的在线课程,耳濡目染中,总会顺带着学习学习。

        我虽不参与讲任何课程(我所在公司“七月在线”的所有在线课程都是由目前讲师团队的数百位讲师讲),但依然可以用最最小白的方式 把一些初看复杂的东西抽丝剥茧的通俗写出来。这算重写技术博客的价值所在。

        在dl中,有一个很重要的概念,就是卷积神经网络CNN,基本是入门dl必须搞懂的东西。本文基本根据斯坦福的机器学习公开课、cs231n、与七月在线寒老师讲的5月dl班所写,是一篇课程笔记。

        一开始本文只是想重点讲下CNN中的卷积操作具体是怎么计算怎么操作的,但后面不断补充,包括增加不少自己的理解,故写成了关于卷积神经网络的通俗导论性的文章。有何问题,欢迎不吝指正。

    2 人工神经网络

    2.1 神经元

        神经网络由大量的神经元相互连接而成。每个神经元接受线性组合的输入后,最开始只是简单的线性加权,后来给每个神经元加上了非线性的激活函数,从而进行非线性变换后输出。每两个神经元之间的连接代表加权值,称之为权重(weight)。不同的权重和激活函数,则会导致神经网络不同的输出。

        举个手写识别的例子,给定一个未知数字,让神经网络识别是什么数字。此时的神经网络的输入由一组被输入图像的像素所激活的输入神经元所定义。在通过非线性激活函数进行非线性变换后,神经元被激活然后被传递到其他神经元。重复这一过程,直到最后一个输出神经元被激活。从而识别当前数字是什么字。

        神经网络的每个神经元如下

        基本wx + b的形式,其中

    • 表示输入向量
    • 为权重,几个输入则意味着有几个权重,即每个输入都被赋予一个权重
    • b为偏置bias
    • g(z) 为激活函数
    • a 为输出

        如果只是上面这样一说,估计以前没接触过的十有八九又必定迷糊了。事实上,上述简单模型可以追溯到20世纪50/60年代的感知器,可以把感知器理解为一个根据不同因素、以及各个因素的重要性程度而做决策的模型。

        举个例子,这周末北京有一草莓音乐节,那去不去呢?决定你是否去有二个因素,这二个因素可以对应二个输入,分别用x1、x2表示。此外,这二个因素对做决策的影响程度不一样,各自的影响程度用权重w1、w2表示。一般来说,音乐节的演唱嘉宾会非常影响你去不去,唱得好的前提下 即便没人陪同都可忍受,但如果唱得不好还不如你上台唱呢。所以,我们可以如下表示:

    • :是否有喜欢的演唱嘉宾。 = 1 你喜欢这些嘉宾, = 0 你不喜欢这些嘉宾。嘉宾因素的权重 = 7
    • :是否有人陪你同去。 = 1 有人陪你同去, = 0 没人陪你同去。是否有人陪同的权重 = 3。

        这样,咱们的决策模型便建立起来了:g(z) = g( * + * + b ),g表示激活函数,这里的b可以理解成 为更好达到目标而做调整的偏置项。

        一开始为了简单,人们把激活函数定义成一个线性函数,即对于结果做一个线性变化,比如一个简单的线性激活函数是g(z) = z,输出都是输入的线性变换。后来实际应用中发现,线性激活函数太过局限,于是人们引入了非线性激活函数。

    2.2 激活函数

        常用的非线性激活函数有sigmoid、tanhrelu等等,前两者sigmoid/tanh比较常见于全连接层,后者relu常见于卷积层。这里先简要介绍下最基础的sigmoid函数(btw,在本博客中SVM那篇文章开头有提过)。

        sigmoid的函数表达式如下

        其中z是一个线性组合,比如z可以等于:b + * + *通过代入很大的正数或很小的负数到g(z)函数中可知,其结果趋近于0或1

        因此,sigmoid函数g(z)的图形表示如下( 横轴表示定义域z,纵轴表示值域g(z) ):

        也就是说,sigmoid函数的功能是相当于把一个实数压缩至0到1之间。当z是非常大的正数时,g(z)会趋近于1,而z是非常小的负数时,则g(z)会趋近于0

        压缩至0到1有何用处呢?用处是这样一来便可以把激活函数看作一种“分类的概率”,比如激活函数的输出为0.9的话便可以解释为90%的概率为正样本。

        举个例子,如下图(图引自Stanford机器学习公开课

        z = b + * + *,其中b为偏置项 假定取-30,都取为20

    • 如果 = 0  = 0,则z = -30,g(z) = 1/( 1 + e^-z )趋近于0。此外,从上图sigmoid函数的图形上也可以看出,当z=-30的时候,g(z)的值趋近于0
    • 如果 = 0 = 1,或 =1 = 0,则z = b + * + * = -30 + 20 = -10,同样,g(z)的值趋近于0
    • 如果 = 1 = 1,则z = b + * + * = -30 + 20*1 + 20*1 = 10,此时,g(z)趋近于1。

        换言之,只有都取1的时候,g(z)→1,判定为正样本;取0的时候,g(z)→0,判定为负样本如此达到分类的目的。

    2.3 神经网络

        将下图的这种单个神经元

        组织在一起,便形成了神经网络。下图便是一个三层神经网络结构

        上图中最左边的原始输入信息称之为输入层,最右边的神经元称之为输出层(上图中输出层只有一个神经元),中间的叫隐藏层。

        啥叫输入层、输出层、隐藏层呢?

    • 输入层(Input layer),众多神经元(Neuron)接受大量非线形输入讯息。输入的讯息称为输入向量。
    • 输出层(Output layer),讯息在神经元链接中传输、分析、权衡,形成输出结果。输出的讯息称为输出向量。
    • 隐藏层(Hidden layer),简称“隐层”,是输入层和输出层之间众多神经元和链接组成的各个层面。如果有多个隐藏层,则意味着多个激活函数。

        同时,每一层都可能由单个或多个神经元组成,每一层的输出将会作为下一层的输入数据。比如下图中间隐藏层来说,隐藏层的3个神经元a1、a2、a3皆各自接受来自多个不同权重的输入(因为有x1、x2、x3这三个输入,所以a1 a2 a3都会接受x1 x2 x3各自分别赋予的权重,即几个输入则几个权重),接着,a1、a2、a3又在自身各自不同权重的影响下 成为的输出层的输入,最终由输出层输出最终结果。

        上图(图引自Stanford机器学习公开课)中

    • 表示第j层第i个单元的激活函数/神经元
    • 表示从第j层映射到第j+1层的控制函数的权重矩阵 

        此外,输入层和隐藏层都存在一个偏置(bias unit),所以上图中也增加了偏置项:x0、a0。针对上图,有如下公式

        此外,上文中讲的都是一层隐藏层,但实际中也有多层隐藏层的,即输入层和输出层中间夹着数层隐藏层,层和层之间是全连接的结构,同一层的神经元之间没有连接。

    3 卷积神经网络之层级结构

       cs231n课程里给出了卷积神经网络各个层级结构,如下图

        上图中CNN要做的事情是:给定一张图片,是车还是马未知,是什么车也未知,现在需要模型判断这张图片里具体是一个什么东西,总之输出一个结果:如果是车 那是什么车

        所以

    • 最左边是数据输入层,对数据做一些处理,比如去均值(把输入数据各个维度都中心化为0,避免数据过多偏差,影响训练效果)、归一化(把所有的数据都归一到同样的范围)、PCA/白化等等。CNN只对训练集做“去均值”这一步。

        中间是

    • CONV:卷积计算层,线性乘积 求和。
    • RELU:激励层,上文2.2节中有提到:ReLU是激活函数的一种。
    • POOL:池化层,简言之,即取区域平均或最大。

        最右边是

    • FC:全连接层

        这几个部分中,卷积计算层是CNN的核心,下文将重点阐述。


    4 CNN之卷积计算层

    4.1 CNN怎么进行识别
       简言之,当我们给定一个"X"的图案,计算机怎么识别这个图案就是“X”呢?一个可能的办法就是计算机存储一张标准的“X”图案,然后把需要识别的未知图案跟标准"X"图案进行比对,如果二者一致,则判定未知图案即是一个"X"图案。

       而且即便未知图案可能有一些平移或稍稍变形,依然能辨别出它是一个X图案。如此,CNN是把未知图案和标准X图案一个局部一个局部的对比,如下图所示 [图来自参考文案25]

    而未知图案的局部和标准X图案的局部一个一个比对时的计算过程,便是卷积操作。卷积计算结果为1表示匹配,否则不匹配。

    具体而言,为了确定一幅图像是包含有"X"还是"O",相当于我们需要判断它是否含有"X"或者"O",并且假设必须两者选其一,不是"X"就是"O"。

     理想的情况就像下面这个样子:

    标准的"X"和"O",字母位于图像的正中央,并且比例合适,无变形

    对于计算机来说,只要图像稍稍有一点变化,不是标准的,那么要解决这个问题还是不是那么容易的:

    计算机要解决上面这个问题,一个比较天真的做法就是先保存一张"X"和"O"的标准图像(就像前面给出的例子),然后将其他的新给出的图像来和这两张标准图像进行对比,看看到底和哪一张图更匹配,就判断为哪个字母。

    但是这么做的话,其实是非常不可靠的,因为计算机还是比较死板的。在计算机的“视觉”中,一幅图看起来就像是一个二维的像素数组(可以想象成一个棋盘),每一个位置对应一个数字。在我们这个例子当中,像素值"1"代表白色,像素值"-1"代表黑色。

    当比较两幅图的时候,如果有任何一个像素值不匹配,那么这两幅图就不匹配,至少对于计算机来说是这样的。

    对于这个例子,计算机认为上述两幅图中的白色像素除了中间的3*3的小方格里面是相同的,其他四个角上都不同:

    因此,从表面上看,计算机判别右边那幅图不是"X",两幅图不同,得出结论:

    但是这么做,显得太不合理了。理想的情况下,我们希望,对于那些仅仅只是做了一些像平移,缩放,旋转,微变形等简单变换的图像,计算机仍然能够识别出图中的"X"和"O"。就像下面这些情况,我们希望计算机依然能够很快并且很准的识别出来:

    这也就是CNN出现所要解决的问题。

    Features

    对于CNN来说,它是一块一块地来进行比对。它拿来比对的这个“小块”我们称之为Features(特征)。在两幅图中大致相同的位置找到一些粗糙的特征进行匹配,CNN能够更好的看到两幅图的相似性,相比起传统的整幅图逐一比对的方法。

    每一个feature就像是一个小图(就是一个比较小的有值的二维数组)。不同的Feature匹配图像中不同的特征。在字母"X"的例子中,那些由对角线和交叉线组成的features基本上能够识别出大多数"X"所具有的重要特征。

    这些features很有可能就是匹配任何含有字母"X"的图中字母X的四个角和它的中心。那么具体到底是怎么匹配的呢?如下:

    看到这里是不是有了一点头目呢。但其实这只是第一步,你知道了这些Features是怎么在原图上面进行匹配的。但是你还不知道在这里面究竟进行的是怎样的数学计算,比如这个下面3*3的小块到底干了什么?

    这里面的数学操作,就是我们常说的“卷积”操作。接下来,我们来了解下什么是卷积操作。

    4.2 什么是卷积

        对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是所谓的『卷积』操作,也是卷积神经网络的名字来源。

        非严格意义上来讲,下图中红框框起来的部分便可以理解为一个滤波器,即带着一组固定权重的神经元。多个滤波器叠加便成了卷积层。

        OK,举个具体的例子。比如下图中,图中左边部分是原始输入数据,图中中间部分是滤波器filter,图中右边是输出的新的二维数据。

        分解下上图

    对应位置上是数字先相乘后相加 =

        中间滤波器filter与数据窗口做内积,其具体计算过程则是:4*0 + 0*0 + 0*0 + 0*0 + 0*1 + 0*1 + 0*0 + 0*1 + -4*2 = -8

    4.3 图像上的卷积

        在下图对应的计算过程中,输入是一定区域大小(width*height)的数据,和滤波器filter(带着一组固定权重的神经元)做内积后等到新的二维数据。

        具体来说,左边是图像输入,中间部分就是滤波器filter(带着一组固定权重的神经元),不同的滤波器filter会得到不同的输出数据,比如颜色深浅、轮廓。相当于如果想提取图像的不同特征,则用不同的滤波器filter,提取想要的关于图像的特定信息:颜色深浅或轮廓。

        如下图所示

      

    4.4 GIF动态卷积图

        在CNN中,滤波器filter(带着一组固定权重的神经元)对局部输入数据进行卷积计算。每计算完一个数据窗口内的局部数据后,数据窗口不断平移滑动,直到计算完所有数据。这个过程中,有这么几个参数: 
      a. 深度depth:神经元个数,决定输出的depth厚度。同时代表滤波器个数。
      b. 步长stride:决定滑动多少步可以到边缘。

      c. 填充值zero-padding:在外围边缘补充若干圈0,方便从初始位置以步长为单位可以刚好滑倒末尾位置,通俗地讲就是为了总长能被步长整除。 

      这里写图片描述 

        cs231n课程中有一张卷积动图,貌似是用d3js 和一个util 画的,我根据cs231n的卷积动图依次截取了18张图,然后用一gif 制图工具制作了一gif 动态卷积图。如下gif 图所示

        可以看到:

    • 两个神经元,即depth=2,意味着有两个滤波器。
    • 数据窗口每次移动两个步长取3*3的局部数据,即stride=2。
    • zero-padding=1。

        然后分别以两个滤波器filter为轴滑动数组进行卷积计算,得到两组不同的结果。

        如果初看上图,可能不一定能立马理解啥意思,但结合上文的内容后,理解这个动图已经不是很困难的事情:

    • 左边是输入(7*7*3中,7*7代表图像的像素/长宽,3代表R、G、B 三个颜色通道)
    • 中间部分是两个不同的滤波器Filter w0、Filter w1
    • 最右边则是两个不同的输出

        随着左边数据窗口的平移滑动,滤波器Filter w0 / Filter w1对不同的局部数据进行卷积计算。

        值得一提的是:左边数据在变化,每次滤波器都是针对某一局部的数据窗口进行卷积,这就是所谓的CNN中的局部感知机制。

    • 打个比方,滤波器就像一双眼睛,人类视角有限,一眼望去,只能看到这世界的局部。如果一眼就看到全世界,你会累死,而且一下子接受全世界所有信息,你大脑接收不过来。当然,即便是看局部,针对局部里的信息人类双眼也是有偏重、偏好的。比如看美女,对脸、胸、腿是重点关注,所以这3个输入的权重相对较大。

    与此同时,数据窗口滑动,导致输入在变化,但中间滤波器Filter w0的权重(即每个神经元连接数据窗口的权重)是固定不变的,这个权重不变即所谓的CNN中的参数(权重)共享机制。

    • 再打个比方,某人环游全世界,所看到的信息在变,但采集信息的双眼不变。btw,不同人的双眼 看同一个局部信息 所感受到的不同,即一千个读者有一千个哈姆雷特,所以不同的滤波器 就像不同的双眼,不同的人有着不同的反馈结果。

        我第一次看到上面这个动态图的时候,只觉得很炫,另外就是据说计算过程是“相乘后相加”,但到底具体是个怎么相乘后相加的计算过程 则无法一眼看出,网上也没有一目了然的计算过程。本文来细究下。

        首先,我们来分解下上述动图,如下图

        接着,我们细究下上图的具体计算过程。即上图中的输出结果1具体是怎么计算得到的呢?其实,类似wx + b,w对应滤波器Filter w0,x对应不同的数据窗口,b对应Bias b0,相当于滤波器Filter w0与一个个数据窗口相乘再求和后,最后加上Bias b0得到输出结果1,如下过程所示:

    1* 0 + 1*0 + -1*

    +

    -1*0 + 0*0 + 1*1

    +

    -1*0 + -1*0 + 0*1

    +

    -1*0 + 0*0 + -1*0

    +

    0*0 + 0*1 + -1*1

    +

    1*0 + -1*0 + 0*2

    +

    0*0 + 1*0 + 0*0

    +

    1*0 + 0*2 + 1*0

    +

    0*0 + -1*0 + 1*0

    +

    1

    =

    1

        然后滤波器Filter w0固定不变,数据窗口向右移动2步,继续做内积计算,得到0的输出结果

        最后,换做另外一个不同的滤波器Filter w1、不同的偏置Bias b1,再跟图中最左边的数据窗口做卷积,可得到另外一个不同的输出。

    5 CNN之激励层与池化层

    5.1 ReLU激励层

        2.2节介绍了激活函数sigmoid,但实际梯度下降中,sigmoid容易饱和、造成终止梯度传递,且没有0中心化。咋办呢,可以尝试另外一个激活函数:ReLU,其图形表示如下

        ReLU的优点是收敛快,求梯度简单。

    5.2 池化pool层

        前头说了,池化,简言之,即取区域平均或最大,如下图所示(图引自cs231n)

        上图所展示的是取区域最大,即上图左边部分中 左上角2x2的矩阵中6最大,右上角2x2的矩阵中8最大,左下角2x2的矩阵中3最大,右下角2x2的矩阵中4最大,所以得到上图右边部分的结果:6 8 3 4。很简单不是?


    6 参考文献及推荐阅读

    1. 人工神经网络wikipedia
    2. 斯坦福机器学习公开课
    3. Neural networks and deep learning
    4. 雨石 卷积神经网络:卷积神经网络_雨石-CSDN博客_卷积神经网络
    5. cs231n 神经网络结构与神经元激励函数:CS231n Convolutional Neural Networks for Visual Recognition中译版
    6. cs231n 卷积神经网络:CS231n Convolutional Neural Networks for Visual Recognition
    7. 七月在线寒老师讲的5月dl班第4次课CNN与常用框架视频,已经剪切部分放在七月在线官网:julyedu.com
    8. 七月在线5月深度学习班第5课CNN训练注意事项部分视频:视频播放
    9. 七月在线5月深度学习班:5 月深度学习班 [国内第1个DL商业课程] - 七月在线
    10. 七月在线5月深度学习班课程笔记——No.4《CNN与常用框架》:CNN与常用框架_会思考的蜗牛-CSDN博客_cnn框架
    11. 七月在线6月数据数据挖掘班第7课视频:数据分类与排序
    12. 手把手入门神经网络系列(1)_从初等数学的角度初探神经网络:手把手入门神经网络系列(1)_从初等数学的角度初探神经网络
    13. 深度学习与计算机视觉系列(6)_神经网络结构与神经元激励函数:深度学习与计算机视觉系列(6)_神经网络结构与神经元激励函数
    14. 深度学习与计算机视觉系列(10)_细说卷积神经网络:深度学习与计算机视觉系列(10)_细说卷积神经网络
    15. zxy 图像卷积与滤波的一些知识点:图像卷积与滤波的一些知识点_zouxy09的专栏-CSDN博客_图像卷积
    16. zxy 深度学习CNN笔记:Deep Learning(深度学习)学习笔记整理系列之(七)_zouxy09的专栏-CSDN博客_深度学习 笔记
    17. Understanding Convolutional Neural Networks for NLP – WildML中译版
    18. 《神经网络与深度学习》中文讲义:Sina Visitor System
    19. ReLU与sigmoid/tanh的区别:请问人工神经网络中的activation function的作用具体是什么?为什么ReLu要好过于tanh和sigmoid function? - 知乎
    20. CNN、RNN、DNN内部网络结构区别:CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)的内部网络结构有什么区别? - 知乎
    21. 理解卷积:如何通俗易懂地解释卷积? - 知乎
    22. 神经网络与深度学习简史:1 感知机和BP算法4 深度学习的伟大复兴
    23. 在线制作gif 动图:在线Photoshop 在线ps
    24. 支持向量机通俗导论(理解SVM的三层境界)
    25. CNN究竟是怎样一步一步工作的? 本博客把卷积操作具体怎么个计算过程写清楚了,但这篇把为何要卷积操作也写清楚了,而且配偶图非常形象,甚赞。

    7 后记

        本文基本上边看5月dl班寒讲的CNN视频边做笔记,之前断断续续看过不少CNN相关的资料(包括cs231n),但看过视频之后,才系统了解CNN到底是个什么东西,作为听众 寒讲的真心赞、清晰。然后在写CNN相关的东西时,发现一些前置知识(比如神经元、多层神经网络等也需要介绍下),包括CNN的其它层次机构(比如激励层),所以本文本只想简要介绍下卷积操作的,但考虑到知识之间的前后关联,所以越写越长,便成本文了。

        此外,在写作本文的过程中,请教了我们讲师团队里的寒、冯两位,感谢他两。同时,感谢爱可可老师的微博转发,感谢七月在线所有同事。

    以下是修改日志:

    • 2016年7月5日,修正了一些笔误、错误,以让全文更通俗、更精准。有任何问题或槽点,欢迎随时指出。
    • 2016年7月7日,第二轮修改完毕。且根据cs231n的卷积动图依次截取了18张图,然后用制图工具制作了一gif 动态卷积图,放在文中4.3节。
    • 2016年7月16日,完成第三轮修改。本轮修改主要体现在sigmoid函数的说明上,通过举例和统一相关符号让其含义更一目了然、更清晰。
    • 2016年8月15日,完成第四轮修改,增补相关细节。比如补充4.3节GIF动态卷积图中输入部分的解释,即7*7*3的含义(其中7*7代表图像的像素/长宽,3代表R、G、B 三个颜色通道)。不断更易懂。
    • 2016年8月22日,完成第五轮修改。本轮修改主要加强滤波器的解释,及引入CNN中滤波器的通俗比喻。

        July、最后修改于二零一六年八月二十二日中午于七月在线办公室。

    展开全文
  • node_beginner Node入门书原始码,包含一些个人理解和笔记 没有完全复制书中原始代码,可选择领会精神。 以下个人理解的流程图表示,欢迎拍砖!
  • 作者:朱金灿http://blog.csdn.net/clever101 类的前置声明(forward declaration)和包含头文件(#... 首先我们需要问一个问题是:为什么两个类不能互相包含头文件?所谓互相包含头文件,我举一个例子:我实现了

     

    作者:朱金灿

    http://blog.csdn.net/clever101

     

        类的前置声明(forward declaration)和包含头文件(#include)的区别常常会迷惑我们,特别是涉及两个类相互包含的时候。因此我们有必要搞清楚二者的区别以及二者的适用场合。

     

    首先我们需要问一个问题是:为什么两个类不能互相包含头文件?所谓互相包含头文件,我举一个例子:我实现了两个类:图层类CLayer和符号类CSymbol,它们的大致关系是图层里包含有符号,符号里定义一个相关图层指针,具体请参考如下代码(注:以下代码仅供说明问题,不作为类设计参考,所以不适宜以此讨论类的设计,编译环境为Microsoft Visual C++ 2005,Windows XP + sp2,以下同):

     

          

     

         

       

    现在开始编译,编译出错,出错信息如下:

    1>正在编译...

    1>TestUnix.cpp

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C2143: 语法错误: 缺少“;(在“*”的前面)

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

    1>Layer.cpp

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C2143: 语法错误: 缺少“;(在“*”的前面)

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

    1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

    1>Symbol.cpp

    1>f:/mytest/mytest/src/testunix/layer.h(18) : error C2143: 语法错误: 缺少“;(在“*”的前面)

    1>f:/mytest/mytest/src/testunix/layer.h(18) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

    1>f:/mytest/mytest/src/testunix/layer.h(18) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

     

        现在让我们分析一下编译出错信息(我发现分析编译信息对加深程序的编译过程的理解非常有好处)。首先我们明确:编译器在编译文件时,遇到#include   "x.h"时,就打开x.h文件进行编译,这相当于把x.h文件的内容放在#include   "x.h"处。编译信息告诉我们:它是先编译TestUnix.cpp文件的,那么接着它应该编译stdafx.h接着是Layer.h如果编译Layer.h那么会编译Symbol.h但是编译Symbol.h又应该编译Layer.h啊,这岂不是陷入一个死循环? 呵呵,如果没有预编译指令,是会这样的,实际上在编译Symbol.h再去编译Layer.hLayer.h头上的那个#pragma once就会告诉编译器:老兄,这个你已经编译过了,就不要再浪费力气编译了!那么编译器得到这个信息就会不再编译Layer.h而转回到编译Symbol.h的余下内容。当编译到CLayer *m_pRelLayer;这一行编译器就会迷惑了:CLayer是什么东西呢?我怎么没见过呢?那么它就得给出一条出错信息,告诉你CLayer没经定义就用了呢?TestUnix.cpp#include "Layer.h"这句算是宣告编译结束(呵呵,简单一句弯弯绕绕不断),下面轮到#include "Symbol.h",由于预编译指令的阻挡,Symbol.h实际上没有得到编译,接着再去编译TestUnix.cpp的余下内容。

     

         当然上面仅仅是我的一些推论,还没得到完全证实,不过我们可以稍微测试一下,假如在TestUnix.cpp#include "Layer.h"#include "Symbol.h"互换一下位置,那么会不会先提示CSymbol类没有定义呢?实际上是这样的。当然这个也不能完全证实我的推论。

     

        照这样看,两个类的互相包含头文件肯定出错,那么如何解决这种情况呢?一种办法是在A类中包含B类的头文件,在B类中前置盛明A类,不过注意的是B类使用A类变量必须通过指针来进行,具体见拙文:类互相包含的办法。为何不能前置声明只能通过指针来使用?通过分析这个实际上我们可以得出前置声明和包含头文件的区别。我们把CLayer类的代码改动一下,再看下面的代码:

        

     

       

    然后编译,出现一个编译警告:>f:/mytest/mytest/src/testunix/layer.cpp(16) : warning C4150: 删除指向不完整“CSymbol”类型的指针;没有调用析构函数

    1>                            f:/mytest/mytest/src/testunix/layer.h(9) : 参见“CSymbol”的声明

     

           看到这个警告,我想你一定悟到了什么。下面我说说我的结论:类的前置声明和包含头文件的区别在于类的前置声明是告诉编译器有这种类型,但是它没有告诉编译器这种类型的大小、成员函数和数据成员,而包含头文件则是完全告诉了编译器这种类型到底是怎样的(包括大小和成员)。这下我们也明白了为何前置声明只能使用指针来进行,因为指针大小在编译器是确定的。上面正因为前置声明不能提供析构函数信息,所以编译器提醒我们:CSymbol”类型的指针没有调用析构函数。如何解决这个问题呢?在Layer.cpp加上#include "Symbol.h"就可以消除这个警告。

     

     

     

    展开全文
  • Mysql_Excersises 该存储库将包含mysql项目,以更好地理解语言
  • 关于scene understanding场景理解概念的理解

    千次阅读 热门讨论 2018-02-01 13:23:21
    Scene understanding 场景理解感觉定义并不是十分明确,找了几个供参考。 LSUN Challenge 大规模场景理解比赛 INTRODUCTION The PASCAL VOC and ImageNet ILSVRC challenges have enabled significant progress ...
  • 今天看WPF高级编程,在里面看到这样一句话"WPF体系结构包括非托管的服务,托管的子系统,以及一套WPF应用程序所需要的托管API,称为呈现架构(presentation framework)",想请教一下怎么理解![图片]...
  • 大家好,我是 Rocky0429,一个连数据结构和算法都不会的蒟蒻… 学过数据结构和算法的都知道这玩意儿不好学,没学过的经常听到...在简单的链表、栈和队列这些我还能靠着在草稿上写写画画理解过程,但是到了数论、图...
  • Windows程序设计示例代码,包含多个示例,可以更好的理解Windows应用程序。主要是给初学者使用。代码简单,容易理解
  • 深入理解BodyTagSupport,包括SKIP_PAGE, EVAL_PAGE等 2009年06月29日 星期一 下午 05:52 BodyTagSupport类的方法: 编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartT
  • 数学爱好 此回购包括我为理解数学所做的工作,以发展我的逻辑和解决问题的能力。
  • 自然语言理解

    千次阅读 2018-08-14 00:44:20
    人类对机器理解语言的认识走了一条大...包括,目前语音理解的输出输入的打通都需要自然语言理解的基础支撑,目前,自然语言理解使用了万金油技术--神经网络,如虎添翼,一路攻城拔寨,效能飞速上升。学习掌握 NLP...
  • 在用例关系中有有三种关系,一是包括,"include" 一是扩展"extend"一是泛化,当然还有最基本的关系,“关联”. 其中,包含关系: 包含关系用于将部分工作流程分离出去,对这部分工作流程来说,基本用例只取决于结果...
  • KMP算法最浅显理解——一看就明白

    万次阅读 多人点赞 2017-02-07 17:41:08
    说明 KMP算法看懂了觉得特别简单,思路很简单,看不懂之前,查各种资料,看的稀里糊涂,...给你两个字符串,寻找其中一个字符串是否包含另一个字符串,如果包含,返回包含的起始位置。 如下面两个字符串: c...
  • SpringBoot理解

    千次阅读 2018-09-15 00:41:20
    SpringBoot框架包含内容: 关于Springboot的微服务?网上大家都说的的很多,说Springboot是一个微服务架构?关于什么是微服务这个我目前还没有很好的理解,这个貌似Springboot和微服务没有多大关系,...
  • elasticsearch写入数据时涉及到的核心概念讲解: segment file: 存储逆向索引的文件,每个segment本质上就是一个逆向索引,每秒都会生成...commit point(重点理解): 记录当前所有可用的segment,每个commit poin...
  • Geo_Question_Analysis GeoST:中文分词与词性标注工具 AtrributeExtraction:实体与属性识别工程 KBBuild:知识图谱构建工程,其中包含一个python项目Crawler,用于爬取数据以及RDF数据操作 QASystem:问题理解系统
  • having理解概念

    2020-12-02 17:48:10
    1、having子句即可包含聚合函数作用的字段也可以包括普通的标量字段 2、使用having的同时可以使用where子句 3、having子句可以脱离于group by子句使用,效果与where一样,但不推荐没有group by时使用having 4、...
  • 自然语言处理(NLP) vs 自然语言理解(NLU)

    万次阅读 多人点赞 2018-01-08 10:27:03
    自然语言处理,是Natural ...1、概括来说,NLP,除了NLU(图中红框部分),还包含理解之前的处理阶段、和理解之后的应用阶段。也就是说,NLU是NLP的子集——他们不是并集、更不是等价的概念。这里,是很多AI从业人员都
  • result_ks = ks(df, 'label', 'score') ks_curve(result_ks)
  • 理解F1值

    万次阅读 2018-07-23 20:06:30
    正确率应用范围很广,理解起来比较容易, 计算起来也方便。但是,造假很容易。换句话说,你很容易就能实现一个正确率很高,但实际用处不大的算法。 例如,对于垃圾邮件过滤器而言,其所处理的邮件很可能80%以上都...
  • 谈到系统,它包含所有必需的功能,包括添加,查看,删除和更新联系人列表。 在添加一个人的联系人时,他/她必须提供名字,姓氏,性别,地址和联系方式。 用户还可以根据需要更新联系人列表。 为此,用户必须双击他/...
  • Hold time 个人理解

    千次阅读 2019-09-05 14:38:39
    下面图中包括两个DFF,一个launch flip-flop(launch the data,UFF0),一个capture flip-flop(capture the data,UFF1),图中两个flip-flop的clock一致,当然,相对于CLKM(source clk)包含一定的d...
  • 阅读理解大致可以分为四个任务,即填空型阅读理解任务、选择型阅读理解任务、片段抽取型阅读理解任务以及自由格式阅读理解任务。随着以BERT为代表的预训练模型的发展,四种阅读理解任务都有着飞速的发展,主要体现为...
  • Java变量的理解

    千次阅读 2018-12-17 10:14:02
    Java中的变量理解: 基本数据类型: 基本类型包括四类八种: 整数类型:byte,short,int,long 浮点数类型:float,double 字符类型:char 布尔类型:boolean 注:bit:比特,指的是二进制的位数 引用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,399,505
精华内容 959,802
关键字:

包含怎么理解