【问题标题】:Matlab and Python Reading Binary File DifferentlyMatlab 和 Python 读取二进制文件的方式不同
【发布时间】:2015-04-26 19:36:23
【问题描述】:

我正在将相同的二进制文件读入 Python 和 Matlab 并将其放入矩阵中。当我取这个矩阵的范数时,我会得到不同的结果。

我正在使用各自的 smatload 函数来加载二进制文件。

Python:

def smatload(filename):
    #print 'opening: ', filename
    f = open(filename, 'rb')
    m = np.fromfile(f,'q',1)
    n = np.fromfile(f,'q',1)
    nnz = np.fromfile(f,'q',1)
    print 'reading %d x %d with %d non-zeros' % (m,n,nnz)
    S = np.fromfile(f,'d',3*nnz)
    f.close()
    S = S.reshape((nnz,3))
    rows = S[:,0].astype(int) - 1
    cols = S[:,1].astype(int) - 1
    vals = S[:,2]
    return csr_matrix((vals,(rows,cols)),shape=(m,n))

Matlab:

function [A] = smatload(filename)

fid = fopen(filename,'r');
if( fid == -1 )
    disp(sprintf('Error: Unable to open file [%s], fid=%d\n',filename,fid));
    A = [-1];
    fclose(fid);
    return;
end

m   = fread(fid,[1 1],'uint64');
n   = fread(fid,[1 1],'uint64');
nnz = fread(fid,[1 1],'uint64');

fprintf('Reading %d x %d with %d non-zeros\n',m,n,nnz);

S = fread(fid,[3 nnz],'double');
fclose(fid);
A = sparse(S(1,:)',S(2,:)',S(3,:)',m,n);

我得到的返回矩阵范数的结果是

Matlab: norm(A.'fro') = 0.018317077159881

Python:np.linalg.norm(A) = 0.018317077159760

我已确认它们都读取了正确数量的值(6590x7126 矩阵,122526 个非零),并且我对两者使用了相同的规范 (frobenius)。

关于什么可能导致这种情况的任何想法?

【问题讨论】:

  • 这可能只是 MATLAB 做各种事情来提高浮点数学精度的一个例子。我知道,在 MATLAB 中,如果您将 0.01 1,000,000 次相加,您实际上会得到 10,000,而不是您在大多数其他语言中得到的稍有偏差的版本。
  • 我曾在其他时候将这个功能用于我正在做的项目中,但我没有看到任何区别。我很好奇为什么现在会出现这种情况。这导致了我的 Matlab 解决方案没有遇到的问题。
  • 所以您在处理 100,000 个浮点数时担心小数点后 12 位的差异?不是很相关,但是我很好奇MATLAB数组是否可以保存到.mat文件中,并用scipy.io.loadmat读取,结果是否相同。
  • 鉴于我正在做的实验,它会导致收敛标准出现一些问题。让我检查一下,我会更新我的帖子。
  • @David 您以前使用该函数是否涉及如此大的矩阵?我可以很容易地看到一个 6590x7126 矩阵的数字太大,以至于典型的浮点表示无法获得高精度。

标签: python matlab file numpy binary


【解决方案1】:

快速浏览一下 Frobenius 范数会发现它需要对所有值进行平方并将它们相加。

由于您在读取命令中有 uint64,看起来您可能正在填满浮点存储。当您将两个二进制数相乘时,存储答案需要两倍的位数。这意味着您需要 128 位来存储所有十进制值。如果 Python 和 MATLAB 执行此操作的方式不同,则可以解释为什么您的十进制值不同。

有关 MATLAB 和 Python 如何处理浮点精度的信息,请参阅这两个链接:

Python: https://docs.python.org/2/tutorial/floatingpoint.html

MATLAB: http://blogs.mathworks.com/cleve/2014/07/07/floating-point-numbers/

【讨论】:

  • 不太确定如何在此处上传文件,但不太可能发布数字。
  • 另外,您是否确认您在单独的计算中得到相同的值?
  • 是的,我有。我使用这个矩阵的范数进行一些计算,所以这种差异会在整个程序中传播。
  • 你能把产生值“0.018317077159881”和“0.018317077159760”的数字相加吗?
  • 我会尝试一个总和,一秒钟。
【解决方案2】:

不是答案,但我没有足够的代表发表评论。尝试缩小问题范围是否值得?如果您将原始矩阵划分为 4 个子矩阵(左上、右上、左下、右下)并比较每个子矩阵在 Matlab 和 Python 中报告的 Frobenius 范数,您是否仍然看到任何值之间存在差异?如果是,则冲洗并在该子矩阵上重复。如果不是,那么甚至不要浪费时间阅读此评论。 :-)

【讨论】:

  • 我可以试试。我担心由于规范已关闭,但原始数据匹配,因此 matlab/numpy 实现 sqrt 和 ^2 的方式可能有所不同。如果是这样,那么我将无法解决此问题。
  • 我猜您的原始矩阵在磁盘上的大小必须约为 375 MB。如果你能以某种方式将它发送给我(dropbox 等),我可以在我的机器上运行你的示例 Matlab 和 Python 代码来计算规范。这可能会告诉您是否有特定的版本/环境导致差异。 (当然,我们更有可能只有四个不同的规范值 - 两个来自您的机器,另外两个来自我的机器。:-)
  • 您的条目是真实的还是复杂的?如果您自己计算规范怎么样?还是平方范数?您的计算是否与相应的 Matlab 和 Python 版本一致?如果您在计算(平方)范数时使用求幂与普通旧乘法,是否会有所不同?您提到其中一个实现(我忘了哪个)给出了“正确”的答案——你怎么知道?(我不是在怀疑你,我只是不知道你是怎么知道的)
  • 我假设 matlab 是正确的,因为它运行完成并正确运行。 Python 在 svd 计算过程中出现错误,因为我正在使用规范来计算我想要多少个值。我会上传文件并在一分钟内给你发一个链接。
  • 文件为here 大小为1.3mb,因为所有内容都以二进制编码。格式是第一维的无符号 64 位 int,第二维的无符号 64 位 int,非零的数量的无符号 64 位 int,然后由三个 64 位双精度行、列、值组成的非零条目数.我会尝试你的建议,但我确实在 python 中手动进行了规范并得到了相同的结果。我什至手动计算平方根到低于机器精度。
【解决方案3】:

好吧,Matlab 似乎对于稀疏数组和密集数组有不同的实现。使用 4425x7126 稀疏矩阵 A 和您链接到的 54882 个非零条目以及以下命令:

FA=full(A);
av=A(:);
fav=FA(:);

我希望以下命令都产生相同的值,因为它们都在计算 A 的(非零)元素的平方和的平方根:

norm(A,'fro')
norm(av,2)
norm(FA,'fro')
norm(fav,2)

sqrt( sum(av .* av) )
sqrt( sum(av .^ 2) )

sqrt( sum(fav .* fav) )
sqrt( sum(fav .^ 2) )

事实上,我们看到了三个略有不同的答案:

 norm(A,'fro')             0.0223294051001499
 norm(av,2)                0.0223294051001499
 norm(FA,'fro')            0.0223294051001499
 norm(fav,2)               0.0223294051001499

 sqrt( sum(av .* av) )     0.0223294051001521
 sqrt( sum(av .^ 2) )      0.0223294051001521

 sqrt( sum(fav .* fav) )   0.0223294051001506
 sqrt( sum(fav .^ 2) )     0.0223294051001506

事实上,即使是 A 的稀疏表示和密集表示的元素的报告总和也(有点)不同:

sum(A(:))                 1.00000000000068
sum(FA(:))                1.00000000000035

这些差异似乎与您在 Python 和 Matlab 规范之间看到的数量级相同。

【讨论】:

    猜你喜欢
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    相关资源
    最近更新 更多