【pytorch笔记】Resnet 复现实例
Resnet 复现实例
【pytorch笔记】Resnet 复现实例
前言
- 使用教程来自小土堆pytorch教程
- 配置环境:torch2.0.1+cu118与对应torchaudio和torchvision
之前复现某篇论文用的代码
读取数据代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from torch.utils.data import Dataset
import os
from PIL import Image
# 定义
class myData(Dataset):
def __init__(self, root_dir_path, img_dir_path, label_dir_path, transform, label_transform):
'''
Args:
label_dir_path: 根目录 图片与标签的上级文件夹路径
img_dir_path: 存储了图片的文件夹的路径
label_dir_path: 存储了标签的文件夹路径
transform: 应用何种变换
label_transform: 标签应用何种变换
'''
# 定义标签映射
# 必须映射!
# self.label_mapping = {
# 'very quiet': 0,
# 'quiet': 1,
# 'noisy': 2,
# 'very noisy': 3,
# }
# 存储了根目录 图片的文件夹的路径 与 标签的excel文件路径
self.root_dir_path = root_dir_path
self.img_dir_path = img_dir_path
self.label_dir_path = label_dir_path
# 存储了图片名字的列表
self.img_name_list = os.listdir(os.path.join(self.root_dir_path, self.img_dir_path))
# 存储了图片标签的列表 索引与名字列表一一对应
self.img_label_list = []
for img_name in self.img_name_list:
img_label_path = os.path.join(self.root_dir_path, self.label_dir_path, img_name + '.txt')
label = None
with open(img_label_path, 'r') as f:
label = f.read().strip()
#mapping_label = self.label_mapping.get(label)
label = int(label)
self.img_label_list.append(label)
# transform
self.transform = transform
self.label_transform = label_transform
def __getitem__(self, index):
# 读取图片
img_name = self.img_name_list[index]
img_path = os.path.join(self.root_dir_path, self.img_dir_path, img_name)
img = Image.open(img_path)
label = self.img_label_list[index]
if self.transform is not None:
img = self.transform(img)
if self.label_transform is not None:
label = self.label_transform(label)
# 返回图片与标签
return img, label
def __len__(self):
return len(self.img_name_list)
训练代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# encoding: utf-8
import torch
import torchvision
from torch import nn, optim
# from torch.utils.data import Dataset
from torch.utils.data import DataLoader
# from PIL import Image
from torchvision import transforms
from sklearn.metrics import accuracy_score, precision_score
# import os
from mydata_definition import myData
# -------------- 及时调整超参数 -------------- #
myBatch_size = 16
myEpochs = 30
myNum_workers = 0
myLr = 0.0001
# -------------- 及时修改训练与测试的文件路径 -------------- #
root_dir = "/"
train_img_dir = "train"
train_label_dir = "train_label"
model_save_path = f"resnet50_{myBatch_size}_{myEpochs}_{myNum_workers}_{myLr}.pth"
# 确定设备
myDevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 定义更新
myTransform = transforms.Compose([
transforms.Resize((224, 224)), # 调整到224*224 ResNet 专用
transforms.ToTensor() # 转换为张量
])
train_set = myData(root_dir, train_img_dir, train_label_dir,
transform=myTransform,
label_transform=None)
train_loader = DataLoader(dataset=train_set, batch_size=myBatch_size,
shuffle=False, num_workers=myNum_workers,
drop_last=False)
# 载入 resnet50 模型
resnet50 = torchvision.models.resnet50(weights=None)
resnet50 = nn.DataParallel(resnet50).to(device=myDevice)
# 修改最后的线性层 输出为4个特征
num_ftrs = resnet50.module.fc.in_features
resnet50.module.fc = nn.Linear(num_ftrs, 4).to(myDevice) # !!!!!!!!!!!!!!!!!!!!!! 这里 修改最后一层的输出类别!!!!!!!!!!!!!
# # 由于训练数据较小 所以只训练 softmax 层
# for param in resnet50.parameters():
# param.requires_grad = False
# # 允许fc层的权重和偏置更新
# for param in resnet50.module.fc.parameters():
# param.requires_grad = True
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(resnet50.parameters(), lr=myLr) # 只优化最后一层
# 调整为训练状态
resnet50.train()
print("------------ 开始训练啦 ------------")
print(f"共有{len(train_set)}条训练数据")
# 开始训练
num_epochs = myEpochs
for epoch in range(num_epochs):
running_loss = 0.0 # 用于累计损失
for inputs, labels in train_loader:
inputs, labels = inputs.to(myDevice), labels.to(myDevice)
optimizer.zero_grad()
outputs = resnet50(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() # 累加损失
epoch_loss = running_loss / len(train_loader)
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}')
print("------------ 训练结束 ------------")
print("------------ 开始保存 ------------")
torch.save(resnet50, model_save_path)
print("------------ 保存结束 ------------")
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# encoding: utf-8
import torch
import torchvision
from torch import nn, optim
# from torch.utils.data import Dataset
from torch.utils.data import DataLoader
# from PIL import Image
from torchvision import transforms
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
# import os
from mydata_definition import myData
# -------------- 及时调整超参数 -------------- #
myBatch_size = 16
myEpochs = 30
myNum_workers = 0
myLr = 0.0001
# -------------- 及时修改训练与测试的文件路径 -------------- #
root_dir = "/"
test_img_dir = "test"
test_label_dir = "test_label"
model_save_path = f"/resnet50_{myBatch_size}_{myEpochs}_{myNum_workers}_{myLr}.pth"
print(f"使用模型路径为{model_save_path}")
# 确定设备
myDevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 定义更新
myTransform = transforms.Compose([
transforms.Resize((224, 224)), # 调整到224*224 ResNet 专用
transforms.ToTensor() # 转换为张量
])
test_set = myData(root_dir, test_img_dir, test_label_dir,
transform=myTransform,
label_transform=None)
test_loader = DataLoader(dataset=test_set, batch_size=myBatch_size,
shuffle=False, num_workers=myNum_workers,
drop_last=False)
# 载入我们训练好的 resnet50 模型
load_model = model_save_path
resnet50 = torch.load(load_model)
resnet50 = resnet50.to(myDevice)
# 调整为测试状态
resnet50.eval()
# 进行测试
total = 0
correct = 0
all_labels = []
all_preds = []
print("------------ 开始测试 ------------")
print(f"共有{len(test_set)}条测试数据")
with torch.no_grad(): # 测试时不需要计算梯度
for inputs, labels in test_loader:
inputs, labels = inputs.to(myDevice), labels.to(myDevice)
outputs = resnet50(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct_num = (predicted == labels).sum().item()
correct = correct + correct_num
all_labels.extend(labels.cpu().numpy())
all_preds.extend(predicted.cpu().numpy())
accuracy = accuracy_score(all_labels, all_preds)
precision = precision_score(all_labels, all_preds, average="weighted", zero_division=0)
recall = recall_score(all_labels, all_preds, average="weighted", zero_division=0)
f1 = (2 * precision * recall) / (precision + recall)
print(f"ResNet50 测试准确率为:{accuracy}")
print(f"ResNet50 测试精确率为:{precision}")
print(f"ResNet50 测试召回率为:{recall}")
print(f"ResNet50 测试 F1 值为:{f1}")
# # watch -n 1 nvidia-smi
# gpustat -i
This post is licensed under CC BY 4.0 by the author.