Ryanhub - file viewer
filename: includes.c
branch: main
back to repo
// includes.c

// this file includes typedefs, includes, and helpers used by our model

// inlcudes

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

// macros

#define LR 0.0001f
#define W 32
#define H 32
#define C 3
#define IMAGESIZE (W*H*C)
#define LATENT 512

// structs

typedef struct {
    float *w1; // IMAGESIZE x LATENT
    float *b1; // LATENT
    float *w2; // LATENT x IMAGESIZE
    float *b2; // IMAGESIZE
} Model;

typedef struct {
    int count;
    float *images;
} Dataset;

// math functions

float randf(float min, float max) {
    float scale = (float)rand() / (float)RAND_MAX; 
    return min + scale * (max - min); 
}

float gauss() {
    return (randf(0,1) + randf(0,1) + randf(0,1) - 1.5f);
}

// model tools

void encode(Model *m, float *input, float *latent) {
	/* for each component of latent
	 *  add bias 1 to sum
	 *  add each pixel * w1 value to sum
	 *  take tanh of sum to squash values
	 * return a latent vector
	 */
    for (int j = 0; j < LATENT; j++) {
        float sum = m->b1[j];
		for (int i = 0; i < IMAGESIZE; i++) 
            sum += input[i] * m->w1[i*LATENT + j];
        latent[j] = tanhf(sum);
    }
}

void decode(Model *m, float *latent, float *out) { 
	/* for each component of image
	 *  add bias 2 to sum
	 *  add sum of each latent value * w2
	 *  take tanh derivative of sum
	 * return an image
	 */
	for (int i = 0; i < IMAGESIZE; i++) { 
		float sum = m->b2[i];
		for (int j = 0; j < LATENT; j++)
			sum += latent[j] * m->w2[j*IMAGESIZE + i]; 
		out[i] = 0.5f * (tanhf(sum) + 1.0f); 
	} 
}

void reconstruct(Model *m, float *input, float *out) {
    float latent[LATENT];
    encode(m, input, latent);
    decode(m, latent, out);
}

// helpers

void init_model(Model *m) {
    m->w1 = malloc(sizeof(float) * IMAGESIZE * LATENT);
    m->b1 = malloc(sizeof(float) * LATENT);
    m->w2 = malloc(sizeof(float) * LATENT * IMAGESIZE);
    m->b2 = malloc(sizeof(float) * IMAGESIZE);

    for (int i = 0; i < IMAGESIZE * LATENT; i++)
        m->w1[i] = randf(-0.01f, 0.01f);

    for (int i = 0; i < LATENT; i++)
        m->b1[i] = 0;

    for (int i = 0; i < LATENT * IMAGESIZE; i++)
        m->w2[i] = randf(-0.01f, 0.01f);

    for (int i = 0; i < IMAGESIZE; i++)
        m->b2[i] = 0;
}

void save_model(char *path, Model *m) {
    FILE *f = fopen(path, "wb");
    if (!f) return;

    fwrite(m->w1, sizeof(float), IMAGESIZE * LATENT, f);
    fwrite(m->b1, sizeof(float), LATENT, f);
    fwrite(m->w2, sizeof(float), LATENT * IMAGESIZE, f);
    fwrite(m->b2, sizeof(float), IMAGESIZE, f);

    fclose(f);
}

void load_model(char *path, Model *m) {
    FILE *f = fopen(path, "rb");
    if (!f) {
        printf("failed to open model\n");
        exit(1);
    }

    m->w1 = malloc(sizeof(float) * IMAGESIZE * LATENT);
    m->b1 = malloc(sizeof(float) * LATENT);
    m->w2 = malloc(sizeof(float) * LATENT * IMAGESIZE);
    m->b2 = malloc(sizeof(float) * IMAGESIZE);

    fread(m->w1, sizeof(float), IMAGESIZE * LATENT, f);
    fread(m->b1, sizeof(float), LATENT, f);
    fread(m->w2, sizeof(float), LATENT * IMAGESIZE, f);
    fread(m->b2, sizeof(float), IMAGESIZE, f);

    fclose(f);
}

void load_dataset(char *path, Dataset *d) {
    FILE *f = fopen(path, "rb");
    if (!f) {
        printf("failed to open dataset\n");
        exit(1);
    }

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    rewind(f);

    d->count = size / (IMAGESIZE * sizeof(float));

    d->images = malloc(size);
    fread(d->images, 1, size, f);
    fclose(f);

    printf("loaded %d images\n", d->count);
}

void save_bmp(const char *filename, float *image) {
    FILE *f = fopen(filename, "wb");
    if (!f) return;

    int row_size = (3 * W + 3) & ~3;   // row padded to multiple of 4 bytes
    int pixel_data_size = row_size * H;
    int file_size = 54 + pixel_data_size;

    unsigned char header[54] = {0};

    // BMP header
    header[0] = 'B';
    header[1] = 'M';

    // file size
    header[2] = file_size;
    header[3] = file_size >> 8;
    header[4] = file_size >> 16;
    header[5] = file_size >> 24;

    // pixel data offset
    header[10] = 54;

    // DIB header size
    header[14] = 40;

    // width
    header[18] = W;
    header[19] = W >> 8;
    header[20] = W >> 16;
    header[21] = W >> 24;

    // height
    header[22] = H;
    header[23] = H >> 8;
    header[24] = H >> 16;
    header[25] = H >> 24;

    // planes
    header[26] = 1;

    // bits per pixel
    header[28] = 24;

    fwrite(header, 1, 54, f);

    unsigned char row[row_size];

    for (int y = H - 1; y >= 0; y--) {
        for (int x = 0; x < W; x++) {
            int i = (y * W + x) * 3;

            float r = image[i + 0];
            float g = image[i + 1];
            float b = image[i + 2];

            if (r < 0) r = 0; if (r > 1) r = 1;
            if (g < 0) g = 0; if (g > 1) g = 1;
            if (b < 0) b = 0; if (b > 1) b = 1;

            row[x * 3 + 2] = (unsigned char)(r * 255);
            row[x * 3 + 1] = (unsigned char)(g * 255);
            row[x * 3 + 0] = (unsigned char)(b * 255);
        }

        // zero padding
        for (int i = W * 3; i < row_size; i++)
            row[i] = 0;

        fwrite(row, 1, row_size, f);
    }

    fclose(f);
}