nn module, log, div, pow
This commit is contained in:
parent
bd1e62d895
commit
ca4a0f0dbc
20 changed files with 567 additions and 24 deletions
BIN
build/cpu.o
BIN
build/cpu.o
Binary file not shown.
BIN
build/cuda.cu.o
BIN
build/cuda.cu.o
Binary file not shown.
Binary file not shown.
BIN
build/tensor.o
BIN
build/tensor.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
import math
|
||||
|
||||
class AddBackward:
|
||||
def __init__(self, x, y):
|
||||
self.input = [x, y]
|
||||
|
|
@ -35,13 +37,42 @@ class MatmulBackward:
|
|||
x, y = self.input
|
||||
return [gradient @ y.transpose(-1,-2), x.transpose(-1,-2) @ gradient]
|
||||
|
||||
class PowBackward:
|
||||
"""class PowBackward:
|
||||
def __init__(self, x, power):
|
||||
self.input = [x]
|
||||
self.power = power
|
||||
|
||||
def backward(self, gradient):
|
||||
return [(gradient * self.power) * (self.input[0]) ** (self.power - 1)]
|
||||
return [(gradient * self.power) * (self.input[0]) ** (self.power - 1)]"""
|
||||
|
||||
class PowBackward:
|
||||
def __init__(self, base, exponent):
|
||||
self.input = [base, exponent]
|
||||
|
||||
def backward(self, gradient):
|
||||
base, exponent = self.input[0], self.input[1]
|
||||
|
||||
if isinstance(base, (int, float)):
|
||||
grad_base = gradient * (base ** (exponent - 1))
|
||||
grad_exponent = (gradient * base ** exponent) * math.log(base)
|
||||
|
||||
else:
|
||||
grad_base = gradient * exponent * (base ** (exponent - 1))
|
||||
grad_exponent = (gradient * base ** exponent) * (base.log())
|
||||
|
||||
return [grad_base, grad_exponent]
|
||||
|
||||
|
||||
class LogBackward:
|
||||
def __init__(self, input_tensor):
|
||||
self.input_tensor = input_tensor
|
||||
|
||||
def backward(self, gradient):
|
||||
input_tensor = self.input_tensor
|
||||
|
||||
grad_input = gradient / input_tensor
|
||||
|
||||
return [grad_input]
|
||||
|
||||
class SumBackward:
|
||||
def __init__(self, x):
|
||||
|
|
@ -66,3 +97,14 @@ class TransposeBackward:
|
|||
|
||||
def backward(self, gradient):
|
||||
return [gradient.transpose(self.axis2, self.axis1)]
|
||||
|
||||
class DivisionBackward:
|
||||
def __init__(self, x, y):
|
||||
self.input = [x, y]
|
||||
|
||||
def backward(self, gradient):
|
||||
x, y = self.input
|
||||
grad_x = gradient / y
|
||||
grad_y = -1 * gradient * (x / (y * y))
|
||||
return [grad_x, grad_y]
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor1->size; i++) {
|
||||
|
|
@ -32,6 +33,20 @@ void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data) {
|
|||
}
|
||||
}
|
||||
|
||||
void scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor->size; i++) {
|
||||
result_data[i] = scalar / tensor->data[i];
|
||||
}
|
||||
}
|
||||
|
||||
void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor->size; i++) {
|
||||
result_data[i] = tensor->data[i] / scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor1->shape[0]; i++) {
|
||||
|
|
@ -85,10 +100,23 @@ void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_d
|
|||
}
|
||||
}
|
||||
|
||||
void pow_tensor_cpu(Tensor* tensor, float power, float* result_data) {
|
||||
void scalar_pow_tensor_cpu(float base, Tensor* tensor, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor->size; i++) {
|
||||
result_data[i] = powf(tensor->data[i], power);
|
||||
result_data[i] = powf(base, tensor->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void tensor_pow_scalar_cpu(Tensor* tensor, float exponent, float* result_data) {
|
||||
|
||||
for (int i = 0; i < tensor->size; i++) {
|
||||
result_data[i] = powf(tensor->data[i], exponent);
|
||||
}
|
||||
}
|
||||
|
||||
void log_tensor_cpu(Tensor* tensor, float* result_data) {
|
||||
for (int i = 0; i < tensor->size; i++) {
|
||||
result_data[i] = logf(tensor->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,14 @@ void add_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
|||
void sum_tensor_cpu(Tensor* tensor1, float* result_data);
|
||||
void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
void scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data);
|
||||
void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data);
|
||||
void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
void broadcasted_batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
void pow_tensor_cpu(Tensor* tensor, float power, float* result_data);
|
||||
void scalar_pow_tensor_cpu(float base, Tensor* tensor, float* result_data);
|
||||
void tensor_pow_scalar_cpu(Tensor* tensor, float exponent, float* result_data);
|
||||
void log_tensor_cpu(Tensor* tensor, float* result_data);
|
||||
void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data);
|
||||
void ones_like_tensor_cpu(Tensor* tensor, float* result_data);
|
||||
void zeros_like_tensor_cpu(Tensor* tensor, float* result_data);
|
||||
|
|
|
|||
|
|
@ -107,9 +107,6 @@ __host__ void sum_tensor_cuda(Tensor* tensor, float* result_data) {
|
|||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
__global__ void sub_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
|
@ -176,6 +173,50 @@ __host__ void scalar_mul_tensor_cuda(Tensor* tensor, float scalar, float* result
|
|||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
__global__ void scalar_div_tensor_cuda_kernel(float scalar, float* data, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < size) {
|
||||
result_data[i] = scalar / data[i];
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void scalar_div_tensor_cuda(float scalar, Tensor* tensor, float* result_data) {
|
||||
|
||||
int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
|
||||
scalar_div_tensor_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(scalar, tensor->data, result_data, tensor->size);
|
||||
|
||||
cudaError_t error = cudaGetLastError();
|
||||
if (error != cudaSuccess) {
|
||||
printf("CUDA error: %s\n", cudaGetErrorString(error));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
__global__ void tensor_div_scalar_cuda_kernel(float* data, float scalar, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < size) {
|
||||
result_data[i] = data[i] / scalar;
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void tensor_div_scalar_cuda(Tensor* tensor, float scalar, float* result_data) {
|
||||
|
||||
int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
|
||||
tensor_div_scalar_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(tensor->data, scalar, result_data, tensor->size);
|
||||
|
||||
cudaError_t error = cudaGetLastError();
|
||||
if (error != cudaSuccess) {
|
||||
printf("CUDA error: %s\n", cudaGetErrorString(error));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
/*__global__ void matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int rows1, int cols1, int cols2) {
|
||||
|
||||
int row = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
|
@ -258,18 +299,18 @@ __host__ void matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result
|
|||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
__global__ void pow_tensor_cuda_kernel(float* data, float power, float* result_data, int size) {
|
||||
__global__ void tensor_pow_scalar_cuda_kernel(float* data, float exponent, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < size) {
|
||||
result_data[i] = powf(data[i], power);
|
||||
result_data[i] = powf(data[i], exponent);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data) {
|
||||
__host__ void tensor_pow_scalar_cuda(Tensor* tensor, float exponent, float* result_data) {
|
||||
|
||||
int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
|
||||
pow_tensor_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(tensor->data, power, result_data, tensor->size);
|
||||
tensor_pow_scalar_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(tensor->data, exponent, result_data, tensor->size);
|
||||
|
||||
cudaError_t error = cudaGetLastError();
|
||||
if (error != cudaSuccess) {
|
||||
|
|
@ -280,6 +321,51 @@ __host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data) {
|
|||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
__global__ void scalar_pow_tensor_cuda_kernel(float base, float* data, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < size) {
|
||||
result_data[i] = powf(base, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void scalar_pow_tensor_cuda(float base, Tensor* tensor, float* result_data) {
|
||||
|
||||
int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
|
||||
scalar_pow_tensor_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(base, tensor->data, result_data, tensor->size);
|
||||
|
||||
cudaError_t error = cudaGetLastError();
|
||||
if (error != cudaSuccess) {
|
||||
printf("CUDA error: %s\n", cudaGetErrorString(error));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
__global__ void log_tensor_cuda_kernel(float* data, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < size) {
|
||||
result_data[i] = logf(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void log_tensor_cuda(Tensor* tensor, float* result_data) {
|
||||
|
||||
int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
|
||||
log_tensor_cuda_kernel<<<number_of_blocks, THREADS_PER_BLOCK>>>(tensor->data, result_data, tensor->size);
|
||||
|
||||
cudaError_t error = cudaGetLastError();
|
||||
if (error != cudaSuccess) {
|
||||
printf("CUDA error: %s\n", cudaGetErrorString(error));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
|
||||
__global__ void ones_like_tensor_cuda_kernel(float* data, float* result_data, int size) {
|
||||
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,23 @@
|
|||
__global__ void scalar_mul_tensor_cuda_kernel(float* data, float scalar, float* result_data, int size);
|
||||
__host__ void scalar_mul_tensor_cuda(Tensor* tensor, float scalar, float* result_data);
|
||||
|
||||
__global__ void scalar_div_tensor_cuda_kernel(float scalar, float* data, float* result_data, int size);
|
||||
__host__ void scalar_div_tensor_cuda(float scalar, Tensor* tensor, float* result_data);
|
||||
|
||||
__global__ void tensor_div_scalar_cuda_kernel(float* data, float scalar, float* result_data, int size);
|
||||
__host__ void tensor_div_scalar_cuda(Tensor* tensor, float scalar, float* result_data);
|
||||
|
||||
__global__ void matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int rows1, int cols1, int cols2);
|
||||
__host__ void matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data);
|
||||
|
||||
__global__ void pow_tensor_cuda_kernel(float* data, float power, float* result_data, int size);
|
||||
__host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data);
|
||||
__global__ void tensor_pow_scalar_cuda_kernel(float* data, float exponent, float* result_data, int size);
|
||||
__host__ void tensor_pow_scalar_cuda(Tensor* tensor, float exponent, float* result_data);
|
||||
|
||||
__global__ void scalar_pow_tensor_cuda_kernel(float base, float* data, float* result_data, int size);
|
||||
__host__ void scalar_pow_tensor_cuda(float base, Tensor* tensor, float* result_data);
|
||||
|
||||
__global__ void log_tensor_cuda_kernel(float* data, float* result_data, int size);
|
||||
__host__ void log_tensor_cuda(Tensor* tensor, float* result_data);
|
||||
|
||||
__global__ void ones_like_tensor_cuda_kernel(float* data, float* result_data, int size);
|
||||
__host__ void ones_like_tensor_cuda(Tensor* tensor, float* result_data);
|
||||
|
|
|
|||
|
|
@ -335,6 +335,82 @@ extern "C" {
|
|||
}
|
||||
}
|
||||
|
||||
Tensor* scalar_div_tensor(float scalar, Tensor* tensor) {
|
||||
|
||||
char* device = (char*)malloc(strlen(tensor->device) + 1);
|
||||
if (device != NULL) {
|
||||
strcpy(device, tensor->device);
|
||||
} else {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
int ndim = tensor->ndim;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
shape[i] = tensor->shape[i];
|
||||
}
|
||||
|
||||
if (strcmp(tensor->device, "cuda") == 0) {
|
||||
|
||||
float* result_data;
|
||||
cudaMalloc((void **)&result_data, tensor->size * sizeof(float));
|
||||
scalar_div_tensor_cuda(scalar, tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
else {
|
||||
float* result_data = (float*)malloc(tensor->size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
scalar_div_tensor_cpu(scalar, tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
}
|
||||
|
||||
Tensor* tensor_div_scalar(Tensor* tensor, float scalar) {
|
||||
|
||||
char* device = (char*)malloc(strlen(tensor->device) + 1);
|
||||
if (device != NULL) {
|
||||
strcpy(device, tensor->device);
|
||||
} else {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
int ndim = tensor->ndim;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
shape[i] = tensor->shape[i];
|
||||
}
|
||||
|
||||
if (strcmp(tensor->device, "cuda") == 0) {
|
||||
|
||||
float* result_data;
|
||||
cudaMalloc((void **)&result_data, tensor->size * sizeof(float));
|
||||
tensor_div_scalar_cuda(tensor, scalar, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
else {
|
||||
float* result_data = (float*)malloc(tensor->size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
tensor_div_scalar_cpu(tensor, scalar, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
}
|
||||
|
||||
Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2) {
|
||||
//MxN @ NxP = MxP
|
||||
// Check if tensors have compatible shapes for matrix multiplication
|
||||
|
|
@ -528,7 +604,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
Tensor* pow_tensor(Tensor* tensor, float power) {
|
||||
Tensor* tensor_pow_scalar(Tensor* tensor, float exponent) {
|
||||
char* device = (char*)malloc(strlen(tensor->device) + 1);
|
||||
if (device != NULL) {
|
||||
strcpy(device, tensor->device);
|
||||
|
|
@ -551,7 +627,7 @@ extern "C" {
|
|||
|
||||
float* result_data;
|
||||
cudaMalloc((void **)&result_data, tensor->size * sizeof(float));
|
||||
pow_tensor_cuda(tensor, power, result_data);
|
||||
tensor_pow_scalar_cuda(tensor, exponent, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
else {
|
||||
|
|
@ -560,7 +636,81 @@ extern "C" {
|
|||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
pow_tensor_cpu(tensor, power, result_data);
|
||||
tensor_pow_scalar_cpu(tensor, exponent, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
}
|
||||
|
||||
Tensor* scalar_pow_tensor(float base, Tensor* tensor) {
|
||||
char* device = (char*)malloc(strlen(tensor->device) + 1);
|
||||
if (device != NULL) {
|
||||
strcpy(device, tensor->device);
|
||||
} else {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
int ndim = tensor->ndim;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
shape[i] = tensor->shape[i];
|
||||
}
|
||||
|
||||
if (strcmp(tensor->device, "cuda") == 0) {
|
||||
|
||||
float* result_data;
|
||||
cudaMalloc((void **)&result_data, tensor->size * sizeof(float));
|
||||
scalar_pow_tensor_cuda(base, tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
else {
|
||||
float* result_data = (float*)malloc(tensor->size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
scalar_pow_tensor_cpu(base, tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
}
|
||||
|
||||
Tensor* log_tensor(Tensor* tensor) {
|
||||
char* device = (char*)malloc(strlen(tensor->device) + 1);
|
||||
if (device != NULL) {
|
||||
strcpy(device, tensor->device);
|
||||
} else {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
int ndim = tensor->ndim;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
shape[i] = tensor->shape[i];
|
||||
}
|
||||
|
||||
if (strcmp(tensor->device, "cuda") == 0) {
|
||||
|
||||
float* result_data;
|
||||
cudaMalloc((void **)&result_data, tensor->size * sizeof(float));
|
||||
log_tensor_cuda(tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
else {
|
||||
float* result_data = (float*)malloc(tensor->size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
log_tensor_cpu(tensor, result_data);
|
||||
return create_tensor(result_data, shape, ndim, device);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,13 @@ extern "C" {
|
|||
Tensor* sub_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
Tensor* scalar_mul_tensor(Tensor* tensor, float scalar);
|
||||
Tensor* scalar_div_tensor(float scalar, Tensor* tensor);
|
||||
Tensor* tensor_div_scalar(Tensor* tensor, float scalar);
|
||||
Tensor* reshape_tensor(Tensor* tensor, int* new_shape, int new_ndim);
|
||||
Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
Tensor* pow_tensor(Tensor* tensor, float power);
|
||||
Tensor* tensor_pow_scalar(Tensor* tensor, float exponent);
|
||||
Tensor* scalar_pow_tensor(float base, Tensor* tensor);
|
||||
Tensor* log_tensor(Tensor* tensor);
|
||||
void to_device(Tensor* tensor, char* device);
|
||||
Tensor* ones_like_tensor(Tensor* tensor);
|
||||
Tensor* zeros_like_tensor(Tensor* tensor);
|
||||
|
|
|
|||
2
norch/nn/__init__.py
Normal file
2
norch/nn/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from .modules import *
|
||||
from .activations import *
|
||||
20
norch/nn/activation.py
Normal file
20
norch/nn/activation.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from module import Module
|
||||
import math
|
||||
|
||||
class Activation(Module):
|
||||
"""
|
||||
Abstract classes for activations
|
||||
"""
|
||||
def __init__(self):
|
||||
super(Activation, self).__init__()
|
||||
|
||||
def forward(self, x):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Sigmoid(Activation):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def forward(self, x):
|
||||
return 1.0 / (1.0 + (math.e) ** (-x))
|
||||
81
norch/nn/module.py
Normal file
81
norch/nn/module.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from parameter import Parameter
|
||||
from collections import OrderedDict
|
||||
from abc import ABC
|
||||
import pickle
|
||||
import json
|
||||
import inspect
|
||||
import warnings
|
||||
|
||||
class Module(ABC):
|
||||
"""
|
||||
Abstract class for modules
|
||||
"""
|
||||
def __init__(self):
|
||||
self._modules = OrderedDict()
|
||||
self._params = OrderedDict()
|
||||
self._grads = OrderedDict()
|
||||
self.training = True
|
||||
|
||||
def __call__(self, *inputs, **kwargs):
|
||||
return self.forward(*inputs, **kwargs)
|
||||
|
||||
def train(self):
|
||||
self.training = True
|
||||
for param in self.parameters():
|
||||
param.requires_grad = True
|
||||
|
||||
def eval(self):
|
||||
self.training = False
|
||||
for param in self.parameters():
|
||||
param.requires_grad = False
|
||||
|
||||
def parameters(self):
|
||||
for name, value in inspect.getmembers(self):
|
||||
if isinstance(value, Parameter):
|
||||
yield value
|
||||
elif isinstance(value, Module):
|
||||
yield from value.parameters()
|
||||
|
||||
def to(self, device):
|
||||
for parameter in self.parameters():
|
||||
parameter.to(device)
|
||||
|
||||
def state_dict(self):
|
||||
state = OrderedDict()
|
||||
for i, param in enumerate(self.parameters()):
|
||||
state[f'param{i}'] = param.tolist()
|
||||
return state
|
||||
|
||||
def load_state(self, state_dict):
|
||||
for i, param in self.parameters():
|
||||
data = state_dict[f'param{i}']
|
||||
if param.shape != data.shape:
|
||||
warnings.warn(f"The 'state_dict' shape does not match model's parameter shape. "
|
||||
f"Got {data.shape}, expected {param.shape}.")
|
||||
param.data = Parameter(data=data)
|
||||
|
||||
def save(self, filename='model.pickle'):
|
||||
with open(filename, 'wb') as f:
|
||||
pickle.dump(self, f)
|
||||
|
||||
def save_dict(self, filename='state_dict.json'):
|
||||
state = self.state_dict()
|
||||
with open(filename, 'w') as f:
|
||||
json.dump(state, f)
|
||||
|
||||
def inner_repr(self):
|
||||
return ""
|
||||
|
||||
def __repr__(self):
|
||||
string = f"{self.get_name()}("
|
||||
tab = " "
|
||||
modules = self._modules
|
||||
if modules == {}:
|
||||
string += f'\n{tab}(parameters): {self.inner_repr()}'
|
||||
else:
|
||||
for key, module in modules.items():
|
||||
string += f"\n{tab}({key}): {module.get_name()}({module.inner_repr()})"
|
||||
return f'{string}\n)'
|
||||
|
||||
def get_name(self):
|
||||
return self.__class__.__name__
|
||||
18
norch/nn/modules/linear.py
Normal file
18
norch/nn/modules/linear.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from module import Module
|
||||
from parameter import Parameter
|
||||
|
||||
class Linear(Module):
|
||||
def __init__(self, input_dim, output_dim):
|
||||
super().__init__()
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
self.weight = Parameter(shape=[self.input_dim, self.output_dim])
|
||||
self.bias = Parameter(shape=[self.output_dim, 1])
|
||||
|
||||
def forward(self, x):
|
||||
z = self.weight @ x + self.bias
|
||||
return z
|
||||
|
||||
def inner_repr(self):
|
||||
return f"input_dim={self.input_dim}, output_dim={self.output_dim}, " \
|
||||
f"bias={True if self.bias is not None else False}"
|
||||
14
norch/nn/parameter.py
Normal file
14
norch/nn/parameter.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from tensor import Tensor
|
||||
import random
|
||||
|
||||
class Parameter(Tensor):
|
||||
"""
|
||||
A parameter is a trainable tensor.
|
||||
"""
|
||||
def __init__(self, shape):
|
||||
data = []
|
||||
for dim_size in reversed(shape):
|
||||
random_dim = [random.random() for _ in range(dim_size)]
|
||||
data.insert(0, random_dim)
|
||||
|
||||
super().__init__(data, requires_grad=True)
|
||||
|
|
@ -344,14 +344,93 @@ class Tensor:
|
|||
|
||||
return result_data
|
||||
|
||||
def __pow__(self, power):
|
||||
def __pow__(self, other):
|
||||
if isinstance(other, (int, float)):
|
||||
other = float(other)
|
||||
Tensor._C.tensor_pow_scalar.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float]
|
||||
Tensor._C.tensor_pow_scalar.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.tensor_pow_scalar(self.tensor, ctypes.c_float(other))
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = self.shape.copy()
|
||||
result_data.ndim = self.ndim
|
||||
result_data.device = self.device
|
||||
|
||||
result_data.requires_grad = self.requires_grad
|
||||
if result_data.requires_grad:
|
||||
result_data.grad_fn = PowBackward(self, other)
|
||||
|
||||
elif isinstance(self, (int, float)):
|
||||
self = float(self)
|
||||
Tensor._C.scalar_pow_tensor.argtypes = [ctypes.c_float, ctypes.POINTER(CTensor)]
|
||||
Tensor._C.scalar_pow_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.scalar_pow_tensor(ctypes.c_float(self), other.tensor)
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = other.shape.copy()
|
||||
result_data.ndim = other.ndim
|
||||
result_data.device = other.device
|
||||
|
||||
result_data.requires_grad = other.requires_grad
|
||||
if result_data.requires_grad:
|
||||
result_data.grad_fn = PowBackward(other, self)
|
||||
|
||||
power_ctypes = ctypes.c_float(power)
|
||||
else:
|
||||
raise ValueError("Tensor to tensor power is not supported")
|
||||
|
||||
return result_data
|
||||
|
||||
Tensor._C.pow_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float]
|
||||
Tensor._C.pow_tensor.restype = ctypes.POINTER(CTensor)
|
||||
def __truediv__(self, other):
|
||||
other = float(other)
|
||||
Tensor._C.tensor_div_scalar.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float]
|
||||
Tensor._C.tensor_div_scalar.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.pow_tensor(self.tensor, power_ctypes)
|
||||
result_tensor_ptr = Tensor._C.tensor_div_scalar(other.tensor, ctypes.c_float(self))
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = self.shape.copy()
|
||||
result_data.ndim = self.ndim
|
||||
result_data.device = self.device
|
||||
|
||||
result_data.requires_grad = self.requires_grad
|
||||
if result_data.requires_grad:
|
||||
result_data.grad_fn = DivisionBackward(self, other)
|
||||
|
||||
return result_data
|
||||
|
||||
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
other = float(other)
|
||||
|
||||
Tensor._C.scalar_div_tensor.argtypes = [ctypes.c_float, ctypes.POINTER(CTensor)]
|
||||
Tensor._C.scalar_div_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.scalar_div_tensor(ctypes.c_float(other), self.tensor)
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = self.shape.copy()
|
||||
result_data.ndim = self.ndim
|
||||
result_data.device = self.device
|
||||
|
||||
result_data.requires_grad = self.requires_grad
|
||||
if result_data.requires_grad:
|
||||
result_data.grad_fn = DivisionBackward(other, self)
|
||||
|
||||
return result_data
|
||||
|
||||
|
||||
def log(self):
|
||||
Tensor._C.log_tensor.argtypes = [ctypes.POINTER(CTensor)]
|
||||
Tensor._C.log_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.log_tensor(self.tensor)
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
|
|
@ -361,7 +440,7 @@ class Tensor:
|
|||
|
||||
result_data.requires_grad = self.requires_grad
|
||||
if result_data.requires_grad:
|
||||
result_data.grad_fn = PowBackward(self, power)
|
||||
result_data.grad_fn = LogBackward(self)
|
||||
|
||||
return result_data
|
||||
|
||||
|
|
|
|||
3
test.py
3
test.py
|
|
@ -74,6 +74,9 @@ if __name__ == "__main__":
|
|||
[[13, 14], [15, 16], [17, 18]],
|
||||
[[19, 20], [21, 22], [23, 24]],
|
||||
[[25, 26], [27, 28], [29, 30]]], requires_grad=True)
|
||||
|
||||
print(tensor1 / 1)
|
||||
exit()
|
||||
|
||||
# Reshape tensor1 to 2x3x5
|
||||
reshaped_tensor = tensor1.transpose(1, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue