Writing loss function with two inputs for the torchsample library

ZSheikhb: <p>I have been following the instruction on how to use <a href="https://github.com/ncullen93/torchsample/tree/master/torchsample" rel="noopener nofollow ugc">torchsample</a> library and I wrote my own loss function</p>
<pre><code class="lang-auto">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

</code></pre>
<p>when I ran my code I keep getthing this error message.</p>
<pre><code class="lang-auto">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
</code></pre>
<p>I will really appreciate if someone here can help to figure out how to fix this problem.</p>

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

ZSheikhb: <p>I have tried different things for instance I changed the structure of <code>LogisticRegressionLoss</code> and because I was getting this error:</p>
<pre><code class="lang-auto">  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
</code></pre>
<p>Then I used <code>DataLoader</code></p>
<pre><code class="lang-auto">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
</code></pre>
<p>The data set looks like this</p>
<pre><code class="lang-auto">{'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])
</code></pre>
<p>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:</p>
<pre><code class="lang-auto">  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
</code></pre>

ptrblck: <p>This error:</p>
<pre data-code-wrap="python"><code class="lang-python">    return - torch.mean(torch.log(torch.nn.Sigmoid(p_outputs) +self.epsilon)) \
TypeError: __init__() takes 1 positional argument but 2 were given
</code></pre>
<p>is raised because you are passing the <code>p_outputs</code> tensor to the <code>__init__</code> method of <code>nn.Sigmoid()</code>. Either create an object first:</p>
<pre data-code-wrap="python"><code class="lang-python">torch.nn.Sigmoid()(p_outputs)
</code></pre>
<p>or use the functional API:</p>
<pre data-code-wrap="python"><code class="lang-python">torch.sigmoid(p_outputs)
</code></pre>
<aside class="quote no-group" data-username="ZSheikhb" data-post="3" data-topic="158488">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/zsheikhb/48/41639_2.png" class="avatar"> ZSheikhb:</div>
<blockquote>
<p><code>TypeError: 'DataLoader' object is not subscriptable</code></p>
</blockquote>
</aside>
<p>Your code seems to try to slice the <code>DataLoader</code>, which is not possible as you would need to iterate it.</p>
<p>Given that <a href="https://github.com/ncullen93/torchsample"><code>torchsample</code></a> received the last updates ~5 years ago, I would probably not use it as you might be hitting more and more issues.</p>

ZSheikhb: <aside class="quote no-group" data-username="ptrblck" data-post="4" data-topic="158488">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Your code seems to try to slice the <code>DataLoader</code>, which is not possible as you would need to iterate it.</p>
</blockquote>
</aside>
<p>Thank you for your answer. I change the train module in my class</p>
<pre><code class="lang-auto">    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]
</code></pre>
<p>Now I get a new error:</p>
<pre><code class="lang-auto">  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 &lt;lambda&gt;
    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

</code></pre>
<p>The reason I have been using this library is it has similar structure as <code>tf.keras.callbacks</code>. Thank you again.</p>

ptrblck: <p>I don’t see any error message so did you forget to include it in your post?</p>

ZSheikhb: <p>Included the error message.</p>

ptrblck: <p>It seems <code>q_outputs</code> is <code>None</code> instead of a tensor. Did you forget to <code>return</code> a tensor in a <code>forward</code> method in one of your models?</p>