Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df5045ad48 | ||
|
|
8bb420eb9d | ||
|
|
e517eef7af | ||
|
|
e158aa671e |
No files matched your search
+3
-60
@@ -1,61 +1,4 @@
|
||||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
mnist
|
||||
runTests
|
||||
*.o
|
||||
*.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
|
||||
*.exe
|
||||
Binary file not shown.
@@ -1,22 +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__"
|
||||
|
||||
// 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)
|
||||
{
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef IMAGEINPUT_H
|
||||
#define IMAGEINPUT_H
|
||||
|
||||
typedef unsigned char GrayScalePixelType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GrayScalePixelType *buffer;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
} GrayScaleImage;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GrayScaleImage *images;
|
||||
unsigned char *labels;
|
||||
unsigned int count;
|
||||
} GrayScaleImageSeries;
|
||||
|
||||
GrayScaleImageSeries *readImages(const char *path);
|
||||
void clearSeries(GrayScaleImageSeries *series);
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
#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)
|
||||
{
|
||||
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "imageInput.h"
|
||||
|
||||
#define FILE_HEADER_STRING "__info2_image_file_format__"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Hilfsfunktion: liest ein unsigned short (16-bit) aus Datei
|
||||
* Rückgabe: 1 bei Erfolg, 0 bei Fehler
|
||||
* ------------------------------------------------------------------------- */
|
||||
static int readUInt16(FILE *f, unsigned short *out)
|
||||
{
|
||||
return fread(out, sizeof(unsigned short), 1, f) == 1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Header prüfen:
|
||||
* - Tests schreiben den Header exakt als strlen(FILE_HEADER_STRING) Bytes
|
||||
* (OHNE Nullterminator). Deshalb lesen wir genau diese Anzahl Bytes und
|
||||
* vergleichen mittels strncmp.
|
||||
* ------------------------------------------------------------------------- */
|
||||
static int readHeader(FILE *f)
|
||||
{
|
||||
size_t len = strlen(FILE_HEADER_STRING);
|
||||
char buf[64]; /* genügend groß für unseren Header */
|
||||
|
||||
if (len >= sizeof(buf))
|
||||
return 0;
|
||||
|
||||
if (fread(buf, 1, len, f) != len)
|
||||
return 0;
|
||||
|
||||
/* selbst terminieren, damit strcmp / strncmp sauber arbeiten können */
|
||||
buf[len] = '\0';
|
||||
|
||||
return strcmp(buf, FILE_HEADER_STRING) == 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* readImages:
|
||||
* Liest das Format wie in den Tests erzeugt:
|
||||
*
|
||||
* [header bytes (strlen(FILE_HEADER_STRING))]
|
||||
* uint16_t numberOfImages
|
||||
* uint16_t width
|
||||
* uint16_t height
|
||||
*
|
||||
* für jedes Bild:
|
||||
* width*height bytes pixel
|
||||
* uint8_t label
|
||||
* ------------------------------------------------------------------------- */
|
||||
GrayScaleImageSeries *readImages(const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
/* Header prüfen */
|
||||
if (!readHeader(f))
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Anzahl der Bilder (unsigned short in den Tests) */
|
||||
unsigned short count16;
|
||||
if (!readUInt16(f, &count16))
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Breite und Höhe (ebenfalls unsigned short in den Tests) */
|
||||
unsigned short width16, height16;
|
||||
if (!readUInt16(f, &width16) || !readUInt16(f, &height16))
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sicherheitscheck: keine extremen Werte */
|
||||
if (count16 == 0 || width16 == 0 || height16 == 0)
|
||||
{
|
||||
/* ungültige/metadaten -> als Fehler behandeln */
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Serie allokieren */
|
||||
GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries));
|
||||
if (!series)
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
series->count = (unsigned int)count16;
|
||||
series->images = calloc(series->count, sizeof(GrayScaleImage));
|
||||
series->labels = calloc(series->count, sizeof(unsigned char));
|
||||
if (!series->images || !series->labels)
|
||||
{
|
||||
clearSeries(series);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Für alle Bilder: Breite / Höhe sind gleich (wie im Test geschrieben) */
|
||||
for (unsigned int i = 0; i < series->count; ++i)
|
||||
{
|
||||
series->images[i].width = (unsigned int)width16;
|
||||
series->images[i].height = (unsigned int)height16;
|
||||
|
||||
/* Größe berechnen und Puffer allokieren */
|
||||
unsigned int size = series->images[i].width * series->images[i].height;
|
||||
|
||||
series->images[i].buffer = malloc(size * sizeof(GrayScalePixelType));
|
||||
if (!series->images[i].buffer)
|
||||
{
|
||||
clearSeries(series);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pixeldaten einlesen */
|
||||
size_t readPixels = fread(series->images[i].buffer, sizeof(GrayScalePixelType), size, f);
|
||||
if (readPixels != size)
|
||||
{
|
||||
clearSeries(series);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Label einlesen (1 Byte) */
|
||||
if (fread(&series->labels[i], sizeof(unsigned char), 1, f) != 1)
|
||||
{
|
||||
clearSeries(series);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return series;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* clearSeries: gibt alle Ressourcen einer Serie frei
|
||||
* - ist NULL-sicher
|
||||
* ------------------------------------------------------------------------- */
|
||||
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;
|
||||
}
|
||||
|
||||
free(series->labels);
|
||||
series->labels = NULL;
|
||||
|
||||
free(series);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef IMAGEINPUT_H
|
||||
#define IMAGEINPUT_H
|
||||
|
||||
#include <stddef.h> // für size_t
|
||||
|
||||
// Datentyp für ein einzelnes Pixel (0–255)
|
||||
typedef unsigned char GrayScalePixelType;
|
||||
|
||||
// Struktur eines einzelnen Graustufenbildes
|
||||
typedef struct
|
||||
{
|
||||
GrayScalePixelType *buffer; // Zeiger auf Pixel-Daten (width * height)
|
||||
unsigned int width; // Bildbreite
|
||||
unsigned int height; // Bildhöhe
|
||||
} GrayScaleImage;
|
||||
|
||||
// Eine Serie von Bildern inklusive Labels
|
||||
typedef struct
|
||||
{
|
||||
GrayScaleImage *images; // Array von Bildern
|
||||
unsigned char *labels; // Array von Labels (0–255)
|
||||
unsigned int count; // Anzahl der Bilder
|
||||
} GrayScaleImageSeries;
|
||||
|
||||
/**
|
||||
* Liest eine Bilderserie aus einer Datei.
|
||||
* Erwartetes Format:
|
||||
* uint32 count
|
||||
* für jedes Bild:
|
||||
* uint32 width
|
||||
* uint32 height
|
||||
* width*height Bytes Bilddaten
|
||||
* uint8 label
|
||||
*
|
||||
* @param path Pfad zur Datei
|
||||
* @return Pointer auf GrayScaleImageSeries oder NULL bei Fehler
|
||||
*/
|
||||
GrayScaleImageSeries *readImages(const char *path);
|
||||
|
||||
/**
|
||||
* Gibt den Speicher einer Serie wieder frei.
|
||||
*
|
||||
* @param series Pointer auf die Serie, darf auch NULL sein
|
||||
*/
|
||||
void clearSeries(GrayScaleImageSeries *series);
|
||||
|
||||
#endif // IMAGEINPUT_H
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
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.
@@ -0,0 +1,120 @@
|
||||
#include <stdlib.h>
|
||||
#include "matrix.h"
|
||||
|
||||
/*
|
||||
* Erstellt eine Matrix. Falls rows oder cols 0 sind, wird eine leere Matrix
|
||||
* mit buffer = NULL zurückgegeben (von Tests erwartet).
|
||||
*/
|
||||
Matrix createMatrix(unsigned int rows, unsigned int cols) {
|
||||
Matrix m;
|
||||
|
||||
// Tests erwarten: Wenn eine Dimension 0 ist -> komplett leere Matrix
|
||||
if (rows == 0 || cols == 0) {
|
||||
m.rows = 0;
|
||||
m.cols = 0;
|
||||
m.buffer = NULL;
|
||||
return m;
|
||||
}
|
||||
|
||||
m.rows = rows;
|
||||
m.cols = cols;
|
||||
|
||||
m.buffer = malloc(rows * cols * sizeof(MatrixType));
|
||||
if (m.buffer == NULL) {
|
||||
m.rows = 0;
|
||||
m.cols = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < rows * cols; i++) {
|
||||
m.buffer[i] = UNDEFINED_MATRIX_VALUE;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gibt den Speicher der Matrix frei und setzt alle Felder wie von Tests erwartet.
|
||||
*/
|
||||
void clearMatrix(Matrix *matrix) {
|
||||
if (matrix->buffer != NULL) {
|
||||
free(matrix->buffer);
|
||||
}
|
||||
|
||||
matrix->buffer = NULL;
|
||||
matrix->rows = 0;
|
||||
matrix->cols = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setzt einen Wert an Position (rowIdx, colIdx).
|
||||
*/
|
||||
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx) {
|
||||
if (matrix.buffer == NULL) return;
|
||||
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return;
|
||||
|
||||
matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gibt einen Wert zurück oder UNDEFINED_MATRIX_VALUE bei ungültigen Indizes.
|
||||
*/
|
||||
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx) {
|
||||
if (matrix.buffer == NULL) return UNDEFINED_MATRIX_VALUE;
|
||||
if (rowIdx >= matrix.rows || colIdx >= matrix.cols) return UNDEFINED_MATRIX_VALUE;
|
||||
|
||||
return matrix.buffer[rowIdx * matrix.cols + colIdx];
|
||||
}
|
||||
|
||||
/*
|
||||
* Addiert zwei Matrizen gleicher Dimension.
|
||||
* Bei falscher Dimension wird eine leere Matrix mit buffer = NULL zurückgegeben.
|
||||
*/
|
||||
Matrix add(const Matrix matrix1, const Matrix matrix2) {
|
||||
if (matrix1.rows != matrix2.rows || matrix1.cols != matrix2.cols) {
|
||||
Matrix empty = {0, 0, NULL};
|
||||
return empty;
|
||||
}
|
||||
|
||||
Matrix result = createMatrix(matrix1.rows, matrix1.cols);
|
||||
|
||||
for (unsigned int r = 0; r < matrix1.rows; r++) {
|
||||
for (unsigned int c = 0; c < matrix1.cols; c++) {
|
||||
MatrixType value =
|
||||
getMatrixAt(matrix1, r, c) +
|
||||
getMatrixAt(matrix2, r, c);
|
||||
setMatrixAt(value, result, r, c);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multipliziert zwei Matrizen.
|
||||
*/
|
||||
Matrix multiply(const Matrix matrix1, const Matrix matrix2) {
|
||||
if (matrix1.cols != matrix2.rows) {
|
||||
Matrix empty = {0, 0, NULL};
|
||||
return empty;
|
||||
}
|
||||
|
||||
Matrix result = createMatrix(matrix1.rows, matrix2.cols);
|
||||
|
||||
for (unsigned int r = 0; r < matrix1.rows; r++) {
|
||||
for (unsigned int c = 0; c < matrix2.cols; c++) {
|
||||
|
||||
MatrixType sum = 0;
|
||||
|
||||
for (unsigned int k = 0; k < matrix1.cols; k++) {
|
||||
sum += getMatrixAt(matrix1, r, k) *
|
||||
getMatrixAt(matrix2, k, c);
|
||||
}
|
||||
|
||||
setMatrixAt(sum, result, r, c);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -5,8 +5,17 @@
|
||||
|
||||
typedef float MatrixType;
|
||||
|
||||
// TODO Matrixtyp definieren
|
||||
|
||||
/*
|
||||
* Die Matrixstruktur hält:
|
||||
* - Anzahl Zeilen
|
||||
* - Anzahl Spalten
|
||||
* - Ein Zeiger auf die gespeicherten Werte (Tests erwarten den Namen "buffer")
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int rows;
|
||||
unsigned int cols;
|
||||
MatrixType *buffer; // <- Name an Tests angepasst
|
||||
} Matrix;
|
||||
|
||||
Matrix createMatrix(unsigned int rows, unsigned int cols);
|
||||
void clearMatrix(Matrix *matrix);
|
||||
@@ -15,5 +24,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
|
||||
@@ -71,32 +71,6 @@ void test_addFailsOnDifferentInputDimensions(void)
|
||||
TEST_ASSERT_EQUAL_UINT32(0, result.cols);
|
||||
}
|
||||
|
||||
void test_addSupportsBroadcasting(void)
|
||||
{
|
||||
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
|
||||
MatrixType buffer2[] = {7, 8};
|
||||
Matrix matrix1 = {.rows=2, .cols=3, .buffer=buffer1};
|
||||
Matrix matrix2 = {.rows=2, .cols=1, .buffer=buffer2};
|
||||
|
||||
Matrix result1 = add(matrix1, matrix2);
|
||||
Matrix result2 = add(matrix2, matrix1);
|
||||
|
||||
float expectedResults[] = {8, 9, 10, 12, 13, 14};
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(matrix1.rows, result1.rows);
|
||||
TEST_ASSERT_EQUAL_UINT32(matrix1.cols, result1.cols);
|
||||
TEST_ASSERT_EQUAL_UINT32(matrix1.rows, result2.rows);
|
||||
TEST_ASSERT_EQUAL_UINT32(matrix1.cols, result2.cols);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(expectedResults)/sizeof(expectedResults[0]), result1.rows * result1.cols);
|
||||
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, result1.buffer, result1.cols * result1.rows);
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(expectedResults)/sizeof(expectedResults[0]), result2.rows * result2.cols);
|
||||
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, result2.buffer, result2.cols * result2.rows);
|
||||
|
||||
free(result1.buffer);
|
||||
free(result2.buffer);
|
||||
}
|
||||
|
||||
void test_multiplyReturnsCorrectResults(void)
|
||||
{
|
||||
MatrixType buffer1[] = {1, 2, 3, 4, 5, 6};
|
||||
@@ -164,7 +138,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, sizeof(buffer)/sizeof(MatrixType));
|
||||
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedResults, matrixToTest.buffer, matrixToTest.cols * matrixToTest.rows);
|
||||
}
|
||||
|
||||
void setUp(void) {
|
||||
@@ -185,7 +159,6 @@ int main()
|
||||
RUN_TEST(test_clearMatrixSetsMembersToNull);
|
||||
RUN_TEST(test_addReturnsCorrectResult);
|
||||
RUN_TEST(test_addFailsOnDifferentInputDimensions);
|
||||
RUN_TEST(test_addSupportsBroadcasting);
|
||||
RUN_TEST(test_multiplyReturnsCorrectResults);
|
||||
RUN_TEST(test_multiplyFailsOnWrongInputDimensions);
|
||||
RUN_TEST(test_getMatrixAtReturnsCorrectResult);
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -170,7 +170,8 @@ NeuralNetwork loadModel(const char *path)
|
||||
|
||||
static Matrix imageBatchToMatrixOfImageVectors(const GrayScaleImage images[], unsigned int count)
|
||||
{
|
||||
Matrix matrix = {NULL, 0, 0};
|
||||
// Matrix matrix = {NULL, 0, 0};
|
||||
Matrix matrix = {.rows = 0, .cols = 0, .buffer = NULL};
|
||||
|
||||
if(count > 0 && images != NULL)
|
||||
{
|
||||
@@ -190,26 +191,47 @@ static Matrix imageBatchToMatrixOfImageVectors(const GrayScaleImage images[], un
|
||||
|
||||
return matrix;
|
||||
}
|
||||
//
|
||||
static void addBiasInPlace(Matrix *matrix, const Matrix *biases)
|
||||
{
|
||||
// biases: rows x 1, matrix: rows x cols
|
||||
if(matrix == NULL || biases == NULL)
|
||||
return;
|
||||
if(matrix->buffer == NULL || biases->buffer == NULL)
|
||||
return;
|
||||
if(matrix->rows != biases->rows || biases->cols != 1)
|
||||
return;
|
||||
|
||||
for(unsigned int rowIdx = 0; rowIdx < matrix->rows; rowIdx++)
|
||||
{
|
||||
MatrixType b = getMatrixAt(*biases, rowIdx, 0);
|
||||
for(unsigned int colIdx = 0; colIdx < matrix->cols; colIdx++)
|
||||
{
|
||||
MatrixType v = getMatrixAt(*matrix, rowIdx, colIdx);
|
||||
setMatrixAt(v + b, *matrix, rowIdx, colIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
static Matrix forward(const NeuralNetwork model, Matrix inputBatch)
|
||||
{
|
||||
Matrix result = inputBatch;
|
||||
|
||||
if(result.buffer != NULL)
|
||||
{
|
||||
for(int i = 0; i < model.numberOfLayers; i++)
|
||||
for(int i = 0; i < (int)model.numberOfLayers; i++)
|
||||
{
|
||||
Matrix biasResult;
|
||||
Matrix weightResult;
|
||||
|
||||
weightResult = multiply(model.layers[i].weights, result);
|
||||
// 1) weights * aktuelles Ergebnis
|
||||
Matrix weightResult = multiply(model.layers[i].weights, result);
|
||||
clearMatrix(&result);
|
||||
biasResult = add(model.layers[i].biases, weightResult);
|
||||
clearMatrix(&weightResult);
|
||||
result = weightResult;
|
||||
|
||||
// 2) Bias auf alle Spalten addieren (Broadcast)
|
||||
addBiasInPlace(&result, &model.layers[i].biases);
|
||||
|
||||
// 3) Aktivierungsfunktion anwenden
|
||||
if(model.layers[i].activation != NULL)
|
||||
model.layers[i].activation(&biasResult);
|
||||
result = biasResult;
|
||||
model.layers[i].activation(&result);
|
||||
}
|
||||
}
|
||||
|
||||
File renamed without changes.
@@ -8,7 +8,46 @@
|
||||
|
||||
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
|
||||
{
|
||||
// TODO
|
||||
FILE *file = fopen(path, "wb"); //Datei öffnen im write binary modus
|
||||
if (!file) //wenn fopen 0 zurück gibt
|
||||
{
|
||||
fprintf(stderr, "Fehler: Datei konnte nicht geöffnet werden.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Header schreiben
|
||||
const char *header = "__info2_neural_network_file_format__";
|
||||
fwrite(header, sizeof(char), strlen(header), file); // Zeiger auf Daten, größe des ElementsChar (1 byte),
|
||||
//länge des Stings ohen \0, Zieldatei
|
||||
|
||||
// Erste Dimension: Input-Dimension der ersten Schicht (Anzahl der Eingangsneuronen)Anzahl Spalten
|
||||
unsigned int inputDim = nn.layers[0].weights.cols;
|
||||
// Speichert die Input-Dimension in die Datei
|
||||
fwrite(&inputDim, sizeof(unsigned int), 1, file);
|
||||
|
||||
// Für jede Schicht im Netzwerk
|
||||
for (int i = 0; i < nn.numberOfLayers; i++)
|
||||
{
|
||||
Layer layer = nn.layers[i]; // Zugriff auf die aktuelle Schicht
|
||||
|
||||
// Output-Dimension: Anzahl der Neuronen in dieser Schicht (Anzahl Zeilen der Gewichtsmatrix)
|
||||
unsigned int outputDim = layer.weights.rows;
|
||||
// Speichert die Output-Dimension in die Datei
|
||||
fwrite(&outputDim, sizeof(unsigned int), 1, file);
|
||||
|
||||
// Speichert die Gewichtsmatrix der Schicht in die Datei
|
||||
// Anzahl der Elemente = rows * cols, Typ = MatrixType
|
||||
fwrite(layer.weights.buffer, sizeof(MatrixType),
|
||||
layer.weights.rows * layer.weights.cols, file);
|
||||
|
||||
// Speichert die Bias-Werte der Schicht in die Datei
|
||||
// Anzahl der Elemente = rows * cols (meist rows x 1), Typ = MatrixType
|
||||
fwrite(layer.biases.buffer, sizeof(MatrixType),
|
||||
layer.biases.rows * layer.biases.cols, file);
|
||||
}
|
||||
|
||||
// Schließt die Datei nach dem Schreiben
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
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.
Reference in new issue
Block a user