#include #include #include #include #include #include "config.h" #include "tensor.hpp" #include "ConstantTensorDescriptor.hip.hpp" #include "conv_common.hip.hpp" //#include "device_direct_convolution_1.hpp" #include "device_direct_convolution_2_nchw_kcyx_nkhw.hpp" //#include "device_direct_convolution_2_vectorized_nchw_kcyx_nkhw.hpp" #include "device_implicit_gemm_convolution_1_chwn_cyxk_khwn.hpp" //#include "device_implicit_gemm_convolution_1_chwn_cyxk_khwn_padded.hpp" #include "device_implicit_gemm_convolution_2_chwn_cyxk_khwn.hpp" struct GeneratorTensor_1 { template double operator()(Is... is) { return 1; } }; struct GeneratorTensor_2 { int min_value = 0; int max_value = 1; template double operator()(Is...) { return (std::rand() % (max_value - min_value)) + min_value; } }; struct GeneratorTensor_Checkboard { template double operator()(Ts... Xs) const { std::array dims = {{static_cast(Xs)...}}; return std::accumulate(dims.begin(), dims.end(), true, [](bool init, index_t x) -> int { return init != (x % 2); }) ? 1 : -1; } }; // this is ugly, only for 4d template void ostream_ConstantTensorDescriptor(TConstTensorDesc, std::ostream& os = std::cout) { static_assert(TConstTensorDesc::nDim == 4, "nDim is not 4"); constexpr auto I0 = Number<0>{}; constexpr auto I1 = Number<1>{}; constexpr auto I2 = Number<2>{}; constexpr auto I3 = Number<3>{}; constexpr auto desc = TConstTensorDesc{}; os << "Lengths: {" << desc.GetLength(I0) << ", " << desc.GetLength(I1) << ", " << desc.GetLength(I2) << ", " << desc.GetLength(I3) << "}, " << "Strides: {" << desc.GetStride(I0) << ", " << desc.GetStride(I1) << ", " << desc.GetStride(I2) << ", " << desc.GetStride(I3) << "}" << std::endl; } // this is ugly, only for 4d template auto make_TensorDescriptor(TConstTensorDesc) { static_assert(TConstTensorDesc::nDim == 4, "nDim is not 4"); constexpr auto I0 = Number<0>{}; constexpr auto I1 = Number<1>{}; constexpr auto I2 = Number<2>{}; constexpr auto I3 = Number<3>{}; constexpr auto desc = TConstTensorDesc{}; std::initializer_list lengths = { desc.GetLength(I0), desc.GetLength(I1), desc.GetLength(I2), desc.GetLength(I3)}; std::initializer_list strides = { desc.GetStride(I0), desc.GetStride(I1), desc.GetStride(I2), desc.GetStride(I3)}; return TensorDescriptor(lengths, strides); } template void host_direct_convolution(const Tensor& in_nchw, const Tensor& wei_kcyx, Tensor& out_nkhw, LowerPads, UpperPads) { index_t h_pad_low = LowerPads{}.Get(Number<0>{}); index_t w_pad_low = LowerPads{}.Get(Number<1>{}); index_t h_pad_up = UpperPads{}.Get(Number<0>{}); index_t w_pad_up = UpperPads{}.Get(Number<1>{}); auto f = [&](auto n, auto k, auto ho, auto wo) { double v = 0; for(int c = 0; c < wei_kcyx.mDesc.GetLengths()[1]; ++c) { for(int y = 0; y < wei_kcyx.mDesc.GetLengths()[2]; ++y) { int hi = ho + y - h_pad_low; for(int x = 0; x < wei_kcyx.mDesc.GetLengths()[3]; ++x) { int wi = wo + x - w_pad_low; if(hi >= 0 && hi < in_nchw.mDesc.GetLengths()[2] && wi >= 0 && wi < in_nchw.mDesc.GetLengths()[3]) { v += double(in_nchw(n, c, hi, wi)) * double(wei_kcyx(k, c, y, x)); } } } } out_nkhw(n, k, ho, wo) = v; }; auto f_par = make_ParallelTensorFunctor(f, out_nkhw.mDesc.GetLengths()[0], out_nkhw.mDesc.GetLengths()[1], out_nkhw.mDesc.GetLengths()[2], out_nkhw.mDesc.GetLengths()[3]); f_par(std::thread::hardware_concurrency()); } template void host_winograd_3x3_convolution(const Tensor& in_nchw, const Tensor& wei_kcyx, Tensor& out_nkhw, LowerPads, UpperPads) { constexpr std::size_t HoPerTile = 2; constexpr std::size_t WoPerTile = 2; std::size_t N = in_nchw.mDesc.GetLengths()[0]; std::size_t C = in_nchw.mDesc.GetLengths()[1]; std::size_t HI = in_nchw.mDesc.GetLengths()[2]; std::size_t WI = in_nchw.mDesc.GetLengths()[3]; std::size_t K = wei_kcyx.mDesc.GetLengths()[0]; std::size_t Y = wei_kcyx.mDesc.GetLengths()[2]; std::size_t X = wei_kcyx.mDesc.GetLengths()[3]; std::size_t HO = out_nkhw.mDesc.GetLengths()[2]; std::size_t WO = out_nkhw.mDesc.GetLengths()[3]; index_t h_pad_low = LowerPads{}.Get(Number<0>{}); index_t w_pad_low = LowerPads{}.Get(Number<1>{}); index_t h_pad_up = UpperPads{}.Get(Number<0>{}); index_t w_pad_up = UpperPads{}.Get(Number<1>{}); std::size_t HiPerTile = HoPerTile + Y - 1; std::size_t WiPerTile = WoPerTile + X - 1; std::size_t HTile = (HO + HoPerTile - 1) / HoPerTile; std::size_t WTile = (WO + WoPerTile - 1) / WoPerTile; Tensor in_hold({N, C, HTile, WTile, HiPerTile, WiPerTile}); Tensor in_transform({N, C, HTile, WTile, HiPerTile, WiPerTile}); Tensor wei_transform({K, C, HiPerTile, WiPerTile}); Tensor out_transform({N, K, HTile, WTile, HiPerTile, HiPerTile}); Tensor out_hold({N, K, HTile, WTile, HoPerTile, WoPerTile}); auto f_in_hold = [&](auto n, auto c, auto htile, auto wtile) { for(int j = 0; j < HiPerTile; ++j) { int hi = HoPerTile * htile + j - h_pad_low; for(int i = 0; i < WiPerTile; ++i) { int wi = WoPerTile * wtile + i - w_pad_low; if(hi >= 0 && hi < in_nchw.mDesc.GetLengths()[2] && wi >= 0 && wi < in_nchw.mDesc.GetLengths()[3]) { in_hold(n, c, htile, wtile, j, i) = in_nchw(n, c, hi, wi); } else { in_hold(n, c, htile, wtile, j, i) = TIn(0); } } } }; auto f_in_transform = [&](auto n, auto c, auto htile, auto wtile) { in_transform(n, c, htile, wtile, 0, 0) = in_hold(n, c, htile, wtile, 0, 0) - in_hold(n, c, htile, wtile, 0, 2) - in_hold(n, c, htile, wtile, 2, 0) + in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 0, 1) = in_hold(n, c, htile, wtile, 0, 1) + in_hold(n, c, htile, wtile, 0, 2) - in_hold(n, c, htile, wtile, 2, 1) - in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 0, 2) = -in_hold(n, c, htile, wtile, 0, 1) + in_hold(n, c, htile, wtile, 0, 2) + in_hold(n, c, htile, wtile, 2, 1) - in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 0, 3) = in_hold(n, c, htile, wtile, 0, 1) - in_hold(n, c, htile, wtile, 0, 3) - in_hold(n, c, htile, wtile, 2, 1) + in_hold(n, c, htile, wtile, 2, 3); in_transform(n, c, htile, wtile, 1, 0) = in_hold(n, c, htile, wtile, 1, 0) - in_hold(n, c, htile, wtile, 1, 2) + in_hold(n, c, htile, wtile, 2, 0) - in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 1, 1) = in_hold(n, c, htile, wtile, 1, 1) + in_hold(n, c, htile, wtile, 1, 2) + in_hold(n, c, htile, wtile, 2, 1) + in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 1, 2) = -in_hold(n, c, htile, wtile, 1, 1) + in_hold(n, c, htile, wtile, 1, 2) - in_hold(n, c, htile, wtile, 2, 1) + in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 1, 3) = in_hold(n, c, htile, wtile, 1, 1) - in_hold(n, c, htile, wtile, 1, 3) + in_hold(n, c, htile, wtile, 2, 1) - in_hold(n, c, htile, wtile, 2, 3); in_transform(n, c, htile, wtile, 2, 0) = -in_hold(n, c, htile, wtile, 1, 0) + in_hold(n, c, htile, wtile, 1, 2) + in_hold(n, c, htile, wtile, 2, 0) - in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 2, 1) = -in_hold(n, c, htile, wtile, 1, 1) - in_hold(n, c, htile, wtile, 1, 2) + in_hold(n, c, htile, wtile, 2, 1) + in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 2, 2) = in_hold(n, c, htile, wtile, 1, 1) - in_hold(n, c, htile, wtile, 1, 2) - in_hold(n, c, htile, wtile, 2, 1) + in_hold(n, c, htile, wtile, 2, 2); in_transform(n, c, htile, wtile, 2, 3) = -in_hold(n, c, htile, wtile, 1, 1) + in_hold(n, c, htile, wtile, 1, 3) + in_hold(n, c, htile, wtile, 2, 1) - in_hold(n, c, htile, wtile, 2, 3); in_transform(n, c, htile, wtile, 3, 0) = in_hold(n, c, htile, wtile, 1, 0) - in_hold(n, c, htile, wtile, 1, 2) - in_hold(n, c, htile, wtile, 3, 0) + in_hold(n, c, htile, wtile, 3, 2); in_transform(n, c, htile, wtile, 3, 1) = in_hold(n, c, htile, wtile, 1, 1) + in_hold(n, c, htile, wtile, 1, 2) - in_hold(n, c, htile, wtile, 3, 1) - in_hold(n, c, htile, wtile, 3, 2); in_transform(n, c, htile, wtile, 3, 2) = -in_hold(n, c, htile, wtile, 1, 1) + in_hold(n, c, htile, wtile, 1, 2) + in_hold(n, c, htile, wtile, 3, 1) - in_hold(n, c, htile, wtile, 3, 2); in_transform(n, c, htile, wtile, 3, 3) = in_hold(n, c, htile, wtile, 1, 1) - in_hold(n, c, htile, wtile, 1, 3) - in_hold(n, c, htile, wtile, 3, 1) + in_hold(n, c, htile, wtile, 3, 3); }; auto f_wei_transform = [&](auto k, auto c) { wei_transform(k, c, 0, 0) = double(wei_kcyx(k, c, 0, 0)); wei_transform(k, c, 0, 1) = 0.5 * double(wei_kcyx(k, c, 0, 0)) + 0.5 * double(wei_kcyx(k, c, 0, 1)) + 0.5 * double(wei_kcyx(k, c, 0, 2)); wei_transform(k, c, 0, 2) = 0.5 * double(wei_kcyx(k, c, 0, 0)) - 0.5 * double(wei_kcyx(k, c, 0, 1)) + 0.5 * double(wei_kcyx(k, c, 0, 2)); wei_transform(k, c, 0, 3) = double(wei_kcyx(k, c, 0, 2)); wei_transform(k, c, 1, 0) = 0.5 * double(wei_kcyx(k, c, 0, 0)) + 0.5 * double(wei_kcyx(k, c, 1, 0)) + 0.5 * double(wei_kcyx(k, c, 2, 0)); wei_transform(k, c, 1, 1) = 0.25 * double(wei_kcyx(k, c, 0, 0)) + 0.25 * double(wei_kcyx(k, c, 0, 1)) + 0.25 * double(wei_kcyx(k, c, 0, 2)) + 0.25 * double(wei_kcyx(k, c, 1, 0)) + 0.25 * double(wei_kcyx(k, c, 1, 1)) + 0.25 * double(wei_kcyx(k, c, 1, 2)) + 0.25 * double(wei_kcyx(k, c, 2, 0)) + 0.25 * double(wei_kcyx(k, c, 2, 1)) + 0.25 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 1, 2) = 0.25 * double(wei_kcyx(k, c, 0, 0)) - 0.25 * double(wei_kcyx(k, c, 0, 1)) + 0.25 * double(wei_kcyx(k, c, 0, 2)) + 0.25 * double(wei_kcyx(k, c, 1, 0)) - 0.25 * double(wei_kcyx(k, c, 1, 1)) + 0.25 * double(wei_kcyx(k, c, 1, 2)) + 0.25 * double(wei_kcyx(k, c, 2, 0)) - 0.25 * double(wei_kcyx(k, c, 2, 1)) + 0.25 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 1, 3) = 0.5 * double(wei_kcyx(k, c, 0, 2)) + 0.5 * double(wei_kcyx(k, c, 1, 2)) + 0.5 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 2, 0) = 0.5 * double(wei_kcyx(k, c, 0, 0)) - 0.5 * double(wei_kcyx(k, c, 1, 0)) + 0.5 * double(wei_kcyx(k, c, 2, 0)); wei_transform(k, c, 2, 1) = 0.25 * double(wei_kcyx(k, c, 0, 0)) + 0.25 * double(wei_kcyx(k, c, 0, 1)) + 0.25 * double(wei_kcyx(k, c, 0, 2)) - 0.25 * double(wei_kcyx(k, c, 1, 0)) - 0.25 * double(wei_kcyx(k, c, 1, 1)) - 0.25 * double(wei_kcyx(k, c, 1, 2)) + 0.25 * double(wei_kcyx(k, c, 2, 0)) + 0.25 * double(wei_kcyx(k, c, 2, 1)) + 0.25 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 2, 2) = 0.25 * double(wei_kcyx(k, c, 0, 0)) - 0.25 * double(wei_kcyx(k, c, 0, 1)) + 0.25 * double(wei_kcyx(k, c, 0, 2)) - 0.25 * double(wei_kcyx(k, c, 1, 0)) + 0.25 * double(wei_kcyx(k, c, 1, 1)) - 0.25 * double(wei_kcyx(k, c, 1, 2)) + 0.25 * double(wei_kcyx(k, c, 2, 0)) - 0.25 * double(wei_kcyx(k, c, 2, 1)) + 0.25 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 2, 3) = 0.5 * double(wei_kcyx(k, c, 0, 2)) - 0.5 * double(wei_kcyx(k, c, 1, 2)) + 0.5 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 3, 0) = double(wei_kcyx(k, c, 2, 0)); wei_transform(k, c, 3, 1) = 0.5 * double(wei_kcyx(k, c, 2, 0)) + 0.5 * double(wei_kcyx(k, c, 2, 1)) + 0.5 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 3, 2) = 0.5 * double(wei_kcyx(k, c, 2, 0)) - 0.5 * double(wei_kcyx(k, c, 2, 1)) + 0.5 * double(wei_kcyx(k, c, 2, 2)); wei_transform(k, c, 3, 3) = double(wei_kcyx(k, c, 2, 2)); }; auto f_out_transform = [&](auto n, auto k, auto htile, auto wtile) { for(int j = 0; j < HiPerTile; ++j) { for(int i = 0; i < WiPerTile; ++i) { double v = 0; for(int c = 0; c < C; ++c) { v += in_transform(n, c, htile, wtile, j, i) * wei_transform(k, c, j, i); } out_transform(n, k, htile, wtile, j, i) = v; } } }; auto f_out_hold = [&](auto n, auto k, auto htile, auto wtile) { out_hold(n, k, htile, wtile, 0, 0) = out_transform(n, k, htile, wtile, 0, 0) + out_transform(n, k, htile, wtile, 0, 1) + out_transform(n, k, htile, wtile, 0, 2) + out_transform(n, k, htile, wtile, 1, 0) + out_transform(n, k, htile, wtile, 1, 1) + out_transform(n, k, htile, wtile, 1, 2) + out_transform(n, k, htile, wtile, 2, 0) + out_transform(n, k, htile, wtile, 2, 1) + out_transform(n, k, htile, wtile, 2, 2); out_hold(n, k, htile, wtile, 0, 1) = out_transform(n, k, htile, wtile, 0, 1) - out_transform(n, k, htile, wtile, 0, 2) - out_transform(n, k, htile, wtile, 0, 3) + out_transform(n, k, htile, wtile, 1, 1) - out_transform(n, k, htile, wtile, 1, 2) - out_transform(n, k, htile, wtile, 1, 3) + out_transform(n, k, htile, wtile, 2, 1) - out_transform(n, k, htile, wtile, 2, 2) - out_transform(n, k, htile, wtile, 2, 3); out_hold(n, k, htile, wtile, 1, 0) = out_transform(n, k, htile, wtile, 1, 0) + out_transform(n, k, htile, wtile, 1, 1) + out_transform(n, k, htile, wtile, 1, 2) - out_transform(n, k, htile, wtile, 2, 0) - out_transform(n, k, htile, wtile, 2, 1) - out_transform(n, k, htile, wtile, 2, 2) - out_transform(n, k, htile, wtile, 3, 0) - out_transform(n, k, htile, wtile, 3, 1) - out_transform(n, k, htile, wtile, 3, 2); out_hold(n, k, htile, wtile, 1, 1) = out_transform(n, k, htile, wtile, 1, 1) - out_transform(n, k, htile, wtile, 1, 2) - out_transform(n, k, htile, wtile, 1, 3) - out_transform(n, k, htile, wtile, 2, 1) + out_transform(n, k, htile, wtile, 2, 2) + out_transform(n, k, htile, wtile, 2, 3) - out_transform(n, k, htile, wtile, 3, 1) + out_transform(n, k, htile, wtile, 3, 2) + out_transform(n, k, htile, wtile, 3, 3); }; auto f_out = [&](auto n, auto k, auto htile, auto wtile) { for(int j = 0; j < HoPerTile; ++j) { std::size_t ho = HoPerTile * htile + j; for(int i = 0; i < WoPerTile; ++i) { std::size_t wo = WoPerTile * wtile + i; out_nkhw(n, k, ho, wo) = out_hold(n, k, htile, wtile, j, i); } } }; std::size_t num_thread = std::thread::hardware_concurrency(); make_ParallelTensorFunctor(f_in_hold, N, C, HTile, WTile)(num_thread); make_ParallelTensorFunctor(f_in_transform, N, C, HTile, WTile)(num_thread); make_ParallelTensorFunctor(f_wei_transform, K, C)(num_thread); make_ParallelTensorFunctor(f_out_transform, N, K, HTile, WTile)(num_thread); make_ParallelTensorFunctor(f_out_hold, N, K, HTile, WTile)(num_thread); make_ParallelTensorFunctor(f_out, N, K, HTile, WTile)(num_thread); } template void check_error(const Tensor& ref, const Tensor& result) { // printf("\n"); float error = 0; float max_diff = -1; float ref_value = 0, result_value = 0; for(int i = 0; i < ref.mData.size(); ++i) { error += std::abs(double(ref.mData[i]) - double(result.mData[i])); float diff = std::abs(double(ref.mData[i]) - double(result.mData[i])); if(max_diff < diff) { max_diff = diff; ref_value = ref.mData[i]; result_value = result.mData[i]; } // printf("{%f, %f}", double(ref.mData[i]), double(result.mData[i])); } // printf("\n"); std::cout << "error: " << error << std::endl; std::cout << "max_diff: " << max_diff << ", " << ref_value << ", " << result_value << std::endl; } int main(int argc, char* argv[]) { #if 0 constexpr index_t N = 1; constexpr index_t C = 1; constexpr index_t HI = 28; constexpr index_t WI = 28; constexpr index_t K = 1; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 3x3, 34x34 constexpr index_t N = 64; constexpr index_t C = 256; constexpr index_t HI = 34; constexpr index_t WI = 34; constexpr index_t K = 64; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 3x3, 56x56 constexpr index_t N = 64; constexpr index_t C = 64; constexpr index_t HI = 56; constexpr index_t WI = 56; constexpr index_t K = 64; constexpr index_t Y = 3; constexpr index_t X = 3; #elif 0 // 3x3, 58x58 constexpr index_t N = 64; constexpr index_t C = 64; constexpr index_t HI = 58; constexpr index_t WI = 58; constexpr index_t K = 64; constexpr index_t Y = 3; constexpr index_t X = 3; #elif 0 // 5x5, 36x36 constexpr index_t N = 64; constexpr index_t C = 256; constexpr index_t HI = 36; constexpr index_t WI = 36; constexpr index_t K = 64; constexpr index_t Y = 5; constexpr index_t X = 5; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 7x7, 38x38 constexpr index_t N = 64; constexpr index_t C = 256; constexpr index_t HI = 38; constexpr index_t WI = 38; constexpr index_t K = 64; constexpr index_t Y = 7; constexpr index_t X = 7; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 3x3, 58x58 constexpr index_t N = 16; constexpr index_t C = 128; constexpr index_t HI = 58; constexpr index_t WI = 58; constexpr index_t K = 256; constexpr index_t Y = 3; constexpr index_t X = 3; #elif 0 // 3x3 filter, 58x58 image, 0x0 padding constexpr index_t N = 16; constexpr index_t C = 128; constexpr index_t HI = 58; constexpr index_t WI = 58; constexpr index_t K = 256; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 3x3 filter, 56x56 image, 1x1 padding constexpr index_t N = 16; constexpr index_t C = 128; constexpr index_t HI = 56; constexpr index_t WI = 56; constexpr index_t K = 256; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 1; constexpr index_t WPad = 1; #elif 0 // 3x3 filter, 28x28 image, 1x1 padding constexpr index_t N = 16; constexpr index_t C = 256; constexpr index_t HI = 28; constexpr index_t WI = 28; constexpr index_t K = 512; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 1; constexpr index_t WPad = 1; #elif 0 // 1x1 filter, 28x28 image constexpr index_t N = 16; constexpr index_t C = 256; constexpr index_t HI = 28; constexpr index_t WI = 28; constexpr index_t K = 512; constexpr index_t Y = 1; constexpr index_t X = 1; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 3x3 filter, 20x84 image, 1x1 padding constexpr index_t N = 16; constexpr index_t C = 256; constexpr index_t HI = 20; constexpr index_t WI = 84; constexpr index_t K = 256; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 1; constexpr index_t WPad = 1; #elif 0 // 3x3 filter, 112x112 image, 1x1 padding constexpr index_t N = 16; constexpr index_t C = 64; constexpr index_t HI = 112; constexpr index_t WI = 112; constexpr index_t K = 128; constexpr index_t Y = 3; constexpr index_t X = 3; constexpr index_t HPad = 1; constexpr index_t WPad = 1; #elif 0 // 5x5 filter, 20x86 image, 1x1 padding constexpr index_t N = 16; constexpr index_t C = 256; constexpr index_t HI = 20; constexpr index_t WI = 86; constexpr index_t K = 512; constexpr index_t Y = 5; constexpr index_t X = 5; constexpr index_t HPad = 1; constexpr index_t WPad = 1; #elif 0 // 5x5 filter, 28x28 image, 2x2 padding constexpr index_t N = 16; constexpr index_t C = 192; constexpr index_t HI = 28; constexpr index_t WI = 28; constexpr index_t K = 32; constexpr index_t Y = 5; constexpr index_t X = 5; constexpr index_t HPad = 2; constexpr index_t WPad = 2; #elif 0 // 1x1 filter, 32x32 image constexpr index_t N = 64; constexpr index_t C = 256; constexpr index_t HI = 32; constexpr index_t WI = 32; constexpr index_t K = 512; constexpr index_t Y = 1; constexpr index_t X = 1; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 0 // 1x1 filter, 14x14 image, C = 2048 constexpr index_t N = 128; constexpr index_t C = 2048; constexpr index_t HI = 14; constexpr index_t WI = 14; constexpr index_t K = 512; constexpr index_t Y = 1; constexpr index_t X = 1; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #elif 1 // 1x1 filter, 14x14 image, C = 128 constexpr index_t N = 128; constexpr index_t C = 128; constexpr index_t HI = 14; constexpr index_t WI = 14; constexpr index_t K = 512; constexpr index_t Y = 1; constexpr index_t X = 1; constexpr index_t HPad = 0; constexpr index_t WPad = 0; #endif auto lower_pads = Sequence{}; auto upper_pads = Sequence{}; auto in_nchw_desc = make_ConstantTensorDescriptor(Sequence{}); auto wei_kcyx_desc = make_ConstantTensorDescriptor(Sequence{}); auto out_nkhw_desc = get_convolution_with_padding_output_default_4d_tensor_descriptor( in_nchw_desc, wei_kcyx_desc, lower_pads, upper_pads); ostream_ConstantTensorDescriptor(in_nchw_desc, std::cout << "in_nchw_desc: "); ostream_ConstantTensorDescriptor(wei_kcyx_desc, std::cout << "wei_kcyx_desc: "); ostream_ConstantTensorDescriptor(out_nkhw_desc, std::cout << "out_nkhw_desc: "); using in_data_t = float; using out_data_t = float; Tensor in_nchw(make_TensorDescriptor(in_nchw_desc)); Tensor wei_kcyx(make_TensorDescriptor(wei_kcyx_desc)); Tensor out_nkhw_host(make_TensorDescriptor(out_nkhw_desc)); Tensor out_nkhw_device(make_TensorDescriptor(out_nkhw_desc)); std::size_t num_thread = std::thread::hardware_concurrency(); if(argc != 3) { printf("arg1: do_verification, arg2: nrepeat\n"); exit(1); } bool do_verification = atoi(argv[1]); index_t nrepeat = atoi(argv[2]); if(do_verification) { #if 0 in_nchw.GenerateTensorValue(GeneratorTensor_1{}, num_thread); wei_kcyx.GenerateTensorValue(GeneratorTensor_1{}, num_thread); #elif 0 in_nchw.GenerateTensorValue(GeneratorTensor_1{}, num_thread); wei_kcyx.GenerateTensorValue(GeneratorTensor_2{-5, 5}, num_thread); #elif 0 in_nchw.GenerateTensorValue(GeneratorTensor_2{-5, 5}, num_thread); wei_kcyx.GenerateTensorValue(GeneratorTensor_1{}, num_thread); #elif 1 in_nchw.GenerateTensorValue(GeneratorTensor_2{-5, 5}, num_thread); wei_kcyx.GenerateTensorValue(GeneratorTensor_2{-5, 5}, num_thread); #elif 0 in_nchw.GenerateTensorValue(GeneratorTensor_2{1, 5}, num_thread); auto gen_wei = [](auto... is) { return GeneratorTensor_2{1, 5}(is...) * GeneratorTensor_Checkboard{}(is...); }; wei_kcyx.GenerateTensorValue(gen_wei, num_thread); #endif } #if 1 #if 0 device_direct_convolution_1 #elif 0 device_direct_convolution_2_nchw_kcyx_nkhw #elif 0 device_direct_convolution_2_vectorized_nchw_kcyx_nkhw #elif 0 device_implicit_gemm_convolution_1_chwn_cyxk_khwn #elif 1 device_implicit_gemm_convolution_2_chwn_cyxk_khwn #endif (in_nchw_desc, in_nchw, wei_kcyx_desc, wei_kcyx, out_nkhw_desc, out_nkhw_device, nrepeat); #elif 1 device_implicit_gemm_convolution_1_chwn_cyxk_khwn_padded(in_nchw_desc, in_nchw, wei_kcyx_desc, wei_kcyx, out_nkhw_desc, out_nkhw_device, lower_pads, upper_pads, nrepeat); #endif if(do_verification) { if(Y == 3 && X == 3) { host_winograd_3x3_convolution(in_nchw, wei_kcyx, out_nkhw_host, lower_pads, upper_pads); } else { host_direct_convolution(in_nchw, wei_kcyx, out_nkhw_host, lower_pads, upper_pads); } check_error(out_nkhw_host, out_nkhw_device); #if 0 LogRange(std::cout << "in_nchw : ", in_nchw.mData, ",") << std::endl; LogRange(std::cout << "wei_kcyx: ", wei_kcyx.mData, ",") << std::endl; LogRange(std::cout << "out_nkhw_host : ", out_nkhw_host.mData, ",") << std::endl; LogRange(std::cout << "out_nkhw_device: ", out_nkhw_device.mData, ",") << std::endl; #endif } }