Repository: pytorch/ignite

Issue:
Replace asserts in the code by if condition then raise 
It would be better to replace the code as 

https://github.com/pytorch/ignite/blob/0f1905e87b95779cf6544a5fe29b46519ad9d4e0/ignite/metrics/epoch_metric.py#L33-L34

by 
```python
if y_pred.ndimension()  < 1 or  y_pred.ndimension() > 2:
    raise TypeError("Predictions should be of shape (batch_size, n_classes)"
# etc
```

Usage of assert to change in `EpochMetric`, `EarlyStopping` and `Loss`



Discussion:

Resolving patch:
diff --git a/ignite/handlers/early_stopping.py b/ignite/handlers/early_stopping.py
--- a/ignite/handlers/early_stopping.py
+++ b/ignite/handlers/early_stopping.py
@@ -32,9 +32,16 @@ def score_function(engine):
 
     """
     def __init__(self, patience, score_function, trainer):
-        assert callable(score_function), "Argument score_function should be a function"
-        assert patience > 0, "Argument patience should be positive"
-        assert isinstance(trainer, Engine), "Argument trainer should be an instance of Engine"
+
+        if not callable(score_function):
+            raise TypeError("Argument score_function should be a function")
+
+        if patience < 1:
+            raise ValueError("Argument patience should be positive integer")
+
+        if not isinstance(trainer, Engine):
+            raise TypeError("Argument trainer should be an instance of Engine")
+
         self.score_function = score_function
         self.patience = patience
         self.trainer = trainer
diff --git a/ignite/metrics/epoch_metric.py b/ignite/metrics/epoch_metric.py
--- a/ignite/metrics/epoch_metric.py
+++ b/ignite/metrics/epoch_metric.py
@@ -19,7 +19,10 @@ class EpochMetric(Metric):
     """
 
     def __init__(self, compute_fn, output_transform=lambda x: x):
-        assert callable(compute_fn), "Argument compute_fn should be callable"
+
+        if not callable(compute_fn):
+            raise TypeError("Argument compute_fn should be callable")
+
         super(EpochMetric, self).__init__(output_transform=output_transform)
         self.compute_fn = compute_fn
 
@@ -30,11 +33,15 @@ def reset(self):
     def update(self, output):
         y_pred, y = output
 
-        assert 1 <= y_pred.ndimension() <= 2, "Predictions should be of shape (batch_size, n_classes)"
-        assert 1 <= y.ndimension() <= 2, "Targets should be of shape (batch_size, n_classes)"
+        if y_pred.ndimension() not in (1, 2):
+            raise ValueError("Predictions should be of shape (batch_size, n_classes) or (batch_size, )")
+
+        if y.ndimension() not in (1, 2):
+            raise ValueError("Targets should be of shape (batch_size, n_classes) or (batch_size, )")
 
         if y.ndimension() == 2:
-            assert torch.equal(y ** 2, y), 'Targets should be binary (0 or 1)'
+            if not torch.equal(y ** 2, y):
+                raise ValueError('Targets should be binary (0 or 1)')
 
         if y_pred.ndimension() == 2 and y_pred.shape[1] == 1:
             y_pred = y_pred.squeeze(dim=-1)
diff --git a/ignite/metrics/loss.py b/ignite/metrics/loss.py
--- a/ignite/metrics/loss.py
+++ b/ignite/metrics/loss.py
@@ -38,7 +38,10 @@ def update(self, output):
         else:
             y_pred, y, kwargs = output
         average_loss = self._loss_fn(y_pred, y, **kwargs)
-        assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'
+
+        if len(average_loss.shape) != 0:
+            raise ValueError('loss_fn did not return the average loss')
+
         self._sum += average_loss.item() * y.shape[0]
         self._num_examples += y.shape[0]
 


Test patch:
diff --git a/tests/ignite/handlers/test_early_stopping.py b/tests/ignite/handlers/test_early_stopping.py
--- a/tests/ignite/handlers/test_early_stopping.py
+++ b/tests/ignite/handlers/test_early_stopping.py
@@ -12,14 +12,13 @@ def update_fn(engine, batch):
 
     trainer = Engine(update_fn)
 
-    # save_interval & score_func
-    with pytest.raises(AssertionError):
+    with pytest.raises(ValueError):
         h = EarlyStopping(patience=-1, score_function=lambda engine: 0, trainer=trainer)
 
-    with pytest.raises(AssertionError):
+    with pytest.raises(TypeError):
         h = EarlyStopping(patience=2, score_function=12345, trainer=trainer)
 
-    with pytest.raises(AssertionError):
+    with pytest.raises(TypeError):
         h = EarlyStopping(patience=2, score_function=lambda engine: 0, trainer=None)
 
 
diff --git a/tests/ignite/metrics/test_epoch_metric.py b/tests/ignite/metrics/test_epoch_metric.py
--- a/tests/ignite/metrics/test_epoch_metric.py
+++ b/tests/ignite/metrics/test_epoch_metric.py
@@ -5,23 +5,32 @@
 
 def test_epoch_metric():
 
+    # Wrong compute function
+    with pytest.raises(TypeError):
+        EpochMetric(12345)
+
     def compute_fn(y_preds, y_targets):
         return 0.0
 
     em = EpochMetric(compute_fn)
 
     # Wrong input dims
-    with pytest.raises(AssertionError):
+    with pytest.raises(ValueError):
         output = (torch.tensor(0), torch.tensor(0))
         em.update(output)
 
     # Wrong input dims
-    with pytest.raises(AssertionError):
+    with pytest.raises(ValueError):
+        output = (torch.rand(4, 3), torch.rand(4, 3, 1))
+        em.update(output)
+
+    # Wrong input dims
+    with pytest.raises(ValueError):
         output = (torch.rand(4, 3, 1), torch.rand(4, 3))
         em.update(output)
 
     # Target is not binary
-    with pytest.raises(AssertionError):
+    with pytest.raises(ValueError):
         output = (torch.rand(4, 3), torch.randint(0, 5, size=(4, 3)))
         em.update(output)
 
@@ -38,6 +47,20 @@ def compute_fn(y_preds, y_targets):
     assert torch.equal(em._targets[4:, :], output2[1])
     assert em.compute() == 0.0
 
+    # test when y and y_pred are (batch_size, 1) that are squeezed to (batch_size, )
+    em.reset()
+    output1 = (torch.rand(4, 1), torch.randint(0, 2, size=(4, 1), dtype=torch.long))
+    em.update(output1)
+    output2 = (torch.rand(4, 1), torch.randint(0, 2, size=(4, 1), dtype=torch.long))
+    em.update(output2)
+
+    assert em._predictions.device.type == 'cpu' and em._targets.device.type == 'cpu'
+    assert torch.equal(em._predictions[:4], output1[0][:, 0])
+    assert torch.equal(em._predictions[4:], output2[0][:, 0])
+    assert torch.equal(em._targets[:4], output1[1][:, 0])
+    assert torch.equal(em._targets[4:], output2[1][:, 0])
+    assert em.compute() == 0.0
+
 
 def test_mse_epoch_metric():
 
diff --git a/tests/ignite/metrics/test_loss.py b/tests/ignite/metrics/test_loss.py
--- a/tests/ignite/metrics/test_loss.py
+++ b/tests/ignite/metrics/test_loss.py
@@ -46,7 +46,7 @@ def test_non_averaging_loss():
 
     y_pred = torch.Tensor([[0.1, 0.4, 0.5], [0.1, 0.7, 0.2]]).log()
     y = torch.LongTensor([2, 2])
-    with pytest.raises(AssertionError):
+    with pytest.raises(ValueError):
         loss.update((y_pred, y))