Merge pull request #287 from COM8/master

Refactor build system
This commit is contained in:
Alejandro Saucedo 2022-11-14 20:08:36 +00:00 committed by GitHub
commit 1344ece4ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
113 changed files with 3004 additions and 5933 deletions

View file

@ -12,9 +12,9 @@ This is the accompanying code for the Blog post ["Supercharging your Mobile Apps
<p>
This example provides an end to end example that can be run using android studio.
The example uses the Kompute build in the relative folder to build the respective binaries for android.
The example uses the Kompute built-in the relative folder to build the respective binaries for android.
The build structure provides a range of options to build in different Android hardware. This example was tested in various emulators including Pixel 2, and a physical Samsung S7 phone.
The build structure provides a range of options to built-in different Android hardware. This example was tested in various emulators including Pixel 2, and a physical Samsung S7 phone.
</p>
<br>

View file

@ -3,29 +3,25 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
ndkVersion '21.2.6472646'
compileSdkVersion 33
ndkVersion '25.1.8937393'
defaultConfig {
applicationId "com.ethicalml.kompute"
minSdkVersion 23
targetSdkVersion 29
minSdkVersion 26
targetSdkVersion 33
versionCode = 1
versionName = "0.0.1"
externalNativeBuild {
cmake {
abiFilters "armeabi-v7a", 'arm64-v8a', 'x86', 'x86_64'
arguments '-DANDROID_TOOLCHAIN=clang',
'-DANDROID_STL=c++_static',
'-DKOMPUTE_OPT_ANDROID_BUILD=1',
'-DKOMPUTE_OPT_REPO_SUBMODULE_BUILD=1',
'-DKOMPUTE_OPT_INSTALL=0',
'-DKOMPUTE_OPT_ENABLE_SPDLOG=0',
'-DKOMPUTE_OPT_BUILD_SINGLE_HEADER=0',
'-DKOMPUTE_OPT_DISABLE_VK_DEBUG_LAYERS=1',
'-DKOMPUTE_EXTRA_CXX_FLAGS=-DKOMPUTE_VK_API_MINOR_VERSION=0'
'-DANDROID_STL=c++_static'
}
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
buildFeatures {
@ -41,6 +37,7 @@ android {
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
version '3.22.2'
}
}
@ -64,6 +61,7 @@ android {
// armeabi-v7a, arm64-v8a, x86, x86_64
}
}
namespace 'com.ethicalml.kompute'
}
dependencies {

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ethicalml.kompute">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
@ -9,7 +8,8 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".KomputeJni">
<activity android:name=".KomputeJni"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View file

@ -1,27 +1,22 @@
cmake_minimum_required(VERSION 3.4.1)
cmake_minimum_required(VERSION 3.20)
add_subdirectory(../../../../../../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build)
set(CMAKE_CXX_STANDARD 17)
set(VK_ANDROID_INCLUDE_DIR ${ANDROID_NDK}/sources/third_party/vulkan/src/include)
include(FetchContent)
FetchContent_Declare(kompute GIT_REPOSITORY https://github.com/COM8/kompute.git
GIT_TAG 675f6dc771cea044ead99a5467a9b817c2d8feb6) # The commit hash for a dev version before v0.9.0. Replace with the latest from: https://github.com/KomputeProject/kompute/releases
set(KOMPUTE_OPT_ANDROID_BUILD ON)
set(KOMPUTE_OPT_DISABLE_VK_DEBUG_LAYERS ON)
FetchContent_MakeAvailable(kompute)
include_directories(${kompute_SOURCE_DIR}/src/include)
add_library(kompute-jni SHARED
KomputeJniNative.cpp
KomputeModelML.cpp)
# Add to the list, so CMake can later find the code to compile shaders to header files
list(APPEND CMAKE_PREFIX_PATH "${kompute_SOURCE_DIR}/cmake")
add_subdirectory(shader)
include_directories(
${VK_ANDROID_COMMON_DIR}
${VK_ANDROID_INCLUDE_DIR}
../../../../../../../single_include/
../../../../../../../vk_ndk_wrapper_include/)
add_library(kompute-jni SHARED KomputeJniNative.cpp
KomputeModelML.cpp
KomputeModelML.hpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 \
-DVK_USE_PLATFORM_ANDROID_KHR=1 \
-DKOMPUTE_DISABLE_VK_DEBUG_LAYERS=1")
target_link_libraries(kompute-jni PRIVATE kompute::kompute shader log android)
target_link_libraries(kompute-jni
# Libraries from kompute build
kompute
kompute_vk_ndk_wrapper
# Libraries from android build
log
android)

View file

@ -24,10 +24,7 @@
// Allows us to use the C++ sleep function to wait when loading the
// Vulkan library in android
#include <unistd.h>
#ifndef KOMPUTE_VK_INIT_RETRIES
#define KOMPUTE_VK_INIT_RETRIES 5
#endif
#include <kompute/logger/Logger.hpp>
static std::vector<float>
jfloatArrayToVector(JNIEnv* env, const jfloatArray& fromArray)
@ -53,27 +50,6 @@ vectorToJFloatArray(JNIEnv* env, const std::vector<float>& fromVector)
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_com_ethicalml_kompute_KomputeJni_initVulkan(JNIEnv* env, jobject thiz)
{
KP_LOG_INFO("Initialising vulkan");
uint32_t totalRetries = 0;
while (totalRetries < KOMPUTE_VK_INIT_RETRIES) {
KP_LOG_INFO("VULKAN LOAD TRY NUMBER: %u", totalRetries);
if (InitVulkan()) {
break;
}
sleep(1);
totalRetries++;
}
return totalRetries < KOMPUTE_VK_INIT_RETRIES;
}
JNIEXPORT jfloatArray JNICALL
Java_com_ethicalml_kompute_KomputeJni_kompute(JNIEnv* env,
jobject thiz,

View file

@ -1,5 +1,8 @@
#include "KomputeModelML.hpp"
#include "my_shader.hpp"
#include <kompute/Kompute.hpp>
KomputeModelML::KomputeModelML() {}
@ -10,7 +13,6 @@ KomputeModelML::train(std::vector<float> yData,
std::vector<float> xIData,
std::vector<float> xJData)
{
std::vector<float> zerosData;
for (size_t i = 0; i < yData.size(); i++) {
@ -41,15 +43,11 @@ KomputeModelML::train(std::vector<float> yData,
wIn, wOutI, wOutJ,
bIn, bOut, lOut };
std::vector<uint32_t> spirv = std::vector<uint32_t>(
(uint32_t*)kp::shader_data::shaders_glsl_logisticregression_comp_spv,
(uint32_t*)(kp::shader_data::
shaders_glsl_logisticregression_comp_spv +
kp::shader_data::
shaders_glsl_logisticregression_comp_spv_len));
const std::vector<uint32_t> shader = std::vector<uint32_t>(
shader::MY_SHADER_COMP_SPV.begin(), shader::MY_SHADER_COMP_SPV.end());
std::shared_ptr<kp::Algorithm> algorithm = mgr.algorithm(
params, spirv, kp::Workgroup({ 5 }), std::vector<float>({ 5.0 }));
params, shader, kp::Workgroup({ 5 }), std::vector<float>({ 5.0 }));
mgr.sequence()->eval<kp::OpTensorSyncDevice>(params);
@ -84,7 +82,6 @@ KomputeModelML::train(std::vector<float> yData,
std::vector<float>
KomputeModelML::predict(std::vector<float> xI, std::vector<float> xJ)
{
KP_LOG_INFO("Running prediction inference");
assert(xI.size() == xJ.size());
@ -113,7 +110,6 @@ KomputeModelML::predict(std::vector<float> xI, std::vector<float> xJ)
std::vector<float>
KomputeModelML::get_params()
{
KP_LOG_INFO("Displaying results");
std::vector<float> retVector;

View file

@ -1,13 +1,8 @@
#ifndef KOMPUTEMODELML_HPP
#define KOMPUTEMODELML_HPP
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "kompute/Kompute.hpp"
class KomputeModelML
{
@ -27,62 +22,3 @@ class KomputeModelML
std::vector<float> mWeights;
std::vector<float> mBias;
};
static std::string LR_SHADER = R"(
#version 450
layout (constant_id = 0) const uint M = 0;
layout (local_size_x = 1) in;
layout(set = 0, binding = 0) buffer bxi { float xi[]; };
layout(set = 0, binding = 1) buffer bxj { float xj[]; };
layout(set = 0, binding = 2) buffer by { float y[]; };
layout(set = 0, binding = 3) buffer bwin { float win[]; };
layout(set = 0, binding = 4) buffer bwouti { float wouti[]; };
layout(set = 0, binding = 5) buffer bwoutj { float woutj[]; };
layout(set = 0, binding = 6) buffer bbin { float bin[]; };
layout(set = 0, binding = 7) buffer bbout { float bout[]; };
layout(set = 0, binding = 8) buffer blout { float lout[]; };
float m = float(M);
float sigmoid(float z) {
return 1.0 / (1.0 + exp(-z));
}
float inference(vec2 x, vec2 w, float b) {
// Compute the linear mapping function
float z = dot(w, x) + b;
// Calculate the y-hat with sigmoid
float yHat = sigmoid(z);
return yHat;
}
float calculateLoss(float yHat, float y) {
return -(y * log(yHat) + (1.0 - y) * log(1.0 - yHat));
}
void main() {
uint idx = gl_GlobalInvocationID.x;
vec2 wCurr = vec2(win[0], win[1]);
float bCurr = bin[0];
vec2 xCurr = vec2(xi[idx], xj[idx]);
float yCurr = y[idx];
float yHat = inference(xCurr, wCurr, bCurr);
float dZ = yHat - yCurr;
vec2 dW = (1. / m) * xCurr * dZ;
float dB = (1. / m) * dZ;
wouti[idx] = dW.x;
woutj[idx] = dW.y;
bout[idx] = dB;
lout[idx] = calculateLoss(yHat, yCurr);
}
)";
#endif // ANDROID_SIMPLE_KOMPUTEMODELML_HPP

View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.20)
# To add more shaders simply copy the vulkan_compile_shader command and replace it with your new shader
vulkan_compile_shader(INFILE my_shader.comp
OUTFILE my_shader.hpp
NAMESPACE "shader"
RELATIVE_PATH "${kompute_SOURCE_DIR}/cmake")
# Then add it to the library, so you can access it later in your code
add_library(shader INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/my_shader.hpp"
# "${CMAKE_CURRENT_BINARY_DIR}/my_shader2.hpp"
)
target_include_directories(shader INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

View file

@ -0,0 +1,54 @@
#version 450
layout (constant_id = 0) const uint M = 0;
layout (local_size_x = 1) in;
layout(set = 0, binding = 0) buffer bxi { float xi[]; };
layout(set = 0, binding = 1) buffer bxj { float xj[]; };
layout(set = 0, binding = 2) buffer by { float y[]; };
layout(set = 0, binding = 3) buffer bwin { float win[]; };
layout(set = 0, binding = 4) buffer bwouti { float wouti[]; };
layout(set = 0, binding = 5) buffer bwoutj { float woutj[]; };
layout(set = 0, binding = 6) buffer bbin { float bin[]; };
layout(set = 0, binding = 7) buffer bbout { float bout[]; };
layout(set = 0, binding = 8) buffer blout { float lout[]; };
float m = float(M);
float sigmoid(float z) {
return 1.0 / (1.0 + exp(-z));
}
float inference(vec2 x, vec2 w, float b) {
// Compute the linear mapping function
float z = dot(w, x) + b;
// Calculate the y-hat with sigmoid
float yHat = sigmoid(z);
return yHat;
}
float calculateLoss(float yHat, float y) {
return -(y * log(yHat) + (1.0 - y) * log(1.0 - yHat));
}
void main() {
uint idx = gl_GlobalInvocationID.x;
vec2 wCurr = vec2(win[0], win[1]);
float bCurr = bin[0];
vec2 xCurr = vec2(xi[idx], xj[idx]);
float yCurr = y[idx];
float yHat = inference(xCurr, wCurr, bCurr);
float dZ = yHat - yCurr;
vec2 dW = (1. / m) * xCurr * dZ;
float dB = (1. / m) * dZ;
wouti[idx] = dW.x;
woutj[idx] = dW.y;
bout[idx] = dB;
lout[idx] = calculateLoss(yHat, yCurr);
}

View file

@ -22,16 +22,7 @@ class KomputeJni : AppCompatActivity() {
binding.komputeGifView.getSettings().setUseWideViewPort(true)
binding.komputeGifView.getSettings().setLoadWithOverviewMode(true)
val successVulkanInit = initVulkan()
if (successVulkanInit) {
Toast.makeText(applicationContext, "Vulkan Loaded SUCCESS", Toast.LENGTH_SHORT).show()
} else {
binding.KomputeButton.isEnabled = false
Toast.makeText(applicationContext, "Vulkan Load FAILED", Toast.LENGTH_SHORT).show()
}
Log.i("KomputeJni", "Vulkan Result: " + successVulkanInit)
binding.predictionTextView.text = "N/A"
}

View file

@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.72'
ext.kotlin_version = '1.6.20'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

View file

@ -1,40 +1,37 @@
cmake_minimum_required(VERSION 3.4.1)
project(kompute_array_mult VERSION 0.1.0)
cmake_minimum_required(VERSION 3.20)
project(kompute_array_mult)
set(CMAKE_CXX_STANDARD 14)
option(KOMPUTE_ARR_OPT_INSTALLED_KOMPUTE "Enable if you prefer to use your installed Kompute library" 0)
option(KOMPUTE_OPT_ENABLE_SPDLOG "Extra compile flags for Kompute, see docs for full list" 0)
set(KOMPUTE_EXTRA_CXX_FLAGS "" CACHE STRING "Extra compile flags for Kompute, see docs for full list")
# Set a default build type if none was specified
# Based on: https://github.com/openchemistry/tomviz/blob/master/cmake/BuildType.cmake
set(DEFAULT_BUILD_TYPE "Release")
if(KOMPUTE_OPT_ENABLE_SPDLOG)
set(KOMPUTE_EXTRA_CXX_FLAGS "${KOMPUTE_EXTRA_CXX_FLAGS} -DKOMPUTE_ENABLE_SPDLOG=1")
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(DEFAULT_BUILD_TYPE "Debug")
endif()
# It is necessary to pass the DEBUG or RELEASE flag accordingly to Kompute
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 ${KOMPUTE_EXTRA_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE=1 ${KOMPUTE_EXTRA_CXX_FLAGS}")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
if(KOMPUTE_ARR_OPT_INSTALLED_KOMPUTE)
find_package(kompute REQUIRED)
else()
add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
find_package(Vulkan REQUIRED)
add_executable(kompute_array_mult
src/Main.cpp)
target_link_libraries(kompute_array_mult
kompute::kompute
Vulkan::Vulkan)
include_directories(
../../single_include/)
if(KOMPUTE_OPT_ENABLE_SPDLOG)
target_link_libraries(kompute_array_mult
spdlog::spdlog)
if(WIN32) # Install dlls in the same directory as the executable on Windows
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
include(FetchContent)
FetchContent_Declare(kompute GIT_REPOSITORY https://github.com/COM8/kompute.git
GIT_TAG f4d72e2aa7b23ffe05d5ea3191bf72ad00def0ec) # The commit hash for a dev version before v0.9.0. Replace with the latest from: https://github.com/KomputeProject/kompute/releases
FetchContent_MakeAvailable(kompute)
include_directories(${kompute_SOURCE_DIR}/src/include)
# Add to the list, so CMake can later find the code to compile shaders to header files
list(APPEND CMAKE_PREFIX_PATH "${kompute_SOURCE_DIR}/cmake")
add_subdirectory(shader)
add_subdirectory(src)

View file

@ -1,31 +1,39 @@
# Kompute Array Multiplication Example
This folder contains an end to end Kompute Example that implements logistic regression.
This example is structured such that you will be able to extend it for your project.
It contains a cmake build configuration that can be used in your production applications.
It contains a CMake build configuration that can be used in your production applications.
## Building the example
You will notice that it's a standalone project, so you can re-use it for your application.
It uses CMake's [`fetch_content`](https://cmake.org/cmake/help/latest/module/FetchContent.html) to consume Kompute as a dependency.
To build you just need to run the CMake command in this folder as follows:
This project has the option to either import the Kompute dependency relative to the project or use your existing installation of Kompute.
To build you just need to run the cmake command in this folder as follows:
```
cmake -Bbuild/ \
-DCMAKE_BUILD_TYPE=Debug \
-DKOMPUTE_OPT_INSTALL=0 \
-DKOMPUTE_OPT_REPO_SUBMODULE_BUILD=1 \
-DKOMPUTE_OPT_ENABLE_SPDLOG=1
```bash
git clone https://github.com/KomputeProject/kompute.git
cd kompute/examples/array_multiplication
mkdir build
cd build
cmake ..
cmake --build .
```
You can pass the following optional parameters based on your desired configuration:
* If you wish to install with spdlog support you just have to pass `-DKOMPUTE_OPT_ENABLE_SPDLOG=1`.
* If you are using a package manager such as `vcpkg` make sure you pass the `-DCMAKE_TOOLCHAIN_FILE=` parameter
* If you wish to load shader from raw glsl string instead of spirv bytes you can use `-DKOMPUTE_ANDROID_SHADER_FROM_STRING`
## Executing
Form inside the `build/` directory run:
### Linux
```bash
./kompute_array_mult
```
### Windows
```bash
.\Debug\kompute_array_mult.exe
```
## Pre-requisites
@ -33,18 +41,5 @@ In order to run this example, you will need the following dependencies:
* REQUIRED
+ The Vulkan SDK must be installed
* OPTIONAL
+ Kompute library must be accessible (by default it uses the source directory)
+ SPDLOG - for logging
+ FMT - for text formatting
We will cover how you can install Kompute in the next section.
For the Vulkan SDK, the simplest way to install it is through [their website](https://vulkan.lunarg.com/sdk/home). You just have to follow the instructions for the relevant platform.
For the other libraries, because they are optional you can just make sure you build and install Kompute with these disabled (this will be covered in more detail below).
Alternatively you can use package managers such as vcpkg to help you install them, although to simplify things you can start without the dependencies first.

View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.20)
# To add more shaders simply copy the vulkan_compile_shader command and replace it with your new shader
vulkan_compile_shader(INFILE my_shader.comp
OUTFILE my_shader.hpp
NAMESPACE "shader"
RELATIVE_PATH "${kompute_SOURCE_DIR}/cmake")
# Then add it to the library, so you can access it later in your code
add_library(shader INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/my_shader.hpp"
# "${CMAKE_CURRENT_BINARY_DIR}/my_shader2.hpp"
)
target_include_directories(shader INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

View file

@ -0,0 +1,14 @@
#version 450
// The execution structure
layout (local_size_x = 1) in;
// The buffers are provided via the tensors
layout(binding = 0) buffer bufA { float a[]; };
layout(binding = 1) buffer bufB { float b[]; };
layout(binding = 2) buffer bufOut { float o[]; };
void main() {
uint index = gl_GlobalInvocationID.x;
o[index] = a[index] * b[index];
}

View file

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.20)
add_executable(kompute_array_mult main.cpp)
target_link_libraries(kompute_array_mult PRIVATE shader kompute::kompute)

View file

@ -1,79 +0,0 @@
#include <iostream>
#include <memory>
#include <vector>
#include "kompute/Kompute.hpp"
static std::vector<uint32_t>
compileSource(const std::string& source)
{
std::ofstream fileOut("tmp_kp_shader.comp");
fileOut << source;
fileOut.close();
if (system(
std::string(
"glslangValidator -V tmp_kp_shader.comp -o tmp_kp_shader.comp.spv")
.c_str()))
throw std::runtime_error("Error running glslangValidator command");
std::ifstream fileStream("tmp_kp_shader.comp.spv", std::ios::binary);
std::vector<char> buffer;
buffer.insert(
buffer.begin(), std::istreambuf_iterator<char>(fileStream), {});
return { (uint32_t*)buffer.data(),
(uint32_t*)(buffer.data() + buffer.size()) };
}
int
main()
{
#if KOMPUTE_ENABLE_SPDLOG
spdlog::set_level(
static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL));
#endif
kp::Manager mgr;
auto tensorInA = mgr.tensor({ 2.0, 4.0, 6.0 });
auto tensorInB = mgr.tensor({ 0.0, 1.0, 2.0 });
auto tensorOut = mgr.tensor({ 0.0, 0.0, 0.0 });
std::string shader(R"(
// The version to use
#version 450
// The execution structure
layout (local_size_x = 1) in;
// The buffers are provided via the tensors
layout(binding = 0) buffer bufA { float a[]; };
layout(binding = 1) buffer bufB { float b[]; };
layout(binding = 2) buffer bufOut { float o[]; };
void main() {
uint index = gl_GlobalInvocationID.x;
o[index] = a[index] * b[index];
}
)");
std::vector<std::shared_ptr<kp::Tensor>> params = { tensorInA,
tensorInB,
tensorOut };
std::shared_ptr<kp::Algorithm> algo =
mgr.algorithm(params, compileSource(shader));
mgr.sequence()
->record<kp::OpTensorSyncDevice>(params)
->record<kp::OpAlgoDispatch>(algo)
->record<kp::OpTensorSyncLocal>(params)
->eval();
// prints "Output { 0 4 12 }"
std::cout << "Output: { ";
for (const float& elem : tensorOut->vector()) {
std::cout << elem << " ";
}
std::cout << "}" << std::endl;
}

View file

@ -0,0 +1,41 @@
#include <iostream>
#include <memory>
#include <vector>
#include "my_shader.hpp"
#include <kompute/Kompute.hpp>
int
main()
{
kp::Manager mgr;
std::shared_ptr<kp::TensorT<float>> tensorInA =
mgr.tensor({ 2.0, 4.0, 6.0 });
std::shared_ptr<kp::TensorT<float>> tensorInB =
mgr.tensor({ 0.0, 1.0, 2.0 });
std::shared_ptr<kp::TensorT<float>> tensorOut =
mgr.tensor({ 0.0, 0.0, 0.0 });
const std::vector<std::shared_ptr<kp::Tensor>> params = { tensorInA,
tensorInB,
tensorOut };
const std::vector<uint32_t> shader = std::vector<uint32_t>(
shader::MY_SHADER_COMP_SPV.begin(), shader::MY_SHADER_COMP_SPV.end());
std::shared_ptr<kp::Algorithm> algo = mgr.algorithm(params, shader);
mgr.sequence()
->record<kp::OpTensorSyncDevice>(params)
->record<kp::OpAlgoDispatch>(algo)
->record<kp::OpTensorSyncLocal>(params)
->eval();
// prints "Output { 0 4 12 }"
std::cout << "Output: { ";
for (const float& elem : tensorOut->vector()) {
std::cout << elem << " ";
}
std::cout << "}" << std::endl;
}

View file

@ -1,41 +1,37 @@
cmake_minimum_required(VERSION 3.4.1)
project(kompute_linear_reg VERSION 0.1.0)
cmake_minimum_required(VERSION 3.20)
project(kompute_logistic_regression)
set(CMAKE_CXX_STANDARD 14)
option(KOMPUTE_ARR_OPT_INSTALLED_KOMPUTE "Enable if you prefer to use your installed Kompute library" 0)
option(KOMPUTE_OPT_ENABLE_SPDLOG "Extra compile flags for Kompute, see docs for full list" 0)
set(KOMPUTE_EXTRA_CXX_FLAGS "" CACHE STRING "Extra compile flags for Kompute, see docs for full list")
# Set a default build type if none was specified
# Based on: https://github.com/openchemistry/tomviz/blob/master/cmake/BuildType.cmake
set(DEFAULT_BUILD_TYPE "Release")
if(KOMPUTE_OPT_ENABLE_SPDLOG)
set(KOMPUTE_EXTRA_CXX_FLAGS "${KOMPUTE_EXTRA_CXX_FLAGS} -DKOMPUTE_ENABLE_SPDLOG=1")
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(DEFAULT_BUILD_TYPE "Debug")
endif()
# It is necessary to pass the DEBUG or RELEASE flag accordingly to Kompute
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 ${KOMPUTE_EXTRA_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE=1 ${KOMPUTE_EXTRA_CXX_FLAGS}")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
if(KOMPUTE_ARR_OPT_INSTALLED_KOMPUTE)
find_package(kompute REQUIRED)
else()
add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
find_package(Vulkan REQUIRED)
add_executable(kompute_linear_reg
src/Main.cpp)
target_link_libraries(kompute_linear_reg
kompute::kompute
Vulkan::Vulkan
)
include_directories(
../../single_include/)
if(KOMPUTE_OPT_ENABLE_SPDLOG)
target_link_libraries(kompute_linear_reg
spdlog::spdlog)
if(WIN32) # Install dlls in the same directory as the executable on Windows
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
include(FetchContent)
FetchContent_Declare(kompute GIT_REPOSITORY https://github.com/COM8/kompute.git
GIT_TAG f4d72e2aa7b23ffe05d5ea3191bf72ad00def0ec) # The commit hash for a dev version before v0.9.0. Replace with the latest from: https://github.com/KomputeProject/kompute/releases
FetchContent_MakeAvailable(kompute)
include_directories(${kompute_SOURCE_DIR}/src/include)
# Add to the list, so CMake can later find the code to compile shaders to header files
list(APPEND CMAKE_PREFIX_PATH "${kompute_SOURCE_DIR}/cmake")
add_subdirectory(shader)
add_subdirectory(src)

View file

@ -1,31 +1,39 @@
# Kompute Logistic Regression Example
This folder contains an end to end Kompute Example that implements logistic regression.
This example is structured such that you will be able to extend it for your project.
It contains a cmake build configuration that can be used in your production applications.
It contains a CMake build configuration that can be used in your production applications.
## Building the example
You will notice that it's a standalone project, so you can re-use it for your application.
It uses CMake's [`fetch_content`](https://cmake.org/cmake/help/latest/module/FetchContent.html) to consume Kompute as a dependency.
To build you just need to run the CMake command in this folder as follows:
This project has the option to either import the Kompute dependency relative to the project or use your existing installation of Kompute.
To build you just need to run the cmake command in this folder as follows:
```
cmake -Bbuild/ \
-DCMAKE_BUILD_TYPE=Debug \
-DKOMPUTE_OPT_INSTALL=0 \
-DKOMPUTE_OPT_REPO_SUBMODULE_BUILD=1 \
-DKOMPUTE_OPT_ENABLE_SPDLOG=1
```bash
git clone https://github.com/KomputeProject/kompute.git
cd kompute/examples/logistic_regression
mkdir build
cd build
cmake ..
cmake --build .
```
You can pass the following optional parameters based on your desired configuration:
* If you wish to install with spdlog support you just have to pass `-DKOMPUTE_OPT_ENABLE_SPDLOG=1`.
* If you are using a package manager such as `vcpkg` make sure you pass the `-DCMAKE_TOOLCHAIN_FILE=` parameter
* If you wish to load shader from raw glsl string instead of spirv bytes you can use `-DKOMPUTE_ANDROID_SHADER_FROM_STRING`
## Executing
Form inside the `build/` directory run:
### Linux
```bash
./kompute_logistic_regression
```
### Windows
```bash
.\Debug\kompute_logistic_regression.exe
```
## Pre-requisites
@ -33,8 +41,5 @@ In order to run this example, you will need the following dependencies:
* REQUIRED
+ The Vulkan SDK must be installed
* OPTIONAL
+ Kompute library must be accessible (by default it uses the source directory)
+ SPDLOG - for logging
+ FMT - for text formatting
For the Vulkan SDK, the simplest way to install it is through [their website](https://vulkan.lunarg.com/sdk/home). You just have to follow the instructions for the relevant platform.

View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.20)
# To add more shaders simply copy the vulkan_compile_shader command and replace it with your new shader
vulkan_compile_shader(INFILE my_shader.comp
OUTFILE my_shader.hpp
NAMESPACE "shader"
RELATIVE_PATH "${kompute_SOURCE_DIR}/cmake")
# Then add it to the library, so you can access it later in your code
add_library(shader INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/my_shader.hpp"
# "${CMAKE_CURRENT_BINARY_DIR}/my_shader2.hpp"
)
target_include_directories(shader INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

View file

@ -52,5 +52,3 @@ void main() {
lout[idx] = calculateLoss(yHat, yCurr);
}

View file

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.20)
add_executable(kompute_logistic_regression main.cpp)
target_link_libraries(kompute_logistic_regression PRIVATE shader kompute::kompute)

View file

@ -1,72 +0,0 @@
#include <iostream>
#include <memory>
#include <vector>
#include "kompute/Kompute.hpp"
int
main()
{
#if KOMPUTE_ENABLE_SPDLOG
spdlog::set_level(
static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL));
#endif
uint32_t ITERATIONS = 100;
float learningRate = 0.1;
kp::Manager mgr;
auto xI = mgr.tensor({ 0, 1, 1, 1, 1 });
auto xJ = mgr.tensor({ 0, 0, 0, 1, 1 });
auto y = mgr.tensor({ 0, 0, 0, 1, 1 });
auto wIn = mgr.tensor({ 0.001, 0.001 });
auto wOutI = mgr.tensor({ 0, 0, 0, 0, 0 });
auto wOutJ = mgr.tensor({ 0, 0, 0, 0, 0 });
auto bIn = mgr.tensor({ 0 });
auto bOut = mgr.tensor({ 0, 0, 0, 0, 0 });
auto lOut = mgr.tensor({ 0, 0, 0, 0, 0 });
std::vector<std::shared_ptr<kp::Tensor>> params = { xI, xJ, y,
wIn, wOutI, wOutJ,
bIn, bOut, lOut };
std::vector<uint32_t> spirv(
(uint32_t*)kp::shader_data::shaders_glsl_logisticregression_comp_spv,
(uint32_t*)(kp::shader_data::shaders_glsl_logisticregression_comp_spv +
kp::shader_data::
shaders_glsl_logisticregression_comp_spv_len));
std::shared_ptr<kp::Algorithm> algo = mgr.algorithm(
params, spirv, kp::Workgroup({ 5 }), std::vector<float>({ 5.0 }));
mgr.sequence()->eval<kp::OpTensorSyncDevice>(params);
std::shared_ptr<kp::Sequence> sq =
mgr.sequence()
->record<kp::OpTensorSyncDevice>({ wIn, bIn })
->record<kp::OpAlgoDispatch>(algo)
->record<kp::OpTensorSyncLocal>({ wOutI, wOutJ, bOut, lOut });
// Iterate across all expected iterations
for (size_t i = 0; i < ITERATIONS; i++) {
sq->eval();
for (size_t j = 0; j < bOut->size(); j++) {
wIn->data()[0] -= learningRate * wOutI->data()[j];
wIn->data()[1] -= learningRate * wOutJ->data()[j];
bIn->data()[0] -= learningRate * bOut->data()[j];
}
}
std::cout << "RESULTS" << std::endl;
std::cout << "w1: " << wIn->data()[0] << std::endl;
std::cout << "w2: " << wIn->data()[1] << std::endl;
std::cout << "b: " << bIn->data()[0] << std::endl;
}

View file

@ -0,0 +1,66 @@
#include <iostream>
#include <memory>
#include <vector>
#include "kompute/Tensor.hpp"
#include "my_shader.hpp"
#include <kompute/Kompute.hpp>
int
main()
{
uint32_t ITERATIONS = 100;
float learningRate = 0.1;
kp::Manager mgr;
std::shared_ptr<kp::TensorT<float>> xI = mgr.tensor({ 0, 1, 1, 1, 1 });
std::shared_ptr<kp::TensorT<float>> xJ = mgr.tensor({ 0, 0, 0, 1, 1 });
std::shared_ptr<kp::TensorT<float>> y = mgr.tensor({ 0, 0, 0, 1, 1 });
std::shared_ptr<kp::TensorT<float>> wIn = mgr.tensor({ 0.001, 0.001 });
std::shared_ptr<kp::TensorT<float>> wOutI = mgr.tensor({ 0, 0, 0, 0, 0 });
std::shared_ptr<kp::TensorT<float>> wOutJ = mgr.tensor({ 0, 0, 0, 0, 0 });
std::shared_ptr<kp::TensorT<float>> bIn = mgr.tensor({ 0 });
std::shared_ptr<kp::TensorT<float>> bOut = mgr.tensor({ 0, 0, 0, 0, 0 });
std::shared_ptr<kp::TensorT<float>> lOut = mgr.tensor({ 0, 0, 0, 0, 0 });
const std::vector<std::shared_ptr<kp::Tensor>> params = {
xI, xJ, y, wIn, wOutI, wOutJ, bIn, bOut, lOut
};
const std::vector<uint32_t> shader = std::vector<uint32_t>(
shader::MY_SHADER_COMP_SPV.begin(), shader::MY_SHADER_COMP_SPV.end());
std::shared_ptr<kp::Algorithm> algo = mgr.algorithm(
params, shader, kp::Workgroup({ 5 }), std::vector<float>({ 5.0 }));
mgr.sequence()->eval<kp::OpTensorSyncDevice>(params);
std::shared_ptr<kp::Sequence> sq =
mgr.sequence()
->record<kp::OpTensorSyncDevice>({ wIn, bIn })
->record<kp::OpAlgoDispatch>(algo)
->record<kp::OpTensorSyncLocal>({ wOutI, wOutJ, bOut, lOut });
// Iterate across all expected iterations
for (size_t i = 0; i < ITERATIONS; i++) {
sq->eval();
for (size_t j = 0; j < bOut->size(); j++) {
wIn->data()[0] -= learningRate * wOutI->data()[j];
wIn->data()[1] -= learningRate * wOutJ->data()[j];
bIn->data()[0] -= learningRate * bOut->data()[j];
}
}
std::cout << "RESULTS" << std::endl;
std::cout << "w1: " << wIn->data()[0] << std::endl;
std::cout << "w2: " << wIn->data()[1] << std::endl;
std::cout << "b: " << bIn->data()[0] << std::endl;
}