字符识别模型训练与验证

  1. 构建验证集
    在机器学习与深度学习模型的训练过程中,模型非常容易出现过拟合的现象。构建验证集能够有效解决过拟合问题,验证集需要尽可能与测试集保持一致,在训练过程中不断验证模型在验证集上的精度,以此控制模型训练。

验证集构建方法
(1)留出法(Hold-out)
这种方法直接将训练集分成新的训练集与验证集。优点是直接简单,缺点是只得到一份验证集,有可能导致模型在验证集上出现过拟合。留出法适用于数据量较大的情况。
(2)交叉验证法(Cross Validation)
将训练集划分为K份,将其中的K-1份作为训练集,剩余的一份作为验证集,循环K训练。这种划分方法使所有的训练集都是验证集,最终模型验证精度都是K份平均得到。优点是验证机京都较高,训练K次可以得到K个有多样性差异的模型;缺点是需要训练K次,不适用于大数据量。
(3)自助采样法(BootStrap)
通过有放回的采样方式得到新的训练集与验证集,每次训练集和验证集都有区别。此方法适用于小数据量情况。

#定义读取数据dataloader
train_path = glob.glob('F:\目标检测\街景字符识别\mchar_train\mchar_train/*.png')#匹配所有的符合条件的文件,并将其以list的形式返回。
train_path.sort()
train_json = json.load(open('F:\目标检测\街景字符识别\mchar_train/mchar_train.json'))#从json文件中读取数据
train_label = [train_json[x]['label'] for x in train_json]
print(len(train_path), len(train_label))

train_loader = torch.utils.data.DataLoader(
    SVHNDataset(train_path, train_label,
                transforms.Compose([
                    transforms.Resize((64, 128)),#缩放尺寸
                    transforms.RandomCrop((60, 120)),#RandomCrop(size, padding=0)随机裁剪。size可以是tuple也可以是Integer。
                    transforms.ColorJitter(0.3, 0.3, 0.2),#修改亮度、对比度和饱和度
                    transforms.RandomRotation(10),#随机旋转
                    transforms.ToTensor(),#转为tensor,并归一化至[0-1]
                    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#标准化
    ])), 
    batch_size=40, 
    shuffle=True, 
    num_workers=0,#修改num_works参数为 0 (原来为10),只启用一个主进程加载数据集,避免在windows使用多线程
)

val_path = glob.glob('F:\目标检测\街景字符识别\mchar_val\mchar_val/*.png')
val_path.sort()
val_json = json.load(open('F:\目标检测\街景字符识别\mchar_val/mchar_val.json'))
val_label = [val_json[x]['label'] for x in val_json]
print(len(val_path), len(val_label))

val_loader = torch.utils.data.DataLoader(
    SVHNDataset(val_path, val_label,
                transforms.Compose([
                    transforms.Resize((60, 120)),
                    # transforms.ColorJitter(0.3, 0.3, 0.2),
                    # transforms.RandomRotation(5),
                    transforms.ToTensor(),
                    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])), 
    batch_size=40, 
    shuffle=False, 
    num_workers=0,
)

训练与验证

#训练与验证
model = SVHN_Model1()
criterion = nn.CrossEntropyLoss()#交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), 0.001)
best_loss = 1000.0

# 是否使用GPU
use_cuda = True
if use_cuda:
    model = model.cuda()
    
for epoch in range(10):
    train_loss = train(train_loader, model, criterion, optimizer, epoch)
    val_loss = validate(val_loader, model, criterion)
    
    val_label = [''.join(map(str, x)) for x in val_loader.dataset.img_label]
    val_predict_label = predict(val_loader, model, 1)
    val_predict_label = np.vstack([
        val_predict_label[:, :11].argmax(1),
        val_predict_label[:, 11:22].argmax(1),
        val_predict_label[:, 22:33].argmax(1),
        val_predict_label[:, 33:44].argmax(1),
        val_predict_label[:, 44:55].argmax(1),
    ]).T
    val_label_pred = []
    for x in val_predict_label:
        val_label_pred.append(''.join(map(str, x[x!=10])))
    
    val_char_acc = np.mean(np.array(val_label_pred) == np.array(val_label))
    
    print('Epoch: {0}, Train loss: {1} \t Val loss: {2}'.format(epoch, train_loss, val_loss))
    print('Val Acc', val_char_acc)
    # 记录下验证集精度
    if val_loss < best_loss:
        best_loss = val_loss
        # print('Find better model in Epoch {0}, saving model.'.format(epoch))
        torch.save(model.state_dict(), 'F:\目标检测\街景字符识别/model.pt')

你可能感兴趣的:(深度学习)