Files
paddlepaddle--paddle/paddle/phi/kernels/funcs/fake_quantize_functor.cu
T
2026-07-13 12:40:42 +08:00

783 lines
29 KiB
Plaintext

/* Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/phi/kernels/funcs/fake_quantize_functor.h"
#include "paddle/common/enforce.h"
namespace phi {
namespace funcs {
template <typename T>
struct QuantizeDataType {
using type = T;
};
template <>
struct QuantizeDataType<phi::float16> {
using type = float;
};
template <typename T>
__global__ void FindAbsMaxKernel(const T *in, const int64_t n, T *out) {
int64_t bid =
static_cast<int64_t>(threadIdx.x) +
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x);
int tid = threadIdx.x;
extern __shared__ char *shared_max_data_tmp[];
auto shared_max_data = reinterpret_cast<T *>(shared_max_data_tmp);
if (gridDim.x > 1) {
T local_max_data = T(0);
for (int64_t i = bid; i < n; i += blockDim.x * gridDim.x) {
T tmp = abs(in[i]);
if (tmp > local_max_data) {
local_max_data = tmp;
}
}
shared_max_data[tid] = local_max_data;
} else {
if (bid < n) {
shared_max_data[tid] = abs(in[bid]);
} else {
shared_max_data[tid] = T(0);
}
}
__syncthreads();
for (int i = blockDim.x / 2; i > 0; i >>= 1) {
if (tid < i && (shared_max_data[tid] < shared_max_data[tid + i])) {
shared_max_data[tid] = shared_max_data[tid + i];
}
__syncthreads();
}
if (tid == 0) {
out[blockIdx.x] = shared_max_data[0];
}
}
template <typename T>
__global__ void ClipAndQuantKernel(const T *in,
const T *scale,
const int qmax,
const int round_type,
const int64_t n,
T *out) {
int64_t bid =
static_cast<int64_t>(threadIdx.x) +
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x);
int tid = threadIdx.x;
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType s = static_cast<ComputeDataType>(scale[0]);
ComputeDataType inv_s = inverse(s);
ComputeDataType qmax_t = static_cast<ComputeDataType>(qmax);
for (int64_t i = bid; i < n; i += blockDim.x * gridDim.x) {
ComputeDataType x = static_cast<ComputeDataType>(in[i]);
if (round_type == 0) {
x = qmax_t * inv_s * x;
if (qmax_t == static_cast<ComputeDataType>(448)) {
x = float8_e4m3fn(x);
} else if (qmax_t == static_cast<ComputeDataType>(57344)) {
x = float8_e5m2(x);
} else {
x = roundWithTiesToEven(x);
}
ComputeDataType max_bound = qmax_t;
ComputeDataType min_bound = -qmax_t - static_cast<ComputeDataType>(1);
if (qmax_t == static_cast<ComputeDataType>(448) ||
qmax_t == static_cast<ComputeDataType>(57344)) {
min_bound = -qmax_t;
}
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out[i] = static_cast<T>(x);
} else {
ComputeDataType v = x > s ? s : x;
v = v < -s ? -s : v;
v = qmax_t * inv_s * v;
out[i] = static_cast<T>(round(v));
}
}
}
template <typename T>
__global__ void FindMovingAverageAbsMaxKernel(const T *in_state,
const T *in_accum,
const T *cur_scale,
const T rate,
T *out_state,
T *out_accum,
T *out_scale) {
T state = rate * (*in_state) + T(1.0f);
T accum = rate * (*in_accum) + (*cur_scale);
*out_state = state;
*out_accum = accum;
*out_scale = accum / state;
}
template <typename T>
__global__ void FindRangeAbsMaxAndFillArray(const T *cur_scale,
const T *last_scale,
const int64_t *iter,
const int window_size,
T *scale_arr,
T *out_scale,
int *need_find_max,
int *out_size) {
int64_t it = iter[0];
int64_t idx = it % window_size;
T removed = scale_arr[idx];
T cur = cur_scale[0];
scale_arr[idx] = cur;
T max = last_scale[0];
out_scale[0] = max < cur ? cur : max;
if (fabs(static_cast<typename QuantizeDataType<T>::type>(removed - max)) <
1e-6) {
need_find_max[0] = 1;
out_size[0] = it > window_size ? window_size : it;
} else {
need_find_max[0] = 0;
}
}
template <typename T>
__global__ void ClipAndQuantDequantKernel(const T *in,
const T *scale,
const int bin_cnt,
const int round_type,
const int64_t n,
T *out) {
int64_t bid =
static_cast<int64_t>(threadIdx.x) +
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x);
int tid = threadIdx.x;
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType s = static_cast<ComputeDataType>(scale[0]);
ComputeDataType inv_s = funcs::inverse(s);
ComputeDataType bin_cnt_t = static_cast<ComputeDataType>(bin_cnt);
for (int64_t i = bid; i < n; i += blockDim.x * gridDim.x) {
ComputeDataType x = static_cast<ComputeDataType>(in[i]);
if (round_type == 0) {
x = bin_cnt_t * inv_s * x;
x = funcs::roundWithTiesToEven(x);
ComputeDataType max_bound = bin_cnt_t;
ComputeDataType min_bound = -bin_cnt_t - static_cast<ComputeDataType>(1);
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out[i] = static_cast<T>((x * s) / bin_cnt_t);
} else {
x = x > s ? s : x;
x = x < -s ? -s : x;
x = bin_cnt_t * inv_s * x;
x = round(x);
out[i] = static_cast<T>((x * s) / bin_cnt_t);
}
}
}
template <typename Context, typename T>
void FindAbsMaxFunctor<Context, T>::operator()(const Context &dev_ctx,
const T *in,
const int64_t num,
T *out) {
uint32_t block = 1024;
int64_t grid_64 = (num + block - 1) / block;
grid_64 = (grid_64 > block) ? block : grid_64;
uint32_t grid = static_cast<uint32_t>(grid_64);
DenseTensor max;
max.Resize({grid_64});
T *max_data = dev_ctx.template Alloc<T>(&max);
FindAbsMaxKernel<T>
<<<grid, block, 1024 * sizeof(T), dev_ctx.stream()>>>(in, num, max_data);
FindAbsMaxKernel<T>
<<<1, block, 1024 * sizeof(T), dev_ctx.stream()>>>(max_data, grid, out);
}
template <typename Context, typename T>
void ClipAndFakeQuantFunctor<Context, T>::operator()(const Context &dev_ctx,
const DenseTensor &in,
const DenseTensor &scale,
const int qmax,
const int round_type,
DenseTensor *out) {
int64_t num = in.numel();
uint32_t block = 1024;
int64_t max_grid = dev_ctx.GetCUDAMaxGridDimSize()[0];
int64_t grid_64 = std::min((num + block - 1) / block, max_grid);
PADDLE_ENFORCE_LE_UINT32_MAX(grid_64, "fake_quantize grid.x");
uint32_t grid = static_cast<uint32_t>(grid_64);
const T *in_data = in.data<T>();
const T *scale_data = scale.data<T>();
T *out_data = dev_ctx.template Alloc<T>(out);
ClipAndQuantKernel<T><<<grid, block, 0, dev_ctx.stream()>>>(
in_data, scale_data, qmax, round_type, num, out_data);
}
template <typename Context, typename T>
void FindMovingAverageAbsMaxFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &in_accum,
const DenseTensor &in_state,
const T *cur_scale,
const float rate,
DenseTensor *out_state,
DenseTensor *out_accum,
DenseTensor *out_scale) {
T rate_t = static_cast<T>(rate);
T *out_state_data = dev_ctx.template Alloc<T>(out_state);
T *out_accum_data = dev_ctx.template Alloc<T>(out_accum);
T *out_scale_data = dev_ctx.template Alloc<T>(out_scale);
FindMovingAverageAbsMaxKernel<T>
<<<1, 1, 0, dev_ctx.stream()>>>(in_state.data<T>(),
in_accum.data<T>(),
cur_scale,
rate_t,
out_state_data,
out_accum_data,
out_scale_data);
}
template <typename T>
__global__ void FindChannelAbsMaxKernelQuantAxis0(const T *in,
const int64_t n,
const int64_t c,
T *out) {
int tid = threadIdx.x;
int64_t channel_size = n / c;
const T *in_c = in + blockIdx.x * channel_size;
extern __shared__ char *shared_max_data_tmp[];
auto shared_max_data = reinterpret_cast<T *>(shared_max_data_tmp);
T local_max_data = T(0);
for (int64_t i = tid; i < channel_size; i += blockDim.x) {
T tmp = static_cast<T>(
fabs(static_cast<typename QuantizeDataType<T>::type>(in_c[i])));
if (tmp > local_max_data) {
local_max_data = tmp;
}
}
shared_max_data[tid] = local_max_data;
__syncthreads();
for (int i = blockDim.x / 2; i > 0; i >>= 1) {
if (tid < i && (shared_max_data[tid] < shared_max_data[tid + i])) {
shared_max_data[tid] = shared_max_data[tid + i];
}
__syncthreads();
}
if (tid == 0) {
out[blockIdx.x] = shared_max_data[0];
}
}
template <typename T>
__global__ void FindChannelAbsMaxKernelQuantAxis1(const T *in,
const int64_t n,
const int64_t cin,
const int64_t cout,
T *out) {
extern __shared__ char *shared_max_data_tmp[];
auto shared_max_data = reinterpret_cast<T *>(shared_max_data_tmp);
int64_t cout_wh_size = n / cin;
int64_t wh_size = n / (cin * cout);
int tid = threadIdx.x;
int bid = blockIdx.x;
const T *in_current = in + tid * cout_wh_size + bid * wh_size;
T local_max_data = T(0);
for (int64_t i = 0; i < wh_size; i++) {
T tmp = static_cast<T>(
fabs(static_cast<typename QuantizeDataType<T>::type>(in_current[i])));
if (tmp > local_max_data) {
local_max_data = tmp;
}
}
shared_max_data[tid] = local_max_data;
__syncthreads();
int len = blockDim.x;
for (int i = (len + 1) / 2; i > 0; len = i, i = (i + 1) / 2) {
if (tid < i && tid + i < len &&
shared_max_data[tid] < shared_max_data[tid + i]) {
shared_max_data[tid] = shared_max_data[tid + i];
}
if (i == 1) {
i = 0; // break the loop
}
__syncthreads();
}
if (tid == 0 && shared_max_data[0] > out[bid]) {
out[bid] = shared_max_data[0];
}
}
template <typename Context, typename T>
void FindChannelAbsMaxFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &in_tensor,
const int quant_axis,
T *out_abs_max) {
PADDLE_ENFORCE_EQ(
quant_axis == 0 || quant_axis == 1,
true,
common::errors::InvalidArgument("'quant_axis' should be 0 or 1, but "
"the received is %d",
quant_axis));
const int64_t num = in_tensor.numel();
// big tensor currently not supported
PADDLE_ENFORCE_LE(num,
(1LL << 31) - 1,
::common::errors::PreconditionNotMet(
"in_tensor's numel too large, allowed size is 2 ^ 31 - "
"1 elements, but got %lld",
num));
auto in_dims = in_tensor.dims();
const T *in_data = in_tensor.data<T>();
if (quant_axis == 0) {
int64_t cout = in_dims[0];
int grid = cout;
int block = 1024;
FindChannelAbsMaxKernelQuantAxis0<T>
<<<grid, block, block * sizeof(T), dev_ctx.stream()>>>(
in_data, num, cout, out_abs_max);
} else if (quant_axis == 1) {
int64_t cin = in_dims[0];
int64_t cout = in_dims[1];
int grid = cout;
int max_threads = 1024;
#ifdef PADDLE_WITH_HIP
hipMemset(out_abs_max, 0, sizeof(T) * cout);
#else
cudaMemset(out_abs_max, 0, sizeof(T) * cout);
#endif // PADDLE_FLUID_OPERATORS_FAKE_QUANTIZE_OP_CU_H_
for (int64_t i = 0; i < cin / max_threads; i++) {
int block = max_threads;
FindChannelAbsMaxKernelQuantAxis1<T>
<<<grid, block, block * sizeof(T), dev_ctx.stream()>>>(
in_data, num, cin, cout, out_abs_max);
in_data += cout * max_threads;
}
int block = cin % max_threads;
if (block > 0) {
FindChannelAbsMaxKernelQuantAxis1<T>
<<<grid, block, block * sizeof(T), dev_ctx.stream()>>>(
in_data, num, in_dims[0], in_dims[1], out_abs_max);
}
}
}
// ChannelClipAndQuantKernel for quant_axis is 0
template <typename T>
__global__ void ChannelClipAndQuantKernelQuantAxis0(const T *in,
const T *scale,
const int qmax,
const int round_type,
const int64_t n,
const int64_t c,
T *out) {
int tid = threadIdx.x;
int64_t channel_size = n / c;
const T *in_c = in + blockIdx.x * channel_size;
T *out_c = out + blockIdx.x * channel_size;
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType s = static_cast<ComputeDataType>(scale[blockIdx.x]);
ComputeDataType inv_s = inverse(s);
ComputeDataType qmax_t = static_cast<ComputeDataType>(qmax);
for (int64_t i = tid; i < channel_size; i += blockDim.x) {
ComputeDataType x = static_cast<ComputeDataType>(in_c[i]);
if (round_type == 0) {
x = qmax_t * inv_s * x;
if (qmax_t == static_cast<ComputeDataType>(448)) {
x = float8_e4m3fn(x);
} else if (qmax_t == static_cast<ComputeDataType>(57344)) {
x = float8_e5m2(x);
} else {
x = roundWithTiesToEven(x);
}
ComputeDataType max_bound = qmax_t;
ComputeDataType min_bound = -qmax_t - static_cast<ComputeDataType>(1);
if (qmax_t == static_cast<ComputeDataType>(448) ||
qmax_t == static_cast<ComputeDataType>(57344)) {
min_bound = -qmax_t;
}
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out_c[i] = static_cast<T>(x);
} else {
ComputeDataType v = x > s ? s : x;
v = v < -s ? -s : v;
v = qmax_t * inv_s * v;
out_c[i] = static_cast<T>(round(v));
}
}
}
// ChannelClipAndQuantKernel for quant_axis is N
template <typename T>
__global__ void ChannelClipAndQuantKernelQuantAxisN(const T *in,
const T *scale,
const int qmax,
const int round_type,
const int64_t n,
const int nScale,
const int quant_stride,
T *out) {
int64_t idx =
static_cast<int64_t>(blockDim.x) * static_cast<int64_t>(blockIdx.x) +
static_cast<int64_t>(threadIdx.x);
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType qmax_t = static_cast<ComputeDataType>(qmax);
for (int64_t i = idx; i < n; i += blockDim.x * gridDim.x) {
ComputeDataType s =
static_cast<ComputeDataType>(scale[(i / quant_stride) % nScale]);
ComputeDataType inv_s = inverse(s);
ComputeDataType x = static_cast<ComputeDataType>(in[i]);
if (round_type == 0) {
x = qmax_t * inv_s * x;
if (qmax_t == static_cast<ComputeDataType>(448)) {
x = float8_e4m3fn(x);
} else if (qmax_t == static_cast<ComputeDataType>(57344)) {
x = float8_e5m2(x);
} else {
x = roundWithTiesToEven(x);
}
ComputeDataType max_bound = qmax_t;
ComputeDataType min_bound = -qmax_t - static_cast<ComputeDataType>(1);
if (qmax_t == static_cast<ComputeDataType>(448) ||
qmax_t == static_cast<ComputeDataType>(57344)) {
min_bound = -qmax_t;
}
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out[i] = static_cast<T>(x);
} else {
ComputeDataType v = x > s ? s : x;
v = v < -s ? -s : v;
v = qmax_t * inv_s * v;
out[i] = static_cast<T>(round(v));
}
}
}
template <typename Context, typename T>
void ChannelClipAndFakeQuantFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &in,
const DenseTensor &scale,
const int qmax,
const int round_type,
const int quant_axis,
DenseTensor *out) {
int64_t num = in.numel();
auto in_dims = in.dims();
const T *in_data = in.data<T>();
const T *scale_data = scale.data<T>();
T *out_data = dev_ctx.template Alloc<T>(out);
if (quant_axis == 0) {
int64_t grid_64 = in_dims[0];
PADDLE_ENFORCE_LE_UINT32_MAX(grid_64, "fake_quantize channel grid.x");
uint32_t grid = static_cast<uint32_t>(grid_64);
uint32_t block = 1024;
ChannelClipAndQuantKernelQuantAxis0<T>
<<<grid, block, 0, dev_ctx.stream()>>>(
in_data, scale_data, qmax, round_type, num, in_dims[0], out_data);
} else {
int64_t quant_stride_64 = 1;
for (int i = quant_axis + 1; i < in_dims.size(); i++) {
quant_stride_64 *= in_dims[i];
}
PADDLE_ENFORCE_LE_INT_MAX(quant_stride_64, "fake_quantize quant_stride");
int quant_stride = static_cast<int>(quant_stride_64);
int64_t block_size_64 = std::min(
num, static_cast<int64_t>(dev_ctx.GetMaxThreadsPerBlock() / 4));
int64_t max_threads =
dev_ctx.GetMaxPhysicalThreadCount(); // SM * block_per_SM
const int64_t max_blocks = std::max(((max_threads - 1) / block_size_64 + 1),
static_cast<int64_t>(1));
const int64_t grid_size_64 =
std::min(max_blocks, (num + block_size_64 - 1) / block_size_64);
PADDLE_ENFORCE_LE_UINT32_MAX(grid_size_64, "fake_quantize channel grid.x");
PADDLE_ENFORCE_LE_UINT32_MAX(block_size_64,
"fake_quantize channel block.x");
PADDLE_ENFORCE_LE_INT_MAX(in_dims[quant_axis],
"fake_quantize channel nScale");
uint32_t grid_size = static_cast<uint32_t>(grid_size_64);
uint32_t block_size = static_cast<uint32_t>(block_size_64);
int nScale = static_cast<int>(in_dims[quant_axis]);
ChannelClipAndQuantKernelQuantAxisN<T>
<<<grid_size, block_size>>>(in_data,
scale_data,
qmax,
round_type,
num,
nScale,
quant_stride,
out_data);
}
}
// ChannelClipAndQuantDequantKernel for quant_axis is 0
template <typename T>
__global__ void ChannelClipAndQuantDequantKernelQuantAxis0(const T *in,
const T *scale,
const int bin_cnt,
const int round_type,
const int wh_size,
const int64_t num,
const int cout,
T *out) {
int64_t idx =
static_cast<int64_t>(blockDim.x) * static_cast<int64_t>(blockIdx.x) +
static_cast<int64_t>(threadIdx.x);
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType bin_cnt_t = static_cast<ComputeDataType>(bin_cnt);
for (int64_t i = idx; i < num; i += blockDim.x * gridDim.x) {
T s = scale[(i / wh_size) % cout];
T inv_s = inverse(s);
T x = in[i];
if (round_type == 0) {
x = bin_cnt * inv_s * x;
x = roundWithTiesToEven(x);
T max_bound = bin_cnt;
T min_bound = -bin_cnt - static_cast<T>(1);
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out[i] = (x * s) / bin_cnt;
} else {
T v = x > s ? s : x;
v = v < -s ? -s : v;
v = bin_cnt * inv_s * v;
out[i] = round(v) * s / bin_cnt;
}
}
}
// ChannelClipAndQuantDequantKernel for quant_axis is 1
template <typename T>
__global__ void ChannelClipAndQuantDequantKernelQuantAxis1(const T *in,
const T *scale,
const int bin_cnt,
const int round_type,
const int wh_size,
const int64_t num,
const int64_t cout,
T *out) {
int64_t idx =
static_cast<int64_t>(blockDim.x) * static_cast<int64_t>(blockIdx.x) +
static_cast<int64_t>(threadIdx.x);
using ComputeDataType = typename QuantizeDataType<T>::type;
ComputeDataType bin_cnt_t = static_cast<ComputeDataType>(bin_cnt);
for (int64_t i = idx; i < num; i += blockDim.x * gridDim.x) {
T s = scale[(i / wh_size) % cout];
T inv_s = inverse(s);
T x = in[i];
if (round_type == 0) {
x = bin_cnt * inv_s * x;
x = roundWithTiesToEven(x);
T max_bound = bin_cnt;
T min_bound = -bin_cnt - static_cast<T>(1);
x = x > max_bound ? max_bound : x;
x = x < min_bound ? min_bound : x;
out[i] = (x * s) / bin_cnt;
} else {
T v = x > s ? s : x;
v = v < -s ? -s : v;
v = bin_cnt * inv_s * v;
out[i] = round(v) * s / bin_cnt;
}
}
}
template <typename Context, typename T>
void ChannelClipFakeQuantDequantFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &in,
const DenseTensor &scale,
const int bin_cnt,
const int round_type,
const int quant_axis,
DenseTensor *out) {
// At present, channelwise quantization supports conv2d, depthwise_conv2d
// conv2d_transpose and mul
int64_t num = in.numel();
auto in_dims = in.dims();
const T *in_data = in.data<T>();
const T *scale_data = scale.data<T>();
T *out_data = dev_ctx.template Alloc<T>(out);
int64_t block_size_64 =
std::min(static_cast<int64_t>(num),
static_cast<int64_t>(dev_ctx.GetMaxThreadsPerBlock() / 4));
int64_t max_threads =
dev_ctx.GetMaxPhysicalThreadCount(); // SM * block_per_SM
const int64_t max_blocks = std::max(((max_threads - 1) / block_size_64 + 1),
static_cast<int64_t>(1));
const int64_t grid_size_64 =
std::min(max_blocks, (num + block_size_64 - 1) / block_size_64);
PADDLE_ENFORCE_LE_UINT32_MAX(grid_size_64,
"fake_quantize_dequant channel grid.x");
PADDLE_ENFORCE_LE_UINT32_MAX(block_size_64,
"fake_quantize_dequant channel block.x");
uint32_t grid_size = static_cast<uint32_t>(grid_size_64);
uint32_t block_size = static_cast<uint32_t>(block_size_64);
if (quant_axis == 0) {
int64_t window_size_64 = num / in_dims[0];
PADDLE_ENFORCE_LE_INT_MAX(window_size_64,
"fake_quantize_dequant window_size");
PADDLE_ENFORCE_LE_INT_MAX(in_dims[0], "fake_quantize_dequant cout");
int window_size = static_cast<int>(window_size_64);
int cout = static_cast<int>(in_dims[0]);
ChannelClipAndQuantDequantKernelQuantAxis0<T>
<<<grid_size, block_size, 0, dev_ctx.stream()>>>(in_data,
scale_data,
bin_cnt,
round_type,
window_size,
num,
cout,
out_data);
} else if (quant_axis == 1) {
int64_t window_size_64 = num / (in_dims[0] * in_dims[1]);
PADDLE_ENFORCE_LE_INT_MAX(window_size_64,
"fake_quantize_dequant window_size");
int window_size = static_cast<int>(window_size_64);
ChannelClipAndQuantDequantKernelQuantAxis1<T>
<<<grid_size, block_size, 0, dev_ctx.stream()>>>(in_data,
scale_data,
bin_cnt,
round_type,
window_size,
num,
in_dims[1],
out_data);
}
}
template <typename Context, typename T>
void FindRangeAbsMaxFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &cur_scale,
const DenseTensor &last_scale,
const DenseTensor &iter,
const int window_size,
DenseTensor *scales_arr,
DenseTensor *out_scale) {
const auto gpu_place = dev_ctx.GetPlace();
T *scale_arr = dev_ctx.template Alloc<T>(scales_arr);
T *out_scale_data = dev_ctx.template Alloc<T>(out_scale);
DenseTensor need_find_max, out_size;
need_find_max.Resize({1});
out_size.Resize({1});
int *find_max = dev_ctx.template Alloc<int>(&need_find_max);
int *out_size_data = dev_ctx.template Alloc<int>(&out_size);
FindRangeAbsMaxAndFillArray<T>
<<<1, 1, 0, dev_ctx.stream()>>>(cur_scale.data<T>(),
last_scale.data<T>(),
iter.data<int64_t>(),
window_size,
scale_arr,
out_scale_data,
find_max,
out_size_data);
int g_find_max;
memory_utils::Copy(CPUPlace(),
&g_find_max,
gpu_place,
find_max,
sizeof(int),
dev_ctx.stream());
dev_ctx.Wait();
if (g_find_max) {
int len;
memory_utils::Copy(CPUPlace(),
&len,
gpu_place,
out_size_data,
sizeof(int),
dev_ctx.stream());
dev_ctx.Wait();
funcs::FindAbsMaxFunctor<GPUContext, T>()(
dev_ctx, scale_arr, len, out_scale_data);
}
}
template <typename Context, typename T>
void ClipAndFakeQuantDequantFunctor<Context, T>::operator()(
const Context &dev_ctx,
const DenseTensor &in,
const DenseTensor &scale,
const int bin_cnt,
int round_type,
DenseTensor *out) {
int64_t num = in.numel();
uint32_t block = 1024;
int64_t max_grid = dev_ctx.GetCUDAMaxGridDimSize()[0];
int64_t grid_64 = std::min((num + block - 1) / block, max_grid);
PADDLE_ENFORCE_LE_UINT32_MAX(grid_64, "fake_quantize_dequant grid.x");
uint32_t grid = static_cast<uint32_t>(grid_64);
const T *in_data = in.data<T>();
const T *scale_data = scale.data<T>();
T *out_data = dev_ctx.template Alloc<T>(out);
ClipAndQuantDequantKernel<T><<<grid, block, 0, dev_ctx.stream()>>>(
in_data, scale_data, bin_cnt, round_type, num, out_data);
}
template class FindAbsMaxFunctor<GPUContext, float16>;
template class FindAbsMaxFunctor<GPUContext, float>;
template class ClipAndFakeQuantFunctor<GPUContext, float16>;
template class ClipAndFakeQuantFunctor<GPUContext, float>;
template class FindMovingAverageAbsMaxFunctor<GPUContext, float16>;
template class FindMovingAverageAbsMaxFunctor<GPUContext, float>;
template class FindChannelAbsMaxFunctor<GPUContext, float16>;
template class FindChannelAbsMaxFunctor<GPUContext, float>;
template class ChannelClipAndFakeQuantFunctor<GPUContext, float16>;
template class ChannelClipAndFakeQuantFunctor<GPUContext, float>;
template class ChannelClipFakeQuantDequantFunctor<GPUContext, float>;
template class FindRangeAbsMaxFunctor<GPUContext, float16>;
template class FindRangeAbsMaxFunctor<GPUContext, float>;
template class ClipAndFakeQuantDequantFunctor<GPUContext, float16>;
template class ClipAndFakeQuantDequantFunctor<GPUContext, float>;
} // namespace funcs
} // namespace phi