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

Unet++单类别训练报错:'tuple' object has no attribute 'size'

问题描述

开展Unet++单类别分割模型训练任务时,编写的训练代码如下:

model.train()
for epoch in range(3):

  running_loss = 0.0
  for i,data in enumerate(train_loader,0):
    inputs,labels,_ = data
    inputs = inputs[:,None,:]
    #labels = labels[:,None,:]
    print(inputs.shape)
    inputs = inputs.to(device=device)
    labels = labels.to(device=device)

    optimizer.zero_grad()
    #print("Input: ", inputs.shape)
    #print("Labels: ",labels.shape)
    outputs = model(inputs)
    #thresh_output = threshold(outputs,0.5)
    loss = criterion(outputs,labels)
    #dice_score = dice_loss(thresh_output,labels).item()
    loss.backward()
    optimizer.step()
    #wandb.log({"Train_Loss":loss})
    if(i%500 == 0):
      scheduler.step()
    running_loss += loss.item()
    # if(i == 1000):
    #   break
    print("Epoch : {}, iteration : {} and Loss : {}".format(epoch+1,i+1,loss.item()))

运行代码触发异常,控制台警告与完整报错信息如下:

torch.Size([1, 1, 256, 256]) /usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:1944: UserWarning: nn.functional.sigmoid is deprecated. Use torch.sigmoid instead. warnings.warn("nn.functional.sigmoid is deprecated. Use torch.sigmoid instead.")
AttributeError Traceback (most recent call last) in () 16 outputs = model(inputs) 17 #thresh_output = threshold(outputs,0.5) ---> 18 loss = criterion(outputs,labels) 19 #dice_score = dice_loss(thresh_output,labels).item() 20 loss.backward()

2 frames /usr/local/lib/python3.7/dist-packages/torch/nn/functional.py in binary_cross_entropy(input, target, weight, size_average, reduce, reduction) 3053 else: 3054 reduction_enum = _Reduction.get_enum(reduction) -> 3055 if target.size() != input.size(): 3056 raise ValueError( 3057 "Using a target size ({}) that is different to the input size ({}) is deprecated. "

AttributeError: 'tuple' object has no attribute 'size'

报错触发于损失计算语句loss = criterion(outputs,labels),最终抛出AttributeError异常,提示'tuple' object has no attribute 'size'。

根因定位
  • 核心报错诱因:主流开源Unet++实现默认开启**深监督(deep supervision)**机制,模型前向传播的返回值不是单个预测张量,而是不同解码层分支输出的预测结果组成的元组。二元交叉熵损失函数预期输入为张量,会调用.size()方法做形状校验,传入元组时就会触发属性不存在的错误。
  • 隐性问题:代码中调整标签维度的labels = labels[:,None,:]语句被注释,单通道分割场景下标签缺少通道维度,就算解决元组问题,后续也会触发输入、输出形状不匹配的报错。
  • 警告诱因:模型定义代码中使用了已弃用的nn.functional.sigmoid接口,PyTorch新版本要求替换为torch.sigmoid。
修复方案
  1. 处理模型输出格式
    • 方案一:初始化Unet++模型时,将深监督开关设为关闭,例如初始化时传入参数deep_supervision=False,模型前向传播就会直接返回单个最终预测张量。
    • 方案二:如果需要保留深监督提升训练效果,训练阶段可以对所有分支的输出计算平均损失,推理阶段取最后一个分支的最终输出即可。如果不需要用到多分支输出,也可以在得到模型返回值后直接提取最终分支结果:
    outputs = model(inputs)
    # 适配深监督返回的元组格式
    if isinstance(outputs, tuple):
        outputs = outputs[-1]
    
  2. 取消标签维度调整语句的注释,保证输入、预测输出、标签三者形状完全对齐,均为[batch_size, 1, H, W]格式。
  3. (可选)修复弃用警告:找到模型定义文件中调用nn.functional.sigmoid的位置,替换为torch.sigmoid即可。

修复后的核心训练循环代码如下:

model.train()
for epoch in range(3):
  running_loss = 0.0
  for i,data in enumerate(train_loader,0):
    inputs,labels,_ = data
    inputs = inputs[:,None,:]
    # 取消注释,给标签增加通道维度
    labels = labels[:,None,:]
    print(inputs.shape)
    inputs = inputs.to(device=device)
    labels = labels.to(device=device)

    optimizer.zero_grad()
    outputs = model(inputs)
    # 处理深监督返回的元组
    if isinstance(outputs, tuple):
        outputs = outputs[-1]
    loss = criterion(outputs,labels)
    loss.backward()
    optimizer.step()
    if(i%500 == 0):
      scheduler.step()
    running_loss += loss.item()
    print("Epoch : {}, iteration : {} and Loss : {}".format(epoch+1,i+1,loss.item()))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:12:25