Compare commits

..
4 Commits
38 changed files with 119 additions and 341 deletions

No files matched your search

+60 -3
View File
@@ -1,4 +1,61 @@
mnist
runTests
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.exe
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
Startcode/mnist
Startcode/runTests
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# IDE folders
.vscode/
.idea/
# macOS
.DS_Store
+22
View File
@@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei
// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
GrayScaleImageSeries *readImages(const char *path)
{
GrayScaleImageSeries *series = NULL;
return series;
}
// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt
void clearSeries(GrayScaleImageSeries *series)
{
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+35
View File
@@ -0,0 +1,35 @@
#include <stdlib.h>
#include <string.h>
#include "matrix.h"
// TODO Matrix-Funktionen implementieren
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
}
void clearMatrix(Matrix *matrix)
{
}
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
}
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
}
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
}
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
}
-7
View File
@@ -6,13 +6,6 @@
typedef float MatrixType;
// TODO Matrixtyp definieren
typedef struct
{
int rows;
int cols;
float *buffer;
} Matrix;
Matrix createMatrix(unsigned int rows, unsigned int cols);
+1 -1
View File
@@ -164,7 +164,7 @@ void test_setMatrixAtFailsOnIndicesOutOfRange(void)
Matrix matrixToTest = {.rows=2, .cols=3, .buffer=buffer};
setMatrixAt(-1, matrixToTest, 2, 3);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, matrixToTest.cols * matrixToTest.rows);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, sizeof(buffer)/sizeof(MatrixType));
}
void setUp(void) {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -8,43 +8,7 @@
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
{
FILE *file = fopen(path, "wb");
if (file == NULL) {
return;
}
// Magic String direkt schreiben
const char *header = "__info2_neural_network_file_format__";
fwrite(header, sizeof(char), strlen(header), file);
// Erste inputDimension schreiben (vom ersten Layer)
if (nn.numberOfLayers > 0) {
unsigned int inputDim = nn.layers[0].weights.cols;
fwrite(&inputDim, sizeof(unsigned int), 1, file);
}
// Für jeden Layer: outputDimension, weights und biases schreiben
for (unsigned int i = 0; i < nn.numberOfLayers; i++) {
Layer layer = nn.layers[i];
// Output-Dimension dieses Layers schreiben
unsigned int outputDim = layer.weights.rows;
fwrite(&outputDim, sizeof(unsigned int), 1, file);
// Weights schreiben (alle Daten)
unsigned int weightSize = layer.weights.rows * layer.weights.cols;
fwrite(layer.weights.buffer, sizeof(MatrixType), weightSize, file);
// Biases schreiben (alle Daten)
unsigned int biasSize = layer.biases.rows * layer.biases.cols;
fwrite(layer.biases.buffer, sizeof(MatrixType), biasSize, file);
}
// Endmarkierung schreiben (0 als nächste outputDimension)
unsigned int endMarker = 0;
fwrite(&endMarker, sizeof(unsigned int), 1, file);
fclose(file);
// TODO
}
void test_loadModelReturnsCorrectNumberOfLayers(void)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-154
View File
@@ -1,154 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
// Hilfsfunktion: File Header überprüfen
static int checkFileHeader(FILE* f) {
char buffer[BUFFER_SIZE];
size_t len = strlen(FILE_HEADER_STRING);
if (fread(buffer, 1, len, f) != len) {
return -1; // Fehler beim Lesen
}
buffer[len] = '\0';
return strcmp(buffer, FILE_HEADER_STRING) == 0 ? 0 : -1;
}
// Hilfsfunktion: Metadaten lesen (Anzahl, Breite, Höhe)
static int readImageMeta(FILE* f, unsigned short* count, unsigned short* width, unsigned short* height) {
if (fread(count, sizeof(unsigned short), 1, f) != 1) return -1;
if (fread(width, sizeof(unsigned short), 1, f) != 1) return -1;
if (fread(height, sizeof(unsigned short), 1, f) != 1) return -1;
return 0;
}
// Hilfsfunktion: Ein einzelnes Bild einlesen (NUR Pixel, OHNE Label)
static GrayScaleImage readSingleImage(FILE* f, unsigned short width, unsigned short height) {
GrayScaleImage img;
// Breite und Höhe setzen
img.width = width;
img.height = height;
// Speicher für Pixel reservieren
size_t pixelCount = (size_t)width * (size_t)height;
img.buffer = malloc(pixelCount * sizeof(GrayScalePixelType));
if (img.buffer == NULL) {
// Fehlerfall: kein Speicher
img.width = 0;
img.height = 0;
return img;
}
// Pixeldaten einlesen
if (fread(img.buffer, sizeof(GrayScalePixelType), pixelCount, f) != pixelCount) {
// Fehler beim Lesen: Speicher freigeben
free(img.buffer);
img.buffer = NULL;
img.width = 0;
img.height = 0;
}
return img;
}
// Hauptfunktion: Bildserie aus Datei lesen
GrayScaleImageSeries *readImages(const char *path)
{
FILE *f = fopen(path, "rb");
if (f == NULL) {
return NULL; // Datei konnte nicht geöffnet werden
}
// 1. Header prüfen
if (checkFileHeader(f) != 0) {
fclose(f);
return NULL; // falsches Dateiformat
}
// 2. Metadaten lesen (Anzahl, Breite, Höhe)
unsigned short count, width, height;
if (readImageMeta(f, &count, &width, &height) != 0) {
fclose(f);
return NULL; // Metadaten konnten nicht gelesen werden
}
// 3. Speicher für Serie reservieren
GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries));
if (series == NULL) {
fclose(f);
return NULL; // Speicherfehler
}
series->count = count;
series->images = malloc(count * sizeof(GrayScaleImage));
series->labels = malloc(count * sizeof(unsigned char));
if (series->images == NULL || series->labels == NULL) {
free(series->images);
free(series->labels);
free(series);
fclose(f);
return NULL;
}
// 4. Bilder + Labels einlesen
for (unsigned short i = 0; i < count; i++) {
// Bild einlesen
series->images[i] = readSingleImage(f, width, height);
// Prüfen ob Bild erfolgreich gelesen wurde
if (series->images[i].buffer == NULL) {
// Fehler beim Bild-Lesen → Serie freigeben
clearSeries(series);
fclose(f);
return NULL;
}
// Label einlesen
if (fread(&series->labels[i], sizeof(unsigned char), 1, f) != 1) {
// Fehler beim Label-Lesen → Serie freigeben
clearSeries(series);
fclose(f);
return NULL;
}
}
fclose(f);
return series;
}
// Funktion: Bildserie vollständig aus dem Speicher freigeben
void clearSeries(GrayScaleImageSeries *series)
{
if (series == NULL) {
return;
}
// Alle einzelnen Bilder freigeben
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;
}
// Labels-Array freigeben
if (series->labels != NULL) {
free(series->labels);
series->labels = NULL;
}
// Die Serie selbst freigeben
free(series);
}
-139
View File
@@ -1,139 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "matrix.h"
// TODO Matrix-Funktionen implementieren
// Matrix erstellen
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
// Falls eine Matrix eine Null Dimension hat leere Matrix ausgeben
if (rows ==0 || cols == 0){
Matrix empty = {0, 0, NULL};
return empty;
}
Matrix matrix;
matrix.rows = rows;
matrix.cols = cols;
// Speicher erstellen und nullsetzen
matrix.buffer = (MatrixType *)calloc(rows * cols, sizeof(MatrixType));
return matrix;
}
// Matrix Speicher freigeben
void clearMatrix(Matrix *matrix)
{
if (matrix != NULL && matrix->buffer != NULL) {
free(matrix->buffer);
matrix->buffer = NULL;
matrix->rows = 0;
matrix->cols = 0;
}
}
// Matrix muss von 2D in 1D umgewandelt werden deswegen (Zeile* Anzahl Spalten + Spalte)
// um an entsprechende Speicheradresse zu kommen
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
}
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
// Prüfen ob Indizes im gültigen Bereich sind
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) {
return 0;
}
// Prüfen ob was im Buffer ist
if (matrix.buffer == NULL) {
return 0;
}
return matrix.buffer[rowIdx * matrix.cols + colIdx];
}
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
// Broadcasting Fall 1: matrix1 ist ein Spaltenvektor
if (matrix1.cols == 1 && matrix1.rows == matrix2.rows) {
// Neue Matrix mit passender Dimension erstellen
Matrix result = createMatrix(matrix2.rows, matrix2.cols);
// Vektor zu jeder Spalte addieren
for (unsigned int i = 0; i < result.rows; i++) {
for (unsigned int j = 0; j < result.cols; j++) {
MatrixType vectorValue = getMatrixAt(matrix1, i, 0);
MatrixType matrixValue = getMatrixAt(matrix2, i, j);
setMatrixAt(vectorValue + matrixValue, result, i, j);
}
}
return result;
}
// Broadcasting Fall 2: matrix2 ist ein Spaltenvektor
else if (matrix2.cols == 1 && matrix2.rows == matrix1.rows) {
// Neue Matrix mit passender Dimension erstellen
Matrix result = createMatrix(matrix1.rows, matrix1.cols);
// Vektor zu jeder Spalte addieren
for (unsigned int i = 0; i < result.rows; i++) {
for (unsigned int j = 0; j < result.cols; j++) {
MatrixType matrixValue = getMatrixAt(matrix1, i, j);
MatrixType vectorValue = getMatrixAt(matrix2, i, 0);
setMatrixAt(matrixValue + vectorValue, result, i, j);
}
}
return result;
}
// Normale elementweise Addition: Dimensionen müssen übereinstimmen
else if (matrix1.rows == matrix2.rows && matrix1.cols == matrix2.cols) {
// Neue Matrix mit passender Dimension erstellen
Matrix result = createMatrix(matrix1.rows, matrix1.cols);
// Alle Elemente einzeln addieren
for (unsigned int i = 0; i < matrix1.rows * matrix1.cols; i++) {
result.buffer[i] = matrix1.buffer[i] + matrix2.buffer[i];
}
return result;
}
// Fehlerfall: Dimensionen passen nicht
else {
Matrix empty = {0, 0, NULL};
return empty;
}
}
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
// Prüfen ob Matrizen multipiziert werden können
if (matrix1.cols != matrix2.rows) {
// Fehlerfall: Leere Matrix zurückgeben
Matrix empty = {0, 0, NULL};
return empty;
}
// Neue Matrix mit passender Dimension erstellen
Matrix result = createMatrix(matrix1.rows, matrix2.cols);
// Matrix-Multiplikation durchführen
for (unsigned int i = 0; i < result.rows; i++) {
for (unsigned int j = 0; j < result.cols; j++) {
MatrixType sum = 0.0;
// Skalarprodukt der i-ten Zeile mit j-ter Spalte
for (unsigned int k = 0; k < matrix1.cols; k++) {
MatrixType a = getMatrixAt(matrix1, i, k);
MatrixType b = getMatrixAt(matrix2, k, j);
sum += a * b;
}
setMatrixAt(sum, result, i, j);
}
}
return result;
}