from lynxkite.core import workspace from lynxkite_graph_analytics.pytorch import pytorch_core import torch import pytest def make_ws(env, nodes: dict[str, dict], edges: list[tuple[str, str]]): ws = workspace.Workspace(env=env) for id, data in nodes.items(): title = data["title"] del data["title"] ws.nodes.append( workspace.WorkspaceNode( id=id, type="basic", data=workspace.WorkspaceNodeData(title=title, params=data), position=workspace.Position( x=data.get("x", 0), y=data.get("y", 0), ), ) ) ws.edges = [ workspace.WorkspaceEdge( id=f"{source}->{target}", source=source.split(":")[0], target=target.split(":")[0], sourceHandle=source.split(":")[1], targetHandle=target.split(":")[1], ) for source, target in edges ] return ws def summarize_layers(m: pytorch_core.ModelConfig) -> str: return "".join(str(e)[0] for e in m.model) def summarize_connections(m: pytorch_core.ModelConfig) -> str: return " ".join( "".join(n[0] for n in c.param_names) + "->" + "".join(n[0] for n in c.return_names) for c in m.model._children ) async def test_build_model(): ws = make_ws( pytorch_core.ENV, { "input": {"title": "Input: tensor"}, "lin": {"title": "Linear", "output_dim": 4}, "act": {"title": "Activation", "type": "Leaky_ReLU"}, "output": {"title": "Output"}, "label": {"title": "Input: tensor"}, "loss": {"title": "MSE loss"}, "optim": {"title": "Optimizer", "type": "SGD", "lr": 0.1}, }, [ ("input:output", "lin:x"), ("lin:output", "act:x"), ("act:output", "output:x"), ("output:x", "loss:x"), ("label:output", "loss:y"), ("loss:output", "optim:loss"), ], ) x = torch.rand(100, 4) y = x + 1 m = pytorch_core.build_model(ws) for i in range(1000): loss = m.train({"input_output": x, "label_output": y}) assert loss < 0.1 o = m.inference({"input_output": x[:1]}) error = torch.nn.functional.mse_loss(o["output_x"], x[:1] + 1) assert error < 0.1 async def test_build_model_with_repeat(): def repeated_ws(times): return make_ws( pytorch_core.ENV, { "input": {"title": "Input: tensor"}, "lin": {"title": "Linear", "output_dim": 8}, "act": {"title": "Activation", "type": "Leaky_ReLU"}, "output": {"title": "Output"}, "label": {"title": "Input: tensor"}, "loss": {"title": "MSE loss"}, "optim": {"title": "Optimizer", "type": "SGD", "lr": 0.1}, "repeat": {"title": "Repeat", "times": times, "same_weights": False}, }, [ ("input:output", "lin:x"), ("lin:output", "act:x"), ("act:output", "output:x"), ("output:x", "loss:x"), ("label:output", "loss:y"), ("loss:output", "optim:loss"), ("repeat:output", "lin:x"), ("act:output", "repeat:input"), ], ) # 1 repetition m = pytorch_core.build_model(repeated_ws(1)) assert summarize_layers(m) == "ILS S->l l->a a->E E->o o->o" # 2 repetitions m = pytorch_core.build_model(repeated_ws(2)) assert summarize_layers(m) == "ILS S->l l->a a->S S->l l->a a->E E->o o->o" # 3 repetitions m = pytorch_core.build_model(repeated_ws(3)) assert summarize_layers(m) == "ILS S->l l->a a->S S->l l->a a->S S->l l->a a->E E->o o->o" if __name__ == "__main__": pytest.main()