验证集构建方法
(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')