Training¶
arguments ¶
Configuration for Trainer and CrossEncoderTrainer runs.
TrainingArguments
dataclass
¶
TrainingArguments(
output_dir: str,
learning_rate: float = 3e-05,
negative_samples_ratio: int = 5,
use_peft: bool = False,
peft_config: Any | None = None,
num_epochs: int = 3,
batch_size: int = 32,
loss: Literal["infonce", "margin"] = "infonce",
temperature: float = 0.05,
margin: float = 1.0,
device: str = "cpu",
weight_decay: float = 0.01,
warmup_ratio: float = 0.0,
)
Hyperparameters and settings for a training run.
Attributes:
| Name | Type | Description |
|---|---|---|
output_dir |
str
|
Directory where the trained model's |
learning_rate |
float
|
Optimizer learning rate. |
negative_samples_ratio |
int
|
Number of hard negatives sampled per positive pair during batch generation, via sample_hard_negatives. |
use_peft |
bool
|
Whether to wrap the model with LoRA adapters via PEFT.
Requires |
peft_config |
Any | None
|
A |
num_epochs |
int
|
Number of passes over the training data. |
batch_size |
int
|
Number of entity pairs per batch. |
loss |
Literal['infonce', 'margin']
|
Contrastive objective for |
temperature |
float
|
Softmax temperature for the |
margin |
float
|
Margin for the |
device |
str
|
Torch device to train on, e.g. |
weight_decay |
float
|
AdamW weight decay, applied to every parameter
except bias and LayerNorm weights (standard BERT fine-tuning
convention). Defaults to |
warmup_ratio |
float
|
Fraction of total optimizer steps spent linearly
warming up the learning rate before linearly decaying it back
to zero, via |
trainer ¶
Unified training loop for trainable linking modules.
Supports bi-encoder/GNN contrastive training (InfoNCE or Margin Ranking Loss) with hard negative sampling drawn from a BlockingStrategy via sample_hard_negatives, and optional LoRA adapters via PEFT (see TrainingArguments.use_peft).
model must satisfy TrainableModel:
a torch.nn.Module exposing a differentiable encode(entities) ->
torch.Tensor method, one embedding row per entity, on the model's own
device. No linker in this repo implements that yet -- this class is
validated against a small in-repo toy encoder (see
tests/train/test_trainer.py); future bi-encoder/GNN linkers implement
encode() to plug into it.
TrainableModel ¶
Bases: Protocol
Structural type for the model Trainer trains.
Any torch.nn.Module exposing a differentiable encode method
satisfies this -- gradients must flow from its output back to
self.parameters(), and it must return its output on the same
device its parameters currently live on (Trainer moves the model
via .to(device) but never touches tensors itself).
encode ¶
encode(entities: list[Entity]) -> torch.Tensor
Return a (len(entities), dim) tensor of embeddings, one row per entity.
Source code in src/linkingtk/train/trainer.py
55 56 57 | |
Trainer ¶
Trainer(
model: TrainableModel,
args: TrainingArguments,
train_data: list[tuple[Entity, Entity]],
eval_data: list[tuple[Entity, Entity]] | None = None,
blocking: BlockingStrategy = DEFAULT_BLOCKING,
)
Trains a TrainableModel via contrastive learning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
TrainableModel
|
The model to train. |
required |
args
|
TrainingArguments
|
Hyperparameters and settings, see TrainingArguments. |
required |
train_data
|
list[tuple[Entity, Entity]]
|
|
required |
eval_data
|
list[tuple[Entity, Entity]] | None
|
Optional held-out positive pairs. If given, every
epoch's end evaluates Hits@1/Hits@10/MRR over an exhaustive
(not blocking-restricted) ranking of every eval entity, and
appends the result to |
None
|
blocking
|
BlockingStrategy
|
Strategy used to mine hard negatives from |
DEFAULT_BLOCKING
|
Attributes:
| Name | Type | Description |
|---|---|---|
eval_history |
list[EvaluationReport]
|
One EvaluationReport
per epoch, appended in |
Source code in src/linkingtk/train/trainer.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
train ¶
train() -> None
Run the training loop, updating self.model in place.
Source code in src/linkingtk/train/trainer.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
cross_encoder ¶
Training loop for cross-encoder linking modules.
Complements Trainer (bi-encoder/GNN
models: independently encode() each side, then contrast the resulting
embeddings) with the shape a true cross-encoder needs: one joint forward
pass per (entity1, entity2) pair, scored directly, with no independently
comparable embedding space to take a dot product over.
GlossBertLinker is
the first (and, as of this writing, only) consumer.
model must satisfy CrossEncoderModel:
a torch.nn.Module exposing a differentiable score(pairs) -> torch.Tensor
method, one logit-margin per pair (higher = more likely a true match).
CrossEncoderModel ¶
Bases: Protocol
Structural type for the model CrossEncoderTrainer trains.
Any torch.nn.Module exposing a differentiable score method
satisfies this -- gradients must flow from its output back to
self.parameters(), and it must return its output on the same
device its parameters currently live on (CrossEncoderTrainer moves
the model via .to(device) but never touches tensors itself).
score ¶
score(pairs: list[tuple[Entity, Entity]]) -> torch.Tensor
Return a (len(pairs),) tensor: one logit-margin per pair.
Source code in src/linkingtk/train/cross_encoder.py
56 57 58 | |
CrossEncoderTrainer ¶
CrossEncoderTrainer(
model: CrossEncoderModel,
args: TrainingArguments,
train_data: list[tuple[Entity, Entity]],
eval_data: list[tuple[Entity, Entity]] | None = None,
eval_dataset2: list[Entity]
| EntitySource
| None = None,
blocking: BlockingStrategy = DEFAULT_BLOCKING,
)
Trains a CrossEncoderModel with binary cross-entropy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
CrossEncoderModel
|
The model to train. |
required |
args
|
TrainingArguments
|
Hyperparameters and settings, see
TrainingArguments.
|
required |
train_data
|
list[tuple[Entity, Entity]]
|
|
required |
eval_data
|
list[tuple[Entity, Entity]] | None
|
Optional held-out positive pairs. If given, every
epoch's end scores |
None
|
eval_dataset2
|
list[Entity] | EntitySource | None
|
The real target set (or
EntitySource, e.g. a
WnEntitySource) to block
|
None
|
blocking
|
BlockingStrategy
|
Strategy used to mine hard negatives from |
DEFAULT_BLOCKING
|
Attributes:
| Name | Type | Description |
|---|---|---|
eval_history |
list[EvaluationReport]
|
One EvaluationReport
per epoch, appended in |
Source code in src/linkingtk/train/cross_encoder.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | |
train ¶
train() -> None
Run the training loop, updating self.model in place.
Source code in src/linkingtk/train/cross_encoder.py
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | |
ewiser_trainer ¶
Training loop for EwiserEncoder.
A dedicated trainer, not a reuse of
CrossEncoderTrainer:
EWISER's real objective is full-inventory classification (one softmax
cross-entropy per annotated word, over the entire
SenseVocabulary),
not a pairwise margin/BCE loss over (mention, candidate) pairs -- there's
no independently-embedded pair of vectors to contrast, and batching is
per-sentence (every annotated word in a sentence scored by one shared
forward pass), not per-pair.
Confirmed directly against the reference's own training code
(ewiser/fairseq_ext/criterions/weighted_cross_entropy.py): despite the
name, "weighted cross-entropy" is not frequency-based class balancing
-- the weight is 1.0 on every real sense and 0.0 only on the handful
of reserved/special vocabulary slots (a padding mask, not class
weighting, and never actually reachable as a gold class anyway). This
trainer's loss is plain torch.nn.functional.cross_entropy over only
the resolved (word position, gold vocabulary index) pairs -- unresolved
mentions are filtered out before the loss is built (see
_group_into_sentence_batches), which does the same masking job as the
reference's own ignore_index without needing one.
EwiserTrainer ¶
EwiserTrainer(
model: EwiserEncoder,
args: TrainingArguments,
train_data: tuple[list[Entity], list[tuple[str, str]]],
eval_data: tuple[list[Entity], list[tuple[str, str]]]
| None = None,
eval_dataset2: list[Entity]
| EntitySource
| None = None,
blocking: BlockingStrategy = DEFAULT_BLOCKING,
freeze_output_epochs: int = 0,
output_freeze_lr: float = 0.0001,
output_unfreeze_lr: float = 1e-05,
)
Trains an EwiserEncoder with full-inventory cross-entropy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
EwiserEncoder
|
The |
required |
args
|
TrainingArguments
|
Hyperparameters and settings, see
TrainingArguments.
|
required |
train_data
|
tuple[list[Entity], list[tuple[str, str]]]
|
|
required |
eval_data
|
tuple[list[Entity], list[tuple[str, str]]] | None
|
Optional held-out |
None
|
eval_dataset2
|
list[Entity] | EntitySource | None
|
The real target set (or
EntitySource, e.g. a
WnEntitySource) to
block |
None
|
blocking
|
BlockingStrategy
|
Candidate-generation strategy for |
DEFAULT_BLOCKING
|
freeze_output_epochs
|
int
|
Number of leading epochs trained with
|
0
|
output_freeze_lr
|
float
|
Learning rate for the leading
|
0.0001
|
output_unfreeze_lr
|
float
|
Learning rate from |
1e-05
|
Attributes:
| Name | Type | Description |
|---|---|---|
eval_history |
list[EvaluationReport]
|
One EvaluationReport
per epoch, appended in |
Source code in src/linkingtk/train/ewiser_trainer.py
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
train ¶
train() -> None
Run the training loop, updating self.model in place.
Source code in src/linkingtk/train/ewiser_trainer.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | |
esc_trainer ¶
Training loop for EscEncoder.
A dedicated trainer, not a reuse of
CrossEncoderTrainer or
EwiserTrainer: ESC's real
objective is extractive-QA span-position cross-entropy (one joint sequence
per mention, containing every one of that mention's candidates' glosses
at once, with the gold candidate's token span as the target start/end
position) -- not a pairwise margin/BCE loss over independent
(mention, candidate) pairs (CrossEncoderTrainer), and not per-sentence
full-inventory classification (EwiserTrainer). The loss itself needs no
hand-rolled cross-entropy: EscEncoder.forward(..., start_positions=...,
end_positions=...) already returns HF's own (start_loss + end_loss) / 2
via .loss (see EscEncoder's own module docstring).
Unlike EwiserTrainer (whose training never needs a candidate-generation
step -- gold indices are resolved directly against its fixed output
vocabulary), ESC's training is candidate generation: each mention's
training example requires the same real, blocking-restricted candidate
senses (with real gloss text) that EscLinker.link() would score at
inference time. So EscTrainer takes a senses source unconditionally
(not only when evaluating, like EwiserTrainer.eval_dataset2) -- used to
build both training examples and (if eval_data is given) evaluation
candidates.
EscTrainer ¶
EscTrainer(
model: EscEncoder,
args: TrainingArguments,
train_data: tuple[list[Entity], list[tuple[str, str]]],
senses: list[Entity] | EntitySource,
eval_data: tuple[list[Entity], list[tuple[str, str]]]
| None = None,
blocking: BlockingStrategy = DEFAULT_BLOCKING,
)
Trains an EscEncoder with extractive-QA span-position cross-entropy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
EscEncoder
|
The |
required |
args
|
TrainingArguments
|
Hyperparameters and settings, see
TrainingArguments.
|
required |
train_data
|
tuple[list[Entity], list[tuple[str, str]]]
|
|
required |
senses
|
list[Entity] | EntitySource
|
The real target sense set (or
EntitySource, e.g. a
WnEntitySource) |
required |
eval_data
|
tuple[list[Entity], list[tuple[str, str]]] | None
|
Optional held-out |
None
|
blocking
|
BlockingStrategy
|
Candidate-generation strategy for both training examples
and |
DEFAULT_BLOCKING
|
Attributes:
| Name | Type | Description |
|---|---|---|
eval_history |
list[EvaluationReport]
|
One EvaluationReport
per epoch, appended in |
loss_history |
list[float]
|
Mean training loss per epoch, always appended in
|
Source code in src/linkingtk/train/esc_trainer.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
train ¶
train() -> None
Run the training loop, updating self.model in place.
Source code in src/linkingtk/train/esc_trainer.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |