Facebook开源深度学习框架Torchnet与谷歌TensorFlow有何不同

Facebook今天宣布开源深度学习框架 Torchnet。Torchnet 基于广泛使用的开源深度学习框架 Torch 7 搭建,支持模块化编程方法,能减少程序员工作量、降低错误率,简化深度学习模型训练过程。相比其他巨头自己搭建的深度学习框架,Torchnet 更加开放,也将大幅推进深度学习的应用普及。

Facebook开源深度学习框架Torchnet与谷歌TensorFlow有何不同

2016年6月24日,Facebook 宣布开源深度学习框架 Torchnet,简化研究和开发人员建立深度学习系统过程。

深度学习是当下一种时髦的学习方式,涉及到培训人工神经网络处理大量的数据,如图片,然后让神经网络做出新数据的预测。与其建立一个全新的深度学习框架, Facebook 选择的是在 Torch 上编译一个开源库,Facebook 先前也曾致力于此。

“这使得它很容易实现完全隐藏 I/O(输入 / 输出)成本功能,而如果你想创建一个实用的大型深度学习系统,你就很需要这项功能的。” Facebook 人工智能研究所(FAIR)的一名科学家 Laurens van der Maaten 在一次采访中这样说道,“我们并不是要让 Torch 运作的更快或者更慢或者其他怎样,这些都不是框架的重点所在。” van der Maaten 还表示,Torchnet 是用 Lua 脚本语言写成,能够在标准的 x86 芯片或图形处理单元(GPUs)上运行,也可以让程序员重用某些代码。这样一来就能够降低工作量,同时也可以降低出现 bug 的几率。

Facebook 并不是唯一一家为 Torch 编译工具的公司,Twitter 也这样做过,可以肯定的是,同 van der Maaten 聊过的一些 Twitter 的员工似乎也对 Torchnet 感兴趣。亚马逊、谷歌和微软也在近几个月发布了全新的深度学习框架,Facebook 之前一直致力于开发原生开源项目,如 React Native 和 Presto,所以现在 Facebook 做出一些改变看上去还是挺有意思的。

van der Maaten 说道:“这种方法同 Theano 框架的 Blocks and Fuel 库有点相似。”

在这份报告中,van der Maaten 写道:Torchnet 可能并不会一直局限在 Torch 上使用,Torchnet 是抽象的,可以轻松应用到其他框架中,例如 Caffe 还有谷歌的 TensorFlow 框架。

Facebook开源深度学习框架Torchnet与谷歌TensorFlow有何不同

在六、七个月前,Facebook 发布了 Torchnet 的第一版本。van der Maaten 说道:“现在有许多团队在不同应用中使用这一版本。” 他没有说具体是 Facebook 的哪些工作依赖于 Torchnet,但它可以被应用到图像识别和自然语言处理等方面,这样一来便可以在一些事情上派上用场,例如找到相关的 Instagram 图片来为 News Feed 选择最佳 Facebook 帖子。Facebook 希望它的内容能够比网络上的其他内容都更具吸引力,这样既可以留住 “回头客” 又能够吸引新用户,所以这是很重要的东西。

Torchnet 以目前广泛使用的深度学习框架 Torch 7 为基础,采用 Lua 语言编写,可以在 CPU 和 GPU 上运行,支持代码复用,从而减少程序员工作量,降低程序运行的错误率。

Facebook人工智能研究实验室的研究科学家 Laurens van der Maaten 告诉 VentureBeat,Torchnet 主要目的并非为了加快 Torch 运行速度,而是免去输入/输出的成本(cost)。

如今,越来越多的企业都开始使用深度学习,而在训练用于解决实际问题的大规模深度学习系统时,输入/输出成本是非常现实而且经常会遇到的问题。因此,可以预计 Torchnet 将极大推动深度学习应用的普及。

点亮深度学习之路

Facebook 的 3 位研究员在官方博客中比较详细地介绍了 Torchnet。据悉,Torchnet 是 Facebook 于刚刚结束的 ICML 2016 大会上介绍的一款开源的新型深度学习软件包,为了帮助研究和开发人员在 Torch 上建立快速的、可复用的学习系统原型而推出。

虽然 Torch 已经是比较成功的深度机器学习研究框架,但它不为机器学习实验提供抽象概念和样本代码,导致开发人员需要进行大量重复编程工作。这样会造成错误重现,可能得出不正确的研究结论,减慢开发的整体进度。Torchnet 能指引研究者建立清晰编程框架,而样本代码能帮助他们加速开发进程。

Torchnet  提供了基本概念和代码集,包括样本代码(boilerplate code)、关键抽象概念(key abstractions)和参考执行代码(reference implementations)。这些概念和代码集可以被灵活组合或拆开,并在后续开发中重复使用。其中,还有一个重要的子程序包,含有计算视觉、自然语言处理和语音处理等与机器学习有关的样本代码实现。

Facebook开源深度学习框架Torchnet与谷歌TensorFlow有何不同

Torchnet 的总体设计就像乐高,程序块都按照一定的规则设计,很容易组合在一起,所有组合在一起的模块构成了一个统一的系统。在这个系统中,各个组件紧密相连又能相互取代。

Torchnet 的模块化设计使数据集测试、数据加载过程和模型、性能评估等衍生程序测试更加容易,从而加快实验速度。借助 Torchnet,在不同的数据集上运行相同的实验,就跟插入不同的(基本)数据加载器一样简单,改变评估标准只用改变一行代码就能实现(插入不同的性能指示器)。

Facebook 研究员在博文中写道,开源 Torchnet 是为了促进 Torch 开发社区相互交流,让大家共同打造更加高效的深度学习模型。

Torchnet > TensorFlow

继谷歌、微软、亚马逊等巨头之后,Facebook 也终于来到开源深度学习平台的竞技场。Torchnet 的表现会如何?看看它和谷歌的 TensorFlow 有什么不同。

Facebook开源深度学习框架Torchnet与谷歌TensorFlow有何不同

首先,Torchnet 并不关注提升深度神经网络的推理计算和梯度计算性能,而是为了便于研究人员更加便捷地进行机器学习实验或设计相关工具(主要以插件的方式)。如果说谷歌的分布式 TensorFlow 3 天训练一个模型,是高手过招的竞技场,那么 Torchnet 则是将训练深度学习模型的门槛连降 3 级。

此外,TensorFlow 原本是谷歌内部研发的产品,后来变成开源。而 Torchnet 则一开始就 以开源深度学习框架 Torch 7 为基础。虽然目前 TensorFlow 吸引了很多开发者,但 Torch 有着非常活跃的开发者用户群,再加上门槛低,Torchnet 的使用人数反超 TensorFlow 也并非不无可能。

最后,Torchnet 并不局限于 Torch,还可以应用于其他框架,比如 Caffe 和谷歌的 TensorFlow。

名称
支持平台 语言 界面 训练好的模型
TensorFlow Linux, Mac OS,

Windows roadmap

C++, Phython Phython, C/C++
Torchnet Linux, iOS, Android, Mac OS X C, Lua C, Lua, LuaJIT,

utility libaray for OpenCL/C++

深度学习迈入商业应用

虽然近来深度学习广受关注、引领技术潮流,但真正使用深度学习的应用还在少数。

对于任何产业而言,规模或者普及程度都是至关重要的,起着决定性的作用。没有足够大的规模,就无法建立基础设施、商业模式、培养用户、形成市场……也正因此,Facebook 才开源 Torchnet。

这跟此前巨头掀起的“开源”浪潮不同,Facebook 并不是开源公司内部的一个平台,Torchnet 是真正的公开,不仅仅是为了吸引更多开发者,最重要的目的是降低门槛,让更多人使用深度学习技术,扩大产业整体的市场规模。

【本文综合自新智元和36氪】

氧分子网(www.yangfenzi.com)是关注互联网生态圈的科技新媒体

·氧分子网(http://www.yangfenzi.com)延伸阅读:

Facebook深度学习专家:未来的人工智能是怎样
可编程门阵列FPGA:深度学习的未来?
科大讯飞刘庆峰:人工智能全球决战未来十年
地平线机器人李星宇:复杂的中国驾驶场景,正是深度学习的优势
深度学习会让机器学习工程师失业吗?
【nature】深度学习巨头看人工智能界人才迁徙
百度吴恩达谈深度学习局限:AI经济价值目前仅来自监督学习
出门问问李志飞:一个硅谷工程师在中国的 AI 创业“实践论”
《自然》论文详解:AlphaGo 背后的深度神经网络和树搜索

您可能还喜欢…

4 Responses

  1. 深度学习大新闻:谷歌 Tensorflow 选择 Keras说道:

    Keras 的作者、谷歌 AI 研究员 Francois Chollet 宣布了一条激动人心的消息:Keras 将会成为第一个被添加到 TensorFlow 核心中的高级别框架,这将会让Keras 变成 Tensorflow 的默认 API。

    在 Reddit 的一条评论中,Keras 的作者、谷歌 AI 研究员 Francois Chollet 宣布了一条激动人心的消息:Keras 将会成为第一个被添加到 TensorFlow 核心中的高级别框架,这将会让 Keras 变成 Tensorflow 的默认 API。

    背景介绍:Keras 是一个高级别的 Python 神经网络框架,能在 TensorFlow 或者 Theano 上运行。此外,能用到 TensorFlow 上的还有一些高级别的 Python 神经网络框架,比如,TF-Slim,虽然它们发展更不完善,也不是 TensorFlow 的核心部分。

    神经网络研究者 Rachel Thomas 在 fast.ai 上撰文介绍了这一消息,并写下了他使用TensorFlow 的心得体会:

    他说,使用 TensorFlow 给我的感觉就是我还不够聪明,但是,在使用 Keras 的时候我会觉得神经网络要比我想象的简单。这是因为,TensorFlow 的 API 过于冗长和混乱,也是因为 Keras 拥有我体验过的最贴心的、最具表达力的 API。对我来说,在刚开始使用TensorFlow 受挫后就来公开批评它有点尴尬,它让人觉得沉重、不自然。当然,其中有我自己的原因。但是,Keras 和 Theano 确实证实了我的想法:tensors 和 神经网络不一定都是那么折磨人的。

    在一次大学作业中,我曾经使用一个硬件描述语言,通过添加和改变 CPU 暂存器中的字节来编码除法(division)。这是一个很有趣的练习,但是我非常确定,我不想用这种方式对神经网络进行编码。使用一个更高级别的语言的好处是显而易见的:更快地编码、更少的bug,以及,更少的痛苦。Keras 的好处还有更多——它更适配神经网络的概念,能促进新的发现。Keras 让我更加擅长神经网络,因为语言抽象与神经网络的概念搭配得更加好。

    使用与我的思维相同的概念语言写程序,能让我把注意力集中在需要解决的难题上,而不是编程语言的伪迹上。因为,当我把更多的精力花在头脑中的思维与编程语言之间的概念转换的时候,我的思考就会变慢。TensorFlow 影响了我的生产力。

    正如 Chollet 所写:“如果你想要长期使用一个更高级别的面向对象的 TF API ,Karas 就是正确的道路。”

  2. 深入浅出Tensorflow:深度学习及Google深度学习框架说道:

    在国内,从InfoQ的判断来看,TensorFlow仍处于创新传播曲线的创新者使用阶段,大部分人对于TensorFlow还缺乏了解,社区也缺少帮助落地和使用的中文资料。InfoQ期望通过深入浅出TensorFlow系列文章能够推动Tensorflow在国内的发展。本文是整个系列的第一篇文章,将会介绍深度学习的发展历史以及深度学习目前成熟的应用,同时也会介绍目前主流的深度学习工具,以及TensorFlow相比于其他工具的优势。

    从计算机发明之初,人们就希望它能够帮助甚至代替人类完成重复性劳作。利用巨大的存储空间和超高的运算速度,计算机已经可以非常轻易地完成一些对于人类非常困难,但对计算机相对简单的问题。比如统计一本书中不同单词出现的次数,存储一个图书馆中所有的藏书或是计算非常复杂的数学公式都可以轻松通过计算机解决。然而,一些人类通过直觉可以很快解决的问题,目前却很难通过计算机解决。人工智能领域需要解决的问题就是让计算机能像人类一样,甚至超越人类完成类似图像识别、语音识别等问题。

    计算机要像人类一样完成更多智能的工作需要够掌握人类的经验。比如我们需要判断一封邮件是否为垃圾邮件,会综合考虑邮件发出的地址、邮件的标题、邮件的内容以及邮件收件人的长度,等等。这是我们受到无数垃圾邮件骚扰之后总结出来的经验。这个经验很难以固定的方式表达出来,而且不同人对垃圾邮件的判断也会不一样。如何让计算机可以跟人类一样从历史的经验中获取新的知识呢?这就是机器学习需要解决的问题。

    什么是机器学习?

    卡内基梅隆大学(Carnegie Mellon University)的Tom Michael Mitchell教授在1997年出版的书籍Machine Learning中有对机器学习进行非常专业的定义,这个定义在学术界内被多次引用。在这本书中对机器学习的定义为“如果一个程序可以在任务T上,随着经验E的增加,效果P也可以随之增加,则我们称这个程序可以从经验中学习”。让我们通过垃圾邮件分类的问题来解释机器学习的定义。在垃圾邮件分类问题中,“一个程序”指的是需要用到的机器学习算法,比如逻辑回归算法;“任务T”是指区分垃圾邮件的任务;“经验E”为已经区分过是否为垃圾邮件的历史邮件,在监督式机器学习问题中,这也被称之为训练数据,也就是说对于机器学习而言,所谓的经验其实就是数据;“效果P”为机器学习算法在区分是否为垃圾邮件任务上的正确率。

    在使用逻辑回归算法解决垃圾邮件分类问题时,我们会先从每一封邮件中抽取对分类结果可能有影响的因素,比如说上文提到的发邮件的地址、邮件的标题及收件人的长度,等等。每一个因素被称之为一个特征(feature)。逻辑回归算法可以从训练数据中计算出每个特征和预测结果的相关度。比如在垃圾邮件分类问题中,我们可能会发现如果一个邮件的收件人越多,那么邮件为垃圾邮件的概率也就越高。在对一封未知的邮件做判断时,逻辑回归算法会根据从这封邮件中抽取得到的每一个特征以及这些特征和垃圾邮件的相关度来判断这封邮件是否为垃圾邮件。

    在大部分情况下,在训练数据达到一定数量之前,越多的训练数据可以使逻辑回归算法对未知邮件做出的判断越精准。也就是说逻辑回归算法可以根据训练数据(经验E)提高在垃圾邮件分类问题(任务T)上的正确率(效果P)。之所以说在大部分情况下,是因为逻辑回归算法的效果除了依赖于训练数据,也依赖于从数据中提取的特征。假设我们从邮件中抽取的特征只有邮件发送的时间,那么即使有再多的训练数据,逻辑回归算法也无法很好地利用。这是因为邮件发送的时间和邮件是否为垃圾邮件之间的关联不大,而逻辑回归算法无法从数据中习得更好的特征表达。这也是很多传统机器学习算法的一个共同的问题。

    什么是深度学习?

    对许多机器学习问题来说,特征提取不是一件简单的事情。在一些复杂问题上,要通过人工的方式设计有效的特征集合需要很多的时间和精力,有时甚至需要整个领域数十年的研究投入。例如,假设想从很多照片中识别汽车。现在已知的是汽车有轮子,所以希望在图片中抽取“图片中是否出现了轮子”这个特征。但实际上,要从图片的像素中描述一个轮子的模式是非常难的。虽然车轮的形状很简单,但在实际图片中,车轮上可能会有来自车身的阴影、金属车轴的反光,周围物品也可能会部分遮挡车轮。实际图片中各种不确定的因素让我们很难直接抽取这样的特征。

    深度学习解决的核心问题之一就是自动地将简单的特征组合成更加复杂的特征,并使用这些组合特征解决问题。深度学习是机器学习的一个分支,它除了可以学习特征和任务之间的关联以外,还能自动从简单特征中提取更加复杂的特征。图1中展示了深度学习和传统机器学习在流程上的差异。如图1所示,深度学习算法可以从数据中学习更加复杂的特征表达,使得最后一步权重学习变得更加简单且有效。在图2中,展示了通过深度学习解决图像分类问题的具体样例。深度学习可以一层一层地将简单特征逐步转化成更加复杂的特征,从而使得不同类别的图像更加可分。比如图2中展示了深度学习算法可以从图像的像素特征中逐渐组合出线条、边、角、简单形状、复杂形状等更加有效的复杂特征。

    人工智能、机器学习和深度学习的关系

    总的来说,人工智能、机器学习和深度学习是非常相关的几个领域。图3总结了它们之间的关系。人工智能是一类非常广泛的问题,机器学习是解决这类问题的一个重要手段,深度学习则是机器学习的一个分支。在很多人工智能问题上,深度学习的方法突破了传统机器学习方法的瓶颈,推动了人工智能领域的发展。

    图4展示了“deep learning”(深度学习)这个词在最近十年谷歌搜索的热度趋势。从图中可以看出,从2012年之后,深度学习的热度呈指数上升,到2016年时,深度学习已经成为了谷歌上最热门的搜索词。深度学习这个词并不是最近才创造出来的,它基本就是深层神经网络的代名词。受到人类大脑结构的启发,神经网络的计算模型于1943年首次提出。之后感知机的发明使得神经网络成为真正可以从数据中“学习”的模型。但由于感知机的网络结构过于简单,导致无法解决线性不可分问题。再加上神经网络所需要的计算量太大,当时的计算机无法满足计算需求,使得神经网络的研究进入了第一个寒冬。

    到20世纪80年代,深层神经网络和反向传播算法的提出很好地解决了这些问题,让神经网络进入第二个快速发展期。不过,在这一时期中,以支持向量机为主的传统机器学习算法也在飞速发展。在90年代中期,在很多机器学习任务上,传统机器学习算法超越了神经网络的精确度,使得神经网络领域再次进入寒冬。直到2012年前后,随着云计算和海量数据的普及,神经网络以“深度学习”的名字再次进入大家的视野。2012年,深度学习算法AlexNet赢得图像分类比赛ILSVRC(ImageNet Large Scale Visual Recognition Challenge)冠军,深度学习从此开始受到学术界广泛的关注。

    深度学习的应用

    图5展示了历年ILSVRC比赛的情况,从图中可以看到,在深度学习被使用之前,传统计算机视觉的方法在ImageNet数据集上最低的Top5错误率为26%。从2010年到2011年,基于传统机器学习的算法并没有带来正确率的大幅提升。在2012年时,Geoffrey Everest Hinton教授的研究小组利用深度学习技术将ImageNet图像分类的错误率大幅下降到了16%。而且,从2012年到2015年间,通过对深度学习算法的不断研究,ImageNet图像分类的错误率以每年4%的速度递减。这说明深度学习完全打破了传统机器学习算法在图像分类上的瓶颈,让图像分类问题得到了更好的解决。如图5所示,到2015年时,深度学习算法的错误率为4%,已经成功超越了人工标注的错误率(5%),实现了计算机视觉研究领域的一个突破。

    在技术革新的同时,工业界也将图像分类、物体识别应用于各种产品中了。在谷歌,图像分类、物体识别技术已经被广泛应用于谷歌无人驾驶车、YouTube、谷歌地图、谷歌图像搜索等产品中。谷歌通过图像处理技术可以归纳出图片中的主要内容并实现以图搜图的功能。这些技术在国内的百度、阿里、腾讯等科技公司也已经得到了广泛的应用。

    在物体识别问题中,人脸识别是一类应用非常广泛的技术。它既可以应用于娱乐行业,也可以应用于安防、风控行业。在娱乐行业中,基于人脸识别的相机自动对焦、自动美颜基本已经成为每一款自拍软件的必备功能。在安防、风控领域,人脸识别应用更是大大提高了工作效率并节省了人力成本。比如在互联网金融行业,为了控制贷款风险,在用户注册或者贷款发放时需要验证本人信息。个人信息验证中一个很重要的步骤是验证用户提供的证件和用户是同一个人。通过人脸识别技术,这个过程可以被更加高效地实现。

    深度学习在语音识别领域取得的成绩也是突破性的。2009年深度学习的概念被引入语音识别领域,并对该领域产生了巨大的影响。在短短几年时间内,深度学习的方法在TIMIT数据集上将基于传统的混合高斯模型(gaussian mixture model,GMM)的错误率从21.7%降低到了使用深度学习模型的17.9%。如此大的提高幅度很快引起了学术界和工业界的广泛关注。从2010年到2014年间,在语音识别领域的两大学术会议IEEE-ICASSP和Interspeech上,深度学习的文章呈现出逐年递增的趋势。在工业界,包括谷歌、苹果、微软、IBM、百度等在内的国内外大型IT公司提供的语音相关产品,比如谷歌的Google Now,苹果的Siri、微软的Xbox和Skype等,都是基于深度学习算法。

    深度学习在自然语言处理领域的应用也同样广泛。在过去的几年中,深度学习已经在语言模型(language modeling)、机器翻译、词性标注(part-of-speech tagging)、实体识别(named entity recognition,NER)、情感分析(sentiment analysis)、广告推荐以及搜索排序等问题上取得了突出成就。在机器翻译问题上,根据谷歌的实验结果,在主要的语言对上,使用深度学习可以将机器翻译算法的质量提高55%到85%。表1对比了不同算法翻译同一句话的结果。从表中可以直观地看到深度学习算法带来翻译质量的提高。在2016年9月,谷歌正式上线了基于深度学习的中译英软件。现在在谷歌翻译产品中,所有从中文到英文的翻译请求都是由基于深度学习的翻译算法完成的。

    TensorFlow:来自Google的深度学习框架

    要将深度学习更快且更便捷地应用于新的问题中,选择一款深度学习工具是必不可少的步骤。
    TensorFlow是谷歌于2015年11月9日正式开源的计算框架。TensorFlow计算框架可以很好地支持深度学习的各种算法,但它的应用也不限于深度学习。

    TensorFlow是由Jeff Dean领头的谷歌大脑团队基于谷歌内部第一代深度学习系统DistBelief改进而来的通用计算框架。DistBelief是谷歌2011年开发的内部深度学习工具,这个工具在谷歌内部已经获得了巨大的成功。

    基于DistBelief的ImageNet图像分类系统Inception模型赢得了ImageNet2014年的比赛(ILSVRC)。通过DistBelief,谷歌在海量的非标注YouTube视屏中习得了“猫”的概念,并在谷歌图片中开创了图片搜索的功能。使用DistBelief训练的语音识别模型成功将语音识别的错误率降低了25%。在一次BBC采访中,当时的谷歌首席执行官Eric Schmidt表示这个提高比率相当于之前十年的总和。

    虽然DistBelief已经被谷歌内部很多产品所使用,但是DistBelief过于依赖谷歌内部的系统架构,很难对外开源。为了将这样一个在谷歌内部已经获得了巨大成功的系统开源,谷歌大脑团队对DistBelief进行了改进,并于2015年11月正式公布了基于Apache 2.0开源协议的计算框架TensorFlow。相比DistBelief,TensorFlow的计算模型更加通用、计算速度更快、支持的计算平台更多、支持的深度学习算法更广而且系统的稳定性也更高。关于TensorFlow平台本身的技术细节可以参考谷歌的论文TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems。

    如今在谷歌内部,TensorFlow已经得到了广泛的应用。在2015年10月26日,谷歌正式宣布通过TensorFlow实现的排序系统RankBrain上线。相比一些传统的排序算法,使用RankBrain的排序结果更能满足用户需求。在2015年彭博(Bloomberg)的报道中,谷歌透露了在谷歌上千种排序算法中,RankBrain是第三重要的排序算法。基于TensorFlow的系统RankBrain能在谷歌的核心网页搜索业务中占据如此重要的地位,可见TensorFlow在谷歌内部的重要性。包括网页搜索在内,TensorFlow已经被成功应用到了谷歌的各款产品之中。如今,在谷歌的语音搜索、广告、电商、图片、街景图、翻译、YouTube等众多产品之中都可以看到基于TensorFlow的系统。在经过半年的尝试和思考之后,谷歌的DeepMind团队也正式宣布其之后所有的研究都将使用TensorFlow作为实现深度学习算法的工具。

    除了在谷歌内部大规模使用之外,TensorFlow也受到了工业界和学术界的广泛关注。在Google I/O 2016的大会上,Jeff Dean提到已经有1500多个GitHub的代码库中提到了TensorFlow,而只有5个是谷歌官方提供的。如今,包括优步(Uber)、Snapchat、Twitter、京东、小米等国内外科技公司也纷纷加入了使用TensorFlow的行列。正如谷歌在TensorFlow开源原因中所提到的一样,TensorFlow正在建立一个标准,使得学术界可以更方便地交流学术研究成果,工业界可以更快地将机器学习应用于生产之中。

    其他已开源的深度学习工具

    除了TensorFlow,目前还有一些主流的深度学习开源工具。笔者认为,不同的深度学习工具都在发展之中,比较当前的性能、功能固然是选择工具的一种方法,但更加重要的是比较不同工具的发展趋势。深度学习本身就是一个处于蓬勃发展阶段的领域,所以对深度学习工具的选择,笔者认为应该更加看重工具在开源社区的活跃程度。只有社区活跃度更高的工具,才有可能跟上深度学习本身的发展速度,从而在未来不会面临被淘汰的风险。

    图6 不同深度学习工具在GitHub上活跃程度对比图,图中数据获取的时间为2016年11月17日
    图6对比了不同深度学习工具在GitHub上活跃程度的一些指标。图6(a)中比较了不同工具在GitHub上受关注的程度。从图中可以看出,无论是在获得的星数(star)还是在仓库被复制的次数上,TensorFlow都要远远超过其他的深度学习工具。如果说图6(a)只能代表不同深度学习工具在社区受关注程度,那么图6(b)对比了不同深度学习工具社区参与度。图6(b)中展示了不同深度学习工具在GitHub上最近一个月的活跃讨论贴和代码提交请求数量。活跃讨论帖越多,可以说明真正使用这个工具的人也就越多;提交代码请求数量越多,可以说明参与到开发这个工具的人也就越多。从图6(b)中可以看出,无论从哪个指标,TensorFlow都要远远超过其他深度学习工具。大量的活跃开发者再加上谷歌的全力支持,笔者相信TensorFlow在未来将有更大的潜力。

    本文内容来自作者图书作品《TensorFlow:实战Google深度学习框架》

    作者介绍:郑泽宇,才云首席大数据科学家,前谷歌高级工程师。从 2013 年加入谷歌至今,郑泽宇作为主要技术人员参与并领导了多个大数据项目,拥有丰富机器学习、数据挖掘工业界及科研项目经验。2014 年,他提出产品聚类项目用于衔接谷歌购物和谷歌知识图谱(Knowledge Graph)数据,使得知识卡片形式的广告逐步取代传统的产品列表广告,开启了谷歌购物广告在搜索页面投递的新纪元。他于2013 年 5 月获得美国 Carnegie Mellon University(CMU)大学计算机硕士学位, 期间在顶级国际学术会议上发表数篇学术论文,并获得西贝尔奖学金。

  3. 【PyTorch 挑战 TensorFlow】28303 篇 arXiv 论文看深度学习 6 大趋势说道:

    本文由 Andrej Karpathy撰写,他前不久加入了特斯拉,担任AI 负责人。本文是他在 OpenAI 担任研究员期间所写,陈述了他通过分析机器学习论文数据库arxiv-sanity里面的28303篇论文里面的高频关键词所发现的有趣的结论。

    你是否用过谷歌趋势(Google Trends)(https://trends.google.com/trends/?cat=)呢?它的功能很酷:只需要输入关键词,就可以看到该词的搜索量随时间变化的情况。这个产品在一定程度上启发了我,恰巧我有在过去五年中发表在(arxiv)机器学习论文数据库(http://arxiv-sanity.com/)上的28303篇论文,所以我想,为什么不研究一下该领域发展变化的情况呢?研究结果相当有趣,所以我决定跟大家分享一下。
    (注:机器学习是一个包罗万象的领域,本文中相当长的篇幅是对深度学习领域的研究,这也是我最为熟悉的领域)

    arXiv 的奇点

    让我们先来看看提交到arxiv-sanity的所有分类(cs.AI, cs.LG, cs.CV, cs.CL, cs.NE, stat.ML)下的论文总数随时间变化的趋势,如下图所示:

    没错,峰值位于2017年3月,这个月这些领域有近2000篇论文提交。这一峰值很可能是某些会议的截稿日期(例如NIPS/ICML)造成的。由于并不是所有人都会将他们的论文上传至arxiv,而且上传比例也在随时间变化而变化,所提交的论文数量并不能完全体现机器学习这一领域的研究规模。不过可以看到,有大量的论文为人所注意、浏览或者阅读。

    接下来,我们用这一数字作为分母,看看多少文章包含我们感兴趣的关键词。
    深度学习框架

    首先,我们关心的是深度学习框架的使用情况。如果在文中任何地方有提到深度学习框架,包括参考书目,都会被记录在案。下图是在2017年3月提交的论文中提到深度学习框架的情况:

    可见2017年3月提交的论文中有约10%提到了TensorFlow。当然不是每篇文章都会写出他们所用的框架,不过如果我们假定提及与否和框架类型无关(即说明框架的文章有相对确定的使用比例)的话,可以推断出该社区大约有40%的用户正在使用TensorFlow(如果算上带TensorFlow后端的Keras框架,数量会更多)。下图是一些常用框架随时间变化的趋势图:

    我们可以看到,Theano在很长时间占据主流,后来不再流行;2014年Caffe的发展势头强劲,不过在最近几个月内被TensorFlow取代;Torch(和最近的PyTorch)同样在缓慢稳步发展。它们未来发展的状况会是怎样呢?这是一个有趣的话题,个人认为Caffe和Theano会继续下降,TensorFlow的发展速度则会因为PyTorch的竞争而放缓。

    ConvNet 模型

    常用的ConvNet模型的使用情况又是怎样呢?我们可以在下图看到,ResNets模型异军突起,该模型出现在去年3月发表的9%的论文中。

    另外,我很好奇在InceptionNet出现之前有谁在讨论inception呢?

    优化算法

    优化算法方面,Adam一枝独秀,在所有论文中的出现率高达23%!其真正的使用率很难统计,估计会比23%更高,因为很多论文并没有写出他们所使用的优化算法,况且很多关于神经网络的研究并不使用任何此类算法。然而也有可能要下调5%,因为这个词也非常可能是指代作者的名字,而Adam优化算法在2014年12月才被提出。

    研究者

    我关注的另一指标是论文中提及深度学习领域的研究专家的次数(这与引用次数有些类似,但是前者能更好的用0/1指标表达,且能根据文章总数进行标准化):

    需要注意的是:35%的文章提到了“bengio”,但是学界有两个叫Bengio的专家,分别是Samy Bengio和Yoshua Bengio,图中显示的是两者总和。特别地,Geoff Hinton在30%的最新论文中也被提到,这是一个很高的比例。

    关键词研究

    最后,本文没有针对关键词进行手动分类,而是关注了论文中最热门和最不热门的关键词 。

    最热门关键词

    定义最热关键词的方法有很多,本文使用的方法如下:对于在所有论文中出现的一元分词和二元分词,分别计算出去年和去年以前该词的使用次数,并用二者相除得到的比例做排名。排名靠前的关键词是那些一年前影响有限、但是最近一年出现频率极高的词汇,如下表所示(该表是删除重复词以后的结果):

    举例来说,ResNet的比例是8.17,该词在一年之前(2016年3月)只在1.044%的论文中出现,但上个月8.53%的论文中都有这个关键词,所以我们有8.53 / 1.044 ~= 8.17的比例。

    所以可以看到,在过去一年流行起来的核心技术有:1) ResNets, 2) GANs, 3) Adam, 4) 批规范化(BatchNorm)。

    关于研究方向,最火的关键词分别是1)风格转换(Style Transfer), 2) 深度强化学习, 3) 神经网络机器翻译(“nmt”),或许还有 4)图像生成。

    整体构架方面,最流行的是1) 全卷积网络(FCN), 2) LSTMs/GRUs, 3) Siamese网络, 和4) 编码-解码器网络。

    最“过时”关键词

    相反的,过去一年不再流行的关键词有哪些呢?如下表所示:

    我并不确定“fractal”的含义,不过大体上看,贝叶斯非参数统计似乎不那么流行了。

    结论

    所以,是时候提交应用全卷积网络、编码-解码器、批规范化、ResNet、Gan来做风格转换,用Adam来优化你的论文了。嘿,这听起来也不是很离谱嘛:)

    原文链接:
    https://medium.com/@karpathy/a-peek-at-trends-in-machine-learning-ab8a1085a106

  4. 来源:AI前线(ID:ai-front)

    作者:Jacob Buckman 译者:王强、无明

    【新智元导读】本文作者Jacob来自Google AI Resident项目,他在2017年夏天开启了为期一年的Google研究型实习,在此之前他虽然有很多编程经验和机器学习经验,但没有使用过TensorFlow。这篇文章是Jacob为TensorFlow写的一个实用教程,作者表示,要是在开启TensorFlow学习之前有人告诉他这些知识就好了。希望这篇文章也能为读者提供帮助,少走弯路。

    前言:“我叫 Jacob,是谷歌 AI Residency 项目的学者。2017 年夏天我进入这个项目的时候,我自己的编程经验很丰富,对机器学习理解也很深刻,但以前我从未使用过 Tensorflow。当时我认为凭自己的能力可以很快掌握 Tensorflow,但没想到我学习它的过程竟然如此跌宕起伏。甚至加入项目几个月后我还偶尔会感到困惑,不知道怎样用 Tensorflow 代码实现自己的新想法。

    这篇博文就像是我给过去自己写的瓶中信:回顾当初,我希望在开始学习的时候有这样一篇入门介绍。我也希望本文能够帮助同行,为他们提供参考。”

    过去的教程缺少哪些内容?

    Tensorflow 发布已经有三年,如今它已成为深度学习生态系统的基石。然而对于初学者来说它并不怎么简单易懂,与 PyTorch 或 DyNet 这样的运行即定义的神经网络库相比就更明显了。

    有很多 Tensorflow 的入门教程,内容涵盖线性回归、MNIST 分类乃至机器翻译。这些内容具体、实用的指南能帮助人们快速启动并运行 Tensorflow 项目,并且可以作为类似项目的切入点。但有的开发者开发的应用并没有很好的教程参考,还有的项目在探索全新的路线(研究中很常见),对于这些开发者来说入门 Tensorflow 是非常容易感到困惑的。

    我写这篇文章就想弥补这一缺口。本文不会研究某个具体任务,而是提出更加通用的方法,并解析 Tensorflow 的基础抽象概念。掌握好这些概念后,用 Tensorflow 进行深度学习就会更加直观易懂。

    目标受众

    本教程适用于在编程和机器学习方面有一定经验,并想要入门 Tensorflow 的从业者。他们可以是:想在深度学习课程的最后一个项目中使用 Tensorflow 的 CS 专业学生;刚刚被调到涉及深度学习的项目的软件工程师;或者是一位处于困惑之中的 Google AI 新手(向 Jacob 大声打个招呼吧)。如果你需要基础知识入门,请参阅以下资源。这些都了解的话,我们就开始吧!

    理解 Tensorflow

    Tensorflow 不是一个普通的 Python 库。

    大多数 Python 库被编写为 Python 的自然扩展形式。当你导入一个库时,你得到的是一组变量、函数和类,它们补充并扩展了你的代码“工具箱”。使用这些库时,你知道它们将产生怎样的结果。我认为谈及 Tensorflow 时应该抛弃这些认识,这些认知从根本上就不符合 Tensorflow 的理念,无法反映 TF 与其它代码交互的方式。

    Python 和 Tensorflow 之间的联系,可以类比 Javascript 和 HTML 之间的关系。Javascript 是一种全功能的编程语言,可以实现各种出色的效果。HTML 是用于表示某种类型的实用计算抽象(这里指的是可由 Web 浏览器呈现的内容)的框架。Javascript 在交互式网页中的作用是组装浏览器看到的 HTML 对象,然后在需要时通过将其更新为新的 HTML 来与其交互。

    与 HTML 类似,Tensorflow 是用于表示某种类型的计算抽象(称为“计算图”)的框架。当我们用 Python 操作 Tensorflow 时,我们用 Python 代码做的第一件事是组装计算图。之后我们的第二个任务就是与它进行交互(使用 Tensorflow 的“会话”)。但重要的是,要记住计算图不在变量内部,它处在全局命名空间内。莎士比亚曾经说过:“所有的 RAM 都是一个阶段,所有的变量都只不过是指针。”

    第一个关键抽象:计算图

    我们在浏览 Tensorflow 文档时,有时会发现内容提到“图形”和“节点”。如果你仔细阅读、深入挖掘,甚至可能已经发现了这个页面,该页面中涵盖的内容我将以更精确和技术化的风格详细解释。本节将从顶层入手,把握关键的直觉概念,同时略过一些技术细节。

    那么什么是计算图?它实质上是一个全局数据结构:计算图是一个有向图,捕获有关计算方法的指令。

    我们来看看如何构建一个示例。下图中,上半部分是我们运行的代码和它的输出,下半部分是结果计算图。

    显然,仅仅导入 Tensorflow 并不会给我们生成一个有趣的计算图,而只有一个孤独的,空白的全局变量。但是当我们调用一个 Tensorflow 操作时会发生什么呢?

    快看!我们得到了一个节点,它包含常量:2。我知道你很惊讶,惊讶的是一个名为 tf.constant 的函数。当我们打印这个变量时,我们看到它返回一个 tf.Tensor 对象,它是一个指向我们刚创建的节点的指针。为了强调这一点,这里是另一个例子:

    每次我们调用 tf.constant 的时候,我们都会在图中创建一个新节点。即使节点在功能上与现有节点完全相同,即使我们将节点重新分配给同一个变量,甚至我们根本没有将其分配给变量,结果都一样。

    相反,如果创建一个新变量并将其设置为与现有节点相等,则只需将该指针复制到该节点,并且不会向该图添加任何内容:

    好的,我们更进一步。

    现在我们来看——这才是我们要的真正的计算图表!请注意,+ 操作在 Tensorflow 中过载,所以同时添加两个张量会在图中增加一个节点,尽管它看起来不像是 Tensorflow 操作。

    好的,所以 two_node 指向包含 2 的节点,three_node 指向包含 3 的节点,而 sum_node 指向包含… + 的节点?什么情况?它不是应该包含 5 吗?

    事实证明,没有。计算图只包含计算步骤,不包含结果。至少…… 还没有!

    第二个关键抽象:会话

    如果错误地理解 TensorFlow 抽象也有个疯狂三月竞赛(美国大学篮球繁忙冠军赛季),那么“会话”将成为每年排名第一的种子选手。能获此尴尬的荣誉,是因为会话的命名反直觉,应用却如此广泛——几乎每个 Tensorflow 程序都至少会调用一次 tf.Session() 。

    会话的作用是处理内存分配和优化,使我们能够实际执行由图形指定的计算。可以将计算图想象为我们想要执行的计算的“模板”:它列出了所有的步骤。为了使用这个图表,我们还需要发起一个会话,它使我们能够实际地完成任务。例如,遍历模板的所有节点来分配一组用于存储计算输出的存储器。为了使用 Tensorflow 进行各种计算,我们既需要图也需要会话。

    会话包含一个指向全局图的指针,该指针通过指向所有节点的指针不断更新。这意味着在创建节点之前还是之后创建会话都无所谓。

    创建会话对象后,可以使用 sess.run(node) 返回节点的值,并且 Tensorflow 将执行确定该值所需的所有计算。

    精彩!我们还可以传递一个列表,sess.run([node1,node2,…]),并让它返回多个输出:

    一般来说,sess.run() 调用往往是最大的 TensorFlow 瓶颈之一,所以调用它的次数越少越好。可以的话在一个 sess.run() 调用中返回多个项目,而不是进行多个调用。

    占位符和 feed_dict

    我们迄今为止所做的计算一直很乏味:没有机会获得输入,所以它们总是输出相同的东西。一个实用的应用可能涉及构建这样一个计算图:它接受输入,以某种(一致)方式处理它,并返回一个输出。

    最直接的方法是使用占位符。占位符是一种用于接受外部输入的节点。

    ……这是个糟糕的例子,因为它引发了一个异常。占位符预计会被赋予一个值,但我们没有提供,因此 Tensorflow 崩溃了。

    为了提供一个值,我们使用 sess.run() 的 feed_dict 属性。

    好多了。注意传递给 feed_dict 的数值格式。这些键应该是与图中占位符节点相对应的变量(如前所述,它实际上意味着指向图中占位符节点的指针)。相应的值是要分配给每个占位符的数据元素——通常是标量或 Numpy 数组。第三个关键抽象:计算路径下面是另一个使用占位符的例子:

    为什么第二次调用 sess.run() 会失败?我们并没有在检查 input_placeholder,为什么会引发与 input_placeholder 相关的错误?答案在于最终的关键 Tensorflow 抽象:计算路径。还好这个抽象非常直观。

    当我们在依赖于图中其他节点的节点上调用 sess.run() 时,我们也需要计算这些节点的值。如果这些节点有依赖关系,那么我们需要计算这些值(依此类推……),直到达到计算图的“顶端”,也就是所有的节点都没有前置节点的情况。

    考察 sum_node 的计算路径:

    所有三个节点都需要评估以计算 sum_node 的值。最重要的是,这里面包含了我们未填充的占位符,并解释了例外情况!

    相反,考察 three_node 的计算路径:

    根据图的结构,我们不需要计算所有的节点也可以评估我们想要的节点!因为我们不需要评估 placeholder_node 来评估 three_node,所以运行 sess.run(three_node) 不会引发异常。

    Tensorflow 仅通过必需的节点自动路由计算这一事实是它的巨大优势。如果计算图非常大并且有许多不必要的节点,它就能节约大量运行时间。它允许我们构建大型的“多用途”图形,这些图形使用单个共享的核心节点集合根据采取的计算路径来做不同的任务。对于几乎所有应用程序而言,根据所采用的计算路径考虑 sess.run() 的调用方法是很重要的。

    变量和副作用

    到目前为止,我们已经看到两种类型的“无祖先”节点:tf.constant(每次运行都一样)和 tf.placeholder(每次运行都不一样)。还有第三种节点:通常情况下具有相同的值,但也可以更新成新值。这个时候就要用到变量。

    了解变量对于使用 Tensorflow 进行深度学习来说至关重要,因为模型的参数就是变量。在训练期间,你希望通过梯度下降在每个步骤更新参数,但在计算过程中,你希望保持参数不变,并将大量不同的测试输入集传入到模型中。模型所有的可训练参数很有可能都是变量。

    要创建变量,请使用 tf.get_variable()。tf.get_variable() 的前两个参数是必需的,其余是可选的。它们是 tf.get_variable(name,shape)。name 是一个唯一标识这个变量对象的字符串。它在全局图中必须是唯一的,所以要确保不会出现重复的名称。shape 是一个与张量形状相对应的整数数组,它的语法很直观——每个维度对应一个整数,并按照排列。例如,一个 3×8 的矩阵可能具有形状 [3,8]。要创建标量,请使用空列表作为形状:[]。

    发现另一个异常。一个变量节点在首次创建时,它的值基本上就是“null”,任何尝试对它进行计算的操作都会抛出这个异常。我们只能先给一个变量赋值后才能用它做计算。有两种主要方法可以用于给变量赋值:初始化器和 tf.assign()。我们先看看 tf.assign():

    与我们迄今为止看到的节点相比,tf.assign(target,value) 有一些独特的属性:

    标识操作。tf.assign(target,value) 不做任何计算,它总是与 value 相等。

    副作用。当计算“流经”assign_node 时,就会给图中的其他节点带来副作用。在这种情况下,副作用就是用保存在 zero_node 中的值替换 count_variable 的值。

    非依赖边。即使 count_variable 节点和 assign_node 在图中是相连的,两者都不依赖于其他节点。这意味着在计算任一节点时,计算不会通过该边回流。不过,assign_node 依赖 zero_node,它需要知道要分配什么。

    “副作用”节点充斥在大部分 Tensorflow 深度学习工作流中,因此,请确保你对它们了解得一清二楚。当我们调用 sess.run(assign_node) 时,计算路径将经过 assign_node 和 zero_node。

    当计算流经图中的任何节点时,它还会让该节点控制的副作用(绿色所示)起效。由于 tf.assign 的特殊副作用,与 count_variable(之前为“null”)关联的内存现在被永久设置为 0。这意味着,当我们下一次调用 sess.run(count_variable) 时,不会抛出任何异常。相反,我们将得到 0。

    接下来,让我们来看看初始化器:

    这里都发生了什么?为什么初始化器不起作用?

    问题在于会话和图之间的分隔。我们已经将 get_variable 的 initializer 属性指向 const_init_node,但它只是在图中的节点之间添加了一个新的连接。我们还没有做任何与导致异常有关的事情:与变量节点(保存在会话中,而不是图中)相关联的内存仍然为“null”。我们需要通过会话让 const_init_node 更新变量。

    为此,我们添加了另一个特殊节点:init = tf.global_variables_initializer()。与 tf.assign() 类似,这是一个带有副作用的节点。与 tf.assign() 不一样的是,我们实际上并不需要指定它的输入!tf.global_variables_initializer() 将在其创建时查看全局图,自动将依赖关系添加到图中的每个 tf.initializer 上。当我们调用 sess.run(init) 时,它会告诉每个初始化器完成它们的任务,初始化变量,这样在调用 sess.run(count_variable) 时就不会出错。

    变量共享

    你可能会碰到带有变量共享的 Tensorflow 代码,代码有它们的作用域,并设置“reuse=True”。我强烈建议你不要在代码中使用变量共享。如果你想在多个地方使用单个变量,只需要使用指向该变量节点的指针,并在需要时使用它。换句话说,对于打算保存在内存中的每个参数,应该只调用一次 tf.get_variable()。

    优化器

    最后:进行真正的深度学习!如果你还在状态,那么其余的概念对于你来说应该是非常简单的。

    在深度学习中,典型的“内循环”训练如下:

    获取输入和 true_output

    根据输入和参数计算出一个“猜测”

    根据猜测和 true_output 之间的差异计算出一个“损失”

    根据损失的梯度更新参数

    让我们把所有东西放在一个脚本里,解决一个简单的线性回归问题:

    正如你所看到的,损失基本上没有变化,而且我们对真实参数有了很好的估计。这部分代码只有一两行对你来说是新的:

    既然你对 Tensorflow 的基本概念已经有了很好的理解,这段代码应该很容易解释!第一行,optimizer = tf.train.GradientDescentOptimizer(1e-3) 不会向图中添加节点。它只是创建了一个 Python 对象,包含了一些有用的函数。第二行 train_op = optimizer.minimize(loss),将一个节点添加到图中,并将一个指针赋给 train_op。train_op 节点没有输出,但有一个非常复杂的副作用:

    train_op 回溯其输入的计算路径,寻找变量节点。对于找到的每个变量节点,它计算与损失相关的变量梯度。然后,它为该变量计算新值:当前值减去梯度乘以学习率。最后,它执行一个赋值操作来更新变量的值。

    基本上,当我们调用 sess.run(train_op) 时,它为我们对所有的变量做了一个梯度下降的操作。当然,我们还需要使用 feed_dict 来填充输入和输出占位符,并且我们还希望打印这些损失,因为这样方便调试。

    用 tf.Print 进行调试

    当你开始使用 Tensorflow 做更复杂的事情时,你需要进行调试。一般来说,检查计算图中发生了什么是很困难的。你不能使用常规的 Python 打印语句,因为你永远无法访问到要打印的值——它们被锁定在 sess.run() 调用中。举个例子,假设你想检查一个计算的中间值,在调用 sess.run() 之前,中间值还不存在。但是,当 sess.run() 调用返回时,中间值不见了!

    我们来看一个简单的例子。

    我们看到了结果是 5。但是,如果我们想检查中间值 two_node 和 three_node,该怎么办?检查中间值的一种方法是向 sess.run() 添加一个返回参数,该参数指向要检查的每个中间节点,然后在返回后打印它。

    这样做通常没有问题,但当代码变得越来越复杂时,这可能有点尴尬。更方便的方法是使用 tf.Print 语句。令人困惑的是,tf.Print 实际上是 Tensorflow 的一种节点,它有输出和副作用!它有两个必需的参数:一个要复制的节点和一个要打印的内容列表。“要复制的节点”可以是图中的任何节点,tf.Print 是与“要复制的节点”相关的标识操作,也就是说,它将输出其输入的副本。不过,它有个副作用,就是会打印“打印清单”里所有的值。

    有关 tf.Print 的一个重要却有些微妙的点:打印其实只是它的一个副作用。与所有其他副作用一样,只有在计算流经 tf.Print 节点时才会进行打印。如果 tf.Print 节点不在计算路径中,则不会打印任何内容。即使 tf.Print 节点正在复制的原始节点位于计算路径上,但 tf.Print 节点本身可能不是。这个问题要注意!当这种情况发生时,它会让你感到非常沮丧,你需要费力地找出问题所在。一般来说,最好在创建要复制的节点后立即创建 tf.Print 节点。

    这里(https://wookayin.github.io/tensorflow-talk-debugging/#1)有一个很好的资源,提供了更多实用的调试建议。

    结 论

    希望这篇文章能够帮助你更好地理解 Tensorflow,了解它的工作原理以及如何使用它。毕竟,这里介绍的概念对所有 Tensorflow 程序来说都很重要,但这些还都只是表面上的东西。在你的 Tensorflow 探险之旅中,你可能会遇到各种你想要使用的其他有趣的东西:条件、迭代、分布式 Tensorflow、变量作用域、保存和加载模型、多图、多会话和多核数据加载器队列等。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>