krnl 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- krnl/backends/GPU_processer.py +147 -0
- krnl/backends/device.py +40 -0
- krnl/backends/kernels.py +37 -0
- krnl/backends/tensor.py +608 -0
- krnl/nn/__init__.py +20 -0
- krnl/nn/loss.py +47 -0
- krnl/nn/model_utils.py +93 -0
- krnl/nn/optim.py +568 -0
- krnl-0.1.0.dist-info/METADATA +314 -0
- krnl-0.1.0.dist-info/RECORD +13 -0
- krnl-0.1.0.dist-info/WHEEL +5 -0
- krnl-0.1.0.dist-info/licenses/LICENSE +21 -0
- krnl-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pyopencl as cl
|
|
3
|
+
import pyopencl.array as cl_array
|
|
4
|
+
from pyopencl import Program
|
|
5
|
+
from backends.backends.kernels import MATMUL_KERNEL, SIGMOID_KERNEL
|
|
6
|
+
|
|
7
|
+
def get_gpu_info():
|
|
8
|
+
platforms = cl.get_platforms()
|
|
9
|
+
gpu_info = []
|
|
10
|
+
|
|
11
|
+
for platform in platforms:
|
|
12
|
+
devices = platform.get_devices(device_type=cl.device_type.GPU)
|
|
13
|
+
for device in devices:
|
|
14
|
+
info = {
|
|
15
|
+
"platform": platform.name,
|
|
16
|
+
"device": device.name,
|
|
17
|
+
"max_compute_units": device.max_compute_units,
|
|
18
|
+
"max_work_group_size": device.max_work_group_size,
|
|
19
|
+
"global_mem_size": device.global_mem_size,
|
|
20
|
+
"local_mem_size": device.local_mem_size,
|
|
21
|
+
"max_clock_frequency": device.max_clock_frequency,
|
|
22
|
+
}
|
|
23
|
+
gpu_info.append(info)
|
|
24
|
+
|
|
25
|
+
return gpu_info
|
|
26
|
+
|
|
27
|
+
class OpenCLBackend:
|
|
28
|
+
_instance = None
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def instance(cls):
|
|
32
|
+
if cls._instance is None:
|
|
33
|
+
cls._instance = cls()
|
|
34
|
+
return cls._instance
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.context = cl.create_some_context()
|
|
38
|
+
self.queue = cl.CommandQueue(self.context)
|
|
39
|
+
self.matmul_program = Program(self.context, MATMUL_KERNEL).build()
|
|
40
|
+
self.sigmoid_program = Program(self.context, SIGMOID_KERNEL).build()
|
|
41
|
+
|
|
42
|
+
def upload(self, data):
|
|
43
|
+
data = np.ascontiguousarray(data)
|
|
44
|
+
return cl_array.to_device(self.queue, data)
|
|
45
|
+
|
|
46
|
+
def __add__(self, a: cl_array.Array, b: cl_array.Array):
|
|
47
|
+
if a.shape != b.shape:
|
|
48
|
+
raise ValueError("Tensor shapes must match")
|
|
49
|
+
if a.dtype != b.dtype:
|
|
50
|
+
raise TypeError("Tensor dtypes must match")
|
|
51
|
+
if a.dtype != np.dtype(np.float32):
|
|
52
|
+
raise TypeError("Initial OpenCL backend supports float32 only")
|
|
53
|
+
|
|
54
|
+
result = a + b
|
|
55
|
+
|
|
56
|
+
return result
|
|
57
|
+
|
|
58
|
+
def __mul__(self, a: cl_array.Array, b: cl_array.Array):
|
|
59
|
+
if a.shape != b.shape:
|
|
60
|
+
raise ValueError("Tensor shapes must match")
|
|
61
|
+
if a.dtype != b.dtype:
|
|
62
|
+
raise TypeError("Tensor dtypes must match")
|
|
63
|
+
if a.dtype != np.dtype(np.float32):
|
|
64
|
+
raise TypeError("Initial OpenCL backend supports float32 only")
|
|
65
|
+
|
|
66
|
+
result = a * b
|
|
67
|
+
|
|
68
|
+
return result
|
|
69
|
+
|
|
70
|
+
def __sub__(self, a: cl_array.Array, b: cl_array.Array):
|
|
71
|
+
if a.shape != b.shape:
|
|
72
|
+
raise ValueError("Tensor shapes must match")
|
|
73
|
+
if a.dtype != b.dtype:
|
|
74
|
+
raise TypeError("Tensor dtypes must match")
|
|
75
|
+
if a.dtype != np.dtype(np.float32):
|
|
76
|
+
raise TypeError("Initial OpenCL backend supports float32 only")
|
|
77
|
+
|
|
78
|
+
result = a - b
|
|
79
|
+
|
|
80
|
+
return result
|
|
81
|
+
|
|
82
|
+
def __matmul__(self, a: cl_array.Array, b: cl_array.Array):
|
|
83
|
+
if len(a.shape) != 2 or len(b.shape) != 2:
|
|
84
|
+
raise ValueError("matmul requires two 2D tensors")
|
|
85
|
+
|
|
86
|
+
M, K = a.shape
|
|
87
|
+
K2, N = b.shape
|
|
88
|
+
|
|
89
|
+
if K != K2:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Incompatible shapes for matmul: {a.shape} and {b.shape}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if a.dtype != np.dtype(np.float32) or b.dtype != np.dtype(np.float32):
|
|
95
|
+
raise TypeError("matmul supports float32 only")
|
|
96
|
+
|
|
97
|
+
out = cl_array.empty(
|
|
98
|
+
self.queue,
|
|
99
|
+
(M, N),
|
|
100
|
+
dtype=np.float32
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
self.matmul_program.matmul_f32(
|
|
104
|
+
self.queue,
|
|
105
|
+
(M, N),
|
|
106
|
+
None,
|
|
107
|
+
a.data,
|
|
108
|
+
b.data,
|
|
109
|
+
out.data,
|
|
110
|
+
np.int32(M),
|
|
111
|
+
np.int32(K),
|
|
112
|
+
np.int32(N)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def sigmoid(self, input_array: cl_array.Array):
|
|
116
|
+
"""
|
|
117
|
+
Apply sigmoid element-wise to a GPU float32 array.
|
|
118
|
+
|
|
119
|
+
sigmoid(x) = 1 / (1 + exp(-x))
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
if not isinstance(input_array, cl_array.Array):
|
|
123
|
+
raise TypeError(
|
|
124
|
+
"sigmoid expects a pyopencl.array.Array"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if input_array.dtype != np.dtype(np.float32):
|
|
128
|
+
raise TypeError(
|
|
129
|
+
"sigmoid supports float32 arrays only"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
output = cl_array.empty_like(input_array)
|
|
133
|
+
|
|
134
|
+
count = np.uint32(input_array.size)
|
|
135
|
+
|
|
136
|
+
self.sigmoid_program.sigmoid_f32(
|
|
137
|
+
self.queue,
|
|
138
|
+
(input_array.size,),
|
|
139
|
+
None,
|
|
140
|
+
input_array.data,
|
|
141
|
+
output.data,
|
|
142
|
+
count,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
return output
|
|
146
|
+
|
|
147
|
+
|
krnl/backends/device.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import psutil
|
|
3
|
+
from typing import Literal
|
|
4
|
+
from backends.backends.GPU_processer import get_gpu_info
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
cpu_freq = psutil.cpu_freq()
|
|
8
|
+
max_clock = cpu_freq.max if cpu_freq else 0
|
|
9
|
+
virtual_mem = psutil.virtual_memory()
|
|
10
|
+
|
|
11
|
+
info = {
|
|
12
|
+
"platform": platform.system(), # e.g., 'Windows', 'Linux', 'Darwin'
|
|
13
|
+
"device": platform.processor(), # e.g., 'Intel64 Family 6 Model...'
|
|
14
|
+
"max_compute_units": psutil.cpu_count(logical=False), # Physical CPU cores
|
|
15
|
+
"max_work_group_size": psutil.cpu_count(logical=True),# Total logical threads
|
|
16
|
+
"global_mem_size": virtual_mem.total, # Total system RAM (bytes)
|
|
17
|
+
"local_mem_size": None, # Placeholder (psutil cannot read CPU L1/L2 cache sizes directly)
|
|
18
|
+
"max_clock_frequency": max_clock # Max clock speed in MHz
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Device(object):
|
|
23
|
+
def __init__(self, device: Literal["CPU", "GPU"], device_id: int = 0):
|
|
24
|
+
self.device = device
|
|
25
|
+
self.device_id = device_id
|
|
26
|
+
|
|
27
|
+
def __repr__(self):
|
|
28
|
+
return f"Device(device={self.device}, device_id={self.device_id})"
|
|
29
|
+
|
|
30
|
+
def get_device_info(self):
|
|
31
|
+
if self.device == "CPU":
|
|
32
|
+
return info
|
|
33
|
+
elif self.device == "GPU":
|
|
34
|
+
gpu_info = get_gpu_info()
|
|
35
|
+
if self.device_id < len(gpu_info):
|
|
36
|
+
return gpu_info[self.device_id]
|
|
37
|
+
else:
|
|
38
|
+
raise ValueError(f"Invalid GPU device_id: {self.device_id}")
|
|
39
|
+
else:
|
|
40
|
+
raise ValueError(f"Invalid device type: {self.device}")
|
krnl/backends/kernels.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
MATMUL_KERNEL = """
|
|
2
|
+
__kernel void matmul_f32(
|
|
3
|
+
__global const float *a,
|
|
4
|
+
__global const float *b,
|
|
5
|
+
__global float *c,
|
|
6
|
+
const int M,
|
|
7
|
+
const int K,
|
|
8
|
+
const int N
|
|
9
|
+
)
|
|
10
|
+
{
|
|
11
|
+
int row = get_global_id(0);
|
|
12
|
+
int col = get_global_id(1);
|
|
13
|
+
|
|
14
|
+
if (row < M && col < N) {
|
|
15
|
+
float sum = 0.0f;
|
|
16
|
+
|
|
17
|
+
for (int k = 0; k < K; k++) {
|
|
18
|
+
sum += a[row * K + k] * b[k * N + col];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
c[row * N + col] = sum;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
SIGMOID_KERNEL = """
|
|
27
|
+
__kernel void sigmoid_activation(__global const float* input,
|
|
28
|
+
__global float* output,
|
|
29
|
+
const unsigned int count)
|
|
30
|
+
{
|
|
31
|
+
int id = get_global_id(0);
|
|
32
|
+
|
|
33
|
+
if (id < count) {
|
|
34
|
+
output[id] = 1.0f / (1.0f + exp(-input[id]));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
"""
|