oneMKL:支持 SYCL 的 C++ API 用于数据拟合
Intel® oneAPI 数学内核库 (oneMKL) 现在增加了对 C++ 和 GPU 的支持,充分利用了 SYCL 跨平台抽象层。
一目了然的故事
- oneMKL 是一个为科学、工程和金融应用优化的数学例程库,自 2003 年 5 月起就已存在。其丰富的功能集使其自 2015 年以来成为核心数学函数的行业首选。1
- 它涵盖 BLAS、LAPACK、ScaLAPACK、稀疏求解器、快速傅里叶变换、数据拟合、随机数生成器和向量数学。
- 作为第一步,我们使样条和三次 Hermite 插值数据拟合和插值能够通过符合 SYCL 标准的 C++ API 直接访问。
- C++ 代码可以直接访问它,无需包装函数。
- 因此,这些计算可以无缝地在 Intel® GPU 和 CPU 上执行。
使用样条插值进行数据拟合
数据拟合使用插值技术,根据一组离散的已知数据点的范围构造新的数据点。
使用分段定义为多项式的样条曲线函数通常是首选方法。应用涵盖广泛的用途,包括科学、医疗保健、数据科学、神经网络、计算机辅助设计、计算机图形学和游戏物理引擎。
传统上,用于此目的的样条和插值例程是使用 C 或 Fortran API 实现的,这使得在将它们集成到 C++ 代码中时需要创建包装器。
然而,随着异构并行数据处理的出现,C++ 作为实现数据拟合的语言越来越受欢迎。
看待数据拟合的一种方式是将其视为一组用于执行样条插值(函数值和/或导数计算)和积分的函数。基于数据拟合的插值遵循以下数学概念:
假设我们需要在 \([a, b]\) 区间上使用样条插值函数 \(f(x)\)。
- 我们将 \([a, b]\) 分成 \(n\) 个点 \(x_i\) 之间的子区间,这些点称为分区点或简单称为分区。
- 这些点上的函数值 \((y_i=f(x_i ),ix_i),…,n)\) 也给出。
- 然后我们可以调用 \([a, b]\) 上点的 \(f(x)\) 插值。这些点称为插值点或简单地称为点。点可能等于也可能不等于分区点。
- 调用后,用户将获得插值结果。
也可以处理一个分区上的多个函数。函数值存储在一维数组中,包含 \(nx * ny\) 个元素。有两种不同的布局:行主序和列主序。
这两种布局的一维数组方法是我们早期实现所支持的。
尽管如此,如果所有分区的每个函数都存储在单独的内存位置,那也是可取的。这样,就可以按需实现。
使用 oneMKL 2022.1,已提供基于 C++ 的 SYCL 的一个预发行版本,用于线性样条和三次 Hermite 样条插值。这包括样条构造(生成样条系数)和插值,包括函数值和导数计算。我们还提供处理程序来存储您的输入数据。
所有这些工作的目的是建立符合未来标准的、标准的 C++ API 支持,使用 SYCL。一旦完全实现,我们将将其添加到我们提议的 API 中,作为 oneMKL 规范的一部分。它将成为基于行业标准、统一、多架构、多供应商的 oneAPI 编程模型的一部分。
注意: 您现在就可以通过我们的社区论坛提供反馈并建议对接口的更改或改进。我们期待您的意见。这将确保我们最好地满足您的软件开发需求,并将其整合到未来的版本中。
用法概述
oneMKL 中的数据拟合概述和详细的参考文档作为oneMKL 在线文档的一部分提供。不过,让我们以 oneMKL 的 SYCL 兼容 C++ API 用法作为参考,了解它如何应用于您的用例。
标准的用法流程如下:
- 初始化样条参数(例如,X 轴上的点数,要处理的函数数,系数内存分配等)。
- 创建数据集处理程序。您可能需要更改分区布局。这可以通过分区处理程序完成。使用处理程序可以简化样条自定义,而不是在样条构造函数中使用原始格式模板参数。
- 通过调用样条的“construct”方法来计算样条系数。这样做是在样条构造函数本身之外进行的,允许在构造函数外部处理返回数据。此外,它还允许您控制计算在执行流程中发生的精确时间点。
- 计算出的系数现在可以用于插值。
#include "oneapi/mkl/experimental/data_fitting.hpp"
namespace mkl_df = oneapi::mkl::experimental::data_fitiing;
int main() {
std::int64_t nx = 100000; // quantity of x points
std::int64_t ny = 5; // quantity of functions
sycl::usm_allocator<float, sycl::usm::alloc::shared> alloc(q);
std::vector<float, decltype(alloc)> partitions(nx, alloc);
std::vector<float, decltype(alloc)> coeffs(ny * (nx - 1) * 2, alloc);
std::vector<float, decltype(alloc)> functions(ny * nx, alloc);
…
// memory allocation for sites, results, partitions
// and initialization of partitions, functions
// Data Fitting usage
// create spline object to accumulate all data
mkl_df::spline<float, mkl_df::linear_spline::default_type> spl(q, ny);
// handle partitions, coefficients and function values
spl.set_partitions(partitions.data(), nx);
spl.set_coefficients(coeffs.data());
spl.set_function_value(functions.data());
// compute spline coefficients
auto event = spl.construct();
// interpolate data basing on computed spline coefficients (async call in general)
mkl_df::interpolate(spl, sites.data(), nsites, results.data()).wait();
…
}
完整的实际示例可以在 GitHub 上找到,作为oneMKL 示例以及oneMKL 数据并行 C++ 开发人员参考的一部分。
接口
让我们考虑接口。
注意:当前接口是实验性的,可能会根据用户的反馈在未来进行更改。
样条接口定义如下。我们有两个不同的构造函数:一个接受 SYCL 队列,另一个接受设备和上下文。
一个额外的参数名为“were_coeffs_computed
”,以防我们需要使用已预先计算的系数。
- 拷贝/移动构造函数和拷贝/移动赋值运算符已被删除,因为样条类只是对用户管理的内存的包装器。
- “construct”函数执行系数计算,在 SYCL 设备上运行,使用构造函数中的队列。或者,如果调用了相应的构造函数,它会从设备和上下文中创建一个新的。
template <typename FpType, typename SplineType, int Dimensions = 1>
class spline {
public:
using value_type = FpType;
using spline_type = SplineType;
spline(const sycl::queue& q, std::int64_t ny = 1,
bool were_coeffs_computed = false);
spline(const sycl::device& dev, const sycl::context& ctx,
std::int64_t ny = 1, bool were_coeffs_computed = false);
~spline();
spline(const spline<FpType, SplineType, Dimensions>& other) = delete;
spline(spline<FpType, SplineType, Dimensions>&& other) = delete;
spline<FpType, SplineType, Dimensions>& operator=(const spline<FpType,
SplineType, Dimensions>& other) = delete;
spline<FpType, SplineType, Dimensions>& operator=(spline<FpType, SplineType,
Dimensions>&& other) = delete;
spline& set_partitions( FpType* input_data, std::int64_t nx,
partition_hint PartitionHint = partition_hint::non_uniform);
spline& set_function_values(FpType* input_data,
function_hint FunctionHint = storage_hint::row_major);
spline& set_coefficients(FpType* data,
coefficient_hint CoeffHint = storage_hint::row_major);
bool is_initialized() const;
std::int64_t get_required_coeffs_size() const;
sycl::event construct(const std::vector<sycl::event>& dependencies = {});
// for those types of splines where it's applicable
spline& set_internal_conditions(FpType* input_data);
spline& set_boundary_conditions(bc_type BCType = bc_type::free_end,
FpType input_value = {});
};
- 有两个仅用于特定样条类型的设置函数:“
set_internal_condition
”和“set_boundary_condition
”。如果样条不需要内部和边界条件,则不需要这些函数。
插值函数
让我们考虑“interpolate”函数的 API。
- 插值器在大多数情况下是样条。
- 如果您需要在不同的 SYCL 队列中进行插值计算,您可以将队列作为第一个参数提供。
- 然后我们有站点内存和大小,插值结果内存。
- “
der_indicator
”是一个位集,如果需要计算相应的导数阶数,则包含数字 1。如果未提供该参数(不计算导数),则仅计算值。 - 最后两个参数显示结果应放置的布局以及站点的一致性。
template <typename Interpolant>
sycl::event interpolate(
[sycl::queue& q,]
Interpolant& interpolant,
typename Interpolant::fp_type* sites,
std::int64_t n_sites,
typename Interpolant::fp_type* results,
[std::bitset<32> der_indicator,]
const std::vector<sycl::event>& dependencies = {},
interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders,
site_hint SiteHint = site_hint::non_uniform);
后续步骤和您的反馈
试一试,让我们知道这种跨架构的数据拟合方法使用 C++ 接口是否满足您的需求。这是您帮助塑造您最喜欢的数学内核库未来的机会。
也请在我们的社区论坛上告知我们任何功能请求或建议。
获取软件
今天就亲自尝试,下载并安装Intel® oneAPI 基础工具包
或仅Intel® onAPI 数学内核库。除了这些下载位置之外,它们还可以通过合作伙伴存储库获得。详细文档也可在线获取。
在云中获取新 Intel® 技术 Beta 版访问权限
如果您想在云中探索这些工具,请注册一个Intel® Developer Cloud帐户—一个免费的开发沙箱,提供对最新 Intel® 硬件和 oneAPI 软件的访问。
从现在开始,经批准的开发人员和客户可以提前几个月到一年获得对 Intel 技术的早期访问,并在 Intel 增强的基于云的服务平台上进行试用、测试和评估。
Beta 试用包括新的和即将推出的 Intel 计算和加速器平台,例如
- 第 4 代 Intel® Xeon® 可扩展处理器(Sapphire Rapids)
- 带高带宽内存 (HBM) 的 Intel® Xeon 第 4 代® 处理器
- 代号为 Ponte Vecchio 的 Intel® 数据中心 GPU
- Intel® 数据中心 GPU Flex 系列
- Intel® Xeon® D 处理器(Ice Lake D),
- Habana® Gaudi®2 深度学习加速器
需要注册和预审。
访问 cloud.intel.com 即可开始。
相关内容
技术文章
- 使用 DPC++ 和 oneMKL 实现傅里叶相关算法
- 使用 Intel® oneAPI 数学内核库加速 R 代码
- 使用 Intel® oneAPI 数学内核库加速蒙特卡洛模拟
- 一种面向数学加速的供应商中立路径
- 将 HSOpticalFlow 估算从 CUDA* 迁移到 SYCL*
点播网络研讨会
获取软件
Intel® oneAPI Base Toolkit
使用这套核心工具和库开始构建跨不同架构的高性能、以数据为中心的应用程序。