Files
CUDANet/test/layers/test_conv2d.cu
2024-03-11 20:39:44 +01:00

206 lines
6.3 KiB
Plaintext

#include <cuda_runtime_api.h>
#include <gtest/gtest.h>
#include <iostream>
#include "conv2d.cuh"
class Conv2dTest : public ::testing::Test {
protected:
Layers::Conv2d commonTestSetup(
int inputSize,
int inputChannels,
int kernelSize,
int stride,
Padding padding,
int numFilters,
Activation activation,
std::vector<float>& input,
float* kernels,
float*& d_input,
float*& d_output
) {
// Create Conv2d layer
Layers::Conv2d conv2d(
inputSize, inputChannels, kernelSize, stride, padding, numFilters,
activation
);
conv2d.setWeights(kernels);
// Allocate device memory
cudaStatus = cudaMalloc(
(void**)&d_input,
sizeof(float) * inputSize * inputSize * inputChannels
);
EXPECT_EQ(cudaStatus, cudaSuccess);
cudaStatus = cudaMalloc(
(void**)&d_output,
sizeof(float) * conv2d.outputSize * conv2d.outputSize * numFilters
);
EXPECT_EQ(cudaStatus, cudaSuccess);
// // Copy input to device
cudaStatus = cudaMemcpy(
d_input, input.data(), sizeof(float) * input.size(),
cudaMemcpyHostToDevice
);
EXPECT_EQ(cudaStatus, cudaSuccess);
return conv2d;
}
void commonTestTeardown(float* d_input, float* d_output) {
// Free device memory
cudaFree(d_input);
cudaFree(d_output);
}
cudaError_t cudaStatus;
};
TEST_F(Conv2dTest, SimpleTest) {
int inputSize = 4;
int inputChannels = 1;
int kernelSize = 2;
int stride = 1;
Padding padding = VALID;
int numFilters = 1;
Activation activation = LINEAR;
std::vector<float> input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f,
13.0f, 14.0f, 15.0f, 16.0f};
std::vector<float> kernels = {
1.0f,
2.0f,
3.0f,
4.0f,
};
float* d_input;
float* d_output;
Layers::Conv2d conv2d = commonTestSetup(
inputSize, inputChannels, kernelSize, stride, padding, numFilters,
activation, input, kernels.data(), d_input, d_output
);
int outputSize = (inputSize - kernelSize) / stride + 1;
EXPECT_EQ(outputSize, conv2d.outputSize);
conv2d.forward(d_input, d_output);
std::vector<float> expected = {44.0f, 54.0f, 64.0f, 84.0f, 94.0f,
104.0f, 124.0f, 134.0f, 144.0f};
std::vector<float> output(outputSize * outputSize * numFilters);
cudaStatus = cudaMemcpy(
output.data(), d_output, sizeof(float) * output.size(),
cudaMemcpyDeviceToHost
);
EXPECT_EQ(cudaStatus, cudaSuccess);
for (int i = 0; i < output.size(); ++i) {
EXPECT_FLOAT_EQ(expected[i], output[i]);
}
commonTestTeardown(d_input, d_output);
}
TEST_F(Conv2dTest, ComplexTest) {
int inputSize = 5;
int inputChannels = 3;
int kernelSize = 3;
int stride = 1;
Padding padding = SAME;
int numFilters = 2;
Activation activation = LINEAR;
// clang-format off
std::vector<float> input = {
// Channel 1
0.823f, 0.217f, 0.435f, 0.981f, 0.742f,
0.109f, 0.518f, 0.374f, 0.681f, 0.147f,
0.956f, 0.729f, 0.654f, 0.087f, 0.392f,
0.784f, 0.921f, 0.543f, 0.231f, 0.816f,
0.472f, 0.614f, 0.102f, 0.987f, 0.398f,
// Channel 2
0.051f, 0.756f, 0.841f, 0.293f, 0.128f,
0.417f, 0.632f, 0.095f, 0.184f, 0.529f,
0.871f, 0.958f, 0.213f, 0.347f, 0.725f,
0.461f, 0.012f, 0.278f, 0.195f, 0.649f,
0.853f, 0.707f, 0.988f, 0.988f, 0.322f,
// Channel 3
0.345f, 0.123f, 0.789f, 0.123f, 0.456f,
0.456f, 0.789f, 0.123f, 0.345f, 0.123f,
0.789f, 0.123f, 0.345f, 0.123f, 0.456f,
0.123f, 0.345f, 0.123f, 0.789f, 0.123f,
0.345f, 0.123f, 0.789f, 0.123f, 0.456f
};
std::vector<float> kernels = {
// Filter 1, Channel 1
0.128f, 0.754f, 0.987f,
0.321f, 0.412f, 0.635f,
0.298f, 0.017f, 0.845f,
// Filter 1, Channel 2
0.514f, 0.729f, 0.952f,
0.684f, 0.378f, 0.159f,
0.823f, 0.547f, 0.216f,
// Filter 1, Channel 3
0.983f, 0.231f, 0.456f,
0.178f, 0.654f, 0.821f,
0.345f, 0.987f, 0.123f,
// Filter 2, Channel 1
0.789f, 0.543f, 0.210f,
0.012f, 0.371f, 0.638f,
0.456f, 0.198f, 0.907f,
// Filter 2, Channel 2
0.101f, 0.432f, 0.759f,
0.234f, 0.567f, 0.890f,
0.543f, 0.876f, 0.219f,
// Filter 2, Channel 3
0.345f, 0.678f, 0.011f,
0.678f, 0.011f, 0.345f,
0.011f, 0.345f, 0.678f
};
// clang-format on
float* d_input;
float* d_output;
Layers::Conv2d conv2d = commonTestSetup(
inputSize, inputChannels, kernelSize, stride, padding, numFilters,
activation, input, kernels.data(), d_input, d_output
);
EXPECT_EQ(inputSize, conv2d.outputSize);
conv2d.forward(d_input, d_output);
std::vector<float> output(
conv2d.outputSize * conv2d.outputSize * numFilters
);
cudaMemcpy(
output.data(), d_output,
sizeof(float) * conv2d.outputSize * conv2d.outputSize * numFilters,
cudaMemcpyDeviceToHost
);
// Generated by tools/generate_conv2d_test.py
std::vector<float> expected = {
2.29426f, 3.89173f, 4.17634f, 3.25501f, 2.07618f, 5.41483f, 7.09971f,
6.39811f, 5.71432f, 3.10928f, 5.12973f, 6.29638f, 5.26962f, 5.21997f,
3.05852f, 6.17517f, 7.19311f, 6.69771f, 6.2142f, 4.03242f, 3.3792f,
4.36444f, 4.396f, 4.69905f, 3.62061f, 2.87914f, 3.71743f, 3.51854f,
2.98413f, 1.46579f, 4.94951f, 6.18983f, 4.98187f, 4.38372f, 3.35386f,
5.0364f, 5.3756f, 4.05993f, 4.89299f, 2.78625f, 5.33763f, 5.80899f,
5.89785f, 5.51095f, 3.74287f, 2.64053f, 4.05895f, 3.96482f, 4.30177f,
1.94269f
};
for (int i = 0; i < output.size(); i++) {
EXPECT_NEAR(output[i], expected[i], 0.0001f);
}
}