Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh

set -e
mkdir -p build
cd build
cmake ..
cmake --build .

echo "\nBuild complete. Ctensor Tests Executable is in the 'build/bin' directory. Run 'build/bin/cten_tests' to run the tests. \n"
echo "\nFor running the main(Demo) executable, run 'build/cten_exe' \n"
15 changes: 0 additions & 15 deletions build_g.sh

This file was deleted.

2 changes: 1 addition & 1 deletion include/common/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void c11_vector__swap(c11_vector* self, c11_vector* other);
#define c11_vector__erase(T, self, index) \
do { \
T* p = (T*)(self)->data + (index); \
memmove(p, p + 1, ((self)->length - (index)-1) * sizeof(T)); \
memmove(p, p + 1, ((self)->length - (index) - 1) * sizeof(T)); \
(self)->length--; \
} while(0)

Expand Down
52 changes: 36 additions & 16 deletions include/cten.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
#include <limits.h>

#define _CTEN_PICK_REDUCE(_1, _2, NAME, ...) NAME
#define Tensor_max(...) _CTEN_PICK_REDUCE(__VA_ARGS__, Tensor_max_dim, Tensor_max_all)(__VA_ARGS__)
#define Tensor_min(...) _CTEN_PICK_REDUCE(__VA_ARGS__, Tensor_min_dim, Tensor_min_all)(__VA_ARGS__)
#define Tensor_max(...) _CTEN_PICK_REDUCE(__VA_ARGS__, Tensor_max_dim, Tensor_max_all)(__VA_ARGS__)
#define Tensor_min(...) _CTEN_PICK_REDUCE(__VA_ARGS__, Tensor_min_dim, Tensor_min_all)(__VA_ARGS__)

#define _CTEN_PICK(_1,_2,NAME,...) NAME
#define _CTEN_PICK(_1, _2, NAME, ...) NAME
#define Tensor_mean(...) _CTEN_PICK(__VA_ARGS__, Tensor_mean_dim, Tensor_mean_all)(__VA_ARGS__)
#define Tensor_sum(...) _CTEN_PICK(__VA_ARGS__, Tensor_sum_dim, Tensor_sum_all )(__VA_ARGS__)
#define Tensor_sum(...) _CTEN_PICK(__VA_ARGS__, Tensor_sum_dim, Tensor_sum_all)(__VA_ARGS__)

typedef int TensorShape[4];
typedef struct GradNode GradNode;
Expand Down Expand Up @@ -88,8 +88,8 @@ Tensor Tensor_reciprocal(Tensor self);
/* Helper functions that the macros dispatch to */
Tensor Tensor_mean_all(Tensor self);
Tensor Tensor_mean_dim(Tensor self, int dim);
Tensor Tensor_sum_all (Tensor self);
Tensor Tensor_sum_dim (Tensor self, int dim);
Tensor Tensor_sum_all(Tensor self);
Tensor Tensor_sum_dim(Tensor self, int dim);

Tensor Tensor_max_all(Tensor self);
TensorMaxMinResult Tensor_max_dim(Tensor self, int dim);
Expand Down Expand Up @@ -133,24 +133,32 @@ typedef struct optim_adagrad optim_adagrad;
typedef struct optim_rmsprop optim_rmsprop;
typedef struct optim_adam optim_adam;

//SGD
// SGD
optim_sgd* optim_sgd_new(int n_params, Tensor* params, float weight_decay);
void optim_sgd_config(optim_sgd* self, float lr, float momentum);
void optim_sgd_zerograd(optim_sgd* self);
void optim_sgd_step(optim_sgd* self);

//AdaGrad
optim_adagrad* optim_adagrad_new(int n_params, Tensor* params, float lr, float ε,float weight_decay);
// AdaGrad
optim_adagrad*
optim_adagrad_new(int n_params, Tensor* params, float lr, float ε, float weight_decay);
void optim_adagrad_zerograd(optim_adagrad* self);
void optim_adagrad_step(optim_adagrad* self);

//RMSProp
optim_rmsprop* optim_rmsprop_new(int n_params, Tensor* params, float lr, float β, float ε,float weight_decay);
// RMSProp
optim_rmsprop*
optim_rmsprop_new(int n_params, Tensor* params, float lr, float β, float ε, float weight_decay);
void optim_rmsprop_zerograd(optim_rmsprop* self);
void optim_rmsprop_step(optim_rmsprop* self);

//Adam
optim_adam* optim_adam_new(int n_params, Tensor* params, float lr, float β1, float β2, float ε,float weight_decay);
// Adam
optim_adam* optim_adam_new(int n_params,
Tensor* params,
float lr,
float β1,
float β2,
float ε,
float weight_decay);
void optim_adam_zerograd(optim_adam* self);
void optim_adam_step(optim_adam* self);

Expand All @@ -168,13 +176,25 @@ void cten_end_eval();
bool va_arg_is_present(va_list args);

/* Utils */
void Tensor_normalize_dataset(const float (*X)[4], float (*X_norm)[4], int n_samples, int n_train_samples, int n_features);Tensor Tensor_detach(Tensor self);
void Tensor_shuffle_dataset(const float (*X)[4], const int *y,float (*X_shuffled)[4], int *y_shuffled, int n_samples, int n_features);
void Tensor_normalize_dataset(const float (*X)[4],
float (*X_norm)[4],
int n_samples,
int n_train_samples,
int n_features);
Tensor Tensor_detach(Tensor self);
void Tensor_shuffle_dataset(const float (*X)[4],
const int* y,
float (*X_shuffled)[4],
int* y_shuffled,
int n_samples,
int n_features);
void cten_assert(bool cond, const char* fmt, ...);
void cten_assert_shape(const char* title, TensorShape a, TensorShape b);
void cten_assert_dim(const char* title, int a, int b);
bool cten_elemwise_broadcast(Tensor* a, Tensor* b);
int load_iris_dataset(const float (**X)[4], const int** y);
Tensor Tensor_reduce_dim(Tensor self, int dim, const char* operation);
Tensor reduce_gradient_for_broadcasting(Tensor grad, TensorShape original_shape, TensorShape broadcasted_shape);
Tensor reduce_gradient_for_broadcasting(Tensor grad,
TensorShape original_shape,
TensorShape broadcasted_shape);
Tensor Tensor_unsqueeze(Tensor self, int dim);
73 changes: 37 additions & 36 deletions src/basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ int TensorShape_tostring(TensorShape shape, char* buf, int size) {
Tensor Tensor_new(TensorShape shape, bool requires_grad) {
Tensor self;
memset(self.shape, 0, sizeof(TensorShape));
int ndims = TensorShape_dim(shape);
int ndims = TensorShape_dim(shape);
memcpy(self.shape, shape, ndims * sizeof(int));

int numel = TensorShape_numel(self.shape);
self.data = _cten_malloc(sizeof(FloatBuffer) + sizeof(float) * numel);
self.data->numel = numel;
//Initialize tensor with random values

// Initialize tensor with random values
float* data_ptr = self.data->flex;
for (int i = 0; i < numel; i++) {
for(int i = 0; i < numel; i++) {
data_ptr[i] = ((float)rand() / RAND_MAX) * 2.0f - 1.0f;
}

if(requires_grad) {
self.node = _cten_malloc(sizeof(GradNode));
memset(self.node, 0, sizeof(GradNode));
Expand All @@ -76,9 +76,7 @@ Tensor Tensor_ones(TensorShape shape, bool requires_grad) {

Tensor Tensor_transpose(Tensor self) {
int dim = TensorShape_dim(self.shape);
if(dim < 2){
return self;
}
if(dim < 2) { return self; }
TensorShape new_shape;
new_shape[0] = self.shape[1];
new_shape[1] = self.shape[0];
Expand Down Expand Up @@ -121,17 +119,15 @@ Tensor Tensor_detach(Tensor self) {
}

void Tensor_backward(Tensor self, Tensor grad) {
if(self.node == NULL) {
return;
}

if(self.node == NULL) { return; }

if(grad.data == NULL) {
assert(self.data->numel == 1);
grad = Tensor_ones((TensorShape){1, 0, 0, 0}, false);
}

assert(grad.node == NULL);

// Accumulate gradient
if(self.node->grad.data == NULL) {
self.node->grad = grad;
Expand All @@ -141,63 +137,68 @@ void Tensor_backward(Tensor self, Tensor grad) {

for(int i = 0; i < self.node->n_inputs; i++) {
Tensor input_tensor = self.node->inputs[i];
if (input_tensor.node == NULL) {
continue;
}

// Step 1: Get the local gradient (the partial derivative). --> For z = f(x, y), this would be dz/dx or dz/dy.
if(input_tensor.node == NULL) { continue; }

// Step 1: Get the local gradient (the partial derivative). --> For z = f(x, y), this would
// be dz/dx or dz/dy.
Tensor input_grad = self.node->grad_fn(self, i);

// This is the gradient flowing from the output, which we need to propagate backwards.
Tensor grad = self.node->grad;
int input_ndim = TensorShape_dim(input_tensor.shape);
int grad_ndim = TensorShape_dim(grad.shape);

if ((strcmp(self.node->name, "Sum") == 0 || strcmp(self.node->name, "Mean") == 0 || strcmp(self.node->name, "MaxDim") == 0 || strcmp(self.node->name, "MinDim") == 0) && input_ndim > grad_ndim) {
// Find the dimension that was reduced. We assume the non-reduced dimensions match in size.

if((strcmp(self.node->name, "Sum") == 0 || strcmp(self.node->name, "Mean") == 0 ||
strcmp(self.node->name, "MaxDim") == 0 || strcmp(self.node->name, "MinDim") == 0) &&
input_ndim > grad_ndim) {
// Find the dimension that was reduced. We assume the non-reduced dimensions match in
// size.
int unsqueeze_dim = -1;
int grad_idx = 0;
for (int dim_idx = 0; dim_idx < input_ndim; ++dim_idx) {
if (grad_idx >= grad_ndim || input_tensor.shape[dim_idx] != grad.shape[grad_idx]) {
for(int dim_idx = 0; dim_idx < input_ndim; ++dim_idx) {
if(grad_idx >= grad_ndim || input_tensor.shape[dim_idx] != grad.shape[grad_idx]) {
// Yes, this is the dimension that was removed.
unsqueeze_dim = dim_idx;
break;
}
grad_idx++;
}

if (unsqueeze_dim != -1) {
if(unsqueeze_dim != -1) {
grad = Tensor_unsqueeze(grad, unsqueeze_dim);
} else {
cten_assert(false, "Could not deduce unsqueeze dimension.");
}
}

// Step 2: Apply the chain rule (upstream_grad * local_grad)
Tensor combined_grad;
if (strcmp(self.node->name, "Softmax") == 0) {
if(strcmp(self.node->name, "Softmax") == 0) {
combined_grad = input_grad;
} else if(strcmp(self.node->name, "Matmul") == 0) {
if (i == 0) {
if(i == 0) {
combined_grad = Tensor_matmul(grad, input_grad);
} else {
combined_grad = Tensor_matmul(input_grad, grad);
}
} else {
combined_grad = Tensor_mul(grad, input_grad);
}

// Step 3: Handle broadcasting. --> If the original input was broadcasted, the resulting gradient will have the broadcasted shape, it must be reduced back down to the original input's shape.

// Step 3: Handle broadcasting. --> If the original input was broadcasted, the resulting
// gradient will have the broadcasted shape, it must be reduced back down to the original
// input's shape.
bool needs_reduction = false;
for (int dim = 0; dim < 4; dim++) {
if (combined_grad.shape[dim] != input_tensor.shape[dim]) {
for(int dim = 0; dim < 4; dim++) {
if(combined_grad.shape[dim] != input_tensor.shape[dim]) {
needs_reduction = true;
break;
}
}

if (needs_reduction) {
combined_grad = reduce_gradient_for_broadcasting(combined_grad, input_tensor.shape, self.shape);

if(needs_reduction) {
combined_grad =
reduce_gradient_for_broadcasting(combined_grad, input_tensor.shape, self.shape);
}
Tensor_backward(input_tensor, combined_grad);
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/vector.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void* c11_vector__submit(c11_vector* self, int* length) {
return retval;
}

void c11_vector__swap(c11_vector *self, c11_vector *other){
void c11_vector__swap(c11_vector* self, c11_vector* other) {
c11_vector tmp = *self;
*self = *other;
*other = tmp;
Expand Down
Loading
Loading