197 lines
6.2 KiB
Markdown
197 lines
6.2 KiB
Markdown
# Getting started: data science
|
|
|
|
Turn a Python experiment into a flow with recorded parameters, training curves
|
|
and files you can find again. Goodbye, `results_final_v3.csv`.
|
|
|
|
This example uses a toy training curve, so you can try the whole workflow
|
|
without a dataset or GPU. You need Python 3.12 or newer on Linux or macOS.
|
|
Install Git too if you want flow changes recorded in version history.
|
|
|
|
## 1. Start your instance
|
|
|
|
Create a project directory and install Fluksio in a virtual environment:
|
|
|
|
```sh
|
|
mkdir research-flow
|
|
cd research-flow
|
|
python3 -m venv .venv
|
|
. .venv/bin/activate
|
|
pip install fluksio
|
|
fluksio serve
|
|
```
|
|
|
|
Fluksio creates `.fluksio/` for this project's flows, run history and artifacts.
|
|
It prints the initial admin password once and saves a token for local CLI
|
|
commands. Keep the password somewhere safe.
|
|
|
|
At a terminal, `serve` opens a dashboard. Leave it running, then open a second
|
|
terminal in `research-flow` and activate the same environment:
|
|
|
|
```sh
|
|
. .venv/bin/activate
|
|
```
|
|
|
|
For the browser dashboard, sign up at [fluksio.com](https://fluksio.com), add
|
|
an instance, and enter the code it gives you:
|
|
|
|
```sh
|
|
fluksio enroll <code>
|
|
```
|
|
|
|
Select the instance in the portal. The CLI also works without enrolling.
|
|
|
|
!!! tip "Use your existing research environment"
|
|
|
|
You can install Fluksio in the virtual environment that already holds your
|
|
research packages. Nodes use that environment by default. The startup
|
|
banner shows the interpreter; see [Packages](../code/nodes.md#packages)
|
|
for other setups.
|
|
|
|
## 2. Write a small flow
|
|
|
|
Save this as `study.py` in `research-flow`:
|
|
|
|
```python
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
|
|
import fluksio
|
|
from fluksio import Flow, Port, node
|
|
|
|
|
|
@node(
|
|
requires=[Port("lr", "float"), Port("epochs", "int")],
|
|
provides=[
|
|
Port("loss", "float", stream=True),
|
|
Port("weights", "artifact"),
|
|
Port("final_loss", "float"),
|
|
],
|
|
)
|
|
def fit(lr, epochs):
|
|
loss = 1.0
|
|
for epoch in range(epochs):
|
|
loss = math.exp(-lr * (epoch + 1))
|
|
yield {"loss": loss}
|
|
checkpoint = json.dumps({"loss": loss}).encode()
|
|
return {
|
|
"weights": fluksio.save_artifact(
|
|
checkpoint, "weights.json", "application/json"
|
|
),
|
|
"final_loss": loss,
|
|
}
|
|
|
|
|
|
@node(requires=["weights"], provides=Port("score", "float"))
|
|
def evaluate(weights):
|
|
checkpoint = json.loads(Path(fluksio.load_artifact(weights)).read_text())
|
|
return 1.0 - checkpoint["loss"]
|
|
|
|
|
|
train = Flow(
|
|
"train",
|
|
nodes=[fit, evaluate],
|
|
inputs=[Port("lr", "float", initial=0.05), Port("epochs", "int", initial=10)],
|
|
outputs=["score", "final_loss", "weights"],
|
|
)
|
|
```
|
|
|
|
`@node` declares inputs and outputs. Matching message names connect the nodes:
|
|
`fit` produces `weights`, and `evaluate` reads it. `Flow` lists the nodes,
|
|
run parameters and final results.
|
|
|
|
Each `yield` records a loss value. The final `return` sends the checkpoint to
|
|
the next node. Artifact ports carry a small reference; the file stays in the
|
|
artifact store.
|
|
|
|
## 3. Sync and run
|
|
|
|
```sh
|
|
fluksio sync study
|
|
fluksio run train --lr 0.1 --epochs 20 --follow
|
|
```
|
|
|
|
`sync` uploads the flow and generates node code that imports your functions.
|
|
Keep the project files available to the engine. Later `run` commands sync
|
|
edits before submitting; `--follow` waits and prints metrics as they arrive.
|
|
This run should finish with `final_loss` around `0.1353` and `score` around
|
|
`0.8647`.
|
|
|
|
In the portal, open **Flows → train** to see the graph, or **Runs** to inspect
|
|
the parameters, metrics and results. From the CLI:
|
|
|
|
```sh
|
|
fluksio runs --flow train
|
|
fluksio artifacts <run-id>
|
|
fluksio artifacts <run-id> train.weights -o weights.json
|
|
```
|
|
|
|
Use the ID printed by `run`. Artifact names are flow-qualified; the list
|
|
command shows the exact names to download.
|
|
|
|
## 4. Try a few learning rates
|
|
|
|
```sh
|
|
fluksio sweep train --param lr=0.01,0.05,0.1 --wait
|
|
fluksio export metrics --flow train -o curves.csv
|
|
fluksio export runs --flow train --status ok -o results.csv
|
|
```
|
|
|
|
The sweep creates three runs in one group. Select them on **Runs** to compare
|
|
their curves. The exports give you a row per metric point and a row per run,
|
|
ready for your analysis.
|
|
|
|
Python can read the same tables:
|
|
|
|
```python
|
|
from fluksio.sdk.client import Client
|
|
|
|
client = Client()
|
|
results = client.export_runs(flow="train", status="ok")
|
|
curves = client.export_metrics(flow="train", name="train.loss")
|
|
```
|
|
|
|
Pass either list to `pandas.DataFrame` if you use pandas.
|
|
|
|
## Bring your own experiment
|
|
|
|
Replace the toy calculation in `fit` with your training code. Keep ordinary
|
|
Python helpers separate from artifact storage so you can still test them
|
|
without an engine: `save_artifact` and `load_artifact` work only inside nodes.
|
|
The public repository's `examples/myresearch/` package shows this pattern
|
|
across several files.
|
|
|
|
- Defaulted function arguments that are not input ports become node settings.
|
|
Use flow inputs for values you want to vary between runs.
|
|
- Use `fluksio.emit(loss=value)` when metrics arrive through a framework
|
|
callback instead of a loop you can `yield` from.
|
|
- Runs can reuse unchanged stages. Use `--no-cache` when you want every node
|
|
to execute; see [Stage caching](../concepts/runs.md#stage-caching).
|
|
- `--seed` records a seed and fills an input named `seed` when declared. Your
|
|
code still needs to pass that value to its random number generator.
|
|
|
|
### Declaring what a node needs
|
|
|
|
For heavy computation, declare resources on the node:
|
|
|
|
```python
|
|
@node(requires=["dataset"], provides=Port("score", "float"),
|
|
resources={"cpus": 2, "ram": "2G"})
|
|
def score_dataset(dataset):
|
|
return {"score": calculate_score(dataset)}
|
|
```
|
|
|
|
The engine accounts for these resources and sets worker thread limits. GPU
|
|
nodes can request `resources={"gpus": 1}`; check that the Workers screen
|
|
reports your GPU, or set `fluksio serve --gpus 1` when automatic detection
|
|
does not cover it. Resource accounting does not impose a hard memory limit.
|
|
|
|
To run on another machine, attach a [remote worker](../code/workers.md) and
|
|
install your project and its dependencies there.
|
|
|
|
## Next steps
|
|
|
|
- [Writing node code](../code/nodes.md) — ports, streaming, artifacts and packages.
|
|
- [Runs](../concepts/runs.md) — caching, comparisons and retries.
|
|
- [CLI reference](../code/cli.md) — command options and instance settings.
|