Skip to content

Commit

Permalink
feat(#43): Convolutional Neural Network (CNN) Support #43
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Abramov committed Oct 15, 2023
1 parent 4c7c25b commit 0db5f89
Show file tree
Hide file tree
Showing 17 changed files with 1,063 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package de.example.cnn;

import de.edux.api.Classifier;
import de.edux.ml.cnn.*;

public class ConvolutionalNeuralNetworkExample {
final static int NUM_CLASSES = 1000;

public static void main(String[] args) {
Classifier alexNet = new Architect.Builder()
.addLayer(new ConvLayer(11, 11, 3, 96, 4, 0)) // 1. Convolutional Layer
.addLayer(new MaxPoolingLayer(3, 3, 2)) // 1. Max-Pooling Layer
.addLayer(new ConvLayer(5, 5, 96, 256, 1, 2)) // 2. Convolutional Layer
.addLayer(new MaxPoolingLayer(3, 3, 2)) // 2. Max-Pooling Layer
.addLayer(new ConvLayer(3, 3, 256, 384, 1, 1)) // 3. Convolutional Layer
.addLayer(new ConvLayer(3, 3, 384, 384, 1, 1)) // 4. Convolutional Layer
.addLayer(new ConvLayer(3, 3, 384, 256, 1, 1)) // 5. Convolutional Layer
.addLayer(new MaxPoolingLayer(3, 3, 2)) // 3. Max-Pooling Layer
.addLayer(new FlattenLayer()) // Flattening Layer
.addLayer(new DenseLayer(4096)) // 1. Fully Connected (Dense) Layer
.addLayer(new DropOutLayer(0.5)) // 1. Dropout Layer
.addLayer(new DenseLayer(4096)) // 2. Fully Connected (Dense) Layer
.addLayer(new DropOutLayer(0.5)) // 2. Dropout Layer
.addLayer(new DenseLayer(NUM_CLASSES)) // 3. Fully Connected (Dense) Layer
.build();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,7 @@

public enum ActivationFunction {

SIGMOID {
@Override
public double calculateActivation(double x) {
return 1 / (1 + Math.exp(-x));
}

@Override
public double calculateDerivative(double x) {
return calculateActivation(x) * (1 - calculateActivation(x));
}
},
RELU {
@Override
public double calculateActivation(double x) {
return Math.max(0, x);
}

@Override
public double calculateDerivative(double x) {
return x > 0 ? 1 : 0;
}
},
LEAKY_RELU {
@Override
public double calculateActivation(double x) {
return Math.max(0.01 * x, x);
}

@Override
public double calculateDerivative(double x) {
if (x > 0) {
return 1.0;
} else {
return 0.01;
}
}
},
TANH {
@Override
public double calculateActivation(double x) {
return Math.tanh(x);
}

@Override
public double calculateDerivative(double x) {
return 1 - Math.pow(calculateActivation(x), 2);
}
}, SOFTMAX {
SOFTMAX {
@Override
public double calculateActivation(double x) {
return Math.exp(x);
Expand Down
4 changes: 4 additions & 0 deletions lib/src/main/java/de/edux/functions/optimizer/Optimizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package de.edux.functions.optimizer;

public enum Optimizer {
}
18 changes: 18 additions & 0 deletions lib/src/main/java/de/edux/ml/cnn/Architect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.edux.ml.cnn;

import de.edux.api.Classifier;

public class Architect {



public static class Builder {

public Builder addLayer(Layer layer) {
return this;
}
public Classifier build() {
return null;
}
}
}
106 changes: 106 additions & 0 deletions lib/src/main/java/de/edux/ml/cnn/AveragePoolingLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package de.edux.ml.cnn;

import de.edux.functions.optimizer.Optimizer;

public class AveragePoolingLayer implements Layer {
private int poolSize;
private int stride;

public AveragePoolingLayer(int poolSize, int stride) {
this.poolSize = poolSize;
this.stride = stride;
}

@Override
public ITensor forward(ITensor input) {
// Größenangaben des Eingabesensors bestimmen
int[] inputShape = input.getShape();
int height = inputShape[0];
int width = inputShape[1];
int channels = inputShape[2];

// Größenangaben des Ausgabesensors bestimmen
int pooledHeight = (height - poolSize) / stride + 1;
int pooledWidth = (width - poolSize) / stride + 1;

ITensor output = new Tensor(pooledHeight, pooledWidth, channels);

for (int h = 0; h < pooledHeight; h++) {
for (int w = 0; w < pooledWidth; w++) {
for (int c = 0; c < channels; c++) {
double sum = 0;
for (int i = 0; i < poolSize; i++) {
for (int j = 0; j < poolSize; j++) {
sum += input.get(h * stride + i, w * stride + j, c);
}
}
double average = sum / (poolSize * poolSize);
output.set(average, h, w, c);
}
}
}

return output;
}

@Override
public ITensor backward(ITensor gradient) {
// Größenangaben des Gradiententensors bestimmen
int[] gradientShape = gradient.getShape();
int height = gradientShape[0];
int width = gradientShape[1];
int channels = gradientShape[2];

ITensor dInput = new Tensor(height * stride, width * stride, channels);

for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
for (int c = 0; c < channels; c++) {
double gradientValue = gradient.get(h, w, c) / (poolSize * poolSize);
for (int i = 0; i < poolSize; i++) {
for (int j = 0; j < poolSize; j++) {
dInput.set(gradientValue, h * stride + i, w * stride + j, c);
}
}
}
}
}

return dInput;
}

@Override
public void initializeWeights() {

}

@Override
public void updateWeights(Optimizer optimizer) {

}

@Override
public ITensor getWeights() {
return null;
}

@Override
public void setWeights(ITensor weights) {

}

@Override
public ITensor getBiases() {
return null;
}

@Override
public void setBiases(ITensor biases) {

}

@Override
public boolean isTrainable() {
return false;
}
}
81 changes: 81 additions & 0 deletions lib/src/main/java/de/edux/ml/cnn/ConvLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package de.edux.ml.cnn;

import de.edux.functions.optimizer.Optimizer;


public class ConvLayer implements Layer {
private ITensor filters; // Der Filter-Tensor: [filterHeight, filterWidth, inputChannels, outputChannels]
private ITensor biases; // Optional, je nach Architektur
private int stride;
private int padding;

public ConvLayer(int filterHeight, int filterWidth, int inputChannels, int outputChannels, int stride, int padding) {
this.stride = stride;
this.padding = padding;
this.filters = new Tensor(filterHeight, filterWidth, inputChannels, outputChannels);
this.biases = new Tensor(1, 1, 1, outputChannels); // 1x1 bias für jeden Ausgabekanal
initializeWeights();
}

@Override
public ITensor forward(ITensor input) {
// ... Ihre bisherige Implementierung ..
return null;
}

@Override
public ITensor backward(ITensor gradient) {
// ... Ihre bisherige Implementierung ...
return null;
}

@Override
public void initializeWeights() {
// 1. Xavier/Glorot-Initialisierung (als Beispiel):
// Dies ist eine grobe Implementierung; Sie könnten eine spezielle Methode in Ihrem Tensor oder eine Utility-Methode verwenden, um dies effizient zu tun.
int fanIn = filters.getShape()[2]; // Anzahl der Eingangskanäle
int fanOut = filters.getShape()[3]; // Anzahl der Ausgangskanäle
double variance = 2.0 / (fanIn + fanOut);
double scale = Math.sqrt(variance);

for (int i = 0; i < filters.getTotalSize(); i++) {
double weight = (Math.random() * 2 - 1) * scale; // Zufällige Initialisierung im Bereich [-scale, scale]
filters.setValueAt(i, weight);
}

// Biases auf 0 setzen (üblich bei Conv-Layern)
for (int i = 0; i < biases.getTotalSize(); i++) {
biases.setValueAt(i, 0.0);
}
}

@Override
public void updateWeights(Optimizer optimizer) {
// ... Ihre bisherige Implementierung ...
}

@Override
public ITensor getWeights() {
return filters;
}

@Override
public void setWeights(ITensor weights) {
this.filters = weights;
}

@Override
public ITensor getBiases() {
return biases;
}

@Override
public void setBiases(ITensor biases) {
this.biases = biases;
}

@Override
public boolean isTrainable() {
return true; // Faltungsschichten sind in der Regel trainierbar
}
}
20 changes: 20 additions & 0 deletions lib/src/main/java/de/edux/ml/cnn/ConvolutionalNeuralNetwork.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package de.edux.ml.cnn;

import de.edux.api.Classifier;

public class ConvolutionalNeuralNetwork implements Classifier {
@Override
public boolean train(double[][] features, double[][] labels) {
return false;
}

@Override
public double evaluate(double[][] testInputs, double[][] testTargets) {
return 0;
}

@Override
public double[] predict(double[] feature) {
return new double[0];
}
}
57 changes: 57 additions & 0 deletions lib/src/main/java/de/edux/ml/cnn/DenseLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package de.edux.ml.cnn;

import de.edux.functions.optimizer.Optimizer;

public class DenseLayer implements Layer {

public DenseLayer(int inputSize, int outputSize) {
}

public DenseLayer(int numberOfClasses) {
}

@Override
public ITensor forward(ITensor input) {
return null;
}

@Override
public ITensor backward(ITensor gradient) {
return null;
}

@Override
public void initializeWeights() {

}

@Override
public void updateWeights(Optimizer optimizer) {

}

@Override
public ITensor getWeights() {
return null;
}

@Override
public void setWeights(ITensor weights) {

}

@Override
public ITensor getBiases() {
return null;
}

@Override
public void setBiases(ITensor biases) {

}

@Override
public boolean isTrainable() {
return false;
}
}
Loading

0 comments on commit 0db5f89

Please sign in to comment.