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.
| 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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Pass this option to the Java process through your IDE's application run configuration or the command line:
--add-modules=jdk.incubator.vector
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
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?
Thank you!