对比PyTorch和TensorFlow的自动差异和动态模型

使用自定义模型类从头开始训练线性回归 , 比较PyTorch 1.x和TensorFlow 2.x之间的自动差异和动态模型子类化方法 ,
这篇简短的文章重点介绍如何在PyTorch 1.x和TensorFlow 2.x中分别使用带有模块/模型API的动态子类化模型 , 以及这些框架在训练循环中如何使用AutoDiff获得损失的梯度并从头开始实现 一个非常幼稚的渐变后代实现 。
对比PyTorch和TensorFlow的自动差异和动态模型文章插图
生成噪声的线性数据为了专注于自动差异/自动渐变功能的核心 , 我们将使用最简单的模型 , 即线性回归模型 , 然后我们将首先使用numpy生成一些线性数据 , 以添加随机级别的噪声 。
def generate_data(m=0.1, b=0.3, n=200):x = np.random.uniform(-10, 10, n)noise = np.random.normal(0, 0.15, n)y = (m * x + b ) + noisereturn x.astype(np.float32), y.astype(np.float32)x, y = generate_data()plt.figure(figsize = (12,5))ax = plt.subplot(111)ax.scatter(x,y, c = "b", label="samples")
对比PyTorch和TensorFlow的自动差异和动态模型文章插图
模型然后 , 我们将在TF和PyTorch中实现从零开始的线性回归模型 , 而无需使用任何层或激活器 , 而只需定义两个张量w和b , 分别代表线性模型的权重和偏差 , 并简单地实现线性函数即可:y = wx + b
正如您在下面看到的 , 我们的模型的TF和PyTorch类定义基本上完全相同 , 但在一些api名称上只有很小的差异 。
唯一值得注意的区别是 , PyTorch明确地使用Parameter对象定义权重和要由图形"捕获"的偏置张量 , 而TF似乎在这里更"神奇" , 而是自动捕获用于图形的参数 。
确实在PyTorch参数中是Tensor子类 , 当与Module api一起使用时 , 它们具有非常特殊的属性 , 可以自动将自身添加到Module参数列表中 , 并会出现在在parameters()迭代器中 。
无论如何 , 两个框架都能够从此类定义和执行方法(call或 forward ) , 参数和图形定义中提取信息 , 以便向前执行图形执行 , 并且正如我们将看到的那样 , 通过自动可微分获得梯度功能 , 以便能够执行反向传播 。
TensorFlow动态模型
class LinearRegressionKeras(tf.keras.Model):def __init__(self):super().__init__()self.w = tf.Variable(tf.random.uniform(shape=[1], -0.1, 0.1))self.b = tf.Variable(tf.random.uniform(shape=[1], -0.1, 0.1))def __call__(self,x):return x * self.w + self.bPyTorch动态模型
class LinearRegressionPyTorch(torch.nn.Module):def __init__(self):super().__init__()self.w = torch.nn.Parameter(torch.Tensor(1, 1).uniform_(-0.1, 0.1))self.b = torch.nn.Parameter(torch.Tensor(1).uniform_(-0.1, 0.1))def forward(self, x):return x @ self.w + self.b训练循环 , 反向传播和优化器现在我们已经实现了简单的TensorFlow和PyTorch模型 , 我们可以定义TF和PyTorch api来实现均方误差的损失函数 , 最后实例化我们的模型类并运行训练循环 。
同样 , 本着眼于自动差异/自动渐变功能核心的目的 , 我们将使用TF和PyTorch特定的自动差异实现方式实现自定义训练循环 , 以便为我们的简单线性函数提供渐变并手动优化权重和偏差参数以及临时和朴素的渐变后代优化器 。
在TensorFlow训练循环中 , 我们将特别明确地使用GradientTape API来记录模型的正向执行和损失计算 , 然后从该GradientTape中获得用于优化权重和偏差参数的梯度 。
相反 , 在这种情况下 , PyTorch提供了一种更"神奇"的自动渐变方法 , 隐式捕获了对参数张量的任何操作 , 并为我们提供了相同的梯度以用于优化权重和偏置参数 , 而无需使用任何特定的api 。