
嗨,habrozhiteli! 这本书为进一步掌握深度学习技术奠定了基础。 它从描述神经网络的基础开始,然后详细研究其他体系结构级别。
本书是专门为提供尽可能低的入门阈值而编写的。 您不需要线性代数,数值方法,凸优化甚至机器学习的知识。 您将逐步了解了解深度学习所需的所有内容。
我们为您提供熟悉“什么是深度学习框架?”的文章。
好的工具可以减少错误,加快开发速度,并提高执行速度。如果您阅读了很多有关深度学习的文章,您可能会遇到诸如PyTorch,TensorFlow,Theano(最近被淘汰),Keras,Lasagne和DyNet等著名框架。 在过去的几年中,框架发展非常迅速,尽管所有这些框架都是免费和开源的,但每个框架都具有竞争和友善的精神。
到目前为止,我一直没有讨论框架,因为首先,对于您而言,了解幕后发生的事情,手动实现算法(仅使用NumPy库)非常重要。 但是现在我们将开始使用这样的框架,因为我们要训练的网络,具有长期短期记忆(LSTM)的网络非常复杂,并且使用NumPy实现它们的代码很难读取,使用和调试(此代码中的梯度随处可见)。
深度学习框架旨在解决这种复杂性。 深度学习框架可以显着降低代码的复杂度(并减少错误数量并提高开发速度)并提高其执行速度,尤其是如果您使用图形处理器(GPU)训练神经网络,则可以将处理速度提高10到100倍。 由于这些原因,这些框架几乎在研究社区中得到了广泛使用,并且对于您的用户和深度学习研究者的职业生涯,了解框架的功能将对您很有用。
但是我们不会将自己局限于任何特定框架的框架,因为这将阻止您学习所有这些复杂模型(例如LSTM)的工作方式。 相反,我们将根据框架开发的最新趋势创建自己的轻量级框架。 遵循这条路径,您将确切知道在框架的帮助下创建复杂框架时将执行的操作。 此外,尝试自己创建自己的小型框架将有助于您平稳地转换为使用真正的深度学习框架,因为您已经了解组织程序接口(API)及其功能的原理。 这项练习对我非常有用,并且在创建自己的框架时获得的知识对于调试有问题的模型非常有帮助。
框架如何简化代码? 抽象地说,它消除了一次又一次编写相同代码的需要。 具体来说,深度学习框架最方便的功能是支持自动反向传播和自动优化。 这使您仅可以编写直接分配代码,框架将自动处理反向分配和权重校正。 大多数现代框架甚至简化了实现直接分发的代码,提供了用于定义典型层和损失函数的高级接口。
张量介绍
张量是向量和矩阵的抽象形式在此之前,我们使用向量和矩阵作为主要结构。 让我提醒您,矩阵是向量的列表,向量是标量(单个数字)的列表。 张量是一种抽象形式,用于表示数字的嵌套列表。 向量是一维张量。 矩阵是二维张量,具有大量维的结构称为n维张量。 因此,让我们开始通过定义基本类型(我们称为Tensor)来创建新的深度学习框架:
import numpy as np class Tensor (object): def __init__(self, data): self.data = np.array(data) def __add__(self, other): return Tensor(self.data + other.data) def __repr__(self): return str(self.data.__repr__()) def __str__(self): return str(self.data.__str__()) x = Tensor([1,2,3,4,5]) print(x) [1 2 3 4 5] y = x + x print(y) [2 4 6 8 10]
这是我们基本数据结构的第一个版本。 请注意,它将所有数值信息存储在NumPy数组(self.data)中,并支持单个张量运算(加法)。 添加其他操作一点也不难,只需将具有相应功能的其他功能添加到Tensor类中即可。
自动梯度计算简介(autograd)
以前,我们执行手动反向传播。 现在让我们使其自动!在第四章中,我们介绍了导数。 从那时起,我们就在每个新的神经网络中手动计算了这些导数。 让我提醒您,这是通过神经网络的反向移动来实现的:首先,计算网络输出处的梯度,然后将这个结果用于计算前一分量中的导数,依此类推,直到为架构中的所有权重确定正确的梯度为止。 这种用于计算梯度的逻辑也可以添加到张量类中。 下面显示了我的想法。
import numpy as np class Tensor (object): def __init__(self, data, creators=None, creation_op=None): self.data = np.array(data) self.creation_op = creation_op self.creators = creators self.grad = None def backward(self, grad): self.grad = grad if(self.creation_op == "add"): self.creators[0].backward(grad) self.creators[1].backward(grad) def __add__(self, other): return Tensor(self.data + other.data, creators=[self,other], creation_op="add") def __repr__(self): return str(self.data.__repr__()) def __str__(self): return str(self.data.__str__()) x = Tensor([1,2,3,4,5]) y = Tensor([2,2,2,2,2]) z = x + y z.backward(Tensor(np.array([1,1,1,1,1])))
此方法引入了两个创新。 首先,每个张量接收两个新属性。 creators是用于创建当前张量的所有张量的列表(默认为None)。 也就是说,如果张量z是通过将其他两个张量x和y相加而获得的,则张量z的creators属性将包含张量x和y。 creation_op是一个伴随属性,用于存储在创建此张量的过程中使用的操作。 也就是说,指令z = x + y将创建一个具有三个节点(x,y和z)和两个边(z-> x和z-> y)的计算图。 每个边都由creation_op中的操作(即添加)签名。 此图将帮助组织渐变的递归反向传播。
此实现中的第一个创新是在每个数学运算过程中自动创建图形。 如果取z并执行其他运算,则该图将在引用z的新变量中继续。
此版本的Tensor类的第二项创新是使用图形计算梯度的能力。 如果调用z.backward()方法,则会考虑到创建z(加)张量的函数,将传递x和y的渐变。 如上面的示例所示,我们将梯度向量(np.array([1,1,1,1,1]])传递给z,然后将其应用于其父级。 您可能从第4章还记得,通过加法进行的反向传播意味着应用反向传播。 在这种情况下,我们只能将一个渐变添加到x和y,因此我们将其从z复制到x和y:
print(x.grad) print(y.grad) print(z.creators) print(z.creation_op) [1 1 1 1 1] [1 1 1 1 1] [array([1, 2, 3, 4, 5]), array([2, 2, 2, 2, 2])] add
这种自动梯度计算形式的最显着特征是它可以递归工作-每个向量从self.creators列表中调用其所有父级的.backward()方法:
»这本书的更多信息可以
在出版商的网站上找到»
目录»
摘录小贩优惠券25%-
深度学习支付纸质版本的书后,就会通过电子邮件发送电子书。