赞
踩
torch:
这是PyTorch框架的基础库,提供了自动求导机制和丰富的张量运算支持,是构建和训练神经网络的基础。
torch.nn:
PyTorch的神经网络库,包含多种构建神经网络所需的层结构(如卷积层、全连接层)和激活函数等
torch.utils.data:
提供了数据加载和处理的工具,是加载数据集并进行批处理的重要模块
torchvision.transforms:
PyTorch的视觉库中的一个模块,提供了一系列图像处理的变换操作,用于数据增强和预处理
torchvision.datasets:
提供了常见的数据集和相关的数据加载方法,如MNIST、CIFAR-10、ImageNet等
DataLoader:
torch.utils.data中的一个类,用于构建可迭代的数据加载器,可以方便地在训练循环中按批次加载数据
torch.optim.lr_schedule
r: 提供了学习率调整策略,如学习率衰减,有助于训练过程中改善模型性能和减少过拟合
os:
Python的标准库之一,提供了与操作系统交互的功能,如文件创建、路径操作等
import torch.optim as optim
import torch
import torch.nn as nn
import torch.utils.data
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
import torch.optim.lr_scheduler as lr_scheduler
import os
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)):
随机裁剪图像,裁剪后的图像大小为256x256像素。裁剪区域的大小是原始图像尺寸的0.8到1.0倍之间随机选择
transforms.RandomRotation(degrees=15):
随机旋转图像,旋转角度在-15度到15度之间随机选择
transforms.RandomHorizontalFlip():
随机水平翻转图像,即有一半的概率会翻转,一半的概率不翻
transforms.CenterCrop(size=224):
从图像中心裁剪出224x224像素的区域
transforms.ToTensor():
将图像转换为PyTorch张量,并且将像素值从[0, 255]范围缩放到[0, 1]范围
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]):
对图像进行标准化处理。这里使用的是ImageNet数据集的均值和标准差,这些值分别用于每个颜色通道的减均值和除以标准差操作
验证数据预处理 (transform[‘val’])
transforms.Resize(size=256):
将图像大小调整为256x256像素,这里没有使用随机裁剪,而是直接调整大小
transforms.CenterCrop(size=224):
从图像中心裁剪出224x224像素的区域
transforms.ToTensor():
将图像转换为PyTorch张量,并且将像素值从[0, 255]范围缩放到[0, 1]范围
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]):
对图像进行标准化处理,使用的是ImageNet数据集的均值和标准差
# 定义数据预处理 transform = { 'train': transforms.Compose([ transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)), transforms.RandomRotation(degrees=15), transforms.RandomHorizontalFlip(), transforms.CenterCrop(size=224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(size=256), transforms.CenterCrop(size=224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) }
dataset = './dataset':
这行代码设置了数据集的根目录。这里的./表示当前工作目录,所以dataset变量指向的是当前工作目录下的dataset文件夹
train_directory = os.path.join(dataset, 'train'):
这行代码将dataset目录和train子目录连接起来,创建训练数据集的完整路径。如果当前工作目录是/home/user/project,那么train_directory将是/home/user/project/dataset/train
valid_directory = os.path.join(dataset, 'val'):
这行代码将dataset目录和val子目录连接起来,创建验证数据集的完整路径。同样,如果当前工作目录是/home/user/project,那么valid_directory将是/home/user/project/dataset/val
dataset = './dataset'
train_directory = os.path.join(dataset, 'train')
valid_directory = os.path.join(dataset, 'val')
batch_size = 32
num_classes = 2 # 修改为您的分类数
data = { ... }:
这个字典定义了两个键:‘train’和’val’,它们分别对应于训练和验证数据集。对于每个键,都使用torchvision.datasets.ImageFolder类来创建一个数据集。ImageFolder假设每个类别的图像都存储在一个单独的文件夹中,并且文件夹的名称是类别的名称。root参数指定了数据集的根目录,transform参数指定了应用于每个图像的预处理操作
train_loader = DataLoader(data['train'], batch_size=batch_size, shuffle=True, num_workers=8):
这行代码创建了训练数据加载器。DataLoader类接受一个数据集作为输入,并提供一个可迭代的数据加载器。batch_size参数指定了每个批次中图像的数量。shuffle=True表示在每次遍历数据集时都会随机打乱数据的顺序,这对于训练是有益的,因为它可以减少模型的过拟合。num_workers=8表示在加载数据时使用8个子进程。这可以加快数据加载速度,尤其是在使用GPU进行训练时
test_loader = DataLoader(data['val'], batch_size=batch_size, shuffle=False, num_workers=8):
这行代码创建了验证数据加载器。与训练数据加载器类似,但它设置了shuffle=False,因为在验证阶段,我们不希望数据顺序被打乱,以便于评估模型的性能
data = {
'train': datasets.ImageFolder(root=train_directory, transform=transform['train']),
'val': datasets.ImageFolder(root=valid_directory, transform=transform['val'])
}
train_loader = DataLoader(data['train'], batch_size=batch_size, shuffle=True, num_workers=8)
test_loader = DataLoader(data['val'], batch_size=batch_size, shuffle=False, num_workers=8)
class VGG16(nn.Module):
这行代码定义了一个新的类VGG16,它继承自nn.Module。nn.Module是所有神经网络模块的基类
def __init__(self, num_classes=1000):
构造函数接收一个参数num_classes,表示模型输出的类别数。默认值为1000,这是ImageNet数据集的类别数
super(VGG16, self).__init__():
这行代码调用了基类的构造函数
self.features = nn.Sequential(...):
这部分定义了VGG-16的特征提取部分,包括5个卷积块,每个卷积块包含多个卷积层和一个池化层。每个卷积层后面都跟着一个ReLU激活函数
self.classifier = nn.Sequential(...):
这部分定义了VGG-16的分类器部分,包括3个全连接层,每个全连接层后面都跟着一个ReLU激活函数和一个Dropout层。最后一个全连接层的输出节点数与num_classes参数相同
def forward(self, x):
前向传播函数接收输入x,首先通过特征提取部分self.features,然后将特征图展开为一维向量,最后通过分类器部分self.classifier得到最终的分类结果
class VGG16(nn.Module): def __init__(self, num_classes=1000): super(VGG16, self).__init__() self.features = nn.Sequential( # Block 1 nn.Conv2d(3, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(64, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 2 nn.Conv2d(64, 128, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(128, 128, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 3 nn.Conv2d(128, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 4 nn.Conv2d(256, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 5 nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ) self.classifier = nn.Sequential( nn.Linear(512 * 7 * 7, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, num_classes) # 修改这里,默认为1000个类别 ) def forward(self, x): x = self.features(x) x = torch.flatten(x, 1) # 展开特征图 x = self.classifier(x) return x
vgg16 = VGG16(num_classes=2):
这行代码创建了一个VGG-16模型的实例,并将输出类别数设置为2。这意味着模型的最后一层全连接层将有2个输出节点,对应于两个类别
vgg16 = vgg16.to(DEVICE):
这行代码将创建的VGG-16模型移动到指定的设备上。这里的DEVICE应该是一个之前定义的变量,表示您希望模型运行的设备。例如,如果DEVICE是torch.device(‘cuda’),则模型将被移动到GPU上;如果DEVICE是torch.device(‘cpu’),则模型将在CPU上运行
vgg16 = VGG16(num_classes=2)
vgg16 = vgg16.to(DEVICE)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(vgg16.parameters(), lr=0.001, momentum=0.9)
scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
model.train():
这行代码将模型设置为训练模式。在某些模型中,训练模式和评估模式(例如BatchNorm和Dropout)的行为是不同的
running_loss = 0.0:
初始化运行损失为0,用于累加每个批次的损失
correct = 0:
初始化正确分类的样本数为0
total = 0:
初始化总样本数为0
for batch_idx, (data, target) in enumerate(train_loader):
这行代码开始一个循环,遍历训练数据加载器train_loader中的每个批次。batch_idx是批次的索引,data是当前批次的数据,target是当前批次的目标标签
data, target = data.to(device), target.to(device):
这行代码将数据和目标标签移动到之前定义的设备上,如果设备是GPU,这将使数据能够在GPU上进行计算
optimizer.zero_grad(): 清空模型的梯度。在PyTorch中,梯度是累加的,所以在每次反向传播之前需要清空之前的梯度
output = model(data):
将当前批次的数据通过模型前向传播,得到模型的输出
loss = criterion(output, target): 计算模型输出和目标标签之间的损失
loss.backward():
执行反向传播,计算模型的梯度
running_loss += loss.item():
累加当前批次的损失到运行损失中
predicted = torch.max(output.data, 1):
获取模型预测的最大概率类别。torch.max返回最大值和最大值的索引,这里我们只关心索引,即预测的类别
total += target.size(0):
累加当前批次的目标标签数量到总样本数中
correct += (predicted == target).sum().item():
计算当前批次中正确分类的样本数,并累加到正确分类的总数中
if batch_idx % 10 == 0:
: 如果当前批次的索引是10的倍数,打印当前批次的损失
print(f'Epoch {epoch}, Loss: {running_loss / len(train_loader)}, Accuracy: {100 * correct / total}%'):
在一个训练周期结束后,打印出整个周期的平均损失和准确率
def train(model, device, train_loader, optimizer, criterion, epoch): model.train() running_loss = 0.0 correct = 0 total = 0 for batch_idx, (data, target) in enumerate(train_loader): data, target = data.to(device), target.to(device) # 修正缩进 optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() running_loss += loss.item() _, predicted = torch.max(output.data, 1) total += target.size(0) correct += (predicted == target).sum().item() if batch_idx % 10 == 0: # 每10个批次打印一次 print(f'Epoch {epoch}, Batch {batch_idx}, Loss: {loss.item()}') print(f'Epoch {epoch}, Loss: {running_loss / len(train_loader)}, Accuracy: {100 * correct / total}%')
model.eval():
这行代码将模型设置为评估模式。在某些模型中,训练模式和评估模式(例如BatchNorm和Dropout)的行为是不同的
running_loss = 0.0:
初始化运行损失为0,用于累加每个批次的损失
correct = 0: 初始化正确分类的样本数为0
total = 0:
初始化总样本数为0
with torch.no_grad(): 这个上下文管理器用于告诉PyTorch在接下来的代码块中不要计算梯度。因为在验证过程中我们不需要更新模型参数,所以不需要计算梯度
for data, target in test_loader:
这行代码开始一个循环,遍历验证数据加载器test_loader中的每个批次。data是当前批次的数据,target是当前批次的目标标签
data, target = data.to(device), target.to(device):
这行代码将数据和目标标签移动到之前定义的设备上,如果设备是GPU,这将使数据能够在GPU上进行计算
output = model(data):
将当前批次的数据通过模型前向传播,得到模型的输出
loss = criterion(output, target):
计算模型输出和目标标签之间的损失
running_loss += loss.item():
累加当前批次的损失到运行损失中
predicted = torch.max(output.data, 1):
获取模型预测的最大概率类别。torch.max返回最大值和最大值的索引,这里我们只关心索引,即预测的类别
total += target.size(0):
累加当前批次的目标标签数量到总样本数中
correct += (predicted == target).sum().item():
计算当前批次中正确分类的样本数,并累加到正确分类的总数中
print(f'Validation, Loss: {running_loss / len(test_loader)}, Accuracy: {100 * correct / total}%'):
在验证结束后,打印出整个验证周期的平均损失和准确率
# 定义验证过程 def val(model, device, test_loader, criterion): model.eval() running_loss = 0.0 correct = 0 total = 0 with torch.no_grad(): for data, target in test_loader: data, target = data.to(device), target.to(device) output = model(data) loss = criterion(output, target) running_loss += loss.item() _, predicted = torch.max(output.data, 1) total += target.size(0) correct += (predicted == target).sum().item() print(f'Validation, Loss: {running_loss / len(test_loader)}, Accuracy: {100 * correct / total}%')
EPOCHS = 10
for epoch in range(1, EPOCHS + 1):
train(vgg16, DEVICE, train_loader, optimizer, criterion, epoch)
val(vgg16, DEVICE, test_loader, criterion)
scheduler.step() # 调整学习率
torch.save(vgg16.state_dict(), 'vgg16_model_weights.pth')
import torch from PIL import Image import torchvision.transforms as transforms from torchvision import models from torch.autograd import Variable import torch.optim as optim import torch import torch.nn as nn # 定义数据预处理 transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) # 定义类别 classes = ['cat', 'dog'] # 替换为您的实际类别名称 # 检查是否有可用的 GPU DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") class VGG16(nn.Module): def __init__(self, num_classes=1000): super(VGG16, self).__init__() self.features = nn.Sequential( # Block 1 nn.Conv2d(3, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(64, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 2 nn.Conv2d(64, 128, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(128, 128, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 3 nn.Conv2d(128, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 4 nn.Conv2d(256, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), # Block 5 nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ) self.classifier = nn.Sequential( nn.Linear(512 * 7 * 7, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, num_classes) # 修改这里,默认为1000个类别 ) def forward(self, x): x = self.features(x) x = torch.flatten(x, 1) # 展开特征图 x = self.classifier(x) return x # 初始化VGG16模型 model = VGG16(num_classes=2) model = vgg16.to(DEVICE) # 加载权重 model.load_state_dict(torch.load("vgg16_model.pth")) model.to(DEVICE) model.eval() # 定义预测函数 def predict_image(image_path): # 打开图片 image = Image.open(image_path) # 应用预处理 image = transform(image).unsqueeze(0) # 添加batch维度 # 转换为Variable(如果模型需要) image = Variable(image).to(DEVICE) # 获取模型预测 output = model(image) _, prediction = torch.max(output.data, 1) return classes[prediction.item()] # 上传的图片路径 uploaded_image_path = '44.jpg' # 进行预测 predicted_class = predict_image(uploaded_image_path) print(f"The uploaded image is predicted as: {predicted_class}")
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。