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

PyTorch自定义Dataset/DataLoader报str无to属性错误咨询

PyTorch自定义DataLoader训练报'str' object has no attribute 'to'排查方案

问题复现

参照PyTorch官方数据加载教程构建包含图像、48个关键点标注、30类分类标签的人脸关键点数据集,自定义DataLoader经校验返回的图像、关键点字段均为torch.float64类型,接入训练流程时在张量移至设备的代码行触发报错:

AttributeError: ‘str’ object has no attribute 'to'

涉及的核心代码如下:
训练循环片段:

class Trainer():
  
    def __init__(self,criterion = None,optimizer = None,schedular = None):
        self.criterion = criterion
        self.optimizer = optimizer
        self.schedular = schedular
  
    def train_batch_loop(self,model,train_dataloader):    
        train_loss = 0.0
        train_acc = 0.0     
        for images,landmarks, labels in train_dataloader: 
                images = images.to(device)
                landmarks = landmarks.to(device)
                labels = labels.to(device)        
                self.optimizer.zero_grad()

自定义数据集片段:

class FaceLandmarksDataset(Dataset):

    def __init__(self, data_frame, root_dir, transform=None):
        self.data_frame = data_frame
        self.root_dir = root_dir
        self.transform = transform

    def __len__(self):
        return len(self.data_frame)

    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()

        img_name = os.path.join(self.root_dir,
                                self.data_frame.iloc[idx, 2])
        image = io.imread(img_name)
        landmarks = self.data_frame.iloc[idx, 3:]
        landmarks = np.array([landmarks])
        landmarks = landmarks.astype('float').reshape(-1, 2)
        labels = self.data_frame.iloc[idx, 1].reshape(1)
        sample = {'image': image, 'landmarks': landmarks, 'labels': labels}

        if self.transform:
            sample = self.transform(sample)

        return sample

错误截图:
问题报错截图

根因定位与排查点

这个报错是Dataset返回值结构和训练循环的解包逻辑不匹配导致的,不需要逐行溯源数据表字段:

  • 你的__getitem__方法最终返回的是字典类型的sample,但训练循环里直接用images, landmarks, labels三元组对DataLoader返回的batch做顺序解包。PyTorch默认的批拼接逻辑不会自动把字典拆成独立张量,直接对字典做顺序解包时,拿到的前三个元素是字典的键字符串'image'、'landmarks'、'labels',所以第一个赋值给images的变量实际是字符串'image',调用.to(device)自然会触发属性错误。
  • 你之前做的DataLoader数据类型校验逻辑有漏洞:只校验了字典内部的value类型,没校验DataLoader迭代返回的顶层对象类型,才会误以为所有返回组件都是张量。

修复方案

二选一即可:

  1. 修改Dataset返回值格式,和训练循环解包逻辑对齐:把__getitem__方法最后返回字典的逻辑改为直接返回元组
    # 替换原来return sample的逻辑
    return sample['image'], sample['landmarks'], sample['labels']
    
  2. 保留字典返回格式,修改训练循环的取值逻辑,按键从batch字典中取对应张量
    for batch in train_dataloader:
        images = batch['image'].to(device)
        landmarks = batch['landmarks'].to(device)
        labels = batch['labels'].to(device)
        self.optimizer.zero_grad()
        # 后续训练逻辑保持不变
    

额外校验项

修复结构问题后,还要确认transform流水线中已经将numpy格式的关键点、标签字段转换为torch张量:官方教程提供的ToTensor类仅会处理图像字段的格式转换,关键点、标签如果没有手动转张量,后续会触发新的类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:57:25