use std::marker::PhantomData;
use static_assertions::assert_impl_all;
use crate::{Element, Symbol, Tape, Tensor, Value};
use super::{Module, Visitor};
assert_impl_all!(Embedding<f64>: Send, Sync);
#[derive(Debug, Clone)]
pub struct Embedding<E> {
table: Symbol,
_marker: PhantomData<E>,
}
impl<E: Element> Embedding<E> {
pub fn new(tape: &Tape<E>, table: Tensor<E>) -> Self {
let shape = table.shape();
assert_eq!(
shape.rank(),
2,
"an embedding table must be rank 2 [vocab, dim], got {shape}"
);
Self {
table: tape.parameter(table).symbol(),
_marker: PhantomData,
}
}
pub fn table(&self) -> Symbol {
self.table
}
pub fn parameters(&self) -> impl Iterator<Item = Symbol> + '_ {
super::parameters(self).into_iter()
}
}
impl<E: Element> Module<E> for Embedding<E> {
fn express<'tape>(&self, input: Value<'tape, E>) -> Value<'tape, E> {
let table = input.tape().resolve(self.table);
table.gather(input)
}
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.parameter("weights", self.table);
}
}
#[cfg(test)]
#[path = "tests/embedding_tests.rs"]
mod tests;