下载链接:https://github.com/attractivechaos/kann
以什么是KANN:
KANN是一个独立的轻量级库,用于构建和训练中小型人工神经网络,如多层感知器,卷积神经网络和递归神经网络(包括LSTM和GRU)。它实现了基于图形的反向模式自动区分,并允许构建具有递归,共享权重和多个输入/输出/成本的拓扑复杂神经网络。与主流深度学习框架(如TensorFlow)相比,KANN不具备可扩展性,但它的灵活性接近,代码库小得多,仅依赖于标准C库。与其他轻量级框架(如tiny-dnn)相比,KANN仍然更小,更快,更通用,支持RNN,VAE和非标准神经网络,可能会使这些轻量级框架失效。
特征
灵活。通过使用运算符构建计算图来进行模型构建。支持RNN,权重共享和多个输入/输出。
高效。合理优化的矩阵产品和卷积。支持迷你批处理和有效的多线程。有时在主CPU模式下比主流框架更快。
小巧便携。截至目前,KANN在四个源代码文件中的代码少于4000行,默认情况下没有非标准依赖项。与ANSI C编译器兼容。
限制
仅限CPU。因此,KANN 不是用于训练巨大的神经网络。
缺少一些常见的运算符和体系结构,如批量标准化。
缺少用于训练RNN的详细API
API
神经网络中的网络层:
kad_node_t *kad_feed(int n_d, ...):设置输入层节点,如:t = kad_feed(4, 1, 1, 28, 28);
kad_node_t *kann_layer_dense(kad_node_t *in, int n1)
kad_node_t *kann_layer_conv2d(kad_node_t *in, int n_flt, int k_rows, int k_cols, int stride_r, int stride_c, int pad_r, int pad_c):
kad_node_t *kann_layer_gru(kad_node_t *in, int n1, int rnn_flag)
kad_node_t *kann_layer_rnn(kad_node_t *in, int n1, int rnn_flag)
kad_node_t *kann_layer_layernorm(kad_node_t *in) //Batch Normalization
kad_node_t *kann_layer_dropout(kad_node_t *t, float r)
kad_node_t *kad_max2d(kad_node_t *x, int kernel_r, int kernel_c, int stride_r, int stride_c, int top_pad, int left_pad)
激活函数:
kad_node_t *kad_square(kad_node_t *x); /* f(x) = x^2 (element-wise square) */
kad_node_t *kad_sigm(kad_node_t *x); /* f(x) = 1/(1+exp(-x)) (element-wise sigmoid) */
kad_node_t *kad_tanh(kad_node_t *x); /* f(x) = (1-exp(-2x)) / (1+exp(-2x)) (element-wise tanh) */
kad_node_t *kad_relu(kad_node_t *x); /* f(x) = max{0,x} (element-wise rectifier, aka ReLU) */
kad_node_t *kad_softmax(kad_node_t *x); /* f_i(x_1,...,x_n) = exp(x_i) / \sum_j exp(x_j) (softmax: tf.nn.softmax(x,dim=-1)) */
kad_node_t *kad_1minus(kad_node_t *x); /* f(x) = 1 - x */
kad_node_t *kad_exp(kad_node_t *x); /* f(x) = exp(x) */
kad_node_t *kad_log(kad_node_t *x); /* f(x) = log(x) */
kad_node_t *kad_sin(kad_node_t *x); /* f(x) = sin(x) */
构建网络:
kann_t *kann_new(kad_node_t *cost, int n_rest, ...)
训练网络:
int kann_train_fnn1(kann_t *ann, float lr, int mini_size, int max_epoch, int max_drop_streak, float frac_val, int n, float **_x, float **_y)
对于RNN多输入的网络, kann_train_fnn1并不适合,而且kann中也没有提供类似API
模型保存及加载:
kann_t *kann_load_fp(FILE *fp)
void kann_save(const char *fn, kann_t *ann)
线程加速:
void kann_mt(kann_t *ann, int n_threads, int max_batch_size)
内存释放:
void kann_data_free(kann_data_t *d)
void kann_delete(kann_t *a)
数据结构
输入数据结构为【1,1,28,28】
The shape of n-d arrays
For 2D convolution, cuDNN and Theano take images in shape of (batch-size,in-channel,height,width) and convolution weights in shape of (out-channel,in-channel,kernel-height,kernel-width). KANN follows the cuDNN and Theano convention. Caffe and TensorFlow are different. They take images in shape of (batch-size,height,weight,in-channel) and weights in (kernel-height,kernel-width,in-channel,out-channel).
存储到链表中为:
typedef struct kad_node_t {
uint8_t n_d; /* number of dimensions; no larger than KAD_MAX_DIM */ //尺寸数;不大于KADY-Max
uint8_t flag; /* type of the node; see KAD_F_* for valid flags */ //节点的类型
uint16_t op; /* operator; kad_op_list[op] is the actual function */
int32_t n_child; /* number of operands/child nodes */
int32_t tmp; /* temporary field; MUST BE zero before calling kad_compile() */
int32_t ptr_size; /* size of ptr below */
int32_t d[KAD_MAX_DIM]; /* dimensions */
int32_t ext_label; /* labels for external uses (not modified by the kad_* APIs) */
uint32_t ext_flag; /* flags for external uses (not modified by the kad_* APIs) */
float *x; /* value; allocated for internal nodes */
float *g; /* gradient; allocated for internal nodes */
void *ptr; /* for special operators that need additional parameters (e.g. conv2d) */
void *gtmp; /* temporary data generated at the forward pass but used at the backward pass */
struct kad_node_t **child; /* operands/child nodes */
struct kad_node_t *pre; /* usually NULL; only used for RNN */
} kad_node_t, *kad_node_p;
图示结构图: