tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
classif.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <tinyopt/math.h>
7#include <tinyopt/traits.h>
8
9namespace tinyopt::losses {
10
16template <typename T, typename ExportJ = std::nullptr_t>
17auto Softmax(const T &x, const ExportJ &Jx_or_bool = nullptr) {
18 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>;
19 if constexpr (traits::is_pair_v<T>) { // pair
20 return Softmax(x.first, x.second);
21 } else if constexpr (!IsMatrix) { // scalar
22 if constexpr (std::is_null_pointer_v<ExportJ>)
23 return 1;
24 else if constexpr (traits::is_matrix_or_array_v<ExportJ>)
25 return std::make_pair(1, Jx_or_bool);
26 else
27 return std::make_pair(1, 1);
28 } else { // Matrix
29 using std::exp;
30 using Scalar = typename T::Scalar;
31 constexpr Index Dims = T::RowsAtCompileTime;
32 const auto si = x.array().exp().matrix().eval();
33 const Scalar sum = si.sum();
34 const T out = x.unaryExpr([sum](Scalar v) { return exp(v) / sum; }).eval();
35 if constexpr (std::is_null_pointer_v<ExportJ>) {
36 return out;
37 } else {
38 Matrix<Scalar, Dims, Dims> Jo(x.rows(), x.rows());
39 Jo.setZero();
40 for (int c = 0; c < Jo.cols(); ++c) {
41 for (int r = c; r < Jo.rows(); ++r) {
42 Jo(r, c) = r == c ? out[c] * (1.0 - out[c]) : -out[r] * out[c];
43 }
44 }
45 Jo.template triangularView<Upper>() = Jo.template triangularView<Lower>().transpose();
46 return std::make_pair(out, (Jo * Jx_or_bool).eval());
47 }
48 }
49}
50
52template <typename T, typename ExportJ = std::nullptr_t>
53auto SafeSoftmax(const T &x, const ExportJ &Jx_or_bool = nullptr) {
54 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>;
55 if constexpr (traits::is_pair_v<T>) { // pair
56 return SafeSoftmax(x.first, x.second);
57 } else if constexpr (!IsMatrix) { // scalar
58 if constexpr (std::is_null_pointer_v<ExportJ>)
59 return std::make_pair(1, 1);
60 else if constexpr (traits::is_matrix_or_array_v<ExportJ>)
61 return std::make_pair(1, Jx_or_bool);
62 else
63 return 1;
64 } else { // Matrix
65 using std::exp;
66 using Scalar = typename T::Scalar;
67 constexpr Index Dims = T::RowsAtCompileTime;
68 const Scalar mx = x.maxCoeff();
69 const auto si = (x.array() - mx).exp().matrix().eval();
70 const Scalar sum = si.sum();
71 const T out = x.unaryExpr([mx, sum](Scalar v) { return exp(v - mx) / sum; });
72 if constexpr (std::is_null_pointer_v<ExportJ>) {
73 return out;
74 } else {
75 Matrix<Scalar, Dims, Dims> Jo(x.rows(), x.rows());
76 Jo.setZero();
77 for (int c = 0; c < Jo.cols(); ++c) {
78 for (int r = c; r < Jo.rows(); ++r) {
79 Jo(r, c) = r == c ? out[c] * (1.0 - out[c]) : -out[r] * out[c];
80 }
81 }
82 Jo.template triangularView<Upper>() = Jo.template triangularView<Lower>().transpose();
83 return std::make_pair(out, (Jo * Jx_or_bool).eval());
84 }
85 }
86}
87
89} // namespace tinyopt::losses
Definition activations.h:8
auto Softmax(const T &x, const ExportJ &Jx_or_bool=nullptr)
Softmax = e^xi / sum(e^x), jacobian = {i=j: si(x)*(1-si(x)) , i!=j: -si(x)*sj(x)}.
Definition classif.h:17
auto SafeSoftmax(const T &x, const ExportJ &Jx_or_bool=nullptr)
Safe Softmax = e^(xi-max(xi)) / sum(e^(x-max(xi)).
Definition classif.h:53