Training Configuration
TranscriptML model training is controlled by a JSON or TOML file. The same top-level training settings are used across Saluki, MPRA-LegNet, and structured RBPNet runs; the model and loss determine the batch contract.
Warning
RBPNet preprocessing and modeling are experimental. They have been minimally tested and have only been confirmed to preprocess data successfully and train reasonable models on PUM2 eCLIP data. They need substantially more validation than other TranscriptML functionality.
Create a starter JSON config with:
transcriptml init-run --workflow saluki --out-dir configs/saluki
transcriptml init-run --workflow legnet --out-dir configs/legnet
transcriptml init-run --workflow rbpnet --out-dir configs/rbpnet
Then train directly:
transcriptml train configs/saluki/train_config.json
For cross-validation, pass the starter config to transcriptml cv prepare-fold. Fold preparation preserves training, loss, and sequence-control
settings, while replacing dataset, output_dir, the model name, and the
fold-specific training seed.
Saluki Starter Configuration
transcriptml init-run --workflow saluki writes the following training
defaults:
{
"dataset": "__EDIT_ME_DATASET_DIR__",
"output_dir": "__EDIT_ME_RUN_DIR__/model",
"model": {
"name": "saluki_exact",
"params": {}
},
"batch_size": 64,
"epochs": 250,
"learning_rate": 0.0001,
"weight_decay": 0.0,
"gradient_clip_norm": 0.5,
"patience": 10,
"monitor": ["val_loss", "val_pearson"],
"loss": {
"name": "mse"
},
"device": "auto",
"num_workers": 0,
"mmap_mode": "r",
"seed": 42,
"head_layernorm": false,
"split_source": "auto",
"split": {
"method": "random",
"val_frac": 0.1,
"test_frac": 0.1
}
}
An empty model.params mapping means that the model constructor defaults
described below are used. You only need to add parameters that you want to
change.
The Sherlock workflow uses scripts/example_train_config.json as its base
config and starts from the same optimization settings. Its shell helpers
replace the two path fields, so leave dataset and output_dir as placeholders
when using those scripts.
MPRA-LegNet Starter Configuration
transcriptml init-run --workflow legnet selects LegNet and writes:
{
"dataset": "__EDIT_ME_DATASET_DIR__",
"output_dir": "__EDIT_ME_RUN_DIR__/model",
"model": {
"name": "legnet",
"params": {}
},
"batch_size": 64,
"epochs": 20,
"learning_rate": 0.001,
"weight_decay": 0.0,
"patience": 5,
"monitor": "val_loss",
"loss": {
"name": "mse"
},
"device": "auto",
"seed": 123,
"split_source": "auto",
"split": {
"method": "random",
"val_frac": 0.1,
"test_frac": 0.1
}
}
Fields omitted from this starter, such as gradient_clip_norm,
num_workers, and mmap_mode, use the generic trainer fallbacks in the next
section. The Sherlock MPRA workflow has its own editable base config at
scripts/mpra/example_legnet_train_config.json.
RBPNet Starter Configuration
Warning
This starter config is part of the experimental RBPNet workflow. Successful execution and reasonable training behavior have been checked on PUM2 eCLIP, but the preprocessing, model, losses, and evaluation require broader validation before scientific or production use.
transcriptml init-run --workflow rbpnet selects the structured RBPNet trainer.
Edit the bundle path, output path, and profile_length to match the bundle:
{
"dataset": "__EDIT_ME_RBPNET_BUNDLE_DIR__",
"output_dir": "__EDIT_ME_RUN_DIR__/model",
"model": {
"name": "rbpnet",
"params": {
"profile_length": 300,
"enrichment_head_type": "none"
}
},
"batch_size": 64,
"epochs": 100,
"learning_rate": 0.001,
"weight_decay": 0.0,
"optimizer": {"name": "adamw"},
"lr_scheduler": {"name": "reduce_on_plateau", "patience": 3},
"mixed_precision": false,
"gradient_clip_norm": 0.5,
"patience": 10,
"monitor": "val_loss",
"loss": {
"name": "rbpnet",
"lambda_ip_profile": 1.0,
"lambda_sm_profile": 1.0,
"lambda_enrichment": 1.0
},
"device": "auto",
"num_workers": 0,
"mmap_mode": "r",
"seed": 123,
"max_train_jitter": 0,
"deduplicate_loci": true,
"split_source": "config",
"split": {
"method": "group",
"group_col": "group_gene_id",
"val_frac": 0.1,
"test_frac": 0.1
}
}
Set enrichment_head_type to linear (or mlp) to add the independent
replicate-aware enrichment likelihood. The three RBPNet component weights are
independent; lambda_enrichment has no effect when the head is disabled. See
the RBPNet guide for the equations, bundle
fields, and jitter semantics.
Top-Level Training Settings
The following fields are accepted by transcriptml train. The default column
shows the generic trainer fallback when a field is omitted. Workflow starter
configs can deliberately override those fallbacks, as the Saluki starter does
above.
Field |
Type |
Default when omitted |
Meaning |
|---|---|---|---|
|
path |
required |
Dataset bundle containing |
|
path |
required |
Directory for checkpoints, history, split information, predictions, and the run summary. |
|
mapping or string |
|
Registered model name and optional constructor parameters. Workflow starters explicitly select their model. |
|
integer |
|
Number of examples per optimizer or evaluation batch. A final singleton training batch is dropped because batch-normalized models cannot train on it reliably. |
|
integer |
|
Maximum number of training epochs before early stopping. |
|
float |
|
Learning rate. Structured RBPNet passes this to the selected optimizer unless overridden there. |
|
float |
|
Weight-decay coefficient. |
|
string or mapping |
|
Structured RBPNet supports AdamW, Adam, and SGD, with optional optimizer parameters. Scalar workflows retain AdamW. |
|
string, mapping, or |
|
Structured RBPNet supports plateau, cosine, and step schedulers. |
|
boolean |
|
Enable autocast; CUDA also uses gradient scaling. |
|
float or |
|
Maximum global gradient norm. Set to |
|
integer |
|
Number of consecutive non-improving epochs tolerated by early stopping. A negative value disables early stopping. |
|
string or list |
|
Validation metric or metrics used to select |
|
string, mapping, or |
|
Training objective. Available loss configurations are described below. |
|
string |
|
PyTorch device such as |
|
integer |
|
Number of worker processes used by each PyTorch DataLoader. Workers remain alive between epochs when this is greater than zero. |
|
string or |
|
NumPy memory-map mode used when loading bundle arrays. Use |
|
integer |
|
Seeds Python, NumPy, and PyTorch. It also seeds a config-defined random split unless |
|
boolean |
|
Whether to print data-processing, batch, epoch, and evaluation progress. |
|
boolean |
|
Save deterministic end-of-epoch train and validation predictions to |
|
boolean |
|
For |
|
mapping, list, or |
|
Optional sequence ablations applied before split selection. |
|
string |
|
Whether splits come from the bundle or from the |
|
mapping |
random 80/10/10 |
Config-defined split settings, used according to |
|
integer |
|
Structured RBPNet shift range; cannot exceed the bundle’s materialized margin. Evaluation remains shift zero. |
|
boolean |
|
Collapse repeated eligibility rows for an identical RBPNet locus while retaining all replicate arrays. |
|
boolean |
|
Explicitly permit unsafe RBPNet row-random splitting. Grouped splitting is the safe default. |
|
path or |
|
Saved balanced chromosome CV plan. Must be provided together with |
|
integer or |
|
Zero-based chromosome CV test-fold index. Validation is the following fold modulo |
The canonical model mapping contains a registered name and a params
mapping:
{
"model": {
"name": "saluki_exact",
"params": {
"filters": 64
}
}
}
Parameters that are absent from params use the selected model’s defaults.
Checkpoint Selection And Early Stopping
The metrics available to monitor are:
train_losstrain_pearsonval_lossval_pearson
Structured RBPNet runs instead expose train_loss, val_loss, and the
corresponding train_/val_ forms of ip_profile_loss, sm_profile_loss, and
enrichment_loss. Profile-only runs report enrichment loss as zero.
Loss metrics improve when they decrease; Pearson metrics improve when they increase. A string can name one metric:
{"monitor": "val_loss"}
A list uses an OR rule. With:
{"monitor": ["val_loss", "val_pearson"]}
an epoch is considered improved when validation loss decreases or validation
Pearson correlation increases. That epoch replaces best.pt and resets
patience. last.pt is written after every epoch.
Epoch Prediction Debugging
Set "debug_epoch_predictions": true to write
debug_epoch_predictions.csv in the training output directory. The file has
one row per train or validation example per completed epoch. Predictions are
made in evaluation mode using the model at the end of the epoch, so dropout
and stochastic augmentation are disabled and all training examples are
included.
The columns include epoch, split, original dataset index, id, target,
prediction, residual, squared_error, configured split-level loss and
pearson, the corresponding online history_loss and history_pearson,
loss_name, and checkpoint-monitoring context. Split-level metrics are
repeated on each example row to keep the CSV self-contained.
For the training split, loss and pearson can differ from the
history_loss and history_pearson columns. History metrics are collected
while batches are being trained and the model parameters are changing, with
augmentation and dropout active when configured. The debug metrics instead
evaluate the final model state for that epoch deterministically.
Saluki Model Parameters
Saluki dataset bundles normally have six channels: A, C, G, U, CDS codon
starts, and splice junctions. TranscriptML provides the close architecture
reproduction saluki_exact and the smaller configurable alternative
saluki_like.
Inspect the installed defaults at any time:
transcriptml models show saluki_exact --json
transcriptml models show saluki_like --json
saluki_exact
This is the model used by the standard Saluki workflow.
{
"model": {
"name": "saluki_exact",
"params": {
"seq_depth": 6,
"filters": 64,
"kernel_size": 5,
"num_layers": 6,
"pooling": "max",
"dropout": 0.3,
"augment_shift": 3,
"ln_epsilon": 0.007,
"keras_bn_momentum": 0.9,
"bn_eps": 0.001
}
}
}
Parameter |
Default |
Meaning |
|---|---|---|
|
|
Number of input channels. Keep this at six for an ordinary Saluki bundle. |
|
|
Width of the convolutional stack, GRU, and dense hidden layer. |
|
|
Width of the initial and repeated one-dimensional convolutions. |
|
|
Number of convolution, dropout, and pooling blocks after the initial convolution. |
|
|
Downsampling operation in each convolutional block. Use |
|
|
Dropout probability in convolutional blocks and the dense head. |
|
|
Maximum random right shift applied during training. The sampled shift is between zero and this value; set to zero to disable it. |
|
|
Numerical epsilon used by channel layer normalization. |
|
|
Batch-normalization momentum expressed using the Keras convention reproduced by this model. |
|
|
Numerical epsilon used by normalization layers in the head. |
|
|
Checkpoint-level record of whether the head uses LayerNorm. During training, set the top-level |
Set the top-level training option to enable the experimental head:
{
"model": {"name": "saluki_exact", "params": {}},
"head_layernorm": true
}
This preserves the original Normalization → ReLU → Linear → Dropout → Normalization → ReLU → Linear ordering, but makes both head normalization
layers independent of batch and running statistics. LayerNorm uses bn_eps
so enabling the option changes the normalization behavior without also
changing its numerical epsilon. The resolved value is saved in checkpoint
model_config.params, allowing the checkpoint loader to reconstruct the
correct head, and is also recorded in summary.json.
To use average pooling and disable stochastic shift augmentation, set the corresponding model parameters:
{
"model": {
"name": "saluki_exact",
"params": {
"pooling": "average",
"augment_shift": 0
}
}
}
During each training forward pass, a positive augment_shift samples one
integer offset from zero through the configured maximum. All channels are
shifted right together, zeros are inserted at the left boundary, and the same
number of positions are removed from the right boundary. Evaluation mode never
applies the shift. Setting augment_shift to zero bypasses the operation in
training mode as well.
saluki_like
saluki_like is a compact convolutional/GRU model inspired by Saluki rather
than an exact reproduction. saluki_gru is an alias for the same
implementation.
Parameter |
Default |
Meaning |
|---|---|---|
|
|
Number of input channels. |
|
|
Number of channels in every convolutional block. |
|
|
Width of each one-dimensional convolution. |
|
|
Number of convolutional blocks; must be at least one. |
|
|
Max-pooling factor after each convolution. Values at or below one disable pooling. |
|
|
Dropout probability in the encoder, recurrent stack when applicable, and regression head. |
|
|
GRU hidden-state width. |
|
|
Number of stacked GRU layers. |
|
|
Whether the GRU reads the sequence in both directions. |
|
|
Width of the hidden layer in the regression head. |
|
|
Number of outputs. Leave this at one for TranscriptML’s scalar training workflow. |
MPRA-LegNet Model Parameters
MPRA bundles have four A/C/G/U channels. The standard MPRA workflow selects the
registered legnet model:
{
"model": {
"name": "legnet",
"params": {
"in_ch": 4,
"stem_ch": 64,
"stem_ks": 7,
"ef_ks": 5,
"ef_block_sizes": [64, 96, 128],
"pool_sizes": [2, 2, 2],
"resize_factor": 4,
"block_dropout": 0.0,
"head_dropout": 0.1,
"stem_dropout": 0.0,
"output_dim": 1
}
}
}
Parameter |
Default |
Meaning |
|---|---|---|
|
|
Number of input channels. Keep this at four for an ordinary MPRA bundle. |
|
|
Number of channels produced by the initial convolutional stem. |
|
|
Kernel size of the stem convolution. |
|
|
Kernel size used by efficient and local blocks after the stem. |
|
|
Output-channel width of each successive LegNet stage. |
|
|
Pooling factor after each stage. This list must have the same length as |
|
|
Internal channel expansion factor in each efficient block. |
|
|
Channel-dropout probability inside efficient and local stage blocks. |
|
|
Dropout probability in the regression head. |
|
|
Channel-dropout probability after the stem activation. |
|
|
Number of outputs. Leave this at one for TranscriptML’s scalar training workflow. |
Run transcriptml models show legnet --json to inspect these defaults from the
installed package.
Loss Configuration
TranscriptML supports unweighted MSE, metadata-weighted MSE, and a binomial
count likelihood. Losses that refer to metadata columns require those columns
to be present in the dataset bundle’s metadata.json.
Unweighted MSE
This is the default for both workflows:
{
"loss": {
"name": "mse"
}
}
The string form "loss": "mse" and a missing or null loss block have the
same effect.
Weighted MSE
Use exactly one of weight_col or se_col.
If metadata already contains final per-example weights:
{
"loss": {
"name": "weighted_mse",
"weight_col": "log_kdeg_weight",
"min_weight": 0.01,
"max_weight": 100.0
}
}
If metadata instead contains standard errors:
{
"loss": {
"name": "weighted_mse",
"se_col": "log_kdeg_se",
"eps": 1e-8,
"min_weight": 0.01,
"max_weight": 100.0
}
}
Field |
Default |
Meaning |
|---|---|---|
|
required |
Use |
|
none |
Metadata column containing final nonnegative weights. Mutually exclusive with |
|
none |
Metadata column containing nonnegative standard errors. Weights are calculated as |
|
|
Stabilizer used only when deriving weights from |
|
|
Lower clipping bound. Set to |
|
|
Upper clipping bound. Set to |
Binomial Count Likelihood
This loss is intended for pulse-labeling measurements with total reads, new reads, and pulse duration:
{
"loss": {
"name": "binomial_nll",
"total_reads_col": "total_reads",
"new_reads_col": "new_reads",
"pulse_hours_col": "pulse_hours",
"eps": 1e-7,
"max_rate_time": 80.0,
"log_base": "e"
}
}
The model output is interpreted as log(kdeg). The likelihood uses:
new_reads ~ Binomial(total_reads, 1 - exp(-kdeg * pulse_hours))
Field |
Default |
Meaning |
|---|---|---|
|
|
Metadata column containing positive total-read counts. |
|
|
Metadata column containing new-read counts between zero and total reads. |
|
|
Metadata column containing positive pulse durations in hours. |
|
|
Numerical lower bound used in probability and rate calculations. |
|
|
Upper bound on |
|
|
Base of the model’s log-rate output. Accepted values include |
This loss can train without y.npy, but keeping a scalar target is useful
because TranscriptML can then report Pearson correlation and MSE alongside the
count likelihood.
Split Configuration
split_source determines whether training uses splits already stored in the
bundle or constructs them from the split block.
|
Behavior |
|---|---|
|
Use bundle splits when present; otherwise use the config-defined |
|
Require and use the bundle’s |
|
Ignore bundle splits and construct splits from the config. |
Cross-validation fold preparation writes splits.json inside each fold bundle.
The usual CV workflow therefore uses those fold assignments under the default
"auto" setting.
Balanced chromosome CV plans
Create one content-hashed plan from a dataset’s chromosome grouping metadata:
transcriptml cv create-chromosome-plan \
--dataset data/rbpnet \
--group-col group_chromosome \
--n-folds 5 \
--output cv/cv5.json
The JSON records the grouping column, example count on every chromosome,
chromosome membership and total examples for every fold group, algorithm and
tie-breaking rules, format and TranscriptML versions, and a SHA-256 plan_id.
Generation sorts chromosomes from largest to smallest and assigns each to the
group with the smallest current example count; ties use chromosome name and
then fold index deterministically. This balances examples rather than numbers
of chromosomes. Plans require at least three folds and at least one chromosome
per fold. The plan path and validated plan_id are recorded in training
summaries and checkpoints.
For run k, test is group k, validation is (k+1) mod N, and training is all
remaining groups. Inspect or materialize one resolution with:
transcriptml cv resolve-plan \
--dataset data/rbpnet --cv-plan cv/cv5.json --fold 0 \
--output cv/fold0_splits.json
Training accepts overrides suitable for a Slurm job array:
transcriptml train configs/rbpnet/train_config.json \
--dataset data/rbpnet \
--cv-plan cv/cv5.json \
--fold "${SLURM_ARRAY_TASK_ID}" \
--output-dir "cv/fold${SLURM_ARRAY_TASK_ID}/model"
Resolution rejects missing chromosomes, new chromosomes, or changed example counts rather than silently applying an obsolete plan.
Random Splits
{
"split_source": "config",
"split": {
"method": "random",
"val_frac": 0.1,
"test_frac": 0.1,
"seed": 42
}
}
val_frac and test_frac must each be between zero and one, and their sum must
be less than one. split.seed overrides the top-level training seed for split
assignment.
Metadata Splits
{
"split_source": "config",
"split": {
"method": "metadata",
"split_col": "split"
}
}
The selected metadata column may use train, val, valid, validation, or
test labels.
Explicit Split Indices
{
"split_source": "config",
"split": {
"method": "predefined",
"splits": {
"train": [0, 1, 2, 3],
"val": [4],
"test": [5]
}
}
}
No example index may occur in more than one split.
Sequence Controls
Sequence controls perturb selected parts of the input before TranscriptML chooses train, validation, and test examples. All splits in that training run therefore use the same controlled representation.
The preferred form is an explicit operation list:
{
"sequence_controls": {
"seed": 42,
"operations": [
{
"operation": "randomize_nucleotides",
"regions": ["cds"]
}
]
}
}
This example replaces every represented CDS nucleotide independently with a uniformly sampled A, C, G, or U. It preserves UTR bases, region lengths, padding, splice annotations, and the original CDS codon-start channel. Transcripts without a detectable CDS are skipped and counted in the run summary.
Available Operations
Operation |
Regions |
Effect |
|---|---|---|
|
|
Permutes the existing nucleotide calls within each selected region, preserving its nucleotide composition. |
|
|
Permutes complete existing CDS codons as three-nucleotide units, preserving the multiset of codons. |
|
|
Replaces every selected position independently with uniformly random A, C, G, or U. |
|
|
Shifts the CDS/codon-start annotation channel by one or two positions while leaving nucleotide and splice channels unchanged. |
The first three operations rewrite only A/C/G/U base channels. cds_frameshift
rewrites only the CDS annotation channel, so it can be combined with one
base-editing operation on the CDS.
Use shuffle_codons when the control should preserve CDS codon composition.
Use randomize_nucleotides when the sequence itself should be replaced rather
than rearranged.
Regions
The canonical region names are:
5utrcds3utrtranscript
all expands to the three annotated regions independently. A
whole-transcript base operation cannot be combined with separate 5-prime UTR,
CDS, or 3-prime UTR base operations.
When regions is omitted, shuffle_nucleotides and
randomize_nucleotides select all three annotated regions.
shuffle_codons and cds_frameshift select the CDS.
Annotated regions require a schema with a resolvable CDS channel, such as a
Saluki bundle. An ordinary four-channel MPRA bundle can use transcript-wide
shuffle_nucleotides or randomize_nucleotides, but it cannot identify
5-prime UTR, CDS, or 3-prime UTR boundaries.
Frameshift Controls
The shift must be one or two:
{
"sequence_controls": {
"operations": [
{
"operation": "cds_frameshift",
"shift": 1
}
]
}
}
This tests the annotation frame supplied to the model. It does not insert, delete, or move nucleotide bases.
Sequence-Control Settings
Field |
Default |
Meaning |
|---|---|---|
|
|
Set to |
|
|
Seed used for sequence controls. This is separate from the top-level training seed. |
|
none |
List of operation mappings. Each entry contains |
|
|
Save the controlled bundle under |
|
none |
Save to an explicit bundle directory. Providing this field also enables saving. |
|
inferred |
CDS channel name or zero-based channel index. Usually unnecessary for a standard Saluki schema. |
Randomization is deterministic for a given sequence-control seed, sequence
index, operation, and region. In CV, keeping sequence_controls.seed fixed
therefore gives every fold the same controlled input, even though the
top-level training seed changes by fold.
Setting save writes a complete bundle plus sequence_controls.json:
{
"sequence_controls": {
"seed": 42,
"save": true,
"operations": [
{
"operation": "randomize_nucleotides",
"regions": ["cds"]
}
]
}
}
This is useful when a separate transcriptml evaluate or interpretation
command must consume the controlled inputs. Those commands do not
automatically reconstruct controls from the checkpoint; point --dataset at
the saved controlled bundle.
In the Sherlock CV script, for example, a saved fold bundle is located at:
${CV_ROOT}/foldN/model/sequence_controlled_dataset
Evaluating ${CV_ROOT}/foldN/dataset instead uses the original unmodified
inputs.
Shortcut And Legacy Forms
Top-level operation shortcuts are accepted inside sequence_controls:
{
"sequence_controls": {
"seed": 42,
"randomize_nucleotides": ["cds"]
}
}
shuffle_nucleotides, shuffle_codons, randomize_nucleotides, and
cds_frameshift all have shortcut forms. For the three base operations, a
boolean true selects the operation’s default regions; an explicit region list
is clearer.
The value of sequence_controls can also be a bare operation list:
{
"sequence_controls": [
{
"operation": "randomize_nucleotides",
"regions": ["transcript"]
}
]
}
This compact form uses sequence-control seed zero and cannot set save,
save_dir, or cds_channel; use the mapping form when those settings matter.
The older keys 5pUTR_ablation, CDS_ablation, and 3pUTR_ablation remain
available for compatibility. Their "scramble" mode shuffles nucleotides in
UTRs but shuffles codon units in the CDS, while "ablate" selects independent
random nucleotides. The older "true_scramble" mode shuffles nucleotides,
including within the CDS. New configs should use the explicit operation names
so that the intended control is unambiguous.
Using These Settings On Sherlock
The Saluki scripts read:
scripts/example_train_config.json
The MPRA-LegNet scripts read:
scripts/mpra/example_legnet_train_config.json
Edit the copied file in your Sherlock run directory. The split and CV wrappers
preserve model parameters, training settings, losses, and sequence controls.
They replace dataset and output_dir; CV preparation also selects the
configured CV model and adds the fold number to the top-level training seed.
For example:
# Saluki
bash scripts/submit_train_eval_cv.sh
# MPRA-LegNet
bash scripts/mpra/submit_train_eval_cv.sh
After a fold starts, inspect the fully resolved config at:
${CV_ROOT}/foldN/train_config.json
That file is the clearest record of the exact settings used for one trained model.