Clip/limit the loss for outlier samples in a batch

Oli: <p>Hello!</p>
<p>I’m working on a project where we are building a simple image classifier that we intend to deploy on a video stream. Since the images from the video are quite custom-looking we are mostly using our own datasets, and this is where the problem starts.</p>
<p>The labels for our datasets are generated via an automatic process with some added manual oversight. The resulting dataset contains a small amount of dirty data (<strong>unclear images where a part/nothing of the class-object is in frame</strong>). These images are hard to classify for humans, and might not be suitable to train on. Unfortunately, there is no easy way to remove these images from the dataset so I’m looking for an alternative way to handle them.</p>
<p>Since this dirty data is relatively rare (say 5%), I was hoping to reduce its impact on training by identifying these samples at runtime and limit the loss they produce. I’ve come up with two solutions.</p>
<p>Solution 1<br>
The assumption is that the dirty data would show up as samples with high loss, and this code would limit their loss.</p>
<pre><code class="lang-auto">loss_fn = nn.CrossEntropyLoss(reduction="none")
loss = loss_fn(outputs, labels)

loss_threshold = loss.median() * 5 # Hyperparameter
loss_scales = torch.ones_like(loss)
for loss_idx, loss_val in enumerate(loss):
    if loss_val &gt; loss_threshold:
        loss_scales[loss_idx] = loss_threshold / loss[loss_idx]

loss = loss * loss_scales # Ensures no sample-loss is greater than loss_threshold
loss = loss.mean()
</code></pre>
<p>Solution 2<br>
Same idea as solution 1, but using PyTorch’s clamp function.</p>
<pre><code class="lang-auto">loss_fn = nn.CrossEntropyLoss(reduction="none")
loss = loss_fn(outputs, labels)

loss_threshold = loss.median() * 5 # Hyperparameter
loss = loss.clamp(max=loss_threshold.item())
loss = loss.mean()

</code></pre>
<p>It is not obvious to me whether these solutions are good ideas to try. For example, I don’t quite understand what happens to the gradients when you limit/clamp the loss as in these solutions (some info here <a href="https://github.com/pytorch/pytorch/issues/7002" class="inline-onebox" rel="noopener nofollow ugc">torch.clamp kills gradients at the border · Issue #7002 · pytorch/pytorch · GitHub</a>).</p>
<p>Based on a few experiments, these solutions perform worse than baseline. One thing that actually work is to limit the gradients via the pytorch function <code>torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=0.1)</code></p>
<p>Any suggestions to solve my problem would be appreciated <img src="https://discuss.pytorch.org/images/emoji/apple/sun_with_face.png?v=12" title=":sun_with_face:" class="emoji" alt=":sun_with_face:" loading="lazy" width="20" height="20"></p>
<p>Edit: Found some other threads that talk about this. No conclusive answer yet.</p><aside class="quote quote-modified" data-post="14" data-topic="25530">
  <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/john1231983/48/4040_2.png" class="avatar">
    <a href="https://discuss.pytorch.org/t/per-class-and-per-sample-weighting/25530/14">Per-class and per-sample weighting</a> 
  </div>
  <blockquote>
    Thanks. I used above code and it got error in backward() 
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
&lt;ipython-input-22-88aafe38e0f1&gt; in &lt;module&gt;()
     15 loss =(loss * sample_weight / sample_weight.sum()).sum()
     16 print (sample_weight.shape, loss.shape)
---&gt; 17 loss.mean().backward()
     18 
     19 #loss_total = torch.mean(loss * weights)

1 frames
/usr/local/lib/python3.6/dist-p…
  </blockquote>
</aside>
<aside class="quote quote-modified" data-post="1" data-topic="66372">
  <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/oasjd7/48/5053_2.png" class="avatar">
    <a href="https://discuss.pytorch.org/t/how-to-weight-the-loss/66372">How to weight the loss?</a> 
  </div>
  <blockquote>
    ...
for step, input in dataloader:
    outptut = model(input)  
    # top_prob, _ = torch.topk(F.softmax(output, dim=1)[0], 1)
    loss = criterion(output, label)


I want to weight the highest probability of softmax to the loss. 
ex) 
If, prob of softmax : 0.75 -&gt;  Effect of this sample * 0.75 
If, prob of softmax : 0.12 -&gt;  Effect of this sample * 0.12 
But the top_prob is the list (length == batch size) 
like top_prob = [0.72, 0.75, 0.82, ... 0.94] 
and loss is one scalar value. 
(It means th…
  </blockquote>
</aside>
<aside class="onebox stackexchange" data-onebox-src="https://stats.stackexchange.com/questions/346299/whats-the-effect-of-scaling-a-loss-function-in-deep-learning">
  <header class="source">

      <a href="https://stats.stackexchange.com/questions/346299/whats-the-effect-of-scaling-a-loss-function-in-deep-learning" target="_blank" rel="noopener nofollow ugc">stats.stackexchange.com</a>
  </header>

  <article class="onebox-body">
      <a href="https://stats.stackexchange.com/users/94803/chris" target="_blank" rel="noopener nofollow ugc">
    <img alt="Chris" src="https://www.gravatar.com/avatar/0ab81d1add08343653dc53cbc5b1e524?s=256&amp;d=identicon&amp;r=PG" class="thumbnail onebox-avatar" width="256" height="256">
  </a>

<h4>
  <a href="https://stats.stackexchange.com/questions/346299/whats-the-effect-of-scaling-a-loss-function-in-deep-learning" target="_blank" rel="noopener nofollow ugc">What's the effect of scaling a loss function in deep learning?</a>
</h4>

<div class="tags">
  <strong>deep-learning, optimization, loss-functions</strong>
</div>

<div class="date">
  asked by
  
  <a href="https://stats.stackexchange.com/users/94803/chris" target="_blank" rel="noopener nofollow ugc">
    Chris
  </a>
  on <a href="https://stats.stackexchange.com/questions/346299/whats-the-effect-of-scaling-a-loss-function-in-deep-learning" target="_blank" rel="noopener nofollow ugc">09:10AM - 15 May 18 UTC</a>
</div>

  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>


SarthakJain: <p>Hi,</p>
<p>One possible way to deal with this might be to initialize the learning rate to be lower. This will prevent any outlier from having profound affects on the model weights.</p>
<p>I also suggest a learning rate scheduler like Cosine Annealing. This is because once the model starts to converge you don’t want an outlier to make changes to your model that will slow down convergence. Therefore, a learning rate scheduler can lower the learning rate gradually as epochs progress which could help.</p>
<p>Sarthak Jain</p>

Oli: <p>Hi <a class="mention" href="/u/sarthakjain">@SarthakJain</a></p>
<p>Thanks for your input! I’m already doing linear learning rate warmup and cosine annealing to decrease my learning rate.</p>
<p>What I’m worried about is that my dirty data of 5% produces much more than 5% of the loss, hence affecting the model loss-landscape/trajectory more than I’d like (even if the learning rate is low).</p>

Oli: <p>Bump for the americans who might have missed it for July 4th</p>