You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

图像Captioning微调报错:running_mean应含1个元素而非256

问题描述

我正在使用一个图像Captioning教程,针对自定义数据集进行模型微调。目前仅使用1张图像和1条标注训练,此前已解决将BatchNorm1d替换为InstanceNorm1d的问题,现在运行代码出现错误,相关代码如下:

编码器代码

class EncoderCNN(nn.Module):
    def __init__(self, embed_size):
        super(EncoderCNN, self).__init__()
        resnet = models.resnet152(pretrained=True)
        modules = list(resnet.children())[:-1]
        self.resnet = nn.Sequential(*modules)
        self.linear = nn.Linear(resnet.fc.in_features, embed_size)
        #self.bn = nn.BatchNorm1d(embed_size, momentum=0.01)
        self.bn = nn.InstanceNorm1d(256, track_running_stats=True)

    def forward(self, images):
        with torch.no_grad():
            features = self.resnet(images)
        features = features.reshape(features.size(0), -1)
        features = self.bn(self.linear(features))
        return features

数据加载器代码

class CustomDataset(Dataset):
    def __init__(self, image_folder, caption_folder, transform=None):
        self.image_folder = image_folder
        self.caption_folder = caption_folder
        self.transform = transform

    def __len__(self):
        return 256
        #return len(os.listdir(self.image_folder))
    
    def __getitem__(self, idx):
        #img_name = os.path.join(self.image_folder, str(idx) + '.jpg')
        img_name = os.path.join(self.image_folder, "0" + '.jpg')
        img = Image.open(img_name)
        

        transform = transforms.Compose([ 
            transforms.Resize((256,256)),
            transforms.RandomHorizontalFlip(), 
            transforms.ToTensor(), 
            transforms.Normalize((0.485, 0.456, 0.406), 
                                (0.229, 0.224, 0.225))])

        img = transform(img)

        def tokenize(caption, vocabulary):
            words = caption.split()
            tokens = [vocabulary(word) for word in words]
            return tokens

        tokenized_captions = tokenize(caption, vocab)

        print("Image shape:", img.shape)

        return img, torch.tensor(tokenized_captions)

dataset = CustomDataset(image_folder='images/',
                        caption_folder='captions/',
                        transform=transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=1, shuffle=True, drop_last=False)

模型加载代码

class FineTuneModel(nn.Module):
    def __init__(self, embed_size, hidden_size, vocab_size, num_layers):
        super(FineTuneModel, self).__init__()
        self.encoder = EncoderCNN(embed_size)
        self.decoder = DecoderRNN(embed_size,
                                  hidden_size,
                                  vocab_size,
                                  num_layers,
                                  max_seq_length=20)
    def forward(self, images, captions, lengths):
        features = self.encoder(images)
        outputs = self.decoder(features, captions, lengths)
        return outputs
问题排查与修复

1. InstanceNorm1d维度不匹配问题

EncoderCNN中,self.bn = nn.InstanceNorm1d(256, track_running_stats=True) 硬编码了特征维度为256,但self.linear的输出维度是传入的embed_size,若embed_size不等于256会直接导致维度不匹配错误。需将InstanceNorm1d的特征维度改为embed_size:

self.bn = nn.InstanceNorm1d(embed_size, track_running_stats=True)

2. caption变量未定义

在__getitem__方法中,调用tokenize(caption, vocab)时caption变量未被赋值。需从caption_folder中读取对应图像的标注文件,比如对应图像0.jpg的标注文件为0.txt,添加读取逻辑:

# 在tokenize函数定义前添加标注读取代码
caption_path = os.path.join(self.caption_folder, "0.txt")
with open(caption_path, 'r', encoding='utf-8') as f:
    caption = f.read().strip()

3. 数据集长度与实际数据不符

__len__返回256,但实际仅存在1张图像,会导致DataLoader重复读取同一张图,不符合数据集逻辑,应改为返回实际图像数量:

def __len__(self):
    return len(os.listdir(self.image_folder))

4. 变长文本序列处理问题

即使batch_size=1,后续调整batch_size大于1时,不同caption的长度不一致会触发默认collate_fn报错。需自定义collate_fn处理变长序列:

def collate_fn(data):
    # 按caption长度降序排序
    data.sort(key=lambda x: len(x[1]), reverse=True)
    images, captions = zip(*data)
    images = torch.stack(images, 0)
    
    # 生成长度列表和填充后的目标张量
    lengths = [len(cap) for cap in captions]
    targets = torch.zeros(len(captions), max(lengths)).long()
    for i, cap in enumerate(captions):
        end = lengths[i]
        targets[i, :end] = cap[:end]
    return images, targets, lengths

# 初始化DataLoader时传入自定义collate_fn
dataloader = DataLoader(dataset, batch_size=1, shuffle=True, drop_last=False, collate_fn=collate_fn)

5. 冗余的transform参数

Dataset初始化时传入了transform=transforms.ToTensor(),但__getitem__内又重新定义并应用transform,导致重复转换。可将transform统一移至__init__中:

# 修改Dataset的__init__和__getitem__
def __init__(self, image_folder, caption_folder, transform=None):
    self.image_folder = image_folder
    self.caption_folder = caption_folder
    # 若未传入transform则使用默认预处理逻辑
    if transform is None:
        self.transform = transforms.Compose([ 
            transforms.Resize((256,256)),
            transforms.RandomHorizontalFlip(), 
            transforms.ToTensor(), 
            transforms.Normalize((0.485, 0.456, 0.406), 
                                (0.229, 0.224, 0.225))])
    else:
        self.transform = transform

def __getitem__(self, idx):
    # ... 图像读取逻辑 ...
    img = self.transform(img)
    # ... 其余逻辑 ...

内容的提问来源于stack exchange,提问作者Bolofo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 18:35:05