摘要: 不知道自己应该选用那个AI框架和库?看看本文就行了,本文为AI开发的工程师们梳理了现在最流行的框架,并简单的分析了它们的优缺点。 人工智能已经存在很长时间,然而,由于这一领域的巨大发展,近年来它已成为一个流行语。人工智能曾经被称为一个书呆子和天才领域,但由于各种库和框架的发展,它已成为一个友好的IT领域,更多的人开始了他们的人工智能之旅。 在这篇文章中,我们将研究人工智能的高质量库的优点和缺点,以及它们的一些特点。 1. TensorFlow “使用数据流图计算进行机器学习” 语言:C ++或Python。 当你进入AI时,你会听到的第一个框架之一就是Google的TensorFlow。TensorFlow是一个使用数据流图进行数值计算的开源框架。这个框架被称为具有允许在任何CPU或GPU上进行计算的架构,无论是台式机,服务器还是移动设备,另外这个框架在Python编程语言中是可用的,这也是Python大火的原因。 TensorFlow是通过称为节点的数据层进行排序,并根据获得的信息做出决定。 优点: 使用易于学习的语言(Python)。 使用计算图抽象。 可以使用可视化的TensorBoard。 缺点: 它很慢,因为Python不是编程语言中最快的。 缺乏许多预先训练的模型。 不完全开源。 2.CNTK “开源深度学习工具包”。 语言:C ++。 我们可以称之为它是微软对Google的TensorFlow的回应。 微软的CNTK是一个增强分离计算网络模块化和维护的库,它提供了学习算法和模型描述。在需要大量服务器进行操作的情况下,CNTK可以同时利用多台服务器。 据说它的功能与Google的TensorFlow相近,但是,它更快,在这里了解更多。 优点: 非常灵活。 允许分布式培训。 支持C ++,C#,Java和Python。 缺点: 它以一种新的语言——Network Description Language(NDL)来实现。 缺乏可视化。 3. Theano “数值计算库” 语言:Python。 Theano是TensorFlow的强有力竞争者,它是一个功能强大的Python库,允许以高效率的方式进行多维数组的数值操作。 该库透明地使用GPU来执行数据密集型计算而不是CPU,因此操作效率很高。出于这个原因,Theano已经被用于为大规模的计算密集型操作长达十年的时间。然而,于二零一七年九月, Theano的1.0版本停止。 但这并不意味着它不再是一个强大的图书馆,你仍然可以随时进行深入的学习研究。 优点: 优化CPU和GPU。 有效的计算任务。 缺点: 与其他库相比,原生Theano有点低级。 需要与其他库一起使用以获得高度的抽象。 AWS使用它上有点bug。 4. Caffe “快速,开放的深度学习框架” 语言:C ++。 Caffe是一个强大的深度学习框架,像这个清单上的其他框架一样,深度学习的研究速度非常快。 借助Caffe,你可以非常轻松地构建用于图像分类的卷积神经网络(CNN)。Caffe在GPU上运行的也很不错,这有助于在运行期间提高速度。 Caffe主类: 优点: Python和MATLAB都可用。 表现的很好。 无需编写代码即可进行模型的训练。 缺点: 对于RNN网络不太友好。 对于新体系结构不太友好。 5. Keras “为人类普及深度学习” 语言:Python。 Keras是一个用Python编写的开源的神经网络库。与TensorFlow,CNTK和Theano不同,Keras并不意味着是一个端到端的机器学习框架。 相反,它作为一个接口,提供了一个高层次的抽象,这使得神经网络的配置变得简单,无论它坐在哪个框架上。 谷歌的TensorFlow目前支持Keras作为后端,而微软的CNTK也会在很短的时间内做到这一点。 优点: 它对用户非常友好。 它很容易扩展。 在CPU和GPU上无缝运行。 与Theano和TensorFlow无缝工作。 缺点: 不能有效地用作独立的框架。 6.Torch “一个开源的机器学习库” 语言:C. Torch是一个用于科学和数字操作的开源机器学习库。 这是一个基于Lua编程语言的库而不是Python。 它通过提供大量的算法,使得深度学习研究更容易,并且提高了效率和速度。它有一个强大的N维数组,这有助于切片和索引等操作。它还提供了线性代数程序和神经网络模型。 优点: 非常灵活。 高水平的速度和效率。 大量的预训练模型可用。 […]
View Details今天给大家带来的分享是基于支付场景的一个微服务实战,会更偏向于应用层的内容。 主要围绕以下四点进行分享: SOA 与微服务 老支付架构遇到的挑战 基于微服务怎么做的改造 未来计划要做的事 SOA 与微服务 在我看来,微服务虽是国外传进来的技术,却和咱们中国的一些理论是挂钩的。所以在正式进入主题之前,先给大家简单介绍一下麦田理论。 关于麦田理论 古代周朝时期,老百姓种地实际是没有任何规划的,也没有任何区域的限制。 一般来说在地里一会种水稻,一会种小麦,一会种蔬菜地交叉来种,可收成之后发现庄稼受阳光程度非常低,营养非常不均衡,后期维护成本非常高。 直到战国时期,有一位农业专家把地划分为多个区域,每一个区域种一种庄稼,地跟地隔开,形成最初的微服务理念。 过去我们看到的很多文章都只是讲到 SOA 和微服务之间的比较,我今天在这个基础上加了一个 DDD。下面就 DDD、SOA 以及微服务的演进过程先做个引子。 DDD、SOA 与微服务 SOA 架构 SOA 是上一个时代的产物,大概是在 2010 年之前出现的,最早提出时是提供给传统行业计算领域的解决方案,当时 Oracle、IBM 也提了很多方案,包括出现的很多流程引擎。 它的思想是将紧耦合的系统,划分为面向业务的粗粒度、松耦合、无状态的服务。 在这之后,微服务的提出者基于 SOA 做了一个改进,就把它变成单一职责、独立部署、细小的微服务,是一个相反的概念。 微服务与 DDD 今天我们一说到微服务就会想到 DDD,有不少朋友认为 DDD 就是为微服务而生的。其实不是这样的,我在接触 DDD 时,它最早是用来做 UML 设计、领域建模的。 DDD 讲究充血模型,而 J2EE 模型以传统的分层架构和 Spring 架构捆绑在一起形成了以贫血模型为主的架构模式。 贫血模型的优点是容易入门、分层清晰,而充血模型要求设计者前期对业务理解较深,不然后期项目会产生混乱。 另外就是 DDD 思想比较宽泛,导致形成百家争鸣的姿态,没有形成一套固定的方法论。 开发者不容易理解,所以后面关注 DDD 的人变少了,而微服务的提出巧妙地借鉴了 DDD 里面的限界上下文、子域、领域事件等关键词,在微服务得到越来越多业界认可的情况下,也给 DDD 带来了重新的焕发机会。 老支付架构遇到的挑战 判断项目好坏的两个角度 我们判断一个优秀项目的好坏,可以从优秀的代码和高可用架构两个方向来讲。 我们在设计高可用架构的同时,也不能忽视代码的重要性,优秀的代码指的是冗错能力、冥等操作、并发情况、死锁情况等,并不一定是指代码写得多漂亮。 这就好比盖楼一样,楼房的基础架子搭得很好,但盖房的工人不够专业,有很多需要注意的地方忽略了,那么在往里面填砖加瓦的时候出了问题。 后果就是房子经常漏雨,墙上有裂缝等各种问题出现,虽然不至于楼房塌陷,但楼房也已经变成了危楼。 从代码和设计的角度来看有: 由不合理的代码所引起的项目无扩展性 数据库经常发生死锁 数据库事务乱用,导致事务占用时间过长 代码容错能力很差,经常因为考虑不足引起事故 程序中打印的大量的无用日志,并且引起性能问题 常用配置信息依然从数据库中读取 滥用线程池,造成栈和堆溢出 从库中查询数据,每次全部查出 业务代码研发不考虑幂等操作 使用缓存不合理,存在惊群效应、缓存穿透等情况 代码上下流流程定义混乱 异常处理机制混乱 再从整体架构角度来看: 整体依然使用单体集群架构 采用单机房服务器布署方式 采用 Nginx+hessian 的方式实现服务化 业务架构划分不彻底,边界模糊 项目拆分不彻底,一个 […]
View Details最近社区针对框架的争论,从发文互怼再到粉丝站队再到大漠穷秋准备离职,令人唏嘘不已。不知从何而起,前端圈已经逐步变成了前端娱乐圈。越来越多的人开始站队 Angular、Vue、React,仅仅围绕这些库或者框架进行前端技术讨论,这实在不是什么好的现象。其实我想基于我个人的经验聊下前端的演进和未来,希望可以贡献微薄的力量,消除一些我个人认为的前端社区不太好的风气。 注意:以下只是我个人对于前端和业务的理解和感悟,不代表任何其他人和我所在公司、团队的观点,意见不同欢迎一起讨论。 ======== 以史为鉴,想要知道前端的未来,必须知道前端的过去,抽象前端发展的规律。 前端的历史 前端的发展始终伴随着端的发展。 PC 端的兴起 06 年左右国内互联网公司开始有了前端工程师的概念,原因很简单,是因为上网访问网页的人数增多,大型互联网公司为了提升用户体验专门剥离了这样一个岗位来解决相关问题。这是第一批专业前端工程师的起源。 在这几年中的发展,进行了很多轮的技术方案、框架、浏览器的演进。比如 jQuery 兼容性库,再到 Require.js 异步加载,再到现在 React、Vue、Angular 等附带编程思想的前端库以及前后端分离、前端构建器、样式预处理器等。这些演进都是随着 PC 端的用户量的增多和业务复杂度的提升,为了用户体验和开发者体验而进化的。 移动端的兴起 09 年左右,智能手机的兴起导致了移动端开发的热潮。人人拥有智能手机,这种特殊的端的特性,也产生了新的业务形态。因此无线前端相关需求开始爆发,无线前端开发、iOS/Android 工程师等需求量非常大。 这几年中的发展,先从最初把 PC 端页面放在手机上渲染,再到出来响应式设计的概念,再到专门做无线端页面,再到独立客户端和 Weex、React Native 这些跨终端的方案。也是出现了非常多的技术演进,这些演进不难看出也是因为用户量的增多和业务复杂度的提升,为了用户体验和开发者体验而进行优化的。 PC 端的衰落 14 年左右,其实 PC 端颓废之势早已显现,但在双十一下被放大。因此阿里系前端在这个时间点附近就开始弱化 PC 端前端的投入。 以前 PC 端业务,在无线端流量更大的直接被下掉,核心链路的 PC 端业务能用就可以了,不再做效果、功能迭代优化。甚至很多业务直接不做 PC 端只做无线端。业务指标也从 PC 的 PV、UV 变成了客户端的 DAU 等指标。 在这个时间,只做 PC 端的前端,毫无无线端经验的前端,将会慢慢丧失竞争力。PC 兼容库 jQuery 之流也渐渐被替换废弃,因为 PC 的业务很少花费精力做兼容性测试,甚至目前我们团队的业务从来都只测试最新版 Chrome。可以看到,随着端和业务形态的变化,很多前端演进的产物会逐步被替换废掉。 移动端的衰落 移动端目前还没有衰落,但一个端只要兴起,就会有衰落的时候。总会有新的、更好的、更高效的端来替代老的端。但这个时机是难以预测的。 前端的未来 回顾前端的历史,前端总是伴随的端的变化而变化: 端的出现 -> 业务场景的落地 -> 需要端的开发者 -> 端开发者学习、演进 -> 端的开发效率提升 -> 新的端出现 -> 端的没落 -> 端开发者转领域或者被淘汰 这也就是为什么前端需要学习这么多东西,有这么庞大的体系的原因。每一个端都有它自己的特性。比如未来可能会火的 VR、AR 端,它们的特性就不同于二维平面的移动端,掌握 VR、AR 端的开发就需要新学习很多三维图形图像以及图像识别领域的东西。 因此如果你想要知道前端的未来,你需要预测端的发展。但端的发展是很难预测的,回到 06 年,有谁会想到会有智能手机,并开创了移动端这个端? 而现在火热的 […]
View DetailsAOP 概述 面向切面编程(aspect-oriented programming),是一种将横切关注点与业务逻辑分离的编程方式。每个横切关注点都集中在一个地方,而不是分散在多处代码中。这样使我们的服务模块更加简洁,因为它们只包含了主要关注点的代码,而次要的功能或者说辅助的功能被转移到切面中了。 aop-1.png 上图表示划分为三个服务模块的应用,每个模块提供相应的服务,而且这些模块都需要类似的辅助功能,例如日志、安全、事务等等。我们并不想在各个模块中写重复的日志、安全、事务的代码,那么就可以使用选用切面这个方案,来解决这个问题。 AOP 术语 aop-2.png advice – 通知 切面的具体行为,即要切入执行的代码 pointcut – 切点 通知被应用的具体位置 join point – 连接点 程序运行时,能够应用通知的所有点 aspect – 切面 什么时候在什么地方做什么事情,是切点和通知的结合 target – 目标对象 被切入功能的目标对象 introduction – 引入 将新的方法或属性引入到现有的类中 weaving – 织入 把切面应用到目标对象并创建新的代理对象的过程 代理模式 代理模式是使用代理对象完成用户请求,屏蔽用户对真实对象访问的一种设计模式。现实生活中,代理人被授权执行当事人的一些事宜,无需当事人出面,从第三方的角度看,他只和代理人通信。而事实上代理人是要有当事人的授权,并且在核心问题上还需要请示当事人。 AOP 就是使用代理模式实现的,其中的代理类就相当于AOP中的切面。 aop-3.png 静态代理 之所以称为静态代理,是因为在程序运行前,代理类就已经存在了。 举个例子 一般艺人都需要助理,来帮他跑腿,演出前谈价格,演出后收钱,只有表演的时候艺人才亲自出马。 定义一个艺人接口
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package org.nocoder.proxy.staticproxy; /** * 艺人接口 * @author jason * @date 2019/2/14. */ public interface Artist { /** * 表演 */ void perform(); } |
定义艺人实现类刘德华
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package org.nocoder.proxy.staticproxy; /** * 艺人刘德华 * * @author jason * @date 2019/2/14. */ public class LiuDehua implements Artist { private LiuDehua() { } public static LiuDehua getInstance() { return new LiuDehua(); } public void perform() { System.out.println("刘德华出场演唱笨小孩..."); } } |
编写代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package org.nocoder.proxy.staticproxy; /** * 艺人助理(代理类) * * @author jason * @date 2019/2/14. */ public class ArtistProxy implements Artist { private LiuDehua liuDehua; private ArtistProxy() { } public ArtistProxy(LiuDehua liuDehua) { this.liuDehua = liuDehua; } public void perform() { System.out.println("助理出面谈价格,签合同..."); liuDehua.perform(); System.out.println("助理出面收钱..."); } } |
运行main方法,将艺人实例传入代理类的构造方法,然后调用代理类的perform()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package org.nocoder.proxy.staticproxy; /** * @author jason * @date 2019/2/14. */ public class StaticProxyDemo { public static void main(String[] args) { LiuDehua liuDehua = LiuDehua.getInstance(); ArtistProxy proxy = new ArtistProxy(liuDehua); proxy.perform(); } } |
运行结果
1 2 3 4 5 |
助理出面谈价格,签合同... 刘德华出场演唱笨小孩... 助理出面收钱... Process finished with exit code 0 |
静态代理的缺点 假设主题接口中的方法很多,为每一个接口写一个代理方法也很麻烦。如果接口有变动,则真实主题和代理类都要修改,不利于系统维护; 动态代理 动态代理是在程序运行时,利用Java反射机制动态的生成代理类的代理模式。 Jdk动态代理 JDK的动态代理依靠接口实现 如果类并没有实现接口,则不能使用Jdk的动态代理 定义图书服务接口
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package org.nocoder.proxy.jdkproxy; /** * 图书服务接口 * @author jason * @date 2019/2/14. */ public interface BookService { /** * 新增图书接口 */ void addBook(); } |
编写图书服务实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package org.nocoder.proxy.jdkproxy; /** * 图书服务实现类 * @author jason * @date 2019/2/14. */ public class BookServiceImpl implements BookService { @Override public void addBook() { System.out.println("新增图书"); } } |
编写InvocationHandler实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package org.nocoder.proxy.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * JDK 动态代理 * @author jason * @date 2019/2/14. */ public class BookServiceInvocationHandler implements InvocationHandler { private Object target; public BookServiceInvocationHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("事务开始"); Object result = method.invoke(target, args); System.out.println("事务结束"); return result; } } |
运行测试程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package org.nocoder.proxy.jdkproxy; import java.lang.reflect.Proxy; /** * JDK动态代理演示 * * @author jason * @date 2019/2/14. */ public class JdkProxyDemo { public static void main(String[] args) { BookServiceInvocationHandler invocationHandler = new BookServiceInvocationHandler(new BookServiceImpl()); // JDK 动态代理只支持接口 BookService bookServiceProxy = (BookService) Proxy.newProxyInstance( BookServiceImpl.class.getClassLoader(), BookServiceImpl.class.getInterfaces(), invocationHandler); bookServiceProxy.addBook(); } } |
运行结果
1 2 3 4 5 |
事务开始 新增图书 事务结束 Process finished with exit code 0 |
CGLIB动态代理 JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这时就要使用cglib动态代理了。使用cglib需要依赖cglib的jar,使用maven为例
1 2 3 4 5 |
<dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.2.4</version> </dependency> |
定义图书服务类
1 2 3 4 5 6 7 8 9 10 11 |
package org.nocoder.proxy.cglibproxy; /** * @author jason * @date 2019/2/14. */ public class BookService { public void addBook() { System.out.println("新增图书"); } } |
编写MethodInterceptor实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package org.nocoder.proxy.cglibproxy; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author jason * @date 2019/2/14. */ public class BookServiceMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("事务开始"); methodProxy.invokeSuper(o, objects); System.out.println("事务结束"); return null; } } |
运行测试程序 […]
View Details