Sub, matmul, mul, reshape
This commit is contained in:
parent
d29ad014bf
commit
087422a8b0
6 changed files with 260 additions and 22 deletions
Binary file not shown.
161
csrc/tensor.cpp
161
csrc/tensor.cpp
|
|
@ -142,7 +142,7 @@ extern "C" {
|
|||
Tensor* sub_tensor(Tensor* tensor1, Tensor* tensor2) {
|
||||
printf("Adding tensor\n");
|
||||
if (tensor1->ndim != tensor2->ndim) {
|
||||
fprintf(stderr, "Tensors must have the same number of dimensions %d and %d for addition\n", tensor1->ndim, tensor2->ndim);
|
||||
fprintf(stderr, "Tensors must have the same number of dimensions %d and %d for subtraction\n", tensor1->ndim, tensor2->ndim);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ extern "C" {
|
|||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
if (tensor1->shape[i] != tensor2->shape[i]) {
|
||||
fprintf(stderr, "Tensors must have the same shape %d and %d at index %d for addition\n", tensor1->shape[i], tensor2->shape[i], i);
|
||||
fprintf(stderr, "Tensors must have the same shape %d and %d at index %d for subtraction\n", tensor1->shape[i], tensor2->shape[i], i);
|
||||
exit(1);
|
||||
}
|
||||
shape[i] = tensor1->shape[i];
|
||||
|
|
@ -211,4 +211,161 @@ extern "C" {
|
|||
|
||||
return create_tensor(result_data, shape, ndim);
|
||||
}
|
||||
|
||||
Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2) {
|
||||
printf("Adding tensor\n");
|
||||
if (tensor1->ndim != tensor2->ndim) {
|
||||
fprintf(stderr, "Tensors must have the same number of dimensions %d and %d for element-wise multiplication\n", tensor1->ndim, tensor2->ndim);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ndim = tensor1->ndim;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Size: %d\n", tensor1->size);
|
||||
printf("Data: [");
|
||||
for (int i = 0; i < tensor1->size; i++) {
|
||||
printf("%.2f", tensor1->data[i]);
|
||||
if (i < tensor1->size - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]\n");
|
||||
|
||||
printf("Size: %d\n", tensor2->size);
|
||||
printf("Data: [");
|
||||
for (int i = 0; i < tensor2->size; i++) {
|
||||
printf("%.2f", tensor2->data[i]);
|
||||
if (i < tensor2->size - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]\n");
|
||||
|
||||
printf("Shapes : [");
|
||||
for (int i = 0; i < tensor1->ndim; i++) {
|
||||
printf("%d", tensor1->shape[i]);
|
||||
if (i < tensor1->ndim - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]\n");
|
||||
|
||||
printf("Shapes : [");
|
||||
for (int i = 0; i < tensor2->ndim; i++) {
|
||||
printf("%d", tensor2->shape[i]);
|
||||
if (i < tensor2->ndim - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]\n");
|
||||
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
if (tensor1->shape[i] != tensor2->shape[i]) {
|
||||
fprintf(stderr, "Tensors must have the same shape %d and %d at index %d for element-wise multiplication\n", tensor1->shape[i], tensor2->shape[i], i);
|
||||
exit(1);
|
||||
}
|
||||
shape[i] = tensor1->shape[i];
|
||||
}
|
||||
|
||||
float* result_data = (float*)malloc(tensor1->size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tensor1->size; i++) {
|
||||
result_data[i] = tensor1->data[i] * tensor2->data[i];
|
||||
}
|
||||
|
||||
return create_tensor(result_data, shape, ndim);
|
||||
}
|
||||
|
||||
Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2) {
|
||||
// Check if tensors have compatible shapes for matrix multiplication
|
||||
if (tensor1->shape[1] != tensor2->shape[0]) {
|
||||
fprintf(stderr, "Incompatible shapes for matrix multiplication\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Calculate the shape of the result tensor
|
||||
int ndim = tensor1->ndim + tensor2->ndim - 2;
|
||||
int* shape = (int*)malloc(ndim * sizeof(int));
|
||||
if (shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < tensor1->ndim - 1; i++) {
|
||||
shape[i] = tensor1->shape[i];
|
||||
}
|
||||
for (int i = tensor1->ndim - 1; i < ndim; i++) {
|
||||
shape[i] = tensor2->shape[i - tensor1->ndim + 2];
|
||||
}
|
||||
|
||||
int size = 1;
|
||||
for (int i = 0; i < ndim; i++) {
|
||||
size *= shape[i];
|
||||
}
|
||||
|
||||
float* result_data = (float*)malloc(size * sizeof(float));
|
||||
if (result_data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tensor1->shape[0]; i++) {
|
||||
for (int j = 0; j < tensor2->shape[1]; j++) {
|
||||
float sum = 0.0;
|
||||
for (int k = 0; k < tensor1->shape[1]; k++) {
|
||||
sum += tensor1->data[i * tensor1->shape[1] + k] * tensor2->data[k * tensor2->shape[1] + j];
|
||||
}
|
||||
result_data[i * tensor2->shape[1] + j] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
return create_tensor(result_data, shape, ndim);
|
||||
}
|
||||
|
||||
void reshape_tensor(Tensor* tensor, int* new_shape, int new_ndim) {
|
||||
// Calculate the total number of elements in the new shape
|
||||
int new_size = 1;
|
||||
for (int i = 0; i < new_ndim; i++) {
|
||||
new_size *= new_shape[i];
|
||||
}
|
||||
|
||||
// Check if the total number of elements matches the current tensor's size
|
||||
if (new_size != tensor->size) {
|
||||
fprintf(stderr, "Cannot reshape tensor. Total number of elements in new shape does not match the current size of the tensor.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Update the shape
|
||||
tensor->shape = (int*)malloc(new_ndim * sizeof(int));
|
||||
if (tensor->shape == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < new_ndim; i++) {
|
||||
tensor->shape[i] = new_shape[i];
|
||||
}
|
||||
tensor->ndim = new_ndim;
|
||||
|
||||
// Update the strides
|
||||
tensor->strides = (int*)malloc(new_ndim * sizeof(int));
|
||||
if (tensor->strides == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int stride = 1;
|
||||
for (int i = new_ndim - 1; i >= 0; i--) {
|
||||
tensor->strides[i] = stride;
|
||||
stride *= new_shape[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ extern "C" {
|
|||
Tensor* create_tensor(float* data, int* shape, int ndim);
|
||||
Tensor* add_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
Tensor* sub_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2);
|
||||
void reshape_tensor(Tensor* tensor, int* new_shape, int new_ndim);
|
||||
}
|
||||
|
||||
#endif /* TENSOR_H */
|
||||
|
|
|
|||
BIN
csrc/tensor.o
BIN
csrc/tensor.o
Binary file not shown.
Binary file not shown.
119
norch/tensor.py
119
norch/tensor.py
|
|
@ -39,13 +39,36 @@ class Tensor:
|
|||
self.ndim = None
|
||||
|
||||
def flatten(self, nested_list):
|
||||
flat_data = []
|
||||
shape = [len(nested_list), len(nested_list[0])]
|
||||
for sublist in nested_list:
|
||||
for item in sublist:
|
||||
flat_data.append(item)
|
||||
def flatten_recursively(nested_list):
|
||||
flat_data = []
|
||||
shape = []
|
||||
if isinstance(nested_list, list):
|
||||
for sublist in nested_list:
|
||||
inner_data, inner_shape = flatten_recursively(sublist)
|
||||
flat_data.extend(inner_data)
|
||||
shape.append(len(nested_list))
|
||||
shape.extend(inner_shape)
|
||||
else:
|
||||
flat_data.append(nested_list)
|
||||
return flat_data, shape
|
||||
|
||||
flat_data, shape = flatten_recursively(nested_list)
|
||||
return flat_data, shape
|
||||
|
||||
def reshape(self, new_shape):
|
||||
|
||||
new_shape_ctype = (ctypes.c_int * len(new_shape))(*new_shape)
|
||||
new_ndim_ctype = ctypes.c_int(len(new_shape))
|
||||
|
||||
Tensor._C.reshape_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(ctypes.c_int), ctypes.c_int]
|
||||
Tensor._C.reshape_tensor.restype = None
|
||||
Tensor._C.reshape_tensor(self.tensor, new_shape_ctype, new_ndim_ctype)
|
||||
|
||||
self.shape = new_shape
|
||||
self.ndim = len(new_shape)
|
||||
|
||||
return self
|
||||
|
||||
def __getitem__(self, indices):
|
||||
if len(indices) != self.ndim:
|
||||
raise ValueError("Number of indices must match the number of dimensions")
|
||||
|
|
@ -57,14 +80,32 @@ class Tensor:
|
|||
value = Tensor._C.get_item(self.tensor, indices)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def __str__(self):
|
||||
result = ""
|
||||
for i in range(self.shape[0]):
|
||||
for j in range(self.shape[1]):
|
||||
result += str(self[i, j]) + " "
|
||||
result += "\n"
|
||||
return result.strip()
|
||||
def print_recursively(tensor, depth, index):
|
||||
if depth == tensor.ndim - 1:
|
||||
result = ""
|
||||
for i in range(tensor.shape[-1]):
|
||||
index[-1] = i
|
||||
result += str(tensor[tuple(index)]) + ", "
|
||||
return result.strip()
|
||||
else:
|
||||
result = ""
|
||||
if depth > 0:
|
||||
result += "\n" + " " * ((depth - 1) * 4)
|
||||
for i in range(tensor.shape[depth]):
|
||||
index[depth] = i
|
||||
result += "["
|
||||
result += print_recursively(tensor, depth + 1, index) + "],"
|
||||
if i < tensor.shape[depth] - 1:
|
||||
result += "\n" + " " * (depth * 4)
|
||||
return result.strip(",")
|
||||
|
||||
index = [0] * self.ndim
|
||||
result = "tensor(["
|
||||
result += print_recursively(self, 0, index)
|
||||
result += "])"
|
||||
return result
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
|
@ -87,10 +128,10 @@ class Tensor:
|
|||
|
||||
def __sub__(self, other):
|
||||
if self.shape != other.shape:
|
||||
raise ValueError("Tensors must have the same shape for addition")
|
||||
raise ValueError("Tensors must have the same shape for subtraction")
|
||||
|
||||
Tensor._C.add_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)]
|
||||
Tensor._C.add_tensor.restype = ctypes.POINTER(CTensor)
|
||||
Tensor._C.sub_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)]
|
||||
Tensor._C.sub_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.sub_tensor(self.tensor, other.tensor)
|
||||
|
||||
|
|
@ -100,18 +141,56 @@ class Tensor:
|
|||
result_data.ndim = self.ndim
|
||||
|
||||
return result_data
|
||||
|
||||
def __mul__(self, other):
|
||||
if self.shape != other.shape:
|
||||
raise ValueError("Tensors must have the same shape for element-wise multiplication")
|
||||
|
||||
Tensor._C.elementwise_mul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)]
|
||||
Tensor._C.elementwise_mul_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.elementwise_mul_tensor(self.tensor, other.tensor)
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = self.shape.copy()
|
||||
result_data.ndim = self.ndim
|
||||
|
||||
return result_data
|
||||
|
||||
def __matmul__(self, other):
|
||||
if self.ndim != 2 or other.ndim != 2:
|
||||
raise ValueError("Matrix multiplication requires 2D tensors")
|
||||
|
||||
if self.shape[1] != other.shape[0]:
|
||||
raise ValueError("Incompatible shapes for matrix multiplication")
|
||||
|
||||
Tensor._C.matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)]
|
||||
Tensor._C.matmul_tensor.restype = ctypes.POINTER(CTensor)
|
||||
|
||||
result_tensor_ptr = Tensor._C.matmul_tensor(self.tensor, other.tensor)
|
||||
|
||||
result_data = Tensor()
|
||||
result_data.tensor = result_tensor_ptr
|
||||
result_data.shape = [self.shape[0], other.shape[1]]
|
||||
result_data.ndim = 2
|
||||
|
||||
return result_data
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tensor import Tensor
|
||||
import time
|
||||
|
||||
ini = time.time()
|
||||
a = Tensor([[1, 2, 3], [1, 2, 3]])
|
||||
b = Tensor([[1, 2, 3], [1, 2, 3]])
|
||||
a = Tensor([[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]],[[13, 14, 15], [16, 17, 18], [19, 20, 21], [22, 23, 24]]])
|
||||
print(a)
|
||||
b = a.reshape([4, 3, 2])
|
||||
#b = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
||||
#a = Tensor([[[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]]])
|
||||
#b = Tensor([[[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]]])
|
||||
#c = a @ b
|
||||
|
||||
c = a + b - b
|
||||
|
||||
print(c)
|
||||
print("\n###########", b)
|
||||
|
||||
fim = time.time()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue