您误解了 C 与 Fortran 连续内存布局是什么,以及这意味着您可以做什么和不能做什么。比如改变数组中一行的内存布局
a[0] = np.asfortranarray(a[0])
没有意义,因为内存布局决定了一行是什么。
为了说明这一点,让我们看一些 Fortran 连续数据
x = np.asfortranarray(np.arange(12).reshape(3, 4))
x.flags.f_contiguous
# True
x
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
在内部,二维数组当然是线性保存的,C-/Fortran-contigouity 决定了行还是列在前:
x.flatten('A')
# array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
np.asfortranarray(x).flatten('A')
# array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
np.ascontiguousarray(x).flatten('A')
# array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
Fortran 内存布局是列优先的,即列在内存中保持在一起。 C 内存是行优先的,即行在内存中保持在一起。
真正令人困惑的是,该数组中的视图可以是连续的,也可以不是:
x.flags.f_contiguous, x[0].flags.f_contiguous
# (True, False)
x 显然是连续的,但 x[0] 不是。那是因为[0, 1, 2, 3] 在内存中并不相邻。
你想做什么
a = x.copy('A')
a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)
a[0] = np.asfortranarray(a[0])
a[1] = np.asfortranarray(a[1])
a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)
不起作用,因为更改单行的布局没有意义。
现在出现令人困惑的部分:如果您有一个 Fortran 连续数组,并且希望第一行是 Fortran 连续的,则不能将数组更改为 Fortran 连续:
a = x.copy('A')
a = np.asfortranarray(a)
a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)
因为列是连续的,而不是行。
如果改为将数组更改为 C-contigous
a = x.copy('A')
a = np.ascontiguousarray(a)
a.flags.f_contiguous, a[0].flags.f_contiguous
# (False, True)
这意味着行现在是连续的。
另一种解决方案是简单地复制数据
a = x.copy('A')
a[0].copy().flags.f_contiguous
# True
因为复制会将数据写入一个新的、线性的、连续的数组中。
那么最终的解决方案呢?
a, sr = librosa.load("mywave.wav")
stft_L = librosa.stft(a[0].copy())
不过librosa也有removed the need for contiguity recently,所以这个问题以后应该会慢慢消失的。