Fast AI孪生模型训练无提升,准确率始终为50%求助
孪生模型准确率固定50%的问题排查与修复
50%的准确率说明模型完全在随机猜测,核心原因通常是数据配对错误、变换未正确应用、学习率不合理这几个方向,结合你的代码,具体修复点如下:
1. 修复数据变换的应用逻辑
你的after_batch中直接使用*aug_transforms会导致增强无法正确作用于孪生对的两个图像(因为输入是图像tuple,批量变换默认只会处理单个tensor)。需要将变换拆分到after_item阶段,确保每个图像单独应用变换:
dls = tls.dataloaders( after_item=[Tuple(Resize(256, method='squash')), Tuple(ToTensor)], after_batch=[ IntToFloatTensor, # 对批量中的每个图像单独应用增强 Tuple(aug_transforms(flip_vert=True, do_flip=True, max_rotate=50, max_warp=0.4, max_zoom=1.3)), Normalize.from_stats(*imagenet_stats) ], bs = 8 )
或者更稳妥的方式是将增强移到after_item,确保每个图像在转为tensor前完成增强:
after_item=[ Tuple(Resize(256, method='squash')), Tuple(aug_transforms(flip_vert=True, do_flip=True, max_rotate=50, max_warp=0.4, max_zoom=1.3)), Tuple(ToTensor) ], after_batch=[IntToFloatTensor, Normalize.from_stats(*imagenet_stats)]
2. 调整学习率
你设置的base_lr=2.51e-5过小,不足以让模型参数更新。建议调整学习率并拆分训练步骤:
# 先单独训练head(冻结encoder) learn.freeze() learn.fit_one_cycle(5, lr=1e-3, cbs=[SaveModelCallback(monitor='valid_loss'), EarlyStoppingCallback(monitor='valid_loss', patience=3)]) # 解冻后继续训练 learn.unfreeze() learn.fit_one_cycle(10, lr=slice(1e-5, 1e-3), cbs=[SaveModelCallback(monitor='valid_loss'), EarlyStoppingCallback(monitor='valid_loss', patience=5)])
3. 验证数据配对的正确性
检查parent_label(f)是否正确获取了图像的类别标签:
# 打印几个样本的标签,确认类别划分正确 for f in files[:5]: print(f"文件: {f}, 类别: {parent_label(f)}")
如果parent_label返回的不是正确的类别(比如返回文件名而非父目录名),则SiameseTransform生成的配对样本完全错误,模型无法学习。
4. 检查模型输入的有效性
打印dataloader的一个batch,确认输入形状和标签分布:
batch = dls.one_batch() x1, x2, y = batch print(f"x1形状: {x1.shape}, x2形状: {x2.shape}") print(f"标签分布: {torch.bincount(y)}")
正常情况下,x1和x2的形状应为(bs, 3, 256, 256),标签中0和1的数量应大致相等。
修改后的完整训练函数示例
def train(dataset_path): files = get_image_files(dataset_path) labels = list(set(files.map(parent_label))) # 验证标签正确性 for f in files[:5]: print(f"文件: {f}, 类别: {parent_label(f)}") encoder = create_body(resnet50(), cut=-2) head = create_head(2048*2, 2, ps=0.5) model = SiameseModel(encoder, head) splits = RandomSplitter()(files) tfm = SiameseTransform(files, splits, labels) tls = TfmdLists(files, tfm, splits=splits) dls = tls.dataloaders( after_item=[ Tuple(Resize(256, method='squash')), Tuple(aug_transforms(flip_vert=True, do_flip=True, max_rotate=50, max_warp=0.4, max_zoom=1.3)), Tuple(ToTensor) ], after_batch=[IntToFloatTensor, Normalize.from_stats(*imagenet_stats)], bs = 8 ) # 验证batch有效性 batch = dls.one_batch() x1, x2, y = batch print(f"x1形状: {x1.shape}, x2形状: {x2.shape}") print(f"标签分布: {torch.bincount(y)}") torch.cuda.empty_cache() learn = Learner(dls, model, loss_func=loss_func, splitter=siamese_splitter, metrics=accuracy) # 先单独训练head learn.freeze() learn.fit_one_cycle(5, lr=1e-3, cbs=[SaveModelCallback(monitor='valid_loss'), EarlyStoppingCallback(monitor='valid_loss', patience=3)]) # 解冻后继续训练 learn.unfreeze() learn.fit_one_cycle(10, lr=slice(1e-5, 1e-3), cbs=[SaveModelCallback(monitor='valid_loss'), EarlyStoppingCallback(monitor='valid_loss', patience=5)]) learn.export('siamese1.pkl')
内容的提问来源于stack exchange,提问作者Gytis Vejelis
相关产品推荐
相关产品推荐

