xtensor的“操作员/比numpy的/慢”

2024-06-12 16:07:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图把以前用Python编写的代码转换成C++,我现在正在测试XTunSurvior,看看它是否比NUMPY更快地执行我需要的代码。p>

我的一个函数接受一个平方矩阵d和一个标量alpha,并执行元素操作alpha/(alpha+d)。背景:此函数用于测试alpha的哪个值是“最佳的”,因此它处于一个循环中,d总是相同的,但alpha不同

以下所有时间尺度平均为运行函数的100个实例

在numpy中,执行此操作大约需要0.27秒,代码如下:

def kfun(d,alpha):
    k = alpha /(d+alpha)
    return k

但是xtensor大约需要0.36秒,代码如下所示:

xt::xtensor<double,2> xk(xt::xtensor<double,2> d, double alpha){
    return alpha/(alpha+d);
}

我还尝试使用std::vector实现以下版本,但从长远来看,这是我不想使用的,尽管只花了0.22秒

std::vector<std::vector<double>> kloops(std::vector<std::vector<double>> d, double alpha, int d_size){
    for (int i = 0; i<d_size; i++){
        for (int j = 0; j<d_size; j++){
            d[i][j] = alpha/(alpha + d[i][j]);
        }
    }
    return d;
}

我注意到xtensor中的operator/使用了“惰性广播”,是否有办法使其立即生效

编辑:

在Python中,函数调用如下,并使用“time”包计时

t0 = time.time()
for i in range(100):
    kk = k(dsquared,alpha_squared)
print(time.time()-t0)
<>在C++中,调用函数如下,使用的是计时:

//d is saved as a 1D npy file, an artefact from old code
auto sd2 = xt::load_npy<double>("/path/to/d.npy");

shape = {7084, 7084};
    xt::xtensor<double, 2> xd2(shape);
    for (int i = 0; i<7084;i++){
        for (int j=0; j<7084;j++){
            xd2(i,j) = (sd2(i*7084+j));
        }
    }

auto start = std::chrono::steady_clock::now();
for (int i = 0;i<10;i++){
    matrix<double> kk = kfun(xd2,4000*4000,7084);
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "k takes: " << elapsed_seconds.count() << "\n";

如果您希望运行此代码,我建议使用xd2作为对角线上有零的对称7084x7084随机矩阵

函数的输出,一个名为k的矩阵,然后继续在其他函数中使用,但我仍然需要d保持不变,因为它将在以后重新使用

结束编辑

< >运行我的C++代码,我在终端使用以下行:

cd "/path/to/src/" && g++ -mavx2 -ffast-math -DXTENSOR_USE_XSIMD -O3 ccode.cpp -o ccode -I/path/to/xtensorinclude && "/path/to/src/"ccode

提前谢谢


Tags: topath函数代码alphafortime矩阵
1条回答
网友
1楼 · 发布于 2024-06-12 16:07:08

一个C++实现的问题可能是它创建了一个或者可能是两个临时副本,这些副本是可以避免的。第一个副本来自未通过引用传递参数(或完全转发)。如果不看代码的其余部分,就很难判断这是否对性能有影响。如果保证在方法xk()之后不使用d,编译器可能会将d移动到方法中,但更可能将数据复制到d

要通过引用传递,可以将方法更改为

xt::xtensor<double,2> xk(const xt::xtensor<double,2>& d, double alpha){
    return alpha/(alpha+d);
}

要使用完美转发(并启用其他xtensor容器,如xt::xarrayxt::xtensor_fixed),可以将该方法更改为

template<typename T>
xt::xtensor<double,2> xk(T&& d, double alpha){
    return alpha/(alpha+d);
}

此外,您可以避免为返回值保留内存。同样,如果没有看到代码的其余部分,就很难做出判断。但是,如果在循环内部使用该方法,并且返回值始终具有相同的形状,那么在循环外部创建返回值并通过引用返回是有益的。为此,可将方法更改为:

template<typename T, typename U>
void xk(T& r, U&& d, double alpha){
    r = alpha/(alpha+d);
}

如果保证dr不指向同一内存,则可以在xt::noalias()中进一步包装r,以避免在分配结果之前出现临时副本。如果不通过引用返回,函数的返回值也是如此

祝你好运和快乐

相关问题 更多 >