Using KLay¶
This page explains every section of a KLay YAML file, how the fields fit together, and the shorthand notations you can use to keep configs concise.
A complete, minimal example is shown first; each part is dissected in the sections that follow.
model_params:
r_max: 4.0
n_channels: 32
num_elems: 2
model_inputs:
atomic_numbers: "Tensor (N,)"
positions: "Tensor (N,3)"
edge_index: "Tensor (2,E)"
model_layers:
element_embedding:
type: OneHotAtomEncoding
config: {num_elems: 2}
inputs: {x: model_inputs.atomic_numbers}
edge_feature0:
type: SphericalHarmonicEdgeAttrs
config: {lmax: 1}
inputs:
pos: model_inputs.positions
edge_index: model_inputs.edge_index
output: {0: vec0, 1: len0, 2: sh0}
radial_basis_func:
type: RadialBasisEdgeEncoding
config:
r_max: ${model_params.r_max}
inputs:
edge_length: len0
node_features:
type: AtomwiseLinear
config:
irreps_in_block:
- {"l": 0, "mul": '${model_params.num_elems}'}
irreps_out_block:
- {"l": 0, "mul": '${model_params.n_channels}'}
inputs: {h: element_embedding}
conv1:
type: MACE_layer
config:
lmax: 1
correlation: 2
num_elements: ${model_params.num_elems}
hidden_irreps_block:
- {"l": 0, "mul": '${model_params.n_channels}'}
- {"l": 1, "mul": '${model_params.n_channels}'}
input_block: ${model_layers.node_features.config.irreps_out_block}
node_attr_block: ${model_layers.node_features.config.irreps_in_block}
inputs:
vectors: vec0
node_feats: node_features
node_attrs: element_embedding
edge_feats: radial_basis_func
edge_index: model_inputs.edge_index
output_projection:
type: AtomwiseLinear
config:
irreps_in_block:
- {"l": 0, "mul": '${model_params.n_channels}'}
- {"l": 1, "mul": '${model_params.n_channels}'}
irreps_out_block:
- {"l": 0, "mul": 1}
inputs: {h: conv1}
forces:
type: AutogradForces
inputs:
energy: output_projection
pos: model_inputs.positions
model_outputs:
energy: output_projection
forces: forces
representation: conv1
2. model_inputs – declare the forward() signature¶
Keys become argument names of the generated model:
model_inputs:
atomic_numbers: "Tensor (N,)"
positions: "Tensor (N,3)"
edge_index: "Tensor (2,E)"
shifts: "Tensor (E,3)" # optional for PBC
The value is just a comment; KLay never parses it.
3. model_layers – the heart of the graph¶
Each top-level key creates one node in the DAG.
Layer declaration¶
element_embedding:
type: OneHotAtomEncoding # registry key
config: {num_elems: ${model_params.num_elems}}
inputs: {x: model_inputs.atomic_numbers}
Keys¶
type| registry key (seeklay layers)config| kwargs passed tofrom_configor__init__inputs| mapping port -> sourceoutput| optional mapping inner-key (or index) -> aliasalias| optional — treat this entry as another call-site for analready-declared module (shared weights)
Input references¶
Syntax |
Meaning |
|---|---|
|
forward() argument |
|
whole output of that layer |
|
k-th tuple element or dict key |
any alias |
whatever |
Irreducible–representation (irrep) blocks¶
klay follows the same compact string format as e3nn but lets you declare each block as a dictionary—convenient for YAML and programmatic construction. This ensures readability and abstracts away any e3nn specific notation.
Each block has
l– the total angular-momentum order (integer ≥ 0)mul– multiplicity, i.e. how many copies of that irrepoptional
p– explicit parity,"even"or"odd"
Default parity¶
If the p key is omitted, klay assigns it automatically:
e(even) whenlis eveno(odd) whenlis odd
Example¶
blocks = [
{"l": 0, "mul": 64}, # 0 -> default even -> 64x0e
{"l": 1, "mul": 32}, # 1 -> default odd -> 32x1o
{"l": 2, "mul": 16, "p": "odd"}, # explicit override -> 16x2o
]
>>> irreps_blocks_to_string(blocks)
'64x0e + 32x1o + 16x2o'
Copy-and-paste the block list into your *.yaml model file or build
it on the fly in Python; klay will convert it to the canonical irrep
string wherever an irreps_* field is expected.
Output mapping¶
Use it when a layer returns a tuple or dict and you want human-readable names:
edge_feature0:
type: SphericalHarmonicEdgeAttrs
output:
0: vec0 # tuple index -> alias
1: len0
2: sh0
KLay auto-creates both the alias (len0) and edge_feature0.1
reference.
Alias (weight sharing, Experimental)¶
edge_conv: # declares module
type: ConvNetLayer
config: {…}
conv1: # extra call (shares weights)
alias: edge_conv
inputs: {h: node_features, edge_sh: sh0}
4. model_outputs – what you want out¶
A mapping where the key is the public name and the value is a reference:
model_outputs:
energy: output_projection
forces: forces
representation: conv1
A trailing
.kor.keyselects a field from tuple/dict.If you omit
model_inputsandmodel_outputsthe builder returns a dict{name: nn.Module}– handy for “layer library” configs.
Cheat-sheet¶
Syntax |
Expands to |
Use-case |
|---|---|---|
|
placeholder tensor |
raw model input |
|
full output of |
single-output layers |
|
3ʳᵈ tuple slot of |
tuple-return layers |
|
dict key |
dict-return layers |
|
whatever |
readable wiring |
Gotchas & best practices¶
Forces training – set
create_graph: truein theForceFromEnergylayer to keep second-order derivatives.Avoid dotted aliases for clarity: prefer
edge_length: len0overedge_feature0.1.Validate & draw your graph before training:
klay validate model.yml -v
Export a stand-alone TorchScript model:
klay export model.yml -o model.pt