第一章:PyTorch 基础


文档摘要

第一章:PyTorch 基础 第一章:PyTorch 基础 PyTorch,作为深度学习领域中最受欢迎的框架之一,以其灵活性、易用性和强大的功能而备受推崇。无论你是初涉机器学习的新手,还是经验丰富的研究人员,掌握 PyTorch 的基础知识都是至关重要的。本章将深入探讨 PyTorch 的核心概念,为你构建坚实的理论基础和实践能力,为后续深入学习和应用 PyTorch 打下坚实的基础。 1.1 PyTorch 简介 PyTorch 是一个开源的 Python 机器学习库,主要用于自然语言处理和计算机视觉等领域。它由 Facebook 的人工智能研究小组开发,并在 BSD 许可下发布。

第一章:PyTorch 基础

第一章:PyTorch 基础

PyTorch,作为深度学习领域中最受欢迎的框架之一,以其灵活性、易用性和强大的功能而备受推崇。无论你是初涉机器学习的新手,还是经验丰富的研究人员,掌握 PyTorch 的基础知识都是至关重要的。本章将深入探讨 PyTorch 的核心概念,为你构建坚实的理论基础和实践能力,为后续深入学习和应用 PyTorch 打下坚实的基础。

1.1 PyTorch 简介

PyTorch 是一个开源的 Python 机器学习库,主要用于自然语言处理和计算机视觉等领域。它由 Facebook 的人工智能研究小组开发,并在 BSD 许可下发布。PyTorch 的核心优势在于其 动态计算图Python 优先 的特性,使其在研究和快速原型设计方面表现出色。

PyTorch 的主要特点:

  • 动态计算图 (Dynamic Computational Graph):PyTorch 使用动态计算图,这意味着计算图的构建是在运行时进行的。这与 TensorFlow 等框架的静态计算图形成对比,后者需要在运行前预先定义完整的计算图。动态图的优势在于灵活性和易于调试,特别是在处理复杂的模型结构和控制流时更加方便。

  • Pythonic 风格:PyTorch 紧密集成 Python 生态系统,API 设计简洁直观,与 Python 的语法和习惯高度一致。这使得 PyTorch 学习曲线相对平缓,易于上手,并能充分利用 Python 丰富的库和工具。

  • 强大的 GPU 加速:PyTorch 能够充分利用 GPU 进行加速计算,显著提升模型训练和推理的速度。通过简单的配置,即可将计算转移到 GPU 上进行,从而处理大规模的数据和复杂的模型。

  • 丰富的工具和库:PyTorch 拥有庞大的社区支持和丰富的工具库,例如 torchvision (计算机视觉)、torchtext (自然语言处理)、torchaudio (音频处理) 等,这些库提供了预训练模型、常用数据集和实用工具,极大地简化了开发流程。

  • 易于扩展和定制:PyTorch 的模块化设计和清晰的 API 使得用户可以轻松地扩展和定制框架,满足特定的研究和应用需求。

PyTorch 的应用领域:

PyTorch 在学术界和工业界都得到了广泛应用,尤其在以下领域表现突出:

  • 计算机视觉 (Computer Vision):图像分类、目标检测、图像分割、图像生成等。

  • 自然语言处理 (Natural Language Processing):文本分类、机器翻译、文本生成、情感分析等。

  • 语音识别 (Speech Recognition):语音转文本、语音合成等。

  • 强化学习 (Reinforcement Learning):策略学习、价值函数估计等。

  • 生成对抗网络 (Generative Adversarial Networks, GANs):图像生成、风格迁移等。

1.2 张量 (Tensor):PyTorch 的基石

在 PyTorch 中,张量 (Tensor) 是最基本的数据结构,它类似于 NumPy 中的数组 (ndarray)。张量可以看作是多维数组,用于存储和操作数据。深度学习模型中的所有数据,例如输入数据、权重、偏置、中间计算结果等,都以张量的形式表示。

1.2.1 创建张量

PyTorch 提供了多种创建张量的方法:

1. 从 Python 列表或 NumPy 数组创建:

import torch import numpy as np # 从 Python 列表创建张量 list_data = [[1, 2], [3, 4]] tensor_from_list = torch.Tensor(list_data) print("From List:\n", tensor_from_list) # 从 NumPy 数组创建张量 numpy_data = np.array([[5, 6], [7, 8]]) tensor_from_numpy = torch.Tensor(numpy_data) # 或 torch.from_numpy(numpy_data) print("\nFrom NumPy:\n", tensor_from_numpy)

代码详解:

  • torch.Tensor() 是创建张量的常用方法,它可以接受 Python 列表或 NumPy 数组作为输入。

  • torch.from_numpy() 也可以从 NumPy 数组创建张量,它与 torch.Tensor() 的区别在于,torch.from_numpy() 创建的张量与原始 NumPy 数组共享内存,修改其中一个会影响另一个。而 torch.Tensor() 默认会复制数据。

2. 创建特定形状和类型的张量:

# 创建全零张量 zeros_tensor = torch.zeros((2, 3)) # 形状为 (2, 3) print("\nZeros Tensor:\n", zeros_tensor) # 创建全一张量 ones_tensor = torch.ones((3, 2)) # 形状为 (3, 2) print("\nOnes Tensor:\n", ones_tensor) # 创建随机数张量 (均匀分布) rand_tensor = torch.rand((2, 2)) # 形状为 (2, 2),值在 [0, 1) 之间 print("\nRandom Tensor (rand):\n", rand_tensor) # 创建随机数张量 (标准正态分布) randn_tensor = torch.randn((2, 2)) # 形状为 (2, 2),值服从标准正态分布 print("\nRandom Tensor (randn):\n", randn_tensor) # 创建指定范围的整数张量 arange_tensor = torch.arange(0, 10, 2) # 从 0 到 10 (不包含 10),步长为 2 print("\nArange Tensor:\n", arange_tensor) # 创建指定形状的单位矩阵 (对角线为 1,其余为 0) eye_tensor = torch.eye(3) # 3x3 单位矩阵 print("\nEye Tensor:\n", eye_tensor)

代码详解:

  • torch.zeros(shape): 创建指定形状的全零张量。

  • torch.ones(shape): 创建指定形状的全一张量。

  • torch.rand(shape): 创建指定形状的均匀分布随机数张量,值在 [0, 1) 之间。

  • torch.randn(shape): 创建指定形状的标准正态分布随机数张量,值服从均值为 0,标准差为 1 的正态分布。

  • torch.arange(start, end, step): 创建指定范围和步长的整数张量。

  • torch.eye(n): 创建 n x n 的单位矩阵。

1.2.2 张量的属性

每个张量都有一些重要的属性,用于描述其数据类型、形状和存储位置等:

tensor = torch.rand((3, 4)) print(f"数据类型 (dtype): {tensor.dtype}") print(f"形状 (shape): {tensor.shape}") # 或 tensor.size() print(f"设备 (device): {tensor.device}")

代码详解:

  • tensor.dtype: 张量的数据类型,例如 torch.float32 (默认), torch.float64, torch.int64, torch.bool 等。

  • tensor.shapetensor.size(): 张量的形状,表示各维度的大小。例如 torch.Size([3, 4]) 表示一个 3 行 4 列的二维张量。

  • tensor.device: 张量存储的设备,可以是 CPU (cpu) 或 GPU (cuda:0, cuda:1 等)。

1.2.3 张量的操作

PyTorch 提供了丰富的张量操作,包括算术运算、索引切片、形状变换、线性代数运算等。

1. 算术运算:

tensor_a = torch.tensor([[1, 2], [3, 4]]) tensor_b = torch.tensor([[5, 6], [7, 8]]) # 加法 add_tensor = tensor_a + tensor_b # 或 torch.add(tensor_a, tensor_b) print("\nAddition:\n", add_tensor) # 减法 sub_tensor = tensor_a - tensor_b # 或 torch.sub(tensor_a, tensor_b) print("\nSubtraction:\n", sub_tensor) # 乘法 (元素级别) mul_tensor = tensor_a * tensor_b # 或 torch.mul(tensor_a, tensor_b) print("\nElement-wise Multiplication:\n", mul_tensor) # 除法 (元素级别) div_tensor = tensor_a / tensor_b # 或 torch.div(tensor_a, tensor_b) print("\nElement-wise Division:\n", div_tensor) # 矩阵乘法 matmul_tensor = torch.matmul(tensor_a, tensor_b.T) # 或 tensor_a @ tensor_b.T print("\nMatrix Multiplication:\n", matmul_tensor)

代码详解:

  • PyTorch 支持常见的算术运算符 +, -, *, / 进行元素级别的运算。

  • torch.matmul()@ 运算符用于矩阵乘法。注意矩阵乘法需要满足维度匹配的条件。.T 表示转置操作。

2. 索引和切片:

张量的索引和切片操作与 NumPy 数组类似,使用方括号 [] 和冒号 :

tensor = torch.arange(10) # 创建一个 0 到 9 的一维张量 print("\nOriginal Tensor:\n", tensor) print("\nIndex 0:", tensor[0]) # 访问索引为 0 的元素 print("Index 2 to 5:", tensor[2:6]) # 切片,访问索引 2 到 5 (不包含 6) 的元素 print("Index from 5:", tensor[5:]) # 切片,访问索引 5 到末尾的元素 print("Index :3:", tensor[:3]) # 切片,访问索引 0 到 2 (不包含 3) 的元素 print("Index -1:", tensor[-1]) # 访问最后一个元素

代码详解:

  • 张量的索引从 0 开始。

  • 使用冒号 : 进行切片操作,[start:end:step],可以省略 start, end, step,默认分别为 0, 末尾, 1。

  • 负数索引表示从末尾开始计数,-1 表示最后一个元素。

3. 形状变换:

tensor = torch.arange(12) # 创建一个 0 到 11 的一维张量 print("\nOriginal Tensor:\n", tensor) # 改变形状 (reshape) reshaped_tensor = tensor.reshape((3, 4)) # 变为 3x4 的二维张量 print("\nReshaped Tensor:\n", reshaped_tensor) # 展平 (flatten) flattened_tensor = reshaped_tensor.flatten() # 变为一维张量 print("\nFlattened Tensor:\n", flattened_tensor) # 转置 (transpose) transposed_tensor = reshaped_tensor.T # 或 torch.transpose(reshaped_tensor, 0, 1) print("\nTransposed Tensor:\n", transposed_tensor)

代码详解:

  • tensor.reshape(shape): 改变张量的形状,返回一个新的张量,数据共享。

  • tensor.flatten(): 将张量展平成一维张量。

  • tensor.Ttorch.transpose(tensor, dim0, dim1): 转置张量,交换指定的维度。.T 只能用于二维张量的转置。

4. 张量的拼接和分割:

tensor1 = torch.tensor([[1, 2], [3, 4]]) tensor2 = torch.tensor([[5, 6], [7, 8]]) # 沿行 (dim=0) 拼接 cat_row_tensor = torch.cat((tensor1, tensor2), dim=0) print("\nConcatenate along rows (dim=0):\n", cat_row_tensor) # 沿列 (dim=1) 拼接 cat_col_tensor = torch.cat((tensor1, tensor2), dim=1) print("\nConcatenate along columns (dim=1):\n", cat_col_tensor) # 分割张量 split_tensor = torch.split(cat_col_tensor, split_size_or_sections=2, dim=1) # 沿列 (dim=1) 分割成大小为 2 的块 print("\nSplit along columns (dim=1):\n", split_tensor)

代码详解:

  • torch.cat((tensor1, tensor2, ...), dim): 沿指定维度拼接多个张量。

  • torch.split(tensor, split_size_or_sections, dim): 沿指定维度分割张量。split_size_or_sections 可以是整数 (每个块的大小) 或列表 (每个块的大小)。

1.2.4 张量与 NumPy 的互操作性

PyTorch 张量可以与 NumPy 数组无缝转换,这使得我们可以方便地利用 NumPy 丰富的科学计算库。

numpy_array = np.array([[1, 2], [3, 4]]) # NumPy 数组转换为 PyTorch 张量 tensor_from_np = torch.from_numpy(numpy_array) print("\nTensor from NumPy:\n", tensor_from_np) # PyTorch 张量转换为 NumPy 数组 numpy_from_tensor = tensor_from_np.numpy() print("\nNumPy from Tensor:\n", numpy_from_tensor)

代码详解:

  • torch.from_numpy(numpy_array): 将 NumPy 数组转换为 PyTorch 张量,共享内存。

  • tensor.numpy(): 将 PyTorch 张量转换为 NumPy 数组,共享内存。

mermaid graph TD 图示例:张量操作

1.3 自动求导 (Autograd):神经网络的引擎

自动求导 (Autograd) 是 PyTorch 的核心功能之一,它使得 PyTorch 能够自动计算梯度,这对于训练神经网络至关重要。在深度学习中,我们通常使用梯度下降等优化算法来更新模型参数,而梯度就是损失函数关于模型参数的导数。

1.3.1 requires_grad 属性

要启用张量的自动求导功能,需要将其 requires_grad 属性设置为 True。默认情况下,张量的 requires_grad 属性为 False

x = torch.randn(3, 3, requires_grad=True) # 创建一个需要求导的随机数张量 y = torch.randn(3, 3) # 创建一个不需要求导的随机数张量 print("x requires_grad:", x.requires_grad) print("y requires_grad:", y.requires_grad)

代码详解:

  • requires_grad=True 告诉 PyTorch 跟踪对该张量的所有操作,以便后续计算梯度。

1.3.2 计算图与梯度

当我们对 requires_grad=True 的张量进行操作时,PyTorch 会动态构建一个 计算图 (Computational Graph),记录这些操作。计算图描述了张量的计算过程,用于反向传播算法计算梯度。

a = torch.tensor([2.0, 3.0], requires_grad=True) b = torch.tensor([6.0, 4.0], requires_grad=True) Q = 3*a**3 - b**2 external_grad = torch.tensor([1.0, 1.0]) # 外部梯度,对于标量输出可以省略 Q.backward(gradient=external_grad) # 反向传播,计算梯度 print("\nGradient of a:", a.grad) # dQ/da print("Gradient of b:", b.grad) # dQ/db

代码详解:

  1. 前向传播 (Forward Pass)

    • Q = 3*a**3 - b**2 计算了张量 Q 的值,构建了计算图。
  2. 反向传播 (Backward Pass)

    • Q.backward() 启动反向传播过程,从输出张量 Q 开始,沿着计算图反向传播,计算每个参与运算且 requires_grad=True 的张量的梯度。

    • external_grad 是外部梯度,用于链式法则的计算。如果 Q 是标量,则可以省略 gradient 参数。如果 Q 是向量或张量,则 gradient 参数需要与 Q 的形状相同,表示对 Q 的梯度。

  3. 访问梯度

    • a.gradb.grad 分别存储了张量 ab 的梯度值。梯度值累积在 .grad 属性中,每次反向传播后需要手动清零 (使用 tensor.grad.zero_() ),否则会累加之前的梯度。

mermaid graph TD 图示例:自动求导计算图

1.3.3 关闭自动求导

在某些情况下,例如模型推理 (inference) 阶段,我们不需要计算梯度,可以关闭自动求导以节省内存和计算资源。

x = torch.randn(3, 3, requires_grad=True) with torch.no_grad(): y = x + 2 print("\ny requires_grad (inside no_grad):", y.requires_grad) # False z = x + 3 print("\nz requires_grad (outside no_grad):", z.requires_grad) # True

代码详解:

  • torch.no_grad() 上下文管理器用于关闭自动求导。在该上下文中进行的所有张量操作都不会被记录到计算图中,也不会计算梯度。

1.4 简单的神经网络

PyTorch 提供了 torch.nn 模块,用于构建神经网络。nn.Module 是构建神经网络的基本模块,我们可以通过继承 nn.Module 类来定义自己的神经网络模型。

1.4.1 定义神经网络

import torch.nn as nn class SimpleNet(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(SimpleNet, self).__init__() self.linear1 = nn.Linear(input_size, hidden_size) # 第一个线性层 self.relu = nn.ReLU() # ReLU 激活函数 self.linear2 = nn.Linear(hidden_size, output_size) # 第二个线性层 def forward(self, x): out = self.linear1(x) out = self.relu(out) out = self.linear2(out) return out # 创建模型实例 input_size = 10 hidden_size = 5 output_size = 2 model = SimpleNet(input_size, hidden_size, output_size) print("\nSimpleNet Model:\n", model)

代码详解:

  • nn.Module: 所有神经网络模块的基类。

  • __init__(self, ...): 构造函数,定义模型的层结构。

    • nn.Linear(in_features, out_features): 线性层 (全连接层),执行线性变换:y = xW^T + b

    • nn.ReLU(): ReLU 激活函数,f(x) = max(0, x)

  • forward(self, x): 前向传播函数,定义数据在模型中的流动路径。输入数据 x 经过线性层和激活函数,最终输出 out

1.4.2 损失函数和优化器

在训练神经网络时,我们需要定义 损失函数 (Loss Function) 来衡量模型预测结果与真实标签之间的差距,并使用 优化器 (Optimizer) 来更新模型参数,减小损失函数的值。

# 损失函数 (均方误差损失) criterion = nn.MSELoss() # 优化器 (随机梯度下降) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # lr: 学习率

代码详解:

  • nn.MSELoss(): 均方误差损失函数,常用于回归任务。

  • torch.optim.SGD(model.parameters(), lr): 随机梯度下降优化器。

    • model.parameters(): 返回模型中所有需要优化的参数 (即 requires_grad=True 的张量)。

    • lr: 学习率,控制参数更新的步长。

1.4.3 训练循环 (简易版)

# 模拟输入数据和标签 input_data = torch.randn(1, input_size) # 批大小为 1 target_data = torch.randn(1, output_size) # 批大小为 1 # 训练循环 num_epochs = 100 for epoch in range(num_epochs): # 1. 前向传播 output = model(input_data) loss = criterion(output, target_data) # 2. 反向传播和优化 optimizer.zero_grad() # 清零梯度 loss.backward() # 反向传播,计算梯度 optimizer.step() # 更新模型参数 if (epoch+1) % 10 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

代码详解:

  1. 前向传播: output = model(input_data) 将输入数据 input_data 输入模型,得到模型的预测输出 output

  2. 计算损失: loss = criterion(output, target_data) 计算模型输出 output 和真实标签 target_data 之间的损失值。

  3. 清零梯度: optimizer.zero_grad() 将模型参数的梯度清零,防止梯度累加。

  4. 反向传播: loss.backward() 执行反向传播,计算损失函数关于模型参数的梯度。

  5. 参数更新: optimizer.step() 根据计算出的梯度,使用优化器更新模型参数。

  6. 打印信息: 每隔 10 个 epoch 打印一次 epoch 数和损失值。loss.item() 将标量张量 loss 转换为 Python 数值。

mermaid graph TD 图示例:简单神经网络结构

1.5 总结

本章我们介绍了 PyTorch 的基础知识,包括:

  • PyTorch 简介: 了解 PyTorch 的特点和应用领域。

  • 张量 (Tensor): 掌握张量的创建、属性和常用操作。

  • 自动求导 (Autograd): 理解自动求导的原理和使用方法。

  • 简单的神经网络: 学习使用 nn.Module 构建简单的神经网络,并进行基本的训练。

掌握这些基础知识是学习和应用 PyTorch 的关键一步。在接下来的章节中,我们将深入探讨 PyTorch 的更高级特性和应用,例如数据集加载、模型训练技巧、常用神经网络模块、以及在计算机视觉和自然语言处理等领域的应用。希望本章内容能够帮助你扎实 PyTorch 基础,开启你的深度学习之旅!


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U