-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2472bff
Showing
13 changed files
with
995 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
cmake_minimum_required(VERSION 3.15) | ||
project(vulkan_perceptron) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
FILE(GLOB sources src/*.cpp) | ||
|
||
add_executable(vulkan_perceptron main.cpp ${sources}) | ||
|
||
target_include_directories(vulkan_perceptron PUBLIC includes) | ||
|
||
find_package(Vulkan REQUIRED) | ||
|
||
target_include_directories(${PROJECT_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS}) | ||
target_link_libraries(${PROJECT_NAME} Vulkan::Vulkan) | ||
|
||
find_package(PkgConfig REQUIRED) | ||
pkg_search_module(GLM REQUIRED glm) | ||
include_directories(${GLM_INCLUDE_DIRS}) | ||
target_link_libraries(${PROJECT_NAME} ${GLM_LIBRARY_DIRS}) | ||
|
||
find_package(glfw3 REQUIRED) | ||
include_directories(${GLFW_INCLUDE_DIRS}) | ||
target_link_libraries(${PROJECT_NAME} ${GLFW_LIBRARIES} glfw) | ||
|
||
include_directories(shaders) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// Created by Dima Zhylko on 12/05/2020. | ||
// | ||
|
||
#ifndef VULKAN_PERCEPTRON_MLP_H | ||
#define VULKAN_PERCEPTRON_MLP_H | ||
#include <vector> | ||
#include <string> | ||
#include "layer.h" | ||
#include "dense.h" | ||
#include "vulkan_init.h" | ||
#include <iostream> | ||
|
||
class MLP { | ||
std::vector<Layer*> layers{}; | ||
VkInstance instance; | ||
VkDebugUtilsMessengerEXT debugMessenger; | ||
VkPhysicalDevice physicalDevice; | ||
uint32_t queueFamilyIndex; | ||
VkDevice device; | ||
VkQueue queue; | ||
VkDeviceMemory deviceMemory; | ||
|
||
VkBuffer input; | ||
VkBuffer d_input; | ||
std::vector<uint64_t> offsets; | ||
|
||
uint32_t batch_size; | ||
uint32_t input_size; | ||
public: | ||
MLP(); | ||
|
||
MLP(uint32_t input_size, uint32_t batch_size, const std::vector<int>& layer_dims, const std::vector<std::string>& activations); | ||
|
||
void add(int layer_dim, const std::string& activation, uint32_t input_size=0, uint32_t batch_size=0); | ||
|
||
void forward_initialize(); | ||
void forward(const std::vector<std::vector<float>>& batch); | ||
void backward(); | ||
|
||
VkBuffer& get_output() {return layers[layers.size()-1]->get_output();} | ||
|
||
VkDeviceMemory& get_memory() {return layers[layers.size()-1]->get_device_memory();} | ||
|
||
uint64_t get_output_offset(){return offsets[2];} | ||
}; | ||
|
||
#endif //VULKAN_PERCEPTRON_MLP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// | ||
// Created by Dima Zhylko on 12/05/2020. | ||
// | ||
|
||
#ifndef VULKAN_PERCEPTRON_DENSE_H | ||
#define VULKAN_PERCEPTRON_DENSE_H | ||
#include "layer.h" | ||
#include <string> | ||
#include "vulkan_init.h" | ||
#include <iostream> | ||
|
||
class DenseLayer: public Layer{ | ||
VkBuffer weight; | ||
VkBuffer bias; | ||
|
||
VkBuffer d_weight; | ||
VkBuffer d_bias; | ||
|
||
float scale; | ||
|
||
std::string initializer{}; | ||
|
||
struct dims{ | ||
uint32_t batch_size; | ||
uint32_t inp_dim; | ||
uint32_t output_dim; | ||
} dim; | ||
|
||
public: | ||
DenseLayer(VkDevice* device, uint32_t queueFamilyIndex, VkPhysicalDevice* physicalDevice, | ||
int batch_size, int input_dim, int output_dim, VkBuffer input, float scale=10, const std::string& initializer="xavier"); | ||
|
||
void forward_initialize(VkQueue& queue) override; | ||
void forward(VkQueue& queue) override; | ||
void backward(VkQueue& queue) override; | ||
|
||
VkBuffer& get_bias(); | ||
VkBuffer& get_weight(); | ||
|
||
[[nodiscard]] const dims& get_dims() const {return dim;}; | ||
uint32_t get_output_dim() override {return dim.output_dim;} | ||
|
||
uint64_t get_output_offset() override {return offsets[2];} | ||
}; | ||
#endif //VULKAN_PERCEPTRON_DENSE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// Created by Dima Zhylko on 12/05/2020. | ||
// | ||
|
||
#ifndef VULKAN_PERCEPTRON_LAYER_H | ||
#define VULKAN_PERCEPTRON_LAYER_H | ||
|
||
#include <vulkan/vulkan.h> | ||
#include <vector> | ||
|
||
class Layer { | ||
protected: | ||
VkBuffer input; | ||
VkBuffer output; | ||
std::vector<uint64_t> offsets{}; | ||
VkBuffer d_input; | ||
VkBuffer d_output; | ||
|
||
VkDevice* device; | ||
uint32_t queueFamilyIndex; | ||
VkPhysicalDevice* physicalDevice; | ||
|
||
VkDeviceMemory deviceMemory; | ||
|
||
VkPipeline forwardPipeline; | ||
VkPipelineLayout forwardPipelineLayout; | ||
VkDescriptorSetLayout forwardSetLayout; | ||
|
||
VkDescriptorPool forwardDescriptorPool; | ||
VkDescriptorSet forwardDescriptorSet; | ||
|
||
VkCommandPool forwardCommandPool; | ||
VkCommandBuffer forwardCommandBuffer; | ||
|
||
public: | ||
virtual void forward(VkQueue& queue) = 0; | ||
virtual void backward(VkQueue& queue) = 0; | ||
virtual void forward_initialize(VkQueue& queue) = 0; | ||
|
||
VkBuffer& get_output(){return output;} | ||
VkDeviceMemory& get_device_memory(){return deviceMemory;} | ||
|
||
virtual uint64_t get_output_offset() = 0; | ||
|
||
virtual uint32_t get_output_dim() = 0; | ||
}; | ||
#endif //VULKAN_PERCEPTRON_LAYER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// Created by Dima Zhylko on 14/05/2020. | ||
// | ||
|
||
#ifndef VULKAN_PERCEPTRON_VULKAN_INIT_H | ||
#define VULKAN_PERCEPTRON_VULKAN_INIT_H | ||
|
||
#include <vulkan/vulkan.h> | ||
#include <vector> | ||
#include <string> | ||
|
||
void setup_vulkan(VkInstance& instance, VkDebugUtilsMessengerEXT& debugMessenger, VkPhysicalDevice& physicalDevice, | ||
uint32_t& queueFamilyIndex, VkDevice& device, VkQueue& queue); | ||
|
||
void createBuffer(const VkDevice& device, uint32_t queueFamilyIndex, VkBuffer& buffer, | ||
uint32_t n, uint32_t m, uint64_t elem_size=sizeof(float)); | ||
|
||
void allocateAndBindBuffers(const VkDevice& device, const VkPhysicalDevice& physicalDevice, std::vector<VkBuffer*>& buffers, | ||
VkDeviceMemory& memory, std::vector<uint64_t>& offsets); | ||
|
||
void createPipelineLayout(const VkDevice& device, uint32_t bindingsCount, VkDescriptorSetLayout& setLayout, | ||
VkPipelineLayout& pipelineLayout, uint32_t push_constant_size); | ||
|
||
void createComputePipeline(const VkDevice& device, const std::string& shaderName, const VkPipelineLayout& pipelineLayout, | ||
VkPipeline& pipeline, const std::string& entry_point="main"); | ||
|
||
void allocateDescriptorSet(const VkDevice& device, std::vector<VkBuffer*>& buffers, | ||
VkDescriptorPool& descriptorPool, const VkDescriptorSetLayout &setLayout, VkDescriptorSet& descriptorSet); | ||
|
||
void createCommandPoolAndBuffer(const VkDevice& device, uint32_t queueFamilyIndex, | ||
VkCommandPool& commandPool, VkCommandBuffer& commandBuffer, VkCommandPoolCreateFlags flags=0); | ||
|
||
void recordComputePipeline(VkCommandBuffer& commandBuffer, const VkPipelineLayout& pipelineLayout, | ||
uint32_t push_constant_size, void* push_constant_vals, const VkPipeline& pipeline, | ||
VkDescriptorSet& descriptorSet, uint32_t x_group, uint32_t y_group, uint32_t z_group, | ||
VkCommandBufferUsageFlags flags=0); | ||
#endif //VULKAN_PERCEPTRON_VULKAN_INIT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include <iostream> | ||
#include <MLP.h> | ||
#include <string> | ||
|
||
int main() { | ||
|
||
std::vector<int> layers{5, 5}; | ||
std::vector<std::string> activations{"mock", "mock"}; | ||
MLP mlp = MLP(3, 3, layers, activations); | ||
|
||
std::vector<std::vector<float>> batch{{1, 2, 3}, | ||
{1, 2, 3}, | ||
{3, 2, 1}}; | ||
|
||
mlp.forward_initialize(); | ||
mlp.forward(batch); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#version 450 | ||
|
||
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; | ||
|
||
layout(std430, binding=0) buffer inI { float layer_input[]; }; | ||
layout(std430, binding=1) buffer inW { float weight[]; }; | ||
layout(std430, binding=2) buffer inB { float bias[]; }; | ||
layout(std430, binding=3) buffer outO { float layer_output[]; }; | ||
|
||
layout(push_constant) uniform dim { | ||
uint batch_size; | ||
uint inp_dim; | ||
uint out_dim; | ||
}; | ||
|
||
void main(){ | ||
uint x = gl_GlobalInvocationID.x; | ||
uint y = gl_GlobalInvocationID.y; | ||
|
||
if(x >= batch_size || y >= out_dim)return; | ||
|
||
float r = 0.0; | ||
for(uint i=0;i<inp_dim;i++){ | ||
r += layer_input[x*inp_dim + i] * weight[i*out_dim + y]; | ||
} | ||
|
||
layer_output[x*out_dim + y] = r + bias[y]; | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#version 450 | ||
|
||
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; | ||
|
||
layout(std430, binding=0) buffer inI { float layer_input[]; }; | ||
layout(std430, binding=1) buffer inW { float weight[]; }; | ||
layout(std430, binding=2) buffer inB { float bias[]; }; | ||
layout(std430, binding=3) buffer outO { float layer_output[]; }; | ||
|
||
layout(push_constant) uniform dim { | ||
uint batch_szie; | ||
uint inp_dim; | ||
uint out_dim; | ||
}; | ||
|
||
void main(){ | ||
uint x = gl_GlobalInvocationID.x; | ||
uint y = gl_GlobalInvocationID.y; | ||
|
||
if(x >= inp_dim || y >= out_dim)return; | ||
|
||
//weight[x*out_dim + y] = // TODO; | ||
if(x == 0){ | ||
bias[y] = 0.0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// | ||
// Created by Dima Zhylko on 12/05/2020. | ||
// | ||
|
||
#include <MLP.h> | ||
|
||
MLP::MLP(uint32_t input_size, uint32_t batch_size, const std::vector<int> &layer_dims, const std::vector<std::string> &activations) { | ||
setup_vulkan(instance, debugMessenger, physicalDevice, queueFamilyIndex, device, queue); | ||
|
||
for(int i = 0;i<layer_dims.size();i++){ | ||
add(layer_dims[i], activations[i], input_size, batch_size); | ||
} | ||
} | ||
|
||
void MLP::add(int layer_dim, const std::string &activation, uint32_t input_size, uint32_t batch_size) { | ||
if(layers.empty() && (input_size == 0 || batch_size == 0)){ | ||
throw std::invalid_argument("first layer should specify input and batch size greater than 0"); | ||
} | ||
|
||
uint32_t input_dim; | ||
|
||
VkBuffer input_buffer; | ||
|
||
if(layers.empty()){ | ||
input_dim = input_size; | ||
this->batch_size = batch_size; | ||
this->input_size = input_size; | ||
|
||
createBuffer(device, queueFamilyIndex, input, batch_size, input_size); | ||
//createBuffer(device, queueFamilyIndex, d_input, batch_size, input_size); | ||
input_buffer = input; | ||
|
||
} else { | ||
input_buffer = layers[layers.size()-1]->get_output(); | ||
input_dim = layers[layers.size()-1]->get_output_dim(); | ||
} | ||
|
||
DenseLayer* d = new DenseLayer(&device, queueFamilyIndex, &physicalDevice, this->batch_size, input_dim, layer_dim, input_buffer); | ||
|
||
layers.push_back(d); | ||
} | ||
|
||
void MLP::forward_initialize(){ | ||
std::vector<VkBuffer*> buffers{&input}; | ||
allocateAndBindBuffers(device, physicalDevice, buffers, deviceMemory, offsets); | ||
|
||
for(Layer* layer : layers){ | ||
std::cout<<"forward_initialize:"<<std::endl; | ||
layer->forward_initialize(queue); | ||
} | ||
} | ||
|
||
void MLP::forward(const std::vector<std::vector<float> > &batch) { | ||
char *data = nullptr; | ||
if(vkMapMemory(device, deviceMemory, 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void**>(&data)) != VK_SUCCESS){ | ||
throw std::runtime_error("failed to map device memory"); | ||
} | ||
std::cout<<"batch_init:"<<std::endl; | ||
float* batch_data = reinterpret_cast<float*>(data + offsets[0]); | ||
|
||
if(batch.size() != this->batch_size || batch[0].size() != this->input_size){ | ||
throw std::invalid_argument("batch size or input dimension is wrong"); | ||
} | ||
|
||
for(int i = 0;i<this->batch_size;i++){ | ||
for(int j=0;j<this->input_size;j++){ | ||
batch_data[i*this->input_size + j] = batch[i][j]; | ||
} | ||
} | ||
|
||
vkUnmapMemory(device, deviceMemory); | ||
|
||
for(Layer* layer : layers){ | ||
std::cout<<"forward:"<<std::endl; | ||
layer->forward(queue); | ||
} | ||
|
||
std::cout<<"output is:"<<std::endl; | ||
|
||
int n = layers.size(); | ||
data = nullptr; | ||
if(vkMapMemory(device, layers[n-1]->get_device_memory(), 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void **>(&data)) != VK_SUCCESS){ | ||
throw std::runtime_error("failed to map device memory"); | ||
} | ||
|
||
float* output = reinterpret_cast<float*>(data + layers[n-1]->get_output_offset()); | ||
|
||
for(int i = 0;i<this->batch_size;i++){ | ||
for(int j = 0;j<layers[n-1]->get_output_dim();j++){ | ||
std::cout<<output[i*layers[n-1]->get_output_dim() + j]<<" "; | ||
} | ||
std::cout<<std::endl; | ||
} | ||
vkUnmapMemory(device, layers[n-1]->get_device_memory()); | ||
} | ||
|
||
MLP::MLP() { | ||
setup_vulkan(instance, debugMessenger, physicalDevice, queueFamilyIndex, device, queue); | ||
} | ||
|
||
|
||
|
Oops, something went wrong.