Commit 64211316 authored by Nicolas Peslerbe's avatar Nicolas Peslerbe

.gitignore fix

parent af2e133c
Pipeline #31 canceled with stages
......@@ -11,4 +11,4 @@
/build
/captures
.externalNativeBuild
/fertilizeSorting
fertilizeSorting
package ch.bionomous.eggsorter.controller.processing.fertilizeSorting;
import android.graphics.Bitmap;
import android.graphics.Color;
import Jama.Matrix;
public class BoundaryImage {
Bitmap image;
protected static final int WINDOW_SIZE = 500; // in pixels
protected static final int POINT_SIZE = 10; // in pixels
protected static final int BOUNDARY_SIZE = 2; // in pixels
// Global variables
private Matrix Xp_norm;
private int nbFert;
private int ex, ey;
GmmModel gmmModels;
// Constructor
public BoundaryImage(Matrix Xp_norm, int nbFert, int ex, int ey, GmmModel gmmModel) {
image = Bitmap.createBitmap(WINDOW_SIZE, WINDOW_SIZE, Bitmap.Config.ARGB_8888);
this.Xp_norm = Xp_norm;
this.nbFert = nbFert;
this.ex = ex;
this.ey = ey;
this.gmmModels = gmmModels;
}
// Method to draw the background classification boundary
public void drawClassBoundary() {
for (int x=0; x<WINDOW_SIZE; x++) // for every image column
for (int y=0; y<WINDOW_SIZE; y++) {// for every image row
double[][] values = {{(double)x/WINDOW_SIZE}, {(double)y/WINDOW_SIZE}};
Matrix X_test = new Matrix(values);
// Compute the pixel label
SortAlgo0.Class label = gmmModels.classifySingle(X_test);
// Give a color to the pixel in function of the label
int color;
if (label == SortAlgo0.Class.Fertilized)
color = Color.rgb(100, 0, 0); // dark red color
else
color = Color.rgb(0, 0, 100); // dark blue color
image.setPixel(x, y, color);
}
}
// Method to draw the datapoints on classification boundary image
public void drawDatapoints() {
int M = Xp_norm.getColumnDimension();
// Draw the fert datapoints in bright red
int color = Color.RED;
for (int j=0; j<nbFert; j++) {
int projection_x = (int)(Xp_norm.get(ex-1, j)*WINDOW_SIZE);
int projection_y = (int)(Xp_norm.get(ey-1, j)*WINDOW_SIZE);
drawPoint(projection_x, projection_y, color);
}
// Draw the unfert datapoints in bright blue
color = Color.BLUE;
for (int j=nbFert; j<M; j++) {
int projection_x = (int)(Xp_norm.get(ex-1, j)*WINDOW_SIZE);
int projection_y = (int)(Xp_norm.get(ey-1, j)*WINDOW_SIZE);
drawPoint(projection_x, projection_y, color);
}
}
// Method to put a circle with a color C on a datapoint with pixel coordinates (x0;y0)
private void drawPoint(int x0, int y0, int C) {
int R = POINT_SIZE/2;
for (int x=0; x<WINDOW_SIZE; x++) // for every image column
for (int y=0; y<WINDOW_SIZE; y++) // for every image row
if ((x-x0)*(x-x0) + (y-y0)*(y-y0) < R*R)
image.setPixel(x, y, C);
}
}
package ch.bionomous.eggsorter.controller.processing.fertilizeSorting;
import Jama.Matrix;
import ch.bionomous.eggsorter.filesmanager.FilesManager;
public class CrossValidation {
// Constants
protected static final double SMALL_DIFF = 1e-6;
protected static final double MAX_DIST = 1.0;
protected static final int MAX_ITER = 100;
protected static final int N = 2;
// Global variables
private int p, M;
private int best_K;
private int best_ex, best_ey;
private double best_accuracy = 0.0;
// Constructor
public CrossValidation(Matrix xpNorm, int K_max, int E_max, int F_fold, double tt_ratio, double unequalClassCoef, String configId) {
this.p = xpNorm.getRowDimension();
this.M = xpNorm.getColumnDimension();
if (p < E_max)
E_max = p;
int nbFert = FilesManager.getIntValueInFile(configId + "/numberOfFertImagesFile.txt");
for (int K=1; K<=K_max; K++ )
for (int ex=0; ex<E_max; ex++)
for (int ey=0; ey<E_max; ey++)
if (ex<ey) {
// Extract the 2D dataset
int[] rows = {ex, ey};
Matrix Xp_norm_2D = xpNorm.getMatrix(rows, 0, M-1);
// F-fold cross-validation
double mean_accuracy = 0;
for (int f=0; f<F_fold; f++ ) {
// Split the dataset into train and test datasets
SplitDataTrainTest splitDataTrainTest = new SplitDataTrainTest(Xp_norm_2D, nbFert, tt_ratio);
Matrix X_train = splitDataTrainTest.getTrainMatrix();
Matrix X_test = splitDataTrainTest.getTestMatrix();
Matrix y_test = splitDataTrainTest.getTestLabels();
// Train the 2D dataset
GmmModel gmmModels = new GmmModel(X_train, K, unequalClassCoef, configId);
// Test the 2D dataset
Matrix y_est = gmmModels.classify(X_test);
// Compute the mean accuracy
mean_accuracy += getAccuracy(y_test, y_est, unequalClassCoef);
}
mean_accuracy = mean_accuracy/F_fold;
// Find the best accuracy
if (mean_accuracy > best_accuracy) {
best_accuracy = mean_accuracy;
best_K = K;
best_ex = ex;
best_ey = ey;
}
}
}
public double getBestAccuracy() {
return best_accuracy;
}
public int getBestK() {
return best_K;
}
public int getBestEx() {
return best_ex;
}
public int getBestEy() {
return best_ey;
}
// Compute the accuracy of the classification
public static double getAccuracy(Matrix y_test, Matrix y_est, double unequalClassCoef) {
double accuracy = unequalClassCoef * getFertAccuracy(y_test, y_est) +
(1.0-unequalClassCoef) * getUnfertAccuracy(y_test, y_est);
return accuracy;
}
// Compute the fertilized egg classified as unfertilized accuracy
public static double getFertAccuracy(Matrix y_test, Matrix y_est) {
double accuracy = 0;
int M_test = y_test.getColumnDimension();
int M_fert = 0;
int N_errors = 0; // compute the number of missclassified fertilized eggs
for (int j=0; j<M_test; j++)
if ( y_test.get(0, j) == 0 ) { // take the fertilized eggs
M_fert++;
if ( y_est.get(0, j) == 1 ) // take the classified as unfertilized
N_errors++;
}
accuracy = (double)(M_fert - N_errors)/M_fert;
return accuracy;
}
// Compute the unfertilized egg classified as fertilized accuracy
public static double getUnfertAccuracy(Matrix y_test, Matrix y_est) {
double accuracy = 0;
int M_test = y_test.getColumnDimension();
int M_unfert = 0;
int N_errors = 0; // compute the number of missclassified unfertilized eggs
for (int j=0; j<M_test; j++)
if ( y_test.get(0, j) == 1 ) { // take the unfertilized eggs
M_unfert++;
if ( y_est.get(0, j) == 0 ) // take the classified as fertilized
N_errors++;
}
accuracy = (double)(M_unfert - N_errors)/M_unfert;
return accuracy;
}
}
package ch.bionomous.eggsorter.controller.processing.fertilizeSorting;
import Jama.Matrix;
public class GmmEM {
// Constants
protected static final double SMALL_DIFF = 1e-6;
protected static final double MAX_DIST = 1.0;
protected static final int MAX_ITER = 100;
// Global variables
private int N, M;
private int K;
private int[] labels;
private Matrix X;
private double[] priors;
private Matrix mu;
private double[][][] sigma;
// Constructor
public GmmEM(Matrix X, int K) {
this.N = X.getRowDimension();
this.M = X.getColumnDimension();
this.K = K;
this.X = X;
this.priors = new double[K];
this.mu = new Matrix(N, K);
this.sigma = new double[N][N][K];
// Step 1. GMM Initialization
gmmInit();
double loglikelihood = 0;
double loglikelihood_before = 0;
int iter = 0;
while(iter < MAX_ITER && (Math.abs(loglikelihood-loglikelihood_before) > SMALL_DIFF || iter==0) ) {
loglikelihood_before = loglikelihood;
// To compare with all gaussians
Matrix sum_all_gausssians = new Matrix(1, M);
for (int k=0; k<K; k++) {
Matrix prob_k = gaussPdf( X, mu.getMatrix(0, N-1, k, k), getSigmaMatrix(k) );
sum_all_gausssians.plusEquals(prob_k.times(priors[k]));
}
for (int k=0; k<K; k++) {
// Step 2. E-Step
// Responsible gaussian probability for gaussian k
Matrix prob_k = gaussPdf( X, mu.getMatrix(0, N-1, k, k), getSigmaMatrix(k) );
// A posteriori probability for gaussian k
Matrix a_post_prob_k = prob_k.times(priors[k]).arrayRightDivide(sum_all_gausssians);
// Step 3. M-Step
// Update priors
priors[k] = 0;
for (int j=0; j<M; j++)
priors[k] += a_post_prob_k.get(0, j)/M;
// Update means
mu.setMatrix(0, N-1, k, k, X.times(a_post_prob_k.transpose()).times(1/(priors[k]*M)));
// Update covariances
Matrix sigmaMatrix = new Matrix(N, N);
for (int j=0; j<M; j++) {
// Distance vector between the datapoint and the centroid
Matrix X_dist = X.getMatrix(0, N-1, j, j).minus(mu.getMatrix(0, N-1, k, k));
sigmaMatrix.plusEquals(X_dist.times(X_dist.transpose()).times(a_post_prob_k.get(0, j)));
}
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
sigma[i][j][k] = sigmaMatrix.get(i, j)/(priors[k]*M);
}
// Step 4. Check for log likelihood stabilization
// Compute the likelihood
Matrix likelihood = new Matrix(1, M);
for (int k = 0; k<K; k++) {
likelihood.plusEquals(gaussPdf( X, mu.getMatrix(0, N-1, k, k), getSigmaMatrix(k) ).times(priors[k]));
}
loglikelihood = 0;
for (int j = 0; j<M; j++) {
loglikelihood += Math.log(likelihood.get(0, j));
}
iter++;
} // End while loop
}
public double[] getPriors() {
return priors;
}
public double[][] getMu() {
return mu.getArrayCopy();
}
public double[][][] getSigma() {
return sigma;
}
public int[] getLabels() {
return labels;
}
private void gmmInit() {
Kmeans kmeans = new Kmeans(X, K);
int[] labels0 = kmeans.getLabels();
this.mu = kmeans.getMu();
for (int k=0; k<K; k++) {
// Initialize the prior
this.priors[k] = 1.0/K;
int nb_labeled_to_cluster = 0;
for (int j=0; j<M; j++)
if (labels0[j] == k)
nb_labeled_to_cluster++;
Matrix X_k = new Matrix(N, nb_labeled_to_cluster);
int index = 0;
for (int j=0; j<M; j++)
if (labels0[j] == k) {
X_k.setMatrix(0, N-1, index, index, X.getMatrix(0, N-1, j, j));
index++;
}
// Zero-mean data
Matrix X_k_zm = removeTheMean(X_k.copy());
// Initialize the covariance matrix
Matrix SigmaMatrix = X_k_zm.times(X_k_zm.transpose()).times(1/((double)nb_labeled_to_cluster-1));
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
this.sigma[i][j][k] = SigmaMatrix.get(i, j);
}
}
public Matrix removeTheMean(Matrix X) {
int M = X.getColumnDimension();
Matrix meanMatrix = new Matrix(N, M);
// Compute the mean of X
Matrix mean = getTheMean(X);
for (int j=0; j<M; j++)
meanMatrix.setMatrix(0, N-1, j, j, mean);
// Remove the mean to the dataset
X.minusEquals(meanMatrix); // compute X-mean(X)
return X;
}
private Matrix getTheMean(Matrix X) {
int M = X.getColumnDimension();
Matrix mean = new Matrix(N, 1); // construct an N-by-1 matrix of zeros
for (int j=0; j<M; j++)
mean.plusEquals(X.getMatrix(0, N-1, j, j));
mean.timesEquals(1/(double)M);
return mean;
}
// Function to get the covariance matrix of a gaussian of index k
private Matrix getSigmaMatrix(int k) {
Matrix sigma = new Matrix(N, N);
for (int i=0; i<N; i++)
for (int j=0; j<N; j++) {
// Add a tiny variance to the diagonal values to avoid numerical instability
if (i==j)
this.sigma[i][j][k] += SMALL_DIFF;
sigma.set(i, j, this.sigma[i][j][k]);
}
return sigma;
}
// Function to compute the Probability Density Function (PDF) of a multivariate
// Gaussian represented by a mean and a covariance matrix.
private Matrix gaussPdf(Matrix X, Matrix mu, Matrix sigma) {
Matrix pdf = new Matrix(1, M);
// Constant in front of the exponential function
double a = 1/( Math.pow(2*Math.PI, N/2) * Math.sqrt(sigma.det()) );
for (int j=0; j<M; j++) {
try {
// Distance vector between the datapoint and the centroid
Matrix X_dist = X.getMatrix(0, N-1, j, j).minus(mu);
// Exponential term
Matrix B = X_dist.transpose().times( sigma.inverse() ).times( X_dist ).times( -0.5 );
double b = B.get(0, 0);
// Compute the PDF
pdf.set(0, j, a*Math.exp(b));
} catch(Exception e) {System.out.println(e);}
}
return pdf;
}
}
package ch.bionomous.eggsorter.controller.processing.fertilizeSorting;
import android.graphics.Bitmap;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;
import Jama.Matrix;
import ch.bionomous.eggsorter.filesmanager.FilesManager;
public class GmmModel {
// Global variables
protected String _gmmModelFile; // by default
protected String _boundaryFolder;
protected String _boundaryName;
private int N = 2; // by default
private int K;
private double[] pClass;
private double[] priorsFert;
private double[] priorsUnfert;
private double[][] muFert;
private double[][] muUnfert;
private double[][][] sigmaFert;
private double[][][] sigmaUnfert;
// 1st constructor (construct the GMM model from a training dataset)
public GmmModel(Matrix X_train, int K, double unequalClassCoef, String configId) {
this.K = K;
this.N = X_train.getRowDimension()-1;
this.pClass = new double[2];
this._gmmModelFile = configId + "/GMMmodels.txt";
pClass[0] = unequalClassCoef; // we accept some fertilized egg classified as unfertilized
pClass[1] = 1.0 - unequalClassCoef; // we don't want unfertilized egg classified as fertilized
// Train fertilized datapoints
Matrix X_fert_train = getTrainMatrix(SortAlgo0.Class.Fertilized, X_train);
computeModel(SortAlgo0.Class.Fertilized, X_fert_train);
// Train unfertilized datapoints
Matrix X_unfert_train = getTrainMatrix(SortAlgo0.Class.Unfertilized, X_train);
computeModel(SortAlgo0.Class.Unfertilized, X_unfert_train);
}
// 2nd constructor (takes the GMM model from file)
public GmmModel(String configId) {
try {
File filePath = new File(FilesManager.DOCUMENTS_DIR, configId + "/GMMmodels.txt");
Scanner scanner = new Scanner(filePath).useLocale(Locale.US);
N = scanner.nextInt(); // projection dimension
K = scanner.nextInt(); // number of gaussians per class
pClass = new double[2];
priorsFert = new double[K];
priorsUnfert = new double[K];
muFert = new double[N][K];
muUnfert = new double[N][K];
sigmaFert = new double[N][N][K];
sigmaUnfert = new double[N][N][K];
pClass[0] = scanner.nextDouble();
pClass[1] = scanner.nextDouble();
for (int k=0; k<K; k++) {
priorsFert[k] = scanner.nextDouble();
priorsUnfert[k] = scanner.nextDouble();
for (int i=0; i<N; i++)
muFert[i][k] = scanner.nextDouble();
for (int i=0; i<N; i++)
muUnfert[i][k] = scanner.nextDouble();
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
sigmaFert[i][j][k] = scanner.nextDouble();
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
sigmaUnfert[i][j][k] = scanner.nextDouble();
}
scanner.close();
} catch (Exception e) {
System.out.println(e);
}
}
// Method to print the GMM model information in a file
public void printModelsInFile() {
try {
File file = new File(_gmmModelFile);
FileWriter fileWriter = new FileWriter(file);
PrintWriter writer = new PrintWriter(fileWriter);
writer.println(N + " " + K);
writer.println(pClass[0] + " " + pClass[1]);
for (int k=0; k<K; k++) {
writer.println(priorsFert[k] + " " + priorsUnfert[k]);
for (int i=0; i<N; i++)
writer.print(muFert[i][k] + " ");
writer.println(" ");
for (int i=0; i<N; i++)
writer.print(muUnfert[i][k] + " ");
writer.println(" ");
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
writer.print(sigmaFert[i][j][k] + " ");
writer.println(" ");
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
writer.print(sigmaUnfert[i][j][k] + " ");
writer.println(" ");