赞
踩
具体怎么学习pytorch,看b站刘二大人的视频。
完整代码:
- import numpy as np
- import os
- from PIL import Image
- import torch
- import torch.nn as nn
- import torch.optim as optim
- from torchvision import datasets, transforms
- from torch.utils.data import DataLoader, Subset
- # 设置随机种子
- torch.manual_seed(42)
- np.random.seed(42)
- '''https://zhuanlan.zhihu.com/p/156926543'''
- # 定义图片目录
- image_dir = 'images'
-
- # 初始化图片路径列表
- img_list = []
-
- # 遍历指定目录及其子目录中的所有文件
- for parent, _, filenames in os.walk(image_dir):
- for filename in filenames:
- # 拼接文件的完整路径
- filename_path = os.path.join(parent, filename)
- img_list.append(filename_path)
-
- # 初始化图像张量列表和标签列表
- image_tensors = []
- y_list = []
-
- for image_path in img_list:
- # 提取标签 (假设标签是文件名的第一个字符)
- label = int(os.path.basename(image_path)[0])
- y_list.append(label)
-
- # 打开图像
- img = Image.open(image_path)
-
- # 获取图像尺寸
- width, height = img.size
-
- # 定义裁剪的区域(假设要保留图像中心的 100x100 区域)
- left = (width - 100) / 2
- top = (height - 100) / 2
- right = (width + 100) / 2
- bottom = (height + 100) / 2
-
- # 裁剪图像
- img = img.crop((left, top, right, bottom))
-
- # 将图像转换为 NumPy 数组
- img_array = np.asarray(img)
-
- # 将 NumPy 数组转换为 PyTorch 张量
- img_tensor = torch.from_numpy(img_array).float()
-
- # 如果图像是 RGB,将其转换为 (C, H, W) 格式
- if img_tensor.ndimension() == 3 and img_tensor.shape[2] == 3:
- img_tensor = img_tensor.permute(2, 0, 1) # 从 (H, W, C) 变为 (C, H, W)
-
- # 增加 batch 维度
- img_tensor = img_tensor.unsqueeze(0) # 从 (C, H, W) 变为 (1, C, H, W)
-
- # 规范化到0-1之间
- img_tensor = img_tensor / 255.0
-
- # 添加到图像张量列表
- image_tensors.append(img_tensor)
-
- # 打印图像张量的形状
- print(f"当前图像形状: {img_tensor.shape}")
-
- # 将图像张量列表转换为四维张量
- x_data = torch.cat(image_tensors, dim=0)
- # 遍历 y_list 中的每个元素,并将每个数减去 1
- for i in range(len(y_list)):
- y_list[i] -= 1
-
- # 将标签列表转换为张量
- y_labels = torch.tensor(y_list).long() # 注意这里使用 .long() 方法将标签转换为长整型
-
- print(x_data.shape,y_labels.shape)
- print(y_labels)
-
- # 定义数据集和数据加载器
- class CustomDataset(torch.utils.data.Dataset):
- def __init__(self, x_data, y_labels):
- self.x_data = x_data
- self.y_labels = y_labels
-
- def __len__(self):
- return len(self.x_data)
-
- def __getitem__(self, idx):
- return self.x_data[idx], self.y_labels[idx]
-
-
- # 使用自定义数据集和数据加载器
- custom_dataset = CustomDataset(x_data, y_labels)
- train_size = int(0.8 * len(custom_dataset))
- val_size = len(custom_dataset) - train_size
- train_set, val_set = torch.utils.data.random_split(custom_dataset, [train_size, val_size])
-
- train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
- val_loader = DataLoader(val_set, batch_size=32, shuffle=False)
-
- # 定义卷积神经网络模型
- class SimpleCNN(nn.Module):
- def __init__(self):
- super(SimpleCNN, self).__init__()
- self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
- self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
- self.pool = nn.MaxPool2d(2, 2)
- self.fc1 = nn.Linear(32 * 25 * 25, 128)
- self.fc2 = nn.Linear(128, 5) # 假设有5个类别
-
- def forward(self, x):
- x = self.pool(torch.relu(self.conv1(x)))
- x = self.pool(torch.relu(self.conv2(x)))
- x = torch.flatten(x, 1)
- x = torch.relu(self.fc1(x))
- x = self.fc2(x)
- return x
-
-
- # 训练模型
- model = SimpleCNN()
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.Adam(model.parameters(), lr=0.001)
-
- for epoch in range(50): # 假设训练50个epoch
- running_loss = 0.0
- for inputs, labels in train_loader:
- optimizer.zero_grad()
- outputs = model(inputs)
- loss = criterion(outputs, labels)
- loss.backward()
- optimizer.step()
- running_loss += loss.item()
- print(f"Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}")
-
- # 在每个epoch结束后,计算并打印验证集的准确率
- model.eval() # 将模型设置为评估模式
- correct = 0
- total = 0
- with torch.no_grad():
- for inputs, labels in val_loader:
- outputs = model(inputs)
- _, predicted = torch.max(outputs.data, 1)
- total += labels.size(0)
- correct += (predicted == labels).sum().item()
- val_accuracy = correct / total
- print(f'Validation Accuracy after Epoch {epoch + 1}: {val_accuracy}')

本数据集中x_data的维度是四维张量(203,3,100,100),y_labels的维度是一维张量
代码中需要注意的点,卷积模型接受的是四维张量,因此要转变为四维张量。
全连接层中输入的特征数,需要自己计算,通过前面卷积层和池化层后,计算总的维度数。一般是最后的通道数*高度*宽度
定义模型中的forward函数中,在经过全连接层计算前,需要将四维的x转为2维
如果 x
的形状是 (64, 32, 28, 28)
,表示一个批次大小为64的图像张量,其中每个图像有32个通道,高度和宽度都是28像素。现在,我们希望将这个张量展平为一个二维张量,以便输入到全连接层进行进一步处理。
通过 torch.flatten(x, 1)
操作,我们将在指定维度(这里是第一个维度,也就是通道维度)上对张量进行展平。展平后的张量形状将变为 (64, 32*28*28)
,其中64是批次大小,而 32*28*28
是展平后的特征数量,即每个图像的特征数量。这与前面定义的全连接层的输入特征数要一致。
Dataloader中batch_size就是设置第一个维度,比如这里的batch_size是32,那么
for inputs, labels in train_loader:
这里的inputs维度是(32,3,100,100)
新学习pytorch中的分割数据集与测试集方法。
- # 使用自定义数据集和数据加载器
- custom_dataset = CustomDataset(x_data, y_labels)
- train_size = int(0.8 * len(custom_dataset))
- val_size = len(custom_dataset) - train_size
- train_set, val_set = torch.utils.data.random_split(custom_dataset, [train_size, val_size])
-
- train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
- val_loader = DataLoader(val_set, batch_size=32, shuffle=False)
结果展现,可以看见准确率有0.82:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。