Extending xnn#

One implementation per component; put code with the family that uses it (Design of xnn).

Adding a model#

from xnn.common.models import InteratomicPotential, register_model

@register_model("mymodel")
class MyModel(InteratomicPotential):
    def forward(self, data):                      # AtomicGraph in
        node_energy = ...                         # (N,)
        return {"node_energy": node_energy,
                "energy": self.aggregate_energy(node_energy, data)}

    @classmethod
    def from_config(cls, cfg):                    # ModelConfig in
        return cls(cutoff=cfg.cutoff, **cfg.extra)

Adding a dataset#

from xnn.common.data.hub import DatasetBuilder, register_dataset

class MyDataset(DatasetBuilder):
    name = "mydataset"
    description = "One line, shown by list_datasets()."

    def load(self, *, split=None, cache_dir, **kwargs):
        splits = {"train": structures}            # structure dictionaries
        return splits if split is None else splits[split]

register_dataset(MyDataset())

Place it under src/xnn/common/data/hub/ and import it from the package. download_file() caches and verifies by MD5; load_dataset handles the cutoff= wrapping.

Adding a pre-trained model#

Write a portable directory (trainer.save_pretrained() or xnn models pack), upload it, and register a card with register_pretrained() or in models.json. A new checkpoint format is a converter registered with register_format().

Adding a featurizer#

Subclass Featurizer with output_dim and forward(data).

Neighbor lists#

A model only sees edge_index and cell_shifts from build_neighbor_list(); any backend that returns the same pair works (vesin is used when installed).