pytorch深度学习项目实战100例 的学习记录
我的环境:
白票大王: google colab
用其他的话,其实实现也行,但是让小白来重环境来开始安装的话,浪费时间
数据集
Clothing dataset
20 个不同类别的 5000 多张图片。
该数据集可免费用于任何目的,包括商业用途:
例如
创建教程或课程(免费或付费)
撰写书籍
Kaggle 竞赛(作为外部数据集)
训练任何公司的内部模型
数据
images.csv
文件包含
image
- 图像的 ID(用它从 images/.jpg 中加载图像)
sender_id
- 提供图片者的 ID
label
- 图片的类别
kids
- 标记,如果是儿童服装,则为 True
数据集下载
VGG网络,全称为Visual Geometry Group Network
是由牛津大学的Visual Geometry Group提出的一种深度学习网络架构。该网络在2014年的ImageNet挑战赛中取得了优异的成绩,主要以其简洁的架构和出色的性能著称。VGG网络的引入对于深度学习和计算机视觉领域的发展产生了重要影响,以下是VGG网络的一些主要特点和网络结构的详细介绍:
特点
-
统一的卷积核尺寸:VGG网络使用了统一的
3×3的卷积核,步长为1。这种小尺寸卷积核的使用是VGG网络的一个标志性特点,它允许网络通过堆叠多层小卷积核来增加网络深度,同时保持计算效率。 -
增加网络深度:VGG网络通过重复堆叠卷积层和池化层来增加网络深度,最著名的版本是VGG-16和VGG-19,分别含有16层和19层权重层。这种深度的增加显著提高了网络的性能。
-
使用ReLU激活函数:VGG网络在每个卷积层后使用了ReLU(Rectified Linear Unit)作为激活函数,以增加非线性特性并加速训练过程。
-
池化层的使用:VGG网络在连续的几个卷积层之后使用最大池化层来进行特征下采样,这有助于减少计算量和防止过拟合。
网络结构
VGG网络的基本单元是连续的卷积层,后面跟着ReLU激活函数,然后是可选的池化层。这一基本单元重复多次,形成了VGG网络的主体。以下是VGG-16网络的一个典型结构:
-
输入层:接受固定尺寸的图像,如224×224的RGB图像。
-
卷积层:多个3×3卷积层,每个卷积层后面跟着ReLU激活函数。在初期层次中,卷积层的数量较少(通常是2-3层),在更深的层次中数量增多。
-
池化层:每几个卷积层后会跟一个2×2的最大池化层,用于下采样。
-
全连接层:网络末端有三个全连接层,前两个全连接层各有4096个节点,最后一个全连接层用于分类,节点数与分类任务的类别数相等。
-
输出层:最后是一个softmax层,用于输出分类的概率分布。
VGG网络的这种结构设计简洁而有效,尤其是在处理图像分类和识别任务时表现出色。
vgg 迁移学习
首先,利用torchvision
中的models
,通过models
调用vgg16
模型,如果参数pretrained
的true
,就会自动下载
model = models.vgg16(pretrained=True)
查看网络结构
model._modules
VGG模型由于其出色的特征提取能力,常被用于迁移学习中,特别是在图像识别和分类任务上。迁移学习允许我们利用在大型数据集(如ImageNet)上预训练的模型,将其应用于数据量较小的特定任务上,通常可以显著提高性能。但是ImageNet里面有1000类别,我们数据集只有19个类
model.classifier[6]
model.classifier[6] = nn.Linear(in_features=4096, out_features=19)
阿光的代码,完整代码
import json
import os
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
import torchvision.models as models
from tqdm import tqdm
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
data_transform = {
'train': transforms.Compose([transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}
image_path = './images'
train_dataset = datasets.ImageFolder(root=os.path.join(image_path, 'train'),
transform=data_transform['train'])
batch_size = 32
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size,
True)
print('using {} images for training.'.format(len(train_dataset)))
cloth_list = train_dataset.class_to_idx
class_dict = {}
for key, val in cloth_list.items():
class_dict[val] = key
with open('class_dict.pk', 'wb') as f:
pickle.dump(class_dict, f)
model_path = './checkpoints/vgg16-397923af.pth'
model = models.vgg16(pretrained=False)
model.load_state_dict(torch.load(model_path, 'cpu'))
for parma in model.parameters(): # 设置自动梯度为false
parma.requires_grad = False
model.classifier[6] = nn.Linear(in_features=4096, out_features=19)
model.to(device)
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.03)
epochs = 10
best_acc = 0
best_model = None
save_path = './checkpoints/best_model.pkl'
for epoch in range(epochs):
model.train()
running_loss = 0
epoch_acc = 0 # 每个epoch的准确率
epoch_acc_count = 0 # 每个epoch训练的样本数
train_count = 0 # 用于计算总的样本数,方便求准确率
train_bar = tqdm(train_loader)
for data in train_bar:
images, labels = data
optimizer.zero_grad()
output = model(images.to(device))
loss = loss_function(output, labels.to(device))
loss.backward()
optimizer.step()
running_loss += loss.item()
train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
epochs,
loss)
# 计算每个epoch正确的个数
epoch_acc_count += (output.argmax(axis=1) == labels.view(-1)).sum()
train_count += len(images)
# 每个epoch对应的准确率
epoch_acc = epoch_acc_count / train_count
# 打印信息
print("【EPOCH: 】%s" % str(epoch + 1))
print("训练损失为%s" % str(running_loss))
print("训练精度为%s" % (str(epoch_acc.item() * 100)[:5]) + '%')
if epoch_acc > best_acc:
best_acc = epoch_acc
best_model = model.state_dict()
# 在训练结束保存最优的模型参数
if epoch == epochs - 1:
# 保存模型
torch.save(best_model, save_path)
print('Finished Training')
with open('class_dict.pk', 'rb') as f:
class_dict = pickle.load(f)
data_transform = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img_path = r'./images/test/0f2ac7b8-c769-4f0b-a915-5680d0dad34c.jpg'
img = Image.open(img_path)
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
pred = class_dict[model(img).argmax(axis=1).item()]
print('【预测结果分类】:%s' % pred)
没有下载他弄好的数据集,当然不行拉阿 TT
然后我去直接下载github的
发现了skip里面的图片有几张是错误的
只能跳过
import pandas as pd
# CSV文件路径
csv_file_path = '/content/clothing-dataset/images.csv'
# 图片所在目录
images_directory = '/content/clothing-dataset/images/'
# 读取CSV文件
df = pd.read_csv(csv_file_path)
# 过滤掉标签为'skip'的行
df_filtered = df[df['label'] != 'Skip']
# print(df_filtered)
# 找出所有应该被删除的图片文件
images_to_delete = df[df['label'] == 'Skip']['image']
# images_to_delete
for image_id in images_to_delete:
image_path = os.path.join(images_directory,f"{image_id}.jpg")
if os.path.exists(image_path):
os.remove(image_path)
print(f"Deleted{image_path}")
# 保存更新后的DataFrame到新的CSV文件
df_filtered.to_csv('/content/clothing-dataset/updated_file.csv', index=False) # 指定新的CSV文件路径
# 再次加载更新后的CSV文件进行验证
df_updated = pd.read_csv('/content/clothing-dataset/updated_file.csv')
print("含'skip'标签的行数:", df_updated[df_updated['label'] == 'Skip'].shape[0])
优化器
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.03)
训练和保存模型
model.to(device)
epochs = 10
best_acc = 0
best_model = None
save_path = './checkpoints/best_model.pkl'
for epoch in range(epochs):
model.train()
running_loss = 0
epoch_acc = 0 # 每个epoch的准确率
epoch_acc_count = 0 # 每个epoch训练的样本数
train_count = 0 # 用于计算总的样本数,方便求准确率
train_bar = tqdm(train_loader)
for data in train_bar:
images, labels = data
optimizer.zero_grad()
output = model(images.to(device))
loss = loss_function(output, labels.to(device))
loss.backward()
optimizer.step()
running_loss += loss.item()
train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
epochs,
loss)
# 计算每个epoch正确的个数
epoch_acc_count += (output.argmax(axis=1) == labels.view(-1)).sum()
train_count += len(images)
# 每个epoch对应的准确率
epoch_acc = epoch_acc_count / train_count
# 打印信息
print("【EPOCH: 】%s" % str(epoch + 1))
print("训练损失为%s" % str(running_loss))
print("训练精度为%s" % (str(epoch_acc.item() * 100)[:5]) + '%')
if epoch_acc > best_acc:
best_acc = epoch_acc
best_model = model.state_dict()
# 在训练结束保存最优的模型参数
if epoch == epochs - 1:
# 保存模型
torch.save(best_model, save_path)
print('Finished Training')
with open('class_dict.pk', 'rb') as f:
class_dict = pickle.load(f)
data_transform = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img_path = r'./images/test/0f2ac7b8-c769-4f0b-a915-5680d0dad34c.jpg'
img = Image.open(img_path)
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
pred = class_dict[model(img).argmax(axis=1).item()]
print('【预测结果分类】:%s' % pred)