chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+74
View File
@@ -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>) {}
+198
View File
@@ -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
+89
View File
@@ -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
+199
View File
@@ -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