Pytorch
- 一、训练模型
- 1.导入必要的库
- 2.设置超参数
- 3.数据预处理
- 4.读取数据
- 二、定义卷积神经网络
- 1.定义卷积神经网络
- 2.定义学习率
- 3.实例化模型并且移动到GPU
- 4.选择优化器
- 三、定义调整学习率的函数
- 1.定义调整学习率的函数
- 四、训练模型
- 1.设置模型为训练模式
- 2.遍历训练数据加载器
- 3.打印进度
- 五、验证模型
- 1.设置模型为验证模式
- 2.初始化计数器
- 3.遍历测试数据加载器
- 4.计算准确率
- 5.打印验证结果
- 五、定义训练循环
- 2.执行训练和验证
- 3.保存模型
一、训练模型
1.导入必要的库
torch.nn.functional as F: 导入 PyTorch 的不带参数的函数模块,包含各种函数,如激活函数、池化层等。
torch.optim as optim: 导入 PyTorch 的优化器模块,用于定义优化器。
torch.cuda.is_available(): 导入 PyTorch 的 CUDA 模块,用于检查是否有可用的 CUDA GPU。
torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’): 导入 PyTorch 的设备模块,用于定义计算设备。如果 CUDA GPU 可用,则定义为 ‘cuda’;否则定义为 ‘cpu’。
# 导入库
import torch.nn.functional as F
import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
2.设置超参数
定义超参数,这些参数将用于控制模型的训练过程。
以下是超参数的详细说明:
CH_SIZE: 定义了每个训练批次的样本数量。较大的批大小可以提高计算效率,但可能会增加内存需求。在这个例子中,批大小被设置为 20。
EPOCHS: 定义了训练过程中迭代的轮数。每个 epoch 表示数据集被完整地遍历了一次。在这个例子中,训练过程被设置为进行 10 个 epoch。
DEVICE: 定义了计算设备。如果环境中存在可用的 GPU,它会定义为 ‘cuda’;如果环境中没有可用的 GPU,它会定义为 ‘cpu’。
# 设置超参数
#每次的个数
BATCH_SIZE = 20
#迭代次数
EPOCHS = 10
#采用cpu还是gpu进行计算
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
3.数据预处理
定义数据预处理步骤,这些步骤将被应用于每个图像上,以增强数据的多样性并标准化数据格式。
以下是预处理步骤的详细说明:
1)Resize(100): 将图片大小调整为 100x100 像素。
2)RandomVerticalFlip(): 随机垂直翻转图片。
3)RandomCrop(50): 从原始图片中随机裁剪一个大小为 50x50 的区域。
4)RandomResizedCrop(150): 从原始图片中随机裁剪一个大小为 150x150 的区域,并随机调整裁剪区域的缩放比例。
5)ColorJitter(brightness=0.5, contrast=0.5, hue=0.5): 随机调整图片的亮度、对比度和色调。
6)ToTensor(): 将 PIL 图像转换为 PyTorch 张量。
7)Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]): 对图像进行归一化处理,将每个通道的均值和标准差调整为 0.5。
# 定义数据预处理
transform = transforms.Compose([transforms.Resize(100),transforms.RandomVerticalFlip(),transforms.RandomCrop(50),transforms.RandomResizedCrop(150),transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
4.读取数据
使用 PyTorch 的数据加载和处理功能来读取数据集,并为训练和测试阶段准备数据加载器。
以下是代码的详细步骤:
1)dataset_train = datasets.ImageFolder(‘E:\xm\dataset\train’, transform): 创建一个ImageFolder数据集,用于加载和分类E:\xm\dataset\train目录中的图像。这个目录应该包含多个子目录,每个子目录代表一个类别,子目录中的图像将归属于该类别。transform变量包含了应用于每个图像的预处理操作。
2)print(dataset_train.imgs): 打印数据集中所有图像的文件路径和对应的类别索引。imgs是一个列表,每个元素是一个包含图像文件路径和类别索引的元组。
3)print(dataset_train.class_to_idx): 打印类别到索引的映射。class_to_idx是一个字典,键是类别名称,值是相应的索引。
4)dataset_test = datasets.ImageFolder(‘E:\xm\dataset\val’, transform): 创建一个ImageFolder数据集,用于加载和分类E:\xm\dataset\val目录中的验证图像。
5)print(dataset_test.class_to_idx): 这行代码打印验证数据集中类别到索引的映射。
6)train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True): 创建一个训练数据加载器。DataLoader类接受一个数据集和一个批处理大小batch_size,以及一个shuffle标志,表示是否在每次遍历数据集时随机打乱数据的顺序。
7)test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True): 创建一个测试数据加载器。与训练数据加载器类似,但它也用于加载验证数据集。
# 读取数据
dataset_train = datasets.ImageFolder('E:\\xm\dataset\\train', transform)
print(dataset_train.imgs)# 对应文件夹的label
print(dataset_train.class_to_idx)
dataset_test = datasets.ImageFolder('E:\\xm\dataset\\val', transform)# 对应文件夹的label
print(dataset_test.class_to_idx)# 导入数据
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True)
运行结果:
二、定义卷积神经网络
1.定义卷积神经网络
定义名为 ConvNet 的卷积神经网络类,它继承自 torch.nn.Module。这个类实现了一个简单的卷积神经网络结构,用于图像分类任务。
以下是网络结构的详细说明:
1)init(self): 构造函数中,定义了以下层:
- 6 个卷积层(conv1 到 conv6),每个卷积层后面都跟着一个 ReLU 激活函数和 一个最大池化层(max_pool1 到max_pool4)。
- 每个卷积层的输出通道数逐渐增加,从 32 到 128。
- 两个全连接层(fc1 和 fc2),其中 fc1 具有512 个神经元,fc2 具有 1 个神经元(对应于二分类问题)。
- 最后一个全连接层后面跟着一个 Sigmoid 激活函数。
2)forward(self, x): 前向传播函数接收输入 x,并依次通过以下层:
- 6 个卷积和池化层的组合,用于提取图像特征。
- 将最后一个池化层的输出特征图展平为一维向量。
- 通过全连接层 fc1 和 fc2。
- 通过 Sigmoid 激活函数生成最终输出。
class ConvNet(nn.Module):def __init__(self):super(ConvNet, self).__init__()self.conv1 = nn.Conv2d(3, 32, 3)self.max_pool1 = nn.MaxPool2d(2)self.conv2 = nn.Conv2d(32, 64, 3) self.max_pool2 = nn.MaxPool2d(2) self.conv3 = nn.Conv2d(64, 64, 3) self.conv4 = nn.Conv2d(64, 64, 3) self.max_pool3 = nn.MaxPool2d(2) self.conv5 = nn.Conv2d(64, 128, 3) self.conv6 = nn.Conv2d(128, 128, 3) self.max_pool4 = nn.MaxPool2d(2) self.fc1 = nn.Linear(4608, 512) self.fc2 = nn.Linear(512, 1)def forward(self, x): in_size = x.size(0) x = self.conv1(x) x = F.relu(x) x = self.max_pool1(x) x = self.conv2(x) x = F.relu(x) x = self.max_pool2(x) x = self.conv3(x) x = F.relu(x) x = self.conv4(x) x = F.relu(x) x = self.max_pool3(x) x = self.conv5(x) x = F.relu(x) x = self.conv6(x) x = F.relu(x)x = self.max_pool4(x) # 展开x = x.view(in_size, -1)x = self.fc1(x)x = F.relu(x) x = self.fc2(x) x = torch.sigmoid(x) return x
2.定义学习率
定义模型的学习率为 0.0001。
modellr = 1e-4
3.实例化模型并且移动到GPU
创建 ConvNet 模型实例,并使用 to(DEVICE) 方法将其移动到指定的计算设备上。如果 DEVICE 是 ‘cuda’,则模型将被移动到 GPU;如果 DEVICE 是 ‘cpu’,则模型将被移动到 CPU。
# 实例化模型并且移动到GPU
model = ConvNet().to(DEVICE)
4.选择优化器
创建 Adam 优化器,其中 model.parameters() 表示模型的所有参数,lr=modellr 表示学习率为 0.0001。
# 选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model.parameters(), lr=modellr)
三、定义调整学习率的函数
1.定义调整学习率的函数
这个函数实现一个简单的学习率衰减策略,它能够根据当前的 epoch 调整学习率。
1)定义学习率衰减规则:
- modellrnew = modellr * (0.1 ** (epoch // 5)) :定义了一个学习率衰减规则,其中 modellr
是初始学习率,0.1 ** (epoch // 5) 表示每 5 个 epoch 学习率减少 10 倍。
2)打印新学习率:
- print(“lr:”,modellrnew):打印出新的学习率。
3)调整优化器的学习率:
- for param_group in optimizer.param_groups:
遍历优化器中的每个参数组,并将每个参数组的学习率设置为新学习率。
def adjust_learning_rate(optimizer, epoch):"""Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""modellrnew = modellr * (0.1 ** (epoch // 5)) print("lr:",modellrnew) for param_group in optimizer.param_groups: param_group['lr'] = modellrnew
四、训练模型
1.设置模型为训练模式
将模型设置为训练模式,这样模型在计算梯度时会使用 Dropout 和 BatchNorm 层。
# 定义训练过程
def train(model, device, train_loader, optimizer, epoch):model.train()
2.遍历训练数据加载器
遍历 train_loader 中的每个批次,并将数据和标签移动到指定的设备上。然后,它执行前向传播、计算损失、反向传播和更新模型参数。
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device).float().unsqueeze(1)
optimizer.zero_grad()
output = model(data)
# print(output)
loss = F.binary_cross_entropy(output, target)
loss.backward()
optimizer.step()
3.打印进度
在每 10 个批次后打印当前的轮次、批次数、损失值和进度百分比,以便监控训练进度。
if (batch_idx + 1) % 10 == 0:print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),100. * (batch_idx + 1) / len(train_loader), loss.item()))
五、验证模型
1.设置模型为验证模式
将模型设置为验证模式,这样模型在计算梯度时不会使用 Dropout 和 BatchNorm 层。
# 定义测试过程
def val(model, device, test_loader):model.eval()
2.初始化计数器
用于在每次迭代时累积损失、正确预测的数量和总样本数。
test_loss = 0
correct = 0
total = 0
3.遍历测试数据加载器
遍历 test_loader 中的每个批次,并将数据和标签移动到指定的设备上。然后,它执行前向传播并计算损失。由于模型处于验证模式,它不会计算梯度。同时,它累积损失、样本数和正确预测的数量。
with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device).float().unsqueeze(1)output = model(data)test_loss += F.binary_cross_entropy(output, target, reduction='mean').item()pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in output]).to(device)correct += pred.eq(target.long()).sum().item()total += target.size(0) # 计算总数
4.计算准确率
accuracy = 100. * correct / total
5.打印验证结果
在验证过程结束时打印平均损失和准确率。
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
test_loss, correct, total, 100 * correct / total))
说明:这个函数实现了一个基本的验证循环,它能够验证模型在测试数据集上的性能。在实际使用中,您可能需要根据您的具体任务调整超参数,并确保数据加载器的设置与模型的需求相匹配。
五、定义训练循环
1.调整学习率
在每个 epoch 开始时调整学习率。
# 训练
for epoch in range(1, EPOCHS + 1):adjust_learning_rate(optimizer, epoch)
2.执行训练和验证
在每个 epoch 中执行训练和验证过程。
train(model, DEVICE, train_loader, optimizer, epoch) val(model, DEVICE, test_loader)
3.保存模型
在训练结束后保存模型的状态字典。
torch.save(model.state_dict(), 'ConvNet.pth')
运行结果:
# 二、测试模型import torch
from PIL import Image
import torchvision.transforms as transforms
from torchvision import models
from torch.autograd import Variable# 定义数据预处理
transform_test = transforms.Compose([transforms.Resize(100),transforms.RandomVerticalFlip(),transforms.RandomCrop(50),transforms.RandomResizedCrop(150),transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])# 定义类别
classes = ['cat', 'dog'] # 替换为您的实际类别名称# 检查是否有可用的 GPU
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 定义自定义的 VGG-19 模型
# 定义网络
class ConvNet(nn.Module):def __init__(self):super(ConvNet, self).__init__()self.conv1 = nn.Conv2d(3, 32, 3)self.max_pool1 = nn.MaxPool2d(2)self.conv2 = nn.Conv2d(32, 64, 3)self.max_pool2 = nn.MaxPool2d(2)self.conv3 = nn.Conv2d(64, 64, 3)self.conv4 = nn.Conv2d(64, 64, 3)self.max_pool3 = nn.MaxPool2d(2)self.conv5 = nn.Conv2d(64, 128, 3)self.conv6 = nn.Conv2d(128, 128, 3)self.max_pool4 = nn.MaxPool2d(2)self.fc1 = nn.Linear(4608, 512)self.fc2 = nn.Linear(512, 1)def forward(self, x):in_size = x.size(0)x = self.conv1(x)x = F.relu(x)x = self.max_pool1(x)x = self.conv2(x)x = F.relu(x)x = self.max_pool2(x)x = self.conv3(x)x = F.relu(x)x = self.conv4(x)x = F.relu(x)x = self.max_pool3(x)x = self.conv5(x)x = F.relu(x)x = self.conv6(x)x = F.relu(x)x = self.max_pool4(x)# 展开x = x.view(in_size, -1)x = self.fc1(x)x = F.relu(x)x = self.fc2(x)x = torch.sigmoid(x)return x# 实例化 Resnet50 类# 加载权重
model.load_state_dict(torch.load("ConvNet.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}")
运行结果: