NTDLS.Determinet v2.1.0
Version: 2.1.0
Status: Stable
Released: 2026-09-24
License: MIT License
No downloadable files are available for this release
but you can obtain the source code from GitHub.
Source-Code
Release Notes
Full Changelog: https://github.com/NTDLS/NTDLS.Determinet/compare/1.2.1...2.1.0
Nuget Package
https://www.nuget.org/packages/NTDLS.Determinet/ š¦
This release is a correctness overhaul. Backpropagation has been rewritten, and every activation function and loss path is now verified against numerical gradients. Several bugs that silently degraded training are fixed, training and inference are both faster, and model files from 1.x still load.
ā ļø Breaking changes
- New model file layout. Files saved by 2.x can't be opened by 1.x. Files saved by 1.x load normally, with identical predictions.
DniSynapse.Weightsis now a flatdouble[](one row per output node) instead ofdouble[,]. UseGetWeight(input, output)/SetWeight(...)for indexed access.- Renamed or removed parameters:
Network.UseAdamBatchOptimizationāNetwork.UseAdamOptimization. It now applies to bothTrain()andTrainBatch().Layer.UseBatchNormāLayer.UseLayerNorm. See "Training math" below for why.Layer.BatchNormMomentumandSoftMax.MaxLogithave been removed.
Network.GradientClipnow limits the total size of the gradient (default 5.0; 0 disables it). Previously it clamped each value separately, which changed the update's direction.IDniActivationFunction.UsesCrossEntropyhas been removed. SoftMax functions now implementIDniSoftMaxFunction.- SoftMax / SimpleSoftMax are rejected on hidden layers. They have no element-wise derivative, so training through them was never mathematically valid.
- Non-SoftMax outputs now report squared-error loss. Previously they reported cross-entropy while training on squared-error gradients.
Bug fixes
Training math
- Batch normalization was actually a broken layer normalization. It normalized across a single sample's neurons, but:
- backpropagation ignored the normalization step entirely;
- γ/β were updated using the wrong values;
TrainBatch()never trained γ/β;- inference used running averages that training never saw. It is now a correct layer normalization that behaves the same in training and inference.
- SoftMax temperature is now included in the gradient. The loss is computed exactly from the pre-SoftMax values (logits), and
MaxLogitclamping is gone because it distorted outputs. - Activation
Nonereturned the wrong derivative (the pre-activation value instead of 1). Train()andTrainBatch()had drifted into two different implementations.TrainBatch()also ran the forward pass twice per sample.Train()clipped the step (learning rate Ć gradient) instead of the gradient, so clipping effectively never happened. There is now one shared path.- The target array length is now validated. A mismatch previously caused an out-of-range crash or silently ignored values.
- Divergence (NaN/ā) now raises a clear exception. Previously those values were silently replaced with 0.
- Activation derivatives are evaluated at pre-activation values, and
InputLabelsreads the input layer instead of the output layer. (Both were fixed in 090d2ed.)
Activation functions
- PiecewiseLinear is continuous at its range edges; it used to jump whenever Alpha ā 1.
- SoftPlus and Mish no longer overflow to ā for large inputs. Sigmoid and Swish use a numerically stable form.
- SELU now uses the full-precision constants from the paper.
Infrastructure
- Parameters and
DniRangeare stored independent of the system locale, without precision loss. The old format truncated values below 1eā17, and on comma-decimal locales it brokeDniRangeoutright. Old files still parse. - Reading a parameter as a different numeric type (e.g. set as
int, read asdouble) no longer throws. DniUtility.Randomis thread-safe, now backed byRandom.Shared.DniConfiguration.LearningRatedefaults to 0.005. It used to default to 0, which silently trained nothing.
New features
- Adam (AdamW) is available for both single-sample and mini-batch training. Optimizer state is saved with the model, so resumed training continues exactly where it stopped.
TrainBatch(IEnumerable<(double[] inputs, double[] expected)>)overload.ComputeLoss(inputs, expected)evaluates the loss without modifying the network.Save(Stream)/Load(Stream)alongside the file-based methods.- Weight initialization matched to each layer's activation: He for the ReLU family, LeCun for SELU, Glorot/Xavier otherwise. Biases now start at zero.
Forward()no longer modifies the network, so inference is safe to call from multiple threads.- Configuration is validated: node counts, label counts, where SoftMax and layer normalization are allowed, and SoftMax temperature.
Performance
Measured on a 4096ā2048ā512ā128ā62 network:
- Inference is about 5ā7Ć faster, from a memory-friendly weight layout and SIMD dot products.
- Training is about 1.3ā1.9Ć faster. Weight gradients are now applied in a single pass over the weights instead of being built as a full-size matrix first.
Quality
- New
NTDLS.Determinet.Testsproject (104 tests), covering:- gradient checks for every activation, both loss types, SoftMax temperature and layer normalization;
- batch averaging and gradient clipping;
- save/load round trips, including Adam state;
- loading of 1.x files;
- locale-independent parameter storage.
Test harness and samples
- ImageSharp has been replaced by Magick.NET in every sample app (Train, Validate, Draw, GenImages, OCR).
- The Draw app no longer leaks memory on every 250 ms refresh.
- The training harness now uses Adam and a 32Ć32 input with a smaller network (1024ā512ā256).
- Harness fixes from 717a87a: resumed runs no longer overwrite the best checkpoint too early, early stopping counts correctly after a learning-rate change, and loading training samples is faster (O(N log N) instead of O(N²) per epoch).
- The README is rewritten with usage samples and a parameter reference.
Upgrading
- Rename the parameters listed under Breaking changes.
- If you use Adam, lower the learning rate (0.0001ā0.001 is typical) and raise weight decay to around 0.01.
- If you access
Synapse.Weightsdirectly, switch toGetWeight/SetWeight.
This is open source software licensed as MIT License. You can obtain the source code from