Repository: pytorch/pytorch

Issue:
Inconsistency in _assert_no_grad between nn.functional and nn
In various losses, nn.functional does not have _assert_no_grad but Module does. I guess both have their advantages so maybe we can add a flag and make them uniform or document the fact that nn.functional can backpropogate through targets. 


Discussion:
A lot of those losses actually do return gradients for the targets now. I think the right fix here is to remove `_assert_no_grad `: autograd should warn if the gradients can't be computed for certain targets.

Resolving patch:
diff --git a/torch/nn/modules/loss.py b/torch/nn/modules/loss.py
--- a/torch/nn/modules/loss.py
+++ b/torch/nn/modules/loss.py
@@ -7,12 +7,6 @@
 from .. import functional as F
 
 
-def _assert_no_grad(tensor):
-    assert not tensor.requires_grad, \
-        "nn criterions don't compute the gradient w.r.t. targets - please " \
-        "mark these tensors as not requiring gradients"
-
-
 class _Loss(Module):
     def __init__(self, size_average=True, reduce=True):
         super(_Loss, self).__init__()
@@ -81,7 +75,6 @@ def __init__(self, size_average=True, reduce=True):
         super(L1Loss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.l1_loss(input, target, size_average=self.size_average,
                          reduce=self.reduce)
 
@@ -189,7 +182,6 @@ def __init__(self, weight=None, size_average=True, ignore_index=-100, reduce=Tru
         self.ignore_index = ignore_index
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.nll_loss(input, target, self.weight, self.size_average,
                           self.ignore_index, self.reduce)
 
@@ -253,7 +245,6 @@ def __init__(self, log_input=True, full=False, size_average=True, eps=1e-8, redu
         self.eps = eps
 
     def forward(self, log_input, target):
-        _assert_no_grad(target)
         return F.poisson_nll_loss(log_input, target, self.log_input, self.full,
                                   self.size_average, self.eps, self.reduce)
 
@@ -336,7 +327,6 @@ def __init__(self, size_average=True, reduce=True):
         super(KLDivLoss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.kl_div(input, target, size_average=self.size_average, reduce=self.reduce)
 
 
@@ -394,7 +384,6 @@ def __init__(self, size_average=True, reduce=True):
         super(MSELoss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.mse_loss(input, target, size_average=self.size_average, reduce=self.reduce)
 
 
@@ -454,7 +443,6 @@ def __init__(self, weight=None, size_average=True, reduce=True):
         super(BCELoss, self).__init__(weight, size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.binary_cross_entropy(input, target, weight=self.weight,
                                       size_average=self.size_average,
                                       reduce=self.reduce)
@@ -620,7 +608,6 @@ def __init__(self, size_average=True, reduce=True):
         super(MultiLabelMarginLoss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.multilabel_margin_loss(input, target, size_average=self.size_average,
                                         reduce=self.reduce)
 
@@ -672,7 +659,6 @@ def __init__(self, size_average=True, reduce=True):
         super(SmoothL1Loss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.smooth_l1_loss(input, target, size_average=self.size_average,
                                 reduce=self.reduce)
 
@@ -706,7 +692,6 @@ def __init__(self, size_average=True, reduce=True):
         super(SoftMarginLoss, self).__init__(size_average, reduce)
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.soft_margin_loss(input, target, size_average=self.size_average,
                                   reduce=self.reduce)
 
@@ -789,7 +774,6 @@ def __init__(self, weight=None, size_average=True, ignore_index=-100, reduce=Tru
         self.ignore_index = ignore_index
 
     def forward(self, input, target):
-        _assert_no_grad(target)
         return F.cross_entropy(input, target, self.weight, self.size_average,
                                self.ignore_index, self.reduce)
 


Test patch: