Skip to content

Commit

Permalink
Merge pull request #139 from Samyssmile/feat/mlp-layer-based
Browse files Browse the repository at this point in the history
Multilayer Perceptron Layerbased
  • Loading branch information
Samyssmile committed Dec 19, 2023
2 parents 73fafa1 + 4dd2a40 commit 504c579
Show file tree
Hide file tree
Showing 64 changed files with 2,745 additions and 683 deletions.
106 changes: 51 additions & 55 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ Edux supports a variety of image augmentations, which can be used to increase th

#### Single Image

````java
```
AugmentationSequence augmentationSequence=
new AugmentationBuilder()
.addAugmentation(new ResizeAugmentation(250,250))
.addAugmentation(new ColorEqualizationAugmentation())
.build();
BufferedImage augmentedImage=augmentationSequence.applyTo(image);
````
```

#### Run for all images in a directory

```java
```
AugmentationSequence augmentationSequence=
new AugmentationBuilder()
.addAugmentation(new ResizeAugmentation(250,250))
Expand Down Expand Up @@ -127,78 +127,74 @@ A multi-layer perceptron (MLP) is a feedforward artificial neural network that g
input features. An MLP is characterized by several layers of input nodes connected as a directed graph between the input
and output layers.

![Neural Network](https://hc-linux.eu/github/iris-nn.png)
### Step 0: Get Familiar with the Dataset

### Step 1: Data Processing
In this example we use the famouse MNIST Dataset. The MNIST database contains 60,000 training images and 10,000 testing

Firstly, we will load and prepare the IRIS dataset:
![](https://hc-linux.eu/edux/mnist-examples.png)

| sepal.length | sepal.width | petal.length | petal.width | variety |
|--------------|-------------|--------------|-------------|---------|
| 5.1 | 3.5 | 1.4 | 0.2 | Setosa |

```java
var featureColumnIndices=new int[]{0,1,2,3}; // Specify your feature columns
var targetColumnIndex=4; // Specify your target column
### Step 1: Data Processing

var dataProcessor=new DataProcessor(new CSVIDataReader());
var dataset=dataProcessor.loadDataSetFromCSV(
"path/to/your/data.csv", // Replace with your CSV file path
',', // CSV delimiter
true, // Whether to skip the header
featureColumnIndices,
targetColumnIndex
);
dataset.shuffle();
dataset.normalize();
dataProcessor.split(0.8); // Replace with your train-test split ratio
```
String trainImages = "train-images.idx3-ubyte";
String trainLabels = "train-labels.idx1-ubyte";
String testImages = "t10k-images.idx3-ubyte";
String testLabels = "t10k-labels.idx1-ubyte";
Loader trainLoader = new ImageLoader(trainImages, trainLabels, batchSize);
Loader testLoader = new ImageLoader(testImages, testLabels, batchSize);
### Step 2: Preparing Training and Test Sets:
```

Extract the features and labels for both training and test sets:
### Step 2: Configure the MultilayerPerceptron

```java
var trainFeatures=dataProcessor.getTrainFeatures(featureColumnIndices);
var trainLabels=dataProcessor.getTrainLabels(targetColumnIndex);
var testFeatures=dataProcessor.getTestFeatures(featureColumnIndices);
var testLabels=dataProcessor.getTestLabels(targetColumnIndex);
```
int batchSize = 100;
int threads = 1;
int epochs = 10;
float initialLearningRate = 0.1f;
float finalLearningRate = 0.001f;
MetaData trainMetaData = trainLoader.open();
int inputSize = trainMetaData.getInputSize();
int outputSize = trainMetaData.getExpectedSize();
trainLoader.close();
```

### Step 3: Build the Network

### Step 3: Network Configuration
We use the NetworkBuilder Class

```java
var networkConfiguration=new NetworkConfiguration(
trainFeatures[0].length, // Number of input neurons
List.of(128,256,512), // Number of neurons in each hidden layer
3, // Number of output neurons
0.01, // Learning rate
300, // Number of epochs
ActivationFunction.LEAKY_RELU, // Activation function for hidden layers
ActivationFunction.SOFTMAX, // Activation function for output layer
LossFunction.CATEGORICAL_CROSS_ENTROPY, // Loss function
Initialization.XAVIER, // Weight initialization for hidden layers
Initialization.XAVIER // Weight initialization for output layer
);
```
new NetworkBuilder()
.addLayer(new DenseLayer(inputSize, 32)) //32 Neurons as output size
.addLayer(new ReLuLayer())
.addLayer(new DenseLayer(32, outputSize)) //32 Neurons as input size
.addLayer(new SoftmaxLayer())
.withBatchSize(batchSize)
.withLearningRates(initialLearningRate, finalLearningRate)
.withExecutionMode(singleThread)
.withEpochs(epochs)
.build()
.printArchitecture()
.fit(trainLoader, testLoader)
.saveModel("model.edux"); // Save the trained model
```

### Step 4: Load the model and continue training

### Step 4: Training and Evaluation
Load 'model.edux' and continue training for 10 epochs.

```java
MultilayerPerceptron multilayerPerceptron=new MultilayerPerceptron(
networkConfiguration,
testFeatures,
testLabels
);
multilayerPerceptron.train(trainFeatures,trainLabels);
multilayerPerceptron.evaluate(testFeatures,testLabels);
```
NeuralNetwork nn =
new NetworkBuilder().withEpochs(10).loadModel("model.edux").fit(trainLoader, testLoader);
```

### Results

```output
........................Epoch: 1, Loss: 1,14, Accuracy: 91,04
...
MultilayerPerceptron - Best accuracy after restoring best MLP model: 98,56%
........................Epoch: 10, Loss: 0,13, Accuracy: 96,16
```

### Working examples
Expand Down
Binary file added example/datasets/mnist/t10k-images.idx3-ubyte
Binary file not shown.
Binary file added example/datasets/mnist/t10k-labels.idx1-ubyte
Binary file not shown.
Binary file added example/datasets/mnist/train-images.idx3-ubyte
Binary file not shown.
Binary file added example/datasets/mnist/train-labels.idx1-ubyte
Binary file not shown.
23 changes: 0 additions & 23 deletions example/src/main/java/de/example/benchmark/Benchmark.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import de.edux.functions.loss.LossFunction;
import de.edux.ml.decisiontree.DecisionTree;
import de.edux.ml.knn.KnnClassifier;
import de.edux.ml.nn.config.NetworkConfiguration;
import de.edux.ml.nn.network.MultilayerPerceptron;
import de.edux.ml.randomforest.RandomForest;
import de.edux.ml.svm.SVMKernel;
import de.edux.ml.svm.SupportVectorMachine;
Expand Down Expand Up @@ -37,16 +35,13 @@ public class Benchmark {
private double[][] trainLabels;
private double[][] testFeatures;
private double[][] testLabels;
private MultilayerPerceptron multilayerPerceptron;
private NetworkConfiguration networkConfiguration;
private DataProcessor dataProcessor;

public Benchmark() {
results.put("KNN", new ArrayList<>());
results.put("DecisionTree", new ArrayList<>());
results.put("RandomForest", new ArrayList<>());
results.put("SVM", new ArrayList<>());
results.put("MLP", new ArrayList<>());

init();
}
Expand Down Expand Up @@ -80,38 +75,20 @@ private void run() {
Classifier randomForest = new RandomForest(500, 10, 2, 3, 3, 60);
Classifier svm = new SupportVectorMachine(SVMKernel.LINEAR, 1);

networkConfiguration =
new NetworkConfiguration(
trainFeatures[0].length,
List.of(64, 256, 512),
3,
0.01,
300,
ActivationFunction.LEAKY_RELU,
ActivationFunction.SOFTMAX,
LossFunction.CATEGORICAL_CROSS_ENTROPY,
Initialization.XAVIER,
Initialization.XAVIER);
multilayerPerceptron =
new MultilayerPerceptron(networkConfiguration, testFeatures, testLabels);

knn.train(trainFeatures, trainLabels);
decisionTree.train(trainFeatures, trainLabels);
randomForest.train(trainFeatures, trainLabels);
svm.train(trainFeatures, trainLabels);
multilayerPerceptron.train(trainFeatures, trainLabels);

double knnAccuracy = knn.evaluate(testFeatures, testLabels);
double decisionTreeAccuracy = decisionTree.evaluate(testFeatures, testLabels);
double randomForestAccuracy = randomForest.evaluate(testFeatures, testLabels);
double svmAccuracy = svm.evaluate(testFeatures, testLabels);
double multilayerPerceptronAccuracy = multilayerPerceptron.evaluate(testFeatures, testLabels);

results.get("KNN").add(knnAccuracy);
results.get("DecisionTree").add(decisionTreeAccuracy);
results.get("RandomForest").add(randomForestAccuracy);
results.get("SVM").add(svmAccuracy);
results.get("MLP").add(multilayerPerceptronAccuracy);
init();
}

Expand Down
87 changes: 87 additions & 0 deletions example/src/main/java/de/example/mlp/MlpExampleOnMNIST.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package de.example.mlp;

import de.edux.ml.api.ExecutionMode;
import de.edux.ml.mlp.core.network.NetworkBuilder;
import de.edux.ml.mlp.core.network.layers.DenseLayer;
import de.edux.ml.mlp.core.network.layers.ReLuLayer;
import de.edux.ml.mlp.core.network.layers.SoftmaxLayer;
import de.edux.ml.mlp.core.network.loader.image.ImageLoader;
import de.edux.ml.mlp.core.network.loader.Loader;
import de.edux.ml.mlp.core.network.loader.MetaData;
import java.io.File;

public class MlpExampleOnMNIST {
public static void main(String[] args) {
String trainImages =
"example"
+ File.separator
+ "datasets"
+ File.separator
+ "mnist"
+ File.separator
+ "train-images.idx3-ubyte";
String trainLabels =
"example"
+ File.separator
+ "datasets"
+ File.separator
+ "mnist"
+ File.separator
+ "train-labels.idx1-ubyte";
String testImages =
"example"
+ File.separator
+ "datasets"
+ File.separator
+ "mnist"
+ File.separator
+ "t10k-images.idx3-ubyte";
String testLabels =
"example"
+ File.separator
+ "datasets"
+ File.separator
+ "mnist"
+ File.separator
+ "t10k-labels.idx1-ubyte";

int batchSize = 100;
ExecutionMode singleThread = ExecutionMode.SINGLE_THREAD;
int epochs = 5;
float initialLearningRate = 0.1f;
float finalLearningRate = 0.001f;

Loader trainLoader = new ImageLoader(trainImages, trainLabels, batchSize);
Loader testLoader = new ImageLoader(testImages, testLabels, batchSize);

MetaData trainMetaData = trainLoader.open();
int inputSize = trainMetaData.getInputSize();
int outputSize = trainMetaData.getExpectedSize();
trainLoader.close();

// Training from scratch
new NetworkBuilder()
.addLayer(new DenseLayer(inputSize, 128))
.addLayer(new ReLuLayer())
.addLayer(new DenseLayer(128, 128))
.addLayer(new ReLuLayer())
.addLayer(new DenseLayer(128, outputSize))
.addLayer(new SoftmaxLayer())
.withBatchSize(batchSize)
.withLearningRates(initialLearningRate, finalLearningRate)
.withExecutionMode(singleThread)
.withEpochs(epochs)
.build()
.printArchitecture()
.fit(trainLoader, testLoader)
.saveModel("mnist_trained.edux");

// Loading a trained model
new NetworkBuilder()
.withExecutionMode(singleThread)
.withEpochs(5)
.withLearningRates(0.01f, 0.001f)
.loadModel("mnist_trained.edux")
.fit(trainLoader, testLoader);
}
}

This file was deleted.

Loading

0 comments on commit 504c579

Please sign in to comment.