- 你好？
好的，它是在12岁之后，所以我想开始吧。
所以今天，第八讲，我们将谈论
深度学习软件。
这是一个非常令人兴奋的话题，因为它发生
每年都很多。
但也意味着要做这个讲座需要做很多工作
因为它每年都会发生很大的变化。
但像往常一样，有几个行政记录
在我们潜入材料之前。
所以提醒你的项目建议
课程项目将于周二到期。
所以希望你们都把它转过来，
希望你们都有一个好主意
你想要做什么样的项目
为了上课。
所以我们正在将TA分配给项目
根据项目区域
以及TA的专业知识。
所以我们会有更多相关信息
在接下来的几天里，我想。
我们也正在评估作业一，
所以请继续关注，我们会把这些等级还给你
我们能尽快。
另一个提醒是，任务二已经出局
一阵子。
这将是下周，即今天，周四的一周。
再次，在完成任务2时，
请记住停止Google Cloud实例
当你不努力保留你的学分。
还有一点困惑，我只是想
再强调的是，对于任务二，你真的
只需要为最后一个笔记本使用GPU实例。
对于所有这几款笔记本来说，它只是在Python中
和Numpy所以你不需要任何GPU来解决这些问题。
再次，保存你的学分，
只在需要时才使用GPU。
最后的提醒是期中考试即将来临。
我们很难相信我们已经在那里，
但是中期将在星期二五点九上课。
所以期中考试将更具理论性。
这将是一种笔和纸在不同的工作
各种各样的理论问题
检查您对我们所用材料的理解
到目前为止。
而且我认为我们可能会发布至少一小部分内容
期待的问题类型的样本。
题？
[学生的话由于缺少麦克风而模糊]
哦，是的，问题是它是否是开卷的，
所以我们要说闭卷，闭书。
所以就，
是的，是的，这就是我们过去所做的
只是封闭的纸币，闭书，相对而言
就像想要检查你明白
我们提出的大部分内容背后的直觉。
所以，快速回顾一下我们正在谈论的内容
关于上次。
上次我们谈到了更高级的优化算法
适用于深度学习模型，包括SGD Momentum，
Nesterov，RMSProp和Adam。
我们看到了这些相对较小的调整
在香草SGD之上，相对容易实现
但可以使您的网络更快收敛。
我们还谈到了正规化，
尤其是辍学。
所以记得辍学，你有点随意设置
在前进过程中网络的部分为零，
然后你有点边缘化了那个噪音
在测试时在后面。
我们看到这是一种普遍的模式
跨越许多不同类型的正规化
在深度学习中，你可以添加某种东西
训练期间的噪音，但然后边缘化
测试时的噪音，所以它不是随机的
在考试时间。
我们还谈到了转学的地方
也许可以下载经过预先​​培训的大型网络
在一些数据集上，然后为你的微调
自己的问题。
这是一种可以解决许多问题的方法
在深度学习中，即使你没有巨大的
你自己的数据集。
所以今天我们要稍微改变一下
并谈谈一些基本要点
关于编写软件以及硬件的工作原理。
还有一点，潜入了很多细节
关于你实际上看起来像什么软件
用来在实践中训练这些东西。
所以我们将谈谈CPU和GPU
然后我们将讨论几个主要的
正在使用的深度学习框架
这些日子。
首先，我们有点提到这个
一堆不同的时代，
计算机有CPU，计算机有GPU。
深度学习使用GPU，但我们并不是真的
关于究竟究竟是什么，这一点过于明确
这些都是为什么一个人可能会更好
对于不同的任务而言。
那么，谁之前建造了一台电脑？
只是一种举手。
所以，大约三分之一的人，你们中的一半，
在那个球场周围的某个地方。
所以这是我家里电脑的一个镜头
我建造的。
你可以看到有很多东西在继续
在电脑里面，也许，希望你知道
大多数这些部分是什么。
CPU是中央处理单元。
这个小芯片隐藏在这个冷却风扇下面
就在这个靠近案件顶部的地方。
而CPU实际上是相对较小的一块。
案件中的内容相对较小。
它没有占用太多空间。
GPU是这两大怪物
这占据了巨大的空间
在这种情况下。
他们有自己的冷却，
他们占据了很大的力量。
它们非常大。
所以，就他们使用的功率而言，
就它们的大小而言，GPU是那样的
身体强壮，占用了大量空间
在这种情况下。
所以问题是这些东西是什么
为什么它们对深度学习如此重要？
那么，GPU被称为显卡，
或图形处理单元。
这些都是真正开发的，最初用于渲染
计算机图形学，尤其是游戏周围
那种事。
这是另一个在家里玩电子游戏的手
有时，他们的电脑上不时有？
是的，再一次，也许大约一半，很好的分数。
对于那些以前玩过电子游戏的人来说
谁建造了自己的电脑，
你可能对这场辩论有自己的看法。
[笑]
所以这是计算机科学的重大争论之一。
你知道，有像英特尔和AMD，
NVIDIA与AMD的显卡相比。
Vim与Emacs一起用于文本编辑器。
几乎所有玩家都有自己的看法
他们更喜欢这两方面
为他们自己的卡。
在深度学习中，我们大多选择了
这场斗争的一面，那就是NVIDIA。
所以，如果你们有AMD卡，
如果你愿意，你可能会遇到更多麻烦
用于深度学习。
实际上，NVIDIA一直在推动深度学习
在过去的几年里。
这是他们的一些战略的重点。
他们在工程方面付出了很多努力
制作硬件的好方法
更适合深度学习。
所以当我们谈论GPU时，大多数人都在深入学习，
我们几乎只谈论NVIDIA GPU。
也许将来这会有所改变，
并且可能会有新玩家上场，
但至少目前NVIDIA占据主导地位。
所以给你一个关于什么是差异的想法
在CPU和GPU之间，我做了一点点
在这里传播表。
在顶部，我们有两种顶级英特尔
消费者CPU，在底部我们有两个
NVIDIA目前的顶级消费级GPU。
这里有一些一般的趋势需要注意。
GPU和CPU都是通用的
他们可以执行程序的计算机器
并做一些任意的指示，
但它们在质量上非常不同。
所以CPU往往只有几个内核，
对于消费者桌面CPU这些天来，
他们可能会有四六个人
或者最多10个核心。
超线程技术意味着它们可以运行，
硬件可以物理运行，就像八个一样
或同时最多20个线程。
所以CPU可以同时并行完成20件事。
所以这不是一个巨大的数字，
但是CPU的那些线程非常强大。
他们实际上可以做很多事情，
他们非常快。
每条CPU指令实际上都可以做很多事情
的东西。
他们都可以独立工作。
对于GPU而言，它有点不同。
所以对于GPU，我们看到了这些常见的高端产品
消费者GPU拥有数千个核心。
那么NVIDIA Titan XP就是目前的
顶级消费者GPU拥有3840个核心。
所以这是一个疯狂的数字。
这就像你将获得的10个核心一样
对于价格相似的CPU。
GPU的缺点是每个核心，
一，它以更慢的时钟速度运行。
还有两个他们真的不能做得那么多。
您无法真正比​​较CPU核心和GPU核心
苹果到苹果。
GPU核心无法真正独立运行。
他们都需要一起工作
并且在多个核心中瘫痪一项任务
而不是每个核心完全做自己的事情。
所以你无法直接比较这些数字。
但它应该给你一种应有的感觉
对于大量的核心GPU可以分类，
非常适合你的并行事物
需要同时做很多事情，
但那些东西几乎都是一样的味道。
在CPU和GPU之间要指出的另一件事
这是记忆的想法。
是的，所以CPU在CPU上有一些缓存，
但这个数量相对较小而且占多数
你的CPU的内存是从你的
系统内存，RAM，也许就像
典型的8个，12个，16个，32个GB的RAM
消费者桌面这些天。
而GPU实际上已经建立了自己的RAM
进入芯片。
有一个相当大的瓶颈沟通
在系统的RAM和GPU之间，
所以GPU通常都有自己的
卡本身内存相对较大的内存块。
而对于Titan XP来说，这也许是目前的情况
顶级消费卡，
这个东西在GPU本地有12千兆字节的内存。
GPU也有自己的缓存系统
哪里有多种缓存层次结构
在12千兆字节的GPU内存之间
和实际的GPU核心。
这有点类似于缓存层次结构
您可能会在CPU中看到。
因此，CPU有利于通用处理。
他们可以做很多不同的事情。
并且GPU可能对这些高度专业化
可瘫痪的算法。
所以有效的东西的原型算法
非常好，非常适合
到GPU是矩阵乘法。
所以请记住左边的矩阵乘法
我们有一个由一堆行组成的矩阵。
我们将右边的数字乘以另一个矩阵组成
一堆列，然后这产生
另一个，最终的矩阵，其中的每个元素
输出矩阵是其中一行之间的点积
和两个输入矩阵的一列。
这些点产品都是独立的。
就像你可以想象的那样，对于这个输出矩阵
你可以完全拆分它
并拥有这些不同的元素
所有输出矩阵都是并行计算的
他们都在运行相同的计算
这是两个向量的点积。
但他们正在从哪里读取数据
来自两个输入矩阵中的不同位置。
所以你可以想象，对于GPU你可以
喜欢爆炸，并拥有所有这些元素
输出矩阵的所有并行计算
这可以使这个东西计算机超级超级快
在GPU上。
所以这就是典型的问题类型
就像GPU非常适合的地方一样
CPU可能必须进入并逐步完成的地方
顺序并计算这些元素中的每一个
逐一。
这张照片有点像漫画，因为
如今的CPU有多个内核，
他们也可以做矢量化指令，
但是，对于这些像大规模并行的问题
GPU往往具有更好的吞吐量。
特别是当这些矩阵变得非常大时。
顺便说一句，卷积是一样的
有点故事。
你在卷积中知道我们有这个输入张量，
我们有这个权重张量，然后是每个点
卷积之后的输出张量又是一些内在的
部分重量之间的乘积
和一些输入的一部分。
你可以想象GPU真的会瘫痪
这个计算，将它分散在众多核心中
并快速计算它。
所以这种类型的一般风味
GPU为您提供巨大的速度优势的问题
超过CPU。
所以你实际上可以编写直接运行的程序
在GPU上。
所以NVIDIA有这个CUDA抽象，可以让你写
代码看起来像C，
但直接在GPU上执行。
但是CUDA代码真的很棘手。
编写CUDA代码实际上非常困难
高效，实际上挤出所有的果汁
这些GPU。
您必须非常小心地管理内存层次结构
并确保您没有缓存未命中
和分支错误预测和所有那些东西。
所以写高性能实际上真的很难
自己的CUDA代码。
因此NVIDIA已经发布了很多库
实现常见的计算原语
它们针对GPU进行了非常高度优化。
例如，NVIDIA有一个实现的cuBLAS库
不同种类的矩阵乘法
以及超级优化的不同矩阵运算
在GPU上运行得非常好，非常接近
理论峰值硬件利用率。
同样，他们有一个实现的cuDNN库
卷积，前进和后退等通行证，
批量标准化，循环网络，
所有这些计算原语
我们需要深入学习。
NVIDIA已经进入并发布了自己的二进制文件
非常有效地计算这些原语
在NVIDIA硬件上。
所以在实践中，你往往不会写自己的
用于深度学习的CUDA代码。
您通常只是主要调用现有的
其他人写的代码。
其中大部分是重要的东西
已经由NVIDIA优化。
还有另一种叫做OpenCL的语言
这有点笼统。
运行的不仅仅是NVIDIA GPU，
可以在AMD硬件上运行，可以在CPU上运行，
但OpenCL，没有人真的花了很多钱
努力和精力试图获得优化的深度学习
OpenCL的原语，因此它往往要少得多
在CUDA中执行超级优化版本。
所以也许将来我们可能会看到一些更开放的东西
标准，我们可能会看到许多不同的
更多类型的平台，但至少现在，
NVIDIA是镇上深度学习的主要游戏。
所以你可以查看，有很多不同的资源
了解如何自己进行GPU编程。
这很有趣。
这是编写代码的不同范例
因为这是一个大规模并行的架构，
但这有点超出了本课程的范围。
而且，你真的不需要自己编写
CUDA代码在实践中用于深度学习。
事实上，我从未编写过自己的CUDA代码
对于任何研究项目，所以，
但知道它是如何工作的有点有用
即使你不是，基本的想法是什么
自己写。
所以如果你想看一下CPU GPU的性能
在实践中，我去年夏天做了一些基准测试
比较一个体面的英特尔CPU
针对一堆排序的不同GPU
当时最接近顶部的。
这些是我自己的基准，你可以找到
关于GitHub的更多细节，但我的发现是这样的
对于像VGG 16和19，ResNets，各种ResNets，
那么你通常会看到像65到75倍的东西
运行完全相同的计算时加速
在GPU顶部，在这种情况下是Pascal Titan X，
而不是顶线，嗯，不是最重要的
CPU，在这种情况下是Intel E5处理器。
虽然，我想在这里提出一个警告
是你总是需要非常小心
每当你阅读任何基准时
关于深度学习，因为它非常容易
不同事物之间不公平。
你需要了解很多细节
究竟是什么正在进行基准测试才能知道
比较是否公平。
所以在这种情况下，我会马上告诉你
可能这种比较有点不公平
到CPU因为我没有花很多精力
试图挤压最大的表现
超出CPU。
我可能可以更好地调整爆破库
对于CPU性能。
我可能已经得到了这些数字
好一点。
这有点开箱即用
只需安装Torch，在CPU上运行它，
只需安装Torch在GPU上运行它。
所以这是一种开箱即用的性能，
但它并不像峰值，可能，理论上的那样
CPU上的吞吐量。
但话虽如此，我认为仍然很漂亮
这里有大幅加速。
这个基准测试的另一种有趣结果
正在比较这些优化的cuDNN库
来自NVIDIA的卷积和诸如此类的对比
有点天真的手工编写的CUDA
在开源社区。
你可以看到，如果你比较相同的网络
在具有相同深度学习的相同硬件上
框架和唯一的区别是交换
这些cuDNN与手工编写，不太优化
CUDA你可以看到近三倍的加速速度
当你从相对位置切换时全面
简单的CUDA就像超级优化的cuDNN一样
实现。
所以一般来说，无论何时在GPU上编写代码，
你可能几乎总是喜欢确保
你正在使用cuDNN，因为你可能正在离开
如果你是的话，桌面上的三倍X性能提升
没有为你的东西调用cuDNN。
所以在实践中出现了另一个问题，
当你训练这些东西的时候
你知道，你的模型可能是坐在GPU上，
模型的权重在12千兆字节
GPU上的本地存储，但是您的大数据集
坐在硬盘上的右边
或SSD或类似的东西。
所以，如果你不小心，你实际上可能会遇到瓶颈
只需尝试读取数据即可完成培训
关闭磁盘。
'因为GPU超快，它可以计算
前进和后退相当快，但如果你正在阅读
顺便关闭一个旋转磁盘，你实际上可以
你的训练瓶颈很大，
这可能真的很糟糕，让你慢下来。
所以这里的一些解决方案就像你知道的那样
如果您的数据集非常小，有时您可能只是
将整个数据集读入RAM。
或者即使您的数据集不是那么小，
但是你有一台拥有大量内存的巨型服务器，
无论如何你可能会这样做。
您还可以确保使用SSD
一个硬盘驱动器，可以帮助大量读取吞吐量。
另一种常见策略是使用多个线程
在CPU上预先从RAM中取出数据
或关闭磁盘，在内存中缓冲它，在RAM中
然后你可以继续向下输送缓冲区数据
到GPU具有良好的性能。
设置有点痛苦，
但同样，这些GPU是如此之快
如果你不小心尝试喂食
他们尽可能快地提供数据，
只是阅读数据有时会遇到瓶颈
整个培训过程。
所以这是需要注意的事情。
这就是喜欢的简短介绍
实际上GPU GPU硬件的实际应用
深入学习。
然后我想换一点齿轮
并谈论软件方面的事情。
人们正在使用的各种深度学习框架
在实践中。
但我想在继续之前，
关于CPU GPU有什么问题吗？
是的，问题？
[学生的话由于缺少麦克风而模糊]
是的，所以问题是你可以做什么，
你在编码的时候可以用机械方式做什么
避免这些问题？
可能是你在软件中可以做的最重要的事情
设置在CPU上预取。
就像你不喜欢的那样，有点天真
你有这个顺序过程吗？
先从磁盘上读取数据，等待数据，
等待读取迷你币，
然后将小批量送到GPU，
然后在GPU上前进和后退，
然后阅读另一个小批量，并做一切
按顺序。
如果你真的有多个，
比如你可能会在中运行CPU线程
从磁盘中提取数据的背景
这样的，而
你可以将所有这些东西交错。
像GPU一样计算，
CPU后台线程正在从磁盘上提供数据
而你的主要线程是等待这些事情，
只是在这些事情之间做一点同步
所以他们都是并行发生的。
谢天谢地，如果你正在使用这些深度学习
我们即将谈论的框架，
然后，一些这项工作已经为你完成了
因为它有点痛苦。
所以深度学习框架的景观
超级快速移动。
所以去年我做这个讲座的时候我主要谈了
关于Caffe，Torch，Theano和TensorFlow。
而且，当我上次在一年多前再次发表这个演讲时，
TensorFlow相对较新。
当时还没有看到过于广泛的采用。
但现在我想在去年的TensorFlow
已经变得更受欢迎了。
它可能是许多人的主要选择框架。
所以这是一个很大的变化。
我们也看到了大量的新框架
有点像去年的蘑菇一样突然出现。
所以特别是Caffe2和PyTorch是新的框架
来自Facebook，我认为非常有趣。
还有很多其他框架。
Paddle，百度有Paddle，微软有CNTK，
亚马逊主要使用MXNet而且还有很多
其他框架，但我不太熟悉，
而且真的没有时间进入。
但是从这张照片中可以指出一件有趣的事情
就是那种第一代深度学习
真正得到广泛采用的框架
是在学术界建造的。
所以Caffe来自伯克利，Torch就是开发出来的
最初是纽约大学，也是与Facebook合作。
Theana主要建在蒙特利尔大学。
但这些下一代深度学习
框架都源于工业。
所以Caffe2来自Facebook，PyTorch来自Facebook。
TensorFlow来自谷歌。
所以这是我们见过的一种有趣的转变
在过去几年的景观中
是这些想法真的移动了很多
从学术界到工业界。
现在，工业界正在给我们这些强大的力量
很好的框架可以使用。
所以今天我想谈谈PyTorch
和TensorFlow因为我个人认为那些
可能是你应该关注的那些
这些天很多研究类型的问题。
我还会谈谈Caffe和Caffe2。
但可能不那么强调那些。
在我们移动得更远之前，我想我应该做
我自己的偏见更明确一点。
所以我主要是，我和Torch一起工作过
在过去的几年里。
而且我已经使用了很多，我非常喜欢它。
然后在去年我大部分都转向了PyTorch
作为我的主要研究框架。
所以我对一些人的经验稍微少一些
这些其他人，特别是TensorFlow，
但我仍然会尽力给你一个公平的
图片和这些东西的体面概述。
所以，请记住在最近几次讲座中
我们已经敲定了计算图的这个想法
一遍又一遍。
无论什么时候你在做深度学习，
你想考虑建立一些计算图
计算你想要计算的任何函数。
因此，对于线性分类器，您将结合使用
您的数据X和权重W与矩阵相乘。
你可能会做某种铰链损失，
计算你的损失。
你将有一些正规化术语
你想象所有这些不同的拼接在一起
操作到一些图形结构。
请记住，这些图形结构可以变得漂亮
在大神经网络的情况下复杂，
现在有很多不同的层，
许多不同的激活。
许多不同的重量四处蔓延
复杂的图形。
当你转向像神经图灵机这样的东西时
那么你可以得到这些非常疯狂的计算图
你甚至不能真正画画，因为他们是
这么大又乱。
所以深度学习框架的重点是，
你可能有三个主要原因
想要使用这些深度学习框架之一
而不只是编写自己的代码。
所以第一个就是这些框架能够实现
你可以轻松地建造和使用这些大毛
计算图无需担心
关于你自己的很多簿记细节。
另一个主要想法是，
每当我们在深度学习的时候
我们总是需要计算渐变。
我们总是计算一些损失，
我们总是计算机梯度的重量
关于损失。
我们想让它自动计算渐变，
你不想自己编写代码。
您希望该框架处理所有这些反向传播
细节，所以你可以考虑一下
写下网络的正向传递
并且有向后传递的免费出来
没有任何额外的工作。
最后，你希望所有这些东西都能高效运行
在GPU上，所以你不必太担心这些
有关cuBLAS和cuDNN的低级硬件详细信息
和CUDA以及在CPU和GPU内存之间移动数据。
你有点想要处理所有那些凌乱的细节
为了你。
所以这些是一些主要原因
为什么你可能会选择使用框架而不是
从头开始写自己的东西。
所以作为计算图的一个具体例子
我们可以写下这个超级简单的事情。
我们有三个输入，X，Y和Z.
我们要将X和Y结合起来制作A.
然后我们将结合A和Z来产生B.
然后我们最终会做一些可能的总结
在B上操作给出一些定标器最终结果C.
所以你可能已经编写了足够多的Numpy代码
意识到写下来非常容易
实现这个计算图，
或者更确切地说，在Numpy中实现这一点计算，
对？
您可以在Numpy中写下您想要的内容
生成一些随机数据，你想要乘以两件事，
你想要添加两件事，你想要总结几件事。
在Numpy中这样做真的很容易。
但问题就像假设我们想要的那样
计算C相对于X，Y和Z的梯度。
所以，如果你在Numpy工作，你需要写出来
这个向后传递自己。
你已经在这方面做了很多练习
作业，但它可能是一种痛苦
一旦你到达，有点烦人和凌乱
真的很复杂的事情。
Numpy的另一个问题是它没有运行
在GPU上。
所以Numpy绝对是CPU。
而你永远无法体验
或利用这些GPU加速的加速
如果你被困在Numpy工作。
而且，再次，必须计算是一件痛苦的事情
在所有这些情况下你自己的渐变。
所以，大多数深度学习框架的目标都是如此
这些天是让你在前进传递中编写代码
看起来和Numpy很相似
但是让你在GPU上运行它
并让您自动计算渐变。
这就是大多数这些的重要目标
构架。
所以，如果你想象一下，如果我们看一个例子
在完全相同的计算图的TensorFlow中，
我们现在看到在这个前进传球中，
你写这个代码看起来非常相似
到了Numpy前锋，你可以在那里做什么
这些乘法和这些加法运算。
但是现在TensorFlow只有这条神奇的线条
为你计算所有的渐变。
所以现在你没有进去写自己的反向传球
这样更方便。
关于TensorFlow的另一个好处是你真的可以
就像一行一样，你可以切换所有这些计算
在CPU和GPU之间。
所以在这里，如果你只是添加声明
在你做这个前锋之前，
你可以明确告诉框架，
嘿，我想在CPU上运行此代码。
但现在，如果我们只是稍微改变一下
在这种情况下，只需更改一个字符，
将C更改为G，现在代码在GPU上运行。
现在在这个小代码片段中，
我们已经解决了这两个问题。
我们在GPU上运行代码
我们正在让框架计算所有的渐变
对我们来说，这真的很好。
PyTorch看起来几乎完全一样。
再说一次，在PyTorch你有点写下来，
你定义了一些变量，
你有一些前锋和前锋传球
看起来非常相似，在这种情况下相同
到Numpy代码。
然后，您可以使用PyTorch进行计算
渐变，所有渐变只有一行。
现在再次在PyTorch中，它很容易切换
对于GPU，你只需要将所有东西都投入到
在您计算计算之前的CUDA数据类型
现在一切都在GPU上透明地运行。
所以如果你只是看看这三个例子，
这三个代码片段并排，
Numpy，TensorFlow和PyTorch
你看到TensorFlow和PyTorch代码
在前锋看起来几乎就像Numpy
这很棒'因为Numpy有一个漂亮的API，
它真的很容易使用。
但我们可以自动计算梯度
我们可以自动运行GPU。
那么介绍之后，
我想潜入并多谈一谈
关于这里发生了什么的详细信息
TensorFlow示例。
所以在整个讲座的其余部分作为一个运行的例子，
我将使用双层完全连接的训练
ReLU网络上的随机数据作为一种运行的例子
在这里的其余示例中。
我们将用L2欧几里德训练这个东西
随机数据丢失。
所以这是一个愚蠢的网络，它并没有真正做到
什么有用的，但它确实给你，
它相对较小，自给自足，
代码适合幻灯片而不是太小，
它可以让你演示很多有用的东西
这些框架内的想法。
所以在右边，哦，然后是另一个音符，
我有点假设Numpy和TensorFlow
已经在所有这些代码片段中导入。
因此，在TensorFlow中，您通常会划分计算
进入两个主要阶段。
首先，我们将编写一些定义的代码
我们的计算图，就是这个红色代码
在上半部分。
然后在定义图形后，
你要一遍又一遍地运行图表
并实际将数据输入图表
执行你想要它执行的任何计算。
所以这才是真的，这有点大
TensorFlow中的常见模式。
你将首先拥有一堆构建图形的代码
然后你会去运行图并重复使用它
很多次。
所以，如果你有点潜入建筑的代码
这种情况下的图表。
在顶部你看到我们正在定义这个X，Y，
w1和w2，我们正在创建这些tf.placeholder对象。
所以这些将成为图形的输入节点。
这些将成为图表的一些入口点
当我们运行图表时，我们将提供数据
并通过我们的这些输入插槽将它们放入
计算图。
所以这实际上并不像分配任何内存
马上。
我们只是设置这些输入槽
到图表。
然后我们将使用现在的那些输入槽
有点像这些象征性变量
我们将执行不同的TensorFlow操作
在这些符号变量上进行设置
我们想要对这些变量运行什么计算。
所以在这种情况下我们正在进行矩阵乘法
在X和w1之间，我们做了一些tf.maximum来做一个
ReLU非线性然后我们正在做另一个
矩阵乘法来计算我们的输出预测。
然后我们再次使用一种基本的Tensor
计算欧几里德距离的操作，
我们的预测和目标Y之间的L2损失。
另一件要指出的是
这些代码行实际上并没有计算任何东西。
目前系统中没有数据。
我们只是建立这个计算图数据
结构告诉TensorFlow哪些操作
我们希望在输入实际数据后最终运行。
所以这只是构建图形，
这实际上并没有做任何事情。
然后我们有了这条神奇的线，经过我们的计算
我们在这些象征性行动中的损失，
然后我们可以问TensorFlow来计算
相对于w1和w2的损失梯度
在这一条神奇，美丽的线条中。
这可以避免您编写所有自己的backprop代码
你必须在作业中做。
但同样，这里没有实际的计算。
这只是添加额外的操作
现在计算的计算图
图表有这些额外的操作，最终会结束
为你计算这些渐变。
所以现在我们已经计算了我们的计算量
图，我们在这个图数据结构中有这个大图
在内存中知道我们想要执行什么操作
计算梯度损失。
现在我们进入一个TensorFlow会话来实际运行
此图表并将其与数据一起提供。
那么，一旦我们进入会议，
那么我们实际上需要构建一些具体的价值观
将被提供给图表。
所以TensorFlow只希望从中接收数据
大多数情况下是Numpy数组。
所以这里我们只是创造具体的实际价值
对于X，Y，w1和w2使用Numpy然后存储它们
在一些字典中。
现在我们在这里实际运行图表。
所以你可以看到我们正在调用session.run
实际执行图的某些部分。
第一个参数丢失，告诉我们图的哪一部分
我们真的想要输出吗？
那，所以我们实际上想要图表，
在这种情况下，我们需要告诉它我们实际上
想要计算损失和grad1和grad w2
我们需要传入这个feed dict参数
将提供给图表的实际具体值。
之后，在这一行中，
它正在运行图表，然后运行计算
损失grad1到grad w2的那些值
然后返回实际的具体值
对于那些在Numpy阵列中的人。
所以现在在第二行解压缩此输出后，
你得到Numpy数组，或者你得到Numpy数组
和渐变。
那么你可以去做任何你想做的事
有这些价值观。
那么，这只是前进和后退的一种
通过我们的图表，
如果我们实际上只需要几行
想要训练网络。
所以我们现在正在运行多次图表
在一个循环中所以我们正在做一个四循环
并且在循环的每次迭代中，
我们正在调用session.run要求它进行计算
损失和渐变。
现在我们正在进行手动梯度调整步骤
使用这些计算的渐变现在更新我们的当前
权重值。
因此，如果您实际运行此代码并绘制损失，
然后你会看到损失下降
并且网络正在进行培训，而且运行良好。
所以这有点像超级骨头的例子
在TensorFlow中培训完全连接的网络。
但这里有一个问题。
所以在这里，请记住前进传球，
每次我们执行此图表时
我们实际上是在喂重量。
我们将权重称为Numpy数组
我们明确地将它们输入图表中。
现在当图表完成执行时
它会给我们这些渐变。
并记住渐变的大小相同
作为权重。
所以这意味着每次我们在这里运行图表，
我们将权重从Numpy数组复制到
然后TensorFlow获得渐变
然后从TensorFlow复制渐变
回到Numpy阵列。
所以，如果你只是在CPU上运行，
这可能不是什么大不了的事，
但请记住，我们谈到了CPU GPU瓶颈
以及如何复制数据实际上非常昂贵
CPU内存和GPU内存之间。
所以，如果你的网络非常大，你的权重
和渐变非常大，
然后做这样的事情会非常昂贵
因为我们要复制各种数据，因此超级慢
每次在CPU和GPU之间来回切换
时间步。
所以这很糟糕，我们不想这样做。
我们需要解决这个问题。
所以，显然TensorFlow有一些解决方案。
而这个想法是，现在我们想要我们的重量，
w1和w2，而不是我们所在的占位符
去，我们希望将它们送入网络
在每个前进传球上，我们将它们定义为变量。
所以变量就是生活在里面的价值
计算图表，它将持续存在
在不同时间的计算图内
当你运行相同的图表。
所以现在不要将这些w1和w2声明为占位符，
相反，我们只是将它们构造为变量。
但现在因为他们住在图表中，
我们还需要告诉TensorFlow他们应该如何
初始化，对吗？
因为在之前的情况下我们正在喂食
他们的价值来自图表外部，
所以我们在Numpy初始化它们，
但现在因为这些东西都在图中，
TensorFlow负责初始化它们。
所以我们需要传入一个tf.randomnormal操作，
这实际上并没有真正初始化它们
当我们运行这一行时，这只是告诉TensorFlow
我们希望如何初始化它们。
所以这是一个令人困惑的错误方向
继续在这里。
现在，请记住上一个例子
我们实际上是在更新外面的重量
计算图。
在前面的例子中，我们计算了渐变
然后使用它们将权重更新为Numpy数组
然后在下一个时间提供更新的权重
时间步。
但现在因为我们希望这些重量能够存在于内部
图表，这个更新权重的操作
也需要在里面进行操作
计算图。
所以现在我们使用了这个变异的赋值函数
这些变量在计算图中
现在，变异值将持续多次运行
同一图表。
所以现在我们运行这个图表
当我们训练网络时，
现在我们需要稍微运行一次图表
特别咒语告诉TensorFlow设置这些
将存在于图表内的变量。
然后，一旦我们完成初始化，
现在我们可以一遍又一遍地运行图表。
在这里，我们现在只提供数据和标签
X和Y以及权重都在图表中。
在这里，我们已经要求网络，
我们已经要求TensorFlow为我们计算损失。
然后你可能会认为这将训练网络，
但实际上这里有一个错误。
那么，如果您实际运行此代码，
而你绘制的损失，它不训练。
这很糟糕，令人困惑，就像正在发生的事情一样？
我们写了这个分配代码，我们运行了这个东西，
就像我们计算损失和梯度一样
我们的损失是平的，发生了什么？
有任何想法吗？
[学生的话由于缺少麦克风而模糊]
是的，所以一个假设是，也许我们是偶然的
每当我们调用图表时重新初始化w。
这是一个很好的假设，实际上不是问题
在这种情况下。
[学生的话由于缺少麦克风而模糊]
是的，所以答案是我们确实需要明确
告诉TensorFlow我们想要运行这些新的w1
和新的W2操作。
所以我们已经建立了这个大的计算图数据
内存中的结构，现在当我们调用run时，
我们只告诉TensorFlow我们想要计算损失。
如果你看看这些不同的依赖关系
图中的操作，
你看到了为了计算损失
我们实际上不需要执行此更新操作。
所以TensorFlow很聪明，它只计算零件
计算输出所必需的图形
你要求它计算。
所以这是一件好事，因为它意味着它是唯一的
尽可能多地完成工作，
但在这种情况下，它可能会有点混乱
并导致你没想到的行为。
因此，在这种情况下的解决方案是我们实际需要
明确告诉TensorFlow执行这些操作
更新操作。
所以我们可以做的一件事就是建议的
我们可以添加新的w1和新的w2作为输出
然后告诉TensorFlow我们想要生产
这些值作为输出。
但这也是一个问题，因为价值观，
那些新的w1，新的w2值再次成为这些大的推动者。
所以现在如果我们告诉TensorFlow我们希望那些作为输出，
我们将再次获得这种复制行为
在CPU和GPU之间进行迭代。
所以这很糟糕，我们不希望这样。
所以你可以做一些小技巧。
这就是我们在图中添加一种虚拟节点。
有了这些假数据依赖
我们只是说这个虚拟节点更新，
具有新w1和新w2的这些数据依赖性。
现在当我们实际运行图表时，
我们告诉它计算损失和这个虚拟节点。
而这个虚拟节点实际上并没有返回
它只返回没有任何值，但正因为如此
我们放入它确保的节点的依赖关系
当我们运行更新值时，
我们实际上也运行这些更新操作。
那么，问题呢？
[学生的话由于缺少麦克风而模糊]
有没有理由我们没有将X和Y放入图表中？
它就像Numpy一样。
所以在这个例子中我们重复使用X和Y，
我们在每次迭代时重复使用相同的X和Y.
所以你是对的，我们可能也只是坚持那些
在图中，但在更现实的情况下，
X和Y将是小批量数据，因此实际上是这些
每次迭代都会改变，我们会想要提供
每次迭代的值都不同。
所以在这种情况下，他们可能留在图中，
但在大多数情况下，他们会改变，
所以我们不希望他们住在图表中。
哦，另一个问题？
[学生的话由于缺少麦克风而模糊]
是的，所以我们告诉它，我们已经投入了TensorFlow
我们想要的输出是丢失和更新。
更新实际上并不是真正的价值。
因此，当更新评估时，它只返回none。
但由于这种依赖性，我们告诉它更新
取决于这些分配操作。
但这些分配操作都存在于内部
计算图和所有内存都在GPU内存中。
那么我们正在进行这些更新操作
完全在GPU上，我们不再复制了
更新的值退出图表。
[学生的话由于缺少麦克风而模糊]
所以问题是tf.group返回没有？
所以这就陷入了TensorFlow的困境。
所以tf.group返回一些疯狂的TensorFlow值。
它有点像内部TensorFlow节点返回
我们需要继续构建图表的操作。
但是当你执行图表时
当你说，在session.run里面，
当我们告诉它时，我们希望它计算出具体的价值
从更新，然后返回没有。
所以每当你使用TensorFlow时
你在构建图表之间有这种有趣的间接性
和构建图形时的实际输出值
是一个有趣的奇怪的对象，然后你真的得到
运行图形时的具体值。
所以在运行更新后，输出为none。
这有点清楚吗？
[学生的话由于缺少麦克风而模糊]
所以问题是为什么损失是一个价值
为什么没有更新？
这就是更新的工作方式。
所以损失是我们计算时的一个值，
当我们告诉TensorFlow我们想要运行一个张量，
然后我们得到具体的价值。
更新是这种特殊的其他数据类型
它不返回值，而是返回none。
所以这里有一些TensorFlow魔法。
如果你仍然感到困惑，也许我们可以脱机谈话。
[学生的话由于缺少麦克风而模糊]
是的，是的，这种行为来自群体方法。
所以现在，我们有这种奇怪的模式
想做这些不同的分配操作，
我们必须使用这个有趣的tf.group的东西。
这真是一种痛苦，谢天谢地，TensorFlow给出了
你做了一些方便的操作
那种东西给你。
这就是一个优化器。
所以这里我们使用的是tf.train.GradientDescentOptimizer
我们告诉它我们想要使用什么学习率。
你可以想象有，有RMSprop，
这里有各种不同的优化算法。
现在我们称为optimizer.minimize of loss
现在这是一个非常神奇的，
这是一个非常神奇的事情，
因为现在这个调用知道了这些变量
w1和w2默认标记为可训练，
所以然后在内部，在这个optimizer.minimize里面
它进入并向图表添加节点
这将计算相关的损失梯度
到w1和w2然后它也执行该更新
为您操作，它正在进行分组操作
为了你，它正在做分配。
就像在里面做很多神奇的东西一样。
但最终它会给你这个神奇的更新价值
如果你挖掘他们实际使用的代码
tf.group所以内部看起来非常相似
我们之前见过。
现在，当我们在循环中运行图形时
我们采用相同的方式告诉它计算损失
和更新。
每当我们告诉图表计算更新时，
那么它实际上会去更新图表。
题？
[学生的话由于缺少麦克风而模糊]
是的，那么tf.GlobalVariablesInitializer是什么？
所以这是初始化w1和w2，因为它们是
生活在图表中的变量。
因此，当我们看到这一点时，我们需要在创建时
tf.variable我们有这个tf.randomnormal
这是初始化所以
tf.GlobalVariablesInitializer正在导致
tf.randomnormal实际运行并生成具体值
初始化这些变量。
[学生的话由于缺少麦克风而模糊]
对不起，问题是什么？
[学生的话由于缺少麦克风而模糊]
所以它知道占位符将被喂食
在图表之外，变量就是这样的
生活在图表中。
所以我不知道它决定的所有细节，
究竟它决定与该调用一起运行。
我认为你需要深入研究代码
那个，或者也许是在某处记录的。
所以，但现在我们有了这个，
我们再次得到了这个训练的完整例子
TensorFlow中的网络，我们正在添加
钟声和口哨使它更方便一点。
所以我们也可以在前面的例子中
我们使用自己的方法明确计算损失
张量操作，TensorFlow你总是可以这样做，
您可以使用基本张量操作来计算
几乎任何你想要的东西。
但TensorFlow也为您提供了一大堆便利
计算这些常见神经网络事物的函数
为了你。
所以在这种情况下我们可以使用tf.losses.mean_squared_error
它只是为我们做了L2损失，所以我们没有
在基本张量操作方面计算它自己。
所以另一种奇怪的是，它有点像
我们不得不明确定义输入
并定义我们的权重，然后将它们链接在一起
在使用矩阵乘法的前向传递中。
在这个例子中，我们实际上没有偏见
在该层，因为这将是一种额外的，
然后我们必须初始化偏见，
我们必须让它们处于正确的形状，
我们必须针对输出广播偏见
矩阵乘以你可以看到那个
会有很多代码。
这会是一种令人烦恼的写作。
一旦你开始喜欢卷积
和批量标准化和其他类型的图层
这种基本的工作方式，
拥有这些变量，具有这些输入和输出
并将它们与基本结合在一起
计算图操作可能有点
笨拙，这可能真的很烦人
确保用右边初始化权重
形状和所有那些东西。
因此，有一堆更高级别
环绕TensorFlow的库
并为您处理其中的一些细节。
所以TensorFlow附带一个例子，
是这个tf.layers里面。
所以现在在这个代码示例中，您可以看到我们的代码
只是明确地声明了X和Y.
哪些是数据和标签的占位符。
现在我们说H = tf.layers.dense，
我们给它输入X，我们告诉它单位= H.
这又是一条神奇的路线
因为在这条线内，它是一种设置
w1和b1，偏见，它为那些设置变量
具有图形内部的正确形状
但有点隐藏我们。
它正在使用这个xavier初始化器对象
为那些设置初始化策略。
所以在我们自己明确这样做之前
与tf.randomnormal业务，
但现在这里处理其中的一些细节
对我们而言，它只是吐出一个H，
这也是我们看到的那种H
在上一层中，它只是做了一些
我们的详细信息。
你可以看到这里，我们也通过了
activation = tf.nn.relu所以它甚至都在激活，
对于我们来说，这层内的relu激活功能。
所以它正在处理很多这些架构
我们的详细信息。
题？
[学生的话由于缺少麦克风而模糊]
问题是xavier初始化程序是否默认
特别分配？
我确定它有一些默认值，我不确定它是什么。
我想你必须看看文档。
但我认为这似乎是一个合理的策略。
事实上，如果你运行这段代码，
它比前一个收敛得快得多
因为初始化更好。
你可以看到我们正在使用两个电话
tf.layers这可以让我们构建我们的模型
没有做所有这些明确的簿记细节
我们自己。
所以这可能更方便一点。
但是tf.contrib.layer真的不是城里唯一的游戏。
有很多不同的高级库
人们建立在TensorFlow之上。
这是因为这种基本的阳痿不匹配
计算图是相对低级的东西，
但是当我们使用神经网络时
我们有层和重量的概念
并且一些层具有与它们相关的权重，
我们通常认为略高一些
抽象比这个原始的计算图。
这就是这些不同的包正在尝试的东西
帮助你，让你在这个更高层工作
抽象。
所以你可能有另一个非常受欢迎的包
之前见过的是Keras。
Keras是一个非常漂亮，漂亮的API，位于顶部
TensorFlow并处理这些构建
你在后端的计算图。
顺便说一下，Keras也支持Theano作为后端，
所以这也很好。
在这个例子中，您可以看到我们构建模型
作为一系列层次。
我们构建了一些优化器对象
我们称之为model.compile，这会带来很多魔力
在后端构建图形。
现在我们可以调用model.fit来完成整个过程
我们神奇的训练程序。
所以我不知道这是如何工作的所有细节，
但我知道Keras非常受欢迎，
所以你可以考虑使用它，如果你在谈论
TensorFlow。
题？
[学生的话由于缺少麦克风而模糊]
是的，所以问题就是为什么没有明确的
CPU，GPU在这里进行。
所以我有点离开了，以保持代码清洁。
但是你在开始时看到的例子
翻过所有这些东西很容易
CPU和GPU之间有一些全局标志
或一些不同的数据类型
或者有些陈述，通常比较简单
并且在每种情况下只需要交换一行。
但究竟是什么样的线
根据情况略有不同。
所以实际上就像这整个大集
您可能会看到更高级别的TensorFlow包装器
在野外。
而且似乎就像谷歌内部的人一样
不能真正同意哪一个是正确的使用者。
所以Keras和TFLearn是第三方图书馆
其他人在互联网上。
但是有这三种不同的，
tf.layers，TF-Slim和tf.contrib.learn
这一切都与TensorFlow一起出货，这些都是
做一个略有不同的版本
更高层次的包装物。
谷歌还有另一个框架，
但是TensorFlow没有名为Pretty Tensor
做同样的事情。
我猜这些对DeepMind来说都不够好，
因为他们几周前就开始了
并写下并发布了他们自己的高级别
TensorFlow包装器叫Sonnet。
如果你有点困惑，我不会嫉妒你
通过所有这些事情。
有很多不同的选择。
他们并不总能很好地相互配合。
但是你有很多选择，所以这很好。
TensorFlow有预训练模型。
在TF-Slim和Keras中有一些例子。
因为记住重新训练的模型非常重要
当你训练自己的东西时。
Tensorboard也有这个想法
在哪里你可以加载你的，
我不想深入了解细节，
但Tensorboard你可以添加一些仪器
你的代码，然后绘制损失和事情
当你完成培训过程。
TensorFlow也让你运行分布式
你可以在哪里打破计算图
在不同的机器上运行。
这太酷了，但我想可能不是任何人
谷歌以外的人真的用它来取得巨大的成功
这些天，但如果你想运行分布式的东西
可能TensorFlow是镇上的主要游戏。
一个侧面说明是很多TensorFlow的设计
在早期的框架中受到精神启发
从蒙特利尔叫Theano。
我不想在这里详细介绍
如果你自己浏览这些幻灯片，
你可以看到Theano的代码最终看起来
与TensorFlow非常相似。
在我们定义一些变量的地方
我们做了一些前向传球，我们计算了一些渐变，
然后我们编译一些函数，然后运行函数
一遍又一遍地训练网络。
所以它看起来很像TensorFlow。
所以我们还有很多东西需要通过，
所以我要继续前往PyTorch
也许最后会提问。
所以，来自Facebook的PyTorch有点不同
TensorFlow，我们有三种显式
PyTorch中不同的抽象层。
所以PyTorch有这个张量对象就像一个
Numpy数组。
它只是一个命令式阵列，它什么都不知道
关于深度学习，但它可以用GPU运行。
我们有这个变量对象，它是一个节点
构建计算图的计算图，
让你计算渐变，这种事情。
我们有一个模块对象，它是一个神经网络
您可以将这些模块组合在一起的图层
建立大型网络。
所以如果你想要考虑粗略的等价物
在PyTorch和TensorFlow之间你可以想到
PyTorch张量作为履行相同的角色
作为TensorFlow中的Numpy数组。
PyTorch变量类似于TensorFlow张量
或变量或占位符，它们都是各种节点
在计算图中。
现在PyTorch模块有点等同
来自tf.slim或tf.layers的更高级别的东西
或十四行诗或其他更高级别的框架。
所以关于PyTorch就要注意一件事
是因为它带有这种高级抽象
并且喜欢一个非常好的高级抽象
单独称为模块，有一点选择
参与其中。
坚持使用nnmodules，你会很高兴。
您不必担心哪个更高级别的包装器
使用。
因此，正如我所说，PyTorch张量就像Numpy数组一样
所以在右边我们已经完成了整个两层网络
完全使用PyTorch张量。
需要注意的一点是，我们不会在这里导入Numpy
完全没了。
我们正在使用PyTorch张量进行所有这些操作。
这段代码看起来与两层网络代码完全相同
你在Numpy写的第一个作业。
因此，您设置一些随机数据，您使用一些操作
计算前向传球。
然后我们明确地查看了向后传球
我们自己。
只是通过网络进行反向购物，
通过操作，就像你在做作业一样。
现在我们正在手动更新权重
使用学习率并使用我们的计算梯度。
但是PyTorch张量之间的主要区别
和Numpy数组是他们在GPU上运行
所以你需要做的就是让这个代码运行起来
GPU使用不同的数据类型。
而不是使用torch.FloatTensor，
你做了torch.cuda.FloatTensor，投了你所有的张量
到这个新的数据类型，一切都神奇地运行
在GPU上。
您应该将PyTorch张量视为Numpy和GPU。
这正是它的本质，没有什么特别的
深入学习。
所以PyTorch中的下一层抽象是变量。
一旦我们从张量变为变量，这就是这个
现在我们正在构建计算图
我们可以自动获取渐变
以及那样的一切。
所以在这里，如果X是一个变量，那么x.data就是一个张量
和x.grad是另一个包含渐变的变量
关于那个张量的损失。
所以x.grad.data是一个包含的实际张量
那些渐变。
PyTorch张量和变量具有完全相同的API。
因此，任何适用于PyTorch张贴的代码都可以
改为使用变量并运行相同的代码，
除了现在你正在建立一个计算图
而不仅仅是做这些必要的操作。
所以在这里我们创建这些变量
每次调用变量构造函数都会包装一个PyTorch
张量然后还给出一个标志是否
我们想要计算这个变量的渐变。
现在在前进传球看起来很像
在张量的情况下它在变量之前做过
因为他们有相同的API。
所以现在我们正在计算我们的预测，
我们正在计算我们在这种必要条件下的损失
一种方式。
然后我们称之为loss.backwards，现在所有这些渐变
为我们出来。
然后我们可以进行渐变更新步骤
使用现在存在的渐变来衡量我们的重量
在w1.grad.data中。
所以这最终看起来很像Numpy案，
除了所有的渐变都是免费的。
有一点需要注意，两者之间有所不同
PyTorch和TensorFlow是TensorFlow案例中的
我们正在构建这个显式图，
然后多次运行图表。
在PyTorch中，我们正在构建一个新的图形
每次我们做前锋传球。
这使得代码看起来更清晰。
它还有其他一些含义
稍等一下。
所以在PyTorch中你可以定义自己的新自动编程功能
通过在张量方面定义前向和后向。
这最终看起来有点像模块层
你为家庭作业写的代码二。
你可以在哪里实现前进和后退使用
张量操作然后把这些东西粘在里面
计算图。
所以我们在这里定义自己的relu
然后我们可以进入并使用我们自己的relu
操作，现在把它放在我们的计算图中
并以这种方式定义我们自己的操作。
但大多数时候你可能不需要
定义自己的autograd操作。
大多数时候你需要的操作都会
大多数已经为您实施。
所以在TensorFlow中我们看到了，
如果我们能够转向像Keras或TF.Learn这样的东西
这为我们提供了更高级别的API，
而不是这个原始的计算图。
PyTorch中的等价物是nn包。
它提供这些高级包装工作
有了这些东西。
但与TensorFlow不同的是，只有其中一个。
它运作得很好，所以如果你是的话，就这样使用它
使用PyTorch。
所以在这里，这最终看起来像Keras
我们将模型定义为一些层序列。
我们的线性和relu操作。
我们使用nn包中定义的一些损失函数
这是我们的平均误差损失。
现在在循环的每次迭代中
我们可以通过模型向前运行数据来获取
我们的预测。
我们可以通过损失函数向前运行预测
得到我们的规模或损失，
然后我们可以调用loss.backward，获得我们所有的渐变
免费然后循环遍历模型的参数
并做我们明确的梯度下降步骤来更新
模特。
我们再一次看到我们正在构建这个
每次我们进行前向传球时都会有新的计算图。
就像我们在TensorFlow中看到的那样，
PyTorch提供了这些优化器操作
这种更新逻辑的那种抽象
并实现像Adam这样的更高级的更新规则
等等。
所以我们在这里构建一个优化器对象
告诉它我们希望它优化
模型的参数。
在超参数下给它一些学习率。
现在我们计算了渐变之后
我们可以调用optimizer.step并更新它
我们这里的模型的所有参数。
所以你在PyTorch中会做另一件常见的事情
很多是定义你自己的nn模块。
所以通常你会写自己的课
它将整个模型定义为单个模型
新的nn模块类。
而模块只是一种神经网络层
可以包含其他任何模块
或可训练的重量或其他类型的状态。
所以在这种情况下我们可以重做两层网络示例
通过定义我们自己的nn模块类。
所以现在在这个类的初始化器中
我们分配这个linear1和linear2。
我们正在构建这些新的模块对象
然后将它们存储在我们自己的类中。
现在在前进传球中我们可以使用我们自己的传球
内部模块以及任意自动编程操作
用于计算网络输出的变量。
所以我们在这里收到了这个前进方法，
输入充当变量，
然后我们将变量传递给self.linear1
对于第一层。
我们使用autograd op clamp来完成relu，
我们将其输出传递给第二个线性
然后这给了我们输出。
现在剩下的这段代码用于训练这个东西了
看起来几乎一样。
我们在哪里构建优化器并循环遍历
并且在迭代时将数据提供给模型，
用损失计算梯度。向后，
call optimizer.step。
所以这就像是比较有特色的
您可能会在很多PyTorch类型中看到的内容
训练场景。
在哪里定义自己的类，
定义包含其他模块的自己的模型
什么，然后你有一些明确的培训
这样循环运行它并更新它。
你有一种很好的生活品质
在PyTorch中是一个数据加载器。
因此，数据加载器可以为您处理构建小型微型计算机。
它可以处理我们谈到的一些多线程
关于你，它实际上可以使用多个线程
在后台为您建立许多批次
并流出磁盘。
所以这里的数据加载器包装数据集并提供
其中一些抽象适合你。
在实践中，当您想要运行自己的数据时，
您通常会编写自己的数据集类
它知道如何读取您的特定数据类型
关闭你想要的任何来源然后把它包起来
数据加载器和训练。
所以，在这里我们可以看到现在我们正在迭代
dataloader对象和每次迭代
这正在产生小批量的数据。
它在内部处理数据的混乱
和多线程数据加载以及所有这些东西
为了你。
所以这是一个完全PyTorch的例子
很多PyTorch培训代码最终都在寻找
这样的事情。
PyTorch提供预训练模型。
这可能是最简单的预训练模型
我见过的经验。
你只需说torchvision.models.alexnet pretained = true。
那将在后台下载，下载预训练
如果你还没有它们的重量，
然后它就在那里，你很高兴去。
所以这非常容易使用。
PyTorch也有，还有一个名为Visdom的软件包
这使您可以看到这些损失统计信息中的一些
有点类似于Tensorboard。
所以这很好，我实际上并没有得到
有机会自己玩这个，所以我不能真的
说它有多有用，
但是Tensorboard之间的主要区别之一
和Visdom是Tensorboard实际上让你可视化
计算图的结构。
这真的很酷，是一个非常有用的调试策略。
而Visdom还没有这个功能。
但我自己从来没有真正使用过这个，所以我真的不能
说实用。
作为一点点，PyTorch是一种进化，
一种旧框架的更新版本
叫Torch，我在最后一次工作了很多
许多年。
我不想在这里详细介绍
但PyTorch在很多方面都要好得多
比旧的Lua Torch，但他们实际上分享了很多
用于使用张量计算的相同后端C代码
和张量上的GPU操作等等。
所以，如果你看看这个火炬的例子，
其中一些最终看起来与PyTorch类似，
其中一些有点不同。
也许你可以通过这个离线。
但是那种高层次的差异
Torch和PyTorch是Torch实际上在Lua，
不是Python，不像其他东西。
所以学习Lua对某些人来说有点关闭。
火炬没有autograd。
火炬也比较老，所以它更稳定，
不太容易受到错误的影响，可能还有更多示例代码
对于火炬。
他们的速度差不多，这并不是真正的问题。
但是在PyTorch中，它在Python中很棒，
你有autograd，这使它更简单
写复杂的模型。
在Lua Torch你最终写了很多自己的东西
有时回到道具代码，这有点烦人。
但PyTorch更新，现有代码更少，
它仍然有可能改变。
所以这是一次冒险。
但至少对我来说，我更喜欢，
我自己并没有太多理由
此时不再使用Torch而不是PyTorch。
所以我几乎只使用PyTorch
这几天我所有的工作。
我们对这个想法进行了一些讨论
静态图与动态图。
这是主要的区别特征之一
在PyTorch和TensorFlow之间。
所以我们在TensorFlow中看到你有这两个阶段
首先你建立这个的操作
计算图，然后运行计算图
一遍又一遍地重复使用同样的东西
图形。
这就是所谓的静态计算图
只有其中一个。
我们看到PyTorch与我们实际上完全不同
建立这个新的计算图，
每一个前进传球都有这个全新的东西。
这被称为动态计算图。
对于一些简单的案例，有一种前馈
神经网络，它并没有真正产生巨大的差异，
代码最终有点类似
他们的工作方式类似，
但我想谈谈一些影响
静态与动态。
这两者的权衡是什么？
所以静态图是一种好主意
是因为我们有点建立一个
计算图一次，然后多次重复使用，
框架可能有机会进入
并对该图进行优化。
并且有些操作融合，重新排序一些操作，
找出最有效的运作方式
该图表因此可以非常有效。
因为我们要重用那个图表
很多时候，也许是优化过程
前面很贵，
但我们可以通过加速来摊销这个成本
当我们多次运行图表时我们已经得到了。
作为一个具体的例子，
也许你写一些有卷积的图表
和relu操作一个接一个，
你可能会想象一些花哨的图优化器
可以进入并实际输出，就像发出自定义代码一样
它融合了操作，融合了卷积
而relu所以现在它正在计算同样的事情
作为你写的代码，但现在可能是
执行得更有效率。
所以我对实际状态究竟是什么并不太确定
TensorFlow图优化现在是，
但至少在原则上，这是一个地方
静态图真的，你可以有潜力
在静态图中进行此优化
也许它对于动态图表来说不那么容易处理。
另一种关于静态与动态的微妙观点
这是序列化的想法。
因此，使用静态图可以想象你写的
这段代码构建了图表
然后，一旦你建立了图表，
你在内存中有这个数据结构代表
整个网络结构。
现在您可以采用该数据结构
并将其序列化为磁盘。
现在你已经拥有了整个网络结构
保存在某个文件中。
然后你可以后来装载那件东西
然后运行该计算图而无需访问
到构建它的原始代码。
所以这在部署方案中会很好。
你可能会想到你可能想训练你的
Python中的网络，因为它可能更容易使用，
但是在你序列化那个网络之后呢
然后你可以在C ++中部署它
您不需要使用原件的环境
构建图形的代码。
所以这是静态图的一个很好的优势。
而使用动态图，因为我们是交错的
这些图形构建和图形执行的过程，
你总是需要原始代码
如果你想在将来重用该模型。
另一方面，动态图的一些优点
这是有道理的，它只是使你的代码
在很多情况下，更清洁，更轻松。
例如，假设我们想要做一些事情
条件操作，取决于值
一些变量Z，我们想做不同的操作
计算Y.
如果Z为正，我们想要使用一个权重矩阵，
如果Z为负，我们想要使用不同的权重矩阵。
我们只是想在这两种选择之间切断。
在PyTorch中，因为我们使用的是动态图，
它非常简单。
您的代码看起来与您期望的完全一样，
你在Numpy会做什么
您可以使用普通的Python控制流程
处理这件事。
而现在因为我们每次都在构建图表，
每次我们执行此操作都需要一个
这两条路径中的一条可能会形成不同的图形
在每个前进传球上，但对于我们所做的任何图表
最终建立，我们可以通过它传播
正好。
而且代码非常干净，易于使用。
现在在TensorFlow中，情况会更多一些
很复杂因为我们构建了一次图表，
这种控制流操作员需要这样
TensorFlow图中的显式运算符。
现在，所以他们可以看到我们有这个
tf.cond调用，有点像TensorFlow版本
一个if语句，但现在已经融入了
计算图而不是使用
Python控制流程。
问题是因为我们只构建图形
曾经，所有潜在的控制途径都是如此
我们的程序可能需要被烘焙
在我们构建它之前的时间里进入图形
运行。
这意味着任何一种控制流操作员
你想要的不是Python控制流
操作员，你需要使用某种魔法，
特殊张量流操作来做控制流程。
在这种情况下，这个tf.cond。
如果你愿意，会发生另一种类似的情况
有循环。
所以假设我们想要计算某种经常性的
可能Y T等于YT减去1的关系
加上XT乘以一些权重矩阵W并依赖于
每次我们这样做，每次我们计算这个，
我们可能有不同大小的数据序列。
无论我们的数据序列的长度如何，
我们只想计算相同的递归关系
无论输入序列的大小。
所以在PyTorch中这非常简单。
我们可以在Python中使用普通的for循环
只是循环我们想要的次数
展开，现在取决于输入数据的大小，
我们的计算图最终会变成不同的大小，
但那很好，我们可以反过来传播
每一个，一次一个。
现在在TensorFlow中，这变得有点丑陋。
而且，因为我们需要构建图形
在前面，这个控制流循环结构
再次需要是TensorFlow图中的显式节点。
所以我希望你能记住你的函数式编程
因为你必须使用那些类型的运算符
在TensorFlow中实现循环结构。
所以在这种情况下，对于这种特殊的复发关系
你可以使用foldl操作并传入，
根据foldl实现这个特定的循环。
但这基本上意味着你有这种感觉
TensorFlow几乎建立了自己的整体
编程语言，使用的语言
计算图。
和任何类型的控制流操作员，
或者需要滚动任何类型的数据结构
进入计算图，所以你无法真正利用
你迫切需要的所有工作范例
在Python中。
你需要重新学习一整套
控制流操作员。
如果你想做任何种类的控制流程
使用TensorFlow在计算图中。
所以至少对我来说，我发现那种令人困惑的，
有时候我有点难以绕开
我有点像使用PyTorch动态图，
你可以使用你最喜欢的命令式编程
构造，这一切都很好。
顺便说一句，实际上有一些非常新的库
称为TensorFlow Fold，这是另一个
TensorFlow顶部的图层可让您实现
动态图表，您可以编写自己的代码
使用TensorFlow Fold看起来有点像动态
图操作然后TensorFlow Fold做了一些魔术
对于你而言，以某种方式实现了这一点
静态TensorFlow图。
这是一篇正在呈现的超级新论文
ICLR本周在法国举行。
所以我没有机会喜欢潜水和玩耍
还有这个。
但我最初的印象是它确实增加了一些
TensorFlow的动态图形数量仍然存在
与本地人一样，工作有点尴尬
你在PyTorch中拥有的动态图表。
那么，我认为激励可能会很好
为什么我们一般会关心动态图？
因此，一种选择是循环网络。
所以你可以看到像图像字幕之类的东西
我们使用经常运行的经常性网络
不同长度的序列。
在这种情况下，我们想要生成的句子
因为标题是序列，序列可以变化
取决于我们的输入数据。
所以现在你可以看到我们在这件事上有这种活力
根据句子的大小，
我们的计算图可能需要更多
或更少的元素。
这是动态图的一种常见应用。
对于那些上季度参加CS224N的人，
你看到了这种递归网络的想法
有时在自然语言处理中
例如，您可以计算已解析的树
一个句子然后你想要一个神经
网络类的递归操作在这个解析树上。
所以有一个神经网络，那种工作，
它不仅仅是一个连续的层序列，
但相反，它有点像一些图表
或树结构而不是现在每个数据点
可能有不同的图形或树结构
所以计算图的结构
然后有点镜像输入数据的结构。
它可能因数据点而异。
所以这类事情看起来有点复杂
使用TensorFlow实现毛茸茸，
但是在PyTorch中你可以使用它
像普通的Python控制流一样，它会运行起来
正好。
另一点更具研究性的应用就是这个
我喜欢的很酷的想法叫做神经模块网络
用于视觉问题回答。
所以这里的想法是我们想问一些问题
关于我们可能输入此图像的图像
对猫狗来说，有一些问题，
猫是什么颜色，然后是内部系统
可以阅读问题，并有这些不同
用于执行的专用神经网络模块
寻求颜色和寻找猫等操作。
然后根据问题的文字，
它可以编译这个自定义架构进行回答
这个问题。
现在，如果我们问一个不同的问题，
就像有更多的猫比狗？
现在我们可能有相同的基本模块集
做的事情，比如寻找猫和狗，计数，
但他们按照不同的顺序排列。
所以我们在不同的数据点再次获得这种活力
可能会产生不同的计算图。
但这更像是一件研究性的事情
现在也许不是那么主流。
但作为一个更大的点，我认为有
人们很多很酷的创意应用
可以用动态计算图
也许现在没有那么多，
只是因为和他们一起工作太痛苦了。
所以我认为有很多机会
做一些很酷，有创意的事情
动态计算图。
也许如果你想出很酷的想法，
我们将在明年的演讲中展示它。
所以我想简单谈谈Caffe
这是伯克利的这个框架。
哪个Caffe与另一个有些不同
深度学习框架，在许多情况下你
你可以在没有写作的情况下训练网络
任何代码你自己。
你只需要调用这些预先存在的二进制文件，
在许多情况下设置一些配置文件
您可以在不编写任何自己的代码的情况下训练数据。
所以，你可能是第一个，你转换你的数据
像HDF5或LMDB这样的格式存在
Caffe中的一些脚本可以像转换一样
图像和文本文件的文件夹为您提供这些格式。
您需要定义，而不是编写代码
定义计算图的结构，
而是编辑一些称为原型文本的文本文件
它建立了计算图的结构。
这里的结构是我们从一些输入中读取的
HDF5文件，我们执行一些内部产品，
我们计算一些损失和整个结构
图表的设置在此文本文件中。
这里的一个缺点是这些文件
对于非常大的网络来说可能会变得非常难看。
所以对于像152层ResNet模型这样的东西，
那顺便就是在Caffe训练的，
那么这个原型文件文件最终会长达7000行。
所以人们不是手写这些。
人们有时会喜欢编写python脚本
生成这些原型文件。
[笑声]
然后，你在滚动你自己的领域是善良的
计算图形抽象。
这可能不是一个好主意，但我之前见过。
然后，而不是有一些优化器对象，
相反，有一些求解器，你定义一些求解器的东西
在另一个原型文件中。
这定义了你的学习率，
你的优化算法和诸如此类的。
一旦你做了所有这些事情，
你可以用train命令运行Caffe二进制文件
这一切都神奇地发生了。
卡菲有一个带有一系列预训练模型的模型动物园，
这非常有用。
Caffe有一个Python接口，但它不是超级的
有据可查。
你需要阅读python的源代码
界面看它能做什么，
所以这有点烦人。
但它确实有效。
所以，关于Caffe的一般事情就是它
也许对前馈模型有好处，
这对生产场景可能有好处，
因为它不依赖于Python。
但是这些天可能用于研究，我见过Caffe
使用可能少一点。
虽然我认为它仍然很常用
在工业再次生产。
我保证在Caffe 2上有一张幻灯片，一张或两张幻灯片。
所以Caffe 2是来自Facebook的Caffe的继任者。
它是超级新的，它只在一周前发布。
[笑声]
所以我真的没有时间组建超级
关于Caffe 2的教育观点，
但它使用类似于TensorFlow的静态图。
有点像Caffe，核心是用C ++编写的
他们有一些Python界面。
不同的是，现在你不再需要了
编写自己的Python脚本以生成原型文件。
您可以定义计算图结构
所有在Python中，看起来像一个看起来的API
有点像TensorFlow。
但是你可以吐出来，你可以序列化这个
计算图形结构到原型文件。
然后，一旦你的模型被训练，诸如此类的，
然后我们得到了我们谈到静态的这个好处
您可以使用图表，不需要原件
现在训练代码以部署训练有素的模型。
所以有趣的是你见过谷歌
也许有一个主要的深度运行框架，
这是TensorFlow，Facebook有这两个，
PyTorch和Caffe 2。
所以这些都是不同的哲学。
谷歌试图建立一个统治框架
它们可能适用于所有可能的场景
深入学习。
这很好，因为它巩固了所有的努力
在一个框架上。
这意味着你只需要学习一件事
它将适用于许多不同的场景
包括像分布式系统，生产，
部署，移动，研究，一切。
只需要学习一个框架来完成所有这些事情。
Facebook采取了一些不同的方法。
PyTorch真的更专业，
更多的是面向研究，所以在写作方面
研究代码并快速迭代您的想法，
这在PyTorch中非常容易，但对于像
在生产中运行，在移动设备上运行，
PyTorch没有太多的支持。
相反，Caffe 2更倾向于那些
面向生产的用例。
所以我的一般学习，我的一般，总体建议
关于使用哪个框架来解决哪些问题
两种都是，
我认为TensorFlow是一个非常安全的选择
你想要开始新的任何项目，对吧？
因为它是一种统治它们的框架，
它几乎可以用于任何情况。
但是，您可能需要将它与a配对
更高级别的包装器，如果你想要动态图形，
你可能运气不好
一些代码最终看起来有点丑陋
在我看来，但也许这是一种美容细节
这并不重要。
我个人认为PyTorch非常适合研究。
如果你专注于编写研究代码，
我认为PyTorch是一个很好的选择。
但它有点新，社区支持较少，
更少的代码，所以它可能是一个冒险。
如果你想要更好的踩踏路径，TensorFlow
可能是一个更好的选择。
如果您对生产部署感兴趣，
你应该看看Caffe，Caffe 2或TensorFlow。
如果你真的专注于移动部署，
我认为TensorFlow和Caffe 2都内置了一些
对此的支持。
所以不幸的是，不仅如此
一个全球最佳框架，它有点依赖
在你真正想要做的事情上，
您预期的应用程序，但论文有点
我对这些事情的一般建议。
所以下次我们将讨论一些案例研究
关于各种CNN架构。