提问人:Daniel S. 提问时间:8/28/2023 最后编辑:Daniel S. 更新时间:8/28/2023 访问量:65
当在编译时知道形状(大小)时,rust 编译器可以更好地优化 Array2 吗?
Can the rust compiler optimize Array2 better when the shape (size) is known at compile time?
问:
我正在对神经网络中的矩阵使用 or in rust。(是的,我知道有用于 NN 的库。我想用我自己的代码来学习。这个问题独立于神经网络,但神经网络是一个合适的例子,因为在许多情况下,矩阵大小在编译时是已知的。Array2
Array1
当编译器在编译时知道矩阵或向量的大小时,它能做更好的优化吗?如何确保它知道他们?Array2
Array1
这是我的神经网络层的代码,其中标记了我认为也许我们可以为编译器提供额外信息的地方。还是结构中甚至不需要它?
extern crate ndarray;
use ndarray::prelude::*;
use ndarray_rand::RandomExt;
use rand::distributions::Uniform;
struct LayerWithBias<const input_size: usize, const output_size: usize> {
/// weights
w: Array2<f32>, // do something with input_size and output_size here?
/// biases
b: Array1<f32>, // and do something with just output_size here?
}
impl<const input_size: usize, const output_size: usize>
LayerWithBias<input_size, output_size> {
fn new() -> Self {
let w = Array2::random((output_size, input_size), Uniform::new(-1.0, 1.0));
let b = Array1::zeros(output_size);
LayerWithBias { w, b }
}
}
答:
0赞
Peter Hall
8/28/2023
#1
不可以,通过告诉编译器集合最终将包含的项目数,无法启用任何特定的优化。ndarray
编译器可能利用这种信息的唯一方法是固定大小的数组,即固定大小的数组。即便如此,它也可以针对小型数组进行优化,例如确保它们有效地填充缓存行。但是,如果您有足够多的数据值得使用,那么这不会有什么不同;您的数据是连续的,将以最佳方式填充许多缓存行。ndarray
Array1
Array2
ndarray
评论
2赞
Peter Cordes
8/28/2023
我想到的第一个优化是,如果已知大小是 16 或 32 字节(4 或 8 个浮点元素)的倍数,则自动矢量化不需要任何清理代码来处理在执行一定数量的 SIMD 向量后剩余的奇数元素。对于 C 示例,比较两个具有编译时间常量与运行时变量循环计数的函数:godbolt.org/z/1E4v7f1zM 。但是,如果运行时大小确实是向量宽度(乘以展开因子)的倍数,则节省的只是在内部循环之外多了一个 cmp/分支,以及一些死代码。
0赞
Peter Hall
8/28/2023
是的,没错。这就是我说它不会对大量数据产生影响的意思。
0赞
Daniel S.
8/28/2023
@PeterCordes 谢谢你的提示。我的矩阵和向量确实很短。我目前正在试验每个 NN 向量的 32 到 128 个 f32 元素。所有权重加起来可能小于 128KB。我稍后可能会在输出层附近更改为更少的元素和更短的数据类型。因此,NN 的某些向量可能适合单个 SIMD 寄存器。我的 NN 的输出向量大小将是 2 的幂。如果这很重要:我关心推理时间,所以 mat-mat-multiplications 对我来说并不重要,只有 mat-vec-multiplications。
0赞
Daniel S.
8/28/2023
关于“编译器可能会利用这种信息,这些信息将用于固定大小的数组,而 ndarray 的 Array1 和 Array2 则不是” - 我是否应该考虑除 / 之外的替代方案,例如像 [f32; 32] 这样的 rust 数组?鉴于我不太关心垫子的性能,这听起来对我来说是一个不错的选择。Array1
Array2
评论