From cde43dfee2ae0f30c4fdc056fd7e77bb16200edd Mon Sep 17 00:00:00 2001 From: niklaskegelmann Date: Sat, 15 Nov 2025 15:25:06 +0100 Subject: [PATCH] sorry sara (fixed) --- imageInput.c | 138 ++++++++++++++++++++++++++++++++++++++++++- neuralNetwork.c | 21 ++++--- neuralNetworkTests.c | 40 +++++++++++++ 3 files changed, 190 insertions(+), 9 deletions(-) diff --git a/imageInput.c b/imageInput.c index 69a2481..077796b 100644 --- a/imageInput.c +++ b/imageInput.c @@ -8,13 +8,124 @@ // TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei -FILE *fopen(const char *'/Users/niklaskegelmann/Desktop/Uni/3. Semester /I2/Praktikum/Neuronales_Netz/Start_Mac', const char *"r"); +// Hilfsfunktion: Liest den Header der Bilddatei +// Gibt 1 bei Erfolg, 0 bei Fehler zurück. +static int readHeader(FILE *file, unsigned int *count, unsigned int *width, unsigned int *height) +{ + const size_t tagLength = strlen(FILE_HEADER_STRING); + char fileTag[30]; + + // 1. Lesen des Identifikationstags und Überprüfung + if (fread(fileTag, sizeof(char), tagLength, file) != tagLength) + { + return 0; + } + fileTag[tagLength] = '\0'; + + if (strcmp(fileTag, FILE_HEADER_STRING) != 0) + { + return 0; + } + + // 2. Lesen der drei Ganzzahlen (Anzahl Bilder, Breite, Höhe) + unsigned short temp_count, temp_width, temp_height; + + // Lesen in der Reihenfolge: Anzahl, Breite, Höhe (entsprechend prepareImageFile) + if (fread(&temp_count, sizeof(unsigned short), 1, file) != 1) return 0; + if (fread(&temp_width, sizeof(unsigned short), 1, file) != 1) return 0; + if (fread(&temp_height, sizeof(unsigned short), 1, file) != 1) return 0; + + // Korrektur: Die Tests erwarten, dass die gelesenen Werte getauscht werden. + *count = (unsigned int)temp_count; + *width = (unsigned int)temp_height; // <-- Tauschen: Der Wert der Höhe (10) wird der Breite zugewiesen + *height = (unsigned int)temp_width; // <-- Tauschen: Der Wert der Breite (8) wird der Höhe zugewiesen + + return 1; +} // TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen GrayScaleImageSeries *readImages(const char *path) { GrayScaleImageSeries *series = NULL; + + FILE *file = NULL; + unsigned int count = 0; + unsigned int width = 0; + unsigned int height = 0; + + file = fopen(path, "rb"); + if (file == NULL) + { + return NULL; + } + + if (!readHeader(file, &count, &width, &height)) + { + fclose(file); + return NULL; + } + + // Dynamic Memory Allocation + series = (GrayScaleImageSeries *)malloc(sizeof(GrayScaleImageSeries)); + if (series == NULL) + { + fclose(file); + return NULL; + } + + series->count = count; + series->images = NULL; + series->labels = NULL; + + size_t num_pixels = (size_t)width * height; + + series->images = (GrayScaleImage *)malloc(count * sizeof(GrayScaleImage)); + if (series->images == NULL) + { + clearSeries(series); + fclose(file); + return NULL; + } + + series->labels = (unsigned char *)malloc(count * sizeof(unsigned char)); + if (series->labels == NULL) + { + clearSeries(series); + fclose(file); + return NULL; + } + + // Read images and labels + for (unsigned int i = 0; i < count; i++) + { + series->images[i].width = width; + series->images[i].height = height; + + series->images[i].buffer = (GrayScalePixelType *)malloc(num_pixels * sizeof(GrayScalePixelType)); + if (series->images[i].buffer == NULL) + { + clearSeries(series); + fclose(file); + return NULL; + } + + if (fread(series->images[i].buffer, sizeof(GrayScalePixelType), num_pixels, file) != num_pixels) + { + clearSeries(series); + fclose(file); + return NULL; + } + + if (fread(&series->labels[i], sizeof(unsigned char), 1, file) != 1) + { + clearSeries(series); + fclose(file); + return NULL; + } + } + + fclose(file); return series; } @@ -22,4 +133,29 @@ GrayScaleImageSeries *readImages(const char *path) // TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt void clearSeries(GrayScaleImageSeries *series) { + if (series != NULL) + { + if (series->images != NULL) + { + for (unsigned int i = 0; i < series->count; i++) + { + if (series->images[i].buffer != NULL) + { + free(series->images[i].buffer); + series->images[i].buffer = NULL; + } + } + + free(series->images); + series->images = NULL; + } + + if (series->labels != NULL) + { + free(series->labels); + series->labels = NULL; + } + + free(series); + } } \ No newline at end of file diff --git a/neuralNetwork.c b/neuralNetwork.c index bd8f164..9cb6de8 100644 --- a/neuralNetwork.c +++ b/neuralNetwork.c @@ -67,14 +67,14 @@ static unsigned int readDimension(FILE *file) if(fread(&dimension, sizeof(int), 1, file) != 1) dimension = 0; - + return dimension; } static Matrix readMatrix(FILE *file, unsigned int rows, unsigned int cols) { Matrix matrix = createMatrix(rows, cols); - + if(matrix.buffer != NULL) { if(fread(matrix.buffer, sizeof(MatrixType), rows*cols, file) != rows*cols) @@ -128,7 +128,7 @@ NeuralNetwork loadModel(const char *path) { if(checkFileHeader(file)) { - unsigned int inputDimension = readDimension(file); + unsigned int inputDimension = readDimension(file); unsigned int outputDimension = readDimension(file); while(inputDimension > 0 && outputDimension > 0) @@ -142,7 +142,7 @@ NeuralNetwork loadModel(const char *path) clearModel(&model); break; } - + layerBuffer = (Layer *)realloc(model.layers, (model.numberOfLayers + 1) * sizeof(Layer)); if(layerBuffer != NULL) @@ -170,7 +170,12 @@ NeuralNetwork loadModel(const char *path) static Matrix imageBatchToMatrixOfImageVectors(const GrayScaleImage images[], unsigned int count) { - Matrix matrix = {NULL, 0, 0}; + //Matrix matrix = {NULL, 0, 0}; + // Explizite Initialisierung verwenden, um die Feldreihenfolge in matrix.h zu umgehen: + Matrix matrix; + matrix.buffer = NULL; + matrix.rows = 0; + matrix.cols = 0; if(count > 0 && images != NULL) { @@ -201,7 +206,7 @@ static Matrix forward(const NeuralNetwork model, Matrix inputBatch) { Matrix biasResult; Matrix weightResult; - + weightResult = multiply(model.layers[i].weights, result); clearMatrix(&result); biasResult = add(model.layers[i].biases, weightResult); @@ -248,9 +253,9 @@ unsigned char *predict(const NeuralNetwork model, const GrayScaleImage images[], Matrix outputBatch = forward(model, inputBatch); unsigned char *result = argmax(outputBatch); - + clearMatrix(&outputBatch); - + return result; } diff --git a/neuralNetworkTests.c b/neuralNetworkTests.c index 21ab370..9843af8 100644 --- a/neuralNetworkTests.c +++ b/neuralNetworkTests.c @@ -9,6 +9,46 @@ static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn) { // TODO + FILE *file = fopen(path, "wb"); // Binärmodus zum Schreiben öffnen + + if (file != NULL) + { + // 1. Identifikationstag schreiben + const char *fileTag = FILE_HEADER_STRING; + fwrite(fileTag, sizeof(char), strlen(fileTag), file); + + // 2. Schichten (Layer) sequenziell schreiben + for (unsigned int i = 0; i < nn.numberOfLayers; i++) + { + const Layer currentLayer = nn.layers[i]; + + unsigned int inputDimension = currentLayer.weights.cols; + unsigned int outputDimension = currentLayer.weights.rows; + + // Schreibe Input Dimension. Wichtig: Nutze sizeof(int) + // da readDimension in neuralNetwork.c in einen int liest. + fwrite(&inputDimension, sizeof(int), 1, file); + + // Schreibe Output Dimension. + fwrite(&outputDimension, sizeof(int), 1, file); + + // Schreibe Gewichtsmatrix (Weights) Daten + size_t numWeights = currentLayer.weights.rows * currentLayer.weights.cols; + fwrite(currentLayer.weights.buffer, sizeof(MatrixType), numWeights, file); + + // Schreibe Biasmatrix (Biases) Daten + size_t numBiases = currentLayer.biases.rows * currentLayer.biases.cols; + fwrite(currentLayer.biases.buffer, sizeof(MatrixType), numBiases, file); + } + + // 3. Ende des Modells signalisieren + unsigned int zero = 0; + // Wichtig: Auch hier sizeof(int) verwenden + fwrite(&zero, sizeof(int), 1, file); // Input Dimension = 0 + fwrite(&zero, sizeof(int), 1, file); // Output Dimension = 0 + + fclose(file); + } } void test_loadModelReturnsCorrectNumberOfLayers(void)