Reputation: 45
Today i faced with problem
AttributeError: 'tuple' object has no attribute 'to'
I read a data from csv file with 2 columns: Image (where the file path is) and finding (where the photo's label is)
Model:
model = models.resnet18(pretrained=False)
model.fc = nn.Sequential(nn.Linear(model.fc.in_features, 256),
nn.ReLU(),
nn.Dropout(p=0.3),
nn.Linear(256, 100),
nn.ReLU(),
nn.Dropout(p=0.4),
nn.Linear(100,9))
# model.load_state_dict(torch.load('model.pth'))
for name, param in model.named_parameters():
if("bn" not in name):
param.requires_grad = False
Transforms:
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5457, 0.5457, 0.5457], std=[0.2342, 0.2342, 0.2342])
])
Dataset class:
class Col(Dataset):
def __init__(self, csv, main_dir, transform):
self.df = pd.read_csv(csv)
self.main_dir = main_dir
self.transform = transform
def __len__(self):
return self.df.shape[0]
def __getitem__(self, idx):
image = transform(Image.open(self.df.Image[idx]).convert("RGB"))
label = self.df.Finding[idx]
return image, label
Prepairing Data:
data = Col(main_dir=root_dir,csv=csv_file, transform=transform)
dataset = torch.utils.data.DataLoader(data, batch_size=130)
train_set, validate_set= torch.utils.data.random_split(dataset, [round(len(dataset)*0.7), (len(dataset) - round(len(dataset)*0.7))])
Train func:
def train(model, optimizer, loss_fn, train_set, validate_set, epochs=20, device="cpu"):
for epoch in range(1, epochs+1):
training_loss = 0.0
valid_loss = 0.0
model.train()
for batch in train_set:
optimizer.zero_grad()
inputs, labels = batch
inputs = inputs.to(device)
labels = labels.to(device)
output = model(inputs)
loss = loss_fn(output, labels)
loss.backward()
optimizer.step()
training_loss += loss.data.item() * inputs.size(0)
training_loss /= len(train_set.dataset)
model.eval()
num_correct = 0
num_examples = 0
for batch in validate_set:
inputs, labels = batch
inputs = inputs.to(device)
output = model(inputs)
labels = labels.to(device)
loss = loss_fn(output, labels)
valid_loss += loss.data.item() * inputs.size(0)
correct = torch.eq(torch.max(F.softmax(output, dim=1), dim=1)[1], targets)
num_correct += torch.sum(correct).item()
num_examples += correct.shape[0]
valid_loss /= len(validate_set.dataset)
print('Epoch: {}, Training Loss: {:.2f}, Validation Loss: {:.2f}, accuracy = {:.2f}'.format(epoch, training_loss,
valid_loss, num_correct / num_examples))
Optimazer:
optimizer = optim.Adam(model.parameters(), lr=0.0001)
After calling train func
train(model, optimizer,torch.nn.CrossEntropyLoss(), train_set.dataset, validate_set.dataset, epochs=100, device=device)
I've got this error:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_9156/634509595.py in <module>
----> 1 train(model, optimizer,torch.nn.CrossEntropyLoss(), train_set.dataset, validate_set.dataset, epochs=100, device=device)
/tmp/ipykernel_9156/2858123881.py in train(model, optimizer, loss_fn, train_set, validate_set, epochs, device)
8 inputs, labels = batch
9 inputs = inputs.to(device)
---> 10 labels = labels.to(device)
11 output = model(inputs)
12 loss = loss_fn(output, labels)
AttributeError: 'tuple' object has no attribute 'to'
If i try to call this
for batch in train_set.dataset:
inputs, labels = batch
print(labels)
then it will display many large tuples with labels.(like this)
('polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps', 'polyps')
How can i fix this? Help me please
Upvotes: 1
Views: 5450
Reputation: 40748
You need to encode your labels into integers (or one-hot encodings depending on your loss_fn
).
You should have classes
, a list of 9 class names. If not you can get it with self.df.Finding.unique()
.
You can then invert this list into a dictionnary, essentially a label-name -> label-id
mapping:
self.encode = {k: i for i, k in enumerate(classes)}
Then in your dataset __getitem__
definition convert the label names to label ids with encode
:
def __getitem__(self, idx):
image = transform(Image.open(self.df.Image[idx]).convert("RGB"))
label = self.encode[self.df.Finding[idx]]
return image, label
Upvotes: 2