张量创建
import torch
import numpy as np
# 创建一个 2x3 的全 0 张量
a = torch.zeros(2, 3)
print(a)
# 创建一个 2x3 的全 1 张量
b = torch.ones(2, 3)
print(b)
# 创建一个 2x3 的随机数张量
c = torch.randn(2, 3)
print(c)
# 从 NumPy 数组创建张量
numpy_array = np.array([[1, 2], [3, 4]])
tensor_from_numpy = torch.from_numpy(numpy_array)
print(tensor_from_numpy)
# 在指定设备(CPU/GPU) 上创建张量
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
d = torch.randn(2, 3, device=device)
print(d)
张量常用操作
# 常用张量操作
# 张量逐元素相加
e = torch.tensor([[1,2,3],[4,5,6]])
f = torch.tensor([[1,2,3],[4,5,6]])
print(e + f)
# 逐元素乘法
print(e * f)
# 张量的转置
g = torch.randn(3, 2)
print(g,'\n',g.t()) # 或者 g.transpose(0, 1)
# 张量的形状
print(g.shape) # 返回张量形状
# torch.randn() 生出标准正态分布数据
# 基于独立变量方差可加性 h.sum() 服从N(0,1000^2)
h = torch.randn(1000,1000,dtype=torch.float64)
print(h.sum())
自动微分
PyTorch的张量支持自动微分,这是深度学习中的关键特性。创建一个需要梯度的张量时,PyTorch可以自动计算其梯度(采用动态图):
# 创建一个需要梯度的张量
tensor_requires_grad = torch.tensor([1.0], requires_grad=True)
# 进行张量操作
tensor_result = tensor_requires_grad * torch.tensor(2.0)
# 计算梯度
tensor_result.backward()
print(tensor_requires_grad.grad) # 输出梯度
创建NN
SimpleNN 是一个子类(Child Class),它继承自 nn.Module 父类
nn.Module 是所有 PyTorch 神经网络模块(Models and Layers)的基类。当创建一个 PyTorch 模型时,必须确保 nn.Module 中定义的内部机制能够被正确设置和初始化
nn.Module 负责跟踪模型中所有的权重(weight)和偏置(bias)参数,以便它们能被正确地注册到模型的状态字典(state_dict)中。
nn.Module 管理所定义的 self.fc1 和 self.fc2 等子层,使得 PyTorch 能够自动识别这些层并进行统一管理(例如,当调用 model.to(device) 时,所有子层都会被移动到指定的设备上)。
import torch
import torch.nn as nn
# 定义一个简单的神经网络模型
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
# 定义一个输入层到隐藏层的全连接层
self.fc1 = nn. Linear(2, 2) # 输入 2 个特征,输出 2 个特征
# 定义一个隐藏层到输出层的全连接层
self.fc2 = nn.Linear(2, 1) # 输入 2 个特征,输出 1 个预测
def forward(self, x):
# 前向传播过程
x = torch.relu(self.fc1(x)) # 使用ReLU 激活函数
x = self.fc2(x) # 输出层
return x
# 创建模型实例
model = SimpleNN()
# 打印模型
print(model)
'''
Python 实例化 SimpleNN 时调用自定义 __init__。
执行 super().__init__(),代码流暂时切换到 nn.Module 的 __init__ 方法内部。
nn.Module 完成所有基础设置:创建内部列表、字典、设置默认属性等。
代码流回到 SimpleNN 的 __init__ 方法
父类已经准备好了环境来接收和管理这些子模块
'''
super() 是 Python 中的内建函数,提供了一种访问父类(以及祖父类、更上层的基类等)的方法,而无需明确使用父类的名称。
在python3中,解释器能够知道当前所在的类(SimpleNN)和实例(self),所以super(SimpleNN, self).init()可以写成:
super().__init__()
super() 实际上返回了一个临时的代理对象(proxy object)。这个代理对象充当了当前子类和它所有父类之间的桥梁。
当在这个代理对象上调用方法(例如 .init())时:它不会在当前子类 SimpleNN 中查找 init。它会跳过 SimpleNN,直接在其父类(即 nn.Module)中查找并执行 init 方法。
因此,当定义 class SimpleNN(nn.Module): 时,子类(SimpleNN)负责定义网络的结构,而父类负责处理底层机制。
加载自定义dataset
torch.utils.data.Dataset 是一个抽象类,实现为提供的数据源中创建数据集。
需要继承该类并实现以下两个方法:
len(self):返回数据集中的样本数量。
getitem(self, idx):通过索引返回一个样本。
import torch
from torch.utils.data import Dataset
# 自定义数据集类
class MyDataset(Dataset):
def __init__(self, X_data, Y_data):
"""
初始化数据集, X_data 和 Y_data 是两个列表或数组
X_data:输入特征
Y_data:目标标签
"""
self.X_data = X_data
self.Y_data = Y_data
def __len__(self):
"""返回数据集的大小"""
return len(self.X_data)
def __getitem__(self, idx):
"""返回指定索引的数据"""
x = torch.tensor(self.X_data[idx], dtype=torch.float32)
y = torch.tensor(self.Y_data[idx], dtype=torch.float32)
return x, y
# 示例数据
X_data = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] # 输入特征
Y_data = [1, 0, 1, 0, 1, 0] # 目标标签
# 创建数据集实例
dataset = MyDataset(X_data, Y_data)
# 调用 __len(self)__ 与 __getitem__(self,idx)
print(dataset.__getitem__(1) , '\n', dataset.__len__() )
加载数据
DataLoader 允许批量读取数据并进行多线程加载,从而提高训练效率
from torch.utils.data import DataLoader
# 创建 DataLoader 实例,batch_size 设置每次加载的样本数量
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
# 打印加载的数据
for epoch in range(1):
for batch_idx, (inputs, labels) in enumerate(dataloader):
print(f'Batch {batch_idx + 1}:')
print(f'Inputs: {inputs}')
print(f'Labels: {labels}')
'''
示例输出:
Batch 1:
Inputs: tensor([[ 3., 4.],
[11., 12.]])
Labels: tensor([0., 0.])
Batch 2:
Inputs: tensor([[7., 8.],
[1., 2.]])
Labels: tensor([0., 1.])
Batch 3:
Inputs: tensor([[ 5., 6.],
[ 9., 10.]])
Labels: tensor([1., 1.])
'''
enumerate与range
enumerate在遍历(循环)列表或其他可迭代对象(如前所定义的 dataloader)时,同时获取元素的索引(下标)和元素本身。相比于range()更简洁。
enumerate(iterable, start=0)
'''
iterable: 一个可迭代对象(如列表 list、元组 tuple、字符串 string 等)。
start: (可选)计数开始的数字,默认为 0。
enumerate返回一个枚举对象(enumerate object)。
这是一个迭代器,每次生成一个包含 (index, value) 的元组。
'''
示例
fruits = ["Apple", "Banana", "Cherry"]
for i in range(len(fruits)):
print(i, fruits[i])
'''
0 Apple
1 Banana
2 Cherry
'''
for index, fruit in enumerate(fruits):
print(f"idx: {index}, val: {fruit}")
'''
idx: 0, val: Apple
idx: 1, val: Banana
idx: 2, val: Cherry
'''
enumerate 允许通过 start 参数自定义计数的起始值。这在生成排名、行号等场景非常有用
runners = ["Usain", "Tyson", "Asafa"]
# start=1 表示索引从 1 开始
for rank, name in enumerate(runners, start=1):
print(f"第 {rank} 名: {name}")
# 输出:
# 第 1 名: Usain
# 第 2 名: Tyson
# 第 3 名: Asafa
enumerate 也可以用于其它对象:
# 字符串
word = "Python"
for i, char in enumerate(word):
print(i, char)
# 输出:
# 0 P
# 1 y
# 字典
data = {'name': 'Alice', 'age': 25}
for i, key in enumerate(data):
print(f"{i}: {key}")
# 输出:
# 0: name
# 1: age
# 元组
name_age_tuple = ( ('Bob', 24), ('Alice', 28) )
for idx, val in enumerate(name_age_tuple):
print(f'Index:{idx}')
print(f'Value: {val}')
'''
Index:0
Value: ('Bob', 24)
Index:1
Value: ('Alice', 28)
'''
for idx, (name,age) in enumerate(name_age_tuple):
print(f'Index:{idx}')
print(f'Name: {name}')
print(f'Age: {age}')
'''
Index:0
Name: Bob
Age: 24
Index:1
Name: Alice
Age: 28
'''
注意,enumerate 返回的是一个迭代器对象,打印它只返回对象地址
colors = ["Red", "Green", "Blue"]
enum_obj = enumerate(colors, start=10)
# 直接打印对象
print(enum_obj)
# 输出: <enumerate object at 0x...>
# 转换为列表查看结构
print(list(enum_obj))
# 输出: [(10, 'Red'), (11, 'Green'), (12, 'Blue')]
对于上面代码的 for batch_idx, (inputs, labels) in enumerate(dataloader):
for batch_idx, (inputs, labels) in enumerate(dataloader):
'''
dataloader 的工作:它是一个迭代器。每次迭代,它会从 dataset 中取出一组数据(根据 batch_size=2,每次取 2 个样本)。它返回的数据结构是:(Tensor([x1, x2]), Tensor([y1, y2])),也就是代码中的 (inputs, labels)。
enumerate 的工作:它将 dataloader 返回的数据包裹起来,加上一个索引。它返回的结构是:(索引, dataloader产生的数据)。具体形式为:(0, (inputs, labels))。
for 循环的解包:Python 将 enumerate 产生的元组分配给变量:第一个元素(索引) $\rightarrow$ 赋值给 batch_idx第二个元素(数据元组) $\rightarrow$ 赋值给 (inputs, labels)
'''
- 注意到:(inputs, labels) 是为了匹配 dataloader 返回的元组结构。
- enumerate的性质帮助对于每个batch添加索引,便于了解当前训练进程
预处理、数据增强
import torchvision.transforms as transforms
# 定义数据预处理的流水线
transform = transforms.Compose([
transforms.Resize((128, 128)), # 将图像调整为 128x128
transforms.ToTensor(), # 将图像转换为张量
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,0.224,0.225
])
transforms.Compose():将多个变换操作组合在一起。
transforms.Resize():调整图像大小。
transforms.ToTensor():将图像转换为 PyTorch 张量,值会被归一化到 [0,1]范围。
transforms.Normalize():标准化图像数据,通常使用预训练模型时需要进行标准化处理。
transform = transforms.Compose([
transforms.RandomHorizontalFlip(), # 随机水平翻转
transforms.RandomRotation(30), # 随机旋转 30 度
transforms.RandomResizedCrop(128), # 随机裁剪并调整为 128x128
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
1167

被折叠的 条评论
为什么被折叠?



