Skip to content

Commit

Permalink
forward pass works
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhylkaaa committed May 14, 2020
0 parents commit 2472bff
Show file tree
Hide file tree
Showing 13 changed files with 995 additions and 0 deletions.
26 changes: 26 additions & 0 deletions CMakeLists.txt
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)
48 changes: 48 additions & 0 deletions includes/MLP.h
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
45 changes: 45 additions & 0 deletions includes/dense.h
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
47 changes: 47 additions & 0 deletions includes/layer.h
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
37 changes: 37 additions & 0 deletions includes/vulkan_init.h
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
19 changes: 19 additions & 0 deletions main.cpp
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;
}
28 changes: 28 additions & 0 deletions shaders/dense.comp
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 added shaders/dense.comp.spv
Binary file not shown.
26 changes: 26 additions & 0 deletions shaders/xavier_init.comp
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;
}
}
102 changes: 102 additions & 0 deletions src/MLP.cpp
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);
}



Loading

0 comments on commit 2472bff

Please sign in to comment.