AttributeError: 'str' object has no attribute 'items'

I don’t know why I get this error.

model.train()

for imgs, targets, image_ids in train_loader:

    imgs = list(imgs.to(device) for img in imgs)
    targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

    loss_dict = model(imgs, targets)
    losses = sum(loss for loss in loss_dict.values())
    loss_value = losses.item()
    optimizer.zero_grad()
    losses.backward()
    optimizer.step() 
    
    for epoch in range(num_epoch):
        print('Epoch {}/{}'.format(epoch, num_epoch))
        print('-' * 10)

AttributeError Traceback (most recent call last)
/var/folders/z4/_7p6fjpd2hq3n_l3dhnj0h4c0000gn/T/ipykernel_2502/1335634306.py in
4
5 imgs = list(imgs.to(device) for img in imgs)
----> 6 targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
7
8 loss_dict = model(imgs, targets)

/var/folders/z4/_7p6fjpd2hq3n_l3dhnj0h4c0000gn/T/ipykernel_2502/1335634306.py in (.0)
4
5 imgs = list(imgs.to(device) for img in imgs)
----> 6 targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
7
8 loss_dict = model(imgs, targets)

AttributeError: ‘str’ object has no attribute ‘items’

What type is targets? If it’s a dict, then with for t in targets, you are iterating over the keys of the dict, not the values, which is why t is a str.

It looks like this. The data is a csv file.

class PennFudanDataset(Dataset):
    def __init__(self, dataframe, image_dir, transform=None):
        
        self.image_ids = dataframe['ImageID'].unique()
        self.df = dataframe
        self.image_dir = image_dir
        self.transform = transform

    def __getitem__(self, index):
        
        image_id = self.image_ids[index]
        records = self.df[self.df['ImageID'] == image_id]     
        img = np.array(Image.open(f'{self.image_dir}data/{image_id}.jpg'), dtype=np.float32)
        img /= 255.0
        
        boxes = records[['XMin', 'YMin', 'XMax', 'YMax']].values
        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]
        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]
        
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        area = torch.as_tensor(area, dtype=torch.float32)

        # there is only one class
        labels = torch.ones((records.shape[0],), dtype=torch.int64)
        
        # suppose all instances are not crowd
        iscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)

        target = {}
        target['boxes'] = boxes
        target['labels'] = labels
        target['image_id'] = torch.tensor([index])
        target['area'] = area
        target['iscrowd'] = iscrowd
        target['boxes'] = torch.stack(list((map(torch.tensor, target['boxes'])))).type(torch.float32)

        #if self.transform:
        #    img = self.transform(img)

        return img, target, image_id

    def __len__(self) -> int:
        return self.image_ids.shape[0]

Ok so it’s a dict. If I understand your code correctly, you want to apply to(device) to all values in the dict. You could do that like this:

targets = {k: v.to(device) for k, v in targets.items()}
1 Like