chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/kernels/strings/unicode.h"
|
||||
#if defined(__NVCC__) || defined(__HIPCC__)
|
||||
#include <thrust/device_vector.h>
|
||||
#include <thrust/execution_policy.h>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
using pstring = dtype::pstring;
|
||||
struct AsciiToLower {
|
||||
HOSTDEVICE char operator()(char in) const {
|
||||
return ('A' <= in && in <= 'Z') ? in - ('Z' - 'z') : in;
|
||||
}
|
||||
};
|
||||
|
||||
struct AsciiToUpper {
|
||||
HOSTDEVICE char operator()(char in) const {
|
||||
return ('a' <= in && in <= 'z') ? in ^ 0x20 : in;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct UTF8ToLower {
|
||||
HOSTDEVICE UTF8ToLower(const uint8_t* unicode_flag_map,
|
||||
const uint16_t* cases_map)
|
||||
: unicode_flag_map_(unicode_flag_map), cases_map_(cases_map) {}
|
||||
|
||||
HOSTDEVICE uint32_t operator()(uint32_t in) const {
|
||||
uint32_t flg = (in <= 0x00FFFF ? unicode_flag_map_[in] : 0);
|
||||
return (strings::IsUpper(flg) ? cases_map_[in] : in);
|
||||
}
|
||||
|
||||
const uint8_t* unicode_flag_map_;
|
||||
const uint16_t* cases_map_;
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct UTF8ToUpper {
|
||||
HOSTDEVICE UTF8ToUpper(const uint8_t* unicode_flag_map,
|
||||
const uint16_t* cases_map)
|
||||
: unicode_flag_map_(unicode_flag_map), cases_map_(cases_map) {}
|
||||
|
||||
HOSTDEVICE uint32_t operator()(uint32_t in) const {
|
||||
uint32_t flg = (in <= 0x00FFFF ? unicode_flag_map_[in] : 0);
|
||||
return (strings::IsLower(flg) ? cases_map_[in] : in);
|
||||
}
|
||||
|
||||
const uint8_t* unicode_flag_map_;
|
||||
const uint16_t* cases_map_;
|
||||
};
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Copyright (c) 2022 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/strings/strings_copy_kernel.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi::strings {
|
||||
|
||||
template <typename Context>
|
||||
void Copy(const Context& dev_ctx,
|
||||
const StringTensor& src,
|
||||
bool blocking,
|
||||
StringTensor* dst) {
|
||||
auto* src_ptr = src.data();
|
||||
const auto& src_place = src.place();
|
||||
|
||||
VLOG(3) << "StringTensorCopy " << src.dims() << " from " << src.place()
|
||||
<< " to " << src_place;
|
||||
|
||||
dst->Resize(src.dims());
|
||||
dtype::pstring* dst_ptr = dev_ctx.template Alloc<dtype::pstring>(dst);
|
||||
|
||||
if (src_ptr == dst_ptr) {
|
||||
VLOG(3) << "Skip copy the same string data async from " << src_place
|
||||
<< " to " << src_place;
|
||||
return;
|
||||
}
|
||||
VLOG(4) << "src:" << src_ptr << ", dst:" << dst_ptr;
|
||||
int64_t numel = src.numel();
|
||||
|
||||
if (src_place.GetType() == AllocationType::CPU) {
|
||||
for (int64_t i = 0; i < numel; ++i) {
|
||||
dst_ptr[i] = src_ptr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
template PADDLE_API void Copy<CPUContext>(const CPUContext&,
|
||||
const StringTensor&,
|
||||
bool,
|
||||
StringTensor*);
|
||||
#endif
|
||||
} // namespace phi::strings
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(strings_copy,
|
||||
CPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::Copy<phi::CPUContext>) {}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Copyright (c) 2022 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/strings/strings_lower_upper_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/cpu/cpu_context.h"
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi::strings {
|
||||
|
||||
template <typename ContextT>
|
||||
void StringLowerKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out) {
|
||||
StringCaseConvertKernel<AsciiCaseConverter<ContextT, AsciiToLower>,
|
||||
UTF8CaseConverter<ContextT, UTF8ToLower>,
|
||||
ContextT>()(dev_ctx, x, use_utf8_encoding, out);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void StringUpperKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out) {
|
||||
StringCaseConvertKernel<AsciiCaseConverter<ContextT, AsciiToUpper>,
|
||||
UTF8CaseConverter<ContextT, UTF8ToUpper>,
|
||||
ContextT>()(dev_ctx, x, use_utf8_encoding, out);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
template PADDLE_API void StringLowerKernel<CPUContext>(const CPUContext&,
|
||||
const StringTensor& x,
|
||||
bool,
|
||||
StringTensor*);
|
||||
|
||||
template PADDLE_API void StringUpperKernel<CPUContext>(const CPUContext&,
|
||||
const StringTensor& x,
|
||||
bool,
|
||||
StringTensor*);
|
||||
#endif
|
||||
} // namespace phi::strings
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_lower,
|
||||
CPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::StringLowerKernel<phi::CPUContext>) {}
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_upper,
|
||||
CPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::StringUpperKernel<phi::CPUContext>) {}
|
||||
@@ -0,0 +1,198 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
#pragma once
|
||||
#include "paddle/phi/backends/gpu/gpu_helper.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/string_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
__global__ void SerializeStringsData(const phi::dtype::pstring* src_str,
|
||||
uint8_t* strings_data,
|
||||
int32_t* strings_offset,
|
||||
int64_t numel,
|
||||
int32_t start_offset) {
|
||||
if (threadIdx.x == 0 && blockIdx.x == 0) {
|
||||
strings_offset[0] = start_offset;
|
||||
for (int64_t i = 1; i <= numel; ++i) {
|
||||
strings_offset[i] = strings_offset[i - 1] + src_str[i - 1].length() + 1;
|
||||
}
|
||||
}
|
||||
__syncthreads();
|
||||
CUDA_KERNEL_LOOP(i, numel) {
|
||||
memcpy(strings_data + strings_offset[i],
|
||||
src_str[i].data(),
|
||||
src_str[i].length() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void SumStringsLen(const phi::dtype::pstring* src_ptr,
|
||||
int64_t numel,
|
||||
int* num) {
|
||||
extern __shared__ int counter[];
|
||||
int thread_counter = 0;
|
||||
CUDA_KERNEL_LOOP(i, numel) { thread_counter += src_ptr[i].length() + 1; }
|
||||
counter[threadIdx.x] = thread_counter;
|
||||
__syncthreads();
|
||||
if (threadIdx.x == 0) {
|
||||
int block_counter = 0;
|
||||
for (int i = 0; i < blockDim.x; ++i) {
|
||||
block_counter += counter[i];
|
||||
}
|
||||
atomicAdd(num, block_counter);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
int GetAllStringsSize(const Context& dev_ctx,
|
||||
const phi::dtype::pstring* src_ptr,
|
||||
size_t numel) {
|
||||
auto nums_meta = phi::DenseTensorMeta(DataType::INT32, {1}, DataLayout::NCHW);
|
||||
DenseTensor nums_tensor = Empty(dev_ctx, std::move(nums_meta));
|
||||
|
||||
int* nums_ptr = dev_ctx.template Alloc<int>(&nums_tensor);
|
||||
phi::backends::gpu::GpuMemsetAsync(
|
||||
nums_ptr, 0, sizeof(int), dev_ctx.stream());
|
||||
|
||||
dim3 block_size = dim3(PREDEFINED_BLOCK_SIZE, 1);
|
||||
dim3 grid_size =
|
||||
dim3((numel + PREDEFINED_BLOCK_SIZE - 1) / PREDEFINED_BLOCK_SIZE, 1);
|
||||
SumStringsLen<<<grid_size,
|
||||
block_size,
|
||||
PREDEFINED_BLOCK_SIZE * sizeof(int),
|
||||
dev_ctx.stream()>>>(src_ptr, numel, nums_ptr);
|
||||
int num = -1;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
phi::backends::gpu::GpuMemcpyAsync(
|
||||
&num, nums_ptr, sizeof(int), hipMemcpyDeviceToHost, dev_ctx.stream());
|
||||
#else
|
||||
phi::backends::gpu::GpuMemcpyAsync(
|
||||
&num, nums_ptr, sizeof(int), cudaMemcpyDeviceToHost, dev_ctx.stream());
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
|
||||
__global__ void DeserializeCUDAKernel(const char* strings_data,
|
||||
const int* strings_offset,
|
||||
phi::dtype::pstring* dst_str,
|
||||
int numel) {
|
||||
CUDA_KERNEL_LOOP(i, numel) {
|
||||
// -1 not include '\0'
|
||||
auto len = strings_offset[i + 1] - strings_offset[i] - 1;
|
||||
dst_str[i] = phi::dtype::pstring(strings_data + strings_offset[i], len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Context>
|
||||
void SerializeOnCPU(const Context& dev_ctx,
|
||||
const StringTensor& src,
|
||||
DenseTensor* dst) {
|
||||
int64_t numel = src.numel();
|
||||
int64_t num = sizeof(int) * (numel + 1);
|
||||
auto* src_str = src.data();
|
||||
for (int64_t i = 0; i < numel; ++i) {
|
||||
num += src_str[i].length() + 1;
|
||||
}
|
||||
dst->Resize({num});
|
||||
uint8_t* strings_data = dev_ctx.template HostAlloc<uint8_t>(dst);
|
||||
auto* strings_offset = reinterpret_cast<int*>(strings_data);
|
||||
int start_offset = sizeof(int) * (numel + 1);
|
||||
for (int64_t i = 0; i <= numel; ++i) {
|
||||
if (i == 0) {
|
||||
strings_offset[i] = start_offset;
|
||||
} else {
|
||||
strings_offset[i] = strings_offset[i - 1] + src_str[i - 1].length() + 1;
|
||||
}
|
||||
}
|
||||
for (int64_t i = 0; i < numel; ++i) {
|
||||
memcpy(strings_data + strings_offset[i],
|
||||
src_str[i].data(),
|
||||
src_str[i].length() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
void DeserializeOnCPU(const Context& dev_ctx,
|
||||
const DenseTensor& src,
|
||||
StringTensor* dst) {
|
||||
auto* strings_data = reinterpret_cast<const char*>(src.data<uint8_t>());
|
||||
auto* strings_offset = reinterpret_cast<const int*>(strings_data);
|
||||
int numel = strings_offset[0] / sizeof(int) - 1;
|
||||
dst->Resize({numel});
|
||||
dtype::pstring* dst_str = dev_ctx.template HostAlloc<dtype::pstring>(dst);
|
||||
for (int i = 0; i < numel; ++i) {
|
||||
// -1 not include '\0'
|
||||
auto len = strings_offset[i + 1] - strings_offset[i] - 1;
|
||||
dst_str[i] = phi::dtype::pstring(strings_data + strings_offset[i], len);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
void SerializeOnGPU(const phi::GPUContext& dev_ctx,
|
||||
const StringTensor& src,
|
||||
DenseTensor* dst) {
|
||||
int64_t numel = src.numel();
|
||||
auto* src_str = src.data();
|
||||
// 1.get the number of bytes of all strings in string tensor
|
||||
auto strings_size = GetAllStringsSize(dev_ctx, src_str, numel);
|
||||
strings_size += sizeof(int32_t) * (numel + 1);
|
||||
|
||||
dst->Resize({strings_size});
|
||||
uint8_t* strings_data = dev_ctx.template Alloc<uint8_t>(dst);
|
||||
auto* strings_offset = reinterpret_cast<int*>(strings_data);
|
||||
|
||||
int32_t start_offset = sizeof(int32_t) * (numel + 1);
|
||||
// 2. serialize strings data to dense tensor
|
||||
dim3 block_size = dim3(PREDEFINED_BLOCK_SIZE, 1);
|
||||
dim3 grid_size =
|
||||
dim3((numel + PREDEFINED_BLOCK_SIZE - 1) / PREDEFINED_BLOCK_SIZE, 1);
|
||||
|
||||
SerializeStringsData<<<grid_size, block_size, 0, dev_ctx.stream()>>>(
|
||||
src_str, strings_data, strings_offset, numel, start_offset);
|
||||
}
|
||||
|
||||
void DeserializeOnGPU(const phi::GPUContext& dev_ctx,
|
||||
const DenseTensor& src,
|
||||
StringTensor* dst) {
|
||||
auto* strings_data = reinterpret_cast<const char*>(src.data<uint8_t>());
|
||||
auto* strings_offset = reinterpret_cast<const int*>(strings_data);
|
||||
int numel = 0;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
&numel, strings_data, sizeof(numel), hipMemcpyDeviceToHost);
|
||||
#else
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
&numel, strings_data, sizeof(numel), cudaMemcpyDeviceToHost);
|
||||
#endif
|
||||
numel = numel / sizeof(int) - 1;
|
||||
dst->Resize({numel});
|
||||
dtype::pstring* dst_str = dev_ctx.template Alloc<dtype::pstring>(dst);
|
||||
|
||||
dim3 block_size = dim3(PREDEFINED_BLOCK_SIZE, 1);
|
||||
dim3 grid_size =
|
||||
dim3((numel + PREDEFINED_BLOCK_SIZE - 1) / PREDEFINED_BLOCK_SIZE, 1);
|
||||
DeserializeCUDAKernel<<<grid_size, block_size, 0, dev_ctx.stream()>>>(
|
||||
strings_data, strings_offset, dst_str, numel);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,127 @@
|
||||
/* Copyright (c) 2022 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/strings/strings_copy_kernel.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_helper.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/empty_kernel.h"
|
||||
#include "paddle/phi/kernels/strings/gpu/copy_utils.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
__global__ void CopyFromStringTensor(pstring* dst,
|
||||
const pstring* src,
|
||||
int64_t num) {
|
||||
CUDA_KERNEL_LOOP(i, num) { dst[i] = src[i]; }
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
void Copy(const Context& dev_ctx,
|
||||
const StringTensor& src,
|
||||
bool blocking,
|
||||
StringTensor* dst) {
|
||||
auto* src_ptr = src.data();
|
||||
const auto& src_place = src.place();
|
||||
auto dst_place = dst->place();
|
||||
|
||||
if (src_place == dst_place && src_place.GetType() == AllocationType::CPU) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"The src and dst string tensor are all "
|
||||
"CPU string tensor, you should call copy "
|
||||
"function in CPU mode."));
|
||||
}
|
||||
VLOG(3) << "StringTensorCopy " << src.dims() << " from " << src.place()
|
||||
<< " to " << dst_place;
|
||||
|
||||
dst->Resize(src.dims());
|
||||
auto* dst_ptr = dev_ctx.template Alloc<dtype::pstring>(dst);
|
||||
|
||||
if (src_ptr == dst_ptr && src_place == dst_place) {
|
||||
VLOG(3) << "Skip copy the same string data async from " << src_place
|
||||
<< " to " << dst_place;
|
||||
return;
|
||||
}
|
||||
|
||||
VLOG(4) << "src:" << src_ptr << ", dst:" << dst_ptr;
|
||||
|
||||
if (src_place.GetType() == AllocationType::GPU &&
|
||||
dst_place.GetType() == AllocationType::CPU) {
|
||||
// Situation 1: gpu_place->cpu_place
|
||||
DenseTensor gpu_serialized = Empty<uint8_t, GPUContext>(dev_ctx, {1});
|
||||
phi::strings::SerializeOnGPU(dev_ctx, src, &gpu_serialized);
|
||||
|
||||
DenseTensor cpu_serialized;
|
||||
cpu_serialized.Resize(gpu_serialized.dims());
|
||||
dev_ctx.template HostAlloc<uint8_t>(&cpu_serialized);
|
||||
|
||||
phi::Copy(dev_ctx, gpu_serialized, dst_place, false, &cpu_serialized);
|
||||
|
||||
phi::strings::DeserializeOnCPU(dev_ctx, cpu_serialized, dst);
|
||||
|
||||
} else if (src_place.GetType() == AllocationType::CPU &&
|
||||
dst_place.GetType() == AllocationType::GPU) {
|
||||
// Situation 2: cpu_place->gpu_place
|
||||
DenseTensor cpu_serialized;
|
||||
cpu_serialized.Resize({1});
|
||||
dev_ctx.template HostAlloc<uint8_t>(&cpu_serialized);
|
||||
|
||||
phi::strings::SerializeOnCPU(dev_ctx, src, &cpu_serialized);
|
||||
|
||||
DenseTensor gpu_serialized = EmptyLike<uint8_t>(dev_ctx, cpu_serialized);
|
||||
phi::Copy(
|
||||
dev_ctx, cpu_serialized, dev_ctx.GetPlace(), false, &gpu_serialized);
|
||||
|
||||
phi::strings::DeserializeOnGPU(dev_ctx, gpu_serialized, dst);
|
||||
} else if (src_place.GetType() == AllocationType::GPU &&
|
||||
dst_place.GetType() == AllocationType::GPU) {
|
||||
// Situation 3: gpu_place->gpu_place
|
||||
auto src_gpu_place = src_place;
|
||||
auto dst_gpu_place = dst_place;
|
||||
auto ctx_place = dev_ctx.GetPlace();
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ctx_place.GetType(),
|
||||
AllocationType::GPU,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Context place error, excepted GPUPlace, but actually %s.",
|
||||
ctx_place));
|
||||
int64_t numel = src.numel();
|
||||
dim3 block_size = dim3(PREDEFINED_BLOCK_SIZE, 1);
|
||||
dim3 grid_size =
|
||||
dim3((numel + PREDEFINED_BLOCK_SIZE - 1) / PREDEFINED_BLOCK_SIZE, 1);
|
||||
// Copy
|
||||
CopyFromStringTensor<<<grid_size, block_size, 0, dev_ctx.stream()>>>(
|
||||
dst_ptr, src_ptr, numel);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
template PADDLE_API void Copy<GPUContext>(const GPUContext&,
|
||||
const StringTensor&,
|
||||
bool,
|
||||
StringTensor*);
|
||||
#endif
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(strings_copy,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::Copy<phi::GPUContext>) {}
|
||||
@@ -0,0 +1,193 @@
|
||||
/* Copyright (c) 2022 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/strings/strings_lower_upper_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/pstring.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/strings/unicode.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
template <typename CharConverter>
|
||||
__global__ void StringCaseConvertCUDAKernel(pstring* out,
|
||||
const pstring* in,
|
||||
size_t num) {
|
||||
CUDA_KERNEL_LOOP(i, num) {
|
||||
out[i] = pstring(in[i]);
|
||||
thrust::transform(thrust::device,
|
||||
in[i].begin(),
|
||||
in[i].end(),
|
||||
out[i].mdata(),
|
||||
CharConverter());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CharConverter>
|
||||
struct AsciiCaseConverter<phi::GPUContext, CharConverter> {
|
||||
void operator()(const phi::GPUContext& dev_ctx,
|
||||
const pstring* in,
|
||||
pstring* out,
|
||||
size_t num) const {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
dim3 block_size = dim3(256, 1);
|
||||
#else
|
||||
dim3 block_size = dim3(PREDEFINED_BLOCK_SIZE, 1);
|
||||
#endif
|
||||
dim3 grid_size =
|
||||
dim3((num + PREDEFINED_BLOCK_SIZE - 1) / PREDEFINED_BLOCK_SIZE, 1);
|
||||
StringCaseConvertCUDAKernel<CharConverter>
|
||||
<<<grid_size, block_size, 0, dev_ctx.stream()>>>(out, in, num);
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename DeviceContextT> typename CharConverter>
|
||||
struct UTF8CaseConverter<phi::GPUContext, CharConverter> {
|
||||
void operator()(const phi::GPUContext& dev_ctx,
|
||||
const pstring* in,
|
||||
pstring* out,
|
||||
size_t num) const {
|
||||
auto unicode_flag_map = GetGPUUniflagMap();
|
||||
auto cases_map = GetGPUCharCasesMap();
|
||||
thrust::device_vector<uint32_t> unicode_offsets(num + 1, 0);
|
||||
uint32_t* unicode_offsets_ptr =
|
||||
thrust::raw_pointer_cast(unicode_offsets.data());
|
||||
|
||||
thrust::for_each_n(thrust::device,
|
||||
thrust::make_counting_iterator<unsigned int>(0),
|
||||
num,
|
||||
[unicode_offsets_ptr, in] __device__(uint32_t idx) {
|
||||
unicode_offsets_ptr[idx + 1] =
|
||||
GetUnicodeStrLen(in[idx].data(), in[idx].size());
|
||||
});
|
||||
uint32_t total_lengths = thrust::reduce(
|
||||
thrust::device, unicode_offsets_ptr, unicode_offsets_ptr + num + 1, 0);
|
||||
if (total_lengths == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
thrust::device_vector<uint32_t> unicode_output(total_lengths, 0);
|
||||
uint32_t* unicode_output_ptr =
|
||||
thrust::raw_pointer_cast(unicode_output.data());
|
||||
|
||||
CharConverter<GPUContext> converter(unicode_flag_map, cases_map);
|
||||
thrust::for_each_n(
|
||||
thrust::device,
|
||||
thrust::make_counting_iterator<unsigned int>(0),
|
||||
num,
|
||||
[in,
|
||||
out,
|
||||
unicode_output_ptr,
|
||||
unicode_offsets_ptr,
|
||||
converter] __device__(uint32_t idx) {
|
||||
uint32_t unicode_len =
|
||||
unicode_offsets_ptr[idx + 1] - unicode_offsets_ptr[idx];
|
||||
GetUnicodeStr(in[idx].data(),
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx],
|
||||
unicode_len);
|
||||
uint32_t* curr_unicode_output_ptr =
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx];
|
||||
for (uint32_t i = 0; i < unicode_len; ++i) {
|
||||
curr_unicode_output_ptr[i] = converter(curr_unicode_output_ptr[i]);
|
||||
}
|
||||
thrust::transform(thrust::device,
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx],
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx + 1],
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx],
|
||||
converter);
|
||||
});
|
||||
|
||||
thrust::device_vector<uint32_t> utf8_offsets(num + 1, 0);
|
||||
uint32_t* utf8_offsets_ptr = thrust::raw_pointer_cast(utf8_offsets.data());
|
||||
|
||||
thrust::for_each_n(
|
||||
thrust::device,
|
||||
thrust::make_counting_iterator<unsigned int>(0),
|
||||
num,
|
||||
[utf8_offsets_ptr, unicode_output_ptr, unicode_offsets_ptr] __device__(
|
||||
uint32_t idx) {
|
||||
uint32_t unicode_len =
|
||||
unicode_offsets_ptr[idx + 1] - unicode_offsets_ptr[idx];
|
||||
utf8_offsets_ptr[idx + 1] = GetUTF8StrLen(
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx], unicode_len);
|
||||
});
|
||||
uint32_t total_utf8_lengths = thrust::reduce(
|
||||
thrust::device, utf8_offsets_ptr, utf8_offsets_ptr + num + 1, 0);
|
||||
|
||||
thrust::device_vector<char> utf8_output(total_utf8_lengths, 0);
|
||||
char* utf8_output_ptr = thrust::raw_pointer_cast(utf8_output.data());
|
||||
thrust::for_each_n(thrust::device,
|
||||
thrust::make_counting_iterator<unsigned int>(0),
|
||||
num,
|
||||
[utf8_output_ptr,
|
||||
utf8_offsets_ptr,
|
||||
unicode_output_ptr,
|
||||
unicode_offsets_ptr,
|
||||
out] __device__(uint32_t idx) {
|
||||
uint32_t unicode_len = unicode_offsets_ptr[idx + 1] -
|
||||
unicode_offsets_ptr[idx];
|
||||
const uint32_t* input_ptr =
|
||||
unicode_output_ptr + unicode_offsets_ptr[idx];
|
||||
char* result_ptr =
|
||||
utf8_output_ptr + utf8_offsets_ptr[idx];
|
||||
GetUTF8Str(input_ptr, result_ptr, unicode_len);
|
||||
out[idx] = result_ptr;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ContextT>
|
||||
void StringLowerKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out) {
|
||||
StringCaseConvertKernel<AsciiCaseConverter<ContextT, AsciiToLower>,
|
||||
UTF8CaseConverter<ContextT, UTF8ToLower>,
|
||||
ContextT>()(dev_ctx, x, use_utf8_encoding, out);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void StringUpperKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out) {
|
||||
StringCaseConvertKernel<AsciiCaseConverter<ContextT, AsciiToUpper>,
|
||||
UTF8CaseConverter<ContextT, UTF8ToUpper>,
|
||||
ContextT>()(dev_ctx, x, use_utf8_encoding, out);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
template PADDLE_API void StringLowerKernel<GPUContext>(const GPUContext&,
|
||||
const StringTensor& x,
|
||||
bool,
|
||||
StringTensor*);
|
||||
|
||||
template PADDLE_API void StringUpperKernel<GPUContext>(const GPUContext&,
|
||||
const StringTensor& x,
|
||||
bool,
|
||||
StringTensor*);
|
||||
#endif
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_lower,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::StringLowerKernel<phi::GPUContext>) {}
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_upper,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::StringUpperKernel<phi::GPUContext>) {}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/core/string_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
template <typename Context>
|
||||
void Copy(const Context& dev_ctx,
|
||||
const StringTensor& src,
|
||||
bool blocking,
|
||||
StringTensor* dst);
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2022 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/strings/strings_empty_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi::strings {
|
||||
|
||||
template <typename Context>
|
||||
void EmptyKernel(const Context& dev_ctx,
|
||||
const IntArray& shape,
|
||||
StringTensor* out) {
|
||||
out->Resize(shape.GetData());
|
||||
dev_ctx.template Alloc<dtype::pstring>(out);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
void EmptyLikeKernel(const Context& dev_ctx, StringTensor* out) {
|
||||
dev_ctx.template Alloc<dtype::pstring>(out);
|
||||
}
|
||||
|
||||
} // namespace phi::strings
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(strings_empty,
|
||||
CPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::EmptyKernel<phi::CPUContext>) {}
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_empty_like,
|
||||
CPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::EmptyLikeKernel<phi::CPUContext>) {}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(strings_empty,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::EmptyKernel<phi::GPUContext>) {}
|
||||
|
||||
PD_REGISTER_KERNEL_FOR_ALL_DTYPE(
|
||||
strings_empty_like,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::strings::EmptyLikeKernel<phi::GPUContext>) {}
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/api/lib/utils/allocator.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/phi/core/string_tensor.h"
|
||||
#include "paddle/phi/infermeta/strings/nullary.h"
|
||||
#include "paddle/phi/infermeta/strings/unary.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
template <typename Context>
|
||||
void EmptyKernel(const Context& dev_ctx,
|
||||
const IntArray& shape,
|
||||
StringTensor* out);
|
||||
|
||||
template <typename Context>
|
||||
void EmptyLikeKernel(const Context& dev_ctx, StringTensor* out);
|
||||
|
||||
// TODO(zhoushunjie): the tensor creation method need to be replaced later,
|
||||
// all kernel api call Empty here instead of making tensor self
|
||||
template <typename Context>
|
||||
StringTensor Empty(const Context& dev_ctx, StringTensorMeta&& meta) {
|
||||
auto allocator = std::make_unique<paddle::experimental::DefaultAllocator>(
|
||||
dev_ctx.GetPlace());
|
||||
phi::StringTensor string_out(allocator.get(), std::move(meta));
|
||||
return string_out;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
StringTensor Empty(const Context& dev_ctx) {
|
||||
return Empty<Context>(dev_ctx, {{-1}});
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
StringTensor Empty(const Context& dev_ctx, const IntArray& shape) {
|
||||
StringTensor string_out;
|
||||
MetaTensor meta_out(&string_out);
|
||||
phi::strings::CreateInferMeta(shape, &meta_out);
|
||||
EmptyKernel<Context>(dev_ctx, shape, &string_out);
|
||||
return string_out;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
StringTensor EmptyLike(const Context& dev_ctx, const StringTensor& x) {
|
||||
StringTensor string_out;
|
||||
MetaTensor meta_out(&string_out);
|
||||
phi::strings::UnchangedInferMeta(x.meta(), &meta_out);
|
||||
EmptyLikeKernel<Context>(dev_ctx, &string_out);
|
||||
return string_out;
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,120 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/lib/utils/allocator.h"
|
||||
#include "paddle/phi/core/string_tensor.h"
|
||||
#include "paddle/phi/infermeta/strings/unary.h"
|
||||
#include "paddle/phi/kernels/strings/case_utils.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
template <typename ContextT>
|
||||
void StringLowerKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out);
|
||||
|
||||
template <typename ContextT>
|
||||
void StringUpperKernel(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out);
|
||||
|
||||
template <typename ContextT>
|
||||
StringTensor StringLower(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding) {
|
||||
StringTensor string_out;
|
||||
MetaTensor meta_out(&string_out);
|
||||
UnchangedInferMeta(x.meta(), &meta_out);
|
||||
StringLowerKernel(dev_ctx, x, use_utf8_encoding, &string_out);
|
||||
return string_out;
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
StringTensor StringUpper(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding) {
|
||||
StringTensor string_out;
|
||||
MetaTensor meta_out(&string_out);
|
||||
UnchangedInferMeta(x.meta(), &meta_out);
|
||||
StringUpperKernel(dev_ctx, x, use_utf8_encoding, &string_out);
|
||||
return string_out;
|
||||
}
|
||||
|
||||
template <typename AsciiConverter, typename UTF8Converter, typename ContextT>
|
||||
struct StringCaseConvertKernel {
|
||||
void operator()(const ContextT& dev_ctx,
|
||||
const StringTensor& x,
|
||||
bool use_utf8_encoding,
|
||||
StringTensor* out) {
|
||||
AsciiConverter ascii_converter;
|
||||
UTF8Converter utf8_converter;
|
||||
const pstring* in_ptr = x.data();
|
||||
pstring* out_ptr = dev_ctx.template Alloc<pstring>(out);
|
||||
auto num = x.numel();
|
||||
if (!use_utf8_encoding) {
|
||||
ascii_converter(dev_ctx, in_ptr, out_ptr, num);
|
||||
} else {
|
||||
utf8_converter(dev_ctx, in_ptr, out_ptr, num);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DeviceContext, typename CharConverter>
|
||||
struct AsciiCaseConverter {
|
||||
void operator()(const DeviceContext& dev_ctx UNUSED,
|
||||
const pstring* in,
|
||||
pstring* out,
|
||||
size_t num) const {
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
std::transform(
|
||||
in[i].begin(), in[i].end(), out[i].mdata(), CharConverter());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DeviceContext,
|
||||
template <typename DeviceContextT>
|
||||
class CharConverter>
|
||||
struct UTF8CaseConverter {
|
||||
void operator()(const DeviceContext& dev_ctx UNUSED,
|
||||
const pstring* in,
|
||||
pstring* out,
|
||||
size_t num) const {
|
||||
auto unicode_flag_map = GetUniFlagMap();
|
||||
auto cases_map = GetCharCasesMap();
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
uint32_t unicode_len = GetUnicodeStrLen(in[i].data(), in[i].size());
|
||||
std::vector<uint32_t> unicode_in(unicode_len, 0);
|
||||
GetUnicodeStr(in[i].data(), unicode_in.data(), unicode_len);
|
||||
std::transform(unicode_in.begin(),
|
||||
unicode_in.end(),
|
||||
unicode_in.begin(),
|
||||
CharConverter<DeviceContext>(unicode_flag_map, cases_map));
|
||||
uint32_t utf8_len = GetUTF8StrLen(unicode_in.data(), unicode_len);
|
||||
std::vector<char> result(utf8_len, 0);
|
||||
GetUTF8Str(unicode_in.data(), result.data(), unicode_len);
|
||||
out[i] = result.data();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Copyright (c) 2022 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/strings/unicode.h"
|
||||
|
||||
#include <utf8proc.h>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/kernels/strings/unicode_flag.h"
|
||||
|
||||
namespace phi::strings {
|
||||
|
||||
static const void* utils_map[4] = {nullptr}; // NOLINT
|
||||
static uint16_t CHAR_CASES_MAP[65536] = {0}; // NOLINT
|
||||
|
||||
const uint8_t* GetUniFlagMap() {
|
||||
if (utils_map[1] == nullptr) {
|
||||
utils_map[1] = UNIFLAG_MAP;
|
||||
}
|
||||
return reinterpret_cast<const uint8_t*>(utils_map[1]);
|
||||
}
|
||||
|
||||
const uint16_t* GetCharCasesMap() {
|
||||
if (utils_map[0] == nullptr) {
|
||||
for (uint32_t i = 0; i < 65536; ++i) {
|
||||
if (utf8proc_islower(static_cast<int32_t>(i))) {
|
||||
CHAR_CASES_MAP[i] = utf8proc_toupper(static_cast<int32_t>(i));
|
||||
} else if (utf8proc_isupper(static_cast<int32_t>(i))) {
|
||||
CHAR_CASES_MAP[i] = utf8proc_tolower(static_cast<int32_t>(i));
|
||||
}
|
||||
}
|
||||
utils_map[0] = CHAR_CASES_MAP;
|
||||
}
|
||||
return reinterpret_cast<const uint16_t*>(utils_map[0]);
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
|
||||
const uint8_t* GetGPUUniflagMap() {
|
||||
if (utils_map[3] == nullptr) {
|
||||
const uint8_t* cpu_uniflag = GetUniFlagMap();
|
||||
auto size = sizeof(UNIFLAG_MAP);
|
||||
uint8_t* gpu_uniflag;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMalloc(reinterpret_cast<void**>(&gpu_uniflag), size);
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
gpu_uniflag, cpu_uniflag, size, hipMemcpyHostToDevice);
|
||||
#else
|
||||
cudaMalloc(reinterpret_cast<void**>(&gpu_uniflag), size);
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
gpu_uniflag, cpu_uniflag, size, cudaMemcpyHostToDevice);
|
||||
#endif
|
||||
utils_map[3] = gpu_uniflag;
|
||||
}
|
||||
return reinterpret_cast<const uint8_t*>(utils_map[3]);
|
||||
}
|
||||
|
||||
const uint16_t* GetGPUCharCasesMap() {
|
||||
if (utils_map[2] == nullptr) {
|
||||
const uint16_t* cpu_char_cases = GetCharCasesMap();
|
||||
auto size = sizeof(CHAR_CASES_MAP);
|
||||
uint16_t* gpu_char_cases;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMalloc(reinterpret_cast<void**>(&gpu_char_cases), size);
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
gpu_char_cases, cpu_char_cases, size, hipMemcpyHostToDevice);
|
||||
#else
|
||||
cudaMalloc(reinterpret_cast<void**>(&gpu_char_cases), size);
|
||||
phi::backends::gpu::GpuMemcpySync(
|
||||
gpu_char_cases, cpu_char_cases, size, cudaMemcpyHostToDevice);
|
||||
#endif
|
||||
utils_map[2] = gpu_char_cases;
|
||||
}
|
||||
return reinterpret_cast<const uint16_t*>(utils_map[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace phi::strings
|
||||
@@ -0,0 +1,199 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "paddle/common/hostdevice.h"
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace phi {
|
||||
namespace strings {
|
||||
|
||||
HOSTDEVICE inline bool IsSpace(uint32_t chr) { return (chr & 16) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsAlpha(uint32_t chr) { return (chr & 8) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsDigit(uint32_t chr) { return (chr & 4) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsNumeric(uint32_t chr) { return (chr & 2) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsDecimal(uint32_t chr) { return (chr & 1) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsAlphaNum(uint32_t chr) { return (chr & 15) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsUpper(uint32_t chr) { return (chr & 32) > 0; }
|
||||
|
||||
HOSTDEVICE inline bool IsLower(uint32_t chr) { return (chr & 64) > 0; }
|
||||
|
||||
HOSTDEVICE inline uint32_t BytesInUtf8Char(uint8_t byte) {
|
||||
unsigned int count = 1;
|
||||
// no if-statements means no divergence
|
||||
count += static_cast<int>((byte & 0xF0) == 0xF0);
|
||||
count += static_cast<int>((byte & 0xE0) == 0xE0);
|
||||
count += static_cast<int>((byte & 0xC0) == 0xC0);
|
||||
count -= static_cast<int>((byte & 0xC0) == 0x80);
|
||||
return count;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t UTF8ToUInt32(const char* pSrc, uint32_t* chr) {
|
||||
uint32_t chwidth = BytesInUtf8Char(static_cast<uint8_t>(*pSrc));
|
||||
*chr = static_cast<uint32_t>(*pSrc++) & 0xFF;
|
||||
if (chwidth > 1) {
|
||||
*chr = (*chr) << 8;
|
||||
*chr |= (static_cast<uint32_t>(*pSrc++) & 0xFF); // << 8;
|
||||
if (chwidth > 2) {
|
||||
*chr = (*chr) << 8;
|
||||
*chr |= (static_cast<uint32_t>(*pSrc++) & 0xFF); // << 16;
|
||||
if (chwidth > 3) {
|
||||
*chr = (*chr) << 8;
|
||||
*chr |= (static_cast<uint32_t>(*pSrc++) & 0xFF); // << 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chwidth;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t UTF8ToUnicode(uint32_t utf8) {
|
||||
uint32_t unchr = 0;
|
||||
if (utf8 < 0x00000080) {
|
||||
unchr = utf8;
|
||||
} else if (utf8 < 0x0000E000) {
|
||||
unchr = (utf8 & 0x1F00) >> 2;
|
||||
unchr |= (utf8 & 0x003F);
|
||||
} else if (utf8 < 0x00F00000) {
|
||||
unchr = (utf8 & 0x0F0000) >> 4;
|
||||
unchr |= (utf8 & 0x003F00) >> 2;
|
||||
unchr |= (utf8 & 0x00003F);
|
||||
} else if (utf8 <= static_cast<uint32_t>(0xF8000000)) {
|
||||
unchr = (utf8 & 0x03000000) >> 6;
|
||||
unchr |= (utf8 & 0x003F0000) >> 4;
|
||||
unchr |= (utf8 & 0x00003F00) >> 2;
|
||||
unchr |= (utf8 & 0x0000003F);
|
||||
}
|
||||
return unchr;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t UnicodeToUTF8(uint32_t unchr) {
|
||||
uint32_t utf8 = 0;
|
||||
if (unchr < 0x00000080) {
|
||||
utf8 = unchr;
|
||||
} else if (unchr < 0x00000800) {
|
||||
utf8 = (unchr << 2) & 0x1F00;
|
||||
utf8 |= (unchr & 0x3F);
|
||||
utf8 |= 0x0000C080;
|
||||
} else if (unchr < 0x00010000) {
|
||||
utf8 = (unchr << 4) & 0x0F0000; // upper 4 bits
|
||||
utf8 |= (unchr << 2) & 0x003F00; // next 6 bits
|
||||
utf8 |= (unchr & 0x3F); // last 6 bits
|
||||
utf8 |= 0x00E08080;
|
||||
} else if (unchr < 0x00110000) { // 3-byte unicode
|
||||
utf8 = (unchr << 6) & 0x07000000; // upper 3 bits
|
||||
utf8 |= (unchr << 4) & 0x003F0000; // next 6 bits
|
||||
utf8 |= (unchr << 2) & 0x00003F00; // next 6 bits
|
||||
utf8 |= (unchr & 0x3F); // last 6 bits
|
||||
utf8 |= static_cast<uint32_t>(0xF0808080);
|
||||
}
|
||||
return utf8;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t BytesInUnicodeChar(uint32_t chr) {
|
||||
uint32_t count = 1;
|
||||
// no if-statements means no divergence
|
||||
count += static_cast<int>((chr & static_cast<uint32_t>(0x0000FF00)) > 0);
|
||||
count += static_cast<int>((chr & static_cast<uint32_t>(0x00FF0000)) > 0);
|
||||
count += static_cast<int>((chr & static_cast<uint32_t>(0xFF000000)) > 0);
|
||||
return count;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t UnicodeToUTF8Char(uint32_t chr, char* dst) {
|
||||
uint32_t chwidth = BytesInUnicodeChar(chr);
|
||||
for (uint32_t idx = 0; idx < chwidth; ++idx) {
|
||||
dst[chwidth - idx - 1] = static_cast<char>(chr & 0xFF);
|
||||
chr = chr >> 8;
|
||||
}
|
||||
return chwidth;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline void GetUnicodeStr(const char* pSrc,
|
||||
uint32_t* unicode_str,
|
||||
size_t unicode_len) {
|
||||
uint32_t curr_unicode_char;
|
||||
uint32_t count = UTF8ToUInt32(pSrc, &curr_unicode_char);
|
||||
curr_unicode_char = UTF8ToUnicode(curr_unicode_char);
|
||||
for (size_t i = 0; i < unicode_len; ++i) {
|
||||
unicode_str[i] = curr_unicode_char;
|
||||
pSrc += count;
|
||||
count = UTF8ToUInt32(pSrc, &curr_unicode_char);
|
||||
curr_unicode_char = UTF8ToUnicode(curr_unicode_char);
|
||||
}
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t GetUnicodeStrLen(const char* pSrc, size_t size) {
|
||||
uint32_t curr_unicode_char;
|
||||
uint32_t count = 0;
|
||||
uint32_t offset = 0;
|
||||
uint32_t curr_count = 0;
|
||||
while (offset < size) {
|
||||
curr_count = UTF8ToUInt32(pSrc, &curr_unicode_char);
|
||||
offset += curr_count;
|
||||
pSrc += curr_count;
|
||||
if (curr_count == 0) {
|
||||
break;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
HOSTDEVICE inline uint32_t GetUTF8StrLen(const uint32_t* unicode_str,
|
||||
size_t unicode_len) {
|
||||
uint32_t utf8_str_count = 0;
|
||||
for (size_t i = 0; i < unicode_len; ++i) {
|
||||
uint32_t utf8_uint32 = UnicodeToUTF8(unicode_str[i]);
|
||||
utf8_str_count += BytesInUnicodeChar(utf8_uint32);
|
||||
}
|
||||
// +1 means '\0'
|
||||
return utf8_str_count + 1;
|
||||
}
|
||||
// Need to guarantee utf8_str has enough memory
|
||||
|
||||
HOSTDEVICE inline void GetUTF8Str(const uint32_t* unicode_str,
|
||||
char* utf8_str,
|
||||
size_t unicode_len) {
|
||||
char dst_char[5] = {0};
|
||||
for (size_t i = 0; i < unicode_len; ++i) {
|
||||
uint32_t utf8_uint32 = UnicodeToUTF8(unicode_str[i]);
|
||||
uint32_t utf8_char_count = UnicodeToUTF8Char(utf8_uint32, dst_char);
|
||||
dst_char[utf8_char_count] = '\0';
|
||||
memcpy(utf8_str, dst_char, utf8_char_count);
|
||||
utf8_str += utf8_char_count;
|
||||
}
|
||||
*utf8_str = '\0';
|
||||
}
|
||||
|
||||
const uint8_t* GetUniFlagMap();
|
||||
const uint16_t* GetCharCasesMap();
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
|
||||
const uint8_t* GetGPUUniflagMap();
|
||||
const uint16_t* GetGPUCharCasesMap();
|
||||
#endif
|
||||
|
||||
} // namespace strings
|
||||
} // namespace phi
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user