Skip to content

Commit d7c3758

Browse files
thomasjpfanogrisel
authored andcommitted
[MRG] BUG Clips log_loss calculation in neural_network (scikit-learn#16117)
1 parent 999f288 commit d7c3758

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

doc/whats_new/v0.23.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ Changelog
145145
:pr:`16076` by :user:`Guillaume Lemaitre <glemaitre>` and
146146
:user:`Alex Shacked <alexshacked>`.
147147

148+
:mod:`sklearn.neural_network`
149+
.............................
150+
151+
- |Fix| Increases the numerical stability of the logistic loss function in
152+
:class:`neural_network.MLPClassifier` by clipping the probabilities.
153+
:pr:`16117` by `Thomas Fan`_.
154+
148155
:mod:`sklearn.preprocessing`
149156
............................
150157

sklearn/neural_network/_base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ def log_loss(y_true, y_prob):
212212
loss : float
213213
The degree to which the samples are correctly predicted.
214214
"""
215+
eps = np.finfo(y_prob.dtype).eps
216+
y_prob = np.clip(y_prob, eps, 1 - eps)
215217
if y_prob.shape[1] == 1:
216218
y_prob = np.append(1 - y_prob, y_prob, axis=1)
217219

@@ -232,7 +234,7 @@ def binary_log_loss(y_true, y_prob):
232234
y_true : array-like or label indicator matrix
233235
Ground truth (correct) labels.
234236
235-
y_prob : array-like of float, shape = (n_samples, n_classes)
237+
y_prob : array-like of float, shape = (n_samples, 1)
236238
Predicted probabilities, as returned by a classifier's
237239
predict_proba method.
238240
@@ -241,6 +243,8 @@ def binary_log_loss(y_true, y_prob):
241243
loss : float
242244
The degree to which the samples are correctly predicted.
243245
"""
246+
eps = np.finfo(y_prob.dtype).eps
247+
y_prob = np.clip(y_prob, eps, 1 - eps)
244248
return -(xlogy(y_true, y_prob) +
245249
xlogy(1 - y_true, 1 - y_prob)).sum() / y_prob.shape[0]
246250

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
import numpy as np
3+
4+
from sklearn.neural_network._base import binary_log_loss
5+
from sklearn.neural_network._base import log_loss
6+
7+
8+
def test_binary_log_loss_1_prob_finite():
9+
# y_proba is equal to one should result in a finite logloss
10+
y_true = np.array([[0, 0, 1]]).T
11+
y_prob = np.array([[0.9, 1.0, 1.0]]).T
12+
13+
loss = binary_log_loss(y_true, y_prob)
14+
assert np.isfinite(loss)
15+
16+
17+
@pytest.mark.parametrize("y_true, y_prob", [
18+
(np.array([[1, 0, 0], [0, 1, 0]]),
19+
np.array([[0., 1., 0.], [0.9, 0.05, 0.05]])),
20+
(np.array([[0, 0, 1]]).T,
21+
np.array([[0.9, 1.0, 1.0]]).T),
22+
])
23+
def test_log_loss_1_prob_finite(y_true, y_prob):
24+
# y_proba is equal to 1 should result in a finite logloss
25+
loss = log_loss(y_true, y_prob)
26+
assert np.isfinite(loss)

0 commit comments

Comments
 (0)