当前位置:   article > 正文

基于pytorch搭建resnet18网络并训练数据集,loss曲线和精确度曲线振荡,怎么办?_from torchvision.models.resnet import model_urls

from torchvision.models.resnet import model_urls
import torch.nn as nn
import torch.utils.model_zoo as model_zoo
import urllib3
from tqdm import tqdm
from torchvision.models.resnet import model_urls, resnet18

__all__ = ['ResNet18', 'resnet18', 'BasicBlock']

url = 'https://download.pytorch.org/models/resnet18-5c106cde.pth'
http = urllib3.PoolManager()
response = http.request('GET', url, preload_content=False)
total_size = int(response.headers.get('content-length', 0))
block_size = 1024
with tqdm(total=total_size, unit='iB', unit_scale=True) as progress_bar:
    with open('resnet18-5c106cde.pth', 'wb') as f:
        for data in response.stream(block_size):
            progress_bar.update(len(data))
            f.write(data)


class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, inplanes, planes, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.downsample = downsample
        self.stride = stride
        self.fc = nn.Linear(512 * self.expansion, 128)
        self.fc2 = nn.Linear(512 * self.expansion, 20)
        # 添加dropout层
        self.dropout = nn.Dropout(p=0.5)

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)

        # 添加dropout层
        out = self.dropout(out)

        if self.downsample is not None:
            identity = self.downsample(x)

        out += identity
        out = self.relu(out)

        return out


class ResNet18(nn.Module):

    def __init__(self, block=BasicBlock, layers=[2, 2, 2, 2], num_classes=10):
        super(ResNet18, self).__init__()
        self.inplanes = 64
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(block, 64, layers[0])
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
        self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512 * block.expansion, num_classes)  # 将输出维度修改为10
        self.softmax = nn.Softmax(dim=1)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

    def _make_layer(self, block, planes, blocks, stride=1):
        downsample = None
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                nn.Conv2d(self.inplanes, planes * block.expansion,
                          kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes * block.expansion),
            )

        layers = [block(self.inplanes, planes, stride, downsample)]
        self.inplanes = planes * block.expansion
        for i in range(1, blocks):
            layers.append(block(self.inplanes, planes))

        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)

        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)

        x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        x = self.softmax(x)  # 使用softmax函数对输出结果进行归一化

        return x


def resnet18(pretrained=True, progress=True, **kwargs):
    model = ResNet18(BasicBlock, [2, 2, 2, 2], **kwargs)

    if pretrained:
        state_dict = model_zoo.load_url(model_urls['resnet18'], progress=progress)
        model.load_state_dict(state_dict)

    return model

这是resnet18网络搭建的代码

import torch
import random
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import ImageFolder
from net import resnet18
import matplotlib.pyplot as plt
from typing import Any

# 定义超参数
batch_size = 16
learning_rate_backbone = 0.0001
learning_rate_fc = 0.002

num_epochs = 100

# 定义数据增强
train_transforms_list = [
    transforms.Compose([
        transforms.Resize((64, 64)),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ]),
    transforms.Compose([
        transforms.Resize((64, 64)),
        transforms.RandomRotation(degrees=15),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ]),
    transforms.Compose([
        transforms.Resize((64, 64)),
        transforms.RandomCrop(size=64, padding=4),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ]),
]

test_transform = transforms.Compose([
    transforms.Resize((64, 64)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# 加载数据集
train_datasets_list = [
    ImageFolder('train', transform=train_transforms_list[0]),
    ImageFolder('train', transform=train_transforms_list[1]),
    ImageFolder('train', transform=train_transforms_list[2])
]

test_dataset = ImageFolder('test', transform=test_transform)

train_loaders_list = [
    DataLoader(train_datasets_list[0], batch_size=batch_size, shuffle=True),
    DataLoader(train_datasets_list[1], batch_size=batch_size, shuffle=True),
    DataLoader(train_datasets_list[2], batch_size=batch_size, shuffle=True)
]

test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

# 定义模型
model = resnet18(pretrained=False)
num_ftrs = model.fc.in_features
model.fc = torch.nn.Sequential(
    torch.nn.Linear(num_ftrs, 128),
    torch.nn.ReLU(),
    torch.nn.Linear(128, 10)
)

criterion = torch.nn.CrossEntropyLoss()
backbone_params = list(model.parameters())
fc_params = list(model.fc.parameters())

weight_decay = 1e-4
optimizer = torch.optim.Adam([
    {'params': model.fc.parameters(), 'lr': learning_rate_fc},
    {'params': model.layer4.parameters()},
    {'params': model.layer3.parameters()},
    {'params': model.layer2.parameters()},
    {'params': model.layer1.parameters()},
    {'params': model.conv1.parameters()},
], lr=learning_rate_backbone, weight_decay=weight_decay)

# 添加学习率调度器
step_size = 10
gamma = 0.1
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=step_size, gamma=gamma)

# 定义四个列表分别存储4个指标的值
train_losses = []
train_accs = []
test_losses = []
test_accs = []

# 训练模型
device = torch.device('cpu')
model = model.to(device)

for epoch in range(num_epochs):
    train_transform = random.choice(train_transforms_list)
    train_dataset = ImageFolder('train', transform=train_transform)
    train_loader: DataLoader[Any] = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

    model.train()
    train_loss = 0.0
    train_acc = 0.0
    for i, (inputs, labels) in enumerate(train_loader):
        inputs = inputs.to(device)
        labels = labels.to(device)

        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        train_loss += loss.item() * inputs.size(0)
        _, preds = torch.max(outputs, 1)
        train_acc += torch.sum(preds == labels.data)

    train_loss = train_loss / len(train_dataset)
    train_acc = train_acc / len(train_dataset)

    print('Epoch: [{}/{}], Train Loss: {:.4f}, Train Acc: {:.4f}, Train Transform: {}'.format(epoch + 1, num_epochs,
                                                                                          train_loss, train_acc,
                                                                                          train_transform))

    model.eval()
    test_loss = 0.0
    test_acc = 0.0
    for i, (inputs, labels) in enumerate(test_loader):
        inputs = inputs.to(device)
        labels = labels.to(device)

        outputs = model(inputs)
        loss = criterion(outputs, labels)

        test_loss += loss.item() * inputs.size(0)
        _, preds = torch.max(outputs, 1)
        test_acc += torch.sum(preds == labels.data)

    test_loss = test_loss / len(test_dataset)
    test_acc = test_acc / len(test_dataset)

    print('Epoch: [{}/{}], Test Loss: {:.4f}, Test Acc: {:.4f}'.format(epoch + 1, num_epochs, test_loss, test_acc))

    # 更新学习率
    scheduler.step()

    # 将得到的指标添加到对应列表
    train_losses.append(train_loss)
    train_accs.append(train_acc)
    test_losses.append(test_loss)
    test_accs.append(test_acc)
# 绘制精度曲线loss曲线
plt.figure(figsize=(10, 3))
plt.subplot(1, 2, 1)
plt.title('Loss')
plt.plot(train_losses, label='Train Loss')
plt.plot(test_losses, label='Test Loss')
plt.legend()
plt.subplot(1, 2, 2)
plt.title('Accuracy')
plt.plot(train_accs, label='Train Acc')
plt.plot(test_accs, label='Test Acc')
plt.legend()
plt.show()

# 保存模型
torch.save(model.state_dict(), 'resnet18_model.pth')

这是调用resnet18网络,训练自己10个人每个人100个样本一共1000个时频图样本的数据集,为什么生成的loss曲线和精确度曲线振荡呢?

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/351058
推荐阅读
相关标签
  

闽ICP备14008679号