2深度学习Pytorch-神经网络--全连接神经网络、数据准备(构建数据类Dataset、TensorDataset 和数据加载器DataLoader)
文章目录
- 一、深度学习概述
- 二、神经网络基础
- 人工神经网络(ANN)
- 基本结构
- 神经网络的构建
- 全连接神经网络(FCN)
- 计算步骤
- 基本组件
- 1. 线性层组件
- 2. 激活函数(Activation Function)
- 3. 损失函数(Loss Function)
- 4. 优化器(Optimizer)
- 三、数据准备
- 1. 构建数据类
- Dataset 类
- TensorDataset
- 2. 数据加载器(DataLoader)
- CSV文件加载
- 图片加载
- 官方数据集加载
一、深度学习概述
深度学习是机器学习的一个分支,核心是通过多层非线性神经网络自动学习数据的抽象特征,无需人工设计特征。与传统机器学习相比,它能处理更复杂的数据(如图像、文本、语音),且随着数据量和计算能力的提升,性能会显著提高。其核心特点是:
- 端到端学习:直接从原始数据学习目标输出
- 层次化特征提取:底层学简单特征(边缘),高层学复杂特征(物体部件)
- 大数据驱动:需要海量训练数据
- 表示学习:自动发现数据的内在表示
二、神经网络基础
人工神经网络(ANN)
人工神经网络(ANN)受生物神经网络启发,由大量神经元(Neuron) 通过连接构成,用于模拟人脑的信息处理方式。基本要素:
- 神经元:接收输入→加权求和→激活函数处理→输出
- 连接权重:决定信号传递强度
- 激活函数:引入非线性(ReLU、Sigmoid、Tanh)
基本结构
- 输入层(Input Layer):接收原始数据(如图片的像素值、文本的特征向量),不进行计算,仅传递数据。
- 隐藏层(Hidden Layer):位于输入层和输出层之间,对输入数据进行非线性变换,提取抽象特征(层数≥1 时称为 “深度” 神经网络)。
- 输出层(Output Layer):输出模型的预测结果(如分类任务的类别概率、回归任务的数值)。
神经网络的构建
构建神经网络的核心是定义层结构和前向传播(Forward Propagation) 过程。
我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个权重,经典如下:
核心 API
torch.nn.Module
:所有神经网络模块的基类,自定义网络需继承此类。torch.nn.Linear
:全连接层(线性变换层)。forward()
:定义前向传播逻辑,必须实现。
全连接神经网络(FCN)
全连接神经网络(FCN),也称为多层感知机(Multi-Layer Perceptron, MLP),是最基础、最经典的神经网络结构。其核心特点是每一层的每个神经元都与下一层的所有神经元完全连接,这也是 “全连接” 名称的由来。
特点:
- 全连接:每层的每个神经元与下一层的所有神经元连接。
- 参数多:容易过拟合(需正则化)。
- 适用于简单数据:如表格数据,不适合处理图像(参数冗余)。
如上图,网络中每个神经元:
z1=x1∗w1+x2∗w2+b1z2=x1∗w1+x2∗w2+b2z3=x1∗w1+x2∗w2+b3z_1 = x_1*w_1 + x_2*w_2+b_1 \\ z_2 = x_1*w_1 + x_2*w_2+b_2 \\ z_3 = x_1*w_1 + x_2*w_2+b_3 z1=x1∗w1+x2∗w2+b1z2=x1∗w1+x2∗w2+b2z3=x1∗w1+x2∗w2+b3
说明:三个等式中的w1和w2在这里只是为了方便表示对应x1和x2的权重,实际三个等式中的w值是不同的。
向量x为:[x1,x2][x_1,x_2][x1,x2]
向量w:(w1,w2w1,w2w1,w2)\begin{pmatrix}w_1,w_2\\w_1,w_2\\w_1,w_2 \end{pmatrix}w1,w2w1,w2w1,w2,其形状为(3,2),3是神经元节点个数,2是向量x的个数
向量z:[z1,z2,z3][z_1,z_2,z_3][z1,z2,z3]
向量b:[b1,b2,b3][b_1,b_2,b_3][b1,b2,b3]
所以用向量表示为:
z=(z1,z2,z3)=(x1,x2)(w1,w1,w1w2,w2,w2)+(b1,b2,b3)=(x1,x2)(w1,w2w1,w2w1,w2)T+(b1,b2,b3)=xwT+bz = \begin{pmatrix}z_1,z_2,z_3 \end{pmatrix}=\begin{pmatrix}x_1,x_2 \end{pmatrix}\begin{pmatrix}w_1,w_1,w_1\\w_2,w_2,w_2\end{pmatrix}+\begin{pmatrix}b_1,b_2,b_3 \end{pmatrix}=\begin{pmatrix}x_1,x_2 \end{pmatrix}\begin{pmatrix}w_1,w_2\\w_1,w_2\\w_1,w_2 \end{pmatrix}^T + \begin{pmatrix}b_1,b_2,b_3 \end{pmatrix}=xw^T+b z=(z1,z2,z3)=(x1,x2)(w1,w1,w1w2,w2,w2)+(b1,b2,b3)=(x1,x2)w1,w2w1,w2w1,w2T+(b1,b2,b3)=xwT+b
- x是输入数据,形状为 (batch_size, in_features)。
- W是权重矩阵,形状为 (out_features, in_features)。
- b是偏置项,形状为 (out_features,)。
- z是输出数据,形状为 (batch_size, out_features)。
- 代码示例(计算过程模拟)
import torch# 输入(1个样本,2个特征)
x = torch.tensor([[1.0, 2.0]]) # shape: (1, 2)# 全连接层参数(手动定义,模拟nn.Linear)
w1 = torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]) # 隐藏层3个神经元,权重shape: (3, 2)
b1 = torch.tensor([0.1, 0.2, 0.3]) # 偏置,shape: (3,)# 计算隐藏层(加权求和+激活)
z1 = torch.matmul(x, w1.T) + b1 # 矩阵乘法:(1,2) × (2,3) → (1,3),加偏置
h1 = torch.relu(z1) # ReLU激活:max(0, z1)print("隐藏层输入z1:", z1)
print("隐藏层输出h1:", h1)
计算步骤
- 数据传递: 输入数据经过每一层的计算,逐层传递到输出层。
- 激活函数: 每一层的输出通过激活函数处理。
- 损失计算: 在输出层计算预测值与真实值之间的差距,即损失函数值。
- 反向传播(Back Propagation): 通过反向传播算法计算损失函数对每个权重的梯度,并更新权重以最小化损失。
基本组件
1. 线性层组件
nn.Linear是 PyTorch 中的一个非常重要的模块,用于实现全连接层(也称为线性层)。它是神经网络中常用的一种层类型,主要用于将输入数据通过线性变换映射到输出空间。
torch.nn.Linear(in_features, out_features, bias=True)
参数说明:
in_features:
- 输入特征的数量(即输入数据的维度)。
- 例如,如果输入是一个长度为 100 的向量,则 in_features=100。
out_features:
- 输出特征的数量(即输出数据的维度)。
- 例如,如果希望输出是一个长度为 50 的向量,则 out_features=50。
bias:
- 是否使用偏置项(默认值为 True)。
- 如果设置为 False,则不会学习偏置项。
示例:构建3层全连接神经网络:在__init__
方法中定义网络结构,在forward定义前向传播
import torch
from torch import nn
# 定义全连接神经网络模型
class MyFcnn(nn.Module):def __init__(self, input_size,out_size):# 父类初始化super(MyFcnn, self).__init__()# 定义线性层1self.fc1 = nn.Linear(input_size, 64)# 定义线性层2,输入要和第一层的输出一致self.fc2 = nn.Linear(64, 32)# 定义线性层3,输入要和第二层的输出一致self.fc3 = nn.Linear(32, out_size)def forward(self, x):x = self.fc1(x)x = self.fc2(x)x = self.fc3(x)return xinput_size = 32
out_size = 1
model = MyFcnn(input_size,out_size)
print(model)
如果模型中线性层按顺序叠加,也可以使用nn.Sequential构建模型。nn.Sequential
是一个顺序容器,内置了自动的前向传播逻辑,它会自动将输入数据依次传递给其中的每一层,并执行前向传播,不需要显式定义 forward()
方法。
import torch
from torch import nninput_size = 32
# 定义全连接神经网络模型
model = nn.Sequential(nn.Linear(input_size, 64),nn.Linear(64, 32),nn.Linear(32, 1)
)
print(model)
2. 激活函数(Activation Function)
激活函数为神经网络引入非线性变换能力,使网络能够拟合复杂的非线性关系。没有激活函数,无论多少层的神经网络都只能实现线性变换。
1)ReLU(Rectified Linear Unit)
- 公式:
ReLU(x) = max(0, x)
- 特点:计算简单,缓解梯度消失问题,是隐藏层的首选
- API:
torch.nn.ReLU()
relu = nn.ReLU()
x = torch.tensor([-1.0, 0.5, 2.0])
print(relu(x)) # tensor([0.0, 0.5, 2.0])
(2)Sigmoid
- 公式:
sigmoid(x) = 1 / (1 + exp(-x))
- 特点:输出在 (0,1) 之间,可用于二分类输出层
- API:
torch.nn.Sigmoid()
sigmoid = nn.Sigmoid()
x = torch.tensor([-2.0, 0.0, 2.0])
print(sigmoid(x)) # tensor([0.1192, 0.5000, 0.8808])
(3)Tanh
- 公式:
tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
- 特点:输出在 (-1,1) 之间,均值为 0
- API:
torch.nn.Tanh()
tanh = nn.Tanh()
x = torch.tensor([-1.0, 0.0, 1.0])
print(tanh(x)) # tensor([-0.7616, 0.0000, 0.7616])
(4)Leaky ReLU
- 公式:
LeakyReLU(x) = max(αx, x)
(α 通常为 0.01) - 特点:解决 ReLU 的 “死亡神经元” 问题
- API:
torch.nn.LeakyReLU(negative_slope=0.01)
leaky_relu = nn.LeakyReLU(negative_slope=0.01)
x = torch.tensor([-1.0, 0.5, 2.0])
print(leaky_relu(x)) # tensor([-0.0100, 0.5000, 2.0000])
3. 损失函数(Loss Function)
损失函数(或代价函数)用于衡量模型预测值与真实值之间的差异,是模型训练的 “指南针”。训练的目标是最小化损失函数的值。
(1)均方误差损失(MSE Loss)
- 用途:回归任务
- 公式:
MSE(y_true, y_pred) = mean((y_true - y_pred)²)
- API:
torch.nn.MSELoss()
mse_loss = nn.MSELoss()
y_true = torch.tensor([2.0, 3.0, 4.0])
y_pred = torch.tensor([1.5, 3.5, 3.8])
loss = mse_loss(y_pred, y_true)
print(f"MSE损失: {loss.item()}") # 输出: 0.1767
(2)交叉熵损失(Cross-Entropy Loss)
- 用途:分类任务
- 特点:结合了 Softmax 激活和负对数似然损失
- API:
torch.nn.CrossEntropyLoss()
ce_loss = nn.CrossEntropyLoss()
# 预测值(未经过softmax,形状:[样本数, 类别数])
y_pred = torch.tensor([[2.0, 1.0, 0.1], [0.5, 2.0, 0.3]])
# 真实标签(类别索引,形状:[样本数])
y_true = torch.tensor([0, 1])
loss = ce_loss(y_pred, y_true)
print(f"交叉熵损失: {loss.item()}") # 输出: 0.3133
(3)二元交叉熵损失(BCE Loss)
- 用途:二分类任务
- 注意:输入需要经过 Sigmoid 激活
- API:
torch.nn.BCELoss()
bce_loss = nn.BCELoss()
# 预测值(经过sigmoid,形状:[样本数, 1])
y_pred = torch.tensor([[0.8], [0.3]])
# 真实标签(形状:[样本数, 1])
y_true = torch.tensor([[1.0], [0.0]])
loss = bce_loss(y_pred, y_true)
print(f"二元交叉熵损失: {loss.item()}") # 输出: 0.3084
4. 优化器(Optimizer)
优化器用于根据损失函数的梯度更新网络参数,最小化损失函数。核心思想是梯度下降法及其变体。
PyTorch 在 torch.optim
模块中提供了多种优化器,常用的包括:
- SGD(随机梯度下降)
- Adagrad(自适应梯度)
- RMSprop(均方根传播)
- Adam(自适应矩估计)
核心方法有:
zero_grad()
:清空模型参数的梯度(将梯度置零)。必须在loss.backward()
之前调用zero_grad()
,避免梯度累积。
step()
:参数更新;是优化器的核心方法,用于根据计算得到的梯度更新模型参数。优化器会根据梯度和学习率等参数,调整模型的权重和偏置。
随机梯度下降(SGD)
- 基本的梯度下降算法
- API:
torch.optim.SGD(params, lr=0.01, momentum=0)
- 参数:
params
:需要优化的网络参数lr
:学习率momentum
:动量,加速收敛
import torch
import torch.nn as nn
import torch.optim as optim# 优化方法SGD的学习
def test003():model = nn.Linear(20, 60)criterion = nn.MSELoss()# 优化器:更新模型参数optimizer = optim.SGD(model.parameters(), lr=0.01)input = torch.randn(128, 20)output = model(input)# 计算损失及反向传播loss = criterion(output, torch.randn(128, 60))# 梯度清零optimizer.zero_grad()# 反向传播loss.backward()# 更新模型参数optimizer.step()print(loss.item())if __name__ == "__main__":test003()
三、数据准备
在 PyTorch 中,数据加载通过Dataset和DataLoader实现,流程为:
Dataset(定义数据读取逻辑)→ DataLoader(批量加载、打乱、并行处理)
1. 构建数据类
Dataset 类
- 作用:定义数据的索引方式和读取逻辑。
- 必须实现的方法:
__len__()
:返回数据集总样本数。__getitem__(idx)
:返回索引为idx
的样本(特征 + 标签)。
在 PyTorch 中,构建自定义数据加载类通常需要继承 torch.utils.data.Dataset 并实现以下几个方法:
-
_init_ 方法
用于初始化数据集对象:通常在这里加载数据,或者定义如何从存储中获取数据的路径和方法。def __init__(self, data, labels):self.data = dataself.labels = labels
-
_len_ 方法
返回样本数量:需要实现,以便 Dataloader加载器能够知道数据集的大小。def __len__(self):return len(self.data)
-
_getitem_ 方法
根据索引返回样本:将从数据集中提取一个样本,并可能对样本进行预处理或变换。def __getitem__(self, index):sample = self.data[index]label = self.labels[index]return sample, label
自定义 Dataset 示例
import torch
from torch.utils.data import Dataset
import pandas as pd# 自定义数据集类
import torch
from torch.utils.data import Dataset,DataLoader
from torchvision import datasets
'''
Dataset:数据集类
1.数据集类需要继承Dataset类
2.实现__init__方法,数据初始化
3.实现__len__方法,返回数据集的长度
4.实现__getitem__,根据索引下标获取数据DataLoader:数据加载器
返回一个迭代器
参数(
dataset:加载的数据集
batch_size:每批次读取的样本数量
shuffle:是否打乱顺序:True-打乱
)'''
class MyDataset(Dataset):def __init__(self,data,labels):assert len(data) == len(labels)self.data = dataself.labels = labelsdef __len__(self):return len(self.data)def __getitem__(self,index):sample = self.data[index]label = self.labels[index]return sample,labeldef test01():x = torch.randn(100,68)y = torch.randn(100,10)dataset = MyDataset(x,y)# print(len(dataset))# print(dataset[0])dataloader = DataLoader(dataset = dataset,batch_size=100,shuffle=True)for x,y in dataloader:print(x.shape)print(y.shape)if __name__ == '__main__':test01()
TensorDataset
- 作用:当特征和标签已为 Tensor 时,快速构建 Dataset。
- API:
torch.utils.data.TensorDataset(*tensors)
( tensors 长度需一致)。
import torch
from torch.utils.data import DataLoader,TensorDataset'''
TensorDataset:torch提供的dataset类
如果对数据没有特殊处理的情况下使用
如果需要对数据进行特殊处理,使用Dataset类
'''
def test01():x = torch.randn(100,68)y = torch.randn(100,10)dataset = TensorDataset(x,y)dataLoader = DataLoader(dataset = dataset,batch_size=100,shuffle=True)for x,y in dataLoader:print(x.shape)print(y.shape)if __name__ == '__main__':test01()
2. 数据加载器(DataLoader)
在深度学习中,数据加载器(DataLoader)是连接数据与模型的重要组件,负责高效地将数据输入到神经网络中。它解决了大规模数据加载、批处理、并行加载等关键问题,是训练神经网络不可或缺的工具。
核心作用:
- 批量处理数据:将数据分成小批次(batch)输入模型,而不是一次性加载全部数据
- 数据打乱:训练时随机打乱数据顺序,提高模型泛化能力
- 并行加载:利用多进程加速数据加载,缓解 IO 瓶颈
- 数据预处理:配合 Dataset 实现数据的动态预处理
核心参数:
dataset
:传入定义好的 Dataset。batch_size
:每个批次的样本数。shuffle
:是否打乱数据(训练集常用True
)。num_workers
:加载数据的进程数(>0 时需在if __name__ == "__main__":
中运行)。
from torch.utils.data import DataLoader# 从自定义Dataset构建DataLoader
dataloader = DataLoader(dataset=dataset, # 上文定义的MyDatasetbatch_size=2, # 每批2个样本shuffle=True, # 打乱数据num_workers=0 # 单进程(调试用,多进程需在main中)
)# 迭代访问批量数据
for batch_idx, (batch_features, batch_labels) in enumerate(dataloader):print(f"批次 {batch_idx}:")print(f" 特征:{batch_features}")print(f" 标签:{batch_labels}\n")
CSV文件加载
- 使用
pandas
加载和预处理表格数据 - 区分数值型和类别型特征,分别进行标准化和独热编码
- 在
Dataset
中处理训练集和测试集的预处理差异(训练集拟合,测试集仅转换) - 对于大型 CSV 文件,可考虑分块读取
pandas
:读取 CSV/Excel 文件- 自定义 Dataset:提取特征和标签
import torch
from torch.utils.data import Dataset,DataLoader
import pandas as pd
class MyCsvDataset(Dataset):def __init__(self,filepath):df = pd.read_csv(filepath)# 去掉文字列df.drop(columns=['学号', '姓名'], inplace=True)# 转换为tensordata = torch.tensor(df.values)# 最后一列以前的为data,最后一列以后为labelself.data = data[:, :-1]self.labels = data[:, -1]def __len__(self):return len(self.data)def __getitem__(self, index):sample = self.data[index]label = self.labels[index]return sample, labeldef test01():dataset = MyCsvDataset('../../图片资料/大数据答辩成绩表.csv')dataloader = DataLoader(dataset = dataset,batch_size=100,shuffle=True)for data, label in dataloader:print(data, label)break
if __name__ == '__main__':test01()
图片加载
使用ImageFolder加载图片集
ImageFolder
会根据文件夹的结构来加载图像数据。它假设每个子文件夹对应一个类别,文件夹名称即为类别名称。例如,一个典型的文件夹结构如下:
root/class1/img1.jpgimg2.jpg...class2/img1.jpgimg2.jpg......
在这个结构中:
root
是根目录。class1
、class2
等是类别名称。- 每个类别文件夹中的图像文件会被加载为一个样本。
核心 API
torchvision.datasets.ImageFolder
:自动读取按类别分文件夹的图像数据torchvision.transforms
:图像预处理(缩放、裁剪、归一化等)
'''参数解释
torchvision.datasets.ImageFolder
- `root`:字符串,指定图像数据集的根目录。
- `transform`:可选参数,用于对图像进行预处理。通常是一个 `torchvision.transforms` 的组合。
- `target_transform`:可选参数,用于对目标(标签)进行转换。
- `is_valid_file`:可选参数,用于过滤无效文件。如果提供,只有返回 `True` 的文件才会被加载。
'''
import torch
from torch.utils.data import DataLoader
from torchvision import transforms,datasets
def load():filepath = '../../图片资料/animals'# 数据预处理transform = transforms.Compose([transforms.Resize(size=(224,224)),transforms.ToTensor()])# 定义数据集dataset = datasets.ImageFolder(root = filepath,transform = transform,)# 定义数据加载器dataloader = DataLoader(dataset = dataset,batch_size = 4,shuffle = True,)for x,y in dataloader:print(x,y)breakif __name__ == '__main__':load()
官方数据集加载
在 PyTorch 中官方提供了一些经典的数据集,如 CIFAR-10、MNIST、ImageNet 等,可以直接使用这些数据集进行训练和测试。
数据集:https://pytorch.org/vision/stable/datasets.html
常见数据集:
- MNIST: 手写数字数据集,包含 60,000 张训练图像和 10,000 张测试图像。
- CIFAR10: 包含 10 个类别的 60,000 张 32x32 彩色图像,每个类别 6,000 张图像。
- CIFAR100: 包含 100 个类别的 60,000 张 32x32 彩色图像,每个类别 600 张图像。
- COCO: 通用对象识别数据集,包含超过 330,000 张图像,涵盖 80 个对象类别。
torchvision.transforms 和 torchvision.datasets 是 PyTorch 中处理计算机视觉任务的两个核心模块,它们为图像数据的预处理和标准数据集的加载提供了强大支持。
transforms
模块提供了一系列用于图像预处理的工具,可以将多个变换组合成处理流水线。
datasets
模块提供了多种常用计算机视觉数据集的接口,可以方便地下载和加载。
import torch
from torch.utils.data import DataLoader,Dataset
from torchvision import transforms,datasets# MNIST数据集:黑底白字的手写数字,图片分辨率:28*28
# 分训练数据集(60000)和测试数据集(10000)
def test01():transform = transforms.Compose([transforms.ToTensor(),])'''train:是否为训练数据集root:保存数据集的路径transform:图片转换器'''train_dataset = datasets.MNIST(root='../../图片资料',train=True,download=True,transform=transform,)dataloader = DataLoader(dataset=train_dataset,batch_size=4,shuffle=True,)for x,y in dataloader:print(x.shape)print(y.shape)break
if __name__ == '__main__':test01()