Quickstart
Everything below is runnable top to bottom.
Install
Section titled “Install”pip install somatize # core: Graph, Study, tracking, cache, CLIpip install 'somatize[viz]' # + plotly, pandas, rich, tqdm (figures & reports)The viz extra is optional: the core install never needs it, and every
plotting call raises a clear error telling you to add it.
1. A filter
Section titled “1. A filter”A filter is a class with two methods: fit learns state, forward
transforms. Both are cached independently.
from soma import Filter, Graph
class Normalizer(Filter): _cache_version = "quickstart-v1" # see the note below
def fit(self, x, y=None): mean = sum(x) / len(x) std = (sum((v - mean) ** 2 for v in x) / len(x)) ** 0.5 return {"mean": mean, "std": std or 1.0}
def forward(self, x, state): return [(v - state["mean"]) / state["std"] for v in x]
class Scale(Filter): _cache_version = "quickstart-v1"
def __init__(self, factor=2.0, **kwargs): super().__init__(factor=factor, **kwargs) # kwargs → cache key
def forward(self, x, state): return [v * self.factor for v in x]2. A graph
Section titled “2. A graph”Two equivalent ways to compose. Explicit:
g = Graph()g.node("normalizer", Normalizer())g.node("scale", Scale(factor=3.0))g.connect("normalizer", "scale")Or the fluent DSL — >> chains, | forks:
g = Graph.somatize(Normalizer() >> Scale(factor=3.0))Fit, then transform new data with the learned state:
g.fit([10.0, 20.0, 30.0, 40.0])g.forward([15.0, 25.0])In a notebook, evaluating g draws the architecture as a diagram; in a
terminal, print(g) shows the text tree. g.compile() returns the
execution plan plus diagnostics (also self-displaying):
g.compile() # tiles, per-level diagnostics, the plan drawnprint(g.to_mermaid()) # or to_graphviz() / to_svg() / to_text()3. Caching is already on
Section titled “3. Caching is already on”Run the same fit twice and the second one is free — results are stored
content-addressed under $SOMA_CACHE_DIR (default ~/.soma/cache),
survive crashes, and are shared across graphs and processes:
g2 = Graph.somatize(Normalizer() >> Scale(factor=3.0))g2.fit([10.0, 20.0, 30.0, 40.0]) # cache hit — no recomputationsoma cache stats # records, CAS size, compute bankedsoma cache gc --max-size 20G4. Track a run
Section titled “4. Track a run”track_run writes a run directory (.soma/runs/<run_id>/) with the
graph snapshot, a lossless event log, metrics and diagnostics. It is
crash-safe and nothing reads it while training.
with g.track_run("first-run", tags=["quickstart"]) as run: g.fit([10.0, 20.0, 30.0, 40.0]) for step in range(5): run.log("loss", 1.0 / (step + 1), step=step)5. Look at what happened
Section titled “5. Look at what happened”Readers never write, so they work on live, finished and crashed runs alike:
import soma
soma.runs() # table of every run (newest first)view = soma.runs()[0]view.node_timings() # per-node wall time, durations, cache hitsview.metric_series("loss") # the logged curveprint(view.to_mermaid()) # architecture annotated with timing/cache/healthWith the viz extra, the same data as interactive figures:
view.plot_metrics() # metric curvesview.plot_gantt() # where the wall time went, node by nodeAnd from the shell:
soma runs # list runssoma graph <run_id> # annotated diagram (mermaid/dot)soma report <run_id> -o report.html # one self-contained HTML report6. Optimize
Section titled “6. Optimize”Declare the search space where the parameter lives, then let the study
sample it. trial.report feeds live curves and pruning:
from soma import Study, search
class Model(Filter): _cache_version = "quickstart-v1" lr: float = search(1e-4, 1e-1, scale="log")
def fit(self, x, y=None): return {"w": 1.0 - self.lr}
def forward(self, x, state): return [v * state["w"] for v in x]
g = Graph.somatize(Normalizer() >> Model())
study = g.study("quickstart-hpo", strategy="bayesian", n_trials=8, objectives=[("score", "maximize")])
def train(trial): g.apply_params(trial.params) for step in range(5): score = 1.0 - abs(trial["model.lr"] - 0.01) if trial.report("score", score, step): return None # pruned return {"score": score}
study.run(train, progress=True) # progress= draws a tqdm barstudy.best_trial["params"]Then the W&B-style views:
study.plot_optimization_history()study.plot_parallel_coordinate()study.plot_param_importances()study.trials_dataframe()study.to_html("study.html")Where to go next
Section titled “Where to go next”- Tutorials — nine runnable notebooks, from filters to auditing a multimodal model’s health.
- Python API — the complete reference.
- Visualization — diagrams, figures, reports, and the data contract a front-end reads.
- Gradient Health Audit — find vanishing gradients, dead channels and leakage inside your models.