kalfa 3.0.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. kalfa/__init__.py +19 -0
  2. kalfa/api.py +284 -0
  3. kalfa/board/__init__.py +1 -0
  4. kalfa/board/answers.py +419 -0
  5. kalfa/board/server.py +536 -0
  6. kalfa/board/static/api.js +176 -0
  7. kalfa/board/static/app.js +122 -0
  8. kalfa/board/static/board.css +228 -0
  9. kalfa/board/static/charts.css +46 -0
  10. kalfa/board/static/components/badge.js +14 -0
  11. kalfa/board/static/components/chart.js +204 -0
  12. kalfa/board/static/components/diagram.js +857 -0
  13. kalfa/board/static/components/error.js +17 -0
  14. kalfa/board/static/components/loading.js +7 -0
  15. kalfa/board/static/components/progress.js +25 -0
  16. kalfa/board/static/components/settings.js +418 -0
  17. kalfa/board/static/components/spark.js +43 -0
  18. kalfa/board/static/components/table.js +156 -0
  19. kalfa/board/static/diagram.css +76 -0
  20. kalfa/board/static/format.js +138 -0
  21. kalfa/board/static/index.html +34 -0
  22. kalfa/board/static/plot.js +594 -0
  23. kalfa/board/static/predictions.css +20 -0
  24. kalfa/board/static/store.js +215 -0
  25. kalfa/board/static/views/compare.js +185 -0
  26. kalfa/board/static/views/home.js +90 -0
  27. kalfa/board/static/views/record/config.js +81 -0
  28. kalfa/board/static/views/record/curves.js +137 -0
  29. kalfa/board/static/views/record/data.js +378 -0
  30. kalfa/board/static/views/record/files.js +128 -0
  31. kalfa/board/static/views/record/log.js +164 -0
  32. kalfa/board/static/views/record/model.js +286 -0
  33. kalfa/board/static/views/record/overview.js +216 -0
  34. kalfa/board/static/views/record/plots.js +103 -0
  35. kalfa/board/static/views/record/predictions.js +834 -0
  36. kalfa/board/static/views/record.js +179 -0
  37. kalfa/board/static/views/runs.js +124 -0
  38. kalfa/board/static/views/sweep.js +282 -0
  39. kalfa/board/watch.py +87 -0
  40. kalfa/cli.py +371 -0
  41. kalfa/commands/__init__.py +0 -0
  42. kalfa/commands/common.py +8 -0
  43. kalfa/commands/export.py +117 -0
  44. kalfa/commands/generate.py +31 -0
  45. kalfa/commands/guide/__init__.py +101 -0
  46. kalfa/commands/guide/about.py +93 -0
  47. kalfa/commands/guide/calls.py +102 -0
  48. kalfa/commands/guide/sections.py +186 -0
  49. kalfa/commands/guide/seen.py +307 -0
  50. kalfa/commands/guide/show.py +106 -0
  51. kalfa/commands/guide/training.py +333 -0
  52. kalfa/commands/guide/words.py +97 -0
  53. kalfa/commands/legos.py +508 -0
  54. kalfa/commands/plots.py +27 -0
  55. kalfa/commands/report/__init__.py +64 -0
  56. kalfa/commands/report/page.py +112 -0
  57. kalfa/commands/report/predictions.py +216 -0
  58. kalfa/commands/report/sections.py +356 -0
  59. kalfa/commands/stop.py +60 -0
  60. kalfa/commands/sweep/__init__.py +202 -0
  61. kalfa/commands/sweep/checks.py +98 -0
  62. kalfa/commands/sweep/plan.py +183 -0
  63. kalfa/commands/sweep/points.py +123 -0
  64. kalfa/commands/sweep/runner.py +100 -0
  65. kalfa/commands/sweep/space.py +67 -0
  66. kalfa/commands/sweep/strategies.py +228 -0
  67. kalfa/core/__init__.py +0 -0
  68. kalfa/core/aliases.py +229 -0
  69. kalfa/core/build.py +727 -0
  70. kalfa/core/check.py +550 -0
  71. kalfa/core/coerce.py +36 -0
  72. kalfa/core/context.py +149 -0
  73. kalfa/core/device.py +63 -0
  74. kalfa/core/errors.py +45 -0
  75. kalfa/core/graph.py +304 -0
  76. kalfa/core/history.py +70 -0
  77. kalfa/core/loop.py +710 -0
  78. kalfa/core/make.py +121 -0
  79. kalfa/core/plan.py +156 -0
  80. kalfa/core/predict.py +290 -0
  81. kalfa/core/protocols.py +122 -0
  82. kalfa/core/record.py +347 -0
  83. kalfa/core/refs.py +88 -0
  84. kalfa/core/rng.py +100 -0
  85. kalfa/core/rules.py +513 -0
  86. kalfa/core/run.py +568 -0
  87. kalfa/core/spec.py +413 -0
  88. kalfa/core/state.py +100 -0
  89. kalfa/core/wrap.py +671 -0
  90. kalfa/records/__init__.py +24 -0
  91. kalfa/records/compare.py +86 -0
  92. kalfa/records/reader.py +561 -0
  93. kalfa/records/stats/__init__.py +36 -0
  94. kalfa/records/stats/choices.py +282 -0
  95. kalfa/records/stats/classes.py +236 -0
  96. kalfa/records/stats/measures.py +144 -0
  97. kalfa/records/stats/pairs.py +225 -0
  98. kalfa/records/stats/tables.py +153 -0
  99. kalfa/records/sweep.py +244 -0
  100. kalfa/std/__init__.py +17 -0
  101. kalfa/std/actions.py +35 -0
  102. kalfa/std/common.py +56 -0
  103. kalfa/std/data/__init__.py +1 -0
  104. kalfa/std/data/base.py +45 -0
  105. kalfa/std/data/columns.py +190 -0
  106. kalfa/std/data/flow.py +317 -0
  107. kalfa/std/data/images.py +443 -0
  108. kalfa/std/data/options.py +147 -0
  109. kalfa/std/data/pre.py +84 -0
  110. kalfa/std/data/splits.py +140 -0
  111. kalfa/std/data/stream.py +294 -0
  112. kalfa/std/data/table.py +642 -0
  113. kalfa/std/data/text.py +436 -0
  114. kalfa/std/data/transforms.py +327 -0
  115. kalfa/std/data/weights.py +113 -0
  116. kalfa/std/data/window.py +135 -0
  117. kalfa/std/figure.py +37 -0
  118. kalfa/std/init.py +72 -0
  119. kalfa/std/loggers.py +105 -0
  120. kalfa/std/losses.py +161 -0
  121. kalfa/std/metrics.py +463 -0
  122. kalfa/std/models.py +122 -0
  123. kalfa/std/notes.py +1553 -0
  124. kalfa/std/objectives.py +360 -0
  125. kalfa/std/plots/__init__.py +75 -0
  126. kalfa/std/plots/classification.py +207 -0
  127. kalfa/std/plots/common.py +44 -0
  128. kalfa/std/plots/curves.py +56 -0
  129. kalfa/std/plots/images.py +188 -0
  130. kalfa/std/plots/pairs.py +66 -0
  131. kalfa/std/plots/predictions.py +154 -0
  132. kalfa/std/samplers.py +261 -0
  133. kalfa/std/samples.py +72 -0
  134. kalfa/std/schedules.py +74 -0
  135. kalfa/std/steps.py +133 -0
  136. kalfa/std/triggers.py +135 -0
  137. kalfa/summary.py +296 -0
  138. kalfa/tui/__init__.py +4 -0
  139. kalfa/tui/app.py +107 -0
  140. kalfa/tui/config.py +61 -0
  141. kalfa/tui/guide.py +100 -0
  142. kalfa/tui/jobs.py +97 -0
  143. kalfa/tui/legos.py +62 -0
  144. kalfa/tui/records.py +439 -0
  145. kalfa-3.0.0.dev0.dist-info/METADATA +261 -0
  146. kalfa-3.0.0.dev0.dist-info/RECORD +148 -0
  147. kalfa-3.0.0.dev0.dist-info/WHEEL +4 -0
  148. kalfa-3.0.0.dev0.dist-info/entry_points.txt +2 -0
kalfa/std/notes.py ADDED
@@ -0,0 +1,1553 @@
1
+ from kalfa.core import aliases
2
+
3
+
4
+ def lines(*rows):
5
+ return "\n".join(rows)
6
+
7
+
8
+ LR = "the base learning rate; a schedule multiplies it, a group of over may set its own and a rule may patch it"
9
+ BETAS = "[beta1, beta2]: the decay rates of the running mean of the gradient and of its square"
10
+ EPS = "added to the denominator for numerical stability"
11
+ MAXIMIZE = "true climbs the objective instead of descending it"
12
+ REDUCTION = ("how the element losses combine: mean (the default) or sum; none leaves a tensor that an optimizer cannot "
13
+ "step on")
14
+ DEPRECATED = "deprecated by torch; write reduction instead"
15
+ INPLACE = "true overwrites the input tensor to save memory"
16
+ BATCH = ("the batch size, or a mapping of size, eval_size (the batch of the valid and test sets), workers, drop_last "
17
+ "and shuffle")
18
+ WATCH = "the series read every turn, such as val/rmse, train/total/kl or track/optimizers.main.lr"
19
+ ORDER = "the optimizer names in the order they step; null takes the order of the optimizers section"
20
+ AMP = ("runs the forward passes under torch.autocast on cuda and mps (it does nothing on cpu), with a gradient scaler "
21
+ "on cuda")
22
+ GRAD_CLIP = "clips the gradient norm of every update to this value; null does not clip"
23
+ ACCUMULATE = "sums the gradients of this many batches into one update"
24
+ PLOT_PRED = ("the output to draw, by its name (net) or its column (pred_net); null takes the first output that pairs "
25
+ "with a target")
26
+ PLOT_TARGET = "the target column of the predictions table; null takes the target that pairs with pred"
27
+ CLASSES_LAST = ("null finds the class axis from the shapes; true means (batch, tokens, vocabulary) and false (batch, "
28
+ "vocabulary, tokens); needed only when the tokens and the vocabulary have the same size")
29
+ COUNTED = ("the classes 0 to num_classes - 1 that are counted; null counts the classes seen in the predictions and the "
30
+ "targets")
31
+ SCORED = ("kept for symmetry with accuracy and f1 and not read: the classes come from the width of the logits, and one "
32
+ "score column (or (N, 2) logits) is a binary task")
33
+ SAMPLES = "the samples drawn at the end of a run; kalfa generate and write_samples may ask for another count"
34
+ SIZE = "an int for a square, or [height, width]"
35
+ LATENT = "the width of the latent noise z"
36
+ SPLIT_SEED = "the seed of the shuffle; null takes the top level seed"
37
+ SPLIT_RATIOS = "up to three shares for train, valid and test that sum to 1; [0.8, 0.2] makes no test set"
38
+ DEVICE = "the device torch makes the weights on; kalfa moves the models to the run device, so leave it out"
39
+ DTYPE = "the dtype of the weights; leave it out to keep float32"
40
+ GIVEN = "the value that marks the {} rows; null makes no {} set"
41
+ PATH = "a relative path is looked for in the working directory, then next to the config files"
42
+ LOCAL = "an object with write, given from Python; null writes to stderr"
43
+
44
+
45
+ DATA = {
46
+ "table": {
47
+ "params": {
48
+ "file": f"the table to read: a .parquet, .pq, .csv or .tsv file; {PATH}",
49
+ "split": ("required: a list of ratios for a shuffled split into train, valid and test ([0.8, 0.2] makes "
50
+ "no test set), or a split call: random, sequential, kfold or given"),
51
+ "features": ("a mapping of column names or fnmatch patterns (\"x*\") to a preprocessor, a list of "
52
+ "preprocessors applied in order, or null for the raw column; a literal name wins over a "
53
+ "pattern, and a column that no pattern matches is dropped with a warning"),
54
+ "targets": ("a mapping of target columns to a preprocessor, a list of them or null; every target is a "
55
+ "batch field under its column name, and label makes a classification target (an int64 field, "
56
+ "with classes and class_weights exposed)"),
57
+ "filter": ("a pandas query kept for every row before the split, or a mapping of all (before the split) "
58
+ "and train, valid, test (each set after the split) to queries"),
59
+ "drop": "columns removed after the split and the filters, before the features are chosen",
60
+ "weights": ("row weights for a loss: a mapping of a batch field name to a weight column of the table or "
61
+ "to a mapping of pandas conditions to weights ({w: {\"price < 5\": 5}}); the first "
62
+ "condition a row meets wins and a row that meets none weighs 1; the weights are scaled to "
63
+ "mean one on the train set, and a loss reads them with sample_weight: w"),
64
+ "spectators": ("columns or patterns that are not fed to the model but are copied into the predictions "
65
+ "table, such as an id"),
66
+ "feed": "a call that turns the rows into samples another way, such as {use: window, size: 24, horizon: 6}",
67
+ "batch": f"{BATCH}; the default size is 128",
68
+ "stream": ("true or {chunk, fit_rows} reads the train set chunk by chunk instead of loading the file; it "
69
+ "needs a sequential or given split and no feed"),
70
+ },
71
+ "examples": [
72
+ lines(
73
+ "data:",
74
+ " use: table",
75
+ " file: housing.parquet",
76
+ " split: [0.7, 0.15, 0.15]",
77
+ ' features: {"x*": standard_scaler, size: [log, minmax_scaler]}',
78
+ " targets: {price: standard_scaler}",
79
+ ' filter: {all: "price > 0", train: "size < 500"}',
80
+ " spectators: [id]",
81
+ " batch: {size: 128, eval_size: 512}",
82
+ ),
83
+ lines(
84
+ "data:",
85
+ " use: table",
86
+ " file: churn.parquet",
87
+ " split: {use: kfold, folds: 5, fold: 0, valid_ratio: 0.15}",
88
+ ' features: {"num_*": standard_scaler, "cat_*": one_hot}',
89
+ " targets: {churned: label}",
90
+ " drop: [notes]",
91
+ " batch: 64",
92
+ ),
93
+ ],
94
+ },
95
+ "image_folder": {
96
+ "params": {
97
+ "folder": f"the directory whose subdirectories are the classes, each holding its images; {PATH}",
98
+ "split": ("required: a list of ratios for a shuffled split into train, valid and test, or a split call "
99
+ "such as {use: kfold, folds: 5, fold: 0}"),
100
+ "transform": ("the transforms of every set, in order: short names, calls or import paths, each from image "
101
+ "to image; the result always becomes a float tensor (C, H, W)"),
102
+ "train_transform": ("replaces transform for the train set, the place for augmentation such as random_crop "
103
+ "and random_flip; null uses transform"),
104
+ "batch": f"{BATCH}; the default size is 64",
105
+ "labels": ("true gives the label field (int64 codes of the class folders); false gives no target, for "
106
+ "autoencoders and generative models"),
107
+ "extensions": "the file suffixes read as images",
108
+ },
109
+ "examples": [
110
+ lines(
111
+ "data:",
112
+ " use: image_folder",
113
+ " folder: data/pets",
114
+ " split: [0.7, 0.15, 0.15]",
115
+ " transform: [{use: resize, size: 32}, to_tensor, {use: normalize, mean: imagenet}]",
116
+ " train_transform:",
117
+ " - {use: resize, size: 36}",
118
+ " - {use: random_crop, size: 32}",
119
+ " - random_flip",
120
+ " - to_tensor",
121
+ " - {use: normalize, mean: imagenet}",
122
+ " batch: {size: 16, eval_size: 256}",
123
+ ),
124
+ lines(
125
+ "data:",
126
+ " use: image_folder",
127
+ " folder: data/digits",
128
+ " split: [0.8, 0.1, 0.1]",
129
+ " labels: false",
130
+ " transform: [to_tensor]",
131
+ " batch: 16",
132
+ ),
133
+ ],
134
+ },
135
+ "text_lines": {
136
+ "params": {
137
+ "file": f"a utf-8 text file read line by line, empty lines skipped; {PATH}",
138
+ "tokenizer": ("char builds a character vocabulary from the train lines (id 0 is unknown); also a short "
139
+ "name such as char_tokenizer, a call, an import path or an object with encode, decode, size "
140
+ "and fit"),
141
+ "seq_len": ("the tokens of a window: input_ids holds seq_len tokens and targets the next token at each "
142
+ "place"),
143
+ "split": ("required: a list of ratios over the lines, or a split call such as {use: sequential, ratios: "
144
+ "[0.9, 0.1]}"),
145
+ "batch": f"{BATCH}; the default size is 64",
146
+ "stride": "the tokens between the starts of two windows; null takes seq_len, so the windows do not overlap",
147
+ "lowercase": "lowercases the text before the tokenizer reads it",
148
+ },
149
+ "examples": [
150
+ lines(
151
+ "data:",
152
+ " use: text_lines",
153
+ " file: data/corpus.txt",
154
+ " tokenizer: char",
155
+ " seq_len: 64",
156
+ " split: [0.9, 0.05, 0.05]",
157
+ " batch: 64",
158
+ ),
159
+ lines(
160
+ "data:",
161
+ " use: text_lines",
162
+ " file: data/lines.txt",
163
+ " seq_len: 128",
164
+ " stride: 64",
165
+ " lowercase: true",
166
+ " split: {use: sequential, ratios: [0.9, 0.1]}",
167
+ " batch: 32",
168
+ ),
169
+ ],
170
+ },
171
+ }
172
+
173
+
174
+ MODELS = {
175
+ "mlp": {
176
+ "params": {
177
+ "hidden": "the widths of the hidden layers, a list such as [128, 128] or one int",
178
+ "out": ("the width of the last linear layer: 1 for one regression target, \"@data.n_classes\" for the "
179
+ "logits of a classification"),
180
+ "activation": ("the activation after every hidden layer: relu, gelu, tanh, silu, sigmoid, elu, leaky_relu, "
181
+ "softplus or a module class"),
182
+ "dropout": "the dropout probability after every hidden activation; 0 adds no dropout",
183
+ "in_features": ("the input width; null lets the first layer infer it on the first forward pass, a number "
184
+ "or \"@data.n_features\" builds the weights at once"),
185
+ },
186
+ "examples": [
187
+ lines(
188
+ "models:",
189
+ " net: {use: mlp, hidden: [128, 128], out: 1}",
190
+ ),
191
+ lines(
192
+ "models:",
193
+ ' net: {use: mlp, hidden: [64, 32], out: "@data.n_classes", activation: gelu, dropout: 0.1}',
194
+ ),
195
+ ],
196
+ },
197
+ "stack": {
198
+ "params": {
199
+ "layers": ("the layers in order: calls such as {use: linear, out_features: 64}, short names of layers "
200
+ "without params (relu, flatten, last_step) or import paths; the first layer receives the model "
201
+ "input"),
202
+ },
203
+ "examples": [
204
+ lines(
205
+ "models:",
206
+ " net:",
207
+ " use: stack",
208
+ " layers:",
209
+ ' - {use: torch.nn.GRU, input_size: "@data.n_features", hidden_size: 64, batch_first: true}',
210
+ " - last_step",
211
+ " - {use: linear, out_features: 24}",
212
+ ),
213
+ ],
214
+ },
215
+ }
216
+
217
+
218
+ LOSSES = {
219
+ "mse": {
220
+ "params": {"reduction": REDUCTION, "size_average": DEPRECATED, "reduce": DEPRECATED},
221
+ "examples": [
222
+ lines(
223
+ "losses:",
224
+ " mse: mse",
225
+ ),
226
+ lines(
227
+ "losses:",
228
+ " rec: {use: mse, pred: x_hat, target: image}",
229
+ ),
230
+ ],
231
+ },
232
+ "l1": {
233
+ "params": {"reduction": REDUCTION, "size_average": DEPRECATED, "reduce": DEPRECATED},
234
+ "examples": [
235
+ lines(
236
+ "losses:",
237
+ " l1: l1",
238
+ ),
239
+ lines(
240
+ "losses:",
241
+ " mae: {use: l1, pred: y_yield, target: yield}",
242
+ ),
243
+ ],
244
+ },
245
+ "huber": {
246
+ "params": {
247
+ "delta": "the error size where the loss turns from quadratic to linear",
248
+ "reduction": REDUCTION,
249
+ },
250
+ "examples": [
251
+ lines(
252
+ "losses:",
253
+ " huber: {use: huber, delta: 0.5}",
254
+ ),
255
+ ],
256
+ },
257
+ "bce_logits": {
258
+ "params": {
259
+ "weight": "element weights that broadcast over the outputs; a YAML number or list becomes a tensor",
260
+ "pos_weight": ("weighs the positive class of every output, one number per output (above 1 favors recall); "
261
+ "a YAML number or list becomes a tensor"),
262
+ "reduction": REDUCTION,
263
+ "size_average": DEPRECATED,
264
+ "reduce": DEPRECATED,
265
+ },
266
+ "examples": [
267
+ lines(
268
+ "data:",
269
+ " use: table",
270
+ " file: anomaly_data.parquet",
271
+ ' filter: "is_anomaly in [0, 1]"',
272
+ " split: [0.7, 0.15, 0.15]",
273
+ ' features: {"x*": [abs, {use: log, base: 10, norm: 1200}, standard_scaler]}',
274
+ " targets: {is_anomaly: ~}",
275
+ "models:",
276
+ " net: {use: mlp, hidden: [64], out: 1}",
277
+ "losses:",
278
+ " bce: {use: bce_logits, pos_weight: 4.0}",
279
+ ),
280
+ ],
281
+ },
282
+ "poisson_nll": {
283
+ "params": {
284
+ "log_input": ("true reads the prediction as the log of the rate (loss exp(pred) - target * pred); false "
285
+ "reads it as the rate itself"),
286
+ "full": "adds the Stirling approximation term of log(target!)",
287
+ "eps": "added inside the log when log_input is false, so a zero rate does not give infinity",
288
+ "reduction": REDUCTION,
289
+ "size_average": DEPRECATED,
290
+ "reduce": DEPRECATED,
291
+ },
292
+ "examples": [
293
+ lines(
294
+ "losses:",
295
+ " l_defects: {use: poisson_nll, pred: y_defects, target: defects, log_input: true}",
296
+ ),
297
+ ],
298
+ },
299
+ "cross_entropy": {
300
+ "params": {
301
+ "weight": ("a weight per class, a list or \"@data.class_weights\" (inverse frequency, mean one); null "
302
+ "weighs every class the same"),
303
+ "label_smoothing": "the share of the target mass spread over all classes, from 0 to 1",
304
+ "classes_last": CLASSES_LAST,
305
+ },
306
+ "examples": [
307
+ lines(
308
+ "losses:",
309
+ ' ce: {use: cross_entropy, weight: "@data.class_weights", label_smoothing: 0.1}',
310
+ ),
311
+ lines(
312
+ "losses:",
313
+ " ce: {use: cross_entropy, target: targets}",
314
+ ),
315
+ ],
316
+ },
317
+ "weighted_sum": {
318
+ "params": {
319
+ "terms": ("a list of {of, weight, term}: of is a loss reference, weight its factor (default 1.0, a rule "
320
+ "may patch terms[i].weight) and term a key of a dict result; every term is also a series"),
321
+ },
322
+ "examples": [
323
+ lines(
324
+ "losses:",
325
+ " l_yield: {use: mse, pred: y_yield, target: yield}",
326
+ " l_moisture: {use: huber, pred: y_moisture, target: moisture}",
327
+ " total:",
328
+ " use: weighted_sum",
329
+ " terms:",
330
+ ' - {of: "@losses.l_yield", weight: 1.0}',
331
+ ' - {of: "@losses.l_moisture", weight: 0.5}',
332
+ ),
333
+ ],
334
+ },
335
+ "mdmm": {
336
+ "params": {
337
+ "objective": "the loss to minimize, a reference such as \"@losses.mse\"",
338
+ "constraints": ("a list of {of, epsilon, scale, damping, lmbda_init, term}: of is the constrained loss, "
339
+ "epsilon the value it is held at, scale and damping weigh the multiplier and the quadratic "
340
+ "damping, lmbda_init starts the multiplier and term picks a key of a dict result; every "
341
+ "constraint has a lambda, which an optimizer group with a negative lr trains"),
342
+ "term": "a key of the dict result of the objective to minimize; null takes its loss",
343
+ },
344
+ "examples": [
345
+ lines(
346
+ "losses:",
347
+ " mse: mse",
348
+ " mae: l1",
349
+ " total:",
350
+ " use: mdmm",
351
+ ' objective: "@losses.mse"',
352
+ " constraints:",
353
+ ' - {of: "@losses.mae", epsilon: 0.05, lmbda_init: 0.5}',
354
+ "optimizers:",
355
+ " main:",
356
+ " use: adam",
357
+ " lr: 1.0e-3",
358
+ ' over: ["@models.net", {of: "@losses.total", lr: -0.05}]',
359
+ ' minimizes: "@losses.total"',
360
+ ),
361
+ ],
362
+ },
363
+ "vae_elbo": {
364
+ "params": {
365
+ "recon": ("the reconstruction criterion, a reference such as \"@losses.mse\" whose pred and target name "
366
+ "the reconstruction and the input"),
367
+ "w_rec": "the weight of the reconstruction term; a rule may patch it",
368
+ "w_kl": ("the weight of the KL term: a number or a schedule of the update count such as {use: "
369
+ "linear_warmup, start: 0.0, end: 1.0, steps: 1000}"),
370
+ "mu": "the output name of the latent means",
371
+ "logvar": "the output name of the latent log variances",
372
+ },
373
+ "examples": [
374
+ lines(
375
+ "models:",
376
+ " vae: {use: vae_legos.Vae, latent: 32, outputs: [x_hat, mu, logvar]}",
377
+ "losses:",
378
+ " mse: {use: mse, pred: x_hat, target: image}",
379
+ " elbo:",
380
+ " use: vae_elbo",
381
+ ' recon: "@losses.mse"',
382
+ " w_rec: 1.0",
383
+ " w_kl: {use: linear_warmup, start: 0.0, end: 1.0, steps: 100}",
384
+ ),
385
+ ],
386
+ },
387
+ "wgan_gp_d": {
388
+ "params": {
389
+ "generator": ("the generator, a reference such as \"@models.generator\"; called as generator(z) or "
390
+ "generator(z, label)"),
391
+ "critic": ("the critic, a reference such as \"@models.critic\"; called as critic(images) or "
392
+ "critic(images, label)"),
393
+ "latent": f"{LATENT}, drawn from the noise stream",
394
+ "real": "the batch field of the real images",
395
+ "label": "the batch field of the class labels for a conditional pair; null for an unconditional one",
396
+ "gp_weight": "the weight of the gradient penalty on images between the real and the fake ones",
397
+ },
398
+ "examples": [
399
+ lines(
400
+ "losses:",
401
+ ' d: {use: wgan_gp_d, generator: "@models.generator", critic: "@models.critic", latent: 128,',
402
+ " real: image, label: label, gp_weight: 10}",
403
+ ' g: {use: wgan_g, generator: "@models.generator", critic: "@models.critic", latent: 128,',
404
+ " label: label}",
405
+ ),
406
+ ],
407
+ },
408
+ "wgan_g": {
409
+ "params": {
410
+ "generator": ("the generator, a reference such as \"@models.generator\"; called as generator(z) or "
411
+ "generator(z, label)"),
412
+ "critic": "the critic that scores the fresh fakes, a reference such as \"@models.critic\"",
413
+ "latent": f"{LATENT}, drawn from the noise stream",
414
+ "label": "the batch field of the class labels for a conditional pair; null for an unconditional one",
415
+ },
416
+ "examples": [
417
+ lines(
418
+ "losses:",
419
+ ' g: {use: wgan_g, generator: "@models.generator", critic: "@models.critic", latent: 128}',
420
+ "optimizers:",
421
+ ' g: {use: adam, lr: 1.0e-4, betas: [0.0, 0.9], over: "@models.generator", minimizes: "@losses.g"}',
422
+ ),
423
+ ],
424
+ },
425
+ "ddpm": {
426
+ "params": {
427
+ "model": ("the denoiser, a reference such as \"@models.unet\"; it is called as model(x_t, t) and predicts "
428
+ "the noise"),
429
+ "schedule": ("the beta schedule, {use: cosine_beta, steps: 1000} or {use: linear_beta, steps: 1000}; a "
430
+ "sampler reads it back as \"@losses.ddpm.schedule\""),
431
+ "x": "the batch field that is noised",
432
+ },
433
+ "examples": [
434
+ lines(
435
+ "losses:",
436
+ ' ddpm: {use: ddpm, model: "@models.unet", x: image, schedule: {use: cosine_beta, steps: 300}}',
437
+ ),
438
+ ],
439
+ },
440
+ "distill": {
441
+ "params": {
442
+ "student": "the model being trained, a reference such as \"@models.student\"",
443
+ "teacher": ("the guiding model, a reference; it runs without gradients, so freeze it and load its weights "
444
+ "with the weights key"),
445
+ "x": "the batch field fed to both models; null takes the first input of the data",
446
+ "label": "the batch field of the true classes for the cross entropy term; null takes the only target",
447
+ "temperature": "softens both distributions; the KL term is scaled by temperature squared",
448
+ "alpha": "the weight of the KL term; 1 - alpha weighs the cross entropy",
449
+ },
450
+ "examples": [
451
+ lines(
452
+ "models:",
453
+ " teacher:",
454
+ " use: distill_legos.Classifier",
455
+ " width: 32",
456
+ ' n_classes: "@data.n_classes"',
457
+ " weights: {run: runs/teacher, model: net, which: best}",
458
+ " freeze: true",
459
+ ' student: {use: distill_legos.Classifier, width: 8, n_classes: "@data.n_classes"}',
460
+ "losses:",
461
+ ' kd: {use: distill, student: "@models.student", teacher: "@models.teacher", temperature: 4.0,',
462
+ " alpha: 0.7}",
463
+ ),
464
+ ],
465
+ },
466
+ "ntxent": {
467
+ "params": {
468
+ "encoder": "the model that embeds every view, a reference such as \"@models.encoder\"",
469
+ "projector": "a head applied after the encoder, a reference; null uses the encoder output",
470
+ "views": ("the batch field with two views per item, (B, 2, C, H, W), as two_views in the train transform "
471
+ "makes them"),
472
+ "temperature": "divides the cosine similarities; a lower value sharpens the contrast",
473
+ },
474
+ "examples": [
475
+ lines(
476
+ "losses:",
477
+ ' ntxent: {use: ntxent, encoder: "@models.encoder", projector: "@models.projector", views: image,',
478
+ " temperature: 0.5, on: [train]}",
479
+ ),
480
+ ],
481
+ },
482
+ }
483
+
484
+
485
+ METRICS = {
486
+ "rmse": {
487
+ "examples": [
488
+ lines(
489
+ "metrics:",
490
+ " rmse: rmse",
491
+ ),
492
+ lines(
493
+ "metrics:",
494
+ " rmse_yield: {use: rmse, pred: y_yield, target: yield}",
495
+ ),
496
+ ],
497
+ },
498
+ "mae": {
499
+ "examples": [
500
+ lines(
501
+ "metrics:",
502
+ " mae: mae",
503
+ ),
504
+ lines(
505
+ "metrics:",
506
+ " recon: {use: mae, pred: x_hat, target: image}",
507
+ ),
508
+ ],
509
+ },
510
+ "accuracy": {
511
+ "params": {
512
+ "num_classes": COUNTED,
513
+ "average": ("micro is the share of rows predicted right; macro is the mean recall over the classes present "
514
+ "in the targets"),
515
+ },
516
+ "examples": [
517
+ lines(
518
+ "metrics:",
519
+ " accuracy: accuracy",
520
+ " balanced: {use: accuracy, average: macro}",
521
+ ),
522
+ ],
523
+ },
524
+ "f1": {
525
+ "params": {
526
+ "num_classes": f"{COUNTED}; with num_classes, a class that never appears scores 0 under macro",
527
+ "average": ("macro is the mean f1 of the classes, micro the share of rows right, weighted the mean "
528
+ "weighted by support, binary the f1 of class 1"),
529
+ },
530
+ "examples": [
531
+ lines(
532
+ "metrics:",
533
+ ' f1: {use: f1, num_classes: "@data.n_classes", average: macro}',
534
+ ),
535
+ ],
536
+ },
537
+ "auroc": {
538
+ "params": {"num_classes": SCORED},
539
+ "examples": [
540
+ lines(
541
+ "metrics:",
542
+ " auroc: {use: auroc, pred: score, target: is_anomaly}",
543
+ ),
544
+ ],
545
+ },
546
+ "average_precision": {
547
+ "params": {"num_classes": SCORED},
548
+ "examples": [
549
+ lines(
550
+ "metrics:",
551
+ " average_precision: {use: average_precision, pred: score, target: is_anomaly}",
552
+ ),
553
+ ],
554
+ },
555
+ "perplexity": {
556
+ "params": {"classes_last": CLASSES_LAST},
557
+ "examples": [
558
+ lines(
559
+ "metrics:",
560
+ " ppl: {use: perplexity, target: targets}",
561
+ ),
562
+ ],
563
+ },
564
+ "fid": {
565
+ "params": {
566
+ "model": ("the generator, a reference such as \"@models.generator.ema\"; called as model(z) or model(z, "
567
+ "label)"),
568
+ "latent": f"{LATENT}, drawn from the fid stream",
569
+ "real": "the batch field of the real images",
570
+ "label": "the batch field of the class labels for a conditional generator; null for an unconditional one",
571
+ "n": "the real images, and as many fakes, compared at every evaluation",
572
+ "extractor": ("the import path of a function from images to features; null pools the pixels to 16 by 16, "
573
+ "which is cheap but cruder than an inception network"),
574
+ "batch": "the generator batch size while the fakes are made",
575
+ },
576
+ "examples": [
577
+ lines(
578
+ "metrics:",
579
+ ' fid: {use: fid, model: "@models.generator.ema", latent: 128, real: image, label: label, n: 256,',
580
+ " every: 5, on: [valid]}",
581
+ ),
582
+ ],
583
+ },
584
+ }
585
+
586
+
587
+ OPTIMIZERS = {
588
+ "adam": {
589
+ "params": {
590
+ "lr": LR,
591
+ "betas": f"{BETAS}; GANs often take [0.0, 0.9] or [0.5, 0.999]",
592
+ "eps": EPS,
593
+ "weight_decay": "an L2 penalty added to the gradient; adamw decouples it instead",
594
+ "amsgrad": "keeps the largest squared gradient average seen, the AMSGrad variant",
595
+ "maximize": MAXIMIZE,
596
+ "decoupled_weight_decay": "true applies weight_decay the AdamW way",
597
+ },
598
+ "examples": [
599
+ lines(
600
+ "optimizers:",
601
+ ' main: {use: adam, lr: 1.0e-3, over: "@models.net", minimizes: "@losses.mse"}',
602
+ ),
603
+ lines(
604
+ "optimizers:",
605
+ ' d: {use: adam, lr: 1.0e-4, betas: [0.0, 0.9], over: "@models.critic", minimizes: "@losses.d"}',
606
+ ' g: {use: adam, lr: 1.0e-4, betas: [0.0, 0.9], over: "@models.generator", minimizes: "@losses.g"}',
607
+ ),
608
+ ],
609
+ },
610
+ "adamw": {
611
+ "params": {
612
+ "lr": LR,
613
+ "betas": f"{BETAS}; language models often take [0.9, 0.95]",
614
+ "eps": EPS,
615
+ "weight_decay": "the decoupled weight decay, applied to the weights apart from the gradient step",
616
+ "amsgrad": "keeps the largest squared gradient average seen, the AMSGrad variant",
617
+ "maximize": MAXIMIZE,
618
+ },
619
+ "examples": [
620
+ lines(
621
+ "optimizers:",
622
+ " main:",
623
+ " use: adamw",
624
+ " lr: 1.0e-3",
625
+ " weight_decay: 1.0e-2",
626
+ " over:",
627
+ ' - {of: "@models.net", match: "backbone.*", lr: 1.0e-4}',
628
+ ' - "@models.net"',
629
+ ' minimizes: "@losses.ce"',
630
+ " schedule: {use: cosine, steps: 5000, warmup: 200}",
631
+ ),
632
+ ],
633
+ },
634
+ "sgd": {
635
+ "params": {
636
+ "lr": LR,
637
+ "momentum": "the momentum factor; 0 is plain gradient descent",
638
+ "dampening": "damps the gradient added to the momentum",
639
+ "weight_decay": "an L2 penalty added to the gradient",
640
+ "nesterov": "Nesterov momentum; needs momentum above 0 and dampening 0",
641
+ "maximize": MAXIMIZE,
642
+ },
643
+ "examples": [
644
+ lines(
645
+ "optimizers:",
646
+ " main:",
647
+ " use: sgd",
648
+ " lr: 0.1",
649
+ " momentum: 0.9",
650
+ " nesterov: true",
651
+ " weight_decay: 5.0e-4",
652
+ ' over: "@models.net"',
653
+ ' minimizes: "@losses.ce"',
654
+ " schedule: {use: cosine, steps: 360}",
655
+ ),
656
+ ],
657
+ },
658
+ }
659
+
660
+
661
+ SCHEDULES = {
662
+ "cosine": {
663
+ "params": {
664
+ "steps": "the update where the decay reaches floor, counted from the start (the warmup included)",
665
+ "warmup": "the updates of the linear rise from 0 to 1 before the decay",
666
+ "floor": "the factor at the end of the decay and after it",
667
+ },
668
+ "examples": [
669
+ lines(
670
+ "optimizers:",
671
+ " main:",
672
+ " use: adamw",
673
+ " lr: 6.0e-4",
674
+ ' over: "@models.lm"',
675
+ ' minimizes: "@losses.ce"',
676
+ " schedule: {use: cosine, warmup: 50, steps: 1000, floor: 0.1}",
677
+ ),
678
+ ],
679
+ },
680
+ "warmup": {
681
+ "params": {"steps": "the updates of the linear rise from 0 to 1; the factor stays 1 afterwards"},
682
+ "examples": [
683
+ lines(
684
+ "optimizers:",
685
+ " main:",
686
+ " use: adamw",
687
+ " lr: 2.0e-4",
688
+ ' over: "@models.unet"',
689
+ ' minimizes: "@losses.ddpm"',
690
+ " schedule: {use: warmup, steps: 80}",
691
+ ),
692
+ ],
693
+ },
694
+ "linear_warmup": {
695
+ "params": {
696
+ "start": "the value at update 0",
697
+ "end": "the value reached at steps updates and kept afterwards",
698
+ "steps": "the updates of the linear move from start to end",
699
+ },
700
+ "examples": [
701
+ lines(
702
+ "losses:",
703
+ " elbo:",
704
+ " use: vae_elbo",
705
+ ' recon: "@losses.mse"',
706
+ " w_kl: {use: linear_warmup, start: 0.0, end: 1.0, steps: 1000}",
707
+ ),
708
+ lines(
709
+ "optimizers:",
710
+ " main:",
711
+ " use: adam",
712
+ " lr: 1.0e-3",
713
+ ' over: "@models.net"',
714
+ ' minimizes: "@losses.mse"',
715
+ " schedule: {use: linear_warmup, start: 1.0, end: 0.1, steps: 5000}",
716
+ ),
717
+ ],
718
+ },
719
+ "step_decay": {
720
+ "params": {
721
+ "every": "the updates between two decays",
722
+ "gamma": "the factor applied at every decay",
723
+ },
724
+ "examples": [
725
+ lines(
726
+ "optimizers:",
727
+ " main:",
728
+ " use: sgd",
729
+ " lr: 0.1",
730
+ " momentum: 0.9",
731
+ ' over: "@models.net"',
732
+ ' minimizes: "@losses.ce"',
733
+ " schedule: {use: step_decay, every: 2000, gamma: 0.5}",
734
+ ),
735
+ ],
736
+ },
737
+ }
738
+
739
+
740
+ STEPS = {
741
+ "supervised": {
742
+ "params": {"order": ORDER, "amp": AMP, "grad_clip": GRAD_CLIP, "accumulate": ACCUMULATE},
743
+ "examples": [
744
+ lines(
745
+ "train:",
746
+ " epochs: 20",
747
+ " step: {use: supervised, amp: true, grad_clip: 1.0}",
748
+ ),
749
+ lines(
750
+ "train:",
751
+ " updates: {total: 1000, turn: 100}",
752
+ " step: {use: supervised, accumulate: 4}",
753
+ ),
754
+ ],
755
+ },
756
+ "alternating": {
757
+ "params": {
758
+ "order": ORDER,
759
+ "repeat": ("a mapping of optimizer names to the steps each takes per round, such as {d: 5, g: 1}; a "
760
+ "missing name takes 1"),
761
+ "fresh_batch": "true gives every step a new batch; false shares one batch per round",
762
+ "amp": AMP,
763
+ "grad_clip": GRAD_CLIP,
764
+ "accumulate": ACCUMULATE,
765
+ },
766
+ "examples": [
767
+ lines(
768
+ "train:",
769
+ " epochs: 60",
770
+ " step: {use: alternating, order: [d, g], repeat: {d: 5, g: 1}, fresh_batch: true}",
771
+ ),
772
+ ],
773
+ },
774
+ }
775
+
776
+
777
+ TRIGGERS = {
778
+ "after_epoch": {
779
+ "params": {"at": "the turn number from which it fires; absolute, so a resumed run counts on"},
780
+ "examples": [
781
+ lines(
782
+ "rules:",
783
+ " warm:",
784
+ " when: {use: after_epoch, at: 5}",
785
+ " set: {optimizers.main.lr: {times: 0.5}}",
786
+ ),
787
+ ],
788
+ },
789
+ "every": {
790
+ "params": {"epochs": "fires on every turn whose number is a multiple of epochs; pair it with once: false"},
791
+ "examples": [
792
+ lines(
793
+ "rules:",
794
+ " samples:",
795
+ " when: {use: every, epochs: 5}",
796
+ " once: false",
797
+ " run: {use: write_samples, n: 16}",
798
+ ),
799
+ ],
800
+ },
801
+ "plateau": {
802
+ "params": {
803
+ "watch": WATCH,
804
+ "patience": "the turns without an improvement before it fires",
805
+ "mode": "min when lower is better, max when higher is better",
806
+ "min_delta": "the smallest change that counts as an improvement",
807
+ },
808
+ "examples": [
809
+ lines(
810
+ "rules:",
811
+ " stop:",
812
+ " when: {use: plateau, watch: val/rmse, patience: 8}",
813
+ " stop: true",
814
+ ),
815
+ lines(
816
+ "rules:",
817
+ " stop:",
818
+ " when: {use: plateau, watch: val/f1, mode: max, patience: 8, min_delta: 0.001}",
819
+ " stop: true",
820
+ ),
821
+ ],
822
+ },
823
+ "above": {
824
+ "params": {"watch": WATCH, "value": "the threshold the series must be strictly above"},
825
+ "examples": [
826
+ lines(
827
+ "rules:",
828
+ " cool_down:",
829
+ " when: {use: above, watch: val/accuracy, value: 0.9}",
830
+ " set: {optimizers.main.lr: 1.0e-4}",
831
+ ),
832
+ ],
833
+ },
834
+ "below": {
835
+ "params": {"watch": WATCH, "value": "the threshold the series must be strictly below"},
836
+ "examples": [
837
+ lines(
838
+ "rules:",
839
+ " to_huber:",
840
+ " when: {use: below, watch: train/mse, value: 0.05}",
841
+ ' set: {optimizers.main.minimizes: "@losses.huber"}',
842
+ ),
843
+ ],
844
+ },
845
+ "time_budget": {
846
+ "params": {"minutes": "the wall clock minutes since the first turn that asked it"},
847
+ "examples": [
848
+ lines(
849
+ "rules:",
850
+ " budget:",
851
+ " when: {use: time_budget, minutes: 90}",
852
+ " stop: true",
853
+ ),
854
+ ],
855
+ },
856
+ }
857
+
858
+
859
+ ACTIONS = {
860
+ "write_samples": {
861
+ "params": {
862
+ "sampler": "a sampler call or \"@generate\"; null uses the sampler of the generate section",
863
+ "n": "the samples drawn at every firing, written to samples/turn_<k>",
864
+ },
865
+ "examples": [
866
+ lines(
867
+ "rules:",
868
+ " samples:",
869
+ " when: {use: every, epochs: 5}",
870
+ " once: false",
871
+ ' run: {use: write_samples, sampler: "@generate", n: 16}',
872
+ ),
873
+ ],
874
+ },
875
+ }
876
+
877
+
878
+ LOGGERS = {
879
+ "tensorboard": {
880
+ "params": {
881
+ "dir": ("the directory of the event files; null writes to <record>/tensorboard (a run without a "
882
+ "record needs it)"),
883
+ "updates": ("true writes loss/, lr/ and grad_norm/ of every update against the update count; false writes "
884
+ "every series once per turn"),
885
+ "flush_every": "flushes the event file every k turns",
886
+ },
887
+ "examples": [
888
+ lines(
889
+ "train:",
890
+ " epochs: 20",
891
+ " log: [tensorboard]",
892
+ ),
893
+ lines(
894
+ "train:",
895
+ " epochs: 20",
896
+ " log: [{use: tensorboard, updates: false, flush_every: 5}]",
897
+ ),
898
+ ],
899
+ },
900
+ "echo": {
901
+ "params": {
902
+ "series": "a series name or a list of them; null prints every numeric series of the turn",
903
+ "stream": LOCAL,
904
+ },
905
+ "examples": [
906
+ lines(
907
+ "train:",
908
+ " epochs: 20",
909
+ " log: [{use: echo, series: [val/rmse, lr/main]}]",
910
+ ),
911
+ ],
912
+ },
913
+ }
914
+
915
+
916
+ SAMPLERS = {
917
+ "gan_sampler": {
918
+ "params": {
919
+ "model": ("the generator, a reference such as \"@models.generator.ema\"; called as model(z) or "
920
+ "model(z, label)"),
921
+ "latent": f"{LATENT}, drawn from the samples stream",
922
+ "n_classes": ("labels 0 to n_classes - 1 cycle over the samples and go in as model(z, label); null for an "
923
+ "unconditional generator"),
924
+ "n": SAMPLES,
925
+ },
926
+ "examples": [
927
+ lines(
928
+ 'generate: {use: gan_sampler, model: "@models.generator.ema", latent: 128,',
929
+ ' n_classes: "@data.n_classes", n: 64}',
930
+ ),
931
+ ],
932
+ },
933
+ "latent_sampler": {
934
+ "params": {
935
+ "model": "the decoder, a reference such as \"@models.ae.decoder\"",
936
+ "latent": "the width of the standard normal latents fed to the decoder",
937
+ "n": SAMPLES,
938
+ },
939
+ "examples": [
940
+ lines(
941
+ 'generate: {use: latent_sampler, model: "@models.ae.decoder", latent: 32, n: 64}',
942
+ ),
943
+ ],
944
+ },
945
+ "ddpm_sampler": {
946
+ "params": {
947
+ "model": "the denoiser, called as model(x_t, t); often the EMA copy, \"@models.unet.ema\"",
948
+ "schedule": "the beta schedule of the training loss, \"@losses.ddpm.schedule\"",
949
+ "shape": "the shape of one sample, [C, H, W]",
950
+ "n": SAMPLES,
951
+ "steps": ("null walks every step of the schedule with fresh noise; a number takes that many evenly spaced "
952
+ "deterministic steps, which is faster"),
953
+ },
954
+ "examples": [
955
+ lines(
956
+ "generate:",
957
+ " use: ddpm_sampler",
958
+ ' model: "@models.unet.ema"',
959
+ ' schedule: "@losses.ddpm.schedule"',
960
+ " shape: [3, 16, 16]",
961
+ " n: 64",
962
+ " steps: 50",
963
+ ),
964
+ ],
965
+ },
966
+ "lm_sampler": {
967
+ "params": {
968
+ "model": "the language model, a reference; it returns logits (batch, tokens, vocabulary)",
969
+ "tokenizer": ("the tokenizer that encodes the prompt and decodes the draws, \"@data.tokenizer\"; null "
970
+ "falls back to the tokenizer of the data"),
971
+ "prompt": "the text to continue; empty starts from token 0",
972
+ "max_new_tokens": "the tokens drawn after the prompt",
973
+ "temperature": "divides the logits before the draw; 0 picks the most likely token every time",
974
+ "top_k": "keeps only the k most likely tokens at every draw; null keeps them all",
975
+ "n": "the texts drawn",
976
+ },
977
+ "examples": [
978
+ lines(
979
+ "generate:",
980
+ " use: lm_sampler",
981
+ ' model: "@models.lm"',
982
+ ' tokenizer: "@data.tokenizer"',
983
+ ' prompt: "ROMEO:"',
984
+ " max_new_tokens: 400",
985
+ " temperature: 0.8",
986
+ " top_k: 20",
987
+ ),
988
+ ],
989
+ },
990
+ }
991
+
992
+
993
+ PLOTS = {
994
+ "loss_curve": {
995
+ "params": {"series": "a series name or a list of them; null draws every train/ and val/ series"},
996
+ "examples": [
997
+ lines(
998
+ "plots:",
999
+ " loss_curve: loss_curve",
1000
+ ),
1001
+ lines(
1002
+ "plots:",
1003
+ " loss_curve: {use: loss_curve, series: [train/elbo/recon, train/elbo/kl, val/recon_rmse]}",
1004
+ ),
1005
+ ],
1006
+ },
1007
+ "pred_vs_true": {
1008
+ "params": {
1009
+ "pairs": ("a mapping of outputs (or pred_ columns) to target columns; null draws every numeric pair it "
1010
+ "finds"),
1011
+ },
1012
+ "examples": [
1013
+ lines(
1014
+ "plots:",
1015
+ " pred_vs_true: pred_vs_true",
1016
+ ),
1017
+ lines(
1018
+ "plots:",
1019
+ " pred_vs_true: {use: pred_vs_true, pairs: {y_yield: yield, y_moisture: moisture}}",
1020
+ ),
1021
+ ],
1022
+ },
1023
+ "confusion_matrix": {
1024
+ "params": {"pred": PLOT_PRED, "target": PLOT_TARGET},
1025
+ "examples": [
1026
+ lines(
1027
+ "plots:",
1028
+ " confusion: confusion_matrix",
1029
+ ),
1030
+ lines(
1031
+ "plots:",
1032
+ " confusion: {use: confusion_matrix, pred: net, target: churned}",
1033
+ ),
1034
+ ],
1035
+ },
1036
+ "class_histogram": {
1037
+ "params": {
1038
+ "pred": PLOT_PRED,
1039
+ "target": PLOT_TARGET,
1040
+ "bins": "the number of score bins; probabilities are binned over [0, 1]",
1041
+ },
1042
+ "examples": [
1043
+ lines(
1044
+ "plots:",
1045
+ " scores: {use: class_histogram, bins: 30}",
1046
+ ),
1047
+ ],
1048
+ },
1049
+ "binary_roc": {
1050
+ "params": {"pred": PLOT_PRED, "target": PLOT_TARGET},
1051
+ "examples": [
1052
+ lines(
1053
+ "plots:",
1054
+ " roc: binary_roc",
1055
+ ),
1056
+ ],
1057
+ },
1058
+ "binary_precision_recall_curve": {
1059
+ "params": {"pred": PLOT_PRED, "target": PLOT_TARGET},
1060
+ "examples": [
1061
+ lines(
1062
+ "plots:",
1063
+ " pr: {use: binary_precision_recall_curve, pred: net, target: churned}",
1064
+ ),
1065
+ ],
1066
+ },
1067
+ "forecast_samples": {
1068
+ "params": {
1069
+ "n": "the windows drawn, spread evenly over the predicted rows",
1070
+ "pred": PLOT_PRED,
1071
+ "target": PLOT_TARGET,
1072
+ },
1073
+ "examples": [
1074
+ lines(
1075
+ "plots:",
1076
+ " forecast: {use: forecast_samples, n: 4}",
1077
+ ),
1078
+ ],
1079
+ },
1080
+ "image_pairs": {
1081
+ "params": {
1082
+ "n": "the images drawn, each above its reconstruction",
1083
+ "set": "the set the images come from: test, valid or train",
1084
+ "ctx": "the run context, which kalfa passes itself during a run and in kalfa plots; never write it",
1085
+ },
1086
+ "examples": [
1087
+ lines(
1088
+ "plots:",
1089
+ " reconstructions: {use: image_pairs, n: 8, set: valid}",
1090
+ ),
1091
+ ],
1092
+ },
1093
+ "samples_grid": {
1094
+ "params": {
1095
+ "n": "the images in the grid",
1096
+ "file": ("the name under samples/: samples (written by generate) or turn_<k> (written by write_samples), "
1097
+ "a .pt or a .txt file"),
1098
+ },
1099
+ "examples": [
1100
+ lines(
1101
+ "plots:",
1102
+ " samples: {use: samples_grid, n: 64}",
1103
+ ),
1104
+ lines(
1105
+ "plots:",
1106
+ " turn_10: {use: samples_grid, n: 16, file: turn_10}",
1107
+ ),
1108
+ ],
1109
+ },
1110
+ }
1111
+
1112
+
1113
+ STRATEGIES = {
1114
+ "grid": {
1115
+ "params": {
1116
+ "steps": ("the points of every range entry ({float: [a, b]} evenly, {log: [a, b]} geometric, {int: [a, "
1117
+ "b]}); null allows lists only"),
1118
+ },
1119
+ "examples": [
1120
+ lines(
1121
+ "params: {lr: 1.0e-3, width: 128}",
1122
+ "sweep:",
1123
+ " strategy: grid",
1124
+ " space:",
1125
+ " lr: [1.0e-2, 1.0e-3, 1.0e-4]",
1126
+ " width: [64, 128, 256]",
1127
+ " objective: {watch: val/rmse, mode: min, at: best}",
1128
+ " record: runs/sweep_housing",
1129
+ ),
1130
+ lines(
1131
+ "params: {lr: 1.0e-3}",
1132
+ "sweep:",
1133
+ " strategy: {use: grid, steps: 4}",
1134
+ " space:",
1135
+ " lr: {log: [1.0e-4, 1.0e-1]}",
1136
+ " objective: {watch: val/rmse, mode: min}",
1137
+ " record: runs/sweep_lr",
1138
+ ),
1139
+ ],
1140
+ },
1141
+ "random_search": {
1142
+ "params": {
1143
+ "trials": "the number of points; a point drawn twice is drawn again",
1144
+ "seed": "the seed of numpy's default_rng; null takes the top level seed",
1145
+ },
1146
+ "examples": [
1147
+ lines(
1148
+ "params: {lr: 1.0e-3, width: 128}",
1149
+ "sweep:",
1150
+ " strategy: {use: random_search, trials: 12, seed: 1}",
1151
+ " space:",
1152
+ " lr: {log: [1.0e-4, 1.0e-2]}",
1153
+ " width: {int: [16, 256]}",
1154
+ " objective: {watch: val/rmse, mode: min, at: best}",
1155
+ " record: runs/sweep_housing_random",
1156
+ ),
1157
+ ],
1158
+ },
1159
+ "optuna": {
1160
+ "params": {
1161
+ "trials": "the number of points, asked one after another",
1162
+ "sampler": "tpe (adaptive, learns from the finished points) or random",
1163
+ "seed": "the seed of the sampler; null takes the top level seed",
1164
+ },
1165
+ "examples": [
1166
+ lines(
1167
+ "params: {lr: 1.0e-3, width: 128}",
1168
+ "sweep:",
1169
+ " strategy: {use: optuna, trials: 12, sampler: tpe}",
1170
+ " space:",
1171
+ " lr: {log: [1.0e-4, 1.0e-2]}",
1172
+ " width: {int: [16, 256]}",
1173
+ " objective: {watch: val/rmse, mode: min, at: best}",
1174
+ " record: runs/sweep_housing_optuna",
1175
+ ),
1176
+ ],
1177
+ },
1178
+ }
1179
+
1180
+
1181
+ def stacked(*layers):
1182
+ return lines("models:", " net:", " use: stack", " layers:", *[f" - {layer}" for layer in layers])
1183
+
1184
+
1185
+ LAYERS = {
1186
+ "linear": {
1187
+ "params": {
1188
+ "out_features": "the output width; the input width is inferred on the first forward pass",
1189
+ "bias": "adds a learned bias",
1190
+ "device": DEVICE,
1191
+ "dtype": DTYPE,
1192
+ },
1193
+ "examples": [stacked("{use: linear, out_features: 64}", "relu", "{use: linear, out_features: 1}")],
1194
+ },
1195
+ "conv2d": {
1196
+ "params": {
1197
+ "out_channels": "the output channels; the input channels are inferred on the first forward pass",
1198
+ "kernel_size": "the kernel size, an int or [height, width]",
1199
+ "stride": "the step of the kernel, an int or [height, width]",
1200
+ "padding": "zeros added on every side, an int, [height, width], same or valid",
1201
+ "dilation": "the spacing between kernel elements",
1202
+ "groups": "splits the channels into groups convolved apart",
1203
+ "bias": "adds a learned bias",
1204
+ "padding_mode": "zeros, reflect, replicate or circular",
1205
+ "device": DEVICE,
1206
+ "dtype": DTYPE,
1207
+ },
1208
+ "examples": [stacked("{use: conv2d, out_channels: 16, kernel_size: 3, padding: 1}", "relu",
1209
+ "{use: torch.nn.MaxPool2d, kernel_size: 2}", "flatten",
1210
+ '{use: linear, out_features: "@data.n_classes"}')],
1211
+ },
1212
+ "embedding": {
1213
+ "params": {
1214
+ "num_embeddings": "the vocabulary size, such as \"@data.vocab_size\"",
1215
+ "embedding_dim": "the width of every embedding vector",
1216
+ "padding_idx": "an id whose vector stays zero and gets no gradient",
1217
+ "max_norm": "renormalises the looked up vectors to at most this norm",
1218
+ "norm_type": "the p of the norm max_norm uses",
1219
+ "scale_grad_by_freq": "scales the gradients by the inverse frequency of the ids in the batch",
1220
+ "sparse": "gives sparse gradients, which only some optimizers take",
1221
+ "device": DEVICE,
1222
+ "dtype": DTYPE,
1223
+ },
1224
+ "examples": [lines(
1225
+ "models:",
1226
+ " lm:",
1227
+ " use: stack",
1228
+ " layers:",
1229
+ ' - {use: embedding, num_embeddings: "@data.vocab_size", embedding_dim: 64}',
1230
+ ' - {use: linear, out_features: "@data.vocab_size"}',
1231
+ )],
1232
+ },
1233
+ "layer_norm": {
1234
+ "params": {
1235
+ "normalized_shape": "the trailing shape that is normalised, such as 64 or [64]",
1236
+ "eps": EPS,
1237
+ "elementwise_affine": "learns a scale and a shift per element",
1238
+ "bias": "learns the shift too when elementwise_affine is true",
1239
+ "device": DEVICE,
1240
+ "dtype": DTYPE,
1241
+ },
1242
+ "examples": [stacked("{use: linear, out_features: 64}", "{use: layer_norm, normalized_shape: 64}", "gelu",
1243
+ "{use: linear, out_features: 1}")],
1244
+ },
1245
+ "batch_norm": {
1246
+ "params": {
1247
+ "eps": EPS,
1248
+ "momentum": "the update rate of the running mean and variance",
1249
+ "affine": "learns a scale and a shift per feature",
1250
+ "track_running_stats": "keeps running statistics for evaluation; false uses the batch statistics always",
1251
+ "bias": "learns the shift too when affine is true",
1252
+ "device": DEVICE,
1253
+ "dtype": DTYPE,
1254
+ },
1255
+ "examples": [stacked("{use: linear, out_features: 64}", "batch_norm", "relu",
1256
+ "{use: linear, out_features: 1}")],
1257
+ },
1258
+ "dropout": {
1259
+ "params": {"p": "the probability that an element is zeroed in training", "inplace": INPLACE},
1260
+ "examples": [stacked("{use: linear, out_features: 128}", "relu", "{use: dropout, p: 0.2}",
1261
+ "{use: linear, out_features: 1}")],
1262
+ },
1263
+ "flatten": {
1264
+ "params": {"start_dim": "the first dimension that is flattened",
1265
+ "end_dim": "the last dimension that is flattened"},
1266
+ "examples": [stacked("{use: conv2d, out_channels: 8, kernel_size: 3}", "relu", "flatten",
1267
+ '{use: linear, out_features: "@data.n_classes"}')],
1268
+ },
1269
+ "relu": {
1270
+ "params": {"inplace": INPLACE},
1271
+ "examples": [stacked("{use: linear, out_features: 64}", "relu", "{use: linear, out_features: 1}")],
1272
+ },
1273
+ "gelu": {
1274
+ "params": {"approximate": "none for the exact form, tanh for the faster approximation"},
1275
+ "examples": [
1276
+ stacked("{use: linear, out_features: 64}", "gelu", "{use: linear, out_features: 1}"),
1277
+ lines("models:", " net: {use: mlp, hidden: [64, 64], out: 1, activation: gelu}"),
1278
+ ],
1279
+ },
1280
+ "silu": {
1281
+ "params": {"inplace": INPLACE},
1282
+ "examples": [stacked("{use: linear, out_features: 64}", "silu", "{use: linear, out_features: 1}")],
1283
+ },
1284
+ "tanh": {
1285
+ "examples": [stacked("{use: linear, out_features: 64}", "tanh", "{use: linear, out_features: 1}")],
1286
+ },
1287
+ "sigmoid": {
1288
+ "examples": [stacked("{use: linear, out_features: 64}", "relu", "{use: linear, out_features: 1}", "sigmoid")],
1289
+ },
1290
+ "last_step": {
1291
+ "examples": [stacked('{use: torch.nn.LSTM, input_size: "@data.n_features", hidden_size: 32, batch_first: true}',
1292
+ "last_step", "{use: linear, out_features: 6}")],
1293
+ },
1294
+ }
1295
+
1296
+
1297
+ def table_with(features=None, targets="{price: standard_scaler}", split="[0.7, 0.15, 0.15]", file="housing.parquet",
1298
+ extra=()):
1299
+ rows = ["data:", " use: table", f" file: {file}", f" split: {split}"]
1300
+ if features:
1301
+ rows.append(f" features: {features}")
1302
+ rows.append(f" targets: {targets}")
1303
+ return lines(*rows, *extra)
1304
+
1305
+
1306
+ def images_with(*transform, folder="data/pets", key="transform"):
1307
+ rows = ["data:", " use: image_folder", f" folder: {folder}", " split: [0.8, 0.1, 0.1]", f" {key}:"]
1308
+ return lines(*rows, *[f" - {step}" for step in transform])
1309
+
1310
+
1311
+ PREPROCESSORS = {
1312
+ "standard_scaler": {
1313
+ "params": {
1314
+ "with_mean": "subtracts the mean of every column",
1315
+ "with_std": "divides by the standard deviation of every column",
1316
+ "copy": "lets scikit learn copy the values; leave it true",
1317
+ },
1318
+ "examples": [table_with('{"x*": standard_scaler}')],
1319
+ },
1320
+ "minmax_scaler": {
1321
+ "params": {
1322
+ "feature_range": ("the range the train values map onto, as [low, high]; kalfa passes the YAML list as the "
1323
+ "tuple scikit learn wants"),
1324
+ "clip": "clips the values of later rows into feature_range",
1325
+ "copy": "lets scikit learn copy the values; leave it true",
1326
+ },
1327
+ "examples": [table_with('{"x*": standard_scaler, size: [log, minmax_scaler]}'),
1328
+ table_with('{"x*": {use: minmax_scaler, feature_range: [-1, 1]}}')],
1329
+ },
1330
+ "robust_scaler": {
1331
+ "params": {
1332
+ "with_centering": "subtracts the median of every column",
1333
+ "with_scaling": "divides by the interquartile range of every column",
1334
+ "quantile_range": ("the lower and upper quantiles of the range, as [25.0, 75.0]; kalfa passes the YAML "
1335
+ "list as the tuple scikit learn wants"),
1336
+ "unit_variance": "rescales so that normal data ends with variance 1",
1337
+ "copy": "lets scikit learn copy the values; leave it true",
1338
+ },
1339
+ "examples": [table_with('{"x*": robust_scaler}', "{price: robust_scaler}")],
1340
+ },
1341
+ "one_hot": {
1342
+ "examples": [table_with('{"num_*": standard_scaler, "cat_*": one_hot}', "{churned: label}",
1343
+ file="churn.parquet")],
1344
+ },
1345
+ "label": {
1346
+ "examples": [table_with('{"num_*": standard_scaler, "cat_*": one_hot}', "{churned: label}",
1347
+ file="churn.parquet")],
1348
+ },
1349
+ "abs": {
1350
+ "examples": [table_with('{"x*": [abs, {use: log, base: 10, norm: 1200}, standard_scaler]}', "{is_anomaly: ~}",
1351
+ file="anomaly_data.parquet")],
1352
+ },
1353
+ "log": {
1354
+ "params": {
1355
+ "base": "the base of the logarithm, positive and not 1",
1356
+ "norm": ("divides the values before the log, log(1 + x / norm); positive, and the values must stay above "
1357
+ "minus norm, so abs comes first for signed columns"),
1358
+ },
1359
+ "examples": [
1360
+ table_with('{"x*": standard_scaler, size: [log, minmax_scaler]}'),
1361
+ table_with('{"x*": [abs, {use: log, base: 10, norm: 1200}, standard_scaler]}', "{is_anomaly: ~}",
1362
+ file="anomaly_data.parquet"),
1363
+ ],
1364
+ },
1365
+ "cast": {
1366
+ "params": {"dtype": "a numpy dtype name such as float32, int64 or bool"},
1367
+ "examples": [table_with('{"num_*": standard_scaler, "flag_*": {use: cast, dtype: float32}}',
1368
+ "{sales: standard_scaler}", file="shop.parquet")],
1369
+ },
1370
+ }
1371
+
1372
+
1373
+ SPLITS = {
1374
+ "random": {
1375
+ "params": {"ratios": SPLIT_RATIOS, "seed": SPLIT_SEED},
1376
+ "examples": [table_with('{"x*": standard_scaler}', split="{use: random, ratios: [0.8, 0.1, 0.1], seed: 3}")],
1377
+ },
1378
+ "sequential": {
1379
+ "params": {
1380
+ "ratios": f"{SPLIT_RATIOS}; the rows are cut in their order",
1381
+ "group": ("a column; the rows of every value are cut in their order on their own, so every series has its "
1382
+ "own train, valid and test part"),
1383
+ },
1384
+ "examples": [table_with('{"x*": standard_scaler}', "{load: standard_scaler}",
1385
+ "{use: sequential, ratios: [0.7, 0.15, 0.15], group: site_id}", "energy.parquet")],
1386
+ },
1387
+ "kfold": {
1388
+ "params": {
1389
+ "folds": "the number of folds, at least 2",
1390
+ "fold": "the fold that is the test set, from 0 to folds - 1",
1391
+ "seed": SPLIT_SEED,
1392
+ "valid_ratio": "the share of the other folds that becomes the valid set, at least 0 and below 1",
1393
+ },
1394
+ "examples": [lines(
1395
+ "include: [../01_mlp_regression/config.yaml]",
1396
+ "params: {fold: 0}",
1397
+ "data:",
1398
+ " split: {use: kfold, folds: 5, fold: $fold$, valid_ratio: 0.15}",
1399
+ )],
1400
+ },
1401
+ "given": {
1402
+ "params": {
1403
+ "column": "the column whose values name the set of every row",
1404
+ "train": GIVEN.format("train", "train"),
1405
+ "valid": GIVEN.format("valid", "valid"),
1406
+ "test": GIVEN.format("test", "test"),
1407
+ },
1408
+ "examples": [table_with('{"x*": standard_scaler}', split="{use: given, column: part, test: holdout}")],
1409
+ },
1410
+ }
1411
+
1412
+
1413
+ TRANSFORMS = {
1414
+ "to_tensor": {"examples": [images_with("{use: resize, size: 32}", "to_tensor")]},
1415
+ "normalize": {
1416
+ "params": {
1417
+ "mean": ("a number, a list per channel or a preset name (imagenet, cifar10, mnist); a preset also gives "
1418
+ "std unless std is set"),
1419
+ "std": "a number, a list per channel or a preset name; null takes the std of the preset, or 0.5",
1420
+ },
1421
+ "examples": [
1422
+ images_with("to_tensor", "{use: normalize, mean: imagenet}"),
1423
+ images_with("to_tensor", "{use: normalize, mean: 0.5, std: 0.5}", folder="data/faces"),
1424
+ ],
1425
+ },
1426
+ "resize": {
1427
+ "params": {"size": f"the new size, {SIZE}"},
1428
+ "examples": [images_with("{use: resize, size: [32, 32]}", "to_tensor")],
1429
+ },
1430
+ "center_crop": {
1431
+ "params": {"size": f"the crop size, {SIZE}; a crop larger than the image pads with zeros"},
1432
+ "examples": [images_with("{use: resize, size: 36}", "{use: center_crop, size: 32}", "to_tensor")],
1433
+ },
1434
+ "random_crop": {
1435
+ "params": {
1436
+ "size": f"the crop size, {SIZE}",
1437
+ "padding": "zero pixels added on every side before a random window is cut",
1438
+ },
1439
+ "examples": [images_with("{use: random_crop, size: 32, padding: 4}", "random_flip", "to_tensor",
1440
+ key="train_transform")],
1441
+ },
1442
+ "random_flip": {
1443
+ "params": {"p": "the probability of a horizontal flip"},
1444
+ "examples": [images_with("{use: random_crop, size: 32, padding: 4}", "{use: random_flip, p: 0.5}", "to_tensor",
1445
+ key="train_transform")],
1446
+ },
1447
+ "grayscale": {
1448
+ "examples": [images_with("grayscale", "to_tensor", "{use: normalize, mean: mnist}", folder="data/digits")],
1449
+ },
1450
+ "two_views": {
1451
+ "params": {"each": ("the transform list applied twice with fresh randomness; each view becomes a float tensor "
1452
+ "(C, H, W)")},
1453
+ "examples": [lines(
1454
+ "data:",
1455
+ " use: image_folder",
1456
+ " folder: data/unlabeled",
1457
+ " split: [0.8, 0.1, 0.1]",
1458
+ " labels: false",
1459
+ " train_transform:",
1460
+ " - use: two_views",
1461
+ " each: [{use: random_crop, size: 16, padding: 2}, random_flip, to_tensor]",
1462
+ " transform: [to_tensor]",
1463
+ )],
1464
+ },
1465
+ }
1466
+
1467
+
1468
+ OTHERS = {
1469
+ "window": {
1470
+ "params": {
1471
+ "size": "the rows of a window: x is a (size, features) tensor",
1472
+ "horizon": "the rows after the window that every target covers",
1473
+ "stride": "the rows between the starts of two windows",
1474
+ "context": ("true lets the first windows of the valid and test sets reach back into the rows of the set "
1475
+ "before"),
1476
+ "group": "a column whose value every window keeps to, one series per value; it is not a feature",
1477
+ },
1478
+ "examples": [table_with('{"x*": standard_scaler}', "{load: standard_scaler}",
1479
+ "{use: sequential, ratios: [0.7, 0.15, 0.15], group: site_id}", "energy.parquet",
1480
+ [" feed: {use: window, size: 168, horizon: 24, context: true, group: site_id}"])],
1481
+ },
1482
+ "char_tokenizer": {
1483
+ "params": {
1484
+ "lowercase": ("lowercases the text before it is encoded; as a bare name the tokenizer takes the lowercase "
1485
+ "of text_lines"),
1486
+ },
1487
+ "examples": [lines(
1488
+ "data:",
1489
+ " use: text_lines",
1490
+ " file: data/corpus.txt",
1491
+ " tokenizer: {use: char_tokenizer, lowercase: true}",
1492
+ " seq_len: 64",
1493
+ " split: [0.9, 0.05, 0.05]",
1494
+ )],
1495
+ },
1496
+ "normal_init": {
1497
+ "params": {
1498
+ "std": "the standard deviation of the weights",
1499
+ "mean": "the mean of the weights",
1500
+ },
1501
+ "examples": [lines(
1502
+ "models:",
1503
+ " generator:",
1504
+ " use: gan_legos.Generator",
1505
+ " latent: 128",
1506
+ " init: {use: normal_init, std: 0.02}",
1507
+ )],
1508
+ },
1509
+ "xavier_init": {
1510
+ "params": {"gain": "scales the uniform bound; 1.0 suits linear and tanh layers, about 1.41 suits relu"},
1511
+ "examples": [
1512
+ lines("models:", " net: {use: mlp, hidden: [64, 64], out: 1, init: xavier_init}"),
1513
+ lines("models:", " net: {use: mlp, hidden: [64, 64], out: 1, init: {use: xavier_init, gain: 1.41}}"),
1514
+ ],
1515
+ },
1516
+ "cosine_beta": {
1517
+ "params": {
1518
+ "steps": "the diffusion steps T",
1519
+ "s": "the small offset of the cosine curve that keeps the first betas from vanishing",
1520
+ },
1521
+ "examples": [lines(
1522
+ "losses:",
1523
+ ' ddpm: {use: ddpm, model: "@models.unet", x: image, schedule: {use: cosine_beta, steps: 1000}}',
1524
+ )],
1525
+ },
1526
+ "linear_beta": {
1527
+ "params": {
1528
+ "steps": "the diffusion steps T",
1529
+ "start": "the beta of the first step, inside (0, 1)",
1530
+ "end": "the beta of the last step, inside (0, 1)",
1531
+ },
1532
+ "examples": [lines(
1533
+ "losses:",
1534
+ " ddpm:",
1535
+ " use: ddpm",
1536
+ ' model: "@models.unet"',
1537
+ " schedule: {use: linear_beta, steps: 1000, start: 1.0e-4, end: 0.02}",
1538
+ )],
1539
+ },
1540
+ }
1541
+
1542
+
1543
+ NOTES = {**DATA, **MODELS, **LOSSES, **METRICS, **OPTIMIZERS, **SCHEDULES, **STEPS, **TRIGGERS, **ACTIONS, **LOGGERS,
1544
+ **SAMPLERS, **PLOTS, **STRATEGIES, **LAYERS, **PREPROCESSORS, **SPLITS, **TRANSFORMS, **OTHERS}
1545
+
1546
+
1547
+ def apply():
1548
+ for name, note in NOTES.items():
1549
+ if name in aliases.ALIASES:
1550
+ aliases.annotate(name, params=note.get("params"), examples=note.get("examples"))
1551
+
1552
+
1553
+ apply()