DESIGNATION :KE0E -40是什么意思思

&p&HashMap的工作原理是近年来常见的Java面试题。几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此特殊呢?是因为这道题考察的深度很深。这题经常出现在高级或中高级面试中。投资银行更喜欢问这个问题,甚至会要求你实现HashMap来考察你的编程能力。ConcurrentHashMap和其它同步集合的引入让这道题变得更加复杂。让我们开始探索的旅程吧!&/p&&h2&先来些简单的问题&/h2&&p&&b&“你用过HashMap吗?” “什么是HashMap?你为什么用到它?”&/b&&/p&&p&几乎每个人都会回答“是的”,然后回答HashMap的一些特性,譬如HashMap可以接受null键值和值,而Hashtable则不能;HashMap是非HashMap很快;以及HashMap储存的是键值对等等。这显示出你已经用过HashMap,而且对它相当的熟悉。但是面试官来个急转直下,从此刻开始问出一些刁钻的问题,关于HashMap的更多基础的细节。面试官可能会问出下面的问题:&/p&&p&&b&“你知道HashMap的工作原理吗?” “你知道HashMap的get()方法的工作原理吗?”&/b&&/p&&p&你也许会回答“我没有详查标准的Java API,你可以看看Java源代码或者Open JDK。”“我可以用Google找到答案。”&/p&&p&但一些面试者可能可以给出答案,“HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,作为Map.Entry。这一点有助于理解获取对象的逻辑。如果你没有意识到这一点,或者错误的认为仅仅只在bucket中存储值的话,你将不会回答如何从HashMap中获取对象的逻辑。这个答案相当的正确,也显示出面试者确实知道hashing以及HashMap的工作原理。但是这仅仅是故事的开始,当面试官加入一些Java程序员每天要碰到的实际场景的时候,错误的答案频现。下个问题可能是关于HashMap中的碰撞探测(collision detection)以及碰撞的解决方法:&/p&&p&&b&“当两个对象的hashcode相同会发生什么?”&/b& 从这里开始,真正的困惑开始了,一些面试者会回答因为hashcode相同,所以两个对象是相等的,HashMap将会抛出异常,或者不会存储它们。然后面试官可能会提醒他们有equals()和hashCode()两个方法,并告诉他们两个对象就算hashcode相同,但是它们可能并不相等。一些面试者可能就此放弃,而另外一些还能继续挺进,他们回答“因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。”这个答案非常的合理,虽然有很多种处理碰撞的方法,这种方法是最简单的,也正是HashMap的处理方法。但故事还没有完结,面试官会继续问:&/p&&p&&b&“如果两个键的hashcode相同,你如何获取值对象?”&/b& 面试者会回答:当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后获取值对象。面试官提醒他如果有两个值对象储存在同一个bucket,他给出答案:将会遍历链表直到找到值对象。面试官会问因为你并没有值对象去比较,你是如何确定确定找到值对象的?除非面试者直到HashMap在链表中存储的是键值对,否则他们不可能回答出这一题。&/p&&p&其中一些记得这个重要知识点的面试者会说,找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。完美的答案!&/p&&p&许多情况下,面试者会在这个环节中出错,因为他们混淆了hashCode()和equals()方法。因为在此之前hashCode()屡屡出现,而equals()方法仅仅在获取值对象的时候才出现。一些优秀的开发者会指出使用不可变的、声明作final的对象,并且采用合适的equals()和hashCode()方法的话,将会减少碰撞的发生,提高效率。不可变性使得能够缓存不同键的hashcode,这将提高整个获取对象的速度,使用String,Interger这样的wrapper类作为键是非常好的选择。&/p&&p&如果你认为到这里已经完结了,那么听到下面这个问题的时候,你会大吃一惊。&b&“如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?”&/b&除非你真正知道HashMap的工作原理,否则你将回答不出这道题。默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。&/p&&p&如果你能够回答这道问题,下面的问题来了:&b&“你了解重新调整HashMap大小存在什么问题吗?”&/b&你可能回答不上来,这时面试官会提醒你当多线程的情况下,可能产生条件竞争(race condition)。&/p&&p&当重新调整HashMap大小的时候,确实存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。这个时候,你可以质问面试官,为什么这么奇怪,要在多线程的环境下使用HashMap呢?:)&/p&&p&热心的读者贡献了更多的关于HashMap的问题:&/p&&ol&&li&&b&为什么String, Interger这样的wrapper类适合作为键?&/b& String, Interger这样的wrapper类作为HashMap的键是再适合不过了,而且String最为常用。因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。&/li&&li&&b&我们可以使用自定义的对象作为键吗?&/b& 这是前一个问题的延伸。当然你可能使用任何对象作为键,只要它遵守了equals()和hashCode()方法的定义规则,并且当对象插入到Map中之后将不会再改变了。如果这个自定义对象时不可变的,那么它已经满足了作为键的条件,因为当它创建之后就已经不能改变了。&/li&&li&&b&我们可以使用CocurrentHashMap来代替Hashtable吗?&/b&这是另外一个很热门的面试题,因为ConcurrentHashMap越来越多人用了。我们知道Hashtable是synchronized的,但是ConcurrentHashMap同步性能更好,因为它仅仅根据同步级别对map的一部分进行上锁。ConcurrentHashMap当然可以代替HashTable,但是HashTable提供更强的线程安全性。看看这篇博客查看Hashtable和ConcurrentHashMap的区别。&/li&&/ol&&p&我个人很喜欢这个问题,因为这个问题的深度和广度,也不直接的涉及到不同的概念。让我们再来看看这些问题设计哪些知识点:&/p&&ul&&li&hashing的概念&/li&&li&HashMap中解决碰撞的方法&/li&&li&equals()和hashCode()的应用,以及它们在HashMap中的重要性&/li&&li&不可变对象的好处&/li&&li&HashMap多线程的条件竞争&/li&&li&重新调整HashMap的大小&/li&&/ul&&h2&总结&/h2&&h2&HashMap的工作原理&/h2&&p&HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。&/p&&p&当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。&/p&&p&因为HashMap的好处非常多,我曾经在电子商务的应用中使用HashMap作为缓存。因为金融领域非常多的运用Java,也出于性能的考虑,我们会经常用到HashMap和ConcurrentHashMap。&/p&
HashMap的工作原理是近年来常见的Java面试题。几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此特殊呢?是因为这道题考察的深度很深。这题经常出现在高级或中高级面试中。投资银行更喜…
&p&据我所知有一些技术可以用来测量time series数据的predictability:&/p&&p&Forecastable Component Analysis:&/p&&b&&a href=&//link.zhihu.com/?target=https%3A//arxiv.org/abs/& data-draft-node=&block& data-draft-type=&link-card& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&[] Forecastable Component Analysis (ForeCA)&/a&&/b&&b&&a href=&//link.zhihu.com/?target=https%3A//cran.r-project.org/web/packages/ForeCA/index.html& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&cran.r-project.org/web/&/span&&span class=&invisible&&packages/ForeCA/index.html&/span&&span class=&ellipsis&&&/span&&/a&&/b&&b&&a href=&//link.zhihu.com/?target=http%3A//proceedings.mlr.press/v28/goerg13.pdf& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&proceedings.mlr.press/v&/span&&span class=&invisible&&28/goerg13.pdf&/span&&span class=&ellipsis&&&/span&&/a&&/b&&p&Hurst Exponent:&/p&&a href=&//link.zhihu.com/?target=http%3A//analytics-magazine.org/the-hurst-exponent-predictability-of-time-series/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-696eff719ca916e539cbaff_ipico.jpg& data-image-width=&400& data-image-height=&400& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The Hurst Exponent: Predictability of Time Series - Analytics Magazine&/a&&p&Entropy:&/p&&a href=&//link.zhihu.com/?target=https%3A//www.ncbi.nlm.nih.gov/pmc/articles/PMC5422060/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-2bf254b4d032a6dd24d51_180x120.jpg& data-image-width=&1200& data-image-height=&630& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Measuring Complexity and Predictability of Time Series with Flexible Multiscale Entropy for Sensor Networks&/a&&p&还有一些其它的方法,例如:&/p&&a href=&//link.zhihu.com/?target=https%3A//www.sas.upenn.edu/%7Efdiebold/papers/paper36/dk.pdf& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&sas.upenn.edu/~fdiebold&/span&&span class=&invisible&&/papers/paper36/dk.pdf&/span&&span class=&ellipsis&&&/span&&/a&&a href=&//link.zhihu.com/?target=http%3A//www.staff.city.ac.uk/cagatay.turkay.1/files/papers/VisPredict2014_final.pdf& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&staff.city.ac.uk/cagata&/span&&span class=&invisible&&y.turkay.1/files/papers/VisPredict2014_final.pdf&/span&&span class=&ellipsis&&&/span&&/a&&a href=&//link.zhihu.com/?target=https%3A//www.repository.cam.ac.uk/bitstream/handle//Han_et_al-2016-The_Journal_of_Econometrics-AM.pdf%3Fsequence%3D1%26isAllowed%3Dy& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&repository.cam.ac.uk/bi&/span&&span class=&invisible&&tstream/handle//Han_et_al-2016-The_Journal_of_Econometrics-AM.pdf?sequence=1&isAllowed=y&/span&&span class=&ellipsis&&&/span&&/a&&a href=&//link.zhihu.com/?target=http%3A//kidlab.eece.mu.edu/publications/papers/duan.pdf& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&kidlab.eece.mu.edu/publ&/span&&span class=&invisible&&ications/papers/duan.pdf&/span&&span class=&ellipsis&&&/span&&/a&&p&一些相关资料:&/p&&a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Predictability& data-draft-node=&block& data-draft-type=&link-card& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Predictability - Wikipedia&/a&&a href=&//link.zhihu.com/?target=http%3A//pasargadschools.com/wp-content/uploads/2016/07/Svetlana-Bryzgalova-Lecture1.pdf& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&pasargadschools.com/wp-&/span&&span class=&invisible&&content/uploads/2016/07/Svetlana-Bryzgalova-Lecture1.pdf&/span&&span class=&ellipsis&&&/span&&/a&
据我所知有一些技术可以用来测量time series数据的predictability:Forecastable Component Analysis:Hurst Exponent:
&p&前端流行这些:&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-672b3dcaf3bfd810800bbb9755acc663_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&971& data-rawheight=&632& class=&origin_image zh-lightbox-thumb& width=&971& data-original=&https://pic3.zhimg.com/50/v2-672b3dcaf3bfd810800bbb9755acc663_r.jpg&&&/figure&&p&服务器端流行这些:&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-f2f3d54bd5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&989& data-rawheight=&787& class=&origin_image zh-lightbox-thumb& width=&989& data-original=&https://pic1.zhimg.com/50/v2-f2f3d54bd5_r.jpg&&&/figure&&p&而他们都是JHipster生成项目的可选框架或技术。&/p&&a href=&//link.zhihu.com/?target=https%3A//www.jhipster.tech/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-2afcf1fdd2ba878ef7af0c97c40a6272_ipico.jpg& data-image-width=&512& data-image-height=&512& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Generate your Spring Boot + Angular apps!&/a&&p&&br&&/p&&p&关于JHipster,看一看我的另外一个回答:&/p&&a href=&https://www.zhihu.com/question//answer/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/assets/zhihu/editor/zhihu-card-default.jpg& class=&internal&&如何看待JHipster框架?&/a&
前端流行这些:服务器端流行这些:而他们都是JHipster生成项目的可选框架或技术。 关于JHipster,看一看我的另外一个回答:
&figure&&img src=&https://pic1.zhimg.com/v2-dfb68c69ea8_b.jpg& data-rawwidth=&559& data-rawheight=&521& class=&origin_image zh-lightbox-thumb& width=&559& data-original=&https://pic1.zhimg.com/v2-dfb68c69ea8_r.jpg&&&/figure&前言&br&&br&我们知道我们写的程序经过编译后成为了.class文件,.class文件中描述了类的各种信息,最终都需要加载到虚拟机之后才能运行和使用。而虚拟机如何加载这些.class文件?.class文件的信息进入到虚拟机后会发生什么变化?这些都是本文要讲的内容,文章将会讲解加载类加载的每个阶段Java虚拟机需要做什么事(加粗标红)。&br&&br&类使用的7个阶段&br&&br&类从被加载到虚拟机内存中开始,到卸载出内存,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initiallization)、使用(Using)和卸载(Unloading)这7个阶段。其中验证、准备、解析3个部分统称为连接(Linking),这七个阶段的发生顺序如下图:&br&&br&?&br&&br&图中,加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段不一定:它在某些情况下可以初始化阶段之后在开始,这是为了支持Java语言的运行时绑定(也称为动态绑定)。接下来讲解加载、验证、准备、解析、初始化五个步骤,这五个步骤组成了一个完整的类加载过程。使用没什么好说的,卸载属于GC的工作,在之前GC的文章中已经有所提及了。&br&&br&加载Loading&br&&br&加载是类加载的第一个阶段。有两种时机会触发类加载:&br&&br&1、预加载。虚拟机启动时加载,加载的是JAVA_HOME/lib/下的rt.jar下的.class文件,这个jar包里面的内容是程序运行时非常常常用到的,像java.lang.*、java.util.*、java.io.*等等,因此随着虚拟机一起加载。要证明这一点很简单,写一个空的main函数,设置虚拟机参数为”-XX:+TraceClassLoading”来获取类加载信息,运行一下:&br&&br&[Opened E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.Object from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.io.Serializable from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.Comparable from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.CharSequence from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.String from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.reflect.GenericDeclaration from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.reflect.Type from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.reflect.AnnotatedElement from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.Class from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&[Loaded java.lang.Cloneable from E:\MyEclipse10\Common\binary\com.sun.java.jdk.win32.x86_64_1.6.0.013\jre\lib\rt.jar]&br&...&br&&br&2、运行时加载。虚拟机在用到一个.class文件的时候,会先去内存中查看一下这个.class文件有没有被加载,如果没有就会按照类的全限定名来加载这个类。&br&&br&那么,加载阶段做了什么,其实加载阶段做了有三件事情:&br&&br&获取.class文件的二进制流&br&&br&将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中&br&&br&在内存中生成一个代表这个.class文件的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。一般这个Class是在堆里的,不过HotSpot虚拟机比较特殊,这个Class对象是放在方法区中的&br&&br&虚拟机规范对这三点的要求并不具体,因此虚拟机实现与具体应用的灵活度都是相当大的。例如第一条,根本没有指明二进制字节流要从哪里来、怎么来,因此单单就这一条,就能变出许多花样来:&br&&br&从zip包中获取,这就是以后jar、ear、war格式的基础&br&从网络中获取,典型应用就是Applet&br&运行时计算生成,典型应用就是动态代理技术&br&由其他文件生成,典型应用就是JSP,即由JSP生成对应的.class文件&br&从数据库中读取,这种场景比较少见&br&&br&总而言之,在类加载整个过程中,这部分是对于开发者来说可控性最强的一个阶段。&br&&br&验证&br&&br&连接阶段的第一步,这一阶段的目的是为了确保.class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。&br&&br&Java语言本身是相对安全的语言(相对C/C++来说),但是前面说过,.class文件未必要从Java源码编译而来,可以使用任何途径产生,甚至包括用十六进制编辑器直接编写来产生.class文件。在字节码语言层面上,Java代码至少从语义上是可以表达出来的。虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统崩溃,所以验证是虚拟机对自身保护的一项重要工作。&br&&br&验证阶段将做一下几个工作,具体就不细讲了,这是虚拟机实现层面的问题:&br&&br&1、文件格式验证&br&&br&这个地方要说一点和开发者相关的。.class文件的第5~第8个字节表示的是该.class文件的主次版本号,验证的时候会对这4个字节做一个验证,高版本的JDK能向下兼容以前版本的.class文件,但不能运行以后的class文件,即使文件格式未发生任何变化,虚拟机也必须拒绝执行超过其版本号的.class文件。举个具体的例子,如果一段.java代码是在JDK1.6下编译的,那么JDK1.6、JDK1.7的环境能运行这个.java代码生成的.class文件,但是JDK1.5、JDK1.4乃更低的JDK版本是无法运行这个.java代码生成的.class文件的。如果运行,会抛出java.lang.UnsupportedClassVersionError,这个小细节,务必注意。&br&&br&2、元数据验证&br&&br&3、字节码验证&br&&br&4、符号引用验证&br&&br&准备&br&&br&准备阶段是正式为类变量分配内存并设置其初始值的阶段,这些变量所使用的内存都将在方法区中分配。关于这点,有两个地方注意一下:&br&&br&1、这时候进行内存分配的仅仅是类变量(被static修饰的变量),而不是实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆中&br&&br&2、这个阶段赋初始值的变量指的是那些不被final修饰的static变量,比如”public static int value = 123;”,value在准备阶段过后是0而不是123,给value赋值为123的动作将在初始化阶段才进行;比如”public static final int value = 123;”就不一样了,在准备阶段,虚拟机就会给value赋值为123。&br&&br&各个数据类型的零值如下图:&br&&br&?&br&&br&解析&br&&br&解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。来了解一下符号引用和直接引用有什么区别:&br&&br&1、符号引用&br&&br&这个其实是属于编译原理方面的概念,符号引用包括了下面三类常量:&br&&br&类和接口的全限定名&br&字段的名称和描述符&br&方法的名称和描述符&br&&br&这么说可能不太好理解,结合实际看一下,写一段很简单的代码:&br&&br&package com.xrq.test6;&br&&br&public class TestMain&br&{&br&
&br&&br&&br&
public static void print()&br&
private boolean trueOrFalse()&br&
}&br&}&br&&br&用javap把这段代码的.class反编译一下:&br&&br&Constant pool:&br&
#1 = Class
com/xrq/test6/TestMain&br&
com/xrq/test6/TestMain&br&
#3 = Class
java/lang/Object&br&
java/lang/Object&br&
&init&&br&
#10 = Utf8
#11 = Utf8
#12 = Methodref
java/lang/Object.&&init&&:()V&br&
#13 = NameAndType
&&init&&:()V&br&
#14 = Utf8
LineNumberTable&br&
#15 = Utf8
LocalVariableTable&br&
#16 = Utf8
#17 = Utf8
Lcom/xrq/test6/TestM&br&
#18 = Utf8
#19 = Utf8
trueOrFalse&br&
#20 = Utf8
#21 = Utf8
SourceFile&br&
#22 = Utf8
TestMain.java&br&&br&看到Constant Pool也就是常量池中有22项内容,其中带”Utf8″的就是符号引用。比如#2,它的值是”com/xrq/test6/TestMain”,表示的是这个类的全限定名;又比如#5为i,#6为I,它们是一对的,表示变量时Integer(int)类型的,名字叫做i;#6为D、#7为d也是一样,表示一个Double(double)类型的变量,名字为d;#18、#19表示的都是方法的名字。&br&&br&那其实总而言之,符号引用和我们上面讲的是一样的,是对于类、变量、方法的描述。符号引用和虚拟机的内存布局是没有关系的,引用的目标未必已经加载到内存中了。&br&&br&2、直接引用&br&&br&直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同的虚拟机示例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经存在在内存中了。&br&&br&初始化&br&&br&初始化阶段是类加载过程的最后一步,初始化阶段是真正执行类中定义的Java程序代码(或者说是字节码)的过程。初始化过程是一个执行类构造器&clinit&()方法的过程,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。把这句话说白一点,其实初始化阶段做的事就是给static变量赋予用户指定的值以及执行静态代码块。&br&&br&注意一下,虚拟机会保证类的初始化在多线程环境中被正确地加锁、同步,即如果多个线程同时去初始化一个类,那么只会有一个类去执行这个类的&clinit&()方法,其他线程都要阻塞等待,直至活动线程执行&clinit&()方法完毕。因此如果在一个类的&clinit&()方法中有耗时很长的操作,就可能造成多个进程阻塞。不过其他线程虽然会阻塞,但是执行&clinit&()方法的那条线程退出&clinit&()方法后,其他线程不会再次进入&clinit&()方法了,因为同一个类加载器下,一个类只会初始化一次。实际应用中这种阻塞往往是比较隐蔽的,要小心。&br&&br&Java虚拟机规范严格规定了有且只有5种场景必须立即对类进行初始化,这4种场景也称为对一个类进行主动引用(其实还有一种场景,不过暂时我还没弄明白这种场景的意思,就先不写了):&br&&br&1、使用new关键字实例化对象、读取或者设置一个类的静态字段(被final修饰的静态字段除外)、调用一个类的静态方法的时候&br&&br&2、使用java.lang.reflect包中的方法对类进行反射调用的时候&br&&br&3、初始化一个类,发现其父类还没有初始化过的时候&br&&br&4、虚拟机启动的时候,虚拟机会先初始化用户指定的包含main()方法的那个类&br&&br&除了上面4种场景外,所有引用类的方式都不会触发类的初始化,称为被动引用,接下来看下被动引用的几个例子:&br&&br&1、子类引用父类静态字段,不会导致子类初始化。至于子类是否被加载、验证了,前者可以通过”-XX:+TraceClassLoading”来查看&br&&br&public class SuperClass&br&{&br&
public static int value = 123;&br&&br&
static&br&
System.out.println(&SuperClass init&);&br&
}&br&}&br&&br&public class SubClass extends SuperClass&br&{&br&
static&br&
System.out.println(&SubClass init&);&br&
}&br&}&br&&br&public class TestMain&br&{&br&
public static void main(String[] args)&br&
System.out.println(SubClass.value);&br&
}&br&}&br&&br&运行结果为:&br&&br&SuperClass init&br&123&br&&br&2、通过数组定义引用类,不会触发此类的初始化&br&&br&public class SuperClass&br&{&br&
public static int value = 123;&br&&br&
static&br&
System.out.println(&SuperClass init&);&br&
}&br&}&br&&br&public class TestMain&br&{&br&
public static void main(String[] args)&br&
SuperClass[] scs = new SuperClass[10];&br&
}&br&}&br&&br&运行结果为:&br&&br&&br&&br&3、引用静态常量时,常量在编译阶段会存入类的常量池中,本质上并没有直接引用到定义常量的类&br&&br&public class ConstClass&br&{&br&
public static final String HELLOWORLD =
&Hello World&;&br&&br&
static&br&
System.out.println(&ConstCLass init&);&br&
}&br&}&br&&br&public class TestMain&br&{&br&
public static void main(String[] args)&br&
System.out.println(ConstClass.HELLOWORLD);&br&
}&br&}&br&&br&运行结果为:&br&&br&Hello World&br&&br&在编译阶段通过常量传播优化,常量HELLOWORLD的值”Hello World”实际上已经存储到了NotInitialization类的常量池中,以后NotInitialization对常量ConstClass.HELLOWORLD的引用实际上都被转化为NotInitialization类对自身常量池的引用了。也就是说,实际上的NotInitialization的Class文件中并没有ConstClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。
前言 我们知道我们写的程序经过编译后成为了.class文件,.class文件中描述了类的各种信息,最终都需要加载到虚拟机之后才能运行和使用。而虚拟机如何加载这些.class文件?.class文件的信息进入到虚拟机后会发生什么变化?这些都是本文要讲的内容,文章将会…
&figure&&img src=&https://pic3.zhimg.com/v2-0ec2d052ecfb4_b.jpg& data-rawwidth=&1487& data-rawheight=&827& class=&origin_image zh-lightbox-thumb& width=&1487& data-original=&https://pic3.zhimg.com/v2-0ec2d052ecfb4_r.jpg&&&/figure&&p&原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不得转载,不能用于商业目的。 &/p&&p&怎样成为一名优秀的算法工程师?这是很多从事人工智能学术研究和产品研发的同学都关心的一个问题。面对市场对人才的大量需求与供给的严重不足,以及高薪水的诱惑,越来越多的人开始学习这个方向的技术,或者打算向人工智能转型。市面上各种鱼龙混杂的培训班以及误导人的文章会把很多初学者带入歧途,浮躁的跟风将会让你最后收获甚微,根本达不到企业的用人要求。为了更好的帮助大家学习和成长,少走弯路,在今天的文章里,&a href=&http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D2%26sn%3Daaedab3fce91857eec877b%26chksm%3Dfdb695f8cac11cee025ad6d8d77ed90fb20b2f5a6945b58edd97ceba91%5Cl%rd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SIGAI&/a&的作者以自己的亲身经历和思考,为大家写下对这一问题的理解与答案。&/p&&p&首先来看一个高度相关的问题:一个优秀的算法工程师必须具备哪些素质?我们给出的答案是这样的:&/p&&blockquote&数学知识&br&编程能力&br&机器学习与深度学习的知识&br&应用方向的知识&br&对自己所做的问题的思考和经验&/blockquote&&p&除去教育背景,逻辑思维,学习能力,沟通能力等其他方面的因素,大多数公司在考察算法工程师的技术水平时都会考虑上面这几个因素。接下来我们将按照这几个方面进行展开,详细的说明如何学习这些方面的知识以及积累经验。&/p&&h2&数学知识&/h2&&p&与其他工作方向如app、服务器开发相比,以及与计算机科学的其他方向如网络,数据库,分布式计算等相比,人工智能尤其是机器学习属于数学知识密集的方向。在各种书籍,论文,算法中都充斥着大量的数学公式,这让很多打算入门的人或者开始学习的人感到明显的压力。首先我们考虑一个最核心的问题:机器学习和深度学习究竟需要哪些数学知识?在SIGAI之前的公众号文章“学好机器学习需要哪些数学知识”里,我们已经给出了答案。先看下面这张表:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-a916df31afcec795ea72e36c_b.jpg& data-size=&normal& data-rawwidth=&1542& data-rawheight=&1444& class=&origin_image zh-lightbox-thumb& width=&1542& data-original=&https://pic3.zhimg.com/v2-a916df31afcec795ea72e36c_r.jpg&&&figcaption& 更多算法工程师的必读文章,请关注SIGAICN公众号&/figcaption&&/figure&&p&上面的表给出了各种典型的机器学习算法所用到的数学知识点。我们之前已经总结过,理解绝大多数算法和理论,有微积分/高等数学,线性代数,概率论,最优化方法的知识就够了。除流形学习需要简单的微分几何概念之外,深层次的数学知识如实变函数,泛函分析等主要用在一些基础理论结果的证明上,即使不能看懂证明过程,也不影响我们使用具体的机器学习算法。概率图模型、流形学习中基于图的模型会用到图论的一些基本知识,如果学习过离散数学或者数据结构,这些概念很容易理解。除此之外,某些算法会用到离散数学中的树的概念,但很容易理解。&/p&&p&如果你已经学过这些大学数学课,只要把所需的知识点复习一遍就够了。对于微积分,通俗易懂而又被广为采用的是同济版的高等数学:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-3ef8dbd529c5a35aade9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&420& data-rawheight=&440& class=&content_image& width=&420&&&/figure&&p&&br&&/p&&p&在机器学习中主要用到了微分部分,积分用的非常少。具体的,用到了下面的概念:&/p&&blockquote&导数和偏导数的定义与计算方法,与函数性质的关系&br&梯度向量的定义&br&极值定理,可导函数在极值点处导数或梯度必须为0&br&雅克比矩阵,这是向量到向量映射函数的偏导数构成的矩阵,在求导推导中会用到&br&Hessian矩阵,这是2阶导数对多元函数的推广,与函数的极值有密切的联系&br&凸函数的定义与判断方法&br&泰勒展开公式&br&拉格朗日乘数法,用于求解带等式约束的极值问题&/blockquote&&p&其中最核心的是多元函数的泰勒展开公式,根据它我们可以推导出梯度下降法,牛顿法,拟牛顿法等一系列最优化方法。如果你想要深入的学习微积分,可以阅读数学系的教程,称为数学分析:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-e8ea567e089cbb02817b9d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&421& data-rawheight=&616& class=&origin_image zh-lightbox-thumb& width=&421& data-original=&https://pic2.zhimg.com/v2-e8ea567e089cbb02817b9d_r.jpg&&&/figure&&p&与工科的高等数学偏重计算不同,它里面有大量的理论证明,对于锻炼数学思维非常有帮助。北大张筑生先生所著的数学分析可谓是国内这方面教材的精品。&/p&&p&下面来看线性代数,同样是同济版的教材:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-317e5b657402bbf0a8d69d597b2b50d1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&371& data-rawheight=&434& class=&content_image& width=&371&&&/figure&&p&如果想更全面系统的学习线性代数,可以看这本书:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f5b334db82c467ca84dcd2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&389& data-rawheight=&525& class=&content_image& width=&389&&&/figure&&p&相比之下,线性代数用的更多。具体用到的知识点有:&/p&&blockquote&向量和它的各种运算,包括加法,减法,数乘,转置,内积&br&向量和矩阵的范数,L1范数和L2范数&br&矩阵和它的各种运算,包括加法,减法,乘法,数乘&br&逆矩阵的定义与性质&br&行列式的定义与计算方法&br&二次型的定义&br&矩阵的正定性&br&特征值与特征向量&br&奇异值分解&br&线性方程组的数值解&/blockquote&&p&机器学习算法处理的数据一般都是向量、矩阵或者张量。经典的机器学习算法输入的数据都是特征向量,深度学习算法在处理图像时输入的2维的矩阵或者3维的张量。掌握这些概念是你理解机器学习和深度学习算法的基础。&/p&&p&概率论国内理工科专业使用最多的是浙大版的教材:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-1d9ec7dd9f4db320057ae_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&393& data-rawheight=&426& class=&content_image& width=&393&&&/figure&&p&如果把机器学习所处理的样本数据看作随机变量/向量,就可以用概率论的方法对问题进行建模,这代表了机器学习中很大一类方法。在机器学习里用到的概率论知识点有:&/p&&blockquote&随机事件的概念,概率的定义与计算方法&br&随机变量与概率分布,尤其是连续型随机变量的概率密度函数和分布函数&br&条件概率与贝叶斯公式&br&常用的概率分布,包括正态分布,伯努利二项分布,均匀分布&br&随机变量的均值与方差,协方差&br&随机变量的独立性&br&最大似然估计&/blockquote&&p&这些知识不超出普通理工科概率论教材的范围。&/p&&p&最后来说最优化,几乎所有机器学习算法归根到底都是在求解最优化问题。求解最优化问题的指导思想是在极值点出函数的导数/梯度必须为0。因此你必须理解梯度下降法,牛顿法这两种常用的算法,它们的迭代公式都可以从泰勒展开公式而得到。&/p&&p&凸优化是机器学习中经常会提及的一个概念,这是一类特殊的优化问题,它的优化变量的可行域是凸集,目标函数是凸函数。凸优化最好的性质是它的所有局部最优解就是全局最优解,因此求解时不会陷入局部最优解。如果一个问题被证明为是凸优化问题,基本上已经宣告此问题得到了解决。在机器学习中,线性回归、岭回归、支持向量机、logistic回归等很多算法求解的都是凸优化问题。&/p&&p&拉格朗日对偶为带等式和不等式约束条件的优化问题构造拉格朗日函数,将其变为原问题,这两个问题是等价的。通过这一步变换,将带约束条件的问题转换成不带约束条件的问题。通过变换原始优化变量和拉格朗日乘子的优化次序,进一步将原问题转换为对偶问题,如果满足某种条件,原问题和对偶问题是等价的。这种方法的意义在于可以将一个不易于求解的问题转换成更容易求解的问题。在支持向量机中有拉格朗日对偶的应用。&/p&&p&KKT条件是拉格朗日乘数法对带不等式约束问题的推广,它给出了带等式和不等式约束的优化问题在极值点处所必须满足的条件。在支持向量机中也有它的应用。&/p&&p&如果你没有学过最优化方法这门课也不用担心,这些方法根据微积分和线性代数的基础知识可以很容易推导出来。如果需要系统的学习这方面的知识,可以阅读《凸优化》,《非线性规划》两本经典教材。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-09b51d1def45d695c4a7c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&441& data-rawheight=&615& class=&origin_image zh-lightbox-thumb& width=&441& data-original=&https://pic1.zhimg.com/v2-09b51d1def45d695c4a7c_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-7b7c062adbe_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&447& data-rawheight=&612& class=&origin_image zh-lightbox-thumb& width=&447& data-original=&https://pic3.zhimg.com/v2-7b7c062adbe_r.jpg&&&/figure&&h2&编程能力&/h2&&p&编程能力是学好机器学习和深度学习的又一大基础。对于计算机类专业的学生,由于本科已经学了c语言,c++,数据结构与算法,因此这方面一般不存在问题。对于非计算机专业的人来说,要真正学好机器学习和深度学习,这些知识是绕不开的。&/p&&p&虽然现在大家热衷于学习python,但要作为一名真正的算法工程师,还是应该好好学习一下c++,至少,机器学习和深度学习的很多底层开源库都是用它写的;很多公司线上的产品,无论是运行在服务器端,还是嵌入式端,都是用c++写的。此外,如果你是应届生,在校园招聘时不少公司都会面试你c++的知识。&/p&&p&C++最经典的教材无疑是c++ primer:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-533a73e4db82dd3d4414beb7caf57a0b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&356& data-rawheight=&453& class=&content_image& width=&356&&&/figure&&p&对做算法的人来说,这本书其实不用全部看,把常用的点学完就够了。对于进阶,Effective c++是很好的选择,不少公司的面试题就直接出自这本书的知识点:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-bda111ade52fa4fef938f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&294& data-rawheight=&363& class=&content_image& width=&294&&&/figure&&p&接下来说python,相比c++来说,学习的门槛要低很多,找一本通俗易懂的入门教程学习一遍即可。&/p&&p&数据结构和算法是编写很多程序的基础,对于机器学习和深度学习程序也不例外。很多算法的实现都依赖于数组,链表,数,排序,查找之类的数据结构和基础算法。如果有时间和精力,把算法导论啃一遍,你会有不一样的感受:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-e99f0980aacb8046d67acb4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&236& data-rawheight=&318& class=&content_image& width=&236&&&/figure&&p&对于应届生来说,学完它对于你通过大互联网和人工智能公司校园招聘的技术面试也非常有用。&/p&&p&上面说的只是编程语言的程序设计的理论知识,我们还要考虑实际动手能力。对于开发环境如gcc/g++,visual studio之类的工具,以及gdb之类的调试工具需要做到熟练使用。如果是在linux上开发,对linux的常用命令也要熟记于心。这方面的知识看各种具体的知识点和教程即可。另外,对于编程的一些常识,如进程,线程,虚拟内存,文件系统等,你最好也要进行了解。&/p&&h2&机器学习与深度学习&/h2&&p&在说完了数学和编程基础之后,下面我来看核心的内容,机器学习和深度学习知识。机器学习是现阶段解决很多人工智能问题的核心方法,尤其是深度学习,因此它们是算法工程师的核心知识。在这里有一个问题:是否需要先学机器学习,还是直接学深度学习?如果是一个专业的算法工程师,我的建议是先学机器学习。至少,你要知道机器学习中的基本概念,过拟合,生成模型,ROC曲线等,上来就看深度学习,如没有背景知识你将不知所云。另外,神经网络只是机器学习中的一类方法,对于很多问题,其他机器学习算法如logistic回归,随机森林,GBDT,决策树等还在被大规模使用,因此你不要把自己局限在神经网络的小圈子里。&/p&&p&首先来看机器学习,这方面的教材很多,周志华老师的机器学习,李航老师的统计学习方法是国内的经典。这里我们介绍国外的经典教材,首先是PRML:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-75b36efb9c3f4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&266& data-rawheight=&359& class=&content_image& width=&266&&&/figure&&p&此书深厚,内容全面,涵盖了有监督学习,无监督学习的主要方法,理论推导和证明详细深入,是机器学习的经典。此外还有模式分类这本书,在这里不详细介绍。&/p&&p&深度学习目前最权威的教程是下面这本书:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-d0daf03f8b6f3d7bf66cc4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&407& data-rawheight=&593& class=&content_image& width=&407&&&/figure&&p&它涵盖了深度学习的方方面面,从理论到工程,但美中不足的是对应于介绍的相对较少。&/p&&p&强化学习是机器学习很独特的一个分支,大多数人对它不太了解,这方面的教程非常少,我们推荐下面这本书:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-ea4bdf4653bdc9dcc5622_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&287& data-rawheight=&380& class=&content_image& width=&287&&&/figure&&p&美中不足的是这本书对深度强化学习没有介绍,因为出版的较早。不知最新的版本有没有加上这方面的内容。&/p&&p&在这里需要强调的是,你的知识要系统化,有整体感。很多同学都感觉到自己学的机器学习太零散,缺乏整体感。这需要你多思考算法之间的关系,演化历史之类的问题,这样你就做到胸中有图-机器学习算法地图。其实,SIGAI在之前的公众号文章“&a href=&http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dfc8cc8de313bdb61dcd39c1dedb240a4%26chksm%3Dfdb69aedcac113fb4b18cded50bade0e66b26f332ab247bff2a3c0%5Cl%rd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&机器学习算法地图&/a&”里已经给你总结出来了。&/p&&h2&开源库&/h2&&p&上面介绍了机器学习和深度学习的理论教材,下面来说实践问题。我们无需重复造车轮子,熟练的使用主流的开源库是需要掌握的一项技能。对于经典的机器学习,常用的库的有:&/p&&blockquote&libsvm&br&liblinear&br&XGBoost&br&OpenCV&br&HTK&br&Weka&/blockquote&&p&在这里我们不一一列举。借助于这些库,我们可以方便的完成自己的实验,或是研发自己的产品。对于深度学习,目前常用的有:&/p&&blockquote&Caffe&br&TensorFlow&br&MXNet&/blockquote&&p&除此之外,还有其他的。对于你要用到的开源库,一定要理解它的原理,以及使用中的一些细节问题。例如很多算法要求输入的数据先做归一化,否则效果会非常差,而且面临浮点数溢出的问题,这些实际经验需要你在使用中摸索。如果有精力把这些库的核心代码分析一遍,你对实现机器学习算法将会更有底气。以深度学习为例,最核心的代码无非是实现:&/p&&blockquote&各种层,包括它们的正向传播和反向传播&br&激活函数的实现&br&损失函数的实现&br&输入数据的处理&br&求解器,实现各种梯度下降法&/blockquote&&p&这些代码的量并不大,沉下心来,我相信一周之内肯定能分析完。看完之后你会有一种豁然开朗的感觉。&/p&&h2&应用方向的知识&/h2&&p&接下来是各个方向的知识,与机器学习有关的应用方向当前主要有:&/p&&blockquote&机器视觉&br&语音识别 &br&自然语言处理&br&数据挖掘&br&知识图谱&br&推荐系统&/blockquote&&p&除此之外,还有其他一些特定小方向,在这里不一一列举。这些具体的应用方向一般都有自己的教材,如果你以后要从事此方向的研究,系统的学习一遍是必须的。&/p&&h2&实践经验与思考&/h2&&p&在说完理论与实践知识之后,最后我们来说经验与思考。在你确定要做某一个方向之后,对这个方向的方法要有一个全面系统的认识,很多方法是一脉相承的,如果只追求时髦看最新的算法,你很难做出学术上的创新,以及工程上的优化。对于本问题所有的经典论文,都应该化时间细度,清楚的理解它们解决了什么问题,是怎么解决的,还有哪些问题没有解决。例如:&/p&&p&机器视觉目标检测中的遮挡问题&/p&&p&推荐系统中的冷启动问题&/p&&p&自然语言处理中文分词中的歧义切分问题&/p&&p&只有经过大量的编程和实验训练,以及持续的思考,你才能算得上对这个方向深刻理解,以至于有自己的理解。很多同学对自己实现轮上的算法没有底气,解决这个问题最快的途径就是看论文算法的开源代码,在github上有丰富的资源,选择一些合适的,研究一下别人是怎么实现的,你就能明白怎么实现自己的网络结构和损失函数,照葫芦画瓢即可。&/p&&p&计算机以及人工智能是一个偏实践的学科,它的方法和理论既需要我们有扎实的理论功底,又需要有丰富的实践能力与经验。这两个方面构成了算法工程师最主要的素质。科学的学习路径能够让你取得好的学习效果,同时也缩短学习时间。错误和浮躁的做法则会让你最后事倍功半。这是SIGAI对想进入这个领域,或者刚进入这个领域的每个人要说的!&/p&&p&&br&&/p&&p&推荐阅读&/p&&p&[1] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc6e7c4a2e14aeb60f155ac%26chksm%3Dfdb69caecac115be526e99a3f6976fdaa2f6b6a07ccb57b40c40ae3%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&机器学习-波澜壮阔40年&/a& SIGAI .&/p&&p&[2] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D1e7cac73e15691fe17aec%26chksm%3Dfdb69cd6cac115c05f1f90bae9be074ac0dc134e2d60fd64%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&学好机器学习需要哪些数学知识?&/a&SIGAI .&/p&&p&[3] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D9fef4cc9f8d40cc71a6e%26chksm%3Dfdb69cd9cac115cf4ebab64c75e1e55a40bfc28f00c6ff0aa%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&人脸识别算法演化史&/a& SIGAI .&/p&&p&[4] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D237c52bc9ddfebchksm%3Dfdb69cc4cac115d2ca505e0debaffea75c9fef458fd3aca2%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&基于深度学习的目标检测算法综述&/a& SIGAI .&/p&&p&[5] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dfcd09f910e%26chksm%3Dfdb69c3fcacdd0d677dc1bdeb5bbc0aa154escene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&卷积神经网络为什么能够称霸计算机视觉领域?&/a&
SIGAI .&/p&&p&[6] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D84a5acf12ed456c414c12%26chksm%3Dfdb69fb6cac116a02dc68d1a4ae2b6c3d224d9dab21d0f2fccb329%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&用一张图理解SVM的脉络 &/a& SIGAI .&/p&&p&[7] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Da3a5b3f654achksm%3Dfdb69fb9cac116af5dd237cf987e56d12b0d2e54c5c565aab752f3e366c0c45bfefa76f5ed16%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&人脸检测算法综述&/a&
SIGAI .&/p&&p&[8] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D401b211bf72bc70f733d6ac90f7352cc%26chksm%3Dfdb69fdecac116c81aad9e5adaeaf07dc651d2c1473c52fadscene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解神经网络的激活函数&/a& SIGAI .&/p&&p&[9] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D13ad0d521b6a950b41f4%26chksm%3Dfdb69f12cac11604a42ccba11c65a8daeba1aed570a751cb400d276b6%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深度卷积神经网络演化历史及结构改进脉络-40页长文全面解读&/a& SIGAI .&/p&&p&[10] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D4eda0afff1a8%26chksm%3Dfdb69f58cacbdb38d26ebcb7ca5a8de7b9bb%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解梯度下降法&/a& SIGAI .&/p&&p&[11] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D0fc55aa1ae64d7dbfa23d%26chksm%3Dfdb69e01cac1fcde17bd3e826bf654bd0%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&循环神经网络综述—语音识别与自然语言处理的利器&/a& SIGAI &/p&&p&[12] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D4fa8c71ae9cb777d6e97ebd0ddchksm%3Dfdb69980cacca8dc7945606eeefeb21b4f5bdb434fb56f92%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解凸优化&/a&
SIGAI &/p&&p&[13] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D4f3a6ce21cdd1a048e402ed05c9ead91%26chksm%3Dfdb699d8cac110ce53f4fc5e417e107fd3cbf640c6ffb4e7f6ee02f9%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【实验】理解SVM的核函数和参数&/a& SIGAI &/p&&p&[14] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dddaa70c4b92f6005d9bbd6b3a3fe4571%26chksm%3Dfdb699fccac110ea14e6adeb873a00d6ee86dd4145ddf8e90c9b878b908ac7b7655cfa51dab6%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【SIGAI综述】行人检测算法&/a& SIGAI &/p&&p&[15] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3De1e18ad800f7fchksm%3Dfdb699ebcac110fdbc7ebedbc454b63d7f274f7e61ca5187%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&机器学习在自动驾驶中的应用—以百度阿波罗平台为例&/a&(上) SIGAI &/p&&p&[16] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Da0e4ca5edb868fe3eae03%26chksm%3Dfdb6997ccacfe9f8fdd13f6c75c2cbbf1a7c94c58bcdf5f2a6661facd%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解牛顿法&/a& SIGAI &/p&&p&[17] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Df5c9f92c272c7f%26chksm%3Dfdb69965caccaef5d7ba363d9ef7f3d1b9bcd2bca7b7b%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【群话题精华】5月集锦—机器学习和深度学习中一些值得思考的问题 &/a&SIGAI &/p&&p&[18] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D9b389aadddf17c601afbee1%26chksm%3Dfdb69883cac4e94c3b71aa68de67bda8a946c1f9f9ef0bf18fed99b8%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&大话Adaboost算法&/a& SIGAI &/p&&p&[19] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dbb4f54daa%26chksm%3Dfdb698b0cac111ab6f7cfad2342dbaaf624b4e9dcc43c0d85ae06deb%26scene%3D21%5Cl%wechat_redirect%5Ct%_blank& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&FlowNet到FlowNet2.0:基于卷积神经网络的光流预测算法&/a& SIGAI &/p&&p&[20] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Db2c0d56bbc%26chksm%3Dfdb698c5cac111d3e3dca24c50aafbfb61e5b05c5df5bedec8db46b24%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解主成分分析(PCA)&/a& SIGAI &/p&&p&[21] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dceafbae457ad392b9f89c%26chksm%3Dfdb698e7cac111f13d8229d7dcc00b4ada1bd41e7ecc1d29bfa7be520d205c53e9%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&人体骨骼关键点检测综述&/a&
SIGAI &/p&&p&[22] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D043d7d0159baaddfbf92ed78ee5b1124%26chksm%3Dfdb6980ccac1111a9faeae7f517fee46a1dfab19612f76ccfef090ab8fc702d18b8%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解决策树&/a& SIGAI &/p&&p&[23] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D2c4db22fbaf99d%26chksm%3Dfdb6982ccacbe325bb07a947d75f3b50e11e1abd809fb7358bde16%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&用一句话总结常用的机器学习算法&/a& SIGAI &/p&&p&[24] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc02ee17ead63echksm%3Dfdb6987acacec28424baf4ea16ca11d2b13f20d4a825d7b2b82fb8765720ebd1063%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&目标检测算法之YOLO&/a& SIGAI &/p&&p&[25] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc28b7f07cef90e9dbe3ad1%26chksm%3Dfdb69b8dcacfca1d550e2b1c73b280d4e529f9f93cea2%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解过拟合&/a& SIGAI &/p&&p&[26] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Ddchksm%3Dfdb69ba2cac112b4dac620d52100ebd033eb679f97c4dccscene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解计算:从√2到AlphaGo ——第1季 从√2谈起&/a& SIGAI &/p&&p&[27] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D0d4fb43b8db2acfcbf3f478%26chksm%3Dfdb69bdacac112cce05c8b735b4f8b1ccf2348bea55a30afbb8f1ffd0f819bd2%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&场景文本检测——CTPN算法介绍&/a&
SIGAI &/p&&p&[28] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dcdcf8d4b07acf64c7a6f5f7c1a731a12%26chksm%3Dfdb69be5cac112fafbc58d94cf6af61ee5a4bd1bf6cscene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&卷积神经网络的压缩和加速&/a& SIGAI &/p&&p&[29] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D0ebf1bf8f49e9c4d04c95d%26chksm%3Dfdb69b05cacc70afcccfa5fcdb246b3b2decbc80a180abb3%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&k近邻算法&/a& SIGAI &/p&&p&[30] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc0e01da30eb5e750be453eabe4be2bf4%26chksm%3Dfdb69b41cac1dac395e9651dab628fc35dd6d3c02df5f2b%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&自然场景文本检测识别技术综述&/a& SIGAI &/p&&p&[31] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D990cce9fef0a261e6add2a%26chksm%3Dfdb69b74cac112628bdae14cfece20dae9bf7b1ffc8b8b25efeca0a72%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理解计算:从√2到AlphaGo ——第2季 神经计算的历史背景&/a& SIGAI &/p&&p&[32] &a href=&http://link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dfc8cc8de313bdb61dcd39c1dedb240a4%26chksm%3Dfdb69aedcac113fb4b18cded50bade0e66b26f332ab247bff2a3c0%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&机器学习算法地图&/a& SIGAI&/p&&p&[33]
&a href=&http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D57d7dc4ea2c6ee8018cc%26chksm%3Dfdb69591cac11cabe43cf0fa845e5ca2713dae%23rd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&反向传播算法推导-全连接神经网络&/a& SIGAI &/p&&p&[34]
&a href=&http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4MjQ3MDkwNA%3D%3D%26mid%3D%26idx%3D1%26sn%3D213f48c4e55bee688cf2c%26chksm%3Dfdb695f8cac11ceef3ef246c54d811dd64d8cc45fcaa95f72c1abfb5%23rd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&生成式对抗网络模型综述 SIGAI&/a&&/p&&p&&br&&/p&&p&&br&&/p&&p&原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不得转载,不能用于商业目的。 &/p&&p&&/p&&p&&/p&&p&&/p&
原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不得转载,不能用于商业目的。 怎样成为一名优秀的算法工程师?这是很多从事人工智能学术研究和产品研发的同学都关心的一个问题。面对市场对人才的大量需求与供给的严重不足,以及高薪水的诱…
&figure&&img src=&https://pic1.zhimg.com/v2-b87eb8a37bd439d15bf41_b.jpg& data-rawwidth=&800& data-rawheight=&533& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/v2-b87eb8a37bd439d15bf41_r.jpg&&&/figure&&p&作者 | Walker&/p&&p&编辑 | 磐石&/p&&p&出品 | 磐创AI技术团队&/p&&p&【磐创AI导读】:本文主要介绍了常用的一些机器学习中常用的优化算法。想要学习更多的机器学习知识,欢迎大家点击上方蓝字关注我们的公众号:磐创AI。&br&&/p&&p&在机器学习的世界中,通常我们会发现有很多问题并没有最优的解,或是要计算出最优的解要花费很大的计算量,面对这类问题一般的做法是利用迭代的思想尽可能的逼近问题的最优解。我们把解决此类优化问题的方法叫做优化算法,优化算法本质上是一种数学方法,常见的优化算法包括&b&梯度下降法&/b&、&b&牛顿法&/b&、&b&Momentum&/b&, &b&Nesterov Momentum&/b&, &b&Adagrad&/b&, &b&Adam&/b&等。其实大部分机器学习算法的本质都是建立优化模型,通过优化算法对损失函数(优化的&b&目标函数&/b&)进行优化,从而训练出最好的模型。&/p&&p&&b&(1)梯度下降法&/b&&br&梯度下降法是最常用的一种优化算法。其核心思想是:在当前位置寻找梯度下降最快的方向,来逐渐逼近优化的目标函数。且离目标函数越近,逼近的“步伐”也就越小。梯度下降法本质是一种迭代方法,常用于机器学习算法的模型参数求解。其示意图如下图1所示:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-7b0ee08dc01bbf_b.jpg& data-size=&normal& data-rawwidth=&1080& data-rawheight=&513& class=&origin_image zh-lightbox-thumb& width=&1080& data-original=&https://pic2.zhimg.com/v2-7b0ee08dc01bbf_r.jpg&&&figcaption&图1梯度下降法&/figcaption&&/figure&&p&梯度下降法的更新公式为:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-ebb2f8f522f2e2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&325& data-rawheight=&55& class=&content_image& width=&325&&&/figure&&p&其中α为梯度上每次逼近的步长,前边的“-”表示搜索方向为负梯度的方向,L我损失函数。算法更新终止的条件是梯度向量接近于0即可。此外需要特别注意的是,梯度下降法不一定能够找到全局的最优解,很有可能找到的是一个局部最优解。&/p&&p&&b&(2)梯度下降法的变式&/b&&/p&&p&通常基于梯度的下降方法又有很多变式,我们主要为大家介绍:随机梯度下降法(SGD), Momentum, Nesterov Momentum, Adagrad, Adam。&/p&&p&&br&&/p&&p&随机梯度下降法是每次使用一批数据进行梯度的计算,而非计算全部数据的梯度,因为如果每次计算全部数据的梯度,会导致运算量加大,运算时间变长,容易陷入局部最优解,而随机梯度下降可能每次不是朝着真正最小的方向,这样反而可以跳出局部的最优解。&/p&&p&&br&&/p&&p&Momentum是在随机梯度下降法的基础上,增加了动量(Momentum)的技术。其核心是通过优化相关方向的训练和弱化无关方向的振荡,来加速SGD训练。Momentum的方法能够在一定程度上缓解随机梯度下降法收敛不稳定的问题,并且有一定的摆脱陷入局部最优解的能力。&/p&&p&&br&&/p&&p&Nesterov Momentum是基于Momentum的加速算法,相比于传统的动量算法,最大的优化是计算经过动量更新之后的位置梯度。&/p&&p&&br&&/p&&p&Adagrad即adaptive gradient,是一种自适应学习率的梯度法。它通过记录并调整每次迭代过程中的前进方向和距离,使得针对不同问题都有一套自适应学习率的方法。Adagrad最大的优势是不需要手动来调整学习率,但与此同时会降低学习率。&/p&&p&&br&&/p&&p&Adam即Adaptive Moment Estimation,是能够自适应时刻的估计方法,能够针对每个参数,计算自适应学习率。这是一种综合性的优化方法,在机器学习实际训练中,往往能够取得不错的效果。&/p&&p&&b&(3)牛顿法和拟牛顿法&/b&&/p&&p&与上述梯度类型的优化算法最大的不同是,牛顿法是一种二阶收敛算法,所以它的收敛速度相较于一阶算法会更快。牛顿法二阶的意义在于它不仅会沿着梯度最大的方向下降,还会考虑走的下一步坡度是不是也很大,它能够以较远的目光全局的逼近目标函数。其算法的具体步骤为:&/p&&p&&b&1)&/b&首先选择接近于函数f(x)的零点x0,并计算f(x0)处的斜率f’(x0)。然后我们求解以下方程,得到比刚刚的x0更加准确的解x1。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-45916dedf65ddea74abbd_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&259& data-rawheight=&33& class=&content_image& width=&259&&&/figure&&p&&br&&/p&&p&&b&2)&/b&接下来我们利用x1进行下一轮的迭代,迭代公式如下所示。这样经过反复的迭代过程,我们便能取得函数f(x)的最优解。&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-192ca939a008adb10b4d4f76c14c9b9a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&219& data-rawheight=&63& class=&content_image& width=&219&&&/figure&&p&&br&&/p&&p&牛顿法的迭代示意图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-6efcca8d2ad203_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&439& data-rawheight=&356& class=&origin_image zh-lightbox-thumb& width=&439& data-original=&https://pic1.zhimg.com/v2-6efcca8d2ad203_r.jpg&&&/figure&&p&&br&&/p&&p&&i&图2 牛顿法&/i&&/p&&p&虽然牛顿法相较于梯度下降法等优化算法收敛速度更快,但每一步都需要求解复杂的Hessian矩阵,计算非常不易。所以后来美国Argonne国家实验室的物理学家W.C.Davidon又针对牛顿法计算复杂的缺陷提出了拟牛顿法。它的核心思想是使用正定矩阵来近似Hessian矩阵的逆,从而简化了运算的复杂。另外,因为拟牛顿法不需要二阶导数的信息,所以现在拟牛顿法在机器学习实际问题中应用更加的广泛。&/p&&p&&br&&/p&&p&【总结】:除了以上几类较为常见的优化算法以外,还有共轭梯度法、启发式优化算法等。在实际的机器学习问题中,往往需要具体问题具体分析,根据每类优化问题的特征,选择合适的优化算法。&/p&&p&&br&&/p&&p&&b&最后,对深度学习感兴趣,热爱Tensorflow的小伙伴,欢迎关注我们的网站!&a href=&https://link.zhihu.com/?target=http%3A//www.tensorflownews.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&http://www.tensorflownews.com&/a&。我们的公众号:磐创AI。&/b&&/p&
作者 | Walker编辑 | 磐石出品 | 磐创AI技术团队【磐创AI导读】:本文主要介绍了常用的一些机器学习中常用的优化算法。想要学习更多的机器学习知识,欢迎大家点击上方蓝字关注我们的公众号:磐创AI。 在机器学习的世界中,通常我们会发现有很多问题并没有最…
&p&&b&典型的回答&/b&&/p&&p&Java提供了不同层面的线程安全支持。在传统集合框架内部,除了Hashtable等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),可以调用Collections工具类提供的包装方法,来获取一个同步的包装容器,例如Collections.synchronizedMap()。但是它们都是利用非常粗粒度的同步方式,在高并发情况下的性能比较低下。&/p&&p&&br&&/p&&p&另外,更加普遍的选择是利用并发包(java.util.concurrent)提供的线程安全容器类:&/p&&p&&br&&/p&&p&&b&01&/b&&/p&&p&各种并发容器,比如ConcurrentHashMap、CopyOnWriteArrayList。&/p&&p&&b&02&/b&&/p&&p&各种线程安全队列(Queue/Deque),比如ArrayBlockingQueue、SynchronousQueue。&/p&&p&&b&03&/b&&/p&&p&各种有序容器的线程安全版本等。&/p&&p&&br&&/p&&p&具体保证线程安全的方式,包括有从简单的synchronized方式,到基于更加精细化的,比如基于分离锁实现的ConcurrentHashMap等并发实现等。具体选择要看开发的场景需求,总体来说,并发包内提供的容器通用场景,远远优于早期的简单同步实现。&/p&&p&&br&&/p&&p&&b&知识扩展&/b&&/p&&p&&b&1、为什么需要ConcurrentHashMap?&/b&&/p&&p&&br&&/p&&p&首先,Hashtable本身比较低效,因为它的实现基本就是将put、get、size等方法简单粗暴地加上“synchronized”。这就导致了所有并发操作都要竞争同一把锁,一个线程在进行同步操作时,其它线程只能等待,大大降低了并发操作的性能。&/p&&p&&br&&/p&&p&那么能不能利用Collections提供的同步包装器来解决问题呢?以下代码片段摘自Collections:&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&private static class SynchronizedMap&K,V&
implements Map&K,V&, Serializable {
private final Map&K,V& // Backing Map
// Object on which to synchronize
public int size() {
synchronized (mutex) {return m.size();}
&/code&&/pre&&/div&&p&&br&&/p&&p&我们发现同步包装器指示利用输入Map构造了另一个同步版本,所有操作虽然不再声明成为synchronized方法,但是还是利用了“this”作为互斥的mutex,没有真正意义上的改进!&/p&&p&&br&&/p&&p&所以,Hashtable或者同步包装版本都只适合在非高度并发的场景下。&/p&&p&&br&&/p&&p&&b&2、ConcurrentHashMap分析&/b&&/p&&p&&br&&/p&&p&再来看看ConcurrentHashMap是如何设计实现的,为什么它能大大提供并发效率。&/p&&p&&br&&/p&&p&首先需要强调,ConcurrentHashMap的设计实现其实一直在演化,比如在Java 8中就发生了非常大的变化。&/p&&p&&br&&/p&&p&早期的ConcurrentHashMap其实现是基于:&/p&&p&&br&&/p&&p&&b&01&/b&&/p&&p&分离锁,也就是将内部进行分段(Segment),里面则是HashEntry的数组。和HashMap类似,哈希相同的条目也是以链表形式存放。&/p&&p&&b&02&/b&&/p&&p&HashEntry内部使用volatile的value字段来保证可见性,也利用了不可变对象的机制以改进利用sun.misc.Unsafe提供的底层能力,比如volatile access,去直接完成部分操作,以最优化性能。毕竟Unsafe中的很多操作都是JVM intrinsic优化过的。&/p&&p&&br&&/p&&p&参考下面这个早期ConcurrentHashMap内部结构示意图,其核心是利用分段设立,在进行并发操作的时候,只需要锁定相应段,这样就有效避免了类似Hashtable整体同步的问题,大大提高了性能。&/p&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-3281faa05b991fad2260b1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&528& data-rawheight=&385& class=&origin_image zh-lightbox-thumb& width=&528& data-original=&https://pic3.zhimg.com/v2-3281faa05b991fad2260b1_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&p&在构造的时候,Segment的数量由所谓的concurrentcyLevel决定,默认是16,也可以在相应构造函数直接指定。注意,Java需要它是2的整数次幂,例如输入15,将会被自动调整到16。&/p&&p&&br&&/p&&p&分离锁看似完美,但是在size方法实现时会有副作用。试想,如果不进行同步,简单的计算所有Segment的总值,可能会因为并发put,导致结果不准确;但是直接锁定所有Segment进行计算,就会变得非常昂贵。其实,分离锁也给包括Map初始化等操作带来类似的副作用。&/p&&p&&br&&/p&&p&所以,ConcurrentHashMap的实现是通过重试机制(RETRIES_BEFORE_LOCK,指定重复次数2),来试图获得可靠值。如果没有监控到发生变化,就直接返回,否则将获取锁进行操作。&/p&&p&&br&&/p&&p&&b&3、Java 8对ConcurrentHashMap的改进&/b&&/p&&p&&br&&/p&&p&&b&01&/b&&/p&&p&总体结构上,它的内部存储变得和上一讲中介绍的HashMap结构非常相似,同样是大的桶数组,然后内部也是一个个链表结果,同步的粒度要更细致一些。&/p&&p&&b&02&/b&&/p&&p&其内部仍然有Segment定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处。&/p&&p&&b&03&/b&&/p&&p&因为不再使用Segment,初始化操作大大简化,修改为lazy-load形式。这样可以有效避免初始开销,解决了老版本很多人抱怨的这一点。&/p&&p&&b&04&/b&&/p&&p&数据存储利用volatile来保证可见性。&/p&&p&&b&05&/b&&/p&&p&使用CAS(Compare And Swap)等操作,在特定场景进行无锁并发操作。&/p&&p&&b&06&/b&&/p&&p&使用Unsafe、LongAdder之类底层手段,进行极端情况的优化。&/p&&p&&/p&&p&&/p&
典型的回答Java提供了不同层面的线程安全支持。在传统集合框架内部,除了Hashtable等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),可以调用Collections工具类提供的包装方法,来获取一个同步的包装容器,例如Collections.synchronizedMap(…
&figure&&img src=&https://pic1.zhimg.com/v2-c9b4c24fd003b126cc0f452bb9fa203f_b.jpg& data-rawwidth=&1000& data-rawheight=&625& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&https://pic1.zhimg.com/v2-c9b4c24fd003b126cc0f452bb9fa203f_r.jpg&&&/figure&&h2&消失的事务&/h2&&p&端午节前,组内在讨论一个问题:&/p&&p&&b&一个没有加@Transactional注解的方法,去调用一个加了@Transactional的方法,会不会产生事务?&/b&&/p&&p&文字苍白,还是用代码说话。&/p&&p&先写一个@Transactional的方法(&b&本文的所有代码,可到&a href=&https://link.zhihu.com/?target=https%3A//github.com/hzy38324/Spring-Boot-Practice& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Github&/a&上下载&/b&):&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Transactional&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&deleteAllAndAddOneTransactional&/span&&span class=&o&&(&/span&&span class=&n&&Customer&/span& &span class=&n&&customer&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&customerRepository&/span&&span class=&o&&.&/span&&span class=&na&&deleteAll&/span&&span class=&o&&();&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&s&&&Yang&&/span&&span class=&o&&.&/span&&span class=&na&&equals&/span&&span class=&o&&(&/span&&span class=&n&&customer&/span&&span class=&o&&.&/span&&span class=&na&&getFirstName&/span&&span class=&o&&()))&/span& &span class=&o&&{&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&n&&RuntimeException&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&span class=&n&&customerRepository&/span&&span class=&o&&.&/span&&span class=&na&&save&/span&&span class=&o&&(&/span&&span class=&n&&customer&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&方法内先去执行deleteAll(),删除表中全部数据;然后执行save()保存数据。&/p&&p&这两个方法中间,会判断传进来的firstName是不是等于“Yang”,是,则抛异常,用于模拟两个数据库操作之间可能发生的异常场景。&/p&&p&如果没有加@Transactional注解,那么这两个操作就不在一个事务里面,不具有原子性。如果deleteAll之后抛异常,那么就会导致只删除不新增。&/p&&p&而加了@Transactional之后,这两个动作在一个事务里头,具有原子性,要么全部成功,要么全部失败。如果deleteAll之后抛异常,则事务回滚,恢复原先被删除的数据。&/p&&p&测试一下,启动Spring Boot工程,首先调用findAll接口,看看数据库中都有哪些数据:&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-aab046be31e137c4f32dfdb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&304& data-rawheight=&400& class=&content_image& width=&304&&&/figure&&p&&br&&/p&&p&接着调用deleteAndSave接口,故意传入firstName=”Yang”,果然返回失败:&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-0e037874cdadccc8d9e6_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&298& data-rawheight=&400& class=&content_image& width=&298&&&/figure&&p&&br&&/p&&p&然后,在回过头去调用findAll接口,看看数据是不是还在:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-aab046be31e137c4f32dfdb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&304& data-rawheight=&400& class=&content_image& width=&304&&&/figure&&p&&br&&/p&&p&数据都在,说明产生事务了。&/p&&p&上面都没啥,都跟符合我们的直觉。&/p&&p&问题来了,如果我的接口是去调用一个没有加@Transactional的方法,然后这个方法再去调用加了@Transactional的方法呢?&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&deleteAllAndAddOne&/span&&span class=&o&&(&/span&&span class=&n&&Customer&/span& &span class=&n&&customer&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&out&/span&&span class=&o&&.&/span&&span class=&na&&println&/span&&span class=&o&&(&/span&&span class=&s&&&go into deleteAllAndAddOne&&/span&&span class=&o&&);&/span&
&span class=&n&&deleteAllAndAddOneTransactional&/span&&span class=&o&&(&/span&&span class=&n&&customer&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Transactional&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &sp

我要回帖

更多关于 kpi是什么意思 的文章

 

随机推荐