Convert from keras to pytorch

I am training a multilabel classifier in keras ,i want to convert that to pytorch , i am mostly confused about how to handle the loss ,this is what the code looks like

   model = keras.applications.densenet.DenseNet121(include_top=False, input_shape=(224, 224, 3))
x = model.output
x = Flatten()(x)
x = Dense(512)(x)
x = Activation('relu')(x)
x = Dropout(0.5)(x)
output1 = Dense(1, activation = 'sigmoid')(x)
output2 = Dense(1, activation = 'sigmoid')(x)
output3 = Dense(1, activation = 'sigmoid')(x)
output4 = Dense(1, activation = 'sigmoid')(x)
output5 = Dense(1, activation = 'sigmoid')(x)
output6 = Dense(1, activation = 'sigmoid')(x)
output7 = Dense(1, activation = 'sigmoid')(x)
output8 = Dense(1, activation = 'sigmoid')(x)
model = Model(model.inputs,[output1,output2,output3,output4,output5, output6, output7, output8])
# print(model.summary())
model.compile(optimizers.rmsprop(lr = 0.0001, decay = 1e-6),
loss = ["binary_crossentropy","binary_crossentropy","binary_crossentropy","binary_crossentropy", "binary_crossentropy","binary_crossentropy","binary_crossentropy","binary_crossentropy"],metrics = ["accuracy"])

How can i do this in pytorch ,this is what i have till now

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(2304, 256)
        self.fc2 = nn.Linear(256, 8)

    def forward(self, x):

        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(x.size(0), -1) # Flatten layer
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.sigmoid(x)

model = Net().cuda() 
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)



def train(epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        # data, target = data.cuda(async=True), target.cuda(async=True) # On GPU

        data, target = Variable(data).cuda(), Variable(target).float().cuda()
        optimizer.zero_grad()
        output = model(data)

        loss = F.binary_cross_entropy(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 10 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))


for epoch in range(1, 10):
    train(epoch)

Thanks in advance, any suggestions will be very helpful

The output and criterion look alright for a multi-label classification.
Make sure that the target has the same shape as output.

Are you seeing any issues, e.g. lower accuracy etc.?

PS: Variables are deprecated and you can just use tensors :wink:

@ptrblck Thanks for the suggestions, it works fine now.

@ptrblck The model that i currently have trains, but the gpu volatility keeps going to 0, which is making the training really slow is there a way solve this?Thanks in advance.

class OdirDataset(Dataset):
    """Dataset wrapping images and target labels for Kaggle - Planet Amazon from Space competition
    Arguments:
        A CSV file path
        Path to image folder
        Extension of images
        PIL transforms
    """

    def __init__(self, csv_path, img_path, img_ext, transform=None):
        tmp_df = pd.read_csv(csv_path)
        self.img_path = img_path
        self.img_ext = img_ext
        self.transform = transform

        # import pdb;pdb.set_trace()
        self.X_train = tmp_df['Left-Fundus']
        self.y_train = tmp_df.iloc[:, 7:16].values

    def __getitem__(self, index):
        # import pdb;pdb.set_trace()
        img_left = Image.open(self.img_path + self.X_train[index] + self.img_ext)
        img_right= Image.open(self.img_path + self.X_train[0].split('_')[0] +'_right.jpg')
        img_left = img_left.convert('RGB')
        img_right = img_right.convert('RGB')
        if self.transform is not None:
            img_left  = self.transform(img_left)
            img_right = self.transform(img_right)

        img = np.concatenate([img_left,img_right],axis=0)
        label = torch.from_numpy(self.y_train[index])
        return img, label

    def __len__(self):
        return len(self.X_train.index)

 
transformations = transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])
dset_train = OdirDataset(TRAIN_DATA,IMG_PATH,IMG_EXT,transformations)
dset_val = OdirDataset(TEST_DATA,IMG_PATH,IMG_EXT,transformations)
train_loader = DataLoader(dset_train,
                          batch_size=84,
                          shuffle=True,
                          num_workers=12,pin_memory=True)

val_loader = DataLoader(dset_val,
                          batch_size=1,
                          shuffle=False,
                          num_workers=12,pin_memory=True)

Since you are using PIL to load and process the images, you could try to install PIL-SIMD, which is a replacement for the standard PIL lib and might give you a faster preprocessing pipeline.

The np.concatenate operation doesn’t look alright, as the transforms should return a tensor already.
Could you swap it for torch.cat?

Also, the number of workers is currently quite high for train_loader. I would recommend to play around with this number (lower it a bit) and check, if you can get rid of the bottleneck.

That being said, did you make sure that the data loading is actually the bottleneck?
Have a look at the ImageNet example to see, how to time the data loading.

Thanks a lot . let me look into each one of these one by one.

I am guessing data loading is the bottleneck here,not sure what else could cause this.