qq_39730690 2021-10-21 23:53 采纳率: 33.3%
浏览 144
已结题

为什么在pytorch中使用VGG16不用预训练,自己从头训练猫狗分类,正确率只有74%就上不去了?

这是我的代码。请大家过目。
而且我在用训练好的pth模型进行单独测试时总会是第0类正确率很高(也就是猫的识别率很高 狗的识别率很低)
测试集猫狗各500张,猫能识别出400多张而狗只能识别出十几张。
不知道问题出在哪里?
训练的loss会一直降,但是验真loss从0.7降到0.6,就趋于平滑,不再下降。
我试了调整学习率,但是没用。


import math
from torch import nn
from torchvision import models,datasets,transforms
import torch
import os
from torch.autograd import Variable
import csv
#import visdom


#viz = visdom.Visdom()
data_dir = 'VGGTrain'
data_transform = {
    'train':transforms.Compose([transforms.Resize((224, 224)),
                          transforms.ToTensor(),
                          transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225]),
                          transforms.RandomHorizontalFlip(p=0.5),#水平翻转
                          transforms.RandomRotation(15),  # 随机旋转
                          transforms.RandomCrop(224),  #随机剪裁
                          transforms.Pad(padding=4, padding_mode='edge'),#边缘填充
                          ]),
        'valid':transforms.Compose([transforms.Resize((224, 224)),
                          transforms.ToTensor(),
                          transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225])
                          ])
}

image_datasets = {x:datasets.ImageFolder(root=os.path.join(data_dir, x), transform=data_transform[x])
                    for x in ['train','valid']
                    }

dataloader = {x:torch.utils.data.DataLoader(dataset=image_datasets[x], batch_size=32, shuffle=True, num_workers=4)
              for x in ['train','valid']
}

x_example, y_example = next(iter(dataloader['train']))

example_classes = image_datasets['train'].classes

index_classes = image_datasets['train'].class_to_idx


model = models.vgg16(pretrained=False)


# 遍历模型中的所有模块
for m in model.modules():
    # 如果当前模块是卷积层或者线性层
    if isinstance(m, nn.Conv2d):
        #则进行xavier初始化
        nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
        if m.bias is not None:
            nn.init.constant_(m.bias, 0)
    elif isinstance(m, nn.BatchNorm2d):
        nn.init.constant_(m.weight, 1)
        nn.init.constant_(m.bias, 0)
    elif isinstance(m, nn.Linear):
        nn.init.normal_(m.weight, 0, 0.01)
        nn.init.constant_(m.bias, 0)


model.classifier = torch.nn.Sequential(
    torch.nn.Linear(25088,512),
    torch.nn.ReLU(),
    torch.nn.Dropout(p=0.6),
    torch.nn.Linear(512,256),
    torch.nn.ReLU(),
    torch.nn.Dropout(p=0.6),
    torch.nn.Linear(256,2)
)


use_gpu = torch.cuda.is_available()
if use_gpu :
    model = model.cuda()


loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.classifier.parameters(), lr=1e-4,weight_decay=0.01)

epochs = 99999


#viz.line([0], [-1], win='loss', opts=dict(title='loss'))
#viz.line([0], [-1], win='val_acc', opts=dict(title='val_acc'))
global_step = 0
best_acc = 0
best_epoch = 0

with open("loss2.txt", "w") as f:
    for epoch in range(epochs):

        print('----' * 10)
        print('Epoch {}/{}'.format(epoch + 1, epochs))

        for phase in ['train', 'valid']:
            if phase == 'train':
                print('Training...')
                model.train(True)

            else:
                print('Validing...')
                model.train(False)

            running_loss = 0.0
            running_corrects = 0

            for batch, data in enumerate(dataloader[phase]):

                x, y = data
                x, y = Variable(x.cuda()), Variable(y.cuda())

                y_pred = model(x)

                _, pred = torch.max(y_pred.data, 1)
                optimizer.zero_grad()


                loss = loss_f(y_pred, y)

                running_loss += loss.data
                if phase == 'train':
                    global_step += 1
                    loss.backward()
                    optimizer.step()

                running_corrects += torch.sum(pred == y.data)
                    

            epoch_loss = running_loss * 32 / len(image_datasets[phase])
            epoch_acc = 100 * running_corrects / len(image_datasets[phase])

            print('{} Loss:{} ACC:{}'.format(phase, epoch_loss, epoch_acc))
            if(phase == 'train'):
                f.writelines([str(epoch), ',', str(epoch_loss.item()),',',str(epoch_acc.item()), ','])
                
            if(phase == 'valid'):
                f.writelines([str(epoch_acc.item()),',',str(epoch_loss.item()), ';'])
                f.flush()
                if epoch_acc.item() > best_acc:
                    torch.save(model, 'best3.pth')
                    best_acc = epoch_acc.item()
                    best_epoch = epoch
                    print('最好的正确率是epoch:', best_epoch+1, '    正确率为:', best_acc)


print('最好的模型在epoch:', best_epoch)
torch.save(model, 'vggmodel2.pth')


  • 写回答

1条回答 默认 最新

  • 关注

    官方pretrain的模型数据集是imagenet,样本数是你这个数据集的很多倍,这样的vgg网络卷积层的参数基本收敛到比较好的一个情况,你直接用来finetune只要稍微微调一下最后的fc层就可以得到一个比较好的分类结果了。相比于你自己从0训练网络,你的网络见过的数据比较少,容易过拟合在见到过的数据上,因此你自己从0训练的效果远远不如加载pretrain然后finetune的效果。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 10月31日
  • 已采纳回答 10月23日
  • 创建了问题 10月21日

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作