Podcast Script (zh)
[0.120-12.510] SPEAKER_00: 我来说说用Torch和AutoGrad做机器学习。 所以这个演讲描述不完全对。 前半段我会实际操作。 然后深入讲Torch AutoGrad的概念。 这些概念是所有深度学习库共有的。
[12.590-27.871] SPEAKER_00: 我想让你看到各大深度学习库的共同主线。 再谈库的不同点、为什么有这么多库——我猜原因和选择。 我想试一件事——问题很多,已经超时了。 但就算现场没问题,还有人在线看。 有时间优先照顾现场的人。
[27.951-42.280] SPEAKER_00: 如果用DL School标签提问或直接私信我,我会在线答。 离线也会回答。 所以在家观看的话,请提问。 或许能增加在线观看者的参与感。 但如果用#DL School标签或直接私信我, 我会尝试回答线上问题。
[42.360-54.074] SPEAKER_00: 线下当然也会回答。 所以在家看就提问吧。 或许能增加观看者的参与感。 通过今天不在现场的流。 很多材料是和Facebook的Sumit Chintala一起开发的。
[54.154-64.695] SPEAKER_00: 他现在算是Torch生态系统的负责人。 还有你昨天听过的Hugo Larochelle,以及Ryan Adams,他在Twitter与我们 我们。 所有材料都在这个GitHub仓库里。
[64.775-80.358] SPEAKER_00: 这个仓库很棒,你打印的安装指南上就有,用来安装 Torch。 所以我要展示的示例都在一个笔记本里。 还有一个单独的笔记本,我演讲中不会提,它是 一个完整的端到端指南,教你在CIFAR-10上训练卷积神经网络。
[80.438-96.787] SPEAKER_00: 那是自定进度的教程笔记本,你可以按自己的时间学。 但我会专注基础知识和原理,并希望给你们一些 让你们真正深入Torch在线资源的概念和词汇。 按你自己的时间。 那我们就开始吧。 Torch是一种用于Lua的数组编程语言,对吧?
[96.867-112.833] SPEAKER_00: 它就像NumPy,也像MATLAB, 但它是用Lua语言写的。 所以Torch之于Lua就像NumPy之于Python,对吧? 所以你在Torch里能做到的,在任何语言里都能做到。 这是最基础的东西。 你可以获取并打印字符串。 也能放进关联数据类型里。
[112.913-126.870] SPEAKER_00: Python有元组、列表、集合。 还有字典。 Lua只有一种数据类型:表。 所以它很常见,但表能搞定所有。 我刚刚说的所有事情。 还有for循环和if语句。 Torch的核心类型是张量。
[126.950-138.899] SPEAKER_00: 就像NumPy的ndarray,它 能把数字集合塑形成 矩阵或张量,我们就有张量。 可以用随机数填充。 可以对它们做乘法。 标准操作。 张量是Torch的核心数据类型。 我们还有绘图功能。
[138.979-151.206] SPEAKER_00: 从一个高层次来看,我 稍后给你看更具体的代码。 所以所有标准操作你都能做 就跟在其他数组语言里一样 你想用的张量函数都有 包括线性代数和卷积 还有BLAS函数
[151.286-164.895] SPEAKER_00: 我在这里留个链接 等幻灯片上传之后 点这个链接就行 还能仔细看文档 清楚看到有哪些工具 给你用 在iTorch笔记本里 这是Sumith整理的 在任何Torch函数前加个问号
[164.975-173.519] SPEAKER_00: 就会显示该函数的帮助 所以探索功能非常方便 Torch库里,笔记本里 那为什么它用Lua呢 可能有点奇怪 用这么冷门的语言写代码
[173.599-185.223] SPEAKER_00: Lua用起来方便,速度也超快。 特别是LuaJet这个变体。 LuaJet的for循环速度和C一样。 这个for循环实际在生产代码里。 在master和Torch里。 这不是C代码。
[185.303-197.972] SPEAKER_00: 但它足够快了。 Lua很棒的一点是,你可以 依赖高性能C代码。 再上面还有方便的胶水 层,但速度损失很小。 使用那个胶水层。 这是我们用Lua的一个原因。 另一个优势是
[198.052-210.198] SPEAKER_00: 语言本身非常小巧。 所以只有一万行C代码 定义了整个Lua语言。 你可以花个下午读手册 理解大部分语言 一天内自己搞定。 另一个关键点 对深度学习和其它领域
[210.278-224.549] SPEAKER_00: 就是和C库互操作特别容易 它一开始就是嵌入式语言 所以Lua就是专门用来 在别的C程序里运行 但里面有个小脚本层 所以调用C特别容易 C调用Lua也很容易 这也是它成为深度学习库
[224.629-233.928] SPEAKER_00: 另一个重要的原因 FFI调用签名和思路 被很多其他语言模仿 所以Python的C FFI就是Lua FFI的Python版 Julia也有类似功能
[234.008-251.100] SPEAKER_00: 就像我说的它最初 就是嵌入式语言 它出现在很多你想不到 会有Lua的地方 所以在《魔兽世界》里所有图形 用C++或者他们用的任何语言写的, 但Boss战本身就是任务。 当你把宝石给铁匠或别人时, 他们会把魔剑还给你, 事件脚本用Lua写的。
[251.180-269.503] SPEAKER_00: 如果你给魔兽世界写脚本 来做自己的任务,那就是Lua。 Adobe Lightroom 是照片处理软件。 所有图像处理用C++完成, 但用户界面和其他全用Lua。 所以,它又被用来把高性能 代码和脚本层绑在一起。 Redis和Nginx,某种程度上
[269.583-283.320] SPEAKER_00: 是Web开发的主力, 都能用Lua写脚本。 如果你访问GitHub Pages, 比如mypage.github.io,如果有人 在GitHub上托管网页,那部分用Lua服务。 关于最初为什么选它的传说,
[283.400-300.945] SPEAKER_00: 也许你可以纠正我,是Clément Farabé 试着做个嵌入式机器学习应用 能戴在自行车头盔上的设备 他还是Yann学生时,就用CNN给世界分类 他试着用Python实现这个 而且要让 在嵌入式芯片上跑Python很让人沮丧
[301.025-314.982] SPEAKER_00: 现在用树莓派可能会容易些 但当时不是这样 然后他偶然发现 Lua,结果发现人们 多年来一直把Lua嵌入到应用里 在此之前 这就跟滚雪球效应一样 这就是我们用Lua的故事 但也许还有另一个故事
[315.062-329.635] SPEAKER_00: Torch另一个很好的特性 就是它对GPU计算支持一流 交互式GPU计算 所以从CPU取数据特别容易 到GPU,然后你做的所有事 能处理GPU上的数据 不用操心写CUDA内核
[329.715-341.048] SPEAKER_00: Torch一直有这个特性 现在没那么特别了 刚推出时很可靠 就是交互式GPU计算 我快速介绍基本特性 同样,这些例子 都在笔记本里,按自己节奏操作
[341.128-349.127] SPEAKER_00: 随你 有基本的算术运算 比如建矩阵、做操作 做算术运算 求数字和数组最大值 钳制 从范围创建张量
[349.207-357.763] SPEAKER_00: 对数组做布尔运算 特殊函数 通过封装器支持 基于Cephes库 这是NumPy支持功能的一部分。 比如tanh、atan2这类函数。 我觉得这些算特殊类别。
[357.843-374.447] SPEAKER_00: 然后Sumith又封装了Bokeh.js库。 这个库原本只用于Python。 但它能生成非常漂亮的图表。 在iTorch笔记本中。 这样我们就能从喜欢的分布中 抽取随机数,做出漂亮直方图。 所以你可以在iTorch笔记本中 一边做深度学习,一边探索数据。
[374.527-387.915] SPEAKER_00: 所以有个特性很吸引人。 不过这只是Torch生态的一个有趣特性。 尽管Torch生态系统数据很多。 虽然有很多行业支持, 但行业并不拥有它。 所以在Twitter、Facebook AI Research和NVIDIA, 我们都给Torch社区贡献了很多。
[387.995-398.179] SPEAKER_00: 但我们并不拥有它。 但我们不拥有它。 我们控制不了它往哪边开。 这是确定的。 还有很多人用学术方式参与。 在这个生态系统里。 这真是个好特性。
[398.259-410.962] SPEAKER_00: 而且,深度学习的人习惯好, 搞深度学习的, 论文发表时,通常有高质量代码跟着来。 跟着来的实现。 不总是,但很常见,比其他领域多。 Torch 常能看到高质量前沿实现。
[411.042-433.454] SPEAKER_00: 常看到高质量前沿实现。 前沿的内容。 逛 GitHub 关注研究者,就能看到图像描述的高质量实现。 关注 GitHub 研究者,能看到图像描述的高质量实现。 图像描述的。 神经风格迁移的。 所以直接克隆这个仓库运行就行。 Torch 就是其中一个。 Torch 就是其中一个。 Torch就是其中之一。 Torch就是其中之一。
[433.534-444.087] SPEAKER_00: Seq2seq模型,不管技术多先进, 通常都有Torch实现。 最近有些合成图像非常逼真, 它们用了生成对抗网络。 也有很棒的Torch代码实现。
[444.167-452.584] SPEAKER_00: 所以,GitHub上有个活跃社区, Torch深度学习社区,和其他社区比 表现怎么样? 先给你点背景信息。 Python数据科学社区很庞大。
[452.664-466.076] SPEAKER_00: 而且关注点也很多样。 如果你进Torch和Lua的数据社区, 你可能会看到深度学习从业者, 但其他领域的人不多。 所以它在深度学习上的实力, 跟它的规模比,其实非常大。 如果你正在考虑,
[466.156-480.438] SPEAKER_00: 从Python或Lua切换到Torch的人 从Python换到Lua的尝试 如果你试过,可能一天就搞定 在Python编程里 所以我曾是Python程序员 学Lua大概花了几天 实际上,一周左右就很有成效 但你可以直接运行代码
[480.518-495.822] SPEAKER_00: 并能快速理解编写新内容 如果你用过MATLAB或Python这类脚本语言 所以如果你害怕或犹豫 你应该直接去尝试 那Torch和其他深度学习库比怎么样 具体来说,跟语言相比呢 第一点,现在确实没有银弹 现在
[495.902-508.129] SPEAKER_00: 现在有很多深度学习库 我想说TensorFlow现在是最大的 这是Sumith同事做的图表 我希望图上能有置信区间 因为并不是严格这样 就像深度学习里的一个点。
[508.209-522.875] SPEAKER_00: 但这可能是个大概的猜测。 TensorFlow好像是为 在工业环境里表现很好, 而且它确实做到了。 Theano一直专注研究, 在研究领域很出色, 已经很长时间了。 Torch更偏向研究,不是工业。
[522.955-540.813] SPEAKER_00: 我觉得Twitter可能把它 往生产环境推了一点。 我们大概是唯一的例子。 我很想了解其他例子,但我们可能 是唯一用Torch的大公司, 在生产环境里提供模型服务。 所以,进入Twitter的每条媒体内容 目前都用Torch模型处理。 所以我们其实在处理海量数据, 在实时环境里。
[540.893-554.641] SPEAKER_00: Torch的发展就说到这。 可以把它想象成我们怎么搭这个东西的。 还有我们怎么把它变大,其实 我们核心里有些基本原则。 首先,事情应该…… 这不一定是好坏,但这是我们选的路。 每次你在某行按回车,
[554.721-567.691] SPEAKER_00: 在 iTorch 笔记或命令行里, 就会得到一个回答。 这点我们一直努力 严格做到。 所以没有编译时间。 好的。 这就是命令式编程,对吧? 直接写代码,每行 干一件事,结果传给下一行。
[567.771-582.680] SPEAKER_00: 所谓最小抽象,就是说 你想分析代码性能时, 不用跳太多步就能找到实际跑的 C 代码。 实际上,通常一两次跳转就够了。 定义你关心的函数的文件 到实际的C代码 所以如果你想分析性能或者真正
[582.760-592.883] SPEAKER_00: 理解发生了什么,Torch里很容易 我想先绕个弯 告诉你Torch怎么看它的对象 以及怎么看张量,因为这 也能帮你分析性能 人们选Torch的原因很多
[592.963-605.655] SPEAKER_00: 为了快速轻松构建高性能模型 我之前提到过张量 张量是个n维数组 张量其实只是个指针,是个视图 指向你的内存 它是内存中数据的视图 所以它就是个形状
[605.735-618.636] SPEAKER_00: 它是RAM中数据的视图 它按行主序存储 如果访问张量内存的第一个元素 然后移动一个位置 我移一行的元素,不是一列的。 列优先存储确实存在。 不过现在不常见了。
[618.716-632.638] SPEAKER_00: 所以你常看到行优先。 这个张量由存储关联定义。 它的大小是4乘6。 步长是6乘1。 6乘1表示沿列向下移一步。 其实我得跳过六个元素。 这个1表示在行轴上移动。
[632.718-645.154] SPEAKER_00: 移动一个。 我只用在内存中移一个位置。 所以如果用select命令切片张量。 就是沿第一维选第三个元素。 它返回一个新张量。 它不给我新内存。 在Torch里另一个常见情况是。
[645.234-659.040] SPEAKER_00: 你会处理内存视图。 你不会复制内存。 所以你通常处理RAM原始数据。 这样就生成了一个六维张量。 六个元素,步长是一。 我们取的是行,不是列。 偏移量是13。 需要移动13个元素。 从存储的开头。
[659.120-670.651] SPEAKER_00: 才能找到那段内存。 但如果取一列,就不一样了。 我还是有一个。 大小是4。 步长是6,因为要。 取每列元素得跳过6个。 偏移量是3,因为我取了。 那里的第三个元素。
[670.731-679.751] SPEAKER_00: 这是内存模型的一个视图。 如果实际运行这种操作。 比如创建一个双精度张量。 用均匀分布填充它。 打印出来就能看到数值。
[679.831-694.485] SPEAKER_00: 取切片B打印,正是这一行。 拿个数字填进B,然后打印出来。 现在B被那个数字填满了。 要是回去打印A,其实已经 把那里的值覆盖掉了。 这种情况在Torch里很常见, 就是在共享内存上操作。
[694.565-707.280] SPEAKER_00: 就像前面说的,用CUDA 真的特别容易。 所以如果你只用CUTORCH,它 有CUDA显卡就会自动装好, 按GitHub上的说明来, 就能在GPU上创建张量,做同样的事。 而且直接就能用。
[707.360-720.377] SPEAKER_00: 现在聊聊一些框架, 你会在Torch里用它们来训神经网络。 这是个卡通示意图, 展示训练神经网络需要的各部分。 数据存在硬盘里, 或者存在大型分布式文件系统里。
[720.457-738.408] SPEAKER_00: 有专门的系统来加载数据。 文件系统的一部分,进入良好队列。 然后是一些训练代码,这些代码 编排一个神经网络,让它实际上 做预测。 一个成本函数,是一个衡量 神经网络在训练中任意时刻表现好坏的指标。 还有一个优化器,它会获取
[738.488-753.989] SPEAKER_00: 成本对 神经网络中参数的梯度 并尝试改进神经网络。 所以在 Torch 生态系统里,我们有一些包 分别处理这些任务。 所以这里我不讨论线程。 实际上有几个不同的库 可以做到这一点。 实际上有几个不同的库 可以分别完成这些任务。
[754.069-769.489] SPEAKER_00: 但这个可能是最常见或最简单的 入门选择。 而这里的 NN 会涵盖规范。 神经网络的损失函数 以及数据流动 通过网络和损失函数的机制 再把梯度从损失传回参数 还有优化器,今天我们
[769.569-780.447] SPEAKER_00: 多次听到随机梯度下降 或者Atom 或者AdaGrad 所以先聊聊神经网络,给你 它如何工作及各部分的概念 神经网络这个包搭建前馈网络
[780.527-793.672] SPEAKER_00: 主要是前馈网络 就像拼乐高积木 所以你可能从输入开始 然后拼一个全连接层 再加一个全连接层 然后可能就是输出 这里我定义了一个Sequential 它用来装所有乐高积木 积木
[793.752-807.059] SPEAKER_00: 然后我会点个空间卷积。 所以我会处理图像,加个非线性层。 加些最大池化层和其他层。 然后搭好整个网络。 最后我会加一个对数softmax。 算出类别概率。
[807.139-820.005] SPEAKER_00: 这就是你要 在NN里建神经网络,先定义个容器。 然后挨个加组件。 沿着层次往下走。 我刚说过顺序容器, 它从输入开始,然后线性进行。 还有两种容器你可能用到。
[820.085-825.611] SPEAKER_00: 但通常,线性架构下,NN表现很好。 不是有乱七八糟的分支。
[825.691-844.165] SPEAKER_00: NN包的API不多。 所以学会这几个函数, 这些函数后面幻灯片里都有,想参考的话 它们,你就懂后面所有内容了。 你就能理解所有机制。 要懂怎么把数据推进神经网络 再通过损失函数或准则来处理 然后拉回那些梯度
[844.245-858.911] SPEAKER_00: 更新模型的梯度 所以这些API就像操作杆 你得靠它驱动神经网络 我们给神经网络提供了CUDA后端 就好像你直接在数据上调CUDA 你可以在容器上调用CUDA 这会把整个模型移到GPU上
[858.991-873.575] SPEAKER_00: 之后你对模型做的所有操作 都会在GPU上进行 所以这基本是一行代码启动训练 在GPU上运行 所以对前馈网络,NN非常出色 但要尝试更奇特的结构时 就像昨天Richard Socher说的
[873.655-887.972] SPEAKER_00: 一个很复杂的NLP模型 从glove向量开始,类似于浅层神经网络 然后是一个递归神经网络 然后是个张力机制,还有这些。 运行方式很奇怪。 其实在神经网络里很难指定。 在Twitter,我们有个叫Torch Autograd的包,
[888.052-902.520] SPEAKER_00: 能轻松把不同模型片段拼接起来。 变得很容易。 其实片段可以小到加法、除法、 乘法和减法。 所以你可以把任意大小的计算片段拼在一起, 仍然能得到正确的模型。 稍后我会细讲这点。
[902.600-917.022] SPEAKER_00: 需要opt-in包,才能 用随机梯度训练模型 下降法,或梯度外,或delta外, 不管你偏爱哪种优化器。 这个API挺直接, 但对从Python世界来的人来说 可能有点不一样。 它有一些函数式的方法,
[917.102-928.946] SPEAKER_00: 你需要把一个函数传给opt-in。 它会评估你的神经网络。 然后把梯度传回来。 所以这点要注意。 这种风格不太一样。 opt-in还有个陷阱。 你会在有些笔记本里看到。
[929.026-941.253] SPEAKER_00: 线上那个是你的参数。 它在内存中应该是线性的。 如果你想优化两个神经网络。 它们以某种方式交互。 需要先合并它们的参数。 整合到单个张量传给opt-in。 这点要注意。
[941.333-955.464] SPEAKER_00: 接下来我想聊聊Torch。 以及Autograd背后的理念。 这些是Torch Autograd的基础。 它们连接所有深度学习库。 你可以自己选择。 首先,我想退一步说。 欣赏这些美妙稳定的抽象。
[955.544-968.166] SPEAKER_00: 科学计算里用的就是这个。 Fortran呢,57年的版本早没人用了。 但可能还有人用Fortran 90。 那时候计算机还没有数组的概念。 而且确实需要一些很疯狂的想法,我觉得, 来造一个让数组变理所当然的系统。
[968.246-982.517] SPEAKER_00: 我们就觉得理所当然。 线性代数也一样。 大概20年时间,从70年代末开始, 人们就想,哎,也许该 系统性地想想线性代数。 现在呢,我们不用操心了。 要是你想算两个矩阵相乘, 以前大规模做这事得博士水平才行。
[982.597-998.574] SPEAKER_00: 现在连导入BLAST都不需要。 BLAST的封装太多了,我们甚至都不 思考这个问题了。 所以这是另一个抽象。 而且我们应该把可能用到的例程 都放在一个地方,方便使用。 我们不用自己写。 可以说是MATLAB在80年代中期发明的,
[998.654-1012.426] SPEAKER_00: 然后真正地 靠NumPy在开源社区普及开来。 这些我们觉得理所当然。 完全不用去想它们。 因为它们让我们更快。 让我们更好,放心它们能正常工作。 所以机器学习还有别的抽象,
[1012.506-1024.281] SPEAKER_00: 除了这些理所当然的计算抽象。 所有基于梯度的优化, 神经网络是其中一部分, 都依赖自动微分 来计算这些梯度。 我喜欢Barak Perlmutter的这个定义。
[1024.361-1038.492] SPEAKER_00: 自动微分用机械方式计算 导数作为计算机程序 表达的函数。 所以它不会推导我手写的东西, 用铅笔在纸上。 它用机器精度推导程序 并有复杂度保证 最后这两点把它区分开 有限差分法不同,它取输入
[1038.572-1051.484] SPEAKER_00: 对程序做微小扰动 然后用它量梯度 这量梯度的方法很糟糕 数值上它很不稳定 而且它不是符号微分 所以它不是写符号表达式 把神经网络放进Mathematica或Maple里 然后求导
[1051.564-1061.876] SPEAKER_00: 因为表达式可能从这样变成这样 所以当你 搞朴素符号微分时,表达式会膨胀 自动微分不会这样 所以自动微分,我觉得 是基于梯度的机器学习抽象 也就是学习
[1061.956-1075.681] SPEAKER_00: 它被多次重新发现 Woodrow和Lair写了篇评论。 我认为最早实现的地方 Bert Spielpenning在计算机上完成的 1980年实现,但1964年就有描述 Wengert描述的。
[1075.761-1091.193] SPEAKER_00: 在神经网络里,Rumble Heart, 我觉得就是它推广的 以反向传播形式,不过反向传播 是自动微分的一个特例。 我觉得这很重要。 核科学和计算流体动力学中 还有天气建模,这些人 已经用自动微分多年甚至几十年。
[1091.273-1105.463] SPEAKER_00: 他们的工具在很多方面更复杂 比我们机器学习用的复杂得多。 有很多想法我们还没 从气象建模那儿引入,这些想法会 帮助我们训练越来越大的模型。 我想澄清,机器学习中的抽象
[1105.543-1122.809] SPEAKER_00: 其实就是反向模式自动微分。 有两种不同的类型,可以说是两个极端。 前向模式和反向模式。 你从没听过前向模式。 但在机器学习中,你没听过前向模式。 因为机器学习里尝试前向模式,是个很糟的主意。 学习。 我来告诉你为什么。 这是一张网上的猫图片。
[1122.889-1138.158] SPEAKER_00: 我的任务就是判断它到底是不是猫图片。 一张猫图片。 这其实是Twitter在做的事情。 我要做的是把这张猫图片 经过一连串的变换层, 最后输出一个类别概率。 我判断错了。 我的分类器觉得是狗,所以我
[1138.238-1152.404] SPEAKER_00: 想训练神经网络让它认成猫。 所以我有损失,还有损失的梯度, 然后对参数求导得到它。 这就是我的梯度,它将 让我更新参数。 它由好几部分组成。 用链式法则,我能整合它们。 算出我想要的损失,
[1152.484-1162.062] SPEAKER_00: 就是损失梯度对 参数。 我既能从左到右,也能从右到左。 所以从左到右像这样。 哎呀,太快了。 好的。 我要做两次大矩阵乘法。 这很糟糕。
[1162.142-1176.935] SPEAKER_00: 这不好,因为要处理巨大矩阵 乘积,一直留着。 实际更糟,我用另一种方式给你看: 前向模式。 假设我有段程序, 不再是神经网络的符号。 就是个计算机程序。 假设我要优化a。 a是神经网络的唯一参数。
[1177.015-1189.335] SPEAKER_00: 这个例子很傻也很琐碎, 但能帮我们说明问题。 所以我可以运行程序,看看 所有运算步骤, 然后生成一个跟踪。 所以比如定义a等于3。 再定义b=2,c=1,然后执行。
[1189.415-1202.618] SPEAKER_00: 代码开始运行。 我会检查b是否大于c, 选择要执行的分支, 但跟踪里忽略这个检查。 所以我选了一个分支, 就是第一个,因为b比c大。 得到输出值d,然后 返回这个输出。
[1202.698-1216.272] SPEAKER_00: 这就是程序在输入后的跟踪执行。 要用前向模式算d对a的导数, 我把a设为3, 利用a对自身的梯度。 最终我想求 d 的导数。 关于 a 的导数,我一步步构建。
[1216.352-1232.678] SPEAKER_00: 先 da,然后 db、dc、dd 对 a 的导数。 所以从左向右移动。 构建梯度。 对 b 关于……的导数,不能做太多。 现在是关于 a。 所以我定义 c 和 c 关于 a 的导数。 然后我有值 d,然后我
[1232.758-1245.009] SPEAKER_00: 定义目标值,它 是 d 关于 a 的梯度。 如果我想求 d 对 b 的梯度, 如果有一个双参数神经网络 还要同时优化两者。 得重新做整个过程。 并把 db 初始化为 1。
[1245.089-1260.637] SPEAKER_00: 如果你有一百万个参数 或者神经网络里有数千万个。 你得做一百万次前向模式评估, 或者数千万次前向模式评估。 所以尝试前向模式很糟糕, 用于神经网络自动微分, 这就是你从没听过它的原因。 所以现在你可以忘了它。
[1260.717-1274.581] SPEAKER_00: 但替代方案是反向模式, 就是从右向左开始。 现在得到漂亮的矩阵向量乘积, 它们更小,复杂度也更好。 但有个有趣的差异, 当实际在代码中实现时。
[1274.661-1289.489] SPEAKER_00: 你会看到这些词靠得更近, 这是因为反向模式其实 不需要这样做。 我实际得先评估整个程序, 才能开始推导,因为我 从d对d的导数开始, 然后求d对c的导数 再对b再对a。
[1289.569-1302.481] SPEAKER_00: 所以我走另一条路,但 开始前得先拿到所有信息。 现在我能初始化导数。 求d对d的导数,再反向推导。 并返回值和梯度。 好处是,你会发现, 其实我已掌握了所有信息。
[1302.561-1317.366] SPEAKER_00: 来计算d的导数。 相对于其他参数。 所以我们特别爱用反向模式。 自动微分,就是神经网络的反向传播。 如果你有很多这样的参数, 你肯定想一次性算出来。 用矩阵在电脑上算,效率很高。 所以我们搞了一个基于追踪的自动
[1317.446-1329.534] SPEAKER_00: 微分包,叫autograd。 神经网络就这么回事。 这就是在autograd里定义和训练 一个神经网络。 用自动微分的神经网络 那我就初始化参数。 就是些随机数。
[1329.614-1343.513] SPEAKER_00: 这是我的神经网络函数。 我把传入的图像乘以 权重矩阵加偏置和非线性, 重复,然后返回概率。 我有损失函数,接收图像 返回预测,用这个函数。
[1343.593-1354.645] SPEAKER_00: 然后取均方误差, 或者平方误差和。 要得到这个函数的梯度, 损失对参数的导数, 只需导入自动微分包 然后调用grad。
[1354.725-1362.828] SPEAKER_00: 返回新函数,返回梯度 的原始函数。 所以叫高阶函数。 输入输出都是函数。 看到 nabla 倒三角, 梯度三角,是个函数
[1362.908-1374.903] SPEAKER_00: 那是编码的等价物。 训练时,调用DLoss函数。 传入参数、图像和标签。 我假装你已经。 有个系统能到这。 然后我们得到梯度。 然后用随机梯度下降更新。 这里。
[1374.983-1387.779] SPEAKER_00: 它很薄,就是这样。 这是你和autograd的接口。 那实际发生了什么? 这是我的简单函数。 评估时,我们其实。 会记下你做的每一步。 才能反过来做。 我们在构建跟踪列表。
[1387.859-1400.353] SPEAKER_00: 之前说的,内部跟踪。 从第几行开始,大概第五行。 我们会乘一些东西。 记下你乘了啥和输入。 我们跟踪加法和输入。 还有加法的输出。 我们跟踪输入和输出。 还有每次的函数。
[1400.433-1419.034] SPEAKER_00: 然后沿着这个函数一步步建你的计算图。 即时。 所以你运行代码时,我们就知道你在做什么。 而我们跟踪的方式,不深究细节。 我们把Torch里每个函数都替换了。 用一个类似间谍的函数。 所以不只运行torch.sum。 我们的间谍函数会说,哦,我听到了。 你正在运行torch.sum。
[1419.114-1428.390] SPEAKER_00: 让我记住你给的参数。 让我对这些参数做求和。 记住输出,然后返回它。 就像什么都没发生一样。 但内部我们全记住了。 我们实际是这么做的。
[1428.470-1441.916] SPEAKER_00: 我们实际就是要这么做。 反向遍历列表时计算梯度 就像我之前说的 每次我们遇到需要 计算偏导数时,我们就去查 我们已经写好了所有 针对torch函数的偏导数 其实每个神经网络库
[1441.996-1450.413] SPEAKER_00: 都在某种粒度上这么做 让我再带你看几个例子 只是展示它能做什么 所以这是个很普通的例子 我们可以对标量加乘,得到正确梯度
[1450.493-1465.205] SPEAKER_00: 而这里的情况变得更有趣了 如果有个if语句 所以这种控制流可能有点麻烦 或者在很多深度学习库里显得笨拙 因为我们只监听哪些算术函数被执行 我们忽略控制流 所以我们直接跳过这些 这样就能得到正确梯度,即使有控制流
[1465.285-1475.606] SPEAKER_00: 用if语句。 优化时,我们关心张量。 或机器学习。 所以,对标量适用的, 也适用于张量。 都在GitHub笔记本里, 想试的话。 这就变得有趣了。
[1475.686-1488.436] SPEAKER_00: for循环也能用。 不只是固定长度的for, (可能容易展开), 循环次数取决于 刚算的数据。 或while循环,停止条件 依赖内部计算。 我们不在意。 动态构建计算图。
[1488.516-1503.263] SPEAKER_00: 完成后,返回某个值, 我们会计算图导数。 任何for循环都可转成递归函数。 这有点怪。 我是说,实际用起来真不知道咋整。 但能搞出很多疯狂的东西, 用 autograd 试试,它们就能跑。 这里有个函数 f。
[1503.343-1516.476] SPEAKER_00: 如果 b 达到停止条件,就返回 a。 否则,就调用 f。 然后要对这个求导。 也就是对一个完全递归的函数求导。 而且跑得很好。 我们管它叫循环。 另一面,论文越来越多, 这些论文基本不尊重
[1516.556-1527.295] SPEAKER_00: 梯度求导的神圣性。 人们在算合成梯度。 他们在裁剪梯度。 有人乱搞反向传播 或自动微分的内部机制。 其实用 autograd 处理这些挺容易的。
[1527.375-1543.619] SPEAKER_00: 比如我要对 a 的 floor 的三次方求和。 所以向下取整是分段常数。 所以导数几乎处处为零, 除了未定义的地方。 我为什么要这么做? 比如,你想构建一个可微分的JPEG 编码器或可微分的MPEG编码器,
[1543.699-1563.371] SPEAKER_00: 在类似的压缩算法中, 通常有个量化步骤 这个步骤会把数字向下取整、四舍五入或截断。 而如果你想通过它求导 来构建神经JPEG算法或其他东西, 你需要通过那些通常不传递梯度的东西 来传递梯度。 所以,我们看梯度位置, 它处处为零。 我不细讲,但你
[1563.451-1579.881] SPEAKER_00: 可以要求autograd为任何东西用你自己的梯度。 所以,如果你有个想定义的新模块, 要么你为它写了高性能代码 并且想用它,或者你想 重新定义或覆盖已有梯度, 有一种简单机制能做到。 然后调用特殊的.floor时, 可以通过它传播梯度。
[1579.961-1592.955] SPEAKER_00: 基本上就是说, 可以忽略floor的梯度。 这是个玩具示例,但确实 有些场景,计算图中有个不可微瓶颈, 而你 要么跳过它,要么找近似。 而autograd提供机制,可轻松接入 这种情况。
[1593.035-1602.729] SPEAKER_00: 这就是autograd的功能介绍。 现在看autograd与其他深度学习库 相关联, 以及它们的共同点和相似之处 和不同之处。 我发现一个重大区别
[1602.809-1615.768] SPEAKER_00: 在于不同深度学习库之间 允许的操作粒度不同。 用来指定你的神经网络。 所以有很多库,你只要说, 你得到一个卷积或前馈网络, 就这样。 菜单就两个选项。 那也没问题。 我觉得安德烈一针见血,
[1615.848-1630.351] SPEAKER_00: 想解决问题,别逞英雄。 用别人的网络。 所以这可能是你从模型库下的VGG 或类似的东西。 左边就是“别逞英雄”的情况。 中间有很多方便的神经网络 特定库,比如Torch NN、Keras和Lasagna。
[1630.431-1643.819] SPEAKER_00: 你可以组合大的层。 而且你看不到这些层的内部, 但你可以把线性或卷积层拼在一起。 通常,这正是你想做的。 而在另一个极端, 你可以组合的东西, 是宿主里的数值函数
[1643.899-1656.649] SPEAKER_00: 科学计算库,有加减乘除。 这些都是Autograd这类项目的特性。 还有Fiano和TensorFlow。 为什么要设置这些边界? 是因为开发者们选择 在这些接口提供偏导数。
[1656.729-1670.977] SPEAKER_00: 这就是他们定义API的方式。 这些接口用户不能跨越。 不能通过。 如果你想要这种新接口。 如果你想为左侧类型构建自己的模块。 或中间类型,你得进去构建。 做一个全新模型并实现。 偏导数。
[1671.057-1683.726] SPEAKER_00: 但对于右侧库类型。 你可以组合原语操作构建自己模块。 原语操作。 所以你能发现一个区别。 实际上,这些东西底层怎么实现。 通常这东西是完全密封包装的。
[1683.806-1698.750] SPEAKER_00: 也许他们手动做了整个这东西。 通常中间这些就是包装器。 它们用来包装其他库。 而右边这些通常是 实际上是在实现自动微分。 所以Autograd、Fiano和TensorFlow 都实现了自动微分。 而中间这些正在利用这一点。
[1698.830-1715.133] SPEAKER_00: 来制作更方便的包装器。 所以另一个不同的方面 是这些图是怎么构建的。 所以提醒你,在Autograd中,我们构建这些东西只是 通过实时监听你正在做的事。 并记录下来。 但这不是所有神经网络库的构建方式。 而这是一个轴,我觉得
[1715.213-1729.217] SPEAKER_00: 它们在这个轴上可以明显区分。 所以有很多库构建这些图。 显式地,你说,我要 把这个积木放到那个积木上, 不然我给你YAML规范文件。 图是完全静态的, 那儿没编译器优化机会。
[1729.297-1743.440] SPEAKER_00: 还有即时编译库。 比如Autograd和Chainer。 另一种情况,你得到任意图。 图可以是任何东西。 它会随样本变化。 图的长度由计算决定。 发生在图中。 你几乎没编译器优化机会, 所以速度有时成问题。
[1743.520-1757.617] SPEAKER_00: 中间有预编译库, 比如TensorFlow和Fiano,你用 DSL建图,然后交给运行时, 它们能搞各种骚操作来提速。 问题是,用起来可能很笨拙。 估计被截断了。 用控制流可能很笨拙。 我觉得尴尬是有原因的。
[1757.697-1768.810] SPEAKER_00: 这是处理控制流。 因为这些库操作图类型。 实际上在操控。 所以我们常说计算图。 我们常说数据流图。 数据流图定义很严格。 就是图里节点做计算。
[1768.890-1781.361] SPEAKER_00: 边只是数据。 而且图里没有控制流。 就是数据流图。 静态数据流是一种图类型。 Ennin和Cathay用的,因为所有操作 都是节点,边只是数据。 而且图不能变。 JIT数据流,即时编译的。
[1781.441-1797.360] SPEAKER_00: 像Autograd和Chainer,特征相同。 但图每次迭代都能变。 因为我们会等你算完前向传播。 来构建图。 中间有一种混合体, 我不知该叫它什么图类型, 操作是节点, 边是数据,但有特殊信息, 运行时为了扩展获取的
[1797.440-1810.062] SPEAKER_00: 控制流或循环。 所以Theano的scan就是个例子, Theano运行时拥有特殊信息, 能让scan工作,但这是 与图数据类型协同实现的。 其实还有另一种图类型 自然同时表达控制流和数据流,
[1810.142-1822.869] SPEAKER_00: 我还没见过深度学习库实现过。 它叫C of Nodes,Cliff Click论文里的 在90年代中期。 这似乎很自然值得尝试, 也许将来会有, 但这还是个大问号。 所以你们中有人会试试, 看看效果如何。
[1822.949-1836.291] SPEAKER_00: 其实,这种细粒度处理 有时候会拖慢速度。 如果需要做加法和乘法, 想玩点疯狂操作时,这个挺好。 但如果你明确要搭卷积网络, 为什么不直接跳到左边呢? 比如举个例子,
[1836.371-1854.369] SPEAKER_00: 像 inception 网络,再加一层, 你会想要中间那种类型。 而 AutoGrad 就能做到。 那我简单快速演示三种方式 写个神经网络,然后快速问答。 接着,用完全细粒度的方法, 屏幕上文字很多, 但上半部分主要是让我们 按想要的方式初始化参数。
[1854.449-1871.158] SPEAKER_00: 然后,像之前幻灯片展示的, 我们做一次乘法,一次加法, 再通过非线性函数输出。 并做非线性变换处理。 这个很清楚,对吧? 所以我们打破所有抽象边界, 只用原始操作。 你可以用基于层的方法。 在AutoGrad里,我们有个工具,
[1871.238-1885.207] SPEAKER_00: 用来转换所有神经网络模块, 这些模块很多, 基本涵盖标准深度学习应用。 你可以把它们转成函数, 然后直接用。 对线性参数和输入做线性运算, 再加些激活函数。 这样就能遍历整个神经网络。
[1885.287-1899.384] SPEAKER_00: 所以想用的话,选基于层的方法。 如果你只想要, 想用神经网络,比如 一个前馈网络,我们 有现成的标准模型, 直接就能用。 直接说,给我一个神经网络。 give me a Logsoft max and a loss. and let me glue these guys together.
[1899.464-1913.871] SPEAKER_00: So you can do it any of those three ways. AutoGrad at Twitter has had a pretty cool impact. We use NN for a lot of stuff, and we use AutoGrad as well. But being able to reach for AutoGrad to try something totally crazy, and just knowing that you're going to get the right gradient, is really accelerated the pace of high-risk, potentially
[1913.951-1927.720] SPEAKER_00: high-payoff attempts that we make. So one crazy thing you might want to try is experiment with loss functions. So instead of, I have 100 image classes, and I want to have my convolutional neural network be good at classifying those 100 image classes, maybe you have a taxonomy of classes.
[1927.800-1944.846] SPEAKER_00: Maybe you have a vehicle, and then a bus, a car, and a motorcycle. And if you guess any one of those, you kind of want partial credit for vehicle. 或者猜摩托车,只拿部分分数。 汽车的话。 所以构建这种树损失。 在AutoGrad中非常简单。 而且一次就能搞定。 但其他库做起来更复杂。
[1944.926-1957.351] SPEAKER_00: 你得打破抽象屏障。 自己写偏导数。 重新组合,再用那个模块。 你已经建好的。 我们训练了生产用的AutoGrad模型。 所以它经过实战检验。 在Twitter上跑大量媒体内容。
[1957.431-1971.957] SPEAKER_00: 其实AutoGrad并不重要。 生产运行时, 因为你有函数定义。 用于神经网络预测。 然后梯度部分就消失了。 所以我们放的那些Torch花哨东西。 还有秘密监听函数,这些都只是。 消失了,只剩数字代码。 其实测试时速度完全没损失。
[1972.037-1986.029] SPEAKER_00: 我们有个优化模式, 做编译器相关的工作。 还在进行中。 但对普通模型,它跟NN一样快,有时还更快, 而对非常复杂的内容, 手写代码的话,可能更快。 但用AutoGrad首次拟合模型的时间
[1986.109-1999.834] SPEAKER_00: 大幅减少,因为你不用 不用担心正确性。 所以这段话很长,但 让你了解自动微分领域里 一些我们还没有、但非常渴望的 更快更好训练模型的想法。 首先是检查点。
[1999.914-2017.505] SPEAKER_00: 不是每10次就存模型的检查点, 而是在前向传播时, 迭代次数。 这是检查点,在前向传播时。 反向模式自动微分里,你可能会 你得记住每一步计算的每个细节 因为可能用得上 来计算导数 检查点技术里,直接删掉就行
[2017.585-2029.615] SPEAKER_00: 让它们消失,是因为 觉得有些可能其实 重新算比存起来更容易 比如逐点非线性函数 加载数据后,可能更容易 直接重算ReLU,而不是 保存ReLU结果再重新加载
[2029.695-2042.631] SPEAKER_00: 前向反向混合模式是 你可以想象,对于某种 复杂架构挺重要,虽然我不太 知道影响有多大 所以链式法则里,可以从左到右 或者从中间向外算 想的话,能做各种疯狂的事 但我们其实只做反向模式
[2042.711-2057.110] SPEAKER_00: 菱形图里,计算会往外炸。 然后向内收敛,这可能 利于从正向模式开始。 再以反向模式结束。 沙漏结构中,也许从反向开始, 最后以正向模式结束。 模板是卷积的一种泛化,
[2057.190-2071.612] SPEAKER_00: 计算机图形学里常用。 自动算图像处理里高效导数, 包括常见图像处理 算法,现在正积极研究。 图形学界和计算机视觉领域。 这两篇参考文献很不错。 源到源转换是一种
[2071.692-2086.578] SPEAKER_00: 还没真正流行的方法。 它基本已经沉寂了 大概十年或十五年。 以前黄金标准:拿段代码文本 再输出另一段代码。 我们现在深度学习做的 我们一直在搭建运行时。 我们一直在建领域特定层,它
[2086.658-2097.933] SPEAKER_00: 看你跑代码。 以前你只要读那段文本。 然后像编译器输出梯度。 这是黄金标准。 现在可能不是,但值得再研究。 然后高阶梯度。 所以。 黑塞向量积和基于黑塞的
[2098.013-2111.959] SPEAKER_00: 优化不一定总有回报。 我不记得在学校听过这个。 到现在因为太贵了。 而且难实现,成本太高。 黑塞矩阵就是取f的梯度, 它就给出梯度。 你可能要二阶导数,对吧? 所以取f的梯度的梯度。
[2112.039-2125.277] SPEAKER_00: 所以有高效方法做到这点。 这还是个未解决的问题。 不过库存还有一些。 autograd的Python版很棒。 Diffsharp和Hype也做到了。 所以,最后,你试试看。 它真的很容易。 如果你有Anaconda,又用Python,
[2125.357-2141.648] SPEAKER_00: 我们已经让Lua完全可装了。 通过Anaconda就行。 所以,如果你已经用它,那拿到我今天展示的所有工具 真的非常简单。 而且,跟它交互就一行代码。 有问题,Twitter、邮件或GitHub找我。 我很乐意帮忙。 我很乐意回答你的问题。
[2141.728-2143.539] SPEAKER_00: 你问得很好。 哦,对。
[2143.839-2145.534] SPEAKER_03: 我不确定。
[2145.834-2146.704] SPEAKER_00: 嗨。
[2146.784-2147.933] SPEAKER_00: 我不确定。
[2148.233-2154.978] SPEAKER_05: 嗨。 谢谢。 精彩演讲,感谢! 哦,对。 数据可视化现在怎么样? 跟Python比,Lua工具如何?
[2155.278-2169.955] SPEAKER_00: 说实话,没那么好。 Python在这方面做了五到十年, 积极开发Matplotlib和Seaborn, 还有其他各种库。 Lua这边,我们借用别人成果。 所以用Bokeh.jpg。 这确实是我见过最好的。 而且可以直接在笔记本里用。
[2170.035-2172.484] SPEAKER_00: 所以全套库都能用。 是的。
[2172.784-2179.227] SPEAKER_01: 谢谢你的演讲。 能不能把Torch训练的模型 转成可投产的C模型? 还是必须用自己的模型?
[2179.527-2194.413] SPEAKER_00: 我们直接在生产环境跑Torch。 我们用了个Lua模型。 但你想在C里跑它。所以整个Torch层 实际干活的部分在C里。调用Torch 从C里调,我没有具体网站推荐。 但你可以很轻松地从C调用Lua脚本。
[2194.493-2196.420] SPEAKER_00: 就三四行C代码。
[2196.720-2198.136] SPEAKER_01: 酷。 谢谢。
[2198.436-2210.304] SPEAKER_04: 接着刚才C的问题问一下。 比如我想编译, 我想把Torch集成到C++代码里。 会有什么开销? 开销大吗? 你刚才提到了你自己。 我有一万行的Lua即时编译器 得加进去,对吧?
[2210.384-2216.525] SPEAKER_04: 或者能避免吗? 比如,想想如果我要 把它放到嵌入式系统里,资源非常有限。 资源特别有限。
[2216.825-2228.460] SPEAKER_00: Darren说,推理时我认为, 抱歉,推理时没有 没明显开销,如果我没理解错,你 你导入了Lewis,C代码里你会说Lua 运行Lewis脚本,它会调用其他C代码
[2228.540-2231.546] SPEAKER_00: 我提的autograd开销是训练时的
[2231.846-2237.012] SPEAKER_04: 测试时没有,但问题是,我 仍需把Lua编译到sequel中,对
[2237.312-2247.006] SPEAKER_00: Lua用了15到20年,很成熟,用于 比如微波炉,有嵌入式Lua应用 Lua二进制文件大小,大概 几千字节,很小,一万行代码,编译后
[2247.086-2248.235] SPEAKER_00: 缩得很小
[2248.315-2257.800] SPEAKER_00: 有个推特问题说,我结合用了Keras和 TensorFlow,为啥用torch autograd?你满意,那你知道 那挺好。人们倾向用torch,当想
[2257.880-2268.038] SPEAKER_00: 容易推理性能,更多是 编译器基础设施加入深度学习环境 用户更难,远离最初 库作者,用户更难搞懂为什么慢
[2268.118-2282.725] SPEAKER_00: 这个不工作?之后你可能看到GitHub问题,我的网络 网络很慢,你完成一年后问题就被关闭了 你交付了项目,这些事可能发生,不是谁的错 Torch设计得很薄,就是一个薄层覆盖在 C代码之上,所以如果你关心这个,Torch很棒
[2282.805-2289.353] SPEAKER_00: 去用Torch工作;如果Keras和TensorFlow好用,就继续 深度学习很棒。我试着看看,也许很难
[2289.433-2295.319] SPEAKER_00: 筛选。幻灯片会发布在哪里?这不是深度学习问题,但是 会发布的。这就是答案。
[2295.619-2305.243] SPEAKER_02: 我有个问题。我如何通过……访问?通常所有网络服务 生产中常用FastAPI的Python应用,或者 基于Java的网络服务,对吧?或者通过Android手机,
[2305.323-2310.524] SPEAKER_02: 那也是Java,对吧?那么如何调用Torch训练的模型? Torch中?你如何访问它们?
[2310.824-2323.272] SPEAKER_00: 有几种不同方法。 有几种不同方法。如果你用前馈神经 网络,写Java代码做矩阵乘法很直接, 我们以前这样做过。或者更简单:直接写深度学习 代码,加载权重。我们会序列化它,不管怎么加载。
[2323.352-2331.711] SPEAKER_00: 这是一种方法,有点粗糙短期。在Twitter,我们已设计了 我们在Java里跑Lua虚拟机。 通过JNI通信。 好的。 我们有更永久的方案。
[2331.791-2341.624] SPEAKER_00: 但标准做法是序列化权重。 然后用本地深度学习库加载运行。 经过调试,这方法很公平。 适用于测试和部署间的语言环境限制。
[2341.924-2357.031] SPEAKER_02: 通常就是序列化模型再写代码。 那是另一回事。 我做过很多事,比如模型然后尝试读取。 实际上,关于延迟,这和序列化方式有关。 用那种临时方式序列化,至少能解决延迟。 延迟问题。但有没有计划提供接口?
[2357.111-2363.798] SPEAKER_02: 给其他语言,省去额外步骤。 不用序列化再加载到另一种语言? 如果不这样做,就像你在Twitter有Lua可用。
[2363.878-2370.263] SPEAKER_02: 在Java JVM内通过GNI访问。 这对模型延迟有什么影响? 这些模型的延迟有啥影响?
[2370.563-2376.925] SPEAKER_00: 你说的延迟是交付模型的时间,不是模型运行时间? 是预测的延迟?
[2377.225-2378.699] SPEAKER_02: 基本上是预测。
[2378.999-2390.295] SPEAKER_00: 这取决于工程实现。如果你调用 从C调用Torch,延迟比Lua不明显,而且 那可以很快。如果通过封装,比如JNI 就会有开销,尽量选择
[2390.375-2394.484] SPEAKER_00: 减少开销的接口,即使工程开销更大。 不知道有没有回答你的问题。
[2394.784-2397.872] SPEAKER_02: 你过去有没有看到过数据? 延迟方面的数据?
[2398.172-2404.394] SPEAKER_00: 我离服务器有点远, 所以给不了,不知道。但总的来说, 我们受限于机器学习模型复杂度的延迟。
[2404.474-2410.313] SPEAKER_00: 不受限于开销,比如获取预测的方式, 比如HTTP请求。这就是我的限制。
[2410.613-2417.439] SPEAKER_02: 是的,TensorFlow有TensorFlow Serving,这多少 解决了这个问题。 是的。 有什么意见吗?知道它在说什么吗?
[2417.739-2425.900] SPEAKER_00: 据我所知没有。再说一遍,Torch社区不是中心化的,所以人们 可能正在开发一个很棒的TensorFlow服务器补充方案, 但我对此并不知情。
[2426.200-2427.093] SPEAKER_02: 谢谢。
[2427.393-2431.955] SPEAKER_03: 好的,我们要休息15分钟。再次感谢Alex。
[2432.255-2433.090] SPEAKER_00: 。