braintools 0.0.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. braintools/__init__.py +27 -0
  2. braintools/functional/__init__.py +25 -0
  3. braintools/functional/_activations.py +733 -0
  4. braintools/functional/_normalization.py +62 -0
  5. braintools/functional/_spikes.py +90 -0
  6. braintools/init/__init__.py +26 -0
  7. braintools/init/_base.py +36 -0
  8. braintools/init/_generic.py +205 -0
  9. braintools/init/_random_inits.py +489 -0
  10. braintools/init/_regular_inits.py +109 -0
  11. braintools/input/__init__.py +27 -0
  12. braintools/input/currents.py +380 -0
  13. braintools/input/currents_test.py +111 -0
  14. braintools/metric/__init__.py +46 -0
  15. braintools/metric/_classification.py +569 -0
  16. braintools/metric/_classification_test.py +625 -0
  17. braintools/metric/_correlation.py +302 -0
  18. braintools/metric/_correlation_test.py +124 -0
  19. braintools/metric/_fenchel_young.py +67 -0
  20. braintools/metric/_fenchel_young_test.py +55 -0
  21. braintools/metric/_firings.py +85 -0
  22. braintools/metric/_firings_test.py +41 -0
  23. braintools/metric/_lfp.py +139 -0
  24. braintools/metric/_ranking.py +163 -0
  25. braintools/metric/_ranking_test.py +242 -0
  26. braintools/metric/_regression.py +425 -0
  27. braintools/metric/_regression_test.py +133 -0
  28. braintools/metric/_smoothing.py +46 -0
  29. braintools/metric/_smoothing_test.py +43 -0
  30. braintools/metric/_util.py +25 -0
  31. braintools/optim/__init__.py +23 -0
  32. braintools/optim/_lr_scheduler.py +482 -0
  33. braintools/optim/_sgd_optimizer.py +1130 -0
  34. braintools-0.0.2.dist-info/LICENSE +202 -0
  35. braintools-0.0.2.dist-info/METADATA +93 -0
  36. braintools-0.0.2.dist-info/RECORD +38 -0
  37. braintools-0.0.2.dist-info/WHEEL +6 -0
  38. braintools-0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,569 @@
1
+ # This file is modified from [optax/losses](https://github.com/google-deepmind/optax).
2
+ # The copyright notice is as follows:
3
+ #
4
+ # Copyright 2024 BrainPy Ecosystem Limited. All Rights Reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ==============================================================================
18
+
19
+ """
20
+ Classification losses.
21
+ """
22
+
23
+ from typing import Optional
24
+
25
+ import braincore as bc
26
+ import jax
27
+ import jax.numpy as jnp
28
+
29
+ __all__ = [
30
+ 'sigmoid_binary_cross_entropy',
31
+ 'hinge_loss',
32
+ 'perceptron_loss',
33
+ 'softmax_cross_entropy',
34
+ 'softmax_cross_entropy_with_integer_labels',
35
+ 'multiclass_hinge_loss',
36
+ 'multiclass_perceptron_loss',
37
+ 'poly_loss_cross_entropy',
38
+ 'kl_divergence',
39
+ 'kl_divergence_with_log_targets',
40
+ 'convex_kl_divergence',
41
+ 'ctc_loss',
42
+ 'ctc_loss_with_forward_probs',
43
+ 'sigmoid_focal_loss',
44
+ ]
45
+
46
+
47
+ def assert_is_float(array):
48
+ assert bc.math.is_float(array), 'Array must be float.'
49
+
50
+
51
+ def assert_is_int(array):
52
+ assert bc.math.is_int(array), 'Array must be int.'
53
+
54
+
55
+ def sigmoid_binary_cross_entropy(
56
+ logits: bc.typing.ArrayLike,
57
+ labels: bc.typing.ArrayLike,
58
+ ):
59
+ """Computes element-wise sigmoid cross entropy given logits and labels.
60
+
61
+ This function can be used for binary or multiclass classification (where each
62
+ class is an independent binary prediction and different classes are not
63
+ mutually exclusive e.g. predicting that an image contains both a cat
64
+ and a dog.)
65
+
66
+ Because this function is overloaded, please ensure your `logits` and `labels`
67
+ are compatible with each other. If you're passing in binary `labels` (values
68
+ in {0, 1}), ensure your `logits` correspond to class 1 only. If you're
69
+ passing in per-class target probabilities or one-hot `labels`, please ensure
70
+ your `logits` are also multiclass. Be particularly careful if you're relying
71
+ on implicit broadcasting to reshape `logits` or `labels`.
72
+
73
+ References:
74
+ [Goodfellow et al, 2016](http://www.deeplearningbook.org/contents/prob.html)
75
+
76
+ Args:
77
+ logits: Each element is the unnormalized log probability of a binary
78
+ prediction. See note about compatibility with `labels` above.
79
+ labels: Binary labels whose values are {0,1} or multi-class target
80
+ probabilities. See note about compatibility with `logits` above.
81
+
82
+ Returns:
83
+ cross entropy for each binary prediction, same shape as `logits`.
84
+ """
85
+ labels = labels.astype(logits.dtype)
86
+ log_p = jax.nn.log_sigmoid(logits)
87
+ log_not_p = jax.nn.log_sigmoid(-logits)
88
+ return -labels * log_p - (1. - labels) * log_not_p
89
+
90
+
91
+ def hinge_loss(
92
+ predictor_outputs: bc.typing.ArrayLike,
93
+ targets: bc.typing.ArrayLike
94
+ ) -> bc.typing.ArrayLike:
95
+ """Computes the hinge loss for binary classification.
96
+
97
+ Args:
98
+ predictor_outputs: Outputs of the decision function.
99
+ targets: Target values. Target values should be strictly in the set {-1, 1}.
100
+
101
+ Returns:
102
+ loss value.
103
+ """
104
+ return jnp.maximum(0, 1 - predictor_outputs * targets)
105
+
106
+
107
+ def perceptron_loss(
108
+ predictor_outputs: bc.typing.ArrayLike,
109
+ targets: bc.typing.ArrayLike
110
+ ) -> bc.typing.ArrayLike:
111
+ """Binary perceptron loss.
112
+
113
+ References:
114
+ https://en.wikipedia.org/wiki/Perceptron
115
+
116
+ Args:
117
+ predictor_outputs: score produced by the model (float).
118
+ targets: Target values. Target values should be strictly in the set {-1, 1}.
119
+
120
+ Returns:
121
+ loss value.
122
+ """
123
+ assert jnp.shape(predictor_outputs) == jnp.shape(targets), 'shape mismatch'
124
+ return jnp.maximum(0, - predictor_outputs * targets)
125
+
126
+
127
+ def softmax_cross_entropy(
128
+ logits: bc.typing.ArrayLike,
129
+ labels: bc.typing.ArrayLike,
130
+ ) -> bc.typing.ArrayLike:
131
+ """Computes the softmax cross entropy between sets of logits and labels.
132
+
133
+ Measures the probability error in discrete classification tasks in which
134
+ the classes are mutually exclusive (each entry is in exactly one class).
135
+ For example, each CIFAR-10 image is labeled with one and only one label:
136
+ an image can be a dog or a truck, but not both.
137
+
138
+ References:
139
+ [Goodfellow et al, 2016](http://www.deeplearningbook.org/contents/prob.html)
140
+
141
+ Args:
142
+ logits: Unnormalized log probabilities, with shape `[..., num_classes]`.
143
+ labels: Valid probability distributions (non-negative, sum to 1), e.g a
144
+ one hot encoding specifying the correct class for each input;
145
+ must have a shape broadcastable to `[..., num_classes]`.
146
+
147
+ Returns:
148
+ cross entropy between each prediction and the corresponding target
149
+ distributions, with shape `[...]`.
150
+ """
151
+ ret = -jnp.sum(labels * jax.nn.log_softmax(logits, axis=-1), axis=-1)
152
+ return ret
153
+
154
+
155
+ def softmax_cross_entropy_with_integer_labels(
156
+ logits: bc.typing.ArrayLike,
157
+ labels: bc.typing.ArrayLike,
158
+ ) -> bc.typing.ArrayLike:
159
+ """Computes softmax cross entropy between sets of logits and integer labels.
160
+
161
+ Measures the probability error in discrete classification tasks in which
162
+ the classes are mutually exclusive (each entry is in exactly one class).
163
+ For example, each CIFAR-10 image is labeled with one and only one label:
164
+ an image can be a dog or a truck, but not both.
165
+
166
+ References:
167
+ [Goodfellow et al, 2016](http://www.deeplearningbook.org/contents/prob.html)
168
+
169
+ Args:
170
+ logits: Unnormalized log probabilities, with shape `[..., num_classes]`.
171
+ labels: Integers specifying the correct class for each input, with shape
172
+ `[...]`.
173
+
174
+ Returns:
175
+ Cross entropy between each prediction and the corresponding target
176
+ distributions, with shape `[...]`.
177
+ """
178
+ assert_is_float(logits)
179
+ assert_is_int(labels)
180
+ # This is like jnp.take_along_axis(jax.nn.log_softmax(...), ...) except that
181
+ # we avoid subtracting the normalizer from all values, just from the values
182
+ # for the correct labels.
183
+ logits_max = jnp.max(logits, axis=-1, keepdims=True)
184
+ logits -= jax.lax.stop_gradient(logits_max)
185
+ label_logits = jnp.take_along_axis(logits, labels[..., None], axis=-1)[..., 0]
186
+ log_normalizers = jnp.log(jnp.sum(jnp.exp(logits), axis=-1))
187
+ return log_normalizers - label_logits
188
+
189
+
190
+ _dot_last_dim = jnp.vectorize(jnp.dot, signature='(n),(n)->()')
191
+
192
+
193
+ def multiclass_hinge_loss(
194
+ scores: bc.typing.ArrayLike,
195
+ labels: bc.typing.ArrayLike,
196
+ ) -> bc.typing.ArrayLike:
197
+ """Multiclass hinge loss.
198
+
199
+ Args:
200
+ scores: scores produced by the model (floats).
201
+ labels: ground-truth integer label.
202
+
203
+ Returns:
204
+ loss value
205
+
206
+ References:
207
+ https://en.wikipedia.org/wiki/Hinge_loss
208
+
209
+ """
210
+ one_hot_labels = jax.nn.one_hot(labels, scores.shape[-1])
211
+ return (jnp.max(scores + 1.0 - one_hot_labels, axis=-1) -
212
+ _dot_last_dim(scores, one_hot_labels))
213
+
214
+
215
+ def multiclass_perceptron_loss(
216
+ scores: bc.typing.ArrayLike,
217
+ labels: bc.typing.ArrayLike,
218
+ ) -> bc.typing.ArrayLike:
219
+ """Binary perceptron loss.
220
+
221
+ References:
222
+ Michael Collins. Discriminative training methods for Hidden Markov Models:
223
+ Theory and experiments with perceptron algorithms. EMNLP 2002
224
+
225
+ Args:
226
+ scores: score produced by the model.
227
+ labels: ground-truth integer label.
228
+
229
+ Returns:
230
+ loss value.
231
+ """
232
+ one_hot_labels = jax.nn.one_hot(labels, scores.shape[-1])
233
+ return jnp.max(scores, axis=-1) - _dot_last_dim(scores, one_hot_labels)
234
+
235
+
236
+ def poly_loss_cross_entropy(
237
+ logits: bc.typing.ArrayLike,
238
+ labels: bc.typing.ArrayLike,
239
+ epsilon: float = 2.0
240
+ ) -> bc.typing.ArrayLike:
241
+ r"""
242
+ Computes PolyLoss between logits and labels.
243
+
244
+ The PolyLoss is a loss function that decomposes commonly
245
+ used classification loss functions into a series of weighted
246
+ polynomial bases. It is inspired by the Taylor expansion of
247
+ cross-entropy loss and focal loss in the bases of :math:`(1 − P_t)^j`.
248
+
249
+ .. math::
250
+ L_{Poly} = \sum_1^\infty \alpha_j \cdot (1 - P_t)^j \\
251
+ L_{Poly-N} = (\epsilon_1 + 1) \cdot (1 - P_t) + \ldots + \\
252
+ (\epsilon_N + \frac{1}{N}) \cdot (1 - P_t)^N +
253
+ \frac{1}{N + 1} \cdot (1 - P_t)^{N + 1} + \ldots = \\
254
+ - \log(P_t) + \sum_{j = 1}^N \epsilon_j \cdot (1 - P_t)^j
255
+
256
+ This function provides a simplified version of :math:`L_{Poly-N}`
257
+ with only the coefficient of the first polynomial term being changed.
258
+
259
+ References:
260
+ [Zhaoqi Leng et al, 2022](https://arxiv.org/pdf/2204.12511.pdf)
261
+
262
+ Args:
263
+ logits: Unnormalized log probabilities, with shape `[..., num_classes]`.
264
+ labels: Valid probability distributions (non-negative, sum to 1), e.g. a
265
+ one hot encoding specifying the correct class for each input;
266
+ must have a shape broadcastable to `[..., num_classes]`.
267
+ epsilon: The coefficient of the first polynomial term.
268
+ According to the paper, the following values are recommended:
269
+ - For the ImageNet 2d image classification, epsilon = 2.0.
270
+ - For the 2d Instance Segmentation and object detection, epsilon = -1.0.
271
+ - It is also recommended to adjust this value based on the task, e.g. by
272
+ using grid search.
273
+
274
+ Returns:
275
+ Poly loss between each prediction and the corresponding target
276
+ distributions, with shape `[...]`.
277
+ """
278
+ one_minus_pt = jnp.sum(labels * (1 - jax.nn.softmax(logits)), axis=-1)
279
+ cross_entropy = softmax_cross_entropy(logits=logits, labels=labels)
280
+ return cross_entropy + epsilon * one_minus_pt
281
+
282
+
283
+ def kl_divergence(
284
+ log_predictions: bc.typing.ArrayLike,
285
+ targets: bc.typing.ArrayLike
286
+ ) -> bc.typing.ArrayLike:
287
+ """Computes the Kullback-Leibler divergence (relative entropy) loss.
288
+
289
+ Measures the information gain achieved if target probability distribution
290
+ would be used instead of predicted probability distribution.
291
+
292
+ References:
293
+ [Kullback, Leibler, 1951](https://www.jstor.org/stable/2236703)
294
+
295
+ Args:
296
+ log_predictions: Probabilities of predicted distribution with shape [...,
297
+ dim]. Expected to be in the log-space to avoid underflow.
298
+ targets: Probabilities of target distribution with shape [..., dim].
299
+ Expected to be strictly positive.
300
+
301
+ Returns:
302
+ Kullback-Leibler divergence of predicted distribution from target
303
+ distribution with shape [...].
304
+ """
305
+ assert_is_float(log_predictions)
306
+ assert_is_float(targets)
307
+ loss = targets * (jnp.where(targets == 0, 0, jnp.log(targets)) - log_predictions)
308
+ return jnp.sum(loss, axis=-1)
309
+
310
+
311
+ def kl_divergence_with_log_targets(
312
+ log_predictions: bc.typing.ArrayLike,
313
+ log_targets: bc.typing.ArrayLike
314
+ ) -> bc.typing.ArrayLike:
315
+ """Computes the Kullback-Leibler divergence (relative entropy) loss.
316
+
317
+ Version of kl_div_loss where targets are given in log-space.
318
+
319
+ Args:
320
+ log_predictions: Probabilities of predicted distribution with shape
321
+ [..., dim]. Expected to be in the log-space to avoid underflow.
322
+ log_targets: Probabilities of target distribution with shape [..., dim].
323
+ Expected to be in the log-space.
324
+
325
+ Returns:
326
+ Kullback-Leibler divergence of predicted distribution from target
327
+ distribution with shape [...].
328
+ """
329
+ assert_is_float(log_predictions)
330
+ assert_is_float(log_targets)
331
+ loss = jnp.exp(log_targets) * (log_targets - log_predictions)
332
+ return jnp.sum(loss, axis=-1)
333
+
334
+
335
+ def convex_kl_divergence(
336
+ log_predictions: bc.typing.ArrayLike,
337
+ targets: bc.typing.ArrayLike
338
+ ) -> bc.typing.ArrayLike:
339
+ """Computes a convex version of the Kullback-Leibler divergence loss.
340
+
341
+ Measures the information gain achieved if target probability distribution
342
+ would be used instead of predicted probability distribution.
343
+ This version is jointly convex in p (targets) and q (log_predictions).
344
+
345
+ References:
346
+ [Kullback, Leibler, 1951](https://www.jstor.org/stable/2236703)
347
+
348
+ Args:
349
+ log_predictions: Probabilities of predicted distribution with shape [...,
350
+ dim]. Expected to be in the log-space to avoid underflow.
351
+ targets: Probabilities of target distribution with shape [..., dim].
352
+ Expected to be strictly positive.
353
+
354
+ Returns:
355
+ Kullback-Leibler divergence of predicted distribution from target
356
+ distribution with shape [...].
357
+ """
358
+ return kl_divergence(log_predictions, targets) + jnp.sum(jnp.exp(log_predictions) - targets, axis=-1)
359
+
360
+
361
+ def ctc_loss_with_forward_probs(
362
+ logits: bc.typing.ArrayLike,
363
+ logit_paddings: bc.typing.ArrayLike,
364
+ labels: bc.typing.ArrayLike,
365
+ label_paddings: bc.typing.ArrayLike,
366
+ blank_id: int = 0,
367
+ log_epsilon: float = -1e5
368
+ ) -> tuple[bc.typing.ArrayLike, bc.typing.ArrayLike, bc.typing.ArrayLike]:
369
+ r"""Computes CTC loss and CTC forward-probabilities.
370
+
371
+ The CTC loss is a loss function based on log-likelihoods of the model that
372
+ introduces a special blank symbol :math:`\phi` to represent variable-length
373
+ output sequences.
374
+
375
+ Forward probabilities returned by this function, as auxiliary results, are
376
+ grouped into two part: blank alpha-probability and non-blank alpha
377
+ probability. Those are defined as follows:
378
+
379
+ .. math::
380
+ \alpha_{\mathrm{BLANK}}(t, n) =
381
+ \sum_{\pi_{1:t-1}} p(\pi_t = \phi | \pi_{1:t-1}, y_{1:n-1}, \cdots), \\
382
+ \alpha_{\mathrm{LABEL}}(t, n) =
383
+ \sum_{\pi_{1:t-1}} p(\pi_t = y_n | \pi_{1:t-1}, y_{1:n-1}, \cdots).
384
+
385
+ Here, :math:`\pi` denotes the alignment sequence in the reference
386
+ [Graves et al, 2006] that is blank-inserted representations of ``labels``.
387
+ The return values are the logarithms of the above probabilities.
388
+
389
+ References:
390
+ [Graves et al, 2006](https://dl.acm.org/doi/abs/10.1145/1143844.1143891)
391
+
392
+ Args:
393
+ logits: (B, T, K)-array containing logits of each class where B denotes
394
+ the batch size, T denotes the max time frames in ``logits``, and K
395
+ denotes the number of classes including a class for blanks.
396
+ logit_paddings: (B, T)-array. Padding indicators for ``logits``. Each
397
+ element must be either 1.0 or 0.0, and ``logitpaddings[b, t] == 1.0``
398
+ denotes that ``logits[b, t, :]`` are padded values.
399
+ labels: (B, N)-array containing reference integer labels where N denotes
400
+ the max time frames in the label sequence.
401
+ label_paddings: (B, N)-array. Padding indicators for ``labels``. Each
402
+ element must be either 1.0 or 0.0, and ``labelpaddings[b, n] == 1.0``
403
+ denotes that ``labels[b, n]`` is a padded label. In the current
404
+ implementation, ``labels`` must be right-padded, i.e. each row
405
+ ``labelpaddings[b, :]`` must be repetition of zeroes, followed by
406
+ repetition of ones.
407
+ blank_id: Id for blank token. ``logits[b, :, blank_id]`` are used as
408
+ probabilities of blank symbols.
409
+ log_epsilon: Numerically-stable approximation of log(+0).
410
+
411
+ Returns:
412
+ A tuple ``(loss_value, logalpha_blank, logalpha_nonblank)``. Here,
413
+ ``loss_value`` is a (B,)-array containing the loss values for each sequence
414
+ in the batch, ``logalpha_blank`` and ``logalpha_nonblank`` are
415
+ (T, B, N+1)-arrays where the (t, b, n)-th element denotes
416
+ \log \alpha_B(t, n) and \log \alpha_L(t, n), respectively, for ``b``-th
417
+ sequence in the batch.
418
+ """
419
+ assert logits.ndim == 3, 'logits must have shape (B, T, K)'
420
+ assert labels.ndim == 2, 'labels must have shape (B, N)'
421
+ batchsize, unused_maxinputlen, num_classes = logits.shape
422
+ batchsize_of_labels, maxlabellen = labels.shape
423
+ assert batchsize == batchsize_of_labels, 'batchsize mismatch'
424
+ assert label_paddings.shape == labels.shape, 'padding shape mismatch'
425
+ assert logits.shape[:2] == logit_paddings.shape, 'padding shape mismatch'
426
+
427
+ logprobs = jax.nn.log_softmax(logits)
428
+ labellens = maxlabellen - jnp.sum(label_paddings, axis=1).astype(jnp.int32)
429
+
430
+ # repeat[b, n] == 1.0 when label[b, n] == label[b, n+1].
431
+ repeat = (labels[:, :-1] == labels[:, 1:]).astype(jnp.float32)
432
+ repeat = jnp.pad(repeat, ((0, 0), (0, 1)))
433
+
434
+ logprobs_phi = logprobs[:, :, blank_id:blank_id + 1] # [B, T, 1]
435
+ logprobs_phi = jnp.transpose(logprobs_phi, (1, 0, 2)) # [T, B, 1]
436
+
437
+ one_hot = jax.nn.one_hot(labels, num_classes=num_classes) # [B, N, K]
438
+ logprobs_emit = jnp.einsum('btk,bnk->btn', logprobs, one_hot)
439
+ logprobs_emit = jnp.transpose(logprobs_emit, (1, 0, 2)) # [T, B, N]
440
+
441
+ logalpha_phi_init = jnp.ones((batchsize, maxlabellen + 1)) * log_epsilon # [B, N]
442
+ logalpha_phi_init = logalpha_phi_init.at[:, 0].set(0.0)
443
+ logalpha_emit_init = jnp.ones((batchsize, maxlabellen)) * log_epsilon
444
+
445
+ def update_phi_score(phi, added_score):
446
+ # Update `phi[:, 1:]`` with adding `added_score` in log space.
447
+ return jnp.concatenate([phi[:, :1], jnp.logaddexp(phi[:, 1:], added_score)], axis=-1)
448
+
449
+ def loop_body(prev, x):
450
+ prev_phi, prev_emit = prev
451
+ # emit-to-phi epsilon transition, except if the next label is repetition
452
+ prev_phi_orig = prev_phi
453
+ prev_phi = update_phi_score(prev_phi, prev_emit + log_epsilon * repeat)
454
+
455
+ logprob_emit, logprob_phi, pad = x
456
+
457
+ # phi-to-emit transition
458
+ next_emit = jnp.logaddexp(prev_phi[:, :-1] + logprob_emit,
459
+ prev_emit + logprob_emit)
460
+ # self-loop transition
461
+ next_phi = prev_phi + logprob_phi
462
+ # emit-to-phi blank transition only when the next label is repetition
463
+ next_phi = update_phi_score(
464
+ next_phi, prev_emit + logprob_phi + log_epsilon * (1.0 - repeat))
465
+
466
+ pad = pad.reshape((batchsize, 1))
467
+ next_emit = pad * prev_emit + (1.0 - pad) * next_emit
468
+ next_phi = pad * prev_phi_orig + (1.0 - pad) * next_phi
469
+
470
+ return (next_phi, next_emit), (next_phi, next_emit)
471
+
472
+ xs = (logprobs_emit, logprobs_phi, logit_paddings.transpose((1, 0)))
473
+ _, (logalpha_phi, logalpha_emit) = jax.lax.scan(loop_body, (logalpha_phi_init, logalpha_emit_init), xs)
474
+
475
+ # last row needs to be updated with the last epsilon transition
476
+ logalpha_phi_last = update_phi_score(logalpha_phi[-1], logalpha_emit[-1])
477
+ logalpha_phi = logalpha_phi.at[-1].set(logalpha_phi_last)
478
+
479
+ # extract per_seq_loss
480
+ one_hot = jax.nn.one_hot(labellens, num_classes=maxlabellen + 1) # [B, N+1]
481
+ per_seq_loss = -jnp.einsum('bn,bn->b', logalpha_phi_last, one_hot) # pylint:disable=invalid-unary-operand-type
482
+
483
+ return per_seq_loss, logalpha_phi, logalpha_emit
484
+
485
+
486
+ def ctc_loss(
487
+ logits: bc.typing.ArrayLike,
488
+ logit_paddings: bc.typing.ArrayLike,
489
+ labels: bc.typing.ArrayLike,
490
+ label_paddings: bc.typing.ArrayLike,
491
+ blank_id: int = 0,
492
+ log_epsilon: float = -1e5
493
+ ) -> bc.typing.ArrayLike:
494
+ """Computes CTC loss.
495
+
496
+ See docstring for ``ctc_loss_with_forward_probs`` for details.
497
+
498
+ Args:
499
+ logits: (B, T, K)-array containing logits of each class where B denotes
500
+ the batch size, T denotes the max time frames in ``logits``, and K
501
+ denotes the number of classes including a class for blanks.
502
+ logit_paddings: (B, T)-array. Padding indicators for ``logits``. Each
503
+ element must be either 1.0 or 0.0, and ``logitpaddings[b, t] == 1.0``
504
+ denotes that ``logits[b, t, :]`` are padded values.
505
+ labels: (B, N)-array containing reference integer labels where N denotes
506
+ the max time frames in the label sequence.
507
+ label_paddings: (B, N)-array. Padding indicators for ``labels``. Each
508
+ element must be either 1.0 or 0.0, and ``labelpaddings[b, n] == 1.0``
509
+ denotes that ``labels[b, n]`` is a padded label. In the current
510
+ implementation, ``labels`` must be right-padded, i.e. each row
511
+ ``labelpaddings[b, :]`` must be repetition of zeroes, followed by
512
+ repetition of ones.
513
+ blank_id: Id for blank token. ``logits[b, :, blank_id]`` are used as
514
+ probabilities of blank symbols.
515
+ log_epsilon: Numerically-stable approximation of log(+0).
516
+
517
+ Returns:
518
+ (B,)-array containing loss values for each sequence in the batch.
519
+ """
520
+ per_seq_loss, _, _ = ctc_loss_with_forward_probs(
521
+ logits, logit_paddings, labels, label_paddings,
522
+ blank_id=blank_id, log_epsilon=log_epsilon
523
+ )
524
+ return per_seq_loss
525
+
526
+
527
+ def sigmoid_focal_loss(
528
+ logits: bc.typing.ArrayLike,
529
+ labels: bc.typing.ArrayLike,
530
+ alpha: Optional[float] = None,
531
+ gamma: float = 2.,
532
+ ) -> bc.typing.ArrayLike:
533
+ """Sigmoid focal loss.
534
+
535
+ The focal loss is a re-weighted cross entropy for unbalanced problems.
536
+ Use this loss function if classes are not mutually exclusive.
537
+ See `sigmoid_binary_cross_entropy` for more information.
538
+
539
+ References:
540
+ Lin et al. 2018. https://arxiv.org/pdf/1708.02002.pdf
541
+
542
+ Args:
543
+ logits: Array of floats. The predictions for each example.
544
+ The predictions for each example.
545
+ labels: Array of floats. Labels and logits must have
546
+ the same shape. The label array must contain the binary
547
+ classification labels for each element in the data set
548
+ (0 for the out-of-class and 1 for in-class).
549
+ alpha: (optional) Weighting factor in range (0,1) to balance
550
+ positive vs negative examples. Default None (no weighting).
551
+ gamma: Exponent of the modulating factor (1 - p_t).
552
+ Balances easy vs hard examples.
553
+
554
+ Returns:
555
+ A loss value array with a shape identical to the logits and target
556
+ arrays.
557
+ """
558
+ alpha = -1 if alpha is None else alpha
559
+ assert_is_float(logits)
560
+ # see also the original paper's implementation at:
561
+ # https://github.com/facebookresearch/fvcore/blob/main/fvcore/nn/focal_loss.py
562
+ p = jax.nn.sigmoid(logits)
563
+ ce_loss = sigmoid_binary_cross_entropy(logits, labels)
564
+ p_t = p * labels + (1 - p) * (1 - labels)
565
+ loss = ce_loss * ((1 - p_t) ** gamma)
566
+ weighted = lambda loss_arg: (alpha * labels + (1 - alpha) * (1 - labels)) * loss_arg
567
+ not_weighted = lambda loss_arg: loss_arg
568
+ loss = jax.lax.cond(alpha >= 0, weighted, not_weighted, loss)
569
+ return loss