Roadmap - xkqg/DeepSharp GitHub Wiki

Roadmap

In short

This page lists what DeepSharp has built and what it will build, in the order the work is done. What is done comes first, and below it what is still to come.

The one rule behind the order: nothing stands above a row it needs. Among the rows that are free to move, the one a reader reaches for most often, and pays least for, comes first.

There are no dates — a row moves when it is true, and the changelog is where it says so.

The table gives one line per row. The first row says all there is to say; every other row has a section of its own below, under its own name.

What it is In one line
Done Shape, Tensor, ITensorBackend, CpuBackend Everything else is written in terms of these.
Done Pipeline The artefact PDD is named after: declared once, fitted on train alone, replayed unchanged.
Done Notebook The same pipeline as a Verso notebook, one block per step.
Done DeepSharp.Verso.Api and DeepSharp.Verso.Serve The notebook hosted in an application of your own, and DeepSharp's own server.
Done Automatic differentiation The gradient a network learns by.
Done The layers Each a forward pass and its gradient, matched against PyTorch on the same rows.
Done Losses and optimizers The parts that turn a gradient into a change.
Done The training loop Batches, epochs, validation, early stopping, checkpoints and history — and a network trained behind a pipeline.
Done The two vocabularies Keras's words or PyTorch's, lowered onto the same model, bit for bit.
Done The charts DeepSharp.Charts: what a run keeps, drawn as SVG with MatPlotLibNet.
Done A TorchSharp backend The same model, its arithmetic on libtorch, on the processor or a graphics card.
Done Loading what already exists Reading a model trained elsewhere, from PyTorch, Keras and ONNX files.
Done Settling a gap before the features are worked out settle.gaps: a value no row decided, written where the features are worked out.
Done A trainer from ML.NET Boosted trees and a forest, measured beside a network on the same rows.
Done A course to fill in Every step of a pipeline in its order, waiting for what only a person knows.
Done Live sources A source that answers differently each time, fetched once and landed as a file.
Done Optimizing Searching for a network, answers that are a distribution, and what the pipeline owes a network.
Done Everything a window can be Every convolution and pooling setting that used to be refused, built.
Done Everything the parts can be told Every layer and optimizer setting that used to be refused, built.
Done What the flock team asked for a third time Bins, a periodic embedding, how alike the splits are, a better search, averaged weights, a per-key history.
Done The vocabulary a model is written in The activations, normalisations, losses and measures other libraries write.
Done A model watched after it ships The rows a served model meets, measured window by window against the training rows its pipeline keeps.
Later Data that is not a table Images, sound and text read in as rows, varied while training only, and text cut into tokens.
Later Several networks, one answer Networks trained apart — a study's best, or one design under other seeds — answering together.
Later The answer and what it is worth Splits that cut more than once, an interval around the answer, and why a model answers as it does.
Later Training further from what was read A rate of its own for a group of layers, and the low-rank pair beside a frozen layer.
Later A network that is not a straight line Branches, so a residual block, a U-shaped network or two inputs can be written, read and saved.
Later A row that remembers The layers that carry something from one step of a series to the next.
Later Attention, and what it attends over Attention, its many-headed form, the order of a sequence, and one encoder block.
Later Writing what others can read Writing a model in the graph format every runtime reads.
Later A table of its own A model that reads a table a column at a time, measured against ML.NET's trees.
Later The engine's own arithmetic Half-width numbers, a scaled loss and larger batches in the same memory, behind the seam.
Later More than one graphics card One run spread over several cards, by an engine behind the seam that already does it.
Later Smaller numbers to serve with A trained model kept in whole numbers of eight bits, so it answers in less memory and time.

What is done

Pipeline

The artefact PDD is named after: collect, settle the gaps, add features, split, name what a model is asked to predict, fill and normalise, and name the network those rows train. It is declared once, fitted on train alone, replayed unchanged on everything after, and the answers are brought back in their own units.

It came first because every later row is written in terms of it, and because the leak it prevents is invisible once it has happened. See Pipeline.

Notebook

The same pipeline written as a Verso notebook, one block per step:

  • the data, a profile and a heatmap at any block;
  • its columns chosen from the grid or a list, saved beside it and taken over again.

It runs in Verso's VS Code extension, in verso serve, in DeepSharp's own server and in an application of your own. It needed only the pipeline, so it did not wait for the rows below. See Notebook.

DeepSharp.Verso.Api and DeepSharp.Verso.Serve

The notebook's two sister packages:

  • DeepSharp.Verso.Api lets an application of your own host the notebook — opening it, passing a click on, the toolbar and the properties panel, the layouts, the themes and the title, saving, and every view of a notebook told what changed — done for the application rather than by it. Drawing what a block shows stays the application's.
  • DeepSharp.Verso.Serve is DeepSharp's own server built on it: deepsharp-serve shows the notebook in a browser and does there what Verso's browser editor does, with nothing else to install.

What the two would share is kept in one place when there is something to share. Like the notebook, they needed only the pipeline.

Automatic differentiation

A network learns by knowing which way to move. Without a gradient there is no training loop, so this is the one piece nothing can be faked around.

The layers

  • Dense, the activations, dropout, batch and layer normalisation.
  • Convolutions along one, two and three axes — in groups, depthwise, dilated, strided on their own for each axis — and the transposed ones that give those places back.
  • Max and average poolings, global poolings and the poolings to a size.
  • The layers that only pad, the dropouts of whole channels, flattening and reshaping.

Each is a forward pass and its gradient, each starting and working as PyTorch's does, matched against it on the same rows.

Losses and optimizers

The parts that turn a gradient into a change:

  • Losses: mean squared error, cross-entropy and binary cross-entropy, each saying how a network's numbers are read, and the earth mover's distance for shares in an order.
  • Optimizers: SGD with momentum, Adam, AdamW, RMSprop and Nadam as PyTorch writes them, open to an optimizer of your own.
  • A learning-rate schedule: constant, stepped, exponential, a cosine or a warm-up — with gradients clipped by their norm.

The training loop

  • Batches, epochs, validation, and early stopping as Keras's.
  • Checkpoints a run goes on from bit for bit on the engine they were taken on.
  • The history the charts are drawn from.

Through DeepSharp.Learners.Networks, a network is trained behind a pipeline — declared in that pipeline's own chain and trained by pipeline.Train(), or written as code and fitted by hand — measured by its report and kept with it as one file. See Networks.

The two vocabularies

Stack layers, compile and fit — the words TensorFlow and Keras use — or write the forward pass yourself, the way PyTorch does.

The declarative side is a builder that lowers onto the same model the imperative side produces, so nothing downstream knows which door was used — the same network, bit for bit, and the same file.

Both vocabularies can be spoken in the chain that prepares a pipeline's rows too:

  • .WithTensorflow(…) declares the network those rows train in the words TensorFlow and Keras use;
  • .WithTorch(…) declares it in the words PyTorch uses.

pipeline.Train() trains exactly that network, so the model is declared with the pipeline rather than written beside it. Each writes the number its own library leaves where a caller says none, so the file says which run was asked for.

The charts

DeepSharp.Charts, which draws with MatPlotLibNet:

  • the loss curve and the learning rate;
  • confusion matrices, predicted against actual, and the residuals;
  • the measures as bars.

All of it from what the loop and the measures already keep, as SVG, with no viewer to start.

A TorchSharp backend

The same model, running its arithmetic on libtorch, on the processor or a graphics card: DeepSharp.Backends.TorchSharp, TorchBackend.OnCpu() or OnGpu(0), handed to a run and to a trained network as it serves. It is held to the light engine operation by operation and step by step.

It is a package of its own: a project that does not want it never carries it, the application brings libtorch, and no model changes because of it.

Together with the training loop this is the short version of what the library does — you write it the way TensorFlow taught you, and Torch runs it. See TorchSharp backend.

Loading what already exists

Reading what was trained elsewhere, so a model does not have to begin here to run here.

The seam is in the core: IImporter, and network.Load, which puts numbers into a network by the path of each slot, all of them or none. Three packages implement it:

Package What it reads
DeepSharp.Import.PyTorch a safetensors file, and the .pt file torch.save writes, its pickle read as PyTorch's weights-only reader reads it
DeepSharp.Import.Keras the .keras and .h5 files Keras saves
DeepSharp.Import.Onnx the graphs PyTorch's exporters, Keras and tf2onnx write

A model read so is served, measured, or trained further behind a pipeline and kept with it as the one file. See Importing a model.

Settling a gap before the features are worked out

The problem. A feature is worked out from the columns as they stand, and a fill stands below the split because what it puts in a gap is learned from the training rows. So a sum of two columns one of which has a gap was itself a gap, and filling that column afterwards did not reach back into it.

The answer. settle.gaps is the other half: a nought, a number you choose, or a refusal — none of them a value any row decided — written where the features are worked out, so a feature after it is worked out from settled columns.

  • It learns nothing, so it writes nothing into the fitted half.
  • It marks where the gaps were as a fill does.
  • It is a verb of its own rather than the fill moved, which is why the pipeline file went to version 6.

A trainer from ML.NET

The prepared data handed to a trainer from ML.NET, for a table that a tree learns better than a network:

  • .WithML(trainer => trainer.FastTree()) names it in the chain.
  • pipeline.TrainWithML() runs the pipeline for what it needs — Needs.NoScale, so the scalings a tree does without are left out and written down.
  • The pipeline's own report then measures the tree and a network on the same rows, which is the only reason the two can honestly be compared.

It names boosted trees and a forest and no other trainer. A declaration promises that running it again gives the same model; measured on this library's rows the stochastic trainers do not keep that promise, while a tree keeps it from the seed the declaration carries.

It is two packages, because the library may not travel where the verb must: ML.NET learner.

A course to fill in

A pipeline written from nothing starts with an empty chain and a reader who has to know which verb comes where. A course is every step of a prepared pipeline in the order the steps belong, each present and waiting for what only a person knows — the file to read, the columns, the bounds — and starting everything else as its verb starts it.

There are two, because the rules say a table and a series in time cannot share one order: PipelineCourse.Table and PipelineCourse.SeriesInTime.

  • A course is a value. Say fills in a step, Waiting names what still waits, and Pdd.From starts a pipeline from one filled in all the way.
  • A course is a file of its own, read through the same door as the pipeline's and under the same version, so no pipeline file moves.
  • In the Notebook, two buttons write every step the blocks do not hold yet, each as the verb's skeleton with null where only you can say. A block added in DeepSharp's own host arrives as the step that belongs there instead of empty; Verso's own editors never ask a cell type what a cell starts with, so a block added there still starts empty.

See Starting from a course.

Live sources

A source that answers differently every time it is asked — an exchange's prices, an API — fetched once over a closed window and landed as a file, which the pipeline then reads like any other, by fingerprint. Each is in a package of its own, DeepSharp.Pipelines.<Source>, since it brings HTTP, retries and a pacer that a project serving a trained model has no use for.

DeepSharp.Pipelines.Binance lands the candles of a market on Binance: await pipeline.ReadBinanceAsync(new BinanceCandles("BTCEUR", "1d", from, to)) lands the window where it is not landed yet and adds an ordinary .ReadCsv of the file, beside a record of what was asked and what came back.

  • Asking again asks Binance nothing.
  • A file that was changed since is refused rather than replaced.
  • It goes as a guest at an address's shared budget — slowly, waiting once the address has used half of what a minute allows, and stopping at a ban.
  • The pipeline's file names the landed file and nothing of Binance, so serving the model never carries the package.

It stands on the readers. See Live sources.

Optimizing

What a network is trained with, searched for and measured by, and what the pipeline owes it:

  • Searching for a network — a study that chooses by the validation rows and keeps the test rows for the winner, testSeed to fix them, and a paired comparison of two pipelines;
  • answers that are a distribution in an order, with emd, kl and rps, the earth mover's loss and what a flock that arrived short leaves;
  • target.numbers;
  • two files as one source;
  • an id that travels with its rows;
  • a correlation worked out once as numbers, Pearson's and Spearman's;
  • a run that can be watched and stopped;
  • and Writing a step of your own.

Everything a window can be

What a convolution here covered was neighbouring places, one stride on every axis and the places that fit whole, and a source that said anything else was refused at the setting that said it. Those refusals are built:

  • a stride of its own for each axis;
  • a dilated window;
  • channels in groups, a depthwise and a separable convolution;
  • a transposed convolution;
  • a border that differs from side to side, and a layer that only pads;
  • a pooling that rounds the number of places up, and a pooling to a size other than one place.

Each is held to the proof the rest have — its values and its gradient matched to the framework that has it, on every engine — and each is read from the Keras, ONNX and PyTorch files that say it.

Nothing was added to the tensor seam for any of them: they are the unfolding and its fold, a matrix product, a reshape and the first-largest step, in another order. See Networks and Importing a model.

Everything the parts can be told

A layer here took what it needed and little else, and a source that said more was refused at the setting that said it. Those refusals are built.

On the layer's side:

  • a layer without a bias, and a normalisation without its scale or its shift;
  • nine ways to start a weight or a bias;
  • a penalty the loss adds for weights that grow, and a bound on how large a unit's weights may become;
  • a layer held still while the rest learns;
  • the three borders a padding could not do — the one that mirrors, the one that repeats and the one that wraps.

On the other side of the step:

  • the weight decay PyTorch adds to the gradient of Sgd, Adam, RMSprop and Nadam;
  • Nesterov's momentum, dampening, AMSGrad, and RMSprop's centred form;
  • clipping each gradient value as well as the norm of all of them;
  • a step taken once every several batches;
  • an average of the weights kept beside them.

Each is held to the proof the rest have — matched, step by step, to the framework that has it, on every engine — and each is read from the Keras, ONNX and PyTorch files that say it. A part that says none of them is written as it always was, so every file an earlier release wrote still reads. Networks says which to reach for when.

What the flock team asked for a third time

A team that weighs flocks wrote for the third time, with what its rows asked of a network here. Each ask is built as this library builds everything: fitted on the training rows alone where it learns, replayed unchanged everywhere after.

  • A number written down as how far it fills a few bins whose edges the training rows place.
  • The periodic embedding of a number, its frequencies started from a spread the person says, since its authors searched that spread for every dataset.
  • A report of how alike training, validation and test are, column by column, that warns and never refuses.
  • A search that stops a hopeless trial, draws a setting only when another is chosen, and goes on from the trials it ran before.
  • A run judged by the average of its weights, so the best epoch it restores is the best average.
  • A running statistic of each key over its earlier training rows, which a single new flock is served with as the training rows were.

What the letter asked for that is refused is refused by name, with why, in the changelog. See Filling and scaling, Searching for a network and Measuring and drawing.

The vocabulary a model is written in

The words the libraries a model is read from write and this library did not:

  • Activations: the smooth ones a transformer is made of — GELU, exactly or by its tangent, SiLU and mish — the leaky, parametric and self-normalising ones, and softmax as a layer rather than only inside a loss.
  • Normalisations: over groups of channels, over one example's channels, and the one that scales without centring.
  • A category as a small vector learned over the columns its encoder writes it down as, which is one layer and no new arithmetic.
  • Losses: the absolute error, the one squared near nought and absolute away from it, the one that asks for a quantile rather than a mean, the one that leans on the rare class, the hinge, the one for counts, and cross-entropy with its labels softened.
  • Measures beside them: F1, the area under the curve a threshold sweeps out, the error as a share of the answer, and the Brier score with its reliability curve for whether a model that says seventy per cent is right seven times in ten.

It is one release because it was one kind of work done over and over: a forward pass, its gradient, a kind in the file, a read by the three readers — ONNX's both as its newer operators and as the several operators PyTorch's exporters spell each in for older sets — and the framework that has it to hold the numbers to.

The seam gained the sine and the error function for it and nothing more. See Networks, Importing a model and Measuring and drawing.

A model watched after it ships

The likeness of the parts measured how far training, validation and test lie apart, once, while every row was there; and a pipeline read from its file keeps what its steps learned, not the rows they learned it from. So nothing watched the rows a model met once it was served, and a model whose world had moved on went on answering as if it had not.

It is the same measurement turned the other way:

  • watch.reference (.Watch(warnAbove, columns…)), below the split, keeps the training rows of the columns it watches as counts — each value once with how many rows hold it — and changes nothing a replay does;
  • prepared.Watched(window) measures a window of served rows against them, column by column, by the same two distances the likeness of the parts takes, flagged above the watch's bound, each beside how many rows it was worked out from, and says when the window was;
  • nothing is learned from the served rows, so the reference stays the one the model was fitted on, and the windows are the caller's — DeepSharp.Charts draws them one beside another.

A model trained before its pipeline kept the rows is watched once both are made again. See Measuring and drawing.

What is still to come

Data that is not a table

There are convolutions over images and volumes, embeddings and the activations a transformer is made of, and still every row has to arrive as a table: whoever has a folder of pictures turns the pixels into columns by hand first.

What it takes:

  • a source that reads images, sound and text as rows of numbers, beside the files a pipeline reads today;
  • a variation of the training rows only — a flip, a crop, noise — declared in the pipeline and drawn from a seed of its own, so validation and test are never varied and a run can be replayed;
  • a tokenizer that cuts text into the ids an embedding takes, learned from the training rows alone.

It stands here because the layers are built and the way in is not, and because it is what a reader with anything but a table meets first.

Several networks, one answer

A study tries many networks and keeps one; a comparison says whether a change helped. Neither lets several trained networks answer together, which is often steadier than any one of them. The average a run keeps is of one network's weights over its own steps, not of several networks' answers.

What it takes:

  • networks trained apart on the rows one pipeline prepared — the best few of a study, or one design under other seeds;
  • their answers averaged, or for classes their chances averaged or their votes counted, in the answer's own units;
  • measured by the same report on the same rows as each of its members, so what the ensemble adds is a number;
  • kept as one file with the pipeline, refusing any other fit of it, as a single network is.

It stands here because a study and its trained networks are built, and the rest is the answer they give together.

The answer and what it is worth

Three things that are one piece of work — they all touch the split, the report and nothing else — and they are what a reader of this library reaches for most often after a model trains at all:

  • Splits that cut more than once. Every split here cuts once — at random, by time, or keeping the classes' shares — so a small table is measured by luck and a series is not measured the way forecasting is, by moving the cut forward and fitting again.
  • A bound. Rows set aside before anything is fitted, what is worked out from them worked out once, and the answer handed back with an interval around it in its own units — which is this library's own shape rather than a new idea in it.
  • Why. The third thing a reader asks the moment an answer appears: which column the answer leans on, what happens to it as one column moves through its range, and what a single row's answer is made of.

The quantile loss it needs is built.

Training further from what was read

A model read from elsewhere can be trained on further here, and with no say over what moves: everything moves, at one rate, all of it learning.

The held-still layer is built. What it still needs:

  • a rate of its own for a group of layers;
  • the small pair of low-rank matrices beside a frozen layer that has become how a large layer is adapted — which a reader will meet in a Keras file sooner or later anyway, since that is where it is written.

It stands here because reading a model is built already, the rest of it is small, and nothing below is needed for any of it.

A network that is not a straight line

Everything here is a line: layers in order, each handed what the one before it made. A reader meeting anything else refuses it by name — a branch, a node taking another value than the one the node before it made, or two. That one refusal is why a residual block, a dense block, a network shaped like a U, a cascade whose every added unit sees every earlier one, and anything with two inputs can be neither written, read nor saved here.

What it takes:

  • a step that may ask for the output of a step other than the last;
  • an add and a joining of what two steps made;
  • a name per step for the asking to be written down;
  • a shape in the file for a network that is not a sequence.

The readers then stop refusing a branch, and a model trained elsewhere arrives as it was.

It is the hardest row on this list and the one most of what people train today needs, which is why it is here and not later. It needs the row that can hold a layer still, because a cascade that grows is only honest when what it added stays put, and every row below it waits for it.

A row that remembers

The pipeline prepares a series — a course of its own for it, a feature for what comes round again, the indicators — and nothing on the network side carries anything from one step of that series to the next.

What it takes:

  • the two layers that do, as every library writes them;
  • a batch whose rows are of unequal length, and the mask that says where each ends;
  • the two wrappers that make them usable: one that reads the series both ways, one that applies a layer to every step.

The gradient of a network that remembers runs back through time, which is new ground for the backend that records one. What these layers hold inside them is not a line either, so it waits for the row above.

Attention, and what it attends over

The one step everything since has been built from: attention, its many-headed form, somewhere to put the order of a sequence, and one encoder block that puts them together. A mask that hides what a step may not look at is what it gains, softmax over the last axis being a layer already.

It waits for a network that may branch, since an attention block is a branch twice over. It is here rather than higher because almost nothing a reader of this library prepares today asks for it before that row exists.

Writing what others can read

Three readers are built and no writer. A model trained here runs here, and nowhere else — while the graph format every runtime reads is one this library already parses, with the classes for it already in hand.

Writing one back is the symmetric half of a reader that works:

  • a kind for every node;
  • the two version numbers a graph carries;
  • its own proof — write it, run it where it is meant to run, and hold the numbers to ours.

Serving on that runtime is a smaller row beside it, and a different one: a runtime that only answers is not an engine this library can train on, and saying so is half of that design.

It waits for the row that lets a network branch, since a writer that can only write a line would refuse the models anyone most wants out.

A table of its own

The library's own ground is tables, and the shape that reads a table as a model of this kind — a column at a time, attended over — is the one piece of the current state of the art that is missing here.

It is built to be measured, not to be claimed: against the trees from ML.NET, on the same rows, through the pipeline's own report, which is the only comparison that means anything. What it does not do is carry somebody else's trained weights: a model that arrives already knowing something is a decision about what this library ships, not a layer.

It waits for the three rows above it, and it is the one row here that could turn out not to be worth its own weight, which is why it is not higher.

The engine's own arithmetic

  • Numbers kept in half the width, with a full-width copy to be updated.
  • The loss scaled so small gradients survive.
  • A sum of gradients kept wider than the batches that made it.
  • Layers whose workings are thrown away and worked out again to fit a larger batch in the same memory.

All of it belongs behind the seam, on the engine that already has it, and none of it is hand-written GPU code — which is not on this list and does not become so here. It is last because nothing above it needs it and nobody meets it until a run is large enough to be slow.

More than one graphics card

One run spread over several cards — each a share of the batch, the gradients added together. It belongs behind the seam, on an engine that already does it, as the GPU training host this library may reach does; nothing of it is written here. It is late because one card answers every run this library sees today.

Smaller numbers to serve with

A trained model kept in whole numbers of eight bits rather than in single precision, so it answers in less memory and time — measured, as everything here, against the answers it gave before. It asks for arithmetic the seam does not have, so it comes after the rows that use the seam as it is.

What is not on this list

Hand-written GPU code

Reaching a GPU means using an engine that already does, through the seam. No CUDA is written here, and the GPU training host it would reach stays a separate project.

A second network representation

No description of a network kept beside the model and held in step with it, however convenient it would be for one feature. Two of those diverge on the first unusual model, and then every bug is asked twice.

A network that branches is not that and is on the list above: a step may come to ask for what a step other than the last one made, and it does so inside the one model every engine runs and every file holds.

Nor is a file written out for another runtime to read: that is written from the model and never read back as the model.

Matching a Python API call for call

Names that are clear in C# beat names that are familiar from Python. Where the two agree, the familiar one wins; where they do not, the reader here comes first.

⚠️ **GitHub.com Fallback** ⚠️