Current section

Files

Jump to
bumblebee lib bumblebee huggingface transformers model.ex
Raw

lib/bumblebee/huggingface/transformers/model.ex

defprotocol Bumblebee.HuggingFace.Transformers.Model do
@moduledoc false
# This protocol defines details related to loading Bumblebee model
# from huggingface/transformers model.
@type params_mapping :: %{layer_name() => params_source()}
@type params_source :: layer_name() | list(layer_name()) | param_builders()
@type param_builders :: %{param_name() => param_builder()}
@type param_builder ::
{list(param_source()), (list(Nx.tensor()) -> Nx.Tensor.t() | Nx.Container.t())}
@type param_source :: param_ref() | list(param_ref())
@type param_ref :: {layer_name(), param_name()}
@type layer_name :: String.t()
@type param_name :: String.t()
@doc """
Returns a map describing layers/parameters relationship between an
Axon model and a corresponding huggingface/transformers model.
## Mapping format
The basic mapping format is a map with Axon layer names (target) as
keys and PyTorch layer names (source) as values. For example:
%{
"embedder.token_embedding" => "bert.embeddings.word_embeddings",
...
}
The mapping should always use the longest names, that is, depending on
the architecture, the PyTorch layer name could be either
`"bert.embeddings.word_embeddings"` or `"embeddings.word_embeddings"`.
The longer version should generally be used. Prefixes are removed/added
as necessary, so loading partial models is supported automatically.
The layer names may include simple substitutions, useful for lists
of layers:
%{
"encoder.blocks.{n}.self_attention.query" => "bert.encoder.layer.{n}.attention.self.query",
...
}
Both param names and values for corresponding layers may not match
exactly, so they require further transformations. For example, the
convolution `"kernel"` in Axon corresponds to a transposed `"weight"`
from PyTorch. For most common layers such conversions are handled
automatically.
In some cases, particularly with model-specific layers/parameters,
we may need more control over the parameter mapping. In such cases,
instead of source layer name, a map with parameter-level transformations
may be specified:
%{
"embedder.class_embedding" => %{
"embedding" => {
[{"vit.embeddings", "cls_token"}],
fn [value] -> Nx.squeeze(value, axes: [0, 1]) end
}
},
...
}
For each parameter, we specify a list of source parameters in the
form of `{source_layer_name, source_param_name}`, then a function
to build our parameter value. Instead of a single tuple, we can
specify a list of those to try one by one. With the explicit
transformation we can handle arbitrary parameter name and value
transformations.
"""
@spec params_mapping(t()) :: params_mapping()
def params_mapping(spec)
end