Merge pull request #123 from EthicalML/122_remove_spdlog
122 remove spdlog references in python
This commit is contained in:
commit
aaa89e2bbd
6 changed files with 290 additions and 286 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -185,5 +185,6 @@ release/
|
||||||
|
|
||||||
# Kompute
|
# Kompute
|
||||||
swiftshader/
|
swiftshader/
|
||||||
|
vk_swiftshader_icd.json
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Index
|
||||||
:titlesonly:
|
:titlesonly:
|
||||||
:caption: C++ Documentation:
|
:caption: C++ Documentation:
|
||||||
|
|
||||||
C++ Simple & Advanced Examples <overview/advanced-examples>
|
C++ Examples <overview/advanced-examples>
|
||||||
C++ Memory Management Principles <overview/memory-management>
|
C++ Memory Management Principles <overview/memory-management>
|
||||||
C++ Build System Deep Dive <overview/build-system>
|
C++ Build System Deep Dive <overview/build-system>
|
||||||
C++ Converting GLSL/HLSL Shaders to Cpp Headers <overview/shaders-to-headers>
|
C++ Converting GLSL/HLSL Shaders to Cpp Headers <overview/shaders-to-headers>
|
||||||
|
|
@ -26,7 +26,8 @@ Index
|
||||||
:titlesonly:
|
:titlesonly:
|
||||||
:caption: Python Documentation:
|
:caption: Python Documentation:
|
||||||
|
|
||||||
Python Package Overview & Examples <overview/python-package>
|
Python Package Overview <overview/python-package>
|
||||||
|
Python Examples <overview/python-examples>
|
||||||
Python Class Documentation & Reference <overview/python-reference>
|
Python Class Documentation & Reference <overview/python-reference>
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
:format: html
|
:format: html
|
||||||
|
|
||||||
|
|
||||||
Examples
|
C++ Examples
|
||||||
========
|
=================
|
||||||
|
|
||||||
The power of Kompute comes in when the interface is used for complex computations. This section contains an outline of the advanced / end-to-end examples available.
|
The power of Kompute comes in when the interface is used for complex computations. This section contains an outline of the advanced / end-to-end examples available.
|
||||||
|
|
||||||
|
|
|
||||||
254
docs/overview/python-examples.rst
Normal file
254
docs/overview/python-examples.rst
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
|
||||||
|
Python Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
This section contains simple and advanced examples using the Python Kompute class. For an overview of the module check `Python Package Overview <python-package.html>`_, for a deep dive into functions check the `Python Class Reference Section <python-reference.html>`_.
|
||||||
|
|
||||||
|
You will be able to run the examples below by installing the dependencies in `python/test/requirements-dev.txt`
|
||||||
|
|
||||||
|
Python Example (Simple)
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
Then you can interact with it from your interpreter. Below is the same sample as above "Your First Kompute (Simple Version)" but in Python:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
from kp import Manager, Tensor
|
||||||
|
from pyshader import python2shader, ivec3, f32, Array
|
||||||
|
|
||||||
|
mgr = Manager()
|
||||||
|
|
||||||
|
# Can be initialized with List[] or np.Array
|
||||||
|
tensor_in_a = Tensor([2, 2, 2])
|
||||||
|
tensor_in_b = Tensor([1, 2, 3])
|
||||||
|
tensor_out = Tensor([0, 0, 0])
|
||||||
|
|
||||||
|
mgr.eval_tensor_create_def([tensor_in_a, tensor_in_b, tensor_out])
|
||||||
|
|
||||||
|
# Define the function via PyShader or directly as glsl string or spirv bytes
|
||||||
|
@python2shader
|
||||||
|
def compute_shader_multiply(index=("input", "GlobalInvocationId", ivec3),
|
||||||
|
data1=("buffer", 0, Array(f32)),
|
||||||
|
data2=("buffer", 1, Array(f32)),
|
||||||
|
data3=("buffer", 2, Array(f32))):
|
||||||
|
i = index.x
|
||||||
|
data3[i] = data1[i] * data2[i]
|
||||||
|
|
||||||
|
# Run shader operation synchronously
|
||||||
|
mgr.eval_algo_data_def(
|
||||||
|
[tensor_in_a, tensor_in_b, tensor_out], compute_shader_multiply.to_spirv())
|
||||||
|
|
||||||
|
mgr.eval_await_def()
|
||||||
|
|
||||||
|
mgr.eval_tensor_sync_local_def([tensor_out])
|
||||||
|
|
||||||
|
assert tensor_out.data() == [2.0, 4.0, 6.0]
|
||||||
|
|
||||||
|
|
||||||
|
Python Example (Extended)
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
Similarly you can find the same extended example as above:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
from kp import Manager, Tensor
|
||||||
|
from pyshader import python2shader, ivec3, f32, Array
|
||||||
|
|
||||||
|
mgr = Manager(0, [2])
|
||||||
|
|
||||||
|
# Can be initialized with List[] or np.Array
|
||||||
|
tensor_in_a = Tensor([2, 2, 2])
|
||||||
|
tensor_in_b = Tensor([1, 2, 3])
|
||||||
|
tensor_out = Tensor([0, 0, 0])
|
||||||
|
|
||||||
|
mgr.eval_tensor_create_def([tensor_in_a, tensor_in_b, tensor_out])
|
||||||
|
|
||||||
|
seq = mgr.create_sequence("op")
|
||||||
|
|
||||||
|
# Define the function via PyShader or directly as glsl string or spirv bytes
|
||||||
|
@python2shader
|
||||||
|
def compute_shader_multiply(index=("input", "GlobalInvocationId", ivec3),
|
||||||
|
data1=("buffer", 0, Array(f32)),
|
||||||
|
data2=("buffer", 1, Array(f32)),
|
||||||
|
data3=("buffer", 2, Array(f32))):
|
||||||
|
i = index.x
|
||||||
|
data3[i] = data1[i] * data2[i]
|
||||||
|
|
||||||
|
# Run shader operation asynchronously and then await
|
||||||
|
mgr.eval_async_algo_data_def(
|
||||||
|
[tensor_in_a, tensor_in_b, tensor_out], compute_shader_multiply.to_spirv())
|
||||||
|
mgr.eval_await_def()
|
||||||
|
|
||||||
|
seq.begin()
|
||||||
|
seq.record_tensor_sync_local([tensor_in_a])
|
||||||
|
seq.record_tensor_sync_local([tensor_in_b])
|
||||||
|
seq.record_tensor_sync_local([tensor_out])
|
||||||
|
seq.end()
|
||||||
|
|
||||||
|
seq.eval()
|
||||||
|
|
||||||
|
assert tensor_out.data() == [2.0, 4.0, 6.0]
|
||||||
|
|
||||||
|
Kompute Operation Capabilities
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
Handling multiple capabilites of processing can be done by compute shaders being loaded into separate sequences. The example below shows how this can be done:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
from kp import Manager
|
||||||
|
|
||||||
|
# We'll assume we have the shader data available
|
||||||
|
from my_spv_shader_data import mult_shader, sum_shader
|
||||||
|
|
||||||
|
mgr = Manager()
|
||||||
|
|
||||||
|
t1 = mgr.build_tensor([2,2,2])
|
||||||
|
t2 = mgr.build_tensor([1,2,3])
|
||||||
|
t3 = mgr.build_tensor([1,2,3])
|
||||||
|
|
||||||
|
# Create multiple separate sequences
|
||||||
|
sq_mult = mgr.create_sequence("SQ_MULT")
|
||||||
|
sq_sum = mgr.create_sequence("SQ_SUM")
|
||||||
|
sq_sync = mgr.create_sequence("SQ_SYNC")
|
||||||
|
|
||||||
|
# Initialize sq_mult
|
||||||
|
sq_mult.begin()
|
||||||
|
sq_mult.record_algo_data([t1, t2, t3], add_shader)
|
||||||
|
sq_mult.end()
|
||||||
|
|
||||||
|
sq_sum.begin()
|
||||||
|
sq_sum.record_algo_data([t3, t2, t1], sum_shader)
|
||||||
|
sq_sum.end()
|
||||||
|
|
||||||
|
sq_sync.begin()
|
||||||
|
sq_sync.record_tensor_sync_local([t1, t3])
|
||||||
|
sq_sync.end()
|
||||||
|
|
||||||
|
# Run multiple iterations
|
||||||
|
for i in range(10):
|
||||||
|
sq_mult.eval()
|
||||||
|
sq_sum.eval()
|
||||||
|
|
||||||
|
sq_sync.eval()
|
||||||
|
|
||||||
|
print(t1.data(), t2.data(), t3.data())
|
||||||
|
|
||||||
|
Machine Learning Logistic Regression Implementation
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
Similar to the logistic regression implementation in the C++ examples section, below you can find the Python implementation of the Logistic Regression algorithm.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
from kp import Manager, Tensor
|
||||||
|
from pyshader import python2shader, ivec3, f32, Array
|
||||||
|
|
||||||
|
@python2shader
|
||||||
|
def compute_shader(
|
||||||
|
index = ("input", "GlobalInvocationId", ivec3),
|
||||||
|
x_i = ("buffer", 0, Array(f32)),
|
||||||
|
x_j = ("buffer", 1, Array(f32)),
|
||||||
|
y = ("buffer", 2, Array(f32)),
|
||||||
|
w_in = ("buffer", 3, Array(f32)),
|
||||||
|
w_out_i = ("buffer", 4, Array(f32)),
|
||||||
|
w_out_j = ("buffer", 5, Array(f32)),
|
||||||
|
b_in = ("buffer", 6, Array(f32)),
|
||||||
|
b_out = ("buffer", 7, Array(f32)),
|
||||||
|
l_out = ("buffer", 8, Array(f32)),
|
||||||
|
M = ("buffer", 9, Array(f32))):
|
||||||
|
|
||||||
|
i = index.x
|
||||||
|
|
||||||
|
m = M[0]
|
||||||
|
|
||||||
|
w_curr = vec2(w_in[0], w_in[1])
|
||||||
|
b_curr = b_in[0]
|
||||||
|
|
||||||
|
x_curr = vec2(x_i[i], x_j[i])
|
||||||
|
y_curr = y[i]
|
||||||
|
|
||||||
|
z_dot = w_curr @ x_curr
|
||||||
|
z = z_dot + b_curr
|
||||||
|
y_hat = 1.0 / (1.0 + exp(-z))
|
||||||
|
|
||||||
|
d_z = y_hat - y_curr
|
||||||
|
d_w = (1.0 / m) * x_curr * d_z
|
||||||
|
d_b = (1.0 / m) * d_z
|
||||||
|
|
||||||
|
loss = -((y_curr * log(y_hat)) + ((1.0 + y_curr) * log(1.0 - y_hat)))
|
||||||
|
|
||||||
|
w_out_i[i] = d_w.x
|
||||||
|
w_out_j[i] = d_w.y
|
||||||
|
b_out[i] = d_b
|
||||||
|
l_out[i] = loss
|
||||||
|
|
||||||
|
|
||||||
|
# First we create input and ouput tensors for shader
|
||||||
|
tensor_x_i = Tensor([0.0, 1.0, 1.0, 1.0, 1.0])
|
||||||
|
tensor_x_j = Tensor([0.0, 0.0, 0.0, 1.0, 1.0])
|
||||||
|
|
||||||
|
tensor_y = Tensor([0.0, 0.0, 0.0, 1.0, 1.0])
|
||||||
|
|
||||||
|
tensor_w_in = Tensor([0.001, 0.001])
|
||||||
|
tensor_w_out_i = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||||
|
tensor_w_out_j = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||||
|
|
||||||
|
tensor_b_in = Tensor([0.0])
|
||||||
|
tensor_b_out = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||||
|
|
||||||
|
tensor_l_out = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||||
|
|
||||||
|
tensor_m = Tensor([ 5.0 ])
|
||||||
|
|
||||||
|
# We store them in an array for easier interaction
|
||||||
|
params = [tensor_x_i, tensor_x_j, tensor_y, tensor_w_in, tensor_w_out_i,
|
||||||
|
tensor_w_out_j, tensor_b_in, tensor_b_out, tensor_l_out, tensor_m]
|
||||||
|
|
||||||
|
mgr = Manager()
|
||||||
|
|
||||||
|
mgr.eval_tensor_create_def(params)
|
||||||
|
|
||||||
|
# Record commands for efficient evaluation
|
||||||
|
sq = mgr.create_sequence()
|
||||||
|
sq.begin()
|
||||||
|
sq.record_tensor_sync_device([tensor_w_in, tensor_b_in])
|
||||||
|
sq.record_algo_data(params, compute_shader.to_spirv())
|
||||||
|
sq.record_tensor_sync_local([tensor_w_out_i, tensor_w_out_j, tensor_b_out, tensor_l_out])
|
||||||
|
sq.end()
|
||||||
|
|
||||||
|
ITERATIONS = 100
|
||||||
|
learning_rate = 0.1
|
||||||
|
|
||||||
|
# Perform machine learning training and inference across all input X and Y
|
||||||
|
for i_iter in range(ITERATIONS):
|
||||||
|
sq.eval()
|
||||||
|
|
||||||
|
# Calculate the parameters based on the respective derivatives calculated
|
||||||
|
w_in_i_val = tensor_w_in.data()[0]
|
||||||
|
w_in_j_val = tensor_w_in.data()[1]
|
||||||
|
b_in_val = tensor_b_in.data()[0]
|
||||||
|
|
||||||
|
for j_iter in range(tensor_b_out.size()):
|
||||||
|
w_in_i_val -= learning_rate * tensor_w_out_i.data()[j_iter]
|
||||||
|
w_in_j_val -= learning_rate * tensor_w_out_j.data()[j_iter]
|
||||||
|
b_in_val -= learning_rate * tensor_b_out.data()[j_iter]
|
||||||
|
|
||||||
|
# Update the parameters to process inference again
|
||||||
|
tensor_w_in.set_data([w_in_i_val, w_in_j_val])
|
||||||
|
tensor_b_in.set_data([b_in_val])
|
||||||
|
|
||||||
|
assert tensor_w_in.data()[0] < 0.01
|
||||||
|
assert tensor_w_in.data()[0] > 0.0
|
||||||
|
assert tensor_w_in.data()[1] > 1.5
|
||||||
|
assert tensor_b_in.data()[0] < 0.7
|
||||||
|
|
||||||
|
# Print outputs
|
||||||
|
print(tensor_w_in.data())
|
||||||
|
print(tensor_b_in.data())
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
Python Package Overview
|
Python Package Overview
|
||||||
========
|
========
|
||||||
|
|
||||||
This section provides an overview of the Python Package from a functionality perspective. If you wish to see all the classes and their respective functions you can find that in the `Python Class Reference Section <python-reference.html>`_.
|
This section provides an overview of the Python Package from a functionality perspective. If you wish to see examples check the `Python Simple & Advanced Examples section <python-examples.html>`_ all the classes and their respective functions you can find that in the `Python Class Reference Section <python-reference.html>`_.
|
||||||
|
|
||||||
Below is a diagram that provides insights on the relationship between Vulkan Kompute objects and Vulkan resources, which primarily encompass ownership of either CPU and/or GPU memory.
|
Below is a diagram that provides insights on the relationship between Vulkan Kompute objects and Vulkan resources, which primarily encompass ownership of either CPU and/or GPU memory.
|
||||||
|
|
||||||
|
|
@ -52,272 +52,40 @@ More specifically, it can be through the following functions:
|
||||||
* mgr.eval_async_<opname>_def - Runs operation asynchronously under a new anonymous sequence
|
* mgr.eval_async_<opname>_def - Runs operation asynchronously under a new anonymous sequence
|
||||||
* seq.record_<opname> - Records operation in sequence (requires sequence to be in recording mode)
|
* seq.record_<opname> - Records operation in sequence (requires sequence to be in recording mode)
|
||||||
|
|
||||||
Python Examples
|
|
||||||
^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Below we cover a broad set of examples. These use the ```pyshader``` dependency, which you can install with `pip install pyshader`.
|
|
||||||
|
|
||||||
Python Example (Simple)
|
|
||||||
^^^^^
|
|
||||||
|
|
||||||
Then you can interact with it from your interpreter. Below is the same sample as above "Your First Kompute (Simple Version)" but in Python:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
|
|
||||||
from kp import Manager, Tensor
|
|
||||||
from pyshader import python2shader, ivec3, f32, Array
|
|
||||||
|
|
||||||
mgr = Manager()
|
|
||||||
|
|
||||||
# Can be initialized with List[] or np.Array
|
|
||||||
tensor_in_a = Tensor([2, 2, 2])
|
|
||||||
tensor_in_b = Tensor([1, 2, 3])
|
|
||||||
tensor_out = Tensor([0, 0, 0])
|
|
||||||
|
|
||||||
mgr.eval_tensor_create_def([tensor_in_a, tensor_in_b, tensor_out])
|
|
||||||
|
|
||||||
# Define the function via PyShader or directly as glsl string or spirv bytes
|
|
||||||
@python2shader
|
|
||||||
def compute_shader_multiply(index=("input", "GlobalInvocationId", ivec3),
|
|
||||||
data1=("buffer", 0, Array(f32)),
|
|
||||||
data2=("buffer", 1, Array(f32)),
|
|
||||||
data3=("buffer", 2, Array(f32))):
|
|
||||||
i = index.x
|
|
||||||
data3[i] = data1[i] * data2[i]
|
|
||||||
|
|
||||||
# Run shader operation synchronously
|
|
||||||
mgr.eval_algo_data_def(
|
|
||||||
[tensor_in_a, tensor_in_b, tensor_out], compute_shader_multiply.to_spirv())
|
|
||||||
|
|
||||||
# Alternatively can pass raw string/bytes:
|
|
||||||
# shaderFileData = """ shader code here... """
|
|
||||||
# mgr.eval_algo_data_def([tensor_in_a, tensor_in_b, tensor_out], list(shaderFileData))
|
|
||||||
|
|
||||||
mgr.eval_await_def()
|
|
||||||
|
|
||||||
mgr.eval_tensor_sync_local_def([tensor_out])
|
|
||||||
|
|
||||||
assert tensor_out.data() == [2.0, 4.0, 6.0]
|
|
||||||
|
|
||||||
|
|
||||||
Python Example (Extended)
|
|
||||||
^^^^^
|
|
||||||
|
|
||||||
Similarly you can find the same extended example as above:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
|
|
||||||
from kp import Manager, Tensor
|
|
||||||
from pyshader import python2shader, ivec3, f32, Array
|
|
||||||
|
|
||||||
mgr = Manager(0, [2])
|
|
||||||
|
|
||||||
# Can be initialized with List[] or np.Array
|
|
||||||
tensor_in_a = Tensor([2, 2, 2])
|
|
||||||
tensor_in_b = Tensor([1, 2, 3])
|
|
||||||
tensor_out = Tensor([0, 0, 0])
|
|
||||||
|
|
||||||
mgr.eval_tensor_create_def([tensor_in_a, tensor_in_b, tensor_out])
|
|
||||||
|
|
||||||
seq = mgr.create_sequence("op")
|
|
||||||
|
|
||||||
# Define the function via PyShader or directly as glsl string or spirv bytes
|
|
||||||
@python2shader
|
|
||||||
def compute_shader_multiply(index=("input", "GlobalInvocationId", ivec3),
|
|
||||||
data1=("buffer", 0, Array(f32)),
|
|
||||||
data2=("buffer", 1, Array(f32)),
|
|
||||||
data3=("buffer", 2, Array(f32))):
|
|
||||||
i = index.x
|
|
||||||
data3[i] = data1[i] * data2[i]
|
|
||||||
|
|
||||||
# Run shader operation asynchronously and then await
|
|
||||||
mgr.eval_async_algo_data_def(
|
|
||||||
[tensor_in_a, tensor_in_b, tensor_out], compute_shader_multiply.to_spirv())
|
|
||||||
mgr.eval_await_def()
|
|
||||||
|
|
||||||
seq.begin()
|
|
||||||
seq.record_tensor_sync_local([tensor_in_a])
|
|
||||||
seq.record_tensor_sync_local([tensor_in_b])
|
|
||||||
seq.record_tensor_sync_local([tensor_out])
|
|
||||||
seq.end()
|
|
||||||
|
|
||||||
seq.eval()
|
|
||||||
|
|
||||||
assert tensor_out.data() == [2.0, 4.0, 6.0]
|
|
||||||
|
|
||||||
Kompute Operation Capabilities
|
|
||||||
^^^^^
|
|
||||||
|
|
||||||
Handling multiple capabilites of processing can be done by compute shaders being loaded into separate sequences. The example below shows how this can be done:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
|
|
||||||
from kp import Manager
|
|
||||||
|
|
||||||
# We'll assume we have the shader data available
|
|
||||||
from my_spv_shader_data import mult_shader, sum_shader
|
|
||||||
|
|
||||||
mgr = Manager()
|
|
||||||
|
|
||||||
t1 = mgr.build_tensor([2,2,2])
|
|
||||||
t2 = mgr.build_tensor([1,2,3])
|
|
||||||
t3 = mgr.build_tensor([1,2,3])
|
|
||||||
|
|
||||||
# Create multiple separate sequences
|
|
||||||
sq_mult = mgr.create_sequence("SQ_MULT")
|
|
||||||
sq_sum = mgr.create_sequence("SQ_SUM")
|
|
||||||
sq_sync = mgr.create_sequence("SQ_SYNC")
|
|
||||||
|
|
||||||
# Initialize sq_mult
|
|
||||||
sq_mult.begin()
|
|
||||||
sq_mult.record_algo_data([t1, t2, t3], add_shader)
|
|
||||||
sq_mult.end()
|
|
||||||
|
|
||||||
sq_sum.begin()
|
|
||||||
sq_sum.record_algo_data([t3, t2, t1], sum_shader)
|
|
||||||
sq_sum.end()
|
|
||||||
|
|
||||||
sq_sync.begin()
|
|
||||||
sq_sync.record_tensor_sync_local([t1, t3])
|
|
||||||
sq_sync.end()
|
|
||||||
|
|
||||||
# Run multiple iterations
|
|
||||||
for i in range(10):
|
|
||||||
sq_mult.eval()
|
|
||||||
sq_sum.eval()
|
|
||||||
|
|
||||||
sq_sync.eval()
|
|
||||||
|
|
||||||
print(t1.data(), t2.data(), t3.data())
|
|
||||||
|
|
||||||
Machine Learning Logistic Regression Implementation
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Similar to the logistic regression implementation in the C++ examples section, below you can find the Python implementation of the Logistic Regression algorithm.
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
|
|
||||||
from kp import Manager, Tensor
|
|
||||||
from pyshader import python2shader, ivec3, f32, Array
|
|
||||||
|
|
||||||
@python2shader
|
|
||||||
def compute_shader(
|
|
||||||
index = ("input", "GlobalInvocationId", ivec3),
|
|
||||||
x_i = ("buffer", 0, Array(f32)),
|
|
||||||
x_j = ("buffer", 1, Array(f32)),
|
|
||||||
y = ("buffer", 2, Array(f32)),
|
|
||||||
w_in = ("buffer", 3, Array(f32)),
|
|
||||||
w_out_i = ("buffer", 4, Array(f32)),
|
|
||||||
w_out_j = ("buffer", 5, Array(f32)),
|
|
||||||
b_in = ("buffer", 6, Array(f32)),
|
|
||||||
b_out = ("buffer", 7, Array(f32)),
|
|
||||||
l_out = ("buffer", 8, Array(f32)),
|
|
||||||
M = ("buffer", 9, Array(f32))):
|
|
||||||
|
|
||||||
i = index.x
|
|
||||||
|
|
||||||
m = M[0]
|
|
||||||
|
|
||||||
w_curr = vec2(w_in[0], w_in[1])
|
|
||||||
b_curr = b_in[0]
|
|
||||||
|
|
||||||
x_curr = vec2(x_i[i], x_j[i])
|
|
||||||
y_curr = y[i]
|
|
||||||
|
|
||||||
z_dot = w_curr @ x_curr
|
|
||||||
z = z_dot + b_curr
|
|
||||||
y_hat = 1.0 / (1.0 + exp(-z))
|
|
||||||
|
|
||||||
d_z = y_hat - y_curr
|
|
||||||
d_w = (1.0 / m) * x_curr * d_z
|
|
||||||
d_b = (1.0 / m) * d_z
|
|
||||||
|
|
||||||
loss = -((y_curr * log(y_hat)) + ((1.0 + y_curr) * log(1.0 - y_hat)))
|
|
||||||
|
|
||||||
w_out_i[i] = d_w.x
|
|
||||||
w_out_j[i] = d_w.y
|
|
||||||
b_out[i] = d_b
|
|
||||||
l_out[i] = loss
|
|
||||||
|
|
||||||
|
|
||||||
# First we create input and ouput tensors for shader
|
|
||||||
tensor_x_i = Tensor([0.0, 1.0, 1.0, 1.0, 1.0])
|
|
||||||
tensor_x_j = Tensor([0.0, 0.0, 0.0, 1.0, 1.0])
|
|
||||||
|
|
||||||
tensor_y = Tensor([0.0, 0.0, 0.0, 1.0, 1.0])
|
|
||||||
|
|
||||||
tensor_w_in = Tensor([0.001, 0.001])
|
|
||||||
tensor_w_out_i = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
|
||||||
tensor_w_out_j = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
|
||||||
|
|
||||||
tensor_b_in = Tensor([0.0])
|
|
||||||
tensor_b_out = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
|
||||||
|
|
||||||
tensor_l_out = Tensor([0.0, 0.0, 0.0, 0.0, 0.0])
|
|
||||||
|
|
||||||
tensor_m = Tensor([ 5.0 ])
|
|
||||||
|
|
||||||
# We store them in an array for easier interaction
|
|
||||||
params = [tensor_x_i, tensor_x_j, tensor_y, tensor_w_in, tensor_w_out_i,
|
|
||||||
tensor_w_out_j, tensor_b_in, tensor_b_out, tensor_l_out, tensor_m]
|
|
||||||
|
|
||||||
mgr = Manager()
|
|
||||||
|
|
||||||
mgr.eval_tensor_create_def(params)
|
|
||||||
|
|
||||||
# Record commands for efficient evaluation
|
|
||||||
sq = mgr.create_sequence()
|
|
||||||
sq.begin()
|
|
||||||
sq.record_tensor_sync_device([tensor_w_in, tensor_b_in])
|
|
||||||
sq.record_algo_data(params, compute_shader.to_spirv())
|
|
||||||
sq.record_tensor_sync_local([tensor_w_out_i, tensor_w_out_j, tensor_b_out, tensor_l_out])
|
|
||||||
sq.end()
|
|
||||||
|
|
||||||
ITERATIONS = 100
|
|
||||||
learning_rate = 0.1
|
|
||||||
|
|
||||||
# Perform machine learning training and inference across all input X and Y
|
|
||||||
for i_iter in range(ITERATIONS):
|
|
||||||
sq.eval()
|
|
||||||
|
|
||||||
# Calculate the parameters based on the respective derivatives calculated
|
|
||||||
w_in_i_val = tensor_w_in.data()[0]
|
|
||||||
w_in_j_val = tensor_w_in.data()[1]
|
|
||||||
b_in_val = tensor_b_in.data()[0]
|
|
||||||
|
|
||||||
for j_iter in range(tensor_b_out.size()):
|
|
||||||
w_in_i_val -= learning_rate * tensor_w_out_i.data()[j_iter]
|
|
||||||
w_in_j_val -= learning_rate * tensor_w_out_j.data()[j_iter]
|
|
||||||
b_in_val -= learning_rate * tensor_b_out.data()[j_iter]
|
|
||||||
|
|
||||||
# Update the parameters to process inference again
|
|
||||||
tensor_w_in.set_data([w_in_i_val, w_in_j_val])
|
|
||||||
tensor_b_in.set_data([b_in_val])
|
|
||||||
|
|
||||||
assert tensor_w_in.data()[0] < 0.01
|
|
||||||
assert tensor_w_in.data()[0] > 0.0
|
|
||||||
assert tensor_w_in.data()[1] > 1.5
|
|
||||||
assert tensor_b_in.data()[0] < 0.7
|
|
||||||
|
|
||||||
# Print outputs
|
|
||||||
print(tensor_w_in.data())
|
|
||||||
print(tensor_b_in.data())
|
|
||||||
|
|
||||||
|
|
||||||
Log Level Configuration
|
Log Level Configuration
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
You can configure log level with the function `kp.log_level` as outlined below.
|
Logging inside the C++ uses the PyBind logging, which allows for all the std::cout to be passed to a python logger.
|
||||||
|
|
||||||
|
All python output is logged to the logger with the name `kp`. You can interact with the logger similar to any python logging as per the example below:
|
||||||
|
|
||||||
The values are TRACE=0, DEBUG=1, INFO=2, WARN=3, ERROR=4. Kompute defaults to INFO.
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
import kp
|
>>> import kp
|
||||||
kp.log_level(1)
|
>>> import logging
|
||||||
|
>>>
|
||||||
|
>>> kp_logger = logging.getLogger("kp")
|
||||||
|
>>> kp_logger.setLevel(logging.INFO)
|
||||||
|
>>>
|
||||||
|
>>> kp.Manager()
|
||||||
|
INFO:kp:Using physical device index {} found {}
|
||||||
|
<kp.Manager object at 0x7f2ac075ca30>
|
||||||
|
|
||||||
|
>>> kp_logger.setLevel(logging.DEBUG)
|
||||||
|
>>>
|
||||||
|
>>> kp.Manager()
|
||||||
|
DEBUG:kp:Kompute Manager creating instance
|
||||||
|
DEBUG:kp:Kompute Manager Instance Created
|
||||||
|
DEBUG:kp:Kompute Manager creating Device
|
||||||
|
INFO:kp:Using physical device index {} found {}
|
||||||
|
DEBUG:kp:Kompute Manager device created
|
||||||
|
DEBUG:kp:Kompute Manager compute queue obtained
|
||||||
|
DEBUG:kp:Kompute Manager Destructor started
|
||||||
|
INFO:kp:Destroying device
|
||||||
|
DEBUG:kp:Kompute Manager Destroyed Device
|
||||||
|
DEBUG:kp:Kompute Manager Destroyed Instance
|
||||||
|
<kp.Manager object at 0x7f2af6109e30>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ namespace py = pybind11;
|
||||||
py::object kp_debug, kp_info, kp_warning, kp_error;
|
py::object kp_debug, kp_info, kp_warning, kp_error;
|
||||||
|
|
||||||
PYBIND11_MODULE(kp, m) {
|
PYBIND11_MODULE(kp, m) {
|
||||||
|
|
||||||
|
// The logging modules are used in the Kompute.hpp file
|
||||||
py::module_ logging = py::module_::import("logging");
|
py::module_ logging = py::module_::import("logging");
|
||||||
py::object kp_logger = logging.attr("getLogger")("kp");
|
py::object kp_logger = logging.attr("getLogger")("kp");
|
||||||
kp_debug = kp_logger.attr("debug");
|
kp_debug = kp_logger.attr("debug");
|
||||||
|
|
@ -21,19 +23,6 @@ PYBIND11_MODULE(kp, m) {
|
||||||
|
|
||||||
py::module_ np = py::module_::import("numpy");
|
py::module_ np = py::module_::import("numpy");
|
||||||
|
|
||||||
#if KOMPUTE_ENABLE_SPDLOG
|
|
||||||
spdlog::set_level(
|
|
||||||
static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m.def("log_level", [](uint8_t logLevel) {
|
|
||||||
#if KOMPUTE_ENABLE_SPDLOG
|
|
||||||
spdlog::set_level(
|
|
||||||
static_cast<spdlog::level::level_enum>(logLevel));
|
|
||||||
#else
|
|
||||||
SPDLOG_WARN("SPDLOG not enabled so log level config function not supported");
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
|
|
||||||
py::enum_<kp::Tensor::TensorTypes>(m, "TensorTypes", DOC(kp, Tensor, TensorTypes))
|
py::enum_<kp::Tensor::TensorTypes>(m, "TensorTypes", DOC(kp, Tensor, TensorTypes))
|
||||||
.value("device", kp::Tensor::TensorTypes::eDevice, "Tensor holding data in GPU memory.")
|
.value("device", kp::Tensor::TensorTypes::eDevice, "Tensor holding data in GPU memory.")
|
||||||
|
|
@ -42,9 +31,6 @@ PYBIND11_MODULE(kp, m) {
|
||||||
.export_values();
|
.export_values();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
py::class_<kp::Tensor, std::shared_ptr<kp::Tensor>>(m, "Tensor", DOC(kp, Tensor))
|
py::class_<kp::Tensor, std::shared_ptr<kp::Tensor>>(m, "Tensor", DOC(kp, Tensor))
|
||||||
.def(py::init(
|
.def(py::init(
|
||||||
[np](const py::array_t<float> data, kp::Tensor::TensorTypes tensor_type) {
|
[np](const py::array_t<float> data, kp::Tensor::TensorTypes tensor_type) {
|
||||||
|
|
@ -101,9 +87,6 @@ PYBIND11_MODULE(kp, m) {
|
||||||
.def("map_data_into_host", &kp::Tensor::mapDataIntoHostMemory, "Maps data from GPU memory into tensor local data.");
|
.def("map_data_into_host", &kp::Tensor::mapDataIntoHostMemory, "Maps data from GPU memory into tensor local data.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
py::class_<kp::Sequence, std::shared_ptr<kp::Sequence>>(m, "Sequence")
|
py::class_<kp::Sequence, std::shared_ptr<kp::Sequence>>(m, "Sequence")
|
||||||
.def("init", &kp::Sequence::init, "Initialises Vulkan resources within sequence using provided device.")
|
.def("init", &kp::Sequence::init, "Initialises Vulkan resources within sequence using provided device.")
|
||||||
|
|
||||||
|
|
@ -164,9 +147,6 @@ PYBIND11_MODULE(kp, m) {
|
||||||
"Records operation to run left right out operation with custom shader");
|
"Records operation to run left right out operation with custom shader");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
py::class_<kp::Manager>(m, "Manager")
|
py::class_<kp::Manager>(m, "Manager")
|
||||||
.def(py::init(), "Default initializer uses device 0 and first compute compatible GPU queueFamily")
|
.def(py::init(), "Default initializer uses device 0 and first compute compatible GPU queueFamily")
|
||||||
.def(py::init(
|
.def(py::init(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue