a great work has been done here

now there is no mentioning python in c code (except for the
boilerplate at the beginning, but the rest is nice clean c).
all the bridging is being done in cython (where it belongs).
and no memory leaks so there's that!
This commit is contained in:
2019-11-25 22:01:39 -08:00
parent 253c833b5b
commit 76f8d7dcb6
2 changed files with 94 additions and 105 deletions

View File

@@ -3,6 +3,7 @@ import numpy as np
import mynet as mn
from libc.stdlib cimport malloc
from libc.string cimport memcpy
ctr = []
@@ -11,9 +12,6 @@ opt = mn.SGDOptimizer(lr=0.1)
cdef extern from "numpy/arrayobject.h":
object PyArray_SimpleNewFromData(
int nd, long* dims, int typenum, void* data
)
void *PyArray_DATA(np.ndarray arr)
@@ -25,7 +23,7 @@ ctypedef public struct Dense:
ctypedef public struct Network:
Py_ssize_t n_layers;
size_t n_layers;
Dense* layers;
@@ -34,90 +32,86 @@ cdef public char * greeting():
cdef public void debug_print(object o):
print(o.flags)
print(o)
cdef public np.ndarray[np.float32_t, ndim=2, mode='c'] predict(
object net,
np.ndarray[np.float32_t, ndim=2, mode='c'] X
cdef public void predict(
Network* net,
float* X,
size_t batch_size
):
try:
return net(X)
except Exception as e:
print(e)
cdef public object create_network():
return mn.Network((784, 10), mn.relu, mn.sigmoid, mn.bin_x_entropy)
cdef public object combo_net(list nets):
return mn.combo_net(nets)
cdef public object make_like(object neta, object netb):
netb.be_like(neta)
pass
# try:
# return net(X)
# except Exception as e:
# print(e)
cdef public void step_net(
object net,
Network* c_net,
float* batch_data,
Py_ssize_t batch_size
size_t batch_size
):
cdef Py_ssize_t in_dim = net.geometry[0]
cdef Py_ssize_t out_dim = net.geometry[-1]
net = wrap_c_network(c_net)
cdef size_t in_dim = net.geometry[0]
cdef size_t out_dim = net.geometry[-1]
batch = np.asarray(<float[:batch_size,:in_dim+out_dim]>batch_data)
net.step(batch[:, :in_dim], batch[:, in_dim:], opt)
cdef public float eval_net(
object net
):
cdef public float eval_net(Network* c_net):
net = wrap_c_network(c_net)
return net.evaluate(X_test, y_test, 'cls')
cdef public np.ndarray[np.float32_t, ndim=2, mode='c'] mnist_batch(
Py_ssize_t bs
):
cdef public void mnist_batch(float* batch, size_t bs):
idx = np.random.choice(len(X_train), bs, replace=False)
arr = np.concatenate([X_train[idx], y_train[idx]], axis=1)
return arr
memcpy(batch, <float*>PyArray_DATA(arr), arr.size*sizeof(float))
cdef public void inspect_array(
cdef public void create_c_network(Network* c_net):
net = _create_network()
c_net.n_layers = len(net.layers)
c_net.layers = <Dense*>malloc(sizeof(Dense) * c_net.n_layers)
for i, l in enumerate(net.layers):
d0, d1 = l.W.shape
c_net.layers[i].shape[0] = d0
c_net.layers[i].shape[1] = d1
c_net.layers[i].W = <float*>malloc(sizeof(float) * d0 * d1)
c_net.layers[i].b = <float*>malloc(sizeof(float) * d1)
memcpy(c_net.layers[i].W, PyArray_DATA(l.W), sizeof(float) * d0 * d1)
memcpy(c_net.layers[i].b, PyArray_DATA(l.b), sizeof(float) * d1)
c_net.layers[i].ownmem = 1
cdef public void be_like(Network* c_dst, Network* c_src):
dst = wrap_c_network(c_dst)
src = wrap_c_network(c_src)
dst.be_like(src)
cdef object wrap_c_network(Network* c_net):
net = _create_network(init=False)
for i, l in enumerate(net.layers):
d0, d1 = l.W.shape
l.W = np.asarray(<float[:d0,:d1]>c_net.layers[i].W)
l.b = np.asarray(<float[:d1]>c_net.layers[i].b)
return net
cdef void inspect_array(
np.ndarray[np.float32_t, ndim=2, mode='c'] a
):
print(a.flags)
print(a.dtype)
print(a.sum())
print(a.flags, flush=True)
print(a.dtype, flush=True)
print(a.sum(), flush=True)
cdef public void be_like_cified(
object net,
Network* c_net
):
"""WARNING this function makes an assumption that `net` and `c_net`
have the same shape and hopefully is going to crash horribly otherwise."""
for i, l in enumerate(net.layers):
w1, w2 = l.W.shape
l.W[:] = <float[:w1,:w2]>c_net.layers[i].W
l.b[:] = <float[:w2]>c_net.layers[i].b
def _create_network(init=True):
return mn.Network((784, 10), mn.relu, mn.sigmoid, mn.bin_x_entropy,
initialize=init)
cdef public void cify_network(
object net, Network* c_net
):
"""WARNING `c_net` is valid as long as `net` is
Whoever has `c_net` is responsible for freeing c_net.layers list
Layers themselves don't need any de-init.
"""
c_net.n_layers = len(net.layers)
c_net.layers = <Dense*>malloc(len(net.layers) * sizeof(Dense))
for i, l in enumerate(net.layers):
w1, w2 = l.W.shape
c_net.layers[i].shape[0] = w1
c_net.layers[i].shape[1] = w2
c_net.layers[i].W = <float*>PyArray_DATA(l.W)
c_net.layers[i].b = <float*>PyArray_DATA(l.b)
c_net.layers[i].ownmem = 0
def combo_net(nets):
return mn.combo_net(nets)