File size: 6,571 Bytes
8b41169 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | /* sk_model.h β SnapKitty MLC: computation graph, autograd, training
*
* Design:
* - All allocation is arena-based (no malloc/free in the hot path)
* - Computation graph is built by composing sk_mv_* constructors
* - Topological sort in sk_model_prog_create β forward/backward in O(n)
* - Training: mini-batch SGD with Fisher-Yates shuffle per epoch
*
* Authors: Ahmad Ali Parr, Jessica L. Williams (SNAPKITTYWEST)
* Source: SNAPKITTYAGENT9NOVA/MLC
* License: BSL-1.1 / AGPL-3.0 / MPL-2.0
*/
#ifndef SK_MODEL_H
#define SK_MODEL_H
#include "sk_defs.h"
#include "sk_arena.h"
#include "sk_matrix.h"
/* ββ Variable flags βββββββββββββββββββββββββββββββββββββββββββββββββ */
typedef enum {
SK_MV_NONE = 0,
SK_MV_REQUIRES_GRAD = (1 << 0), /* accumulate gradients */
SK_MV_PARAMETER = (1 << 1), /* updated during training */
SK_MV_INPUT = (1 << 2), /* model input slot */
SK_MV_OUTPUT = (1 << 3), /* model output slot */
SK_MV_DESIRED_OUTPUT = (1 << 4), /* ground-truth label slot */
SK_MV_COST = (1 << 5), /* scalar loss slot */
} sk_mv_flags;
/* ββ Operation type βββββββββββββββββββββββββββββββββββββββββββββββββ */
typedef enum {
SK_OP_NULL = 0,
SK_OP_CREATE,
_SK_OP_UNARY_START,
SK_OP_RELU,
SK_OP_SOFTMAX,
_SK_OP_BINARY_START,
SK_OP_ADD,
SK_OP_SUB,
SK_OP_MATMUL,
SK_OP_CROSS_ENTROPY,
} sk_mv_op;
#define SK_MV_MAX_INPUTS 2
#define SK_MV_NUM_INPUTS(op) \
((op) < _SK_OP_UNARY_START ? 0 : ((op) < _SK_OP_BINARY_START ? 1 : 2))
/* ββ Model variable (node in the computation graph) ββββββββββββββββ */
typedef struct sk_model_var {
u32 index;
u32 flags;
sk_matrix* val;
sk_matrix* grad;
sk_mv_op op;
struct sk_model_var* inputs[SK_MV_MAX_INPUTS];
} sk_model_var;
/* ββ Ordered execution program (topological sort output) βββββββββββ */
typedef struct {
sk_model_var** vars;
u32 size;
} sk_model_prog;
/* ββ Model context ββββββββββββββββββββββββββββββββββββββββββββββββββ */
typedef struct {
u32 num_vars;
sk_model_var* input;
sk_model_var* output;
sk_model_var* desired_output;
sk_model_var* cost;
sk_model_prog forward_prog;
sk_model_prog cost_prog;
} sk_model;
/* ββ Training descriptor ββββββββββββββββββββββββββββββββββββββββββββ */
typedef struct {
sk_matrix* train_images;
sk_matrix* train_labels;
sk_matrix* test_images;
sk_matrix* test_labels;
u32 epochs;
u32 batch_size;
f32 learning_rate;
} sk_training_desc;
/* ββ Variable constructors ββββββββββββββββββββββββββββββββββββββββββ */
sk_model_var* sk_mv_create(
sk_arena* arena, sk_model* model, u32 rows, u32 cols, u32 flags
);
sk_model_var* sk_mv_relu(
sk_arena* arena, sk_model* model, sk_model_var* input, u32 flags
);
sk_model_var* sk_mv_softmax(
sk_arena* arena, sk_model* model, sk_model_var* input, u32 flags
);
sk_model_var* sk_mv_add(
sk_arena* arena, sk_model* model,
sk_model_var* a, sk_model_var* b, u32 flags
);
sk_model_var* sk_mv_sub(
sk_arena* arena, sk_model* model,
sk_model_var* a, sk_model_var* b, u32 flags
);
sk_model_var* sk_mv_matmul(
sk_arena* arena, sk_model* model,
sk_model_var* a, sk_model_var* b, u32 flags
);
sk_model_var* sk_mv_cross_entropy(
sk_arena* arena, sk_model* model,
sk_model_var* p, sk_model_var* q, u32 flags
);
/* ββ Program execution ββββββββββββββββββββββββββββββββββββββββββββββ */
sk_model_prog sk_model_prog_create(
sk_arena* arena, sk_model* model, sk_model_var* out_var
);
void sk_model_prog_compute(sk_model_prog* prog);
void sk_model_prog_compute_grads(sk_model_prog* prog);
/* ββ Model lifecycle ββββββββββββββββββββββββββββββββββββββββββββββββ */
sk_model* sk_model_create(sk_arena* arena);
void sk_model_compile(sk_arena* arena, sk_model* model);
void sk_model_feedforward(sk_model* model);
void sk_model_train(sk_model* model, const sk_training_desc* desc);
/* Compatibility aliases (original names) */
#define MV_FLAG_NONE SK_MV_NONE
#define MV_FLAG_REQUIRES_GRAD SK_MV_REQUIRES_GRAD
#define MV_FLAG_PARAMETER SK_MV_PARAMETER
#define MV_FLAG_INPUT SK_MV_INPUT
#define MV_FLAG_OUTPUT SK_MV_OUTPUT
#define MV_FLAG_DESIRED_OUTPUT SK_MV_DESIRED_OUTPUT
#define MV_FLAG_COST SK_MV_COST
#define MV_OP_NULL SK_OP_NULL
#define MV_OP_CREATE SK_OP_CREATE
#define _MV_OP_UNARY_START _SK_OP_UNARY_START
#define MV_OP_RELU SK_OP_RELU
#define MV_OP_SOFTMAX SK_OP_SOFTMAX
#define _MV_OP_BINARY_START _SK_OP_BINARY_START
#define MV_OP_ADD SK_OP_ADD
#define MV_OP_SUB SK_OP_SUB
#define MV_OP_MATMUL SK_OP_MATMUL
#define MV_OP_CROSS_ENTROPY SK_OP_CROSS_ENTROPY
#define MODEL_VAR_MAX_INPUTS SK_MV_MAX_INPUTS
#define MV_NUM_INPUTS SK_MV_NUM_INPUTS
#define model_var sk_model_var
#define model_var_flags sk_mv_flags
#define model_var_op sk_mv_op
#define model_program sk_model_prog
#define model_context sk_model
#define model_training_desc sk_training_desc
#define mv_create sk_mv_create
#define mv_relu sk_mv_relu
#define mv_softmax sk_mv_softmax
#define mv_add sk_mv_add
#define mv_sub sk_mv_sub
#define mv_matmul sk_mv_matmul
#define mv_cross_entropy sk_mv_cross_entropy
#define model_prog_create sk_model_prog_create
#define model_prog_compute sk_model_prog_compute
#define model_prog_compute_grads sk_model_prog_compute_grads
#define model_create sk_model_create
#define model_compile sk_model_compile
#define model_feedforward sk_model_feedforward
#define model_train sk_model_train
#endif /* SK_MODEL_H */
|