Intel MKL函数,如何得到相同的计算结果?【转】

在运行程序时,我们总希望多次运行的结果,是完全一致,甚至在不同的机器与不同的OS中,程序运行的结果每一位都完全相同。

事实上,程序往往很难保证做到这一点。 为什么呢? 我们先看一个简单的例子: 当程序使用单精度或者双精度的浮点数时, 浮点数有一定的精度的限制。 单精度的浮点数,使用23位二进制表示的尾数。 双精度浮点数,使用52位的二进制(http://en.wikipedia.org/wiki/IEEE_754-1985)。

如果,程序中计算下面的表达式:

double d1,d2,d3,d4,d5;
        d1 = 1e-63;
        d2 = 1;
        d3= -1;

d4 = (d1+ d2) +d3;
        d5 = d1+ (d2 +d3);

printf("d4=%e\n",d4);
       printf("d5=%e\n",d5);

通常,它的结果为:
        d4=0.000000e+000
        d5=1.000000e-063

尽管数学表达上, d4 应该有和d5 完全相同的计算结果。但是,由于浮点数的有限精度,(d1+d2),在计算机的值为1. 最终,d4,d5的结果并不完全相同。

如果程序调用Intel MKL 函数,下面的一些因素,往往会对我们的计算结果产生影响:

1> 内存对齐:我们的处理器往往提供了一些专门的指令,对16 byte 或 32 byte (AVX ) 对齐内存地址进行存取操作。 当程序运行时,对齐或不对齐输入数据的地址,运行的代码可能有略微差别。最终,程序的计算结果,可能不是完全一致。

2> 多线程的设置: Intel MKL 函数已经是多核优化后的函数,程序运行多线的数目不同,带来相应的数值精度上也会细微的误差。

3> 针对不同处理器的优化代码: Intel MKL 能够充分利用处理器的指令集,来取得程序的最高性能。 这样在不同的处理器上, 程序运行的代码可能并不是完全一致,从而最终的的结果,可能也略有差别。

新的MKL 11.0提供了conditional bitwise reproducible (CBWR)的特性。 在满足一定的条件下,它能保证MKL函数有相同的结果。如果 1)输入/输出的数据地址按照16或 32字节对齐 ( 选择执行SSE指令需要16 byte 对齐,AVX1指令32 byte 对齐)2)运行的线程数目相同 3)在同一可执行文件中被调用, 那么Intel MKL函数可以在多次执行中,有相同的计算结果。

程序不同处理器上运行的时候,可能运行不同的优化代码。比如, 在较旧Intel® Pentium® 4 处理器上, MKL可能运行SSE2 优化代码,而在支持的AXV指令的新的机器上,MKL 的函数可能运行AVX指令的优化代码。 这样,Intel MKL函数能够根据不同处理器的特性,提供高效的优化代码。但是,当这些代码,有不完全相同的数据处理顺序时,不完全一致的代码可能产生的最有的数值结果可能也不完全一致。 在MKL 11.0 中, 提供的一些新的函数,与环境变量。能够帮助用户来来控制取得一致的计算结果。

下面我们看一下例子:

1> 为确保在Intel 以及Intel 兼容的支持SSE2 指令的处理上,有一致的计算结果, 我们可以将程序须设置固定的线程数目, 保证输入输出数据的地址对齐, 并调用以下的MKL 函数:

mkl_cbwr_set(MKL_CBWR_COMPATIBLE) 或设置环境变量:MKL_CBWR_BRANCH = "COMPATIBLE"

2>在支持SSE4.1 Intel 的处理器上, 为确保MKL 函数有相同的结果。我们可以将程序须设置固定的线程数目,保证输入输出数据的地址对齐, 并调用以下的MKL 函数:

mkl_cbwr_set(MKL_CBWR_SSE4_1) 或设置环境变量: MKL_CBWR_BRANCH = "SSE4_1"

需要说明的是, 如果我们选择了特定CPU优化的代码, 很自然,针对一些新的处理器,MKL 可能会有一些性能开销。 比如,对于矩阵与矩阵乘法的函数(xGEMM), AVX 优化代码的性能有近乎SSE2优化代码的两倍性能。在支持AVX机器上,我们指定,该函数运行SSE2的代码,会有不少的性能损失。对于其他的一些例子,选择特定的优化代码,可能有10%-20%的性能开销。

相关培训材料: /en-us/articles/conditional-bitwise-reproducibility

下载与测试Intel MKL 11.0 Beta

来源:https://software.intel.com/zh-cn/blogs/2012/05/22/intel-mkl-2

时间: 2024-10-08 14:34:26

Intel MKL函数,如何得到相同的计算结果?【转】的相关文章

转载:Intel MKL 稀疏矩阵求解PARDISO 函数

Intel MKL提供了针对稀疏矩阵求解的PARDISO 接口,它是在共享内存机器上,实现的稀疏矩阵的直接求解方法,对于一些大规模的计算问题, PARDISO的算法表现了非常好的计算效率与并行性.一些数值测试表明,随着计算节点数目增加, PARDISO具有接近线性的加速比例. PARDISO对应求解过程包括如下步骤: 1. 矩阵重排与符号分解(Reordering and Symbolic Factorization):PARDISO Solver根据不同的矩阵类型,计算不同类型的行列交换矩阵P

Intel MKL(Math Kernel Library)

1.Intel MKL简介 Intel数学核心函数库(MKL)是一套高度优化.线程安全的数学例程.函数,面向高性能的工程.科学与财务应用.英特尔 MKL 的集群版本包括 ScaLAPACK 与分布式内存快速傅立叶转换,并提供了线性代数 (BLAS.LAPACK 和Sparse Solver).快速傅立叶转换.矢量数学 (Vector Math) 与随机号码生成器支持. 主要包括: ① LAPACK (线形代数工具linear algebra package) ② DFTs (离散傅立叶变换 Di

CAFFE安装(4):ATLAS/ Intel MKL安装

暂不提供OpenBLAS的安装方法,ATLAS/ Intel MKL这两个只需安装其中之一. ATLAS安装较简单 $ sudo apt-get install libatlas-base-dev Intel MKL安装稍复杂 离线下载mkl安装包(需要注册申请),首先解压安装包,下面有一个install_GUI.sh文件, 执行该文件,会出现图形安装界面,根据说明一步一步执行即可. $ tar zxvf parallel_studio_xe_2015.tar.gz (如果你是直接拷贝压缩文件过

macos安装pytorch出现Intel MKL 问题

macos安装pytorch时.执行下面的命令出现报错:Intel MKL FATAL ERROR Cannot load libmkl_intel_thread.dyliconda install numpy pyyaml mkl mkl-include setuptools cmake cffi typing这个问题是mkl模块引起的,所以执行下面的命令,卸载mkl,并更新相关的其他模块conda install nomkl numpy scipy scikit-learn numexpr

[原创]SQL表值函数:获取从当月计算起往前自定义月份数

  今天我现在发现看一篇博文不能够太长,只要能够描述清楚自己想表达的东西,能够让大家知道你要讲什么就行了.因为我今天看了一些长篇博文,真的觉得知识点太多了, 会让人囫囵吞枣. 这篇博文跟我昨天发表的类似,同样是为了解决一个统计需求,结果是要求返回从当月起往回推算出自定义输入的月份 喜欢总结的我,为此写了一个表值函数来解决这一需求.现记录一下,也希望能帮助到一些也遇到此类问题的朋友. 首先我们看一下执行效果图: 返回最近一年即是十二个月的数据,执行调用函数:SELECT * FROM [Fn_Ru

Python 利用函数、列表来实现计算天数

这几天课程学习了列表的操作,结合以前的函数知识,编写了一个能够判断天数的代码 源码如下 def is_year(year): return year % 4 == 0 and year % 100 != 0 or year % 400 == 0 #判断年份是否为闰年,是闰年则返回1, def calculate(year,month,day): is_month=[[31,28,31,30,31,30,31,31,30,31,30,31],[31,29,31,30,31,30,31,31,30,

编写函数fun,其功能是计算并输出如下多项式的值,sn=1+1/2!+1/3!+...+1/n!,例如,主函数从键盘输入15,输出的值是1.718282

#include <stdio.h> double fun(int n) { double sn=0.0,t; int i,j; for(i=0;i<=n;i++){ t=1.0; for(j=0;j<=i;j++) t=t*j; sn=sn+t; } return sn; }

Problem C: 指针:自定义函数length,调用它计算字符串的长度

#include<stdio.h> int length(char*s) { int i,count; while(*s!='\0') { *(s++); count++; } return count; } int main() { char s[80]; while(gets(s)!=NULL) { int t; t=length(s); printf("%d\n",t); } return 0; } 原文地址:https://www.cnblogs.com/chenl

数组作为参数传递的时候,被调用的函数内无法计算出数组的大小

  1 #include <stdio.h> 2 #include <stdlib.h> 3 int ff (int c[])//被调用的函数 4 { 5 int e; 6 e = sizeof (c) ; 7 return e; 8 } 9 int main(void) { 10 11 int c[7] = {1,2,3,6,2,2,7}; 12 13 int e,k; 14 e = sizeof (c); 15 16 k = ff(c); 17 printf("%d#