mirror of
https://github.com/lordmathis/CUDANet.git
synced 2025-12-22 22:34:22 +00:00
Compare commits
6 Commits
25670f90c4
...
10c84d75fc
| Author | SHA1 | Date | |
|---|---|---|---|
| 10c84d75fc | |||
| 4c26efe826 | |||
| 7f203b8947 | |||
| 64eac7050b | |||
| 24606491a3 | |||
| 6340b27055 |
@@ -213,7 +213,7 @@ InceptionB::InceptionB(
|
|||||||
branch3x3->getOutputSize(), branch3x3dbl_3->getOutputSize()
|
branch3x3->getOutputSize(), branch3x3dbl_3->getOutputSize()
|
||||||
);
|
);
|
||||||
concat_2 = new CUDANet::Layers::Concat(
|
concat_2 = new CUDANet::Layers::Concat(
|
||||||
concat_1->getOutputSize(), branchPool->getOutputSize()
|
concat_1->getOutputSize(), branchPool->get_output_size()
|
||||||
);
|
);
|
||||||
|
|
||||||
outputSize = concat_2->getOutputSize();
|
outputSize = concat_2->getOutputSize();
|
||||||
@@ -441,7 +441,7 @@ InceptionD::InceptionD(
|
|||||||
branch3x3_2->getOutputSize(), branch7x7x3_4->getOutputSize()
|
branch3x3_2->getOutputSize(), branch7x7x3_4->getOutputSize()
|
||||||
);
|
);
|
||||||
concat_2 = new CUDANet::Layers::Concat(
|
concat_2 = new CUDANet::Layers::Concat(
|
||||||
concat_1->getOutputSize(), branchPool->getOutputSize()
|
concat_1->getOutputSize(), branchPool->get_output_size()
|
||||||
);
|
);
|
||||||
|
|
||||||
outputSize = concat_2->getOutputSize();
|
outputSize = concat_2->getOutputSize();
|
||||||
@@ -707,7 +707,7 @@ InceptionV3::InceptionV3(
|
|||||||
addLayer("AveragePool", avgpool);
|
addLayer("AveragePool", avgpool);
|
||||||
|
|
||||||
fc = new CUDANet::Layers::Dense(
|
fc = new CUDANet::Layers::Dense(
|
||||||
avgpool->getOutputSize(), 1000, CUDANet::Layers::ActivationType::NONE
|
avgpool->get_output_size(), 1000, CUDANet::Layers::ActivationType::NONE
|
||||||
);
|
);
|
||||||
addLayer("fc", fc);
|
addLayer("fc", fc);
|
||||||
}
|
}
|
||||||
|
|||||||
45
include/backend.hpp
Normal file
45
include/backend.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace CUDANet {
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class Tensor;
|
||||||
|
|
||||||
|
class Backend {
|
||||||
|
public:
|
||||||
|
// Memory management
|
||||||
|
virtual void* allocate(size_t bytes) = 0;
|
||||||
|
virtual void deallocate(void* ptr) = 0;
|
||||||
|
|
||||||
|
// Tensor ops
|
||||||
|
virtual void print(const CUDANet::Tensor& input) = 0;
|
||||||
|
virtual void zero(CUDANet::Tensor& input) = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
copy_to_device(CUDANet::Tensor& tensor, void* data, size_t size) = 0;
|
||||||
|
|
||||||
|
virtual void sum(const CUDANet::Tensor& input, CUDANet::Tensor& sum) = 0;
|
||||||
|
virtual void max(const CUDANet::Tensor& input, CUDANet::Tensor& max) = 0;
|
||||||
|
|
||||||
|
// Layer ops
|
||||||
|
virtual void relu(CUDANet::Tensor& tensor) = 0;
|
||||||
|
virtual void sigmoid(CUDANet::Tensor& tensor) = 0;
|
||||||
|
virtual void softmax(
|
||||||
|
CUDANet::Tensor& tensor,
|
||||||
|
CUDANet::Tensor& temp_max,
|
||||||
|
CUDANet::Tensor& temp_sum
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
virtual CUDANet::Tensor& dense(
|
||||||
|
const CUDANet::Tensor& weights,
|
||||||
|
const CUDANet::Tensor& biases,
|
||||||
|
const CUDANet::Tensor& input,
|
||||||
|
CUDANet::Tensor& output,
|
||||||
|
const size_t input_size,
|
||||||
|
const size_t output_size
|
||||||
|
) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CUDANet
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include "backend/tensor.hpp"
|
|
||||||
|
|
||||||
namespace CUDANet::Backend
|
|
||||||
{
|
|
||||||
|
|
||||||
class IBackend
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Memory management
|
|
||||||
virtual void* allocate(size_t bytes) = 0;
|
|
||||||
virtual void deallocate(void* ptr) = 0;
|
|
||||||
|
|
||||||
// Tensor ops
|
|
||||||
virtual void print(const CUDANet::Backend::Tensor &input) = 0;
|
|
||||||
virtual void clear(CUDANet::Backend::Tensor &input) = 0;
|
|
||||||
virtual void sum(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &sum) = 0;
|
|
||||||
virtual void max(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &max) = 0;
|
|
||||||
|
|
||||||
// Layer ops
|
|
||||||
virtual void relu(CUDANet::Backend::Tensor &tensor) = 0;
|
|
||||||
virtual void sigmoid(CUDANet::Backend::Tensor &tensor) = 0;
|
|
||||||
virtual void softmax(CUDANet::Backend::Tensor &tensor, CUDANet::Backend::Tensor &temp_max, CUDANet::Backend::Tensor &temp_sum) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace CUDANet::Backend
|
|
||||||
26
include/backend/cpu.hpp
Normal file
26
include/backend/cpu.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "backend.hpp"
|
||||||
|
#include "tensor.hpp"
|
||||||
|
|
||||||
|
namespace CUDANet::Backend {
|
||||||
|
|
||||||
|
class CPU : public Backend {
|
||||||
|
public:
|
||||||
|
// Memory management
|
||||||
|
void* allocate(size_t bytes) override;
|
||||||
|
void deallocate(void* ptr) override;
|
||||||
|
|
||||||
|
// Tensor ops
|
||||||
|
void print(const CUDANet::Tensor &input) override;
|
||||||
|
void zero(CUDANet::Tensor &input) override;
|
||||||
|
void sum(const CUDANet::Tensor &input, CUDANet::Tensor &sum) override;
|
||||||
|
void max(const CUDANet::Tensor &input, CUDANet::Tensor &max) override;
|
||||||
|
|
||||||
|
// Layer ops
|
||||||
|
void relu(CUDANet::Tensor &tensor) override;
|
||||||
|
void sigmoid(CUDANet::Tensor &tensor) override;
|
||||||
|
void softmax(CUDANet::Tensor &tensor, CUDANet::Tensor &temp_max, CUDANet::Tensor &temp_sum) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,29 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "backend/backend.hpp"
|
#include "backend.hpp"
|
||||||
#include "backend/tensor.hpp"
|
#include "tensor.hpp"
|
||||||
|
|
||||||
namespace CUDANet::Backend {
|
namespace CUDANet::Backend {
|
||||||
|
|
||||||
class CUDABackend : public IBackend {
|
class CUDA : public Backend {
|
||||||
public:
|
public:
|
||||||
// Memory management
|
// Memory management
|
||||||
void* allocate(size_t bytes) override;
|
void* allocate(size_t bytes) override;
|
||||||
void deallocate(void* ptr) override;
|
void deallocate(void* ptr) override;
|
||||||
|
|
||||||
// Tensor ops
|
// Tensor ops
|
||||||
void print(const CUDANet::Backend::Tensor &input) override;
|
void print(const CUDANet::Tensor& input) override;
|
||||||
void clear(CUDANet::Backend::Tensor &input) override;
|
void zero(CUDANet::Tensor& input) override;
|
||||||
void sum(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &sum) override;
|
void
|
||||||
void max(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &max) override;
|
copy_to_device(CUDANet::Tensor& tensor, void* data, size_t size) override;
|
||||||
|
void sum(const CUDANet::Tensor& input, CUDANet::Tensor& sum) override;
|
||||||
|
void max(const CUDANet::Tensor& input, CUDANet::Tensor& max) override;
|
||||||
|
|
||||||
// Layer ops
|
// Layer ops
|
||||||
void relu(CUDANet::Backend::Tensor &tensor) override;
|
void relu(CUDANet::Tensor& tensor) override;
|
||||||
void sigmoid(CUDANet::Backend::Tensor &tensor) override;
|
void sigmoid(CUDANet::Tensor& tensor) override;
|
||||||
void softmax(CUDANet::Backend::Tensor &tensor, CUDANet::Backend::Tensor &temp_max, CUDANet::Backend::Tensor &temp_sum) override;
|
void softmax(
|
||||||
|
CUDANet::Tensor& tensor,
|
||||||
|
CUDANet::Tensor& temp_max,
|
||||||
|
CUDANet::Tensor& temp_sum
|
||||||
|
) override;
|
||||||
|
|
||||||
private:
|
CUDANet::Tensor& dense(
|
||||||
static constexpr int BLOCK_SIZE = 256;
|
const CUDANet::Tensor& weights,
|
||||||
|
const CUDANet::Tensor& biases,
|
||||||
|
const CUDANet::Tensor& input,
|
||||||
|
CUDANet::Tensor& output,
|
||||||
|
const size_t input_size,
|
||||||
|
const size_t output_size
|
||||||
|
) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CUDANet::Backend
|
} // namespace CUDANet::Backend
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <cstddef>
|
|
||||||
#include "backend/backend.hpp"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace CUDANet::Backend
|
|
||||||
{
|
|
||||||
|
|
||||||
enum class DType
|
|
||||||
{
|
|
||||||
FLOAT32,
|
|
||||||
// FLOAT16, // Not implemented yet
|
|
||||||
// INT32, // Not implemented yet
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<size_t> Shape;
|
|
||||||
|
|
||||||
class Tensor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
Tensor() = default;
|
|
||||||
Tensor(Shape shape, DType dtype, IBackend* backend);
|
|
||||||
~Tensor();
|
|
||||||
|
|
||||||
size_t size() const;
|
|
||||||
size_t numel() const;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T* data() const;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T* data();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Shape shape;
|
|
||||||
DType dtype;
|
|
||||||
|
|
||||||
size_t total_elms;
|
|
||||||
size_t total_size;
|
|
||||||
|
|
||||||
IBackend* backend;
|
|
||||||
void* d_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace CUDANet::Backend
|
|
||||||
42
include/layer.hpp
Normal file
42
include/layer.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "shape.hpp"
|
||||||
|
#include "tensor.hpp"
|
||||||
|
|
||||||
|
#define CUDANET_SAME_PADDING(inputSize, kernelSize, stride) \
|
||||||
|
((stride - 1) * inputSize - stride + kernelSize) / 2;
|
||||||
|
|
||||||
|
|
||||||
|
namespace CUDANet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Basic Sequential Layer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Layer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~Layer(){};
|
||||||
|
|
||||||
|
virtual CUDANet::Tensor& forward(const CUDANet::Tensor &input) = 0;
|
||||||
|
|
||||||
|
virtual CUDANet::Shape input_shape() = 0;
|
||||||
|
|
||||||
|
virtual CUDANet::Shape output_shape() = 0;
|
||||||
|
|
||||||
|
virtual size_t input_size() = 0;
|
||||||
|
|
||||||
|
virtual size_t output_size() = 0;
|
||||||
|
|
||||||
|
virtual void set_weights(void *input) = 0;
|
||||||
|
|
||||||
|
virtual CUDANet::Tensor& get_weights() = 0;
|
||||||
|
|
||||||
|
virtual void set_biases(void *input) = 0;
|
||||||
|
|
||||||
|
virtual CUDANet::Tensor& get_biases() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CUDANet::Layers
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "backend/tensor.hpp"
|
#include "tensor.hpp"
|
||||||
#include "backend/backend.hpp"
|
#include "backend.hpp"
|
||||||
|
#include "layer.hpp"
|
||||||
|
|
||||||
namespace CUDANet::Layers {
|
namespace CUDANet::Layers {
|
||||||
|
|
||||||
@@ -19,40 +20,41 @@ enum ActivationType { SIGMOID, RELU, SOFTMAX, NONE };
|
|||||||
* @brief Utility class that performs activation
|
* @brief Utility class that performs activation
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class Activation {
|
class Activation : public Layer {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Activation() = default;
|
Activation() = default;
|
||||||
|
|
||||||
/**
|
Activation(CUDANet::Backend* backend, ActivationType activation, const CUDANet::Shape &shape);
|
||||||
* @brief Construct a new Activation object
|
|
||||||
*
|
|
||||||
* @param activation Type of activation
|
|
||||||
* @param length Length of the input
|
|
||||||
*/
|
|
||||||
Activation(CUDANet::Backend::IBackend* backend, ActivationType activation, const int length);
|
|
||||||
|
|
||||||
/**
|
~Activation() = default;
|
||||||
* @brief Destroy the Activation object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
~Activation();
|
|
||||||
|
|
||||||
/**
|
CUDANet::Tensor& forward(CUDANet::Tensor &input) override;
|
||||||
* @brief Run the activation function on the input
|
|
||||||
*
|
CUDANet::Shape input_shape() override;
|
||||||
* @param d_input Pointer to the input vector on the device
|
|
||||||
*/
|
CUDANet::Shape output_shape() override;
|
||||||
void activate(CUDANet::Backend::Tensor input);
|
|
||||||
|
size_t input_size() override;
|
||||||
|
|
||||||
|
size_t output_size() override;
|
||||||
|
|
||||||
|
void set_weights(void *input) override;
|
||||||
|
|
||||||
|
CUDANet::Tensor& get_weights() override;
|
||||||
|
|
||||||
|
void set_biases(void *input) override;
|
||||||
|
|
||||||
|
CUDANet::Tensor& get_biases() override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CUDANet::Backend::IBackend* backend;
|
CUDANet::Backend* backend;
|
||||||
ActivationType activationType;
|
ActivationType activationType;
|
||||||
int length;
|
CUDANet::Shape shape;
|
||||||
|
|
||||||
CUDANet::Backend::Tensor softmax_sum;
|
CUDANet::Tensor softmax_sum;
|
||||||
CUDANet::Backend::Tensor tensor_max;
|
CUDANet::Tensor tensor_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CUDANet::Layers
|
} // namespace CUDANet::Layers
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace CUDANet::Layers {
|
namespace CUDANet::Layers {
|
||||||
|
|
||||||
class AvgPooling2d : public SequentialLayer, public TwoDLayer {
|
class AvgPooling2d : public Layer, public TwoDLayer {
|
||||||
public:
|
public:
|
||||||
AvgPooling2d(
|
AvgPooling2d(
|
||||||
shape2d inputSize,
|
shape2d inputSize,
|
||||||
@@ -25,7 +25,7 @@ class AvgPooling2d : public SequentialLayer, public TwoDLayer {
|
|||||||
*
|
*
|
||||||
* @return int output size
|
* @return int output size
|
||||||
*/
|
*/
|
||||||
int getOutputSize();
|
int get_output_size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get input size
|
* @brief Get input size
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#ifndef CUDANET_DENSE_LAYER_H
|
#pragma once
|
||||||
#define CUDANET_DENSE_LAYER_H
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "activation.hpp"
|
#include "backend.hpp"
|
||||||
#include "layer.hpp"
|
#include "layer.hpp"
|
||||||
|
|
||||||
namespace CUDANet::Layers {
|
namespace CUDANet::Layers {
|
||||||
@@ -12,121 +11,42 @@ namespace CUDANet::Layers {
|
|||||||
* @brief Dense (fully connected) layer
|
* @brief Dense (fully connected) layer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class Dense : public WeightedLayer {
|
class Dense : public Layer {
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief Construct a new Dense layer
|
|
||||||
*
|
|
||||||
* @param inputSize Size of the input vector
|
|
||||||
* @param outputSize Size of the output vector
|
|
||||||
* @param activationType Activation function type ('RELU', 'SIGMOID',
|
|
||||||
* 'SOFTMAX' or 'NONE')
|
|
||||||
*/
|
|
||||||
Dense(int inputSize, int outputSize, Layers::ActivationType activationType);
|
|
||||||
|
|
||||||
/**
|
Dense(CUDANet::Backend *backend, CUDANet::Shape input_shape, CUDANet::Shape output_shape);
|
||||||
* @brief Destroy the Dense layer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
~Dense();
|
~Dense();
|
||||||
|
|
||||||
/**
|
CUDANet::Tensor& forward(const CUDANet::Tensor &input) override;
|
||||||
* @brief Forward pass of the dense layer
|
|
||||||
*
|
|
||||||
* @param d_input Device pointer to the input vector
|
|
||||||
* @return Device pointer to the output vector
|
|
||||||
*/
|
|
||||||
float* forward(const float* d_input);
|
|
||||||
|
|
||||||
/**
|
CUDANet::Shape input_shape() override;
|
||||||
* @brief Set the weights of the layer
|
|
||||||
*
|
|
||||||
* @param weights Pointer to vector of weights
|
|
||||||
*/
|
|
||||||
void setWeights(const float* weights);
|
|
||||||
|
|
||||||
/**
|
CUDANet::Shape output_shape() override;
|
||||||
* @brief Get the weights of the layer
|
|
||||||
*
|
|
||||||
* @return Vector of weights
|
|
||||||
*/
|
|
||||||
std::vector<float> getWeights();
|
|
||||||
|
|
||||||
/**
|
size_t input_size() override;
|
||||||
* @brief Set the biases of the layer
|
|
||||||
*
|
|
||||||
* @param biases Pointer to vector of biases
|
|
||||||
*/
|
|
||||||
void setBiases(const float* biases);
|
|
||||||
|
|
||||||
/**
|
size_t output_size() override;
|
||||||
* @brief Get the biases of the layer
|
|
||||||
*
|
|
||||||
* @return Vector of biases
|
|
||||||
*/
|
|
||||||
std::vector<float> getBiases();
|
|
||||||
|
|
||||||
/**
|
void set_weights(void *input) override;
|
||||||
* @brief Get output size
|
|
||||||
*
|
|
||||||
* @return int output size
|
|
||||||
*/
|
|
||||||
int getOutputSize();
|
|
||||||
|
|
||||||
/**
|
CUDANet::Tensor& get_weights() override;
|
||||||
* @brief Get input size
|
|
||||||
*
|
void set_biases(void *input) override;
|
||||||
* @return int input size
|
|
||||||
*/
|
CUDANet::Tensor& get_biases() override;
|
||||||
int getInputSize();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int inputSize;
|
CUDANet::Backend *backend;
|
||||||
int outputSize;
|
|
||||||
|
|
||||||
std::vector<float> weights;
|
CUDANet::Shape in_shape;
|
||||||
std::vector<float> biases;
|
CUDANet::Shape out_shape;
|
||||||
|
|
||||||
Layers::Activation* activation;
|
CUDANet::Tensor weights;
|
||||||
|
CUDANet::Tensor biases;
|
||||||
/**
|
|
||||||
* @brief Initialize the weights to zeros
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void initializeWeights();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize the biases to zeros
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void initializeBiases();
|
|
||||||
|
|
||||||
float* forwardCPU(const float* input);
|
|
||||||
|
|
||||||
#ifdef USE_CUDA
|
|
||||||
float* d_output;
|
|
||||||
|
|
||||||
float* d_weights;
|
|
||||||
float* d_biases;
|
|
||||||
|
|
||||||
// Precompute kernel launch parameters
|
|
||||||
int forwardGridSize;
|
|
||||||
int biasGridSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Copy the weights and biases to the device
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void toCuda();
|
|
||||||
|
|
||||||
void initCUDA();
|
|
||||||
void delCUDA();
|
|
||||||
|
|
||||||
float* forwardCUDA(const float* d_input);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
CUDANet::Tensor output;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CUDANet::Layers
|
} // namespace CUDANet::Layers
|
||||||
|
|
||||||
#endif // CUDANET_DENSE_LAYER_H
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace CUDANet::Layers {
|
|||||||
* @brief Input layer, just copies the input to the device
|
* @brief Input layer, just copies the input to the device
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class Input : public SequentialLayer {
|
class Input : public Layer {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Create a new Input layer
|
* @brief Create a new Input layer
|
||||||
@@ -38,7 +38,7 @@ class Input : public SequentialLayer {
|
|||||||
*
|
*
|
||||||
* @return int output size
|
* @return int output size
|
||||||
*/
|
*/
|
||||||
int getOutputSize();
|
int get_output_size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get input size
|
* @brief Get input size
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
|
|
||||||
#ifndef CUDANET_I_LAYER_H
|
|
||||||
#define CUDANET_I_LAYER_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define CUDANET_SAME_PADDING(inputSize, kernelSize, stride) \
|
|
||||||
((stride - 1) * inputSize - stride + kernelSize) / 2;
|
|
||||||
|
|
||||||
typedef std::pair<int, int> shape2d;
|
|
||||||
|
|
||||||
namespace CUDANet::Layers {
|
|
||||||
|
|
||||||
|
|
||||||
class TwoDLayer {
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual shape2d getOutputDims() = 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Basic Sequential Layer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class SequentialLayer {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Destroy the Sequential Layer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual ~SequentialLayer(){};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Forward propagation virtual function
|
|
||||||
*
|
|
||||||
* @param input Device pointer to the input
|
|
||||||
* @return float* Device pointer to the output
|
|
||||||
*/
|
|
||||||
virtual float* forward(const float* input) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get output size
|
|
||||||
*
|
|
||||||
* @return int output size
|
|
||||||
*/
|
|
||||||
virtual int getOutputSize() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get input size
|
|
||||||
*
|
|
||||||
* @return int input size
|
|
||||||
*/
|
|
||||||
virtual int getInputSize() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Base class for layers with weights and biases
|
|
||||||
*/
|
|
||||||
class WeightedLayer : public SequentialLayer {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Destroy the ILayer object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual ~WeightedLayer(){};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Virtual function for forward pass
|
|
||||||
*
|
|
||||||
* @param input (Device) Pointer to the input
|
|
||||||
* @return float* Device pointer to the output
|
|
||||||
*/
|
|
||||||
virtual float* forward(const float* input) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Virtual function for setting weights
|
|
||||||
*
|
|
||||||
* @param weights Pointer to the weights
|
|
||||||
*/
|
|
||||||
virtual void setWeights(const float* weights) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Virtual function for getting weights
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual std::vector<float> getWeights() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Virtual function for setting biases
|
|
||||||
*
|
|
||||||
* @param biases Pointer to the biases
|
|
||||||
*/
|
|
||||||
virtual void setBiases(const float* biases) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Virtual function for getting biases
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual std::vector<float> getBiases() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* @brief Initialize the weights
|
|
||||||
*/
|
|
||||||
virtual void initializeWeights() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize the biases
|
|
||||||
*/
|
|
||||||
virtual void initializeBiases() = 0;
|
|
||||||
|
|
||||||
#ifdef USE_CUDA
|
|
||||||
/**
|
|
||||||
* @brief Copy the weights and biases to the device
|
|
||||||
*/
|
|
||||||
virtual void toCuda() = 0;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace CUDANet::Layers
|
|
||||||
|
|
||||||
#endif // CUDANET_I_LAYERH
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace CUDANet::Layers {
|
namespace CUDANet::Layers {
|
||||||
|
|
||||||
class MaxPooling2d : public SequentialLayer, public TwoDLayer {
|
class MaxPooling2d : public Layer, public TwoDLayer {
|
||||||
public:
|
public:
|
||||||
MaxPooling2d(
|
MaxPooling2d(
|
||||||
shape2d inputSize,
|
shape2d inputSize,
|
||||||
@@ -25,7 +25,7 @@ class MaxPooling2d : public SequentialLayer, public TwoDLayer {
|
|||||||
*
|
*
|
||||||
* @return int output size
|
* @return int output size
|
||||||
*/
|
*/
|
||||||
int getOutputSize();
|
int get_output_size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get input size
|
* @brief Get input size
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace CUDANet::Layers {
|
namespace CUDANet::Layers {
|
||||||
|
|
||||||
class Output : public SequentialLayer {
|
class Output : public Layer {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Create a new Output layer
|
* @brief Create a new Output layer
|
||||||
@@ -34,7 +34,7 @@ class Output : public SequentialLayer {
|
|||||||
*
|
*
|
||||||
* @return int output size
|
* @return int output size
|
||||||
*/
|
*/
|
||||||
int getOutputSize();
|
int get_output_size();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get input size
|
* @brief Get input size
|
||||||
|
|||||||
9
include/shape.hpp
Normal file
9
include/shape.hpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace CUDANet {
|
||||||
|
|
||||||
|
typedef std::vector<size_t> Shape;
|
||||||
|
|
||||||
|
} // namespace CUDANet
|
||||||
64
include/tensor.hpp
Normal file
64
include/tensor.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "backend.hpp"
|
||||||
|
#include "shape.hpp"
|
||||||
|
|
||||||
|
namespace CUDANet
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class DType
|
||||||
|
{
|
||||||
|
FLOAT32,
|
||||||
|
// FLOAT16, // Not implemented yet
|
||||||
|
// INT32, // Not implemented yet
|
||||||
|
};
|
||||||
|
|
||||||
|
class Tensor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Tensor() = default;
|
||||||
|
Tensor(Shape shape, DType dtype, CUDANet::Backend* backend);
|
||||||
|
|
||||||
|
Tensor(Tensor&& other) noexcept;
|
||||||
|
Tensor& operator=(Tensor&& other) noexcept;
|
||||||
|
Tensor(const Tensor&) = delete;
|
||||||
|
Tensor& operator=(const Tensor&) = delete;
|
||||||
|
|
||||||
|
~Tensor();
|
||||||
|
|
||||||
|
size_t size() const;
|
||||||
|
size_t numel() const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T* data() const {
|
||||||
|
return static_cast<T*>(d_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T* data() {
|
||||||
|
return static_cast<T*>(d_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set_data(T *data) {
|
||||||
|
backend->copy_to_device(*this, data, total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Shape shape;
|
||||||
|
DType dtype;
|
||||||
|
|
||||||
|
size_t total_elms;
|
||||||
|
size_t total_size;
|
||||||
|
|
||||||
|
CUDANet::Backend* backend;
|
||||||
|
void* d_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CUDANet
|
||||||
@@ -28,12 +28,12 @@ cudaDeviceProp initializeCUDA() {
|
|||||||
|
|
||||||
using namespace CUDANet::Backend;
|
using namespace CUDANet::Backend;
|
||||||
|
|
||||||
void* CUDABackend::allocate(size_t bytes) {
|
void* CUDA::allocate(size_t bytes) {
|
||||||
void* d_ptr = nullptr;
|
void* d_ptr = nullptr;
|
||||||
CUDA_CHECK(cudaMalloc(&d_ptr, bytes));
|
CUDA_CHECK(cudaMalloc(&d_ptr, bytes));
|
||||||
return d_ptr;
|
return d_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::deallocate(void* ptr) {
|
void CUDA::deallocate(void* ptr) {
|
||||||
CUDA_CHECK(cudaFree(ptr));
|
CUDA_CHECK(cudaFree(ptr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,29 @@
|
|||||||
#include "backend/cuda.cuh"
|
#include "backend/cuda.cuh"
|
||||||
#include "utils/cuda_helper.cuh"
|
|
||||||
#include "kernels/activation_functions.cuh"
|
#include "kernels/activation_functions.cuh"
|
||||||
#include "kernels/matmul.cuh"
|
#include "kernels/matmul.cuh"
|
||||||
|
#include "utils/cuda_helper.cuh"
|
||||||
|
|
||||||
using namespace CUDANet::Backend;
|
using namespace CUDANet::Backend;
|
||||||
|
|
||||||
void CUDABackend::relu(Tensor &tensor) {
|
void CUDA::relu(Tensor& tensor) {
|
||||||
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
Kernels::relu<<<gridSize, BLOCK_SIZE>>>(tensor.data<float>(), tensor.data<float>(), tensor.numel());
|
Kernels::relu<<<gridSize, BLOCK_SIZE>>>(
|
||||||
|
tensor.data<float>(), tensor.data<float>(), tensor.numel()
|
||||||
|
);
|
||||||
CUDA_CHECK(cudaGetLastError());
|
CUDA_CHECK(cudaGetLastError());
|
||||||
CUDA_CHECK(cudaDeviceSynchronize());
|
CUDA_CHECK(cudaDeviceSynchronize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::sigmoid(Tensor &tensor) {
|
void CUDA::sigmoid(Tensor& tensor) {
|
||||||
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
Kernels::sigmoid<<<gridSize, BLOCK_SIZE>>>(tensor.data<float>(), tensor.data<float>(), tensor.numel());
|
Kernels::sigmoid<<<gridSize, BLOCK_SIZE>>>(
|
||||||
|
tensor.data<float>(), tensor.data<float>(), tensor.numel()
|
||||||
|
);
|
||||||
CUDA_CHECK(cudaGetLastError());
|
CUDA_CHECK(cudaGetLastError());
|
||||||
CUDA_CHECK(cudaDeviceSynchronize());
|
CUDA_CHECK(cudaDeviceSynchronize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::softmax(Tensor &tensor, Tensor &temp_max, Tensor &temp_sum) {
|
void CUDA::softmax(Tensor& tensor, Tensor& temp_max, Tensor& temp_sum) {
|
||||||
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
int gridSize = (tensor.numel() + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
|
||||||
// Find max value
|
// Find max value
|
||||||
@@ -27,7 +31,8 @@ void CUDABackend::softmax(Tensor &tensor, Tensor &temp_max, Tensor &temp_sum) {
|
|||||||
|
|
||||||
// Subtract max value to improve numerical stability
|
// Subtract max value to improve numerical stability
|
||||||
Kernels::vec_scalar_sub<<<gridSize, BLOCK_SIZE>>>(
|
Kernels::vec_scalar_sub<<<gridSize, BLOCK_SIZE>>>(
|
||||||
tensor.data<float>(), tensor.data<float>(), temp_max.data<float>(), tensor.numel()
|
tensor.data<float>(), tensor.data<float>(), temp_max.data<float>(),
|
||||||
|
tensor.numel()
|
||||||
);
|
);
|
||||||
CUDA_CHECK(cudaGetLastError());
|
CUDA_CHECK(cudaGetLastError());
|
||||||
|
|
||||||
@@ -41,8 +46,37 @@ void CUDABackend::softmax(Tensor &tensor, Tensor &temp_max, Tensor &temp_sum) {
|
|||||||
sum(tensor, temp_sum);
|
sum(tensor, temp_sum);
|
||||||
|
|
||||||
Kernels::vec_scalar_div<<<gridSize, BLOCK_SIZE>>>(
|
Kernels::vec_scalar_div<<<gridSize, BLOCK_SIZE>>>(
|
||||||
tensor.data<float>(), tensor.data<float>(), temp_sum.data<float>(), tensor.numel()
|
tensor.data<float>(), tensor.data<float>(), temp_sum.data<float>(),
|
||||||
|
tensor.numel()
|
||||||
);
|
);
|
||||||
CUDA_CHECK(cudaGetLastError());
|
CUDA_CHECK(cudaGetLastError());
|
||||||
CUDA_CHECK(cudaDeviceSynchronize());
|
CUDA_CHECK(cudaDeviceSynchronize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUDANet::Tensor& CUDA::dense(
|
||||||
|
const CUDANet::Tensor& weights,
|
||||||
|
const CUDANet::Tensor& biases,
|
||||||
|
const CUDANet::Tensor& input,
|
||||||
|
CUDANet::Tensor& output,
|
||||||
|
const size_t input_size,
|
||||||
|
const size_t output_size
|
||||||
|
) {
|
||||||
|
auto forwardGridSize =
|
||||||
|
(std::max(input_size, output_size) + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
auto biasGridSize = (output_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
|
||||||
|
Kernels::mat_vec_mul<<<forwardGridSize, BLOCK_SIZE>>>(
|
||||||
|
weights.data<float>(), input.data<float>(), output.data<float>(),
|
||||||
|
input_size, output_size
|
||||||
|
);
|
||||||
|
CUDA_CHECK(cudaGetLastError());
|
||||||
|
|
||||||
|
Kernels::vec_vec_add<<<biasGridSize, BLOCK_SIZE>>>(
|
||||||
|
biases.data<float>(), output.data<float>(), output.data<float>(),
|
||||||
|
output_size
|
||||||
|
);
|
||||||
|
CUDA_CHECK(cudaGetLastError());
|
||||||
|
CUDA_CHECK(cudaDeviceSynchronize());
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "activation.hpp"
|
|
||||||
#include "activation_functions.cuh"
|
|
||||||
#include "cuda_helper.cuh"
|
|
||||||
#include "matmul.cuh"
|
|
||||||
#include "vector.cuh"
|
|
||||||
|
|
||||||
using namespace CUDANet::Layers;
|
|
||||||
|
|
||||||
void Activation::initCUDA() {
|
|
||||||
if (activationType == SOFTMAX) {
|
|
||||||
d_softmax_sum = nullptr;
|
|
||||||
CUDA_CHECK(cudaMalloc((void**)&d_softmax_sum, sizeof(float) * length));
|
|
||||||
|
|
||||||
d_max = nullptr;
|
|
||||||
CUDA_CHECK(cudaMalloc((void**)&d_max, sizeof(float) * length));
|
|
||||||
}
|
|
||||||
|
|
||||||
gridSize = (length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Activation::delCUDA() {
|
|
||||||
if (activationType == SOFTMAX) {
|
|
||||||
CUDA_CHECK(cudaFree(d_softmax_sum));
|
|
||||||
CUDA_CHECK(cudaFree(d_max));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Activation::activateCUDA(float* d_input) {
|
|
||||||
|
|
||||||
// float sum = 0.0f;
|
|
||||||
|
|
||||||
switch (activationType) {
|
|
||||||
case SIGMOID:
|
|
||||||
Kernels::sigmoid<<<gridSize, BLOCK_SIZE>>>(
|
|
||||||
d_input, d_input, length
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RELU:
|
|
||||||
Kernels::relu<<<gridSize, BLOCK_SIZE>>>(d_input, d_input, length);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
break;
|
|
||||||
case SOFTMAX:
|
|
||||||
|
|
||||||
// Find max value
|
|
||||||
Utils::max(d_input, d_max, length);
|
|
||||||
|
|
||||||
// Subtract max value to improve numerical stability
|
|
||||||
Kernels::vec_scalar_sub<<<gridSize, BLOCK_SIZE>>>(
|
|
||||||
d_input, d_input, &d_max[0], length
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
|
|
||||||
// Compute exponentials
|
|
||||||
Kernels::vec_exp<<<gridSize, BLOCK_SIZE>>>(
|
|
||||||
d_input, d_input, length
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
|
|
||||||
// Find sum
|
|
||||||
Utils::sum(d_input, d_softmax_sum, length);
|
|
||||||
|
|
||||||
Kernels::vec_scalar_div<<<gridSize, BLOCK_SIZE>>>(
|
|
||||||
d_input, d_input, &d_softmax_sum[0], length
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CUDA_CHECK(cudaDeviceSynchronize());
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <cuda_runtime.h>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <functional>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "vector.cuh"
|
|
||||||
#include "activation.hpp"
|
|
||||||
#include "cuda_helper.cuh"
|
|
||||||
#include "dense.hpp"
|
|
||||||
#include "matmul.cuh"
|
|
||||||
|
|
||||||
using namespace CUDANet::Layers;
|
|
||||||
|
|
||||||
void Dense::initCUDA() {
|
|
||||||
d_output = nullptr;
|
|
||||||
|
|
||||||
CUDA_CHECK(cudaMalloc((void**)&d_output, sizeof(float) * outputSize));
|
|
||||||
|
|
||||||
d_weights = nullptr;
|
|
||||||
d_biases = nullptr;
|
|
||||||
|
|
||||||
// Allocate GPU memory for weights and biases
|
|
||||||
CUDA_CHECK(
|
|
||||||
cudaMalloc((void**)&d_weights, sizeof(float) * inputSize * outputSize)
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaMalloc((void**)&d_biases, sizeof(float) * outputSize));
|
|
||||||
toCuda();
|
|
||||||
|
|
||||||
// Calculate block and grid sizes
|
|
||||||
forwardGridSize =
|
|
||||||
(std::max(inputSize, outputSize) + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
|
||||||
biasGridSize = (outputSize + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dense::delCUDA() {
|
|
||||||
cudaFree(d_output);
|
|
||||||
cudaFree(d_weights);
|
|
||||||
cudaFree(d_biases);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dense::toCuda() {
|
|
||||||
CUDA_CHECK(cudaMemcpy(
|
|
||||||
d_weights, weights.data(), sizeof(float) * inputSize * outputSize,
|
|
||||||
cudaMemcpyHostToDevice
|
|
||||||
));
|
|
||||||
CUDA_CHECK(cudaMemcpy(
|
|
||||||
d_biases, biases.data(), sizeof(float) * outputSize,
|
|
||||||
cudaMemcpyHostToDevice
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
float* Dense::forwardCUDA(const float* d_input) {
|
|
||||||
Kernels::mat_vec_mul<<<forwardGridSize, BLOCK_SIZE>>>(
|
|
||||||
d_weights, d_input, d_output, inputSize, outputSize
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
|
|
||||||
Kernels::vec_vec_add<<<biasGridSize, BLOCK_SIZE>>>(
|
|
||||||
d_biases, d_output, d_output, outputSize
|
|
||||||
);
|
|
||||||
CUDA_CHECK(cudaGetLastError());
|
|
||||||
|
|
||||||
activation->activate(d_output);
|
|
||||||
CUDA_CHECK(cudaDeviceSynchronize());
|
|
||||||
|
|
||||||
return d_output;
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "backend/backend.hpp"
|
#include "backend.hpp"
|
||||||
#include "backend/cuda.cuh"
|
#include "backend/cuda.cuh"
|
||||||
#include "utils/cuda_helper.cuh"
|
#include "utils/cuda_helper.cuh"
|
||||||
#include "kernels/matmul.cuh"
|
#include "kernels/matmul.cuh"
|
||||||
|
|
||||||
using namespace CUDANet::Backend;
|
using namespace CUDANet::Backend;
|
||||||
|
|
||||||
void CUDABackend::print(const CUDANet::Backend::Tensor &input) {
|
void CUDA::print(const CUDANet::Tensor &input) {
|
||||||
auto length = input.numel();
|
auto length = input.numel();
|
||||||
std::vector<float> h_vec(input.numel());
|
std::vector<float> h_vec(input.numel());
|
||||||
|
|
||||||
@@ -22,11 +22,15 @@ void CUDABackend::print(const CUDANet::Backend::Tensor &input) {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::clear(CUDANet::Backend::Tensor &input) {
|
void CUDA::zero(CUDANet::Tensor &input) {
|
||||||
CUDA_CHECK(cudaMemset(input.data<float>(), 0, sizeof(float) * input.numel()));
|
CUDA_CHECK(cudaMemset(input.data<float>(), 0, sizeof(float) * input.numel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::sum(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &sum) {
|
void CUDA::copy_to_device(CUDANet::Tensor &tensor, void *data, size_t size) {
|
||||||
|
CUDA_CHECK(cudaMemcpy(tensor.data<float>(), data, size, cudaMemcpyHostToDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUDA::sum(const CUDANet::Tensor &input, CUDANet::Tensor &sum) {
|
||||||
auto length = input.numel();
|
auto length = input.numel();
|
||||||
const int gridSize = ( + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
const int gridSize = ( + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ void CUDABackend::sum(const CUDANet::Backend::Tensor &input, CUDANet::Backend::T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUDABackend::max(const CUDANet::Backend::Tensor &input, CUDANet::Backend::Tensor &max) {
|
void CUDA::max(const CUDANet::Tensor &input, CUDANet::Tensor &max) {
|
||||||
auto length = input.numel();
|
auto length = input.numel();
|
||||||
const int grid_size = (length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
const int grid_size = (length + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#include "backend/tensor.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
using namespace CUDANet::Backend;
|
|
||||||
|
|
||||||
Tensor::Tensor(Shape shape, DType dtype, IBackend* backend)
|
|
||||||
: shape(shape), dtype(dtype), backend(backend), d_ptr(nullptr) {
|
|
||||||
// Count total elements
|
|
||||||
size_t count = 1;
|
|
||||||
for (const auto& dim : shape) {
|
|
||||||
count *= dim;
|
|
||||||
}
|
|
||||||
total_elms = count;
|
|
||||||
|
|
||||||
// Compute total size (bytes)
|
|
||||||
size_t type_size = 0;
|
|
||||||
switch (dtype) {
|
|
||||||
case DType::FLOAT32:
|
|
||||||
type_size = 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unsupported data type");
|
|
||||||
}
|
|
||||||
total_size = total_elms * type_size;
|
|
||||||
|
|
||||||
// Allocate memory on backend
|
|
||||||
d_ptr = backend->allocate(total_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tensor::~Tensor() {
|
|
||||||
backend->deallocate(d_ptr);
|
|
||||||
d_ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Tensor::numel() const {
|
|
||||||
return total_elms;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Tensor::size() const {
|
|
||||||
return total_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T* Tensor::data() const {
|
|
||||||
return static_cast<T*>(d_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T* Tensor::data() {
|
|
||||||
return static_cast<T*>(d_ptr);
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,28 @@
|
|||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "activation.hpp"
|
#include "activation.hpp"
|
||||||
#include "backend/tensor.hpp"
|
#include "tensor.hpp"
|
||||||
|
|
||||||
using namespace CUDANet::Layers;
|
using namespace CUDANet::Layers;
|
||||||
|
|
||||||
Activation::Activation(CUDANet::Backend::IBackend* backend, ActivationType activation, const int length)
|
Activation::Activation(CUDANet::Backend* backend, ActivationType activation, const CUDANet::Shape &shape)
|
||||||
: backend(backend), activationType(activation), length(length) {
|
: backend(backend), activationType(activation), shape(shape) {
|
||||||
|
|
||||||
|
if (shape.size() != 1) {
|
||||||
|
throw std::runtime_error(std::format("Invalid shape. Expected [1], got {}", shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto length = shape[0];
|
||||||
|
|
||||||
if (activationType == SOFTMAX) {
|
if (activationType == SOFTMAX) {
|
||||||
softmax_sum = CUDANet::Backend::Tensor({static_cast<size_t>(length)}, CUDANet::Backend::DType::FLOAT32, backend);
|
softmax_sum = CUDANet::Tensor({static_cast<size_t>(length)}, CUDANet::DType::FLOAT32, backend);
|
||||||
tensor_max = CUDANet::Backend::Tensor({static_cast<size_t>(length)}, CUDANet::Backend::DType::FLOAT32, backend);
|
tensor_max = CUDANet::Tensor({static_cast<size_t>(length)}, CUDANet::DType::FLOAT32, backend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activation::activate(CUDANet::Backend::Tensor input) {
|
CUDANet::Tensor& Activation::forward(CUDANet::Tensor &input) {
|
||||||
switch (activationType)
|
switch (activationType)
|
||||||
{
|
{
|
||||||
case ActivationType::SIGMOID:
|
case ActivationType::SIGMOID:
|
||||||
@@ -31,4 +37,30 @@ void Activation::activate(CUDANet::Backend::Tensor input) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUDANet::Shape Activation::input_shape() {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDANet::Shape Activation::output_shape() {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Activation::input_size() {
|
||||||
|
return shape[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Activation::output_size() {
|
||||||
|
return shape[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Activation::set_weights(void *input) {}
|
||||||
|
|
||||||
|
CUDANet::Tensor& Activation::get_weights() {}
|
||||||
|
|
||||||
|
void Activation::set_biases(void *input) {}
|
||||||
|
|
||||||
|
CUDANet::Tensor& Activation::get_biases() {}
|
||||||
@@ -54,7 +54,7 @@ float* AvgPooling2d::forward(const float* input) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int AvgPooling2d::getOutputSize() {
|
int AvgPooling2d::get_output_size() {
|
||||||
return outputSize.first * outputSize.second * nChannels;
|
return outputSize.first * outputSize.second * nChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +1,75 @@
|
|||||||
#include "dense.hpp"
|
#include "dense.hpp"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "activation.hpp"
|
|
||||||
|
|
||||||
using namespace CUDANet::Layers;
|
using namespace CUDANet::Layers;
|
||||||
|
|
||||||
Dense::Dense(int inputSize, int outputSize, ActivationType activationType)
|
Dense::Dense(CUDANet::Backend* backend, CUDANet::Shape in, CUDANet::Shape out)
|
||||||
: inputSize(inputSize), outputSize(outputSize) {
|
: backend(backend),
|
||||||
|
in_shape(in),
|
||||||
|
out_shape(out),
|
||||||
|
weights(
|
||||||
|
CUDANet::Tensor(Shape{in[0] * out[0]}, CUDANet::DType::FLOAT32, backend)
|
||||||
|
),
|
||||||
|
biases(CUDANet::Tensor(Shape{out[0]}, CUDANet::DType::FLOAT32, backend)),
|
||||||
|
output(CUDANet::Tensor(Shape{out[0]}, CUDANet::DType::FLOAT32, backend)) {
|
||||||
// Allocate memory for weights and biases
|
// Allocate memory for weights and biases
|
||||||
weights.resize(outputSize * inputSize);
|
|
||||||
biases.resize(outputSize);
|
|
||||||
|
|
||||||
initializeWeights();
|
if (in.size() != 1) {
|
||||||
initializeBiases();
|
throw std::runtime_error(
|
||||||
|
std::format("Invalid shape. Expected [1], got {}", in)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
activation = new Activation(activationType, outputSize);
|
if (out.size() != 1) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::format("Invalid shape. Expected [1], got {}", out)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_CUDA
|
auto input_len = in[0];
|
||||||
initCUDA();
|
auto output_len = out[0];
|
||||||
#endif
|
|
||||||
|
weights.zero();
|
||||||
|
biases.zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dense::~Dense() {
|
Dense::~Dense() {}
|
||||||
delete activation;
|
|
||||||
#ifdef USE_CUDA
|
CUDANet::Tensor& Dense::forward(const CUDANet::Tensor& input) {
|
||||||
delCUDA();
|
backend->dense(weights, biases, input, output, in_shape[0], out_shape[0]);
|
||||||
#endif
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dense::initializeWeights() {
|
CUDANet::Shape Dense::input_shape() {
|
||||||
std::fill(weights.begin(), weights.end(), 0.0f);
|
return in_shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dense::initializeBiases() {
|
CUDANet::Shape Dense::output_shape() {
|
||||||
std::fill(biases.begin(), biases.end(), 0.0f);
|
return out_shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
float* Dense::forwardCPU(const float* input) {
|
size_t Dense::input_size() {
|
||||||
throw std::logic_error("Not implemented");
|
return in_shape[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t Dense::output_size() {
|
||||||
|
return out_shape[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
void Dense::set_weights(void* input) {
|
||||||
|
weights.set_data<float>(static_cast<float*>(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
float* Dense::forward(const float* input) {
|
CUDANet::Tensor& Dense::get_weights() {
|
||||||
#ifdef USE_CUDA
|
|
||||||
return forwardCUDA(input);
|
|
||||||
#else
|
|
||||||
return forwardCPU(input);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dense::setWeights(const float* weights_input) {
|
|
||||||
std::copy(weights_input, weights_input + weights.size(), weights.begin());
|
|
||||||
#ifdef USE_CUDA
|
|
||||||
toCuda();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<float> Dense::getWeights() {
|
|
||||||
return weights;
|
return weights;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dense::setBiases(const float* biases_input) {
|
void Dense::set_biases(void* input) {
|
||||||
std::copy(biases_input, biases_input + biases.size(), biases.begin());
|
biases.set_data<float>(static_cast<float*>(input));
|
||||||
#ifdef USE_CUDA
|
|
||||||
toCuda();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<float> Dense::getBiases() {
|
CUDANet::Tensor& Dense::get_biases() {
|
||||||
return biases;
|
return biases;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Dense::getOutputSize() {
|
|
||||||
return outputSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Dense::getInputSize() {
|
|
||||||
return inputSize;
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,7 @@ float* Input::forward(const float* input) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int Input::getOutputSize() {
|
int Input::get_output_size() {
|
||||||
return inputSize;
|
return inputSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ float* MaxPooling2d::forward(const float* input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MaxPooling2d::getOutputSize() {
|
int MaxPooling2d::get_output_size() {
|
||||||
return outputSize.first * outputSize.second * nChannels;
|
return outputSize.first * outputSize.second * nChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ float* Output::forward(const float* input) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int Output::getOutputSize() {
|
int Output::get_output_size() {
|
||||||
return inputSize;
|
return inputSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
src/tensor.cpp
Normal file
87
src/tensor.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "tensor.hpp"
|
||||||
|
|
||||||
|
using namespace CUDANet;
|
||||||
|
|
||||||
|
Tensor::Tensor(Shape shape, DType dtype, Backend* backend)
|
||||||
|
: shape(shape), dtype(dtype), backend(backend), d_ptr(nullptr) {
|
||||||
|
|
||||||
|
if (shape.empty()) {
|
||||||
|
throw std::runtime_error("Tensor shape cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count total elements
|
||||||
|
size_t count = 1;
|
||||||
|
for (const auto& dim : shape) {
|
||||||
|
count *= dim;
|
||||||
|
}
|
||||||
|
total_elms = count;
|
||||||
|
|
||||||
|
// Compute total size (bytes)
|
||||||
|
size_t type_size = 0;
|
||||||
|
switch (dtype) {
|
||||||
|
case DType::FLOAT32:
|
||||||
|
type_size = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unsupported data type");
|
||||||
|
}
|
||||||
|
total_size = total_elms * type_size;
|
||||||
|
|
||||||
|
// Allocate memory on backend
|
||||||
|
d_ptr = backend->allocate(total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tensor::Tensor(Tensor&& other) noexcept
|
||||||
|
: shape(std::move(other.shape)),
|
||||||
|
dtype(other.dtype),
|
||||||
|
total_elms(other.total_elms),
|
||||||
|
total_size(other.total_size),
|
||||||
|
backend(other.backend),
|
||||||
|
d_ptr(other.d_ptr)
|
||||||
|
{
|
||||||
|
other.d_ptr = nullptr;
|
||||||
|
other.backend = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tensor& Tensor::operator=(Tensor&& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
// Clean up our current resources
|
||||||
|
if (d_ptr != nullptr && backend != nullptr) {
|
||||||
|
backend->deallocate(d_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steal other's resources
|
||||||
|
shape = std::move(other.shape);
|
||||||
|
dtype = other.dtype;
|
||||||
|
total_elms = other.total_elms;
|
||||||
|
total_size = other.total_size;
|
||||||
|
backend = other.backend;
|
||||||
|
d_ptr = other.d_ptr;
|
||||||
|
|
||||||
|
// Leave other in valid but empty state
|
||||||
|
other.d_ptr = nullptr;
|
||||||
|
other.backend = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tensor::~Tensor() {
|
||||||
|
if (backend && d_ptr) {
|
||||||
|
backend->deallocate(d_ptr);
|
||||||
|
d_ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Tensor::numel() const {
|
||||||
|
return total_elms;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Tensor::size() const {
|
||||||
|
return total_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tensor::zero() {
|
||||||
|
backend->zero(*this);
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ class AvgPoolingLayerTest : public ::testing::Test {
|
|||||||
|
|
||||||
d_output = avgPoolingLayer->forward(d_input);
|
d_output = avgPoolingLayer->forward(d_input);
|
||||||
|
|
||||||
int outputSize = avgPoolingLayer->getOutputSize();
|
int outputSize = avgPoolingLayer->get_output_size();
|
||||||
|
|
||||||
std::vector<float> output(outputSize);
|
std::vector<float> output(outputSize);
|
||||||
cudaStatus = cudaMemcpy(
|
cudaStatus = cudaMemcpy(
|
||||||
@@ -229,7 +229,7 @@ class AdaptiveAvgPoolingLayerTest : public ::testing::Test {
|
|||||||
|
|
||||||
d_output = adaptiveAvgPoolingLayer->forward(d_input);
|
d_output = adaptiveAvgPoolingLayer->forward(d_input);
|
||||||
|
|
||||||
int outputSize = adaptiveAvgPoolingLayer->getOutputSize();
|
int outputSize = adaptiveAvgPoolingLayer->get_output_size();
|
||||||
|
|
||||||
std::vector<float> output(outputSize);
|
std::vector<float> output(outputSize);
|
||||||
cudaStatus = cudaMemcpy(
|
cudaStatus = cudaMemcpy(
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class MaxPoolingLayerTest : public ::testing::Test {
|
|||||||
|
|
||||||
d_output = maxPoolingLayer->forward(d_input);
|
d_output = maxPoolingLayer->forward(d_input);
|
||||||
|
|
||||||
int outputSize = maxPoolingLayer->getOutputSize();
|
int outputSize = maxPoolingLayer->get_output_size();
|
||||||
|
|
||||||
std::vector<float> output(outputSize);
|
std::vector<float> output(outputSize);
|
||||||
cudaStatus = cudaMemcpy(
|
cudaStatus = cudaMemcpy(
|
||||||
|
|||||||
Reference in New Issue
Block a user