PyTorch实战(3)——PyTorch vs. TensorFlow详解

    • 0. 前言
    • 1. 张量
    • 2. PyTorch 模块
      • 2.1 torch.nn
      • 2.2 torch.optim
      • 2.3 torch.utils.data
    • 3. 使用 PyTorch 训练神经网络
    • 小结
    • 系列链接

0. 前言

PyTorch 是一个基于 Torch 库的 Python 机器学习库,广泛用于深度学习的科研和应用开发,主要由 Meta 开发。PyTorch 是另一个知名深度学习库 TensorFlow (由 Google 开发)的有力竞争者,最初,这两者的主要区别在于,PyTorch 基于即时执行 (eager execution),而 TensorFlow 1.x 基于图计算的延迟执行 (deferred execution),但现在 TensorFlow2.x 也提供了即时执行模式。
即时执行基本上是一种命令式编程模式,在这种模式下,数学操作会立即计算。而延迟执行模式会将所有操作存储在计算图中,不立即计算,直到构建完成才对整个图进行评估。即时执行的优势在于其直观的流程、易于调试以及更少的辅助代码。
PyTorch 通过类似 NumPy 的语法/接口,提供了张量计算能力,并能利用 GPU 实现加速计算。张量是计算单元,类似于 NumPy 数组,不同之处在于张量可以在 GPU 上使用,以加速计算。
凭借加速计算能力和创建动态计算图,PyTorch 提供了一个完整的深度学习框架。除此之外,它具有真正的 Python 风格,使 PyTorch 用户能够充分利用 Python 的所有特性,包括丰富的 Python 数据科学生态系统。
在本节中,我们将深入探讨张量的概念及其在 PyTorch 中的实现方式,以及张量具有的属性。我们还将了解一些常用的 PyTorch 模块,这些模块扩展了数据加载、模型构建以及训练过程中优化算法的功能。我们将这些 PyTorch APITensorFlow 的对应功能进行对比,以了解两者在底层实现上的差异。

1. 张量

张量 (Tensor) 的概念类似于 NumPy 数组。张量是一个 nnn 维数组,我们可以对其执行数学函数、通过 GPU 加速计算,还可以跟踪计算图和梯度,这些功能对深度学习至关重要。为了在 GPU 上运行张量,只需将张量转换为特定的数据类型即可。

(1) 使用 PyTorch 实例化一个张量:

points = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])

(2) 获取第一个元素:

points[0]

(4) 查看张量的形状:

points.shape

(5) 使用 TensorFlow 声明一个张量:

points_tf = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0])

访问第一个元素或获取张量形状的命令与 PyTorch 相同。

(6)PyTorch 中,张量是对存储在连续内存块中的一维数组的视图,这些数组称为存储实例。每个 PyTorch 张量都有一个 untyped_storage() 属性,可以调用它来输出张量的底层存储实例:

points = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
points.untyped_storage()

输出结果如下所示:

输出结果

TensorFlow 张量没有 untyped_storage() 属性。PyTorch 张量是存储实例的视图,张量使用以下信息来实现该视图:

  • 大小 (Size)
  • 存储 (Storage)
  • 偏移量 (Offset)
  • 步长 (Stride)

这些信息的含义如下:

  • size 类似于 NumPy 中的 shape 属性,表示每个维度上的元素数量:
    points.size()
    
    这些数字的乘积等于底层存储实例的长度(本例中为 6):
    torch.Size([3, 2])
    
  • storage:底层存储实例
  • offset:张量的第一个元素在存储数组中的索引
  • stride:表示在每个维度上移动一个元素所需的步长

TensorFlow 中,张量的形状可以通过使用 shape 属性获取:

points_tf = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
points_tf.shape

输出结果如下所示:

TensorShape([3, 2])

我们已经了解了 PyTorch 张量的 untyped_storage() 属性,接下来我们看看偏移量 (offset):

points.storage_offset()

输出结果如下所示:

0

offset 表示张量的第一个元素在存储数组中的索引。由于输出为 0,这意味着张量的第一个元素是存储数组的第一个元素。使用以下代码进行验证:

points[1].storage_offset()

输出结果如下所示:

2

因为 points[1][3.0, 4.0],而存储数组是 [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]],可以看到张量中的第一个元素 [3.0, 4.0],在存储数组中的索引位置为 2
接下来,查看 stride 属性:

points.stride()

输出结果如下所示:

(2, 1)

可以看到,stride 属性表示在每个维度上访问下一个元素需要跳过的元素数量。因此,在以上例子中,沿着第一个维度,若要访问第一个元素之后的元素(即 1.0),我们需要跳过 2 个元素(即 1.02.0),才能访问下一个元素,即 3.0。类似地,沿着第二个维度,我们需要跳过 1 个元素,才能访问 1.0 之后的元素,即 2.0。因此,使用这些属性,张量可以从一个连续的一维存储数组中推导出来。TensorFlow 张量并没有 stridestorage_offset 属性。

(7) 张量中包含的数据是数值类型的。具体来说,PyTorch 提供了以下几种数据类型供张量使用:

  • torch.float32torch.float32 位浮点数
  • torch.float64torch.double64 位双精度浮点数
  • torch.float16torch.half16 位半精度浮点数
  • torch.int8 — 有符号 8 位整数
  • torch.uint8 — 无符号 8 位整数
  • torch.int16torch.short — 有符号 16 位整数
  • torch.int32torch.int — 有符号 32 位整数
  • torch.int64torch.long — 有符号 64 位整数

TensorFlow 也提供了类似的数据类型。

(8)PyTorch 中,可以使用 dtype 属性为张量指定特定数据类型:

points = torch.tensor([[1.0,2.0],[3.0,4.0]], dtype=torch.float16)

TensorFlow 中,可以通过以下等效代码实现:

points_tf = tf.constant([[1.0,2.0],[3.0,4.0]], dtype=tf.float16)

(9) 除了数据类型,PyTorch 中的张量可以指定存储设备:

points = torch.tensor([[1.0,2.0],[3.0,4.0]], dtype=torch.float16, device='cuda')

我们也可以在目标设备上创建张量的副本:

points_2 = points.to(device='cuda')

从以上示例可以看出,我们可以将张量分配到 CPU (使用 device='cpu'),如果不指定设备,默认情况下会分配到 CPU,也可以将张量分配给 GPU (使用 device='cuda')。在 TensorFlow 中,可以使用以下方式分配设备:

with tf.device('/gpu:0'):points_tf = tf.constant([[1.0,2.0],[3.0,4.0]], dtype=tf.float16)

PyTorch 支持 NVIDIA (CUDA) 和 AMD GPU

当张量被放置在 GPU 上时,计算速度会显著加快,并且由于 PyTorch 中的张量 APICPUGPU 张量间基本一致,因此可以很方便的在设备之间移动张量、执行计算并移回。
如果有多个相同类型的设备,比如多个 GPU,我们可以通过设备索引精确指定张量放置的设备:

points_3 = points.to(device='cuda:0')

接下来,我们将介绍一些用于构建深度学习模型的重要 PyTorch 模块。

2. PyTorch 模块

PyTorch 库不仅提供了类似 NumPy 的计算功能,还提供了一系列模块,帮助开发者快速设计、训练和测试深度学习模型。

2.1 torch.nn

在构建神经网络架构时,网络的基本组成要素包括层数、每层的神经元数量,以及哪些神经元是可学习的等。PyTorchnn 模块允许用户通过定义这些高层次特性快速实例化神经网络架构,而不需要手动指定所有的细节。如果不使用 nn 模块,需要使用以下方式进行单层神经网络初始化:

import math
weights = torch.randn(256, 4) / math.sqrt(256)
weights. requires_grad_()
bias = torch.zeros(4, requires_grad=True)

而使用 nn 模块,nn.Linear(256, 4) 就可以实现相同的功能。在 TensorFlow 中,可以使用以下方式实现:

tf.keras.layers.Dense(256, input_shape=(4, ), activation=None)

torch.nn 模块中,有一个 torch.nn.functional 子模块,包含了 torch.nn 模块中的所有函数,包括损失函数、激活函数,以及用于以函数式方式创建神经网络的函数(即将每一层表示为前一层输出的函数),例如池化、卷积和线性函数。使用 torch.nn.functional 模块定义损失函数:

import torch.nn.functional as F
loss_func = F.cross_entropy
loss = loss_func(model(X), y)

其中,X 是输入,y 是目标输出,model 是神经网络模型。在 TensorFlow 中,上述代码可以写成:

import tensorflow as tf
loss_func = tf.keras.losses.SparseCategoricalCrossentropy()
loss = loss_func(y, model(X))

2.2 torch.optim

在训练神经网络时,我们通过反向传播调整网络的权重或参数,这一过程称为优化。optim 模块包含了与训练深度学习模型时运行各种优化算法相关的工具和功能。
使用 torch.optim 模块在训练过程中定义优化器:

opt = optim.SGD(model.parameters(), lr=lr)

如果,我们手动编写优化步骤:

with torch.no_grad():for param in model.parameters():param -= param.grad * lrmodel.zero_grad()

使用优化器可以简洁地写成如下形式:

opt.step()
opt.zero_grad()

TensorFlow 不需要显式地编写梯度更新和清除步骤,使用优化器代码如下:

opt = tf.keras.optimizers.SGD(learning_rate=lr)
model.compile(optimizer=opt, loss=loss)

2.3 torch.utils.data

utils.data 模块下,PyTorch 提供了 DatasetDataLoader 类,这些类因其抽象且灵活的实现而非常实用,这些类提供了直观的方式来迭代数据和其他操作。通过使用这些类,我们可以确保高性能的张量计算,并实现可靠的数据输入/输出。可以通过以下方式使用 torch.utils.data.DataLoader

from torch.utils.data import TensorDataset, DataLoader
train_dataset = TensorDataset(x_train, y_train)
train_dataloader = DataLoader(train_dataset, batch_sise)

使用这种方式,我们就不需要手动遍历数据批次:

for i in range((n-1)//bs + 1):x_batch = x_train[start_i:end_i]y_batch = y_train[start_i:end_i]pred = model(x_batch)

我们可以简单地写成:

for x_batch, y_batch in train_dataloader:pred = model(x_batch)

torch.utils.data 类似于 TensorFlow 中的 tf.data.Dataset。在 TensorFlow 中,遍历数据批次的代码如下:

train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataloader = train_dataset.batch(bs)
for x_batch, y_batch in train_dataloader:pred = model(x_batch)

我们已经了解了 PyTorch 库,并了解了 PyTorch 的张量。接下来,我们将学习如何使用 PyTorch 训练神经网络。

3. 使用 PyTorch 训练神经网络

在本节中,我们将使用 MNIST 数据集,该数据集包含手写邮政编码数字( 09 )的图像及其对应的标签。MNIST 数据集包含 60000 个训练样本和 10000 个测试样本,每个样本都是一张 28x28 像素的灰度图像。PyTorchDataset 模块中提供了 MNIST 数据集。我们将使用 PyTorchMNIST 数据集上训练一个深度学习多类分类器,并测试训练后的模型在测试样本上的表现。

(1) 首先,导入所需库:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transformsimport matplotlib.pyplot as plt

(2) 接下来,定义模型架构,如下图所示:

模型架构

该模型由卷积层、Dropout 层以及线性(全连接)层组成,这些层都可以通过 torch.nn 模块实现:

class ConvNet(nn.Module):def __init__(self):super(ConvNet, self).__init__()self.cn1 = nn.Conv2d(1, 16, 3, 1)self.cn2 = nn.Conv2d(16, 32, 3, 1)self.dp1 = nn.Dropout(0.10)self.dp2 = nn.Dropout(0.25)self.fc1 = nn.Linear(4608, 64) # 4608 is basically 12 X 12 X 32self.fc2 = nn.Linear(64, 10)def forward(self, x):x = self.cn1(x)x = F.relu(x)x = self.cn2(x)x = F.relu(x)x = F.max_pool2d(x, 2)x = self.dp1(x)x = torch.flatten(x, 1)x = self.fc1(x)x = F.relu(x)x = self.dp2(x)x = self.fc2(x)op = F.log_softmax(x, dim=1)return op

__init__ 函数定义了模型的核心架构,forward 函数执行网络的前向传播,它包括了每层的激活函数以及池化或 Dropout 操作,函数返回模型的最终输出(即预测值),其维度与目标输出(真实标签)相同。
第一个卷积层的输入通道为 1 (灰度图像),输出通道为 16,卷积核大小为 3,步幅为 1。输入通道为 1 是因为输入图像是灰度图,选择 3x3 的卷积核基于以下原因:

  • 卷积核的大小通常是奇数,以便输入图像的像素围绕中心像素对称分布
  • 1x1 的卷积核太小,无法捕捉相邻像素的信息
  • 3x3 是计算机视觉问题中最常用的卷积核大小之一,因为它能够捕捉局部视觉特征

不选择 57 或者 27 是由于当卷积核的大小过大时,比如 27x27,在 28x28 的图像上卷积,会得到非常粗略的特征。然而,图像中的最重要视觉特征通常是局部的(在较小的空间邻域内),因此使用一个小卷积核逐步查看邻近像素来提取视觉模式更为合理。3x3CNN 中解决计算机视觉问题时最常用的卷积核大小之一。
需要注意的是,我们使用两个连续的卷积层,两个卷积层的卷积核大小都是 3x3。从空间覆盖的角度来看,这相当于使用一个 5x5 的卷积核进行一次卷积。然而,通常更倾向于使用多个小卷积核的层,因为这样可以构建更深的网络,从而学习到更复杂的特征,同时,由于卷积核较小,参数也较少。通过在多个层中使用多个小卷积核,会得到专门检测不同特征的卷积核——例如有些用于检测边缘,有些用于检测圆形,有些用于检测红色等。
第一个卷积层输入的是单通道数据,输出 16 个通道。这意味着该层正在尝试从输入图像中提取 16 种不同类型的信息。每个输出通道称为特征图,每个特征图都有一个专门的卷积核来提取其对应的特征。
第二个卷积层中将通道数从 16 增加到 32,旨在从图像中提取更多种类的特征。卷积层输出通道设计通常遵循先增加后减小的原则。
本节中,我们将步幅 (stride) 设置为 1,因为卷积核大小仅为 3。如果步幅值过大,卷积核会跳过图像中的许多像素,这不利于特征提取。如果卷积核大小是 100,那么可能会考虑将步幅设置为 10。步幅越大,卷积操作的次数越少,卷积核的视野 (field of view) 也会越小。
以上代码也可以使用 torch.nn.Sequential API 来编写:

model = nn.Sequential(nn.Conv2d(1, 16, 3, 1),nn.ReLU(),nn.Conv2d(16, 32, 3,1 ),nn.ReLU(),nn.MaxPool2d(2),nn.Dropout(0.1),nn.Flatten(),nn.Linear(4068, 64),nn.ReLU(),nn.Dropout(0.25),nn.Linear(64, 10),nn.LogSoftmax(dim=1)
)

通常推荐通过单独的 __init__forward 方法来初始化模型,以便在模型层并非顺序执行(例如并行或跳跃连接)时,能够更灵活地定义模型功能。使用 Sequential 的代码与使用 TensorFlow 非常相似:

import tensorflow as tf
model = tf.keras.Sequential([tf.keras.layers.Conv2D(16, 3, activation='relu', input_shape=(28, 28, 1)),tf.keras.layers.Conv2D(32, 3, activation='relu'),tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),tf.keras.layers.Dropout(0.1),tf.keras.layers.Flatten(),tf.keras.layers.Dense(64, activation='relu'),tf.keras.layers.Dropout(0.25),tf.keras.layers.Dense(10, activation='softmax')
])

而使用 __init__forward 方法的代码在 TensorFlow 中如下:

class ConvNet(tf.keras.Model):def __init__(self):super(ConvNet, self).__init__()self.cn1 = tf.keras.layers.Conv2D(16, 3, activation='relu', input_shape=(28, 28, 1))self.cn2 = tf.keras.layers.Conv2D(32, 3, activation='relu')self.dp1 = tf.keras.layers.Dropout(0.10)self.dp2 = tf.keras.layers.Dropout(0.25)self.flatten = tf.keras.layers.Flatten()self.fc1 = tf.keras.layers.Dense(64, activation='relu')self.fc2 = tf.keras.layers.Dense(10, activation='softmax')def call(self, x):x = self.cn1(x)x = self.cn2(x)x = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(x)x = self.dp1(x)x = self.flatten(x)x = self.fc1(x)x = self.dp2(x)x = self.fc2(x)return x

TensorFlow 中,使用 call 方法代替 forward,其余部分与 PyTorch 代码类似。

(3) 接下来,定义训练过程,即实际的反向传播步骤。可以看到,torch.optim 模块极大地简化了代码:

def train(model, device, train_dataloader, optim, epoch):model.train()for b_i, (X, y) in enumerate(train_dataloader):X, y = X.to(device), y.to(device)optim.zero_grad()pred_prob = model(X)loss = F.nll_loss(pred_prob, y) # nll is the negative likelihood lossloss.backward()optim.step()if b_i % 10 == 0:print('epoch: {} [{}/{} ({:.0f}%)]\t training loss: {:.6f}'.format(epoch, b_i * len(X), len(train_dataloader.dataset),100. * b_i / len(train_dataloader), loss.item()))

train() 函数以批次遍历数据集,将数据复制到指定设备上,通过神经网络模型进行前向传播,计算模型预测值与真实标签之间的损失,使用优化器调整模型权重,并每 10 个批次打印一次训练日志。整个过程执行一次称为一个 epoch,即完整遍历一次数据集对于 TensorFlow,我们可以直接以高级方式直接运行训练。PyTorch 中详细的训练过程定义使我们能够更灵活地控制训练过程,而不是用一行高级代码完成训练。

(4) 与训练过程类似,编写一个测试过程,用于评估模型在测试集上的表现:

def test(model, device, test_dataloader):model.eval()loss = 0success = 0with torch.no_grad():for X, y in test_dataloader:X, y = X.to(device), y.to(device)pred_prob = model(X)loss += F.nll_loss(pred_prob, y, reduction='sum').item()  # loss summed across the batchpred = pred_prob.argmax(dim=1, keepdim=True)  # us argmax to get the most likely predictionsuccess += pred.eq(y.view_as(pred)).sum().item()loss /= len(test_dataloader.dataset)print('\nTest dataset: Overall Loss: {:.4f}, Overall Accuracy: {}/{} ({:.0f}%)\n'.format(loss, success, len(test_dataloader.dataset),100. * success / len(test_dataloader.dataset)))

test() 函数的大部分内容与 train() 函数类似。唯一的区别是,计算出的模型预测与真实标签之间的损失不会用来调整模型权重,而是用于计算整个测试批次的总体测试误差。

(5) 接下来,加载数据集。得益于 PyTorchDataLoader 模块,我们可以方便的设置数据集加载机制:

train_dataloader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1302,), (0.3069,))])), # train_X.mean()/256. and train_X.std()/256.batch_size=32, shuffle=True)test_dataloader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1302,), (0.3069,)) ])),batch_size=500, shuffle=False)

可以看到,我们将批大小 batch_size 设置为 32。通常,批大小的选择需要权衡:太小的批大小会导致训练速度变慢,因为需要频繁计算梯度,且梯度噪声较大;太大的批大小也会因等待梯度计算时间过长而减慢训练速度。通常不建议等待太长时间才进行一次梯度更新,更频繁但精度较低的梯度更新最终会引导模型学习到更好的参数。
对于训练集和测试集,我们指定了数据集保存的存储位置,并且设置了批大小,批大小决定了每次训练和测试运行中数据实例的数量。此外,我们还随机打乱训练数据实例,以确保数据样本在各个批次中均匀分布。
最后,将数据集归一化,使其符合具有指定均值和标准差的正态分布。如果我们从零开始训练模型,那么均值和标准差来自于训练数据集,如果我们是从一个预训练模型进行迁移学习,那么均值和标准差值将来自于预训练模型的原始训练数据集。
TensorFlow 中,我们可以使用 tf.keras.datasets 来加载 MNIST 数据,并使用 tf.data.Dataset 模块从数据集中创建训练数据批次:

# Load the MNIST dataset.
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() # Normalize pixel values between 0 and 1
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0# Add a channels dimension (required for CNN)
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]# Create a dataloader for training.
train_dataloader = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataloader = train_dataloader.shuffle(10000)
train_dataloader = train_dataloader.batch(32)# Create a dataloader for testing.
test_dataloader = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataloader = test_dataloader.batch(500)

(6) 定义优化器和设备,使用它们运行模型训练:

device = torch.device("cuda")model = ConvNet().to(device=device)
optimizer = optim.Adadelta(model.parameters(), lr=0.5)

在本节中,使用 Adadelta 作为优化器,学习率设置为 0.5。我们在介绍优化器时提到,如果我们处理的是稀疏数据,选用 Adadelta 可以得到不错的结果。MNIST 数据集就是一个稀疏数据的例子,因为并非图像中的所有像素都具有信息量。但我们也可以尝试其他优化器,如 Adam,来解决这个问题,观察不同优化器对训练过程和模型性能的影响。在 TensorFlow 中,可以使用以下等效代码实例化并编译模型:

model = ConvNet()
optimizer = tf.keras.optimizers.experimental.Adadelta(learning_rate=0.5)
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])

(7) 然后开始实际的模型训练过程,训练多个 epoch,并在每个训练 epoch 结束时测试模型:

for epoch in range(1, 3):train(model, device, train_dataloader, optimizer, epoch)test(model, device, test_dataloader)

训练过程输出结果如下所示:

模型训练

TensorFlow 中的训练循环等效代码如下:

model.fit(train_dataloader, epochs=2, validation_data=test_dataloader)

(8) 模型训练完成后,我们可以手动检查模型在样本图像上的推理结果是否正确:

test_samples = enumerate(test_dataloader)
b_i, (sample_data, sample_targets) = next(test_samples)plt.imshow(sample_data[0][0], cmap='gray', interpolation='none')
plt.show()

输出结果如下所示:

输出结果

TensorFlow 中的等效代码基本相同,唯一不同的是使用 sample_data[0] 而不是 sample_data[0][0]

test_samples = enumerate(test_dataloader)
b_i, (sample_data, sample_targets) = next(test_samples)
plt.imshow(sample_data[0], cmap='gray', interpolation='none')
plt.show()

将图像输入训练后的模型,运行模型推理,并比较预测结果与真实标签:

print(f"Model prediction is : {model(sample_data.to(device=device)).data.max(1)[1][0]}")
print(f"Ground truth is : {sample_targets[0]}")

需要注意的是,对于预测,首先使用 max() 函数在 axis=1 轴上计算概率最大的类别。max() 函数会输出两个列表——sample_data 中每个样本的类别概率列表和每个样本的类别标签列表。因此,我们使用索引 [1] 选择第二个列表(即类别标签列表),并通过索引 [0] 进一步选择第一个类别标签,以查看 sample_data 中的第一个样本。输出结果如下所示:

Model prediction is : 7
Ground truth is : 7

可以看到,得到了正确的预测结果。神经网络的前向传播通过 model() 完成,会得到类别概率。因此,我们使用 max() 函数输出最大概率对应的类别。在 TensorFlow 中,可以使用以下代码获取预测结果:

print(f"Model prediction is : {tf.math.argmax(model(sample_data)[0])}")
print(f"Ground truth is : {sample_targets[0]}")

小结

在本节中,我们比较了 PyTorchTensorFlow 两大深度学习库,并在模型训练的不同阶段(模型初始化、数据加载、训练循环和模型评估)分析了 PyTorchTensorFlowAPI 差异,最后,作为实践分别使用 PyTorchTensorFlow 从零开始训练了一个深度学习模型。

系列链接

PyTorch实战(1)——深度学习概述
PyTorch实战(2)——使用PyTorch构建神经网络
PyTorch实战(4)——卷积神经网络(Convolutional Neural Network,CNN)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94954.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94954.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94954.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在win服务器部署vue+springboot + Maven前端后端流程详解,含ip端口讲解

代码打包与基本配置 首先配置一台win系统服务器,开放你前端和后端运行的端口,如80和8080 前端打包 前端使用vue3,在打包前修改项目配置文件,我使用的是vite所以是vite.config.js。 import { defineConfig } from vite import …

Springcloud-----Nacos

一、Nacos的安装 Nacos是阿里推出的一种注册中心组件,并且已经开源,目前是国内最为流行的注册中心组件。下面我们来了解一下如何安装并启动Nacos。 Nacos是一个独立的项目,我们可以去GitHub上下载其压缩包来使用,地址如下&#x…

腾讯云重保流程详解:从预案到复盘的全周期安全防护

摘要 腾讯云针对国家级重大活动(如进博会、冬奥会等)提供的网络安全保障服务(重保)是一套系统化的主动防御体系。本文从“事前准备”“事中响应”“事后复盘”三个核心阶段出发,结合民生银行等典型用户的实战案例&…

单表查询-group by rollup优化

1、group by rollup基本用法 我们有时候在项目上看到group by rollup用法,其实就是对group by分组进行合计。 下面看一下例子 select count(1),c3 from t1 group by rollup(c3); 计划从计划中解读亦是如此,另外可以从结果上进行分析第21行的count其实就是…

云网络(参考自腾讯云计算工程师认证)

计算机网络:OSI七层模型: 应用层:负责处理网络应用程序之间的通信、 表示层:负责数据的格式化和加密、 会话层:负责建立、管理和终止会话、 传输层:负责端到端的可靠传输、 网络层:负责数据的路…

【MLLM】多模态理解Ovis2.5模型和训练流程(更新中)

note 模型架构:延续 Ovis 系列创新的结构化嵌入对齐设计。 Ovis2.5 由三大组件构成:动态分辨率 ViT 高效提取视觉特征,Ovis 视觉词表模块实现视觉与文本嵌入的结构对齐,最后由强大的 Qwen3 作为语言基座,处理多模态嵌…

mysql中的通用语法及分类

MySQL 是一种广泛使用的关系型数据库管理系统(RDBMS),其语法设计遵循 SQL 标准,但也有一些特有的扩展。以下从​​通用语法规范​​和​​SQL 语句分类​​两个维度系统梳理 MySQL 的核心语法体系。一、MySQL 通用语法规范通用语法…

Linux-搭建NFS服务器

Linux-搭建NFS服务器前言一、网络配置二、在nfs服务器上安装nfs-utils软件包三、设置共享目录四、挂载NFS共享目录前言 NFS(Network File System,网络文件系统) 是一种分布式文件系统协议,最初由 Sun Microsystems 于 1984 年开发…

eslasticsearch+ik分词器+kibana

eslasticsearch 下载地址:https://www.elastic.co/cn/downloads/past-releases ik分词器 下载地址:https://release.infinilabs.com/analysis-ik/stable/ kibana 下载地址:https://www.elastic.co/cn/downloads/kibana 1、解压安装包 将下载的 zi…

SOME/IP-SD IPv4组播的通信参数由谁指定?

<摘要> 在AUTOSAR SOME/IP-SD协议中&#xff0c;组播通信参数&#xff08;地址、协议、端口&#xff09;的协商机制。其核心在于明确规定了组播流的发布者和接收者之间由谁来“指定”通信路径&#xff0c;从而确保双方能够成功会合&#xff0c;实现高效的一对多事件分发。…

新手首次操作SEO核心要点

内容概要 初次接触SEO的新手朋友们&#xff0c;面对浩瀚的网络优化知识&#xff0c;难免感到无从下手。这份2025年的零基础入门指南&#xff0c;正是为你们量身打造。它清晰地规划了学习路径&#xff0c;从最基础的网站搭建注意事项开始&#xff0c;帮助你避开常见陷阱&#xf…

AI、人工智能基础: 模型剪枝的概念与实践(PyTorch版)

胡说八道: 各位观众老爷&#xff0c;大家好&#xff0c;我是诗人啊_&#xff0c;今天和各位分享模型剪枝的相关知识和操作&#xff0c;一文速通&#xff5e; &#xff08;屏幕前的你&#xff0c;帅气低调有内涵&#xff0c;美丽大方很优雅… 所以&#xff0c;求个点赞、收藏、关…

Kubernetes 服务发现与健康检查详解

Kubernetes 提供了多种机制来管理服务发现、负载均衡和容器健康状态监控。本文将围绕以下几个方面展开&#xff1a;Service 类型&#xff1a;ClusterIP、NodePort、Headless Service、LoadBalancer&#xff08;MetallB&#xff09;Ingress 的实现原理健康检查探针&#xff1a;L…

如何规划一年、三年、五年的IP发展路线图?

‍在知识付费领域&#xff0c;规划 IP 发展路线&#xff0c;需要从短期、中期、长期不同阶段&#xff0c;系统地布局内容、运营与商业变现&#xff0c;逐步提升 IP 影响力与商业价值。一年目标&#xff1a;立足定位&#xff0c;夯实基础精准定位&#xff0c;打磨内容利用创客匠…

C++从入门到实战(二十)详细讲解C++List的使用及模拟实现

C从入门到实战&#xff08;二十&#xff09;C List的使用及模拟实现前言一、什么是List1.1 List的核心特性1.2 List与vector的核心差异1.3 List的构造、拷贝构造与析构1.3.1 常用构造函数1.3.2 析构函数1.4 List的迭代器1.4.1 迭代器类型与用法示例1&#xff1a;正向迭代器遍历…

人工智能学习:机器学习相关面试题(一)

1、 机器学习中特征的理解 def: 特征选择和降维 特征选择&#xff1a;原有特征选择出子集 &#xff0c;不改变原来的特征空间 降维&#xff1a;将原有的特征重组成为包含信息更多的特征&#xff0c; 改变了原有的特征空间降维的主要方法 Principal Component Analysis (主成…

亚马逊巴西战略升级:物流网络重构背后的生态革新与技术赋能之路

在全球电商版图中&#xff0c;拉美市场正以惊人的增长速度成为新的战略高地&#xff0c;而巴西作为其中的核心市场&#xff0c;凭借庞大的人口基数、高速发展的数字经济以及不断提升的消费能力&#xff0c;吸引着众多电商巨头争相布局。近日&#xff0c;亚马逊宣布将于2025年底…

PS自由变换

自由变换 自由变换用来对图层、选区、路径或像素内容进行灵活的像素调整。可以进行缩放、旋转、扭曲等多种操作。快捷键&#xff1a;CtrlT&#xff0c;操作完成后使用Enter键可以确认变换自由变换过程中如果出现失误&#xff0c;可以按ESC退出&#xff1b;满意可以按enter确定。…

【K8s】整体认识K8s之存储--volume

为什么要用volume&#xff1f;首先。容器崩溃或重启时&#xff0c;所有的数据都会丢失&#xff0c;我们可以把数据保存到容器的外部&#xff0c;比如硬盘nfs&#xff0c;这样&#xff0c;即使容器没了&#xff0c;数据还在&#xff1b;第二就是容器之间是隔离的。我们如果想共享…

flutter工程

安装flutter 在VSCode中安装flutter extension、flutter组件 国内源下载flutter 3.35.2的SDK&#xff0c;安装&#xff0c;官网下载不了 将flutter安装目录加入环境变量中 D:\program\flutter_sdk\flutter\bin 执行 C:\Windows\System32>flutter --version Flutter 3.35.2 •…