You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Librosa STFT获取相同帧数的数组以构建数据集?

问题:统一音频频谱图数组形状以构建数据集

我正尝试构建由WAV文件生成的Numpy数组数据集,已将单个WAV文件转换为Numpy数组,但因数组形状略有差异(第一维度一致,第二维度即帧数不同),无法合并为单个Numpy数组。我使用librosa.stft进行WAV到Numpy的转换,目前想到的方法是为每个数组补零以匹配最大帧数,但这种方法需要遍历3000个数组的每一行,效率极低,肯定有更好的方法。

预处理代码

def process(directory):
    # Load file
    for file in os.listdir(directory):
        f = os.path.join(directory, file).replace("\\", r"/")
        x, sr = librosa.load(f, sr=22050)
        # Convert to spectrogram
        X = librosa.stft(x)
        print(X.shape)
        spectrogram = np.abs(X)
        # Save file
        np.save(f"C:/Python/GANs/Sound_Digit_Gan/Data2/{file}", spectrogram)
        
process(directory)

打印出的X形状示例:

(1025, 23)
(1025, 29)
(1025, 26)
(1025, 34)
(1025, 26)
(1025, 27)
(1025, 40)
(1025, 22)
(1025, 25)
(1025, 24)
(1025, 35)

合并数据集时的错误

尝试用以下代码创建训练数据集:

directory = "C:/Python/GANs/Sound_Digit_Gan/Data2/"
train = []

for f in os.listdir(directory):
  file = os.path.join(directory, f).replace("\\", r"/")
  array = np.load(file)
  train.append(array)
  
train = np.array(train)  

出现错误:

ValueError: could not broadcast input array from shape (1025,13) into shape (1025,)

我认为这是因为数组形状不一致导致的,请问如何在不丢失音频信号数据的前提下统一数组形状?


解决方案

方法一:预处理阶段直接统一形状(推荐)

不用先保存单个数组再处理,而是在生成频谱图时直接补零到目标长度,步骤如下:

  1. 先遍历所有音频文件,计算出最大的帧数(第二维度的最大值)
  2. 重新遍历文件,生成频谱图后用np.pad补零到最大帧数,再保存

代码示例:

import os
import librosa
import numpy as np

def get_max_frames(directory, sr=22050):
    max_frames = 0
    for file in os.listdir(directory):
        f = os.path.join(directory, file).replace("\\", r"/")
        x, sr = librosa.load(f, sr=sr)
        X = librosa.stft(x)
        current_frames = X.shape[1]
        if current_frames > max_frames:
            max_frames = current_frames
    return max_frames

def process_with_pad(directory, save_dir, max_frames):
    for file in os.listdir(directory):
        f = os.path.join(directory, file).replace("\\", r"/")
        x, sr = librosa.load(f, sr=22050)
        X = librosa.stft(x)
        spectrogram = np.abs(X)
        # 补零:只在第二维度后面补零到max_frames长度
        padded_spectrogram = np.pad(spectrogram, ((0,0), (0, max_frames - spectrogram.shape[1])), mode='constant')
        np.save(os.path.join(save_dir, file), padded_spectrogram)

# 使用流程
source_dir = "你的WAV文件目录"
save_dir = "C:/Python/GANs/Sound_Digit_Gan/Data2/"
max_frames = get_max_frames(source_dir)
process_with_pad(source_dir, save_dir, max_frames)

方法二:对已保存的数组批量补零

如果已经保存了单个数组,也可以高效批量处理,不用逐行遍历:

  1. 先加载所有数组,记录最大帧数
  2. 创建一个形状为(样本数, 1025, max_frames)的空数组
  3. 遍历每个数组,将其赋值到空数组的对应位置,剩余部分自动补零

代码示例:

import os
import numpy as np

directory = "C:/Python/GANs/Sound_Digit_Gan/Data2/"
arrays = []
max_frames = 0

# 第一步:加载所有数组并找到最大帧数
for f in os.listdir(directory):
    file_path = os.path.join(directory, f).replace("\\", r"/")
    arr = np.load(file_path)
    arrays.append(arr)
    if arr.shape[1] > max_frames:
        max_frames = arr.shape[1]

# 第二步:创建统一形状的数据集
sample_count = len(arrays)
train_data = np.zeros((sample_count, 1025, max_frames), dtype=np.float32)

for i, arr in enumerate(arrays):
    # 将原数组赋值到train_data的对应位置,剩余部分保持0
    train_data[i, :, :arr.shape[1]] = arr

# 现在train_data就是统一形状的数据集了
print(train_data.shape)  # 输出 (3000, 1025, max_frames)

关键说明

  • np.pad或者直接赋值到空数组的方式都是向量化操作,numpy内部会用C级别的循环处理,完全不用担心3000个样本的性能问题
  • 补零操作是在频谱图的时间维度(第二维度)末尾补零,不会丢失原有音频的信号数据,只是添加了无意义的静音帧,对后续模型训练影响极小
  • 如果不想补零,也可以考虑截断较长的音频到最短帧数,但这样会丢失部分数据,不推荐;或者使用可变长度输入的模型(比如RNN类),但对于GAN这类模型,固定输入形状会更方便

内容的提问来源于stack exchange,提问作者Conweezy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:55:20