Writing loss function with two inputs for the torchsample library

I have been following the instruction on how to use torchsample library and I wrote my own loss function

LogisticRegressionLoss  = lambda p_outputs, q_outputs: - torch.mean(torch.log(torch.nn.Sigmoid(p_outputs) +1e-12))- torch.mean(torch.log(1 - torch.nn.Sigmoid(q_outputs) + 1e-12))

class DensityRatioEstimator(nn.Module):

    def __init__(self, target_train_samples, hidden_params, target_val_samples=None):
        super(DensityRatioEstimator,self).__init__()
        self._train_contexts = torch.from_numpy(target_train_samples[0]).type(torch.float32)
            
        self._target_train_samples = torch.cat([torch.from_numpy(x) for x in target_train_samples], -1).type(torch.float32)
        self._val_contexts = torch.from_numpy(target_val_samples[0]).type(torch.float32)
        self._target_val_samples = torch.cat([torch.from_numpy(x) for x in target_val_samples], -1).type(torch.float32)

        self.hidden_params=hidden_params
        
        input_dim = self._target_train_samples.shape[-1]
    
        self._ldre_net, self._ldre_regularizer = build_dense_network(input_dim=input_dim, output_dim=1,
                                             output_activation="linear", params=self.hidden_params)

        self._p_samples = nn.Linear(input_dim,input_dim)
        self._q_samples = nn.Linear(input_dim,input_dim)
        
    def forward(self, x):
        p = self._p_samples(x)
        q = self._q_samples(x)
        combined = torch.cat((p.view(p.size(0), -1),
                              q.view(q.size(0), -1)), dim=1)
        self._split_layers = Split(
         self._ldre_net[-1],
         parts=2,
        )
        p_output, q_output =self._split_layers(combined)
        return p_output, q_output 

    def __call__(self, samples):
        return self._ldre_net(samples)

    def train(self, model, batch_size, num_iters):
        self.trainer   = ModuleTrainer(model)
        self.batch_size= batch_size
        metrics   = [DensityRatioAccuracy()]
        optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
        initializers = [XavierUniform(bias=False, module_filter='*')]
        regularizers   = [L2Regularizer(scale=1e-4)]
        model_train_samples, model_val_samples = self.sample_model(model)
        callbacks = [EarlyStopping(monitor='val_loss', patience=10),
                        ReduceLROnPlateau(factor=0.5, patience=5)]
        validation_data =( (self._target_val_samples, model_val_samples),None)
        self.trainer.compile(loss=LogisticRegressionLoss,
                             optimizer=optimizer,
                             regularizers=regularizers,
                             initializers=initializers,
                             metrics=metrics, 
                             callbacks=callbacks)
        self.trainer.fit(inputs    = (self._target_train_samples,model_train_samples),
                         targets   = None,
                         val_data  = validation_data,
                         batch_size= batch_size, 
                         num_epoch = num_iters,
                         verbose   = 0)
        
        print(self.trainer.history['acc_metric'])
        print(self.trainer.history['loss'])
        last_epoch = self.trainer.epoch[-1]
        return last_epoch+1, self.trainer.history.losses[-1],self.trainer.history.batch_metrics[-1]
        
    def sample_model(self, model):
        """Sample model for density ratio estimator training"""
        model_train_samples = torch.cat([self._train_contexts, model.sample(self._train_contexts)], dim=-1)
        else:
        model_train_samples = model.sample(self._target_train_samples.shape[0])
        model_val_samples = torch.cat([self._val_contexts, model.sample(self._val_contexts)], dim=-1)

        return model_train_samples, model_val_samples

when I ran my code I keep getthing this error message.

File "EIM.py", line 783, in train
    self.trainer.fit(inputs    = (self._target_train_samples,model_train_samples),
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 268, in fit
    output_batch = fit_forward_fn(input_batch)
  File "/home/src/torchsample/torchsample/modules/module_trainer.py", line 818, in forward_pass
    return model(*input_batch)
  File "/home/dm_control/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1102, in _call_impl
    return forward_call(*input, **kwargs)
TypeError: forward() takes 2 positional arguments but 3 were given

I will really appreciate if someone here can help to figure out how to fix this problem.

Based on the error message it seems you are passing too many input arguments to trainer.fit (you are passing two inputs) while the forward method expects a single input argument as x.
I’m not familiar with torchsample but would guess that you might need to pass the target tensor as the targets argument to trainer.fit.

I have tried different things for instance I changed the structure of LogisticRegressionLoss and because I was getting this error:

  File "EIM.py", line 791, in train
    self.trainer.fit(inputs    = self._target_train_samples, 
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 269, in fit
    loss = fit_loss_fn(output_batch, target_batch)
  File "/home/dm_control/src/torchsample/torchsample/modules/_utils.py", line 20, in new_loss_fn
    return loss_fn(output_batch, target_batch) + regularizer_container.get_value()
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 669, in calculate_loss
    return loss_fn(output_batch, target_batch)
  File "/home/dm_control/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1102, in _call_impl
    return forward_call(*input, **kwargs)
  File "EIM.py", line 707, in forward
    return - torch.mean(torch.log(torch.nn.Sigmoid(p_outputs) +self.epsilon)) \
TypeError: __init__() takes 1 positional argument but 2 were given

Then I used DataLoader

from torchsample.callbacks import EarlyStopping, ReduceLROnPlateau
from torchsample.modules import ModuleTrainer
from torchsample.metrics import Metric
from torchsample.regularizers import L2Regularizer
from torchsample.initializers import XavierUniform
from torch.utils.data import DataLoader
class DensityRatioEstimator(nn.Module):

    def __init__(self, target_train_samples, hidden_params):
        super(DensityRatioEstimator,self).__init__()
        self._early_stopping = early_stopping
        self._conditional_model = conditional_model

        self._train_contexts = torch.from_numpy(target_train_samples[0]).type(torch.float32)
            
        self._target_train_samples = torch.cat([torch.from_numpy(x) for x in target_train_samples], 
        self._val_contexts = torch.from_numpy(target_val_samples[0]).type(torch.float32)
        self._target_val_samples = torch.cat([torch.from_numpy(x) for x in target_val_samples], -1).type(torch.float32)
        self._target_val_samples = torch.from_numpy(target_val_samples).type(torch.float32)
        self.hidden_params=hidden_params
        
        input_dim = self._target_train_samples.shape[-1]
    
        self._ldre_net, self._ldre_regularizer = build_dense_network(input_dim=input_dim, output_dim=1,
                                             output_activation="linear", params=self.hidden_params)

        self._p_samples = nn.Linear(input_dim,input_dim)
        self._q_samples = nn.Linear(input_dim,input_dim)
        
    def forward(self, x):
        p = self._p_samples(x)
        q = self._q_samples(x)
        combined = torch.cat((p.view(p.size(0), -1),
                              q.view(q.size(0), -1)), dim=1)
        self._split_layers = Split(
         self._ldre_net[-1],
         parts=2,
        )
        p_output, q_output =self._split_layers(combined)
        return p_output, q_output 

    def __call__(self, samples):
        return self._ldre_net(samples)

    def train(self, model, batch_size, num_iters):
        self.trainer   = ModuleTrainer(model)
        self.batch_size= batch_size
        metrics   = [DensityRatioAccuracy()]
        optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
        initializers = [XavierUniform(bias=False, module_filter='*')]
        regularizers   = [L2Regularizer(scale=1e-4)]
        LogisticRegressionLoss  = lambda p_outputs, q_outputs: - torch.mean(torch.log(torch.nn.Sigmoid(p_outputs) +1e-12))- torch.mean(torch.log(1 - torch.nn.Sigmoid(q_outputs) + 1e-12))

        model_train_samples, model_val_samples = self.sample_model(model)
        callbacks = [EarlyStopping(monitor='val_loss', patience=10),
                        ReduceLROnPlateau(factor=0.5, patience=5)]
        val_dataset = torch.utils.data.TensorDataset(self._target_val_samples, model_val_samples)
        val_loader  = DataLoader(val_dataset, batch_size=batch_size, num_workers=0, shuffle=True)
        
        train_dataset = torch.utils.data.TensorDataset(self._target_train_samples, model_train_samples)
        print(train_dataset['tensors'])
        print(batch_size)
        train_loader  = DataLoader(train_dataset, batch_size=batch_size, num_workers=0, shuffle=True)
        

        self.trainer.compile(loss=LogisticRegressionLoss,
                             optimizer=optimizer,
                             regularizers=regularizers,
                             initializers=initializers,
                             metrics=metrics, 
                             callbacks=callbacks)
        print("shape of input data....")
        print(self._target_train_samples.size(), model_train_samples.size())
        self.trainer.fit(train_loader, 
                         val_loader,
                         num_epoch = num_iters,
                         verbose   = 1)
        last_epoch = self.trainer.epoch[-1]
        return last_epoch+1, self.trainer.history.losses[-1],self.trainer.history.batch_metrics[-1]
        


    def eval(self, target_samples):
        #Turns off training-time behavior
        model_samples = torch.cat([target_samples[0], model.sample(target_samples[0])], dim=-1)
        target_samples = torch.cat(target_samples, dim=-1)
        target_ldre = self(target_samples)
        model_ldre = self(model_samples)
        target_prob = nn.Sigmoid(target_ldre)
        model_prob = nn.Sigmoid(model_ldre)
        eval_loss = self.trainer.evaluate(target_ldre, model_ldre, batch_size=self.batch_size, verbose=1)
        ikl_estem = torch.mean(- model_ldre)
        
        return ikl_estem, eval_loss, torch.mean(target_prob), torch.mean(model_prob)

    def sample_model(self, model):
        """Sample model for density ratio estimator training"""
        model_train_samples = torch.cat([self._train_contexts, model.sample(self._train_contexts)], dim=-1)
         model_val_samples = torch.cat([self._val_contexts, model.sample(self._val_contexts)], dim=-1)
         model_val_samples = model.sample(self._target_val_samples.shape[0])
         return model_train_samples, model_val_samples

The data set looks like this

{'tensors': (tensor([[-0.5365,  0.4834, -0.0135,  ...,  0.5613,  0.4535, -0.4859],
        [-0.4767, -0.4059, -0.0204,  ..., -0.5451,  0.5389, -0.2768],
        [-0.4873,  0.4082, -0.0296,  ...,  0.4359,  0.5194,  0.5117],
        ...,
        [-0.5148, -0.4907, -0.0244,  ..., -0.4718,  0.5100,  0.3539],
        [-0.4723, -0.1420,  0.0622,  ...,  0.5040,  0.5407, -0.2489],
        [-0.4061,  0.3949,  0.0471,  ...,  0.5818,  0.4616, -0.6120]]), tensor([[-0.5365,  0.4834, -0.0135,  ...,  0.0000,  0.0000,  0.0000],
        [-0.4767, -0.4059, -0.0204,  ...,  0.0000,  0.0000,  0.0000],
        [-0.4873,  0.4082, -0.0296,  ...,  0.0000,  0.0000,  0.0000],
        ...,
        [-0.5148, -0.4907, -0.0244,  ...,  0.0000,  0.0000,  0.0000],
        [-0.4723, -0.1420,  0.0622,  ...,  0.0000,  0.0000,  0.0000],
        [-0.4061,  0.3949,  0.0471,  ...,  0.0000,  0.0000,  0.0000]]))}
shape of input data....
torch.Size([10000, 12]) torch.Size([10000, 12])

Now I get this error message. I will really appreciate if you suggest a solution because I am really getting confused with these error messages:

  File "EIM.py", line 789, in train
    self.trainer.fit(train_loader, 
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 260, in fit
    input_batch, target_batch = fit_helper.grab_batch(batch_idx, batch_size, inputs, targets)
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 653, in grab_batch
    input_batch = Variable(inputs[batch_idx*batch_size:(batch_idx+1)*batch_size], volatile=volatile)
TypeError: 'DataLoader' object is not subscriptable

This error:

    return - torch.mean(torch.log(torch.nn.Sigmoid(p_outputs) +self.epsilon)) \
TypeError: __init__() takes 1 positional argument but 2 were given

is raised because you are passing the p_outputs tensor to the __init__ method of nn.Sigmoid(). Either create an object first:

torch.nn.Sigmoid()(p_outputs)

or use the functional API:

torch.sigmoid(p_outputs)

Your code seems to try to slice the DataLoader, which is not possible as you would need to iterate it.

Given that torchsample received the last updates ~5 years ago, I would probably not use it as you might be hitting more and more issues.

Thank you for your answer. I change the train module in my class

    def train(self, model, batch_size, num_iters):
        #compile the model
        #https://github.com/ncullen93/torchsample
        self.trainer   = ModuleTrainer(model)
        self.batch_size= batch_size
        metrics   = [DensityRatioAccuracy()]
        optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
        initializers = [XavierUniform(bias=False, module_filter='*')]
        regularizers   = [L2Regularizer(scale=1e-4)]
        LogisticRegressionLoss  = lambda p_outputs, q_outputs: - torch.mean(torch.log(torch.nn.Sigmoid()(p_outputs) +1e-12))- torch.mean(torch.log(1 - torch.nn.Sigmoid()(q_outputs) + 1e-12))

        if self._early_stopping:
           model_train_samples, model_val_samples = self.sample_model(model)
           callbacks = [EarlyStopping(monitor='val_loss', patience=10),
                        ReduceLROnPlateau(factor=0.5, patience=5)]
           validation_data = (self._target_val_samples, model_val_samples)
        else:
           model_train_samples = self.sample_model(model)
           callbacks = []
           validation_data = None
        self.trainer.compile(loss=LogisticRegressionLoss,
                             optimizer=optimizer,
                             regularizers=regularizers,
                             initializers=initializers,
                             metrics=metrics, 
                             callbacks=callbacks)
        print("shape of input data....")
        print(self._target_train_samples.size(), model_train_samples.size())
        self.trainer.fit(self._target_train_samples, model_train_samples,
                         val_data  = validation_data,
                         batch_size= batch_size, 
                         num_epoch = num_iters,
                         verbose   = 1)
   
        print(self.trainer.history['acc_metric'])
        print(self.trainer.history['loss'])
        last_epoch = self.trainer.epoch[-1]
        return last_epoch+1, self.trainer.history.losses[-1],self.trainer.history.batch_metrics[-1]

Now I get a new error:

  File "EIM.py", line 784, in train
    self.trainer.fit(self._target_train_samples, model_train_samples,
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 269, in fit
    loss = fit_loss_fn(output_batch, target_batch)
  File "/home/dm_control/src/torchsample/torchsample/modules/_utils.py", line 20, in new_loss_fn
    return loss_fn(output_batch, target_batch) + regularizer_container.get_value()
  File "/home/dm_control/src/torchsample/torchsample/modules/module_trainer.py", line 669, in calculate_loss
    return loss_fn(output_batch, target_batch)
  File "EIM.py", line 765, in <lambda>
    LogisticRegressionLoss  = lambda p_outputs, q_outputs: - torch.mean(torch.log(torch.nn.Sigmoid()(p_outputs) +1e-12))- torch.mean(torch.log(1 - tor
ch.nn.Sigmoid()(q_outputs) + 1e-12))
TypeError: sigmoid(): argument 'input' (position 1) must be Tensor, not NoneType

The reason I have been using this library is it has similar structure as tf.keras.callbacks. Thank you again.

I don’t see any error message so did you forget to include it in your post?

Included the error message.

It seems q_outputs is None instead of a tensor. Did you forget to return a tensor in a forward method in one of your models?