Table Of Contents


Built with 🛠 MkDocs - Theme 🖤 Github.

View Example on GitHub

Sorting Execution Time Prediction

This walkthrough builds a sorting execution-time predictor one part at a time. It demonstrates simple linear regression: predicting one continuous numerical value from one numerical feature.

Problem: Predict sorting execution time from the number of comparisons.

Dataset: 903 sorting benchmark measurements with one numerical feature and one continuous target.

At a glance

ML task Regression
Level Beginner
Dataset 903 sorting benchmark measurements
Input One numerical feature: comparison_count
Target One continuous value: execution_time_ms
Model 1 -> 1 feed-forward network with a linear output
Default training 3000 CPU epochs
Related concepts Machine Learning Basics, Linear Regression, Backpropagation, Deep Netts API, Model Development

The model uses one numerical feature:

comparison_count

and predicts one continuous target:

execution_time_ms

The complete flow is:

select columns -> load -> inspect -> split -> standardize -> build -> train -> evaluate -> save -> predict

0. Configure the program

Define the dataset and model paths, followed by the expected input and output sizes:

private static final String RAW_DATASET_PATH =
        "src/main/resources/datasets/Sorting_Algorithm.csv";

private static final String DATASET_PATH =
        "target/datasets/sorting_algorithm_regression.csv";

private static final String MODEL_PATH =
        "models/sorting-execution-time-regression.dnet";

private static final int NUM_INPUTS = 1;
private static final int NUM_OUTPUTS = 1;

One input represents comparison_count. One output represents the predicted execution_time_ms.

1. Configure the runtime

Verify Java and disable CUDA at the start of main:

verifyJavaRuntime();
DeepNetts.getInstance().setUseCuda(false);

Output:

WARNING: Using incubator modules: jdk.incubator.vector

The warning confirms that the required incubating Vector API is enabled. This introductory model and dataset are small enough to run efficiently on CPU.

2. Select the model columns

Use DFLib to select one feature and one target from the original CSV:

DataFrame regressionData = Csv.load(RAW_DATASET_PATH)
        .cols("comparison_count", "execution_time_ms")
        .select();

Csv.saver()
        .createMissingDirs()
        .save(regressionData, DATASET_PATH);

The selection order defines the model contract. The generated file lives under target/, so only the original dataset is stored in the repository.

3. Load the dataset

Read the generated two-column CSV with Deep Netts:

TabularDataSet<MLDataItem> dataSet =
        DataSets.readCsv(DATASET_PATH, NUM_INPUTS, NUM_OUTPUTS, true, ",");

Deep Netts interprets the first column as the input and the final column as the target.

4. Inspect the data

Confirm the number of samples and column order:

System.out.println("Samples: " + dataSet.size());
System.out.println("Columns: " + Arrays.toString(dataSet.getColumnNames()));

Output:

Samples: 903
Columns: [comparison_count, execution_time_ms]

The output confirms that all 903 samples and the two selected columns were loaded in the expected order.

5. Create train and test sets

Shuffle reproducibly, then reserve 20% of the samples for evaluation:

dataSet.shuffle(42);

TrainTestSplit split = dataSet.trainTestSplit(0.8);

DataSet<MLDataItem> trainingSet = split.getTrainingSet();
DataSet<MLDataItem> testSet = split.getTestSet();

The model learns only from trainingSet. The fixed seed keeps repeated experiments comparable.

6. Standardize the feature

Fit preprocessing only on training data and apply the same transformation to both subsets:

Standardizer standardizer = new Standardizer(trainingSet);

standardizer.apply(trainingSet);
standardizer.apply(testSet);

Keeping the test set out of the fitting step prevents data leakage.

7. Build a 1 to 1 model

Create a network with one input, no hidden layer, and one linear output:

FeedForwardNetwork neuralNet = FeedForwardNetwork.builder()
        .addInputLayer(NUM_INPUTS)
        .addOutputLayer(NUM_OUTPUTS, ActivationType.LINEAR)
        .lossFunction(LossType.MEAN_SQUARED_ERROR)
        .randomSeed(42)
        .build();

With no hidden layer, the network learns a straight-line relationship. This is what makes the example simple linear regression.

8. Configure and train the model

Configure the trainer and pass it the training set:

neuralNet.getTrainer()
        .setStopEpochs(3000)
        .setLearningRate(0.001f)
        .setOptimizer(OptimizerType.SGD)
        .setShuffle(true);

neuralNet.train(trainingSet);

Output:

TRAINING NEURAL NETWORK
-----------------------

Initial Train Error:510122.28
Epoch:1, Time:5ms, TrainError:287451.84, TrainErrorChange:-222670.44, TrainAccuracy:0.50591326
Epoch:2, Time:1ms, TrainError:94482.77, TrainErrorChange:-192969.06, TrainAccuracy:0.79503703
Epoch:3, Time:1ms, TrainError:49488.473, TrainErrorChange:-44994.3, TrainAccuracy:0.8597123
...
Epoch:3000, Time:0ms, TrainError:35741.2, TrainErrorChange:8.5859375, TrainAccuracy:0.88076025

TRAINING COMPLETED
Total Training Time: 2235ms
---------------------------

The middle epochs are omitted for readability. Mean Squared Error falls sharply during the first epochs, and this run completes all 3,000 configured epochs.

9. Evaluate on unseen data

Test the model with the reserved samples:

RegressionMetrics metrics = (RegressionMetrics) neuralNet.test(testSet);
System.out.println(metrics);

Output:

RegressionMetrics{
r2=0.8672889 Proportion of variance explained by the model. Intuitively how much the model prediction is better than using the mean value as prediction. A value between 0 and 1, where 1 is the best and 0 worst
meanSquaredError=78743.37 Mean/average value of squared errors (the difference betwen actual and predicted value). Highly sensitive to large errors and outliers in inputs. The lower the better ideally 0.
rootMeanSquaredError=280.6125 Squared root of the meanSquaredError. But in the same units as observerd value, makes it easier to interpret, and it is less sensitive to large error values. The lower the better ideally 0.
squaredErrorSum=1.4173806E7 Total sum of squared errors. The lower the better.
meanAbsoluteError=181.06033 Average error. Less sensitive to larger errors and outliers than meanSquaredError. The lower the better ideally 0.
meanAbsolutePercentageError=0.7629041 Mean/average of the absolute errors relative to their targets.Sensitive to relative erors
maxError=689.8218 The biggest error in prediction by the regression model

These are held-out test metrics, not training results. The r2 of about 0.867 shows that the linear model explains most of the observed execution-time variance, while the error metrics quantify the remaining differences in milliseconds.

10. Save the complete pipeline

Attach the fitted standardizer before saving the trained network:

neuralNet.setNormalizer(standardizer);

Files.createDirectories(Path.of("models"));
neuralNet.save(MODEL_PATH);

The saved model now carries the preprocessing expected by future input.

11. Predict execution time

Supply a new comparison count and read the continuous prediction:

float comparisonCount = 100_000;
float predictedExecutionTime = neuralNet.predict(comparisonCount)[0];

System.out.printf("Predicted execution time for %.0f comparisons: %.2f ms%n",
        comparisonCount, predictedExecutionTime);

Output:

Predicted execution time for 100000 comparisons: 337.74 ms

The result estimates an execution time of 337.74 ms for 100,000 comparisons.

Run the example

Pass this option to the Java process through your IDE's application run configuration or the command line:

--add-modules=jdk.incubator.vector

What you built

The completed program contains the full introductory workflow:

Sorting benchmark CSV
        |
        v
Select feature and target with DFLib
        |
        v
One input feature
        |
        v
1 -> 1 linear model
        |
        v
Test-set regression metrics
        |
        v
Saved model and new prediction

← Back to Examples

The model predicts a continuous execution-time value from a numerical comparison count rather than selecting a class label.

The example intentionally models one standardized input and one continuous output to demonstrate the smallest complete regression workflow.

Was this helpful?