Skip to main content

r2l_core/
models.rs

1use std::{fmt, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{error::Result, tensor::R2lTensor};
6
7/// Activation function used between hidden layers in feed-forward networks.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
9pub enum ActivationFunction {
10    /// Exponential linear unit activation with the backend default alpha.
11    Elu,
12    /// Gaussian error linear unit activation.
13    Gelu,
14    /// Gaussian error linear unit activation using the backend tanh approximation.
15    GeluApproximate,
16    /// Hard sigmoid activation with backend default parameters.
17    HardSigmoid,
18    /// Hard swish activation.
19    HardSwish,
20    /// Leaky rectified linear unit activation with the backend default slope.
21    LeakyRelu,
22    /// Rectified linear unit activation.
23    Relu,
24    /// Sigmoid activation.
25    Sigmoid,
26    /// Hyperbolic tangent activation.
27    #[default]
28    Tanh,
29}
30
31impl fmt::Display for ActivationFunction {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        let name = match self {
34            Self::Elu => "elu",
35            Self::Gelu => "gelu",
36            Self::GeluApproximate => "gelu_approximate",
37            Self::HardSigmoid => "hard_sigmoid",
38            Self::HardSwish => "hard_swish",
39            Self::LeakyRelu => "leaky_relu",
40            Self::Relu => "relu",
41            Self::Sigmoid => "sigmoid",
42            Self::Tanh => "tanh",
43        };
44        f.write_str(name)
45    }
46}
47
48impl FromStr for ActivationFunction {
49    type Err = String;
50
51    fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
52        match name {
53            "elu" => Ok(Self::Elu),
54            "gelu" => Ok(Self::Gelu),
55            "gelu_approximate" => Ok(Self::GeluApproximate),
56            "hard_sigmoid" => Ok(Self::HardSigmoid),
57            "hard_swish" => Ok(Self::HardSwish),
58            "leaky_relu" => Ok(Self::LeakyRelu),
59            "relu" => Ok(Self::Relu),
60            "sigmoid" => Ok(Self::Sigmoid),
61            "tanh" => Ok(Self::Tanh),
62            _ => Err(format!("unknown activation function: {name}")),
63        }
64    }
65}
66
67/// A policy-like object that can choose an action for one observation.
68///
69/// Actors are the inference-time surface used by samplers. They must be
70/// sendable so rollout collection can move them into worker threads.
71pub trait Actor: Send + 'static {
72    /// Tensor type accepted as observations and returned as actions.
73    type Tensor: R2lTensor;
74
75    /// Selects an action for a single observation.
76    ///
77    /// # Errors
78    ///
79    /// Returns an error if action inference fails.
80    fn action(&self, observation: Self::Tensor) -> Result<Self::Tensor>;
81
82    /// Selects the modal action for a single observation without sampling.
83    ///
84    /// # Errors
85    ///
86    /// Returns an error if action inference fails.
87    fn mode_action(&self, observation: Self::Tensor) -> Result<Self::Tensor>;
88}
89
90/// A policy that can be serialized as a safetensors artifact.
91pub trait ToSafetensors {
92    /// Serializes this policy as safetensors bytes.
93    ///
94    /// # Errors
95    ///
96    /// Returns an error if the policy parameters cannot be serialized.
97    fn to_safetensors(&self) -> Result<Vec<u8>>;
98}
99
100/// Trainable action distribution interface used by on-policy algorithms.
101///
102/// A `Policy` extends [`Actor`] with the quantities needed to compute policy
103/// gradient losses and entropy bonuses over a batch.
104pub trait Policy: Actor {
105    /// Computes log probabilities for batched observation/action pairs.
106    ///
107    /// # Errors
108    ///
109    /// Returns an error if the policy cannot evaluate the batch.
110    fn log_probs(
111        &self,
112        observations: &[Self::Tensor],
113        actions: &[Self::Tensor],
114    ) -> Result<Self::Tensor>;
115
116    /// Returns a representative action standard deviation when available.
117    ///
118    /// # Errors
119    ///
120    /// Returns an error if the standard deviation cannot be computed.
121    /// Returns `Ok(None)` when the policy has no meaningful scalar standard deviation.
122    fn std(&self) -> Result<Option<f32>>;
123
124    /// Computes the policy entropy for a batch of states.
125    ///
126    /// # Errors
127    ///
128    /// Returns an error if the entropy cannot be computed.
129    fn entropy(&self, states: &[Self::Tensor]) -> Result<Self::Tensor>;
130}
131
132/// Component that learns from backend-specific loss values.
133pub trait Learner {
134    /// Loss bundle consumed by this module.
135    type Losses;
136
137    /// Applies one optimization update from precomputed losses.
138    ///
139    /// # Errors
140    ///
141    /// Returns an error if the optimizer update fails.
142    fn update(&mut self, losses: Self::Losses) -> Result<()>;
143}
144
145/// Batched value-function interface.
146pub trait ValueFunction {
147    /// Tensor type used for observations and returned values.
148    type Tensor: Clone;
149
150    /// Estimates values for a batch of observations.
151    ///
152    /// # Errors
153    ///
154    /// Returns an error if value inference fails.
155    fn values(&self, observations: &[Self::Tensor]) -> Result<Self::Tensor>;
156}