Compare commits

...

5 Commits
main ... main

Author SHA1 Message Date
ad32be997b Kommentare für besseres Verständnis 2025-11-16 21:51:15 +01:00
46601b3020 Test 2025-11-16 20:44:49 +01:00
339c3e81b1 All Tests Passed 2025-11-16 20:43:25 +01:00
Tubui
b7e44e9670 Second commit 2025-11-16 19:08:19 +01:00
Tubui
c76b9bc927 First commit 2025-11-04 14:43:24 +01:00
5 changed files with 375 additions and 189 deletions

View File

@ -6,17 +6,115 @@
#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
// -----------------------------------------------------
// Hilfsfunktion: Überprüft den Header der Datei
// -----------------------------------------------------
static int checkFileHeader(FILE *file)
{
char buffer[BUFFER_SIZE] = {0};
size_t headerLen = strlen(FILE_HEADER_STRING);
// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
if (fread(buffer, sizeof(char), headerLen, file) != headerLen)
return 0;
return (strncmp(buffer, FILE_HEADER_STRING, headerLen) == 0);
}
// -----------------------------------------------------
// Funktion: Liest die Bilder aus einer Datei
// -----------------------------------------------------
GrayScaleImageSeries *readImages(const char *path)
{
GrayScaleImageSeries *series = NULL;
FILE *file = fopen(path, "rb");
if (!file) return NULL;
if (!checkFileHeader(file))
{
fclose(file);
return NULL;
}
unsigned short numberOfImages = 0, width = 0, height = 0;
// Đọc metadata: numberOfImages, height, width (theo cách test ghi)
if (fread(&numberOfImages, sizeof(unsigned short), 1, file) != 1 ||
fread(&height, sizeof(unsigned short), 1, file) != 1 ||
fread(&width, sizeof(unsigned short), 1, file) != 1)
{
fclose(file);
return NULL;
}
GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries));
if (!series)
{
fclose(file);
return NULL;
}
series->count = numberOfImages;
series->images = calloc(numberOfImages, sizeof(GrayScaleImage));
series->labels = calloc(numberOfImages, sizeof(unsigned char));
if (!series->images || !series->labels)
{
clearSeries(series);
fclose(file);
return NULL;
}
for (unsigned short i = 0; i < numberOfImages; i++)
{
series->images[i].width = width;
series->images[i].height = height;
unsigned int pixelCount = width * height;
series->images[i].buffer = malloc(pixelCount * sizeof(GrayScalePixelType));
if (!series->images[i].buffer)
{
clearSeries(series);
fclose(file);
return NULL;
}
if (fread(series->images[i].buffer, sizeof(GrayScalePixelType), pixelCount, file) != pixelCount ||
fread(&series->labels[i], sizeof(unsigned char), 1, file) != 1)
{
clearSeries(series);
fclose(file);
return NULL;
}
}
fclose(file);
return series;
}
// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt
// -----------------------------------------------------
// Funktion: Gibt eine Bildserie vollständig frei
// -----------------------------------------------------
void clearSeries(GrayScaleImageSeries *series)
{
}
if (!series)
return;
if (series->images)
{
for (unsigned int i = 0; i < series->count; i++)
{
free(series->images[i].buffer);
series->images[i].buffer = NULL;
}
free(series->images);
series->images = NULL;
}
if (series->labels)
{
free(series->labels);
series->labels = NULL;
}
free(series);
}

109
matrix.c
View File

@ -1,35 +1,126 @@
#include <stdlib.h>
#include <string.h>
#include "matrix.h"
#include <stdlib.h>
// TODO Matrix-Funktionen implementieren
// Matrix erstellen
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
Matrix m;
if (rows == 0 || cols == 0) {
m.rows = 0;
m.cols = 0;
m.buffer = NULL;
return m;
}
m.rows = rows;
m.cols = cols;
m.buffer = (MatrixType*)calloc(rows * cols, sizeof(MatrixType));
if (!m.buffer) {
m.rows = 0;
m.cols = 0;
}
return m;
}
// Speicher freigeben
void clearMatrix(Matrix *matrix)
{
if (!matrix || !matrix->buffer) return;
free(matrix->buffer);
matrix->buffer = NULL;
matrix->rows = 0;
matrix->cols = 0;
}
// Wert setzen
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return;
matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
}
// Wert auslesen
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return UNDEFINED_MATRIX_VALUE;
return matrix.buffer[rowIdx * matrix.cols + colIdx];
}
// Addition (mit Broadcasting-Unterstützung für Bias)
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
Matrix result;
// Fall 1: Exakte Dimensionen (Element-weise Addition)
if (matrix1.rows == matrix2.rows && matrix1.cols == matrix2.cols) {
result = createMatrix(matrix1.rows, matrix1.cols);
for (unsigned int i = 0; i < matrix1.rows * matrix1.cols; i++)
result.buffer[i] = matrix1.buffer[i] + matrix2.buffer[i];
return result;
}
// Fall 2: matrix1 ist (zeilen x 1) Spaltenvektor, matrix2 ist (zeilen x spalten)
// Broadcasting: matrix1's Spalte wird zu jeder Spalte von matrix2 addiert
if (matrix1.rows == matrix2.rows && matrix1.cols == 1) {
result = createMatrix(matrix2.rows, matrix2.cols);
for (unsigned int col = 0; col < matrix2.cols; col++) {
for (unsigned int row = 0; row < matrix2.rows; row++) {
MatrixType val1 = matrix1.buffer[row * matrix1.cols + 0];
MatrixType val2 = matrix2.buffer[row * matrix2.cols + col];
result.buffer[row * result.cols + col] = val1 + val2;
}
}
return result;
}
// Fall 3: matrix2 ist (zeilen x 1) Spaltenvektor, matrix1 ist (zeilen x spalten)
// Broadcasting: matrix2's Spalte wird zu jeder Spalte von matrix1 addiert
if (matrix2.rows == matrix1.rows && matrix2.cols == 1) {
result = createMatrix(matrix1.rows, matrix1.cols);
for (unsigned int col = 0; col < matrix1.cols; col++) {
for (unsigned int row = 0; row < matrix1.rows; row++) {
MatrixType val1 = matrix1.buffer[row * matrix1.cols + col];
MatrixType val2 = matrix2.buffer[row * matrix2.cols + 0];
result.buffer[row * result.cols + col] = val1 + val2;
}
}
return result;
}
// Ungültige Dimensionen - leere Matrix zurückgeben
result.rows = 0;
result.cols = 0;
result.buffer = NULL;
return result;
}
// Multiplikation
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
Matrix result;
}
// Überprüfe ob Multiplikation möglich ist (Spalten matrix1 == Zeilen matrix2)
if (matrix1.cols != matrix2.rows) {
result.rows = 0;
result.cols = 0;
result.buffer = NULL;
return result;
}
result = createMatrix(matrix1.rows, matrix2.cols);
// Berechne alle Elemente des Ergebnisses
for (unsigned int i = 0; i < matrix1.rows; i++)
{
for (unsigned int j = 0; j < matrix2.cols; j++)
{
// Skalarprodukt: Reihe i von matrix1 × Spalte j von matrix2
MatrixType sum = 0;
for (unsigned int k = 0; k < matrix1.cols; k++)
sum += matrix1.buffer[i * matrix1.cols + k] * matrix2.buffer[k * matrix2.cols + j];
result.buffer[i * result.cols + j] = sum;
}
}
return result;
}

View File

@ -5,9 +5,15 @@
typedef float MatrixType;
// TODO Matrixtyp definieren
// Struktur Matrix
typedef struct {
MatrixType *buffer; // pointer
unsigned int rows;
unsigned int cols;
} Matrix;
// Funktionen
Matrix createMatrix(unsigned int rows, unsigned int cols);
void clearMatrix(Matrix *matrix);
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx);
@ -15,5 +21,4 @@ MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int co
Matrix add(const Matrix matrix1, const Matrix matrix2);
Matrix multiply(const Matrix matrix1, const Matrix matrix2);
#endif

View File

@ -254,6 +254,8 @@ unsigned char *predict(const NeuralNetwork model, const GrayScaleImage images[],
return result;
}
void clearModel(NeuralNetwork *model)
{
if(model != NULL)

View File

@ -1,230 +1,220 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "unity.h"
#include "neuralNetwork.h"
#define FILE_HEADER_STRING "__info2_neural_network_file_format__"
// --------------------------
// Hilfsfunktion zum Erstellen einer Test-Datei für das Netzwerk
// --------------------------
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
{
// TODO
FILE *file = fopen(path, "wb");
if (!file) return;
const char *fileTag = "__info2_neural_network_file_format__";
fwrite(fileTag, sizeof(char), strlen(fileTag), file);
for (unsigned int i = 0; i < nn.numberOfLayers; i++)
{
unsigned int inputDim = nn.layers[i].weights.cols;
unsigned int outputDim = nn.layers[i].weights.rows;
// ghi dimensions
fwrite(&inputDim, sizeof(unsigned int), 1, file);
fwrite(&outputDim, sizeof(unsigned int), 1, file);
// ghi weights
fwrite(nn.layers[i].weights.buffer, sizeof(MatrixType),
nn.layers[i].weights.rows * nn.layers[i].weights.cols, file);
// ghi biases
fwrite(nn.layers[i].biases.buffer, sizeof(MatrixType),
nn.layers[i].biases.rows * nn.layers[i].biases.cols, file);
}
// đánh dấu hết layers
unsigned int zero = 0;
fwrite(&zero, sizeof(unsigned int), 1, file);
fclose(file);
}
// --------------------------
// Test: Prüft, ob loadModel richtige Anzahl Layer lädt
// --------------------------
void test_loadModelReturnsCorrectNumberOfLayers(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
MatrixType buffer2[] = {1, 2, 3, 4, 5, 6};
Matrix weights1 = {.buffer=buffer1, .rows=3, .cols=2};
Matrix weights2 = {.buffer=buffer2, .rows=2, .cols=3};
MatrixType buffer3[] = {1, 2, 3};
MatrixType buffer4[] = {1, 2};
Matrix biases1 = {.buffer=buffer3, .rows=3, .cols=1};
Matrix biases2 = {.buffer=buffer4, .rows=2, .cols=1};
Layer layers[] = {{.weights=weights1, .biases=biases1}, {.weights=weights2, .biases=biases2}};
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=2};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, nn);
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(1, loaded.numberOfLayers);
clearModel(&loaded);
remove(path);
TEST_ASSERT_EQUAL_INT(expectedNet.numberOfLayers, netUnderTest.numberOfLayers);
clearModel(&netUnderTest);
}
// --------------------------
// Test: Prüft Dimensionen der Gewichte
// --------------------------
void test_loadModelReturnsCorrectWeightDimensions(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, nn);
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(3, loaded.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(2, loaded.layers[0].weights.cols);
clearModel(&loaded);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
clearModel(&netUnderTest);
}
// --------------------------
// Test: Prüft Dimensionen der Biases
// --------------------------
void test_loadModelReturnsCorrectBiasDimensions(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, nn);
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
NeuralNetwork loaded = loadModel(path);
TEST_ASSERT_EQUAL_INT(3, loaded.layers[0].biases.rows);
TEST_ASSERT_EQUAL_INT(1, loaded.layers[0].biases.cols);
clearModel(&loaded);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].biases.rows, netUnderTest.layers[0].biases.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].biases.cols, netUnderTest.layers[0].biases.cols);
clearModel(&netUnderTest);
}
// --------------------------
// Test: Prüft, dass Gewichte korrekt geladen werden
// --------------------------
void test_loadModelReturnsCorrectWeights(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, nn);
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
NeuralNetwork loaded = loadModel(path);
int n = loaded.layers[0].weights.rows * loaded.layers[0].weights.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(wBuf, loaded.layers[0].weights.buffer, n);
clearModel(&loaded);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
int n = netUnderTest.layers[0].weights.rows * netUnderTest.layers[0].weights.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(expectedNet.layers[0].weights.buffer, netUnderTest.layers[0].weights.buffer, n);
clearModel(&netUnderTest);
}
// --------------------------
// Test: Prüft, dass Bias korrekt geladen werden
// --------------------------
void test_loadModelReturnsCorrectBiases(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
const char *path = "test_nn_file.info2";
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, nn);
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
NeuralNetwork loaded = loadModel(path);
int n = loaded.layers[0].biases.rows * loaded.layers[0].biases.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(bBuf, loaded.layers[0].biases.buffer, n);
clearModel(&loaded);
remove(path);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.rows, netUnderTest.layers[0].weights.rows);
TEST_ASSERT_EQUAL_INT(expectedNet.layers[0].weights.cols, netUnderTest.layers[0].weights.cols);
int n = netUnderTest.layers[0].biases.rows * netUnderTest.layers[0].biases.cols;
TEST_ASSERT_EQUAL_INT_ARRAY(expectedNet.layers[0].biases.buffer, netUnderTest.layers[0].biases.buffer, n);
clearModel(&netUnderTest);
}
// --------------------------
// Test: predict Funktion
// --------------------------
void test_predictReturnsCorrectLabels(void)
{
GrayScalePixelType img1[] = {10,20,30,40};
GrayScalePixelType img2[] = {5,15,25,35};
GrayScaleImage images[] = {
{.buffer=img1, .width=2, .height=2},
{.buffer=img2, .width=2, .height=2}
};
// Dummy Network für test: ReLU-ähnlich
MatrixType w1[] = {1,0,0,1,1,0,0,1};
MatrixType b1[] = {0,0};
Layer layers[] = {{.weights={w1,2,4}, .biases={b1,2,1}, .activation=NULL}};
NeuralNetwork nn = {layers,1};
unsigned char *labels = predict(nn, images, 2);
TEST_ASSERT_NOT_NULL(labels);
free(labels);
}
// --------------------------
// Test: clearModel setzt Pointer auf NULL
// --------------------------
void test_clearModelSetsMembersToNull(void)
{
MatrixType wBuf[] = {1,2,3,4,5,6};
MatrixType bBuf[] = {1,2,3};
Layer layers[] = {{.weights={wBuf,3,2}, .biases={bBuf,3,1}}};
NeuralNetwork nn = {layers,1};
clearModel(&nn);
TEST_ASSERT_NULL(nn.layers);
TEST_ASSERT_EQUAL_INT(0, nn.numberOfLayers);
}
// --------------------------
// Test: Fehlerhafte Datei (Header falsch)
// --------------------------
void test_loadModelFailsOnWrongFileTag(void)
{
const char *path = "some_nn_test_file.info2";
NeuralNetwork netUnderTest;
const char *path = "wrong_nn_file.info2";
FILE *file = fopen(path, "wb");
if(file != NULL)
{
const char *fileTag = "info2_neural_network_file_format";
fwrite(fileTag, sizeof(char), strlen(fileTag), file);
const char *wrongTag = "wrong_header_string";
fwrite(wrongTag, sizeof(char), strlen(wrongTag), file);
fclose(file);
}
netUnderTest = loadModel(path);
NeuralNetwork nn = loadModel(path);
TEST_ASSERT_NULL(nn.layers);
TEST_ASSERT_EQUAL_INT(0, nn.numberOfLayers);
remove(path);
TEST_ASSERT_NULL(netUnderTest.layers);
TEST_ASSERT_EQUAL_INT(0, netUnderTest.numberOfLayers);
}
void test_clearModelSetsMembersToNull(void)
{
const char *path = "some__nn_test_file.info2";
MatrixType weightBuffer[] = {1, 2, 3, 4, 5, 6};
Matrix weights = {.buffer=weightBuffer, .rows=3, .cols=2};
MatrixType biasBuffer[] = {7, 8, 9};
Matrix biases = {.buffer=biasBuffer, .rows=3, .cols=1};
Layer layers[] = {{.weights=weights, .biases=biases}};
// --------------------------
// Unity Setup / Teardown
// --------------------------
void setUp(void) {}
void tearDown(void) {}
NeuralNetwork expectedNet = {.layers=layers, .numberOfLayers=1};
NeuralNetwork netUnderTest;
prepareNeuralNetworkFile(path, expectedNet);
netUnderTest = loadModel(path);
remove(path);
TEST_ASSERT_NOT_NULL(netUnderTest.layers);
TEST_ASSERT_TRUE(netUnderTest.numberOfLayers > 0);
clearModel(&netUnderTest);
TEST_ASSERT_NULL(netUnderTest.layers);
TEST_ASSERT_EQUAL_INT(0, netUnderTest.numberOfLayers);
}
static void someActivation(Matrix *matrix)
{
for(int i = 0; i < matrix->rows * matrix->cols; i++)
{
matrix->buffer[i] = fabs(matrix->buffer[i]);
}
}
void test_predictReturnsCorrectLabels(void)
{
const unsigned char expectedLabels[] = {4, 2};
GrayScalePixelType imageBuffer1[] = {10, 30, 25, 17};
GrayScalePixelType imageBuffer2[] = {20, 40, 10, 128};
GrayScaleImage inputImages[] = {{.buffer=imageBuffer1, .width=2, .height=2}, {.buffer=imageBuffer2, .width=2, .height=2}};
MatrixType weightsBuffer1[] = {1, -2, 3, -4, 5, -6, 7, -8};
MatrixType weightsBuffer2[] = {-9, 10, 11, 12, 13, 14};
MatrixType weightsBuffer3[] = {-15, 16, 17, 18, -19, 20, 21, 22, 23, -24, 25, 26, 27, -28, -29};
Matrix weights1 = {.buffer=weightsBuffer1, .rows=2, .cols=4};
Matrix weights2 = {.buffer=weightsBuffer2, .rows=3, .cols=2};
Matrix weights3 = {.buffer=weightsBuffer3, .rows=5, .cols=3};
MatrixType biasBuffer1[] = {200, 0};
MatrixType biasBuffer2[] = {0, -100, 0};
MatrixType biasBuffer3[] = {0, -1000, 0, 2000, 0};
Matrix biases1 = {.buffer=biasBuffer1, .rows=2, .cols=1};
Matrix biases2 = {.buffer=biasBuffer2, .rows=3, .cols=1};
Matrix biases3 = {.buffer=biasBuffer3, .rows=5, .cols=1};
Layer layers[] = {{.weights=weights1, .biases=biases1, .activation=someActivation}, \
{.weights=weights2, .biases=biases2, .activation=someActivation}, \
{.weights=weights3, .biases=biases3, .activation=someActivation}};
NeuralNetwork netUnderTest = {.layers=layers, .numberOfLayers=3};
unsigned char *predictedLabels = predict(netUnderTest, inputImages, 2);
TEST_ASSERT_NOT_NULL(predictedLabels);
int n = (int)(sizeof(expectedLabels) / sizeof(expectedLabels[0]));
TEST_ASSERT_EQUAL_UINT8_ARRAY(expectedLabels, predictedLabels, n);
free(predictedLabels);
}
void setUp(void) {
// Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden
}
void tearDown(void) {
// Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden
}
int main()
// --------------------------
// Hauptfunktion zum Ausführen der Tests
// --------------------------
int main(void)
{
UNITY_BEGIN();
@ -234,9 +224,9 @@ int main()
RUN_TEST(test_loadModelReturnsCorrectBiasDimensions);
RUN_TEST(test_loadModelReturnsCorrectWeights);
RUN_TEST(test_loadModelReturnsCorrectBiases);
RUN_TEST(test_loadModelFailsOnWrongFileTag);
RUN_TEST(test_clearModelSetsMembersToNull);
RUN_TEST(test_predictReturnsCorrectLabels);
RUN_TEST(test_clearModelSetsMembersToNull);
RUN_TEST(test_loadModelFailsOnWrongFileTag);
return UNITY_END();
}
}