Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement activation registry (closes #17) #23

Merged
merged 3 commits into from
Dec 29, 2023
Merged

Conversation

daniil-berg
Copy link
Collaborator

@daniil-berg daniil-berg commented Dec 29, 2023

As described in #17, this adds the ability for the user to register his own activation functions and have them (de-)serialized properly.

The interface is comprised of two associated functions for the Activation struct:

  • register takes a name, a pointer to the actual activation function and a pointer to the derivative function (just like the new constructor), creates a new Activation with those and inserts it into the registry. If an instance with the same name was already present, it is replaced and the old one is returned (wrapped in Some(...)). Otherwise None is returned.

    tensorevo/src/activation.rs

    Lines 108 to 113 in 4895317

    pub fn register<S: Into<String>>(name: S, function: TFunc<T>, derivative: TFunc<T>) -> Option<Self> {
    let name: String = name.into();
    let registry_lock = Self::get_activation_registry();
    registry_lock.write().unwrap()
    .insert(name.clone(), Activation::new(name, function, derivative))
    }
  • from_name now returns a clone of the Activation instance registered under the provided name (wrapped in Some(...)). If none was registered under that name, None is returned. Since from_name used to return an Activation proper, this is technically a breaking change.

    tensorevo/src/activation.rs

    Lines 131 to 136 in 4895317

    pub fn from_name<S: Into<String>>(name: S) -> Option<Self> {
    let registry_lock = Self::get_activation_registry();
    registry_lock.read().unwrap()
    .get(&name.into())
    .and_then(|activation| Some(activation.clone()))
    }

The implementation relies on the generic_singleton::get_or_init macro and the registry (for a specific type Activation<T>) is a static singleton. The ActivationRegistry<T> is simply a type alias for HashMap<String, Activation<T>>.

fn get_activation_registry() -> &'static RwLock<ActivationRegistry<T>> {
get_or_init!(|| {
let registry_lock = RwLock::new(ActivationRegistry::<T>::new());
Self::register_common(&registry_lock);
registry_lock
})
}

During initialization of the registry singleton, the pre-implemented common activation functions (currently only sigmoid and relu) are added automatically. Those are then available by default, but can be replaced by custom implementations via register at any point.

fn register_common(registry_lock: &RwLock<ActivationRegistry<T>>) {
let mut registry = registry_lock.write().unwrap();
let _ = registry.insert(
"sigmoid".to_owned(),
Self::new("sigmoid".to_owned(), sigmoid, sigmoid_prime),
);
let _ = registry.insert(
"relu".to_owned(),
Self::new("relu".to_owned(), relu, relu_prime),
);
}

There is still a lot of unwrapping going on there with the RwLock, but since we have not cleaned that up anywhere else in the code yet, I did not bother to handle potential errors more cleanly yet.

- Use `generic_singleton` crate
- Implement registration and retrieval as associated functions
- Use a separate `impl` block for `Activation` with a `'static` bound
- Register `relu` and `sigmoid` automatically by default
- Add `'static` trait bound to `TensorSerde`
@daniil-berg daniil-berg added enhancement New feature or request breaking change Backwards incompatible interface changes labels Dec 29, 2023
@mfajnberg mfajnberg merged commit d518d04 into master Dec 29, 2023
1 check passed
@daniil-berg daniil-berg deleted the activation-registry branch January 11, 2024 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change Backwards incompatible interface changes enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants