CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1194 lines
50 KiB
C++
1194 lines
50 KiB
C++
/*******************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017 Advanced Micro Devices, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifndef MLO_CONVHOST_H_
|
|
#define MLO_CONVHOST_H_
|
|
|
|
#include <miopen/tensor.hpp>
|
|
|
|
#include <cmath>
|
|
#include <iostream>
|
|
|
|
#include "calcerr.hpp"
|
|
|
|
// #if 0 // disable functions
|
|
#if 1
|
|
////////////////////////////////////////////////////////////
|
|
//
|
|
///////////////////////////////////////////////////////////
|
|
template <typename Dtype>
|
|
void ADNN_im2col_cpu(const Dtype* data_im,
|
|
const int channels,
|
|
const int height,
|
|
const int width,
|
|
const int ksize_h,
|
|
const int ksize_w,
|
|
const int pad,
|
|
const int stride,
|
|
Dtype* data_col,
|
|
int stride_col = 0)
|
|
{
|
|
int height_col = (height + 2 * pad - ksize_h) / stride + 1;
|
|
int width_col = (width + 2 * pad - ksize_w) / stride + 1;
|
|
height_col = (height_col < 0) ? 1 : height_col;
|
|
width_col = (width_col < 0) ? 1 : width_col;
|
|
stride_col = (stride_col == 0) ? height_col * width_col : stride_col;
|
|
int channels_col = channels * ksize_h * ksize_w;
|
|
for(int c = 0; c < channels_col; ++c)
|
|
{
|
|
int w_offset = c % ksize_w;
|
|
int h_offset = (c / ksize_w) % ksize_h;
|
|
int c_im = c / ksize_h / ksize_w;
|
|
for(int h = 0; h < height_col; ++h)
|
|
{
|
|
for(int w = 0; w < width_col; ++w)
|
|
{
|
|
int h_pad = h * stride - pad + h_offset;
|
|
int w_pad = w * stride - pad + w_offset;
|
|
if(h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
|
|
{
|
|
data_col[c * stride_col + h * width_col + w] =
|
|
data_im[(c_im * height + h_pad) * width + w_pad];
|
|
}
|
|
else
|
|
{
|
|
data_col[c * stride_col + h * width_col + w] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Dtype>
|
|
void ADNN_col2im_cpu(const Dtype* data_col,
|
|
const int channels,
|
|
const int height,
|
|
const int width,
|
|
const int ksize_h,
|
|
const int ksize_w,
|
|
const int pad,
|
|
const int stride,
|
|
Dtype* data_im)
|
|
{
|
|
memset(data_im, 0, sizeof(Dtype) * height * width * channels);
|
|
int height_col = (height + 2 * pad - ksize_h) / stride + 1;
|
|
int width_col = (width + 2 * pad - ksize_w) / stride + 1;
|
|
height_col = (height_col < 0) ? 1 : height_col;
|
|
width_col = (width_col < 0) ? 1 : width_col;
|
|
int channels_col = channels * ksize_h * ksize_w;
|
|
for(int c = 0; c < channels_col; ++c)
|
|
{
|
|
int w_offset = c % ksize_w;
|
|
int h_offset = (c / ksize_w) % ksize_h;
|
|
int c_im = c / ksize_h / ksize_w;
|
|
for(int h = 0; h < height_col; ++h)
|
|
{
|
|
for(int w = 0; w < width_col; ++w)
|
|
{
|
|
int h_pad = h * stride - pad + h_offset;
|
|
int w_pad = w * stride - pad + w_offset;
|
|
if(h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
|
|
{
|
|
data_im[(c_im * height + h_pad) * width + w_pad] +=
|
|
data_col[(c * height_col + h) * width_col + w];
|
|
#if 0
|
|
if (c_im == 3 && h_pad == 30 && w_pad == 23)
|
|
{
|
|
printf("C:c2i: %d %d %d %d %d %d %14.12f %14.12f\n", c, h * width_col + w, w, h, w_pad, h_pad, data_im[(c_im * height + h_pad) * width + w_pad], data_col[(c * height_col + h) * width_col + w]);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloConvForwarDirectOnHost(
|
|
T_ padding_value, // padding value
|
|
int filter_size_h, // kernel 1 dim
|
|
int pad_h, // padding size
|
|
int conv_stride_h, // scale factor
|
|
int filter_size_w, // kernel 1 dim
|
|
int pad_w, // padding size
|
|
int conv_stride_w, // scale factor
|
|
int n_batchs,
|
|
int n_outputs,
|
|
int n_inputs,
|
|
int top_height,
|
|
int top_width,
|
|
int top_batch_stride,
|
|
int top_channel_stride,
|
|
int top_stride,
|
|
int bot_height,
|
|
int bot_width,
|
|
int bot_batch_stride,
|
|
int bot_channel_stride,
|
|
int bot_stride,
|
|
int weights_stride,
|
|
const T_* bot_ptr, // input "tensor" - batch x channels (input images, feature maps, slices) x
|
|
// width x height
|
|
T_* top_ptr, // output "te4nsor" - batch x channels (output images, feature maps, slices) x
|
|
// width (scaled) x height (scaled)
|
|
const T_*
|
|
weights_ptr, // weights n output channels x n input channels x filter size_y x filter size_x
|
|
const T_* bias_ptr = NULL // bias, NULL if no bias
|
|
)
|
|
{
|
|
int ret = 0;
|
|
const T_* run_bot_ptr = bot_ptr;
|
|
T_* run_top_ptr = top_ptr;
|
|
const T_* run_weights_ptr = weights_ptr;
|
|
|
|
// over all batches
|
|
for(int b = 0; b < n_batchs;
|
|
b++, run_bot_ptr += bot_batch_stride, run_top_ptr += top_batch_stride)
|
|
{
|
|
run_weights_ptr = weights_ptr;
|
|
// over all output channels
|
|
for(int o = 0; o < n_outputs; o++)
|
|
{
|
|
// sum up convolutions
|
|
// over output image (scaled input)
|
|
for(int j = 0; j < top_height; j++)
|
|
{
|
|
for(int i = 0; i < top_width; i++)
|
|
{
|
|
// over all input channels
|
|
T_ accum = 0;
|
|
for(int c = 0; c < n_inputs; c++)
|
|
{
|
|
// do convolution with kernel kernel_size x kerenl_size
|
|
// with padding - left, right, top, bottom = pad, and value = 0
|
|
for(int k_j = 0; k_j < filter_size_h; k_j++)
|
|
{
|
|
|
|
int in_y = (j * conv_stride_h + k_j - pad_h);
|
|
for(int k_i = 0; k_i < filter_size_w; k_i++)
|
|
{
|
|
int in_x = (i * conv_stride_w + k_i - pad_w);
|
|
T_ data_val = padding_value;
|
|
if(!(in_y < 0 || in_x < 0 || in_y >= bot_height ||
|
|
in_x >= bot_width))
|
|
{
|
|
int in_data_off =
|
|
c * bot_channel_stride + in_y * bot_stride + in_x;
|
|
data_val = run_bot_ptr[in_data_off];
|
|
}
|
|
|
|
T_ wei_val = run_weights_ptr[o * weights_stride +
|
|
c * filter_size_h * filter_size_w +
|
|
k_j * filter_size_w + k_i];
|
|
|
|
accum += data_val * wei_val;
|
|
#if 0
|
|
if (b == 0 && o == 0 && j == 1 && i == 0)
|
|
{
|
|
printf("c: %f %f %f\n",
|
|
accum/* + bias_ptr[o]*/,
|
|
data_val,
|
|
wei_val
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
T_ final_val = (bias_ptr) ? accum + bias_ptr[o] : accum;
|
|
run_top_ptr[o * top_channel_stride + j * top_stride + i] = final_val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloBackwardMMOnHost(int kernel_size_h,
|
|
int kernel_size_w,
|
|
int pad,
|
|
int stride,
|
|
const T_* weights_ptr,
|
|
int weights_height,
|
|
int weights_width,
|
|
int weights_stride,
|
|
const T_* top_df_ptr,
|
|
int top_height,
|
|
int top_width,
|
|
int outputs,
|
|
int batch_sz,
|
|
int top_df_batch_stride,
|
|
int top_df_channel_stride,
|
|
int /*top_df_stride*/,
|
|
T_* bot_df_ptr,
|
|
int bot_height,
|
|
int bot_width,
|
|
int inputs,
|
|
int bot_df_batch_stride,
|
|
int /*bot_df_channel_stride*/,
|
|
int /*bot_df_stride*/
|
|
|
|
)
|
|
{
|
|
|
|
int col_we_df_width = top_width * top_height;
|
|
int col_we_df_height = weights_width; // - bias
|
|
int col_we_batch_stride = col_we_df_width * col_we_df_height;
|
|
int col_we_stride = col_we_df_width;
|
|
T_* col_we_df_ptr = new T_[col_we_batch_stride * batch_sz];
|
|
|
|
assert(col_we_df_ptr);
|
|
|
|
for(int b = 0; b < batch_sz; ++b)
|
|
{
|
|
gemm_cpu<T_>(weights_ptr,
|
|
weights_width,
|
|
weights_height,
|
|
weights_stride,
|
|
true,
|
|
&T_(&top_df_ptr[top_df_batch_stride * b]),
|
|
top_width * top_height,
|
|
outputs,
|
|
top_df_channel_stride,
|
|
false,
|
|
&col_we_df_ptr[col_we_batch_stride * b],
|
|
col_we_df_width,
|
|
col_we_df_height,
|
|
col_we_stride,
|
|
1,
|
|
0); //- bias
|
|
|
|
ADNN_col2im_cpu<T_>(&col_we_df_ptr[col_we_batch_stride * b],
|
|
inputs,
|
|
bot_height,
|
|
bot_width,
|
|
kernel_size_h,
|
|
kernel_size_w,
|
|
pad,
|
|
stride,
|
|
&bot_df_ptr[bot_df_batch_stride * b]);
|
|
}
|
|
if(col_we_df_ptr)
|
|
{
|
|
delete[] col_we_df_ptr;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloBackwardDirectOnHost(
|
|
T_ /*padding_value*/, // padding value
|
|
// TO DO: check top, bot dim are equal
|
|
int filter_size_h, // kernel 1 dim
|
|
int pad_h, // padding size
|
|
int conv_stride_h, // scale factor
|
|
int filter_size_w, // kernel 1 dim
|
|
int pad_w, // padding size
|
|
int conv_stride_w, // scale factor
|
|
int n_batchs,
|
|
int n_outputs,
|
|
int n_inputs,
|
|
int top_height,
|
|
int top_width,
|
|
int top_batch_stride,
|
|
int top_channel_stride,
|
|
int top_stride,
|
|
int bot_width,
|
|
int bot_height,
|
|
int bot_batch_stride,
|
|
int bot_channel_stride,
|
|
int bot_stride,
|
|
int weights_stride,
|
|
T_* bot_ptr, // input "tensor" - batch x channels (input images, feature maps, slices) x width x
|
|
// height
|
|
const T_* top_ptr, // output "te4nsor" - batch x channels (output images, feature maps, slices)
|
|
// x width (scaled) x height (scaled)
|
|
const T_*
|
|
weights_ptr // weights n output channels x n input channels x filter size_y x filter size_x
|
|
)
|
|
{
|
|
int ret = 0;
|
|
T_* run_bot_ptr = bot_ptr;
|
|
const T_* run_top_ptr = top_ptr;
|
|
const T_* run_weights_ptr = weights_ptr;
|
|
|
|
// over all batches
|
|
for(int b = 0; b < n_batchs;
|
|
b++, run_bot_ptr += bot_batch_stride, run_top_ptr += top_batch_stride)
|
|
{
|
|
run_weights_ptr = weights_ptr;
|
|
// over all output channels
|
|
for(int c = 0; c < n_inputs; ++c)
|
|
{
|
|
// sum up convolutions
|
|
for(int o = 0; o < n_outputs; ++o)
|
|
{
|
|
|
|
for(int j = 0; j < top_height; ++j)
|
|
{
|
|
|
|
for(int i = 0; i < top_width; ++i)
|
|
{
|
|
|
|
int out_data_off = o * top_channel_stride + j * top_stride + i;
|
|
T_ data_val = run_top_ptr[out_data_off];
|
|
// over all input channels
|
|
T_ accum = 0;
|
|
// do convolution with kernel kernel_size x kerenl_size
|
|
// with padding - left, right, top, bottom = pad, and value = 0
|
|
for(int k_j = 0; k_j < filter_size_h; ++k_j)
|
|
{
|
|
int bot_y = (j * conv_stride_h + k_j - pad_h);
|
|
// int top_y = (j + filter_size_h - 1 - k_j);
|
|
for(int k_i = 0; k_i < filter_size_w; ++k_i)
|
|
{
|
|
// int top_x = (i + filter_size_w - 1 - k_i);
|
|
int bot_x = (i * conv_stride_w + k_i - pad_w);
|
|
if(!(bot_y < 0 || bot_x < 0 || bot_y >= bot_height ||
|
|
bot_x >= bot_width))
|
|
{
|
|
T_ wei_val = run_weights_ptr[o * weights_stride +
|
|
c * filter_size_h * filter_size_w +
|
|
k_j * filter_size_w + k_i];
|
|
|
|
int bot_data_off =
|
|
c * bot_channel_stride + bot_y * bot_stride + bot_x;
|
|
run_bot_ptr[bot_data_off] += data_val * wei_val;
|
|
|
|
#if 0
|
|
if (b == 0 && o == 0 && bot_y == 0 && bot_x == 0)
|
|
{
|
|
printf("c: %d %d %d %d %d %d %f %f %f\n",
|
|
bot_data_off,
|
|
k_j,
|
|
k_i,
|
|
j,
|
|
i,
|
|
out_data_off,
|
|
run_bot_ptr[bot_data_off],
|
|
data_val,
|
|
wei_val
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
template <typename T_>
|
|
void mloPrepad(int o,
|
|
int c,
|
|
int j,
|
|
int i,
|
|
T_ padding_value, // padding value
|
|
int pad_w, // padding size
|
|
int pad_h, // padding size
|
|
int bot_batch_stride,
|
|
int bot_channel_stride,
|
|
int bot_stride,
|
|
int bot_height,
|
|
int bot_width,
|
|
int new_bot_batch_stride,
|
|
int new_bot_channel_stride,
|
|
int new_bot_stride,
|
|
int /*new_bot_height*/,
|
|
int /*new_bot_width*/,
|
|
T_* new_bot_ptr,
|
|
const T_* bot_ptr // input "tensor" - batch x channels (input images, feature maps,
|
|
// slices) x width x height
|
|
)
|
|
{
|
|
int src_j = j - pad_h;
|
|
int src_i = i - pad_w;
|
|
int src_off = o * bot_batch_stride + c * bot_channel_stride + src_j * bot_stride + src_i;
|
|
int dst_off = o * new_bot_batch_stride + c * new_bot_channel_stride + j * new_bot_stride + i;
|
|
|
|
if(src_i >= 0 && src_i < bot_width && src_j >= 0 && src_j < bot_height)
|
|
{
|
|
new_bot_ptr[dst_off] = bot_ptr[src_off];
|
|
}
|
|
else
|
|
{
|
|
new_bot_ptr[dst_off] = padding_value;
|
|
}
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloDirectSPHostPrepad(T_ padding_value, // padding value
|
|
int pad_w, // padding size
|
|
int pad_h, // padding size
|
|
int n_batchs,
|
|
int n_inputs,
|
|
int bot_batch_stride,
|
|
int bot_channel_stride,
|
|
int bot_stride,
|
|
int bot_height,
|
|
int bot_width,
|
|
int new_bot_batch_stride,
|
|
int new_bot_channel_stride,
|
|
int new_bot_stride,
|
|
int new_bot_height,
|
|
int new_bot_width,
|
|
T_* new_bot_ptr,
|
|
const T_* bot_ptr // input "tensor" - batch x channels (input images,
|
|
// feature maps, slices) x width x height
|
|
)
|
|
{
|
|
int ret = 0;
|
|
for(int o = 0; o < n_batchs; ++o)
|
|
{
|
|
for(int c = 0; c < n_inputs; ++c)
|
|
{
|
|
for(int j = 0; j < new_bot_height; ++j)
|
|
{
|
|
for(int i = 0; i < new_bot_width; ++i)
|
|
{
|
|
mloPrepad<T_>(o,
|
|
c,
|
|
j,
|
|
i,
|
|
padding_value, // padding value
|
|
pad_w, // padding size
|
|
pad_h, // padding size
|
|
bot_batch_stride,
|
|
bot_channel_stride,
|
|
bot_stride,
|
|
bot_height,
|
|
bot_width,
|
|
new_bot_batch_stride,
|
|
new_bot_channel_stride,
|
|
new_bot_stride,
|
|
new_bot_height,
|
|
new_bot_width,
|
|
new_bot_ptr,
|
|
bot_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
weihts interleave
|
|
n inputs
|
|
n output blocks (1 block == n output tiles)
|
|
rows 1 * n output tiles
|
|
rows 2 * n output tiles
|
|
rows 3 * n output tiles
|
|
*/
|
|
|
|
template <typename T_>
|
|
void mloInterleavelWeightsInOutputs(int c,
|
|
int o_block,
|
|
int o,
|
|
int k_j,
|
|
int k_i,
|
|
int filter_size_w, // kernel 1 dim
|
|
int filter_size_h, // kernel 1 dim
|
|
int n_outputs,
|
|
int MLO_N_OUT_TILES,
|
|
int n_inputs,
|
|
const T_* wei_ptr,
|
|
T_* new_wei_ptr)
|
|
{
|
|
int src_off = (o_block * MLO_N_OUT_TILES + o) * n_inputs * filter_size_h * filter_size_w +
|
|
c * filter_size_h * filter_size_w + k_j * filter_size_w + k_i;
|
|
int dst_off = c * n_outputs * filter_size_h * filter_size_w +
|
|
o_block * MLO_N_OUT_TILES * filter_size_h * filter_size_w +
|
|
MLO_N_OUT_TILES * k_j * filter_size_w + o * filter_size_w + k_i;
|
|
new_wei_ptr[dst_off] = wei_ptr[src_off];
|
|
}
|
|
|
|
template <typename T_>
|
|
void mloDirectSPHostIntlWeights(bool forward, // forwad = 1, backward = 0
|
|
int filter_size_w, // kernel 1 dim
|
|
int filter_size_h, // kernel 1 dim
|
|
int n_outputs,
|
|
int n_inputs,
|
|
int MLO_N_OUT_TILES,
|
|
const T_* wei_ptr,
|
|
T_* new_wei_ptr)
|
|
{
|
|
if(forward)
|
|
{
|
|
// interleave all
|
|
// outputs per input
|
|
int o_loops = (n_outputs + MLO_N_OUT_TILES - 1) / MLO_N_OUT_TILES;
|
|
|
|
for(int c = 0; c < n_inputs; ++c)
|
|
{
|
|
for(int o_block = 0; o_block < o_loops; ++o_block)
|
|
{
|
|
for(int o = 0; o < MLO_N_OUT_TILES && o_block * MLO_N_OUT_TILES + o < n_outputs;
|
|
++o)
|
|
{
|
|
for(int k_j = 0; k_j < filter_size_h; ++k_j)
|
|
{
|
|
for(int k_i = 0; k_i < filter_size_w; ++k_i)
|
|
{
|
|
mloInterleavelWeightsInOutputs(c,
|
|
o_block,
|
|
o,
|
|
k_j,
|
|
k_i,
|
|
filter_size_w, // kernel 1 dim
|
|
filter_size_h, // kernel 1 dim
|
|
n_outputs,
|
|
MLO_N_OUT_TILES,
|
|
n_inputs,
|
|
wei_ptr,
|
|
new_wei_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloDirectSPConvHost5x5(int MLO_GRP_SZ1,
|
|
int MLO_GRP_SZ0,
|
|
int MLO_OUT_TILE1,
|
|
int MLO_OUT_TILE0,
|
|
int MLO_N_OUT_TILES,
|
|
int MLO_KERNEL_SZ1, // kernel 1 dim
|
|
int MLO_FILTER_SIZE1, // kernel 1 dim
|
|
int MLO_N_BATCHS,
|
|
int MLO_N_OUTPUTS,
|
|
int MLO_TOP_BATCH_STRIDE,
|
|
int MLO_TOP_CHANNEL_STRIDE,
|
|
int MLO_TOP_STRIDE,
|
|
int MLO_TOP_HEIGHT,
|
|
int MLO_TOP_WIDTH,
|
|
int MLO_N_INPUTS,
|
|
int MLO_BOT_BATCH_STRIDE,
|
|
int MLO_BOT_CHANNEL_STRIDE,
|
|
int MLO_BOT_STRIDE,
|
|
int /*MLO_BOT_HEIGHT*/,
|
|
int /*MLO_BOT_WIDTH*/,
|
|
const T_* bot_ptr, // input "tensor" - batch x channels (input images,
|
|
// feature maps, slices) x width x height
|
|
// interleaved weights
|
|
const T_* wei_ptr, // weights n output channels x n input channels x
|
|
// filter size_y x filter size_x
|
|
T_* top_ptr, // output "te4nsor" - batch x channels (output images,
|
|
// feature maps, slices) x width (scaled) x height (scaled)
|
|
const T_* /*bias_ptr = NULL*/ // bias, NULL if no bias
|
|
|
|
)
|
|
{
|
|
int j_loops =
|
|
(MLO_TOP_HEIGHT + MLO_GRP_SZ1 * MLO_OUT_TILE1 - 1) / (MLO_GRP_SZ1 * MLO_OUT_TILE1);
|
|
int i_loops = (MLO_TOP_WIDTH + MLO_GRP_SZ0 * MLO_OUT_TILE0 - 1) / (MLO_GRP_SZ0 * MLO_OUT_TILE0);
|
|
int o_loops = (MLO_N_OUTPUTS + MLO_N_OUT_TILES - 1) / MLO_N_OUT_TILES;
|
|
|
|
T_* bot_stage = new T_[MLO_OUT_TILE1 * (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1)];
|
|
T_* wei_stage = new T_[MLO_FILTER_SIZE1];
|
|
T_* out_tiles = new T_[MLO_OUT_TILE1 * MLO_OUT_TILE0 * MLO_N_OUT_TILES];
|
|
|
|
for(int g2 = 0; g2 < o_loops * MLO_N_BATCHS; ++g2)
|
|
{
|
|
for(int g1 = 0; g1 < j_loops; ++g1)
|
|
{
|
|
for(int g0 = 0; g0 < i_loops; ++g0)
|
|
{
|
|
for(int l1 = 0;
|
|
l1 < MLO_GRP_SZ1 && (g1 * MLO_GRP_SZ1 + l1) * MLO_OUT_TILE1 < MLO_TOP_HEIGHT;
|
|
++l1)
|
|
{
|
|
for(int l0 = 0;
|
|
l0 < MLO_GRP_SZ0 && (g0 * MLO_GRP_SZ0 + l0) * MLO_OUT_TILE1 < MLO_TOP_WIDTH;
|
|
++l0)
|
|
{
|
|
// KERNEL
|
|
int glbl1 = (g1 * MLO_GRP_SZ1 + l1) * MLO_OUT_TILE1;
|
|
int glbl0 = (g0 * MLO_GRP_SZ0 + l0) * MLO_OUT_TILE0;
|
|
int o_block = g2 / MLO_N_BATCHS;
|
|
int b = g2 - o_block * MLO_N_BATCHS; // batch
|
|
// position of on the map of the top-left input pixel
|
|
// bot stride may include additional padding zeros from prepadding
|
|
int bot_off = b * MLO_BOT_BATCH_STRIDE + MLO_BOT_STRIDE * glbl1 + glbl0;
|
|
// weight are interleaved
|
|
int o_base = o_block * MLO_N_OUT_TILES;
|
|
int wei_off = o_base * MLO_KERNEL_SZ1 * MLO_FILTER_SIZE1;
|
|
for(int ii = 0; ii < MLO_OUT_TILE1 * MLO_OUT_TILE0 * MLO_N_OUT_TILES; ++ii)
|
|
{
|
|
out_tiles[ii] = 0;
|
|
}
|
|
// the only place where we jump
|
|
for(int c = 0; c < MLO_N_INPUTS; ++c,
|
|
bot_off += MLO_BOT_CHANNEL_STRIDE,
|
|
wei_off += MLO_KERNEL_SZ1 * MLO_FILTER_SIZE1 * MLO_N_OUTPUTS)
|
|
{
|
|
int bot_off1 = bot_off;
|
|
|
|
// read first MLO_OUT_TILE1 - 1 lines of input
|
|
for(int j = 0; j < MLO_OUT_TILE1 - 1; ++j, bot_off1 += MLO_BOT_STRIDE)
|
|
{
|
|
for(int i = 0; i < (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1); ++i)
|
|
{
|
|
bot_stage[j * (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1) + i] =
|
|
bot_ptr[bot_off1 + i];
|
|
}
|
|
}
|
|
// now all weights are sequencially located
|
|
// see transformed layout
|
|
int wei_off1 = wei_off;
|
|
for(int k_j = 0; k_j < MLO_KERNEL_SZ1;
|
|
++k_j, bot_off1 += MLO_BOT_STRIDE)
|
|
{
|
|
// insertn new line
|
|
for(int i = 0; i < (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1); ++i)
|
|
{
|
|
bot_stage[(MLO_OUT_TILE1 - 1) *
|
|
(MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1) +
|
|
i] = bot_ptr[bot_off1 + i];
|
|
}
|
|
// loop over outputs
|
|
|
|
for(int o_i = 0; o_i < MLO_N_OUT_TILES; ++o_i)
|
|
{
|
|
|
|
// read filter coeff row
|
|
for(int w_i = 0; w_i < MLO_FILTER_SIZE1; ++w_i)
|
|
{
|
|
// moving along the weights
|
|
wei_stage[w_i] = wei_ptr[wei_off1++];
|
|
}
|
|
// convolve
|
|
for(int k_i = 0; k_i < MLO_FILTER_SIZE1; ++k_i)
|
|
{
|
|
for(int m = 0; m < MLO_OUT_TILE1; ++m)
|
|
{
|
|
for(int l = 0; l < MLO_OUT_TILE0; ++l)
|
|
{
|
|
out_tiles[o_i * MLO_OUT_TILE1 * MLO_OUT_TILE0 +
|
|
m * MLO_OUT_TILE0 + l] +=
|
|
bot_stage[m * (MLO_OUT_TILE0 +
|
|
MLO_FILTER_SIZE1 - 1) +
|
|
k_i + l] *
|
|
wei_stage[k_i];
|
|
#if 0
|
|
if (o_i == 1 && l1 == 0 && l0 == 0 && g0==0 && g1==0 && g2==0)
|
|
{
|
|
printf("ek: %f %f %f\n",
|
|
out_tiles[o_i * MLO_OUT_TILE1 * MLO_OUT_TILE0 + m*MLO_OUT_TILE0 + l],
|
|
bot_stage[m * (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1) + k_i + l],
|
|
wei_stage[k_i]
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
} // for (int o_i = 0; o_i < MLO_N_OUT_TILES; ++o_i, wei_off1 +=
|
|
// MLO_FILTER_SIZE1)
|
|
|
|
// move data up
|
|
for(int up = 0; up < MLO_OUT_TILE1 - 1; ++up)
|
|
{
|
|
for(int r = 0; r < (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1); ++r)
|
|
{
|
|
bot_stage[up * (MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1) + r] =
|
|
bot_stage[(up + 1) *
|
|
(MLO_OUT_TILE0 + MLO_FILTER_SIZE1 - 1) +
|
|
r];
|
|
}
|
|
}
|
|
|
|
} // for (int k_j = 0; k_j < MLO_KERNEL_SZ1; ++k_j, bot_off1 +=
|
|
// MLO_BOT_STRIDE, wei_off += MLO_FILTER_SIZE1 * MLO_N_OUTPUTS *
|
|
// MLO_N_INPUTS)
|
|
} // for (int c = 0; c < MLO_N_INPUTS; ++c, bot_off +=
|
|
// MLO_BOT_CHANNEL_STRIDE)
|
|
|
|
// output
|
|
int out_off = b * MLO_TOP_BATCH_STRIDE + o_base * MLO_TOP_CHANNEL_STRIDE +
|
|
glbl1 * MLO_TOP_STRIDE + glbl0;
|
|
for(int o = 0; o < MLO_N_OUT_TILES && o_base + o < MLO_N_OUTPUTS;
|
|
++o, out_off += MLO_TOP_CHANNEL_STRIDE)
|
|
{
|
|
int out_off1 = out_off;
|
|
for(int j = 0; j < MLO_OUT_TILE1; ++j, out_off1 += MLO_TOP_STRIDE)
|
|
{
|
|
for(int i = 0; i < MLO_OUT_TILE0; ++i)
|
|
{
|
|
top_ptr[out_off1 + i] =
|
|
out_tiles[o * MLO_OUT_TILE1 * MLO_OUT_TILE0 +
|
|
j * MLO_OUT_TILE0 + i];
|
|
}
|
|
}
|
|
}
|
|
|
|
} // for (int l0 = 0; l0 < MLO_SPC_GRP0 && (g0*MLO_SPC_GRP0 + l0) *
|
|
// MLO_OUT_TILE1 < MLO_TOP_WIDTH; ++l0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] bot_stage;
|
|
delete[] out_tiles;
|
|
delete[] wei_stage;
|
|
|
|
return (0);
|
|
}
|
|
|
|
template <typename T_>
|
|
int mloDirectSPHost(
|
|
|
|
int MLO_SPC_GRP1,
|
|
int MLO_SPC_GRP0,
|
|
int MLO_OUT_TILE1,
|
|
int MLO_OUT_TILE0,
|
|
int MLO_N_OUT_TILES,
|
|
|
|
bool forward,
|
|
bool do_input_copy,
|
|
T_ padding_value, // padding value
|
|
// TO DO: check top, bot dim are equal
|
|
int filter_size_w, // kernel 1 dim
|
|
int pad_w, // padding size
|
|
int /*conv_stride_w*/, // scale factor
|
|
int filter_size_h, // kernel 1 dim
|
|
int pad_h, // padding size
|
|
int /*conv_stride_h*/, // scale factor
|
|
int n_batchs,
|
|
int n_outputs,
|
|
int top_batch_stride,
|
|
int top_channel_stride,
|
|
int top_stride,
|
|
int top_height,
|
|
int top_width,
|
|
int n_inputs,
|
|
int bot_batch_stride,
|
|
int bot_channel_stride,
|
|
int bot_stride,
|
|
int bot_height,
|
|
int bot_width,
|
|
int new_bot_batch_stride,
|
|
int new_bot_channel_stride,
|
|
int new_bot_stride,
|
|
int new_bot_height,
|
|
int new_bot_width,
|
|
T_* new_bot_ptr,
|
|
const T_* bot_ptr, // input "tensor" - batch x channels (input images, feature maps, slices) x
|
|
// width x height
|
|
|
|
const T_*
|
|
wei_ptr, // weights n output channels x n input channels x filter size_y x filter size_x
|
|
T_* new_wei_ptr,
|
|
T_* top_ptr, // output "te4nsor" - batch x channels (output images, feature maps, slices) x
|
|
// width (scaled) x height (scaled)
|
|
const T_* bias_ptr = NULL // bias, NULL if no bias
|
|
|
|
)
|
|
{
|
|
int ret = 0;
|
|
if(do_input_copy)
|
|
{
|
|
mloDirectSPHostPrepad<T_>(padding_value, // padding value
|
|
pad_w, // padding size
|
|
pad_h, // padding size
|
|
n_batchs,
|
|
n_inputs,
|
|
bot_batch_stride,
|
|
bot_channel_stride,
|
|
bot_stride,
|
|
bot_height,
|
|
bot_width,
|
|
new_bot_batch_stride,
|
|
new_bot_channel_stride,
|
|
new_bot_stride,
|
|
new_bot_height,
|
|
new_bot_width,
|
|
new_bot_ptr,
|
|
bot_ptr // input "tensor" - batch x channels (input images,
|
|
// feature maps, slices) x width x height
|
|
);
|
|
}
|
|
|
|
mloDirectSPHostIntlWeights<T_>(forward, // forwad = 1, backward = 0
|
|
filter_size_w, // kernel 1 dim
|
|
filter_size_h, // kernel 1 dim
|
|
n_outputs,
|
|
n_inputs,
|
|
MLO_N_OUT_TILES,
|
|
wei_ptr,
|
|
new_wei_ptr);
|
|
|
|
mloDirectSPConvHost5x5<T_>(MLO_SPC_GRP1,
|
|
MLO_SPC_GRP0,
|
|
MLO_OUT_TILE1,
|
|
MLO_OUT_TILE0,
|
|
MLO_N_OUT_TILES,
|
|
filter_size_h,
|
|
filter_size_w,
|
|
n_batchs,
|
|
n_outputs,
|
|
top_batch_stride,
|
|
top_channel_stride,
|
|
top_stride,
|
|
top_height,
|
|
top_width,
|
|
n_inputs,
|
|
new_bot_batch_stride,
|
|
new_bot_channel_stride,
|
|
new_bot_stride,
|
|
new_bot_height,
|
|
new_bot_width,
|
|
|
|
new_bot_ptr,
|
|
new_wei_ptr,
|
|
top_ptr, // output "te4nsor" - batch x channels (output images,
|
|
// feature maps, slices) x width (scaled) x height (scaled)
|
|
bias_ptr);
|
|
return (ret);
|
|
}
|
|
|
|
#endif // disable functions
|
|
|
|
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
|
|
typename Tcheck_ /* the data type used in CPU checkings (usually double) */>
|
|
bool mloVerify(const miopenTensorDescriptor_t& cpu_,
|
|
const miopenTensorDescriptor_t& gpu_,
|
|
const Tcheck_* c_ptr,
|
|
const Tgpu_* g_ptr,
|
|
float ulps_tolerance,
|
|
Tcheck_ diff_tolerance,
|
|
double rms_tolerance,
|
|
bool check_ulps,
|
|
double& report_err)
|
|
{
|
|
const auto& cpu = miopen::deref(cpu_);
|
|
const auto& gpu = miopen::deref(gpu_);
|
|
|
|
const auto spatial_dim = cpu.GetLengths().size() - 2;
|
|
|
|
size_t n_batchs, n_channels, depth, height, width;
|
|
size_t c_batch_stride, c_channel_stride, c_depth_stride, c_height_stride, c_width_stride;
|
|
size_t g_batch_stride, g_channel_stride, g_depth_stride, g_height_stride, g_width_stride;
|
|
|
|
std::tie(n_batchs, n_channels, depth, height, width) =
|
|
miopen::GetNCDHW(spatial_dim, cpu.GetLengths());
|
|
std::tie(c_batch_stride, c_channel_stride, c_depth_stride, c_height_stride, c_width_stride) =
|
|
miopen::GetNCDHW(spatial_dim, cpu.GetStrides());
|
|
std::tie(g_batch_stride, g_channel_stride, g_depth_stride, g_height_stride, g_width_stride) =
|
|
miopen::GetNCDHW(spatial_dim, gpu.GetStrides());
|
|
|
|
bool match = true;
|
|
double rms_accum = 0.0;
|
|
Tcheck_ worst_c_val = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_g_val = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_diff = static_cast<Tcheck_>(0);
|
|
size_t worst_b = 0, worst_c = 0, worst_i = 0, worst_j = 0, worst_k = 0;
|
|
|
|
for(size_t b = 0; b < n_batchs; ++b)
|
|
{
|
|
for(size_t c = 0; c < n_channels; ++c)
|
|
{
|
|
for(size_t k = 0; k < depth; ++k)
|
|
{
|
|
for(size_t j = 0; j < height; ++j)
|
|
{
|
|
for(size_t i = 0; i < width; ++i)
|
|
{
|
|
Tcheck_ c_val =
|
|
c_ptr[b * c_batch_stride + c * c_channel_stride + k * c_depth_stride +
|
|
j * c_height_stride + i * c_width_stride];
|
|
Tcheck_ g_val = static_cast<Tcheck_>(
|
|
g_ptr[b * g_batch_stride + c * g_channel_stride + k * g_depth_stride +
|
|
j * g_height_stride + i * g_width_stride]);
|
|
|
|
Tcheck_ diff = std::abs(c_val - g_val);
|
|
rms_accum += diff * diff;
|
|
// Register worst (max) abs error and its position.
|
|
// This info will be used to show additional diagnostics,
|
|
// but only if sgr_accum is too big.
|
|
if(diff > worst_diff)
|
|
{
|
|
worst_diff = diff;
|
|
worst_c_val = c_val;
|
|
worst_g_val = g_val;
|
|
worst_b = b;
|
|
worst_c = c;
|
|
worst_i = i;
|
|
worst_j = j;
|
|
worst_k = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const double rms = std::sqrt(
|
|
rms_accum / (static_cast<double>(n_batchs * n_channels * depth * height * width)));
|
|
report_err = rms;
|
|
|
|
if(rms > rms_tolerance || std::isnan(rms) || !std::isfinite(rms))
|
|
{
|
|
match = false;
|
|
|
|
std::cout << "RMS too big: " << rms << ". Max diff: " << worst_diff << " at {" << worst_b
|
|
<< ',' << worst_c << ',';
|
|
if(spatial_dim == 3)
|
|
std::cout << worst_k << ',';
|
|
std::cout << worst_j << ',' << worst_i << "}, cpu_v = " << worst_c_val
|
|
<< " vs gpu_v = " << worst_g_val << std::endl;
|
|
}
|
|
|
|
if(check_ulps)
|
|
{
|
|
static int n_logged = 0;
|
|
for(size_t b = 0; b < n_batchs && match; ++b)
|
|
{
|
|
for(size_t c = 0; c < n_channels && match; ++c)
|
|
{
|
|
for(size_t k = 0; k < depth && match; ++k)
|
|
{
|
|
for(size_t j = 0; j < height && match; ++j)
|
|
{
|
|
for(size_t i = 0; i < width && match; ++i)
|
|
{
|
|
auto c_val =
|
|
static_cast<Tgpu_>(c_ptr[b * c_batch_stride + c * c_channel_stride +
|
|
k * c_depth_stride + j * c_height_stride +
|
|
i * c_width_stride]);
|
|
auto g_val =
|
|
static_cast<Tgpu_>(g_ptr[b * g_batch_stride + c * g_channel_stride +
|
|
k * g_depth_stride + j * g_height_stride +
|
|
i * g_width_stride]);
|
|
|
|
const auto diff = std::abs(c_val - g_val);
|
|
const auto ulps = ApproxUlps(c_val, g_val);
|
|
const bool check_failed =
|
|
(diff > diff_tolerance && ulps > ulps_tolerance) //
|
|
|| std::isnan(c_val) //
|
|
|| std::isnan(g_val) //
|
|
|| !std::isfinite(c_val) //
|
|
|| !std::isfinite(g_val);
|
|
|
|
if(check_failed)
|
|
match = false;
|
|
|
|
if(check_failed)
|
|
{
|
|
if(!(n_logged >= 10))
|
|
{
|
|
std::cout << "ULPs: " << ulps;
|
|
if(check_failed)
|
|
std::cout << " is too large (> " << ulps_tolerance << ")";
|
|
std::cout << " at {" << b << ',' << c << ',';
|
|
if(spatial_dim == 3)
|
|
std::cout << k << ',';
|
|
std::cout << j << ',' << i << "}, cpu_val = " << c_val
|
|
<< ", gpu_val = " << g_val << " (diff = " << diff
|
|
<< ')' << std::endl;
|
|
++n_logged;
|
|
if(n_logged >= 10)
|
|
std::cout << "(too many lines logged, truncating output...)"
|
|
<< std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return match;
|
|
}
|
|
|
|
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
|
|
typename Tcheck_ /* the data type used in CPU checkings (usually double) */>
|
|
bool mloVerify_mt(const miopenTensorDescriptor_t& cpu_,
|
|
const miopenTensorDescriptor_t& gpu_,
|
|
const Tcheck_* c_ptr,
|
|
const Tgpu_* g_ptr,
|
|
float ulps_tolerance,
|
|
Tcheck_ diff_tolerance,
|
|
double rms_tolerance,
|
|
bool check_ulps,
|
|
double& report_err)
|
|
{
|
|
const auto& cpu = miopen::deref(cpu_);
|
|
const auto& gpu = miopen::deref(gpu_);
|
|
|
|
const auto spatial_dim = cpu.GetLengths().size() - 2;
|
|
|
|
size_t n_batchs, n_channels, depth, height, width;
|
|
size_t c_batch_stride, c_channel_stride, c_depth_stride, c_height_stride, c_width_stride;
|
|
size_t g_batch_stride, g_channel_stride, g_depth_stride, g_height_stride, g_width_stride;
|
|
|
|
std::tie(n_batchs, n_channels, depth, height, width) =
|
|
miopen::GetNCDHW(spatial_dim, cpu.GetLengths());
|
|
std::tie(c_batch_stride, c_channel_stride, c_depth_stride, c_height_stride, c_width_stride) =
|
|
miopen::GetNCDHW(spatial_dim, cpu.GetStrides());
|
|
std::tie(g_batch_stride, g_channel_stride, g_depth_stride, g_height_stride, g_width_stride) =
|
|
miopen::GetNCDHW(spatial_dim, gpu.GetStrides());
|
|
|
|
double rms_accum = 0.0;
|
|
Tcheck_ worst_c_val = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_g_val = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_diff = static_cast<Tcheck_>(0);
|
|
size_t worst_b = 0, worst_c = 0, worst_i = 0, worst_j = 0, worst_k = 0;
|
|
|
|
std::mutex mt;
|
|
miopen::par_ford(n_batchs, n_channels)([&](int b, int c) {
|
|
double rms_local = 0.0;
|
|
Tcheck_ worst_c_val_local = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_g_val_local = static_cast<Tcheck_>(0);
|
|
Tcheck_ worst_diff_local = static_cast<Tcheck_>(0);
|
|
size_t worst_b_local = 0, worst_c_local = 0, worst_i_local = 0, worst_j_local = 0,
|
|
worst_k_local = 0;
|
|
for(size_t k = 0; k < depth; ++k)
|
|
{
|
|
for(size_t j = 0; j < height; ++j)
|
|
{
|
|
for(size_t i = 0; i < width; ++i)
|
|
{
|
|
Tcheck_ c_val =
|
|
c_ptr[b * c_batch_stride + c * c_channel_stride + k * c_depth_stride +
|
|
j * c_height_stride + i * c_width_stride];
|
|
Tcheck_ g_val = static_cast<Tcheck_>(
|
|
g_ptr[b * g_batch_stride + c * g_channel_stride + k * g_depth_stride +
|
|
j * g_height_stride + i * g_width_stride]);
|
|
|
|
Tcheck_ diff = std::abs(c_val - g_val);
|
|
rms_local += diff * diff;
|
|
// Register worst (max) abs error and its position.
|
|
// This info will be used to show additional diagnostics,
|
|
// but only if sgr_accum is too big.
|
|
if(diff > worst_diff_local)
|
|
{
|
|
worst_diff_local = diff;
|
|
worst_c_val_local = c_val;
|
|
worst_g_val_local = g_val;
|
|
worst_b_local = b;
|
|
worst_c_local = c;
|
|
worst_i_local = i;
|
|
worst_j_local = j;
|
|
worst_k_local = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::lock_guard<std::mutex> lock(mt);
|
|
rms_accum += rms_local;
|
|
if(worst_diff_local > worst_diff)
|
|
{
|
|
worst_diff = worst_diff_local;
|
|
worst_c_val = worst_c_val_local;
|
|
worst_g_val = worst_g_val_local;
|
|
worst_b = worst_b_local;
|
|
worst_c = worst_c_local;
|
|
worst_i = worst_i_local;
|
|
worst_j = worst_j_local;
|
|
worst_k = worst_k_local;
|
|
}
|
|
});
|
|
|
|
const double rms = std::sqrt(
|
|
rms_accum / (static_cast<double>(n_batchs * n_channels * depth * height * width)));
|
|
report_err = rms;
|
|
|
|
if(rms > rms_tolerance || std::isnan(rms) || !std::isfinite(rms))
|
|
{
|
|
|
|
std::cout << "RMS too big: " << rms << ". Max diff: " << worst_diff << " at {" << worst_b
|
|
<< ',' << worst_c << ',';
|
|
if(spatial_dim == 3)
|
|
std::cout << worst_k << ',';
|
|
std::cout << worst_j << ',' << worst_i << "}, cpu_v = " << worst_c_val
|
|
<< " vs gpu_v = " << worst_g_val << std::endl;
|
|
|
|
return false;
|
|
}
|
|
|
|
if(check_ulps)
|
|
{
|
|
std::atomic_bool match = true;
|
|
miopen::par_ford(n_batchs, n_channels)([&](int b, int c) {
|
|
for(size_t k = 0; k < depth && match; ++k)
|
|
{
|
|
for(size_t j = 0; j < height && match; ++j)
|
|
{
|
|
for(size_t i = 0; i < width && match; ++i)
|
|
{
|
|
auto c_val = static_cast<Tgpu_>(
|
|
c_ptr[b * c_batch_stride + c * c_channel_stride + k * c_depth_stride +
|
|
j * c_height_stride + i * c_width_stride]);
|
|
auto g_val = static_cast<Tgpu_>(
|
|
g_ptr[b * g_batch_stride + c * g_channel_stride + k * g_depth_stride +
|
|
j * g_height_stride + i * g_width_stride]);
|
|
|
|
const auto diff = std::abs(c_val - g_val);
|
|
const auto ulps = ApproxUlps(c_val, g_val);
|
|
const bool check_failed =
|
|
(diff > diff_tolerance && ulps > ulps_tolerance) //
|
|
|| std::isnan(c_val) //
|
|
|| std::isnan(g_val) //
|
|
|| !std::isfinite(c_val) //
|
|
|| !std::isfinite(g_val);
|
|
|
|
if(check_failed)
|
|
{
|
|
match = false;
|
|
std::cout << "ULPs: " << ulps << " is too large (> " << ulps_tolerance
|
|
<< ")" << " at {" << b << ',' << c << ',';
|
|
if(spatial_dim == 3)
|
|
std::cout << k << ',';
|
|
std::cout << j << ',' << i << "}, cpu_val = " << c_val
|
|
<< ", gpu_val = " << g_val << " (diff = " << diff << ')'
|
|
<< std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return match;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif
|