forked from freudenreichan/info2Praktikum-NeuronalesNetz
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
447e77a7bf | ||
|
|
a6749f07d1 | ||
|
|
2436240736 | ||
|
|
fde82f2d9a |
No files matched your search
+60
-3
@@ -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
|
||||
@@ -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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user