从零开始PyTorch深度学习项目实战教程
本教程将介绍如何使用PyTorch深度学习框架来完成一个完整的深度学习项目。本教程假定你已经具有一定的Python编程经验,并且对深度学习有一定的了解。
环境设置
在开始之前,你需要安装PyTorch和相关的Python库。可以使用Anaconda来创建一个虚拟环境,并在其中安装所需的库:
conda create --name pytorch_env python=3.8
conda activate pytorch_env
conda install pytorch torchvision torchaudio -c pytorch
conda install pandas matplotlib jupyter notebook
项目介绍
我们将使用一个人脸识别任务来演示PyTorch的使用。我们将使用CelebA数据集中的人脸图像,该数据集包含超过200,000个人脸图像,每个人脸都有40个属性注释。
我们的任务是根据图像中人脸的属性,预测该人是否戴眼镜。我们将使用卷积神经网络(CNN)来完成这个任务。
数据准备
在开始之前,我们需要下载CelebA数据集。可以从其官方网站下载此数据集。下载完数据集后,我们需要将其解压到我们的工作目录中。
解压后,我们应该会得到一个名为CelebA的文件夹,其中包含以下子文件夹:
Anno:包含40个属性注释文件。
Eval:包含评估脚本。
Img:包含202,599个JPEG图像。
list_eval_partition.txt:包含图像的分区列表。
list_eval.txt:包含每个图像的属性注释。
我们将使用list_eval.txt和list_eval_partition.txt文件来准备我们的数据。
首先,我们需要读取list_eval_partition.txt文件,并将其拆分为训练、验证和测试集。我们将使用前200,000个图像作为训练集,接下来的20,000个图像作为验证集,最后的2,599个图像作为测试集。
import pandas as pd
partition_file = 'CelebA/list_eval_partition.txt'
partition_df = pd.read_csv(partition_file, delim_whitespace=True, header=None, names=['image_id', 'partition'])
partition_df = partition_df.set_index('image_id')
train_ids = partition_df[partition_df['partition'] == 0].index.tolist()
val_ids = partition_df[partition_df['partition'] == 1].index.tolist()
test_ids = partition_df[partition_df['partition'] == 2].index.tolist()
接下来,我们需要读取list_eval.txt文件,并获取每个图像的属性注释。我们只需要Eyeglasses属性,它指示人物是否戴眼镜。
attributes_file = 'CelebA/list_eval.txt'
attributes_df = pd.read_csv(attributes_file, delim_whitespace=True, header=None, names=['image_id'] + list(range(40)))
attributes_df = attributes_df.set_index('image_id')
train_attributes = attributes_df.loc[train_ids, '20'].tolist()
val_attributes = attributes_df.loc[val_ids, '20'].tolist()
test_attributes = attributes_df.loc[test_ids, '20'].tolist()
现在我们已经准备好了我们的数据,我们可以开始定义我们的数据加载器了。
数据加载器
我们将使用PyTorch的DataLoader类来加载我们的数据。为此,我们需要自定义一个Dataset类,该类将负责将图像和它们的标签加载到内存中。
from PIL import Image
import torch
from torch.utils.data import Dataset
class CelebADataset(Dataset):
def __init__(self, ids, attributes, root_dir='CelebA/Img', transform=None):
self.ids = ids
self.attributes = attributes
self.root_dir = root_dir
self.transform = transform
def __len__(self):
return len(self.ids)
def __getitem__(self, idx):
image_id = self.ids[idx]
image_file = f'{self.root_dir}/{image_id}'
image = Image.open(image_file)
target = self.attributes[idx]
if self.transform:
image = self.transform(image)
return image, target
我们定义了一个CelebADataset类,它继承了PyTorch的Dataset类,并实现了__init__、__len__和__getitem__方法。__init__方法初始化数据集,__len__方法返回数据集的大小,__getitem__方法返回给定索引的图像和标签。
在__getitem__方法中,我们首先将图像ID转换为图像文件路径,然后使用Pillow库的Image.open方法加载图像。我们还将目标属性作为标签返回。
现在,我们可以使用我们的CelebADataset类来创建训练、验证和测试数据加载器了。
from torchvision.transforms import transforms
from torch.utils.data import DataLoader
train_transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.Resize((128, 128)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
test_transform = transforms.Compose([
transforms.Resize((128, 128)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
train_dataset = CelebADataset(train_ids, train_attributes, transform=train_transform)
val_dataset = CelebADataset(val_ids, val_attributes, transform=test_transform)
test_dataset = CelebADataset(test_ids, test_attributes, transform=test_transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
我们使用transforms.Compose方法定义了训练和测试数据集的变换。在训练数据集中,我们使用随机水平翻转来增强数据。我们还将所有图像调整为大小为128x128,并将它们转换为PyTorch张量。最后,我们对图像进行标准化,以便它们的像素值在[-1, 1]范围内。
在测试数据集中,我们只对图像进行大小调整、转换为张量和标准化。
我们使用DataLoader类将我们的数据集加载到内存中,每次返回一个批次的数据。我们将训练数据集进行打乱,以便模型在每个时期都能看到不同的样本顺序。
模型定义
我们将使用一个简单的卷积神经网络来完成我们的任务。该模型由三个卷积层、三个池化层和两个全连接层组成。
import torch.nn as nn
class Net(nn.Module):
def init(self):
super(Net, self).init()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.fc1 = nn.Linear(128 * 16 * 16, 512)
self.fc2 = nn.Linear(512, 1)
def forward(self, x):
x = nn.functional.relu(self.conv1(x))
x = self.pool(nn.functional.relu(self.conv2(x)))
x = self.pool(nn.functional.relu(self.conv3(x)))
x = x.view(-1, 128 * 16 * 16)
x = nn.functional.relu(self.fc1(x))
x = nn.functional.sigmoid(self.fc2(x))
return x
我们使用PyTorch的nn.Module类定义了一个名为Net的模型。在__init__方法中,我们定义了三个卷积层和两个全连接层。每个卷积层之后都有一个ReLU激活函数和一个最大池化层。最后一个全连接层之后有一个Sigmoid激活函数,它将输出值压缩到[0, 1]之间,表示模型对于该图像的置信度。
在forward方法中,我们定义了模型的前向传播过程。我们首先通过第一个卷积层,然后使用ReLU激活函数进行非线性变换。接下来,我们使用最大池化层来减小特征图的大小。我们重复这个过程两次,然后将特征图展平为一个向量。最后,我们通过两个全连接层来计算输出值。
8万+





