Download examples/mnist.c from Snapkitty/snapkitty-mlc: direct link, hf CLI and curl.
- Browser
- Download file 5.46 kB
-
https://huggingface.co/Snapkitty/snapkitty-mlc/resolve/main/examples/mnist.c
- Command line
-
hf download hf://Snapkitty/snapkitty-mlc/examples/mnist.c
-
curl -L -o mnist.c https://huggingface.co/Snapkitty/snapkitty-mlc/resolve/main/examples/mnist.c
5.46 kB
| /* mnist.c β SnapKitty MLC: MNIST digit classifier example | |
| * | |
| * Architecture: | |
| * Input (784) β W0(16Γ784) ReLU β W1(16Γ16) ReLU [+ skip] β W2(10Γ16) Softmax | |
| * Loss: cross-entropy | |
| * Init: Xavier uniform (Glorot) | |
| * Train: SGD, 10 epochs, batch=50, lr=0.01 | |
| * | |
| * Data: run examples/data_convert.py first to generate .mat files. | |
| * | |
| * Authors: Ahmad Ali Parr, Jessica L. Williams (SNAPKITTYWEST) | |
| * Source: SNAPKITTYAGENT9NOVA/MLC | |
| * License: BSL-1.1 / AGPL-3.0 / MPL-2.0 | |
| */ | |
| /* ββ ANSI terminal: render digit as coloured blocks ββββββββββββββββ */ | |
| static void draw_mnist_digit(const f32* data) { | |
| for (u32 y = 0; y < 28; y++) { | |
| for (u32 x = 0; x < 28; x++) { | |
| f32 num = data[x + y * 28]; | |
| u32 col = 232 + (u32)(num * 23); | |
| printf("\x1b[48;5;%dm ", col); | |
| } | |
| printf("\x1b[0m\n"); | |
| } | |
| printf("\x1b[0m"); | |
| } | |
| /* ββ Build the MNIST model ββββββββββββββββββββββββββββββββββββββββββ */ | |
| static void create_mnist_model(sk_arena* arena, sk_model* model) { | |
| /* Xavier uniform init bounds */ | |
| f32 b0 = sqrtf(6.0f / (784 + 16)); | |
| f32 b1 = sqrtf(6.0f / ( 16 + 16)); | |
| f32 b2 = sqrtf(6.0f / ( 16 + 10)); | |
| sk_model_var* input = sk_mv_create(arena, model, 784, 1, SK_MV_INPUT); | |
| sk_model_var* W0 = sk_mv_create(arena, model, 16, 784, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| sk_model_var* W1 = sk_mv_create(arena, model, 16, 16, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| sk_model_var* W2 = sk_mv_create(arena, model, 10, 16, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| sk_mat_fill_rand(W0->val, -b0, b0); | |
| sk_mat_fill_rand(W1->val, -b1, b1); | |
| sk_mat_fill_rand(W2->val, -b2, b2); | |
| sk_model_var* b0v = sk_mv_create(arena, model, 16, 1, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| sk_model_var* b1v = sk_mv_create(arena, model, 16, 1, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| sk_model_var* b2v = sk_mv_create(arena, model, 10, 1, SK_MV_REQUIRES_GRAD | SK_MV_PARAMETER); | |
| /* Layer 0: W0 Γ input + b0 β ReLU */ | |
| sk_model_var* z0 = sk_mv_matmul(arena, model, W0, input, 0); | |
| sk_model_var* z0b = sk_mv_add(arena, model, z0, b0v, 0); | |
| sk_model_var* a0 = sk_mv_relu(arena, model, z0b, 0); | |
| /* Layer 1: W1 Γ a0 + b1 β ReLU + skip */ | |
| sk_model_var* z1 = sk_mv_matmul(arena, model, W1, a0, 0); | |
| sk_model_var* z1b = sk_mv_add(arena, model, z1, b1v, 0); | |
| sk_model_var* z1r = sk_mv_relu(arena, model, z1b, 0); | |
| sk_model_var* a1 = sk_mv_add(arena, model, a0, z1r, 0); /* skip connection */ | |
| /* Layer 2: W2 Γ a1 + b2 β Softmax */ | |
| sk_model_var* z2 = sk_mv_matmul(arena, model, W2, a1, 0); | |
| sk_model_var* z2b = sk_mv_add(arena, model, z2, b2v, 0); | |
| sk_model_var* out = sk_mv_softmax(arena, model, z2b, SK_MV_OUTPUT); | |
| /* Labels + loss */ | |
| sk_model_var* y = sk_mv_create(arena, model, 10, 1, SK_MV_DESIRED_OUTPUT); | |
| sk_model_var* cost = sk_mv_cross_entropy(arena, model, y, out, SK_MV_COST); | |
| (void)cost; | |
| } | |
| /* ββ main βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| int main(void) { | |
| sk_arena* perm = sk_arena_create(GiB(1), MiB(1)); | |
| sk_matrix* train_images = sk_mat_load(perm, 60000, 784, "train_images.mat"); | |
| sk_matrix* test_images = sk_mat_load(perm, 10000, 784, "test_images.mat"); | |
| sk_matrix* train_labels = sk_mat_create(perm, 60000, 10); | |
| sk_matrix* test_labels = sk_mat_create(perm, 10000, 10); | |
| { | |
| sk_matrix* tl = sk_mat_load(perm, 60000, 1, "train_labels.mat"); | |
| sk_matrix* tst = sk_mat_load(perm, 10000, 1, "test_labels.mat"); | |
| for (u32 i = 0; i < 60000; i++) | |
| train_labels->data[i * 10 + (u32)tl->data[i]] = 1.0f; | |
| for (u32 i = 0; i < 10000; i++) | |
| test_labels->data[i * 10 + (u32)tst->data[i]] = 1.0f; | |
| } | |
| draw_mnist_digit(test_images->data); | |
| printf("Label: "); | |
| for (u32 i = 0; i < 10; i++) printf("%.0f ", test_labels->data[i]); | |
| printf("\n\n"); | |
| sk_model* model = sk_model_create(perm); | |
| create_mnist_model(perm, model); | |
| sk_model_compile(perm, model); | |
| memcpy(model->input->val->data, test_images->data, sizeof(f32) * 784); | |
| sk_model_feedforward(model); | |
| printf("Pre-training: "); | |
| for (u32 i = 0; i < 10; i++) printf("%.2f ", model->output->val->data[i]); | |
| printf("\n"); | |
| sk_training_desc desc = { | |
| .train_images = train_images, | |
| .train_labels = train_labels, | |
| .test_images = test_images, | |
| .test_labels = test_labels, | |
| .epochs = 10, | |
| .batch_size = 50, | |
| .learning_rate = 0.01f, | |
| }; | |
| sk_model_train(model, &desc); | |
| memcpy(model->input->val->data, test_images->data, sizeof(f32) * 784); | |
| sk_model_feedforward(model); | |
| printf("Post-training: "); | |
| for (u32 i = 0; i < 10; i++) printf("%.4f ", model->output->val->data[i]); | |
| printf("\nPredicted: %llu\n", (unsigned long long)sk_mat_argmax(model->output->val)); | |
| sk_arena_destroy(perm); | |
| return 0; | |
| } | |