音频特征提取算法介绍

一、汇总对比

以 10 秒、48,000 Hz 采样率的音频数据为例,输入数据的维度为 (480000,)各种算法输出维度如下

算法 输出数据维度 时间帧数 (T) 特征维度 (F) 说明
短时傅里叶变换 (STFT) (1025, 938) 938 1025 n_fft=2048hop_length=512
梅尔频谱 (Mel Spectrogram) (128, 938) 938 128 n_mels=128n_fft=2048 hop_length=512
MuQ 13 x (1, 250, 1024) 250 1024 音频会被重采样到 24000Hz,输出包含 13 层隐藏状态
MERT-v1-95M (13, 749, 768) 749 768 音频会被重采样到 24000Hz,输出包含 13 层隐藏状态
MERT-v1-330M (25, 749, 1024) 749 1024 音频会被重采样到 24000Hz,输出包含 25 层隐藏状态
MusicFM25Hz (13, 250, 1024) 250 1024 音频会被重采样到 24000Hz,输出包含 13 层隐藏状态

二、STFT(短时傅里叶变换)

2.1 原理

短时傅里叶变换(Short-Time Fourier Transform, STFT)是传统傅里叶变换的扩展,它解决了时频分辨率权衡 这一核心问题。与全局傅里叶变换只能提供整个信号的频率信息不同,STFT通过加窗滑动的方式,实现了信号在时间和频率维度上的联合分析。

STFT的数学定义如下:

STFT(t,f)=∫−∞∞x(τ)w(τ−t)e−j2πfτdτSTFT(t, f) = \int_{-\infty}^{\infty} x(\tau)w(\tau-t)e^{-j2\pi f\tau}d\tauSTFT(t,f)=∫−∞∞x(τ)w(τ−t)e−j2πfτdτ

其中:

  • x(t)x(t)x(t):原始时域信号
  • w(t)w(t)w(t):窗函数(如汉明窗、汉宁窗)
  • ttt:时间中心点
  • fff:频率分量

离散形式的STFT(实际计算中使用):
STFTm,k=∑n=0N−1xnwn−me−j2πkn/NSTFTm, k = \sum_{n=0}^{N-1} xnwn-me^{-j2\pi kn/N}STFTm,k=n=0∑N−1xnwn−me−j2πkn/N

2.2 计算过程

  1. 信号分帧

    • 帧长(N_FFT) :决定频率分辨率
      • 较长帧长 → 频率分辨率高,时间分辨率低
      • 较短帧长 → 时间分辨率高,频率分辨率低
    • 帧移(Hop Length) :决定时间分辨率
      • 较小帧移 → 时间分辨率高,计算量大
      • 较大帧移 → 时间分辨率低,计算量小
  2. 应用窗口函数

    • 对每一帧应用窗口函数(如汉明窗、汉宁窗),以减少边缘效应。
  3. 傅里叶变换

    • 对每一帧应用快速傅里叶变换(FFT),将时域信号转换为频域信号。
  4. 构建频谱矩阵

    • 将每一帧的 FFT 结果组合成一个频谱矩阵,行表示频率,列表示时间。

2.3 输入和输出维度

  • 输入信号 y
    • 原始音频信号:一维数组 (n_samples,)
    • 示例:48kHz采样率10秒音频 → (480000,)
  • 输出结果 D
    • 类型:二维复数 NumPy 数组。
    • 维度:(n_freq, n_frames),其中:
      • n_freq = n_fft // 2 + 1,表示频率 bins 的数量。
      • n_frames = 1 + (len(y) - n_fft) // hop_length,表示时间帧的数量。

STFT输出为复数矩阵:

  • 实部:余弦分量强度
  • 虚部:正弦分量强度
  • 幅度谱 :实部2+虚部2\sqrt{实部^2 + 虚部^2}实部2+虚部2 ,表示能量分布
  • 相位谱 :arctan⁡(虚部/实部)\arctan(虚部/实部)arctan(虚部/实部),表示波形位置

2.4 可视化

python 复制代码
import librosa
import numpy as np
import matplotlib.pyplot as plt

# 加载音频文件,统一采样率至48kHz
file_path = 'test.wav'  # 替换为您的音频文件路径
wav, sr = librosa.load(file_path, sr=48000, mono=True)
print(f"输入数据维度: {wav.shape}")
# 计算短时傅里叶变换 (STFT)
n_fft = 2048  # FFT窗口大小
hop_length = 512  # 每次移动的样本数
stft = librosa.stft(wav, n_fft=n_fft, hop_length=hop_length)

# 将幅度转换为分贝
stft_db = librosa.amplitude_to_db(np.abs(stft))
print(f"输出频谱维度: {stft_db.shape}")
# 可视化 STFT 结果
plt.figure(figsize=(15, 7))
librosa.display.specshow(stft_db, sr=sr, hop_length=hop_length, x_axis='time', y_axis='log', cmap='inferno')
plt.colorbar(format='%+2.0f dB')
plt.title('STFT Magnitude (dB)')
plt.xlabel('Time (s)')
plt.ylabel('Frequency (Hz)')
plt.tight_layout()
plt.show()
python 复制代码
输入数据维度: (480000,)
输出频谱维度: (1025, 938)

三、梅尔频谱

梅尔频谱是一种基于人耳听觉特性的音频特征表示方法,通过将线性频率转换为梅尔刻度来模拟人类听觉系统对频率的感知。

3.1 梅尔刻度原理

梅尔刻度是一种非线性频率尺度,反映人耳对频率变化的感知特性:低频分辨率高,高频分辨率低

线性频率fff到梅尔频率fmf_mfm的转换公式:
fm=2595⋅log⁡10(1+f700)f_m = 2595 \cdot \log_{10}(1 + \frac{f}{700})fm=2595⋅log10(1+700f)

特性

  • 低频段:梅尔刻度变化缓慢,分辨率高
  • 高频段:梅尔刻度变化迅速,分辨率低
  • 符合人耳对音高的感知特性

3.2 梅尔滤波器组设计

梅尔滤波器组由一组重叠的三角带通滤波器构成,在梅尔刻度上均匀分布。

  1. 确定频率范围

    • 最小频率:fminf_{min}fmin(通常0Hz)
    • 最大频率:fmaxf_{max}fmax(通常采样率的一半)
  2. 转换为梅尔刻度
    melmin=2595⋅log⁡10(1+fmin700)mel_{min} = 2595 \cdot \log_{10}(1 + \frac{f_{min}}{700})melmin=2595⋅log10(1+700fmin)
    melmax=2595⋅log⁡10(1+fmax700)mel_{max} = 2595 \cdot \log_{10}(1 + \frac{f_{max}}{700})melmax=2595⋅log10(1+700fmax)

  3. 在梅尔刻度上均匀分布
    meli=melmin+i⋅(melmax−melmin)N+1(i=0,1,...,N+1)mel_i = mel_{min} + \frac{i \cdot (mel_{max} - mel_{min})}{N+1} \quad (i=0,1,...,N+1)meli=melmin+N+1i⋅(melmax−melmin)(i=0,1,...,N+1)

    其中NNN为滤波器数量

  4. 转换回线性频率
    fi=700⋅(10meli/2595−1)f_i = 700 \cdot (10^{mel_i/2595} - 1)fi=700⋅(10meli/2595−1)

  5. 构建三角滤波器

    对于每个滤波器Hk(f)H_k(f)Hk(f):
    Hk(f)={0,f<fk−1f−fk−1fk−fk−1,fk−1≤f<fkfk+1−ffk+1−fk,fk≤f<fk+10,f≥fk+1H_k(f) = \begin{cases} 0, & f < f_{k-1} \\ \frac{f - f_{k-1}}{f_k - f_{k-1}}, & f_{k-1} \leq f < f_k \\ \frac{f_{k+1} - f}{f_{k+1} - f_k}, & f_k \leq f < f_{k+1} \\ 0, & f \geq f_{k+1} \end{cases}Hk(f)=⎩ ⎨ ⎧0,fk−fk−1f−fk−1,fk+1−fkfk+1−f,0,f<fk−1fk−1≤f<fkfk≤f<fk+1f≥fk+1

3.3 梅尔频谱计算流程

  1. 计算STFT频谱

    • 输入:时域信号x(t)x(t)x(t)
    • 输出:复数频谱X(t,f)X(t,f)X(t,f)
  2. 计算功率谱
    P(t,f)=∣X(t,f)∣2P(t,f) = |X(t,f)|^2P(t,f)=∣X(t,f)∣2

  3. 应用梅尔滤波器组
    M(t,m)=∑fHm(f)⋅P(t,f)M(t,m) = \sum_f H_m(f) \cdot P(t,f)M(t,m)=f∑Hm(f)⋅P(t,f)

    其中mmm为梅尔频带索引

  4. 对数压缩 (可选):
    Mlog(t,m)=log⁡(M(t,m)+ϵ)M_{log}(t,m) = \log(M(t,m) + \epsilon)Mlog(t,m)=log(M(t,m)+ϵ)

3.4 输入和输出维度

  • 输入维度

    • 原始音频信号:一维数组 (n_samples,)
    • 示例:48kHz采样率10秒音频 → (480000,)
  • 输出维度

    • 梅尔频谱矩阵:二维数组 (n_mels, n_frames)
    • 其中 n_mels 为梅尔滤波器数量(通常64-128),n_frames = 1 + (len(y) - n_fft) // hop_length,表示时间帧的数量。

3.5 可视化

python 复制代码
import librosa
import numpy as np
import matplotlib.pyplot as plt
import librosa.display

# Load the audio file and set the sample rate to 48kHz
file_path = 'test.wav'  # Replace with your audio file path
wav, sr = librosa.load(file_path, sr=48000, mono=True)
print(f"Input data dimensions: {wav.shape}")

# Calculate the Mel spectrogram
n_fft = 2048  # FFT window size
hop_length = 512  # Number of samples to move each time
n_mels = 128  # Number of Mel bands
mel_spectrogram = librosa.feature.melspectrogram(y=wav, sr=sr, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels)

# Convert amplitude to decibels
mel_spectrogram_db = librosa.amplitude_to_db(mel_spectrogram, ref=np.max)
print(f"Output Mel spectrogram dimensions: {mel_spectrogram_db.shape}")

# Visualize the Mel spectrogram
plt.figure(figsize=(15, 7))
librosa.display.specshow(mel_spectrogram_db, sr=sr, hop_length=hop_length, x_axis='time', y_axis='mel', cmap='inferno')
plt.colorbar(format='%+2.0f dB')
plt.title('Mel Spectrogram (dB)')
plt.xlabel('Time (s)')
plt.ylabel('Mel Frequency (Mel)')  # Updated label for clarity
plt.tight_layout()
plt.show()
python 复制代码
Input data dimensions: (480000,)
Output Mel spectrogram dimensions: (128, 938)

四、MUQ模型

MuQ(Music Understanding with Mel Quantization)是一种基于自监督学习的音乐表示模型,通过梅尔残差向量量化(Mel-RVQ)提取音频特征。该模型的核心创新在于使用预训练的Mel-RVQ作为目标生成器,通过残差量化机制将梅尔频谱转换为离散令牌,然后通过Conformer编码器学习这些令牌的上下文表示,最终输出丰富的音频特征。这些特征同时捕获音乐的语义和声学信息,适用于多种音乐信息检索和理解任务。

4.1 特征提取详细流程

  1. 音频预处理与梅尔频谱提取:MuQ首先将原始音频信号转换为梅尔频谱,这是一种符合人耳听觉特性的时频表示。预处理步骤包括:

    • 音频加载:统一采样率为24kHz,确保与预训练模型兼容
    • 梅尔频谱计算:通过短时傅里叶变换(STFT)和梅尔刻度滤波得到128维梅尔频谱
    • 帧处理:使用帧长2048(n_fft)和帧移512(hop_length),对于10秒音频产生约938个时间帧
  2. Mel-RVQ目标生成:预训练的Mel-RVQ对梅尔频谱进行残差向量量化,生成离散标记作为自监督学习目标。

    1. 初始残差 :r(1)=xr^{(1)} = xr(1)=x(梅尔频谱)
    2. 逐步量化 :对于每个码本步骤n=1n = 1n=1到NNN(通常N=8N=8N=8):
      • 投影:z(n)=MP(n)(r(n))z^{(n)} = M_P^{(n)}(r^{(n)})z(n)=MP(n)(r(n))
      • 量化:τ(n)=arg⁡min⁡k∥z(n)−Qk(n)∥2\tau^{(n)} = \arg\min_k \| z^{(n)} - Q_k^{(n)} \|_2τ(n)=argmink∥z(n)−Qk(n)∥2
      • 残差更新:r(n+1)=r(n)−MD(n)(Qτ(n)(n))r^{(n+1)} = r^{(n)} - M_D^{(n)}(Q_{\tau^{(n)}}^{(n)})r(n+1)=r(n)−MD(n)(Qτ(n)(n))
    3. 输出 :生成N个标记序列τ(1),τ(2),...,τ(N)\tau^{(1)}, \tau^{(2)}, \ldots, \tau^{(N)}τ(1),τ(2),...,τ(N)作为目标
  3. Conformer编码与特征学习:MuQ使用12层Conformer编码器处理梅尔频谱,学习令牌的上下文表示。Conformer结合卷积和自注意力机制,能有效捕获音频的局部和全局特征:

    • 输入:部分掩码的梅尔频谱(掩码概率p=0.6)
    • 编码:通过Conformer层进行上下文学习
    • 预测:使用N个线性层预测对应的目标令牌
    • 损失:交叉熵损失 between预测和目标令牌
  4. 特征输出与提取:模型输出包含多个隐藏状态,提供不同层级的特征表示:

  • 最后一层隐藏状态 (output.last_hidden_state):高级语义特征,形状为[batch_size, sequence_length, feature_dim]
  • 所有隐藏状态 (output.hidden_states):包含13层输出(1个嵌入层+12个Conformer层),每层形状相同

4.2 特征提取代码

python 复制代码
import torch
import librosa
from muq import MuQ

device = 'mps'  # 使用 Apple Silicon GPU 进行计算
wav, sr = librosa.load("test.wav", sr=24000)  # 加载音频文件,采样率设置为 24kHz
wavs = torch.tensor(wav).unsqueeze(0).to(device)  # 将音频数据转换为张量并添加批次维度,移动到 GPU

# 这将自动从 Hugging Face 获取检查点
muq = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")  # 加载预训练的 MuQ 模型
muq = muq.to(device).eval()  # 将模型移动到 GPU 并设置为评估模式

with torch.no_grad():  # 禁用梯度计算以提高推理效率
    output = muq(wavs, output_hidden_states=True)  # 进行前向传播,获取输出和隐藏状态

# 打印隐藏层的总数
print('Total number of layers: ', len(output.hidden_states))

# 打印最后一层输出的特征形状
print('Feature shape: ', output.last_hidden_state.shape)

# 打印 output 的完整形状
print('Output shape: ', {
    'last_hidden_state': output.last_hidden_state.shape,
    'hidden_states': [state.shape for state in output.hidden_states]
})

# 分析输出
print("\nAnalysis of output:")
print(f"Last hidden state shape: {output.last_hidden_state.shape}")
print(f"Number of hidden states: {len(output.hidden_states)}")
for i, hidden_state in enumerate(output.hidden_states):
    print(f"Shape of hidden state {i}: {hidden_state.shape}")
python 复制代码
Total number of layers:  13
Output shape:  {'last_hidden_state': torch.Size([1, 250, 1024]), 'hidden_states': [torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024]), torch.Size([1, 250, 1024])]}

Analysis of output:
Last hidden state shape: torch.Size([1, 250, 1024])
Number of hidden states: 13
Shape of hidden state 0: torch.Size([1, 250, 1024])
Shape of hidden state 1: torch.Size([1, 250, 1024])
Shape of hidden state 2: torch.Size([1, 250, 1024])
Shape of hidden state 3: torch.Size([1, 250, 1024])
Shape of hidden state 4: torch.Size([1, 250, 1024])
Shape of hidden state 5: torch.Size([1, 250, 1024])
Shape of hidden state 6: torch.Size([1, 250, 1024])
Shape of hidden state 7: torch.Size([1, 250, 1024])
Shape of hidden state 8: torch.Size([1, 250, 1024])
Shape of hidden state 9: torch.Size([1, 250, 1024])
Shape of hidden state 10: torch.Size([1, 250, 1024])
Shape of hidden state 11: torch.Size([1, 250, 1024])
Shape of hidden state 12: torch.Size([1, 250, 1024])

4.3 输出特征详细分析

MuQ输出特征为三维张量,形状为 [batch_size, sequence_length, feature_dim]

  • batch_size:批处理大小,通常为1(单个音频)
  • sequence_length:时间步数(250),对应10秒音频的时间帧
  • feature_dim特征维度(1024),每个时间步的特征向量维度

MuQ的13层隐藏状态提供多尺度特征表示:

  • 底层(0-3层):捕获低级声学特征(音色、音高、频谱细节)
  • 中层(4-8层):提取中级音乐特征(旋律、节奏、和声)
  • 高层(9-12层):编码高级语义信息(流派、情感、结构)

各层特征在不同任务中的性能表现:

4.4 特征可视化

python 复制代码
import torch
import librosa
import matplotlib.pyplot as plt
from muq import MuQ

device = 'mps'  # 使用 Apple Silicon GPU 进行计算
wav, sr = librosa.load("test.wav", sr=24000)  # 加载音频文件,采样率设置为 24kHz
wavs = torch.tensor(wav).unsqueeze(0).to(device)  # 将音频数据转换为张量并添加批次维度,移动到 GPU

# 这将自动从 Hugging Face 获取检查点
muq = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")  # 加载预训练的 MuQ 模型
muq = muq.to(device).eval()  # 将模型移动到 GPU 并设置为评估模式

with torch.no_grad():  # 禁用梯度计算以提高推理效率
    output = muq(wavs, output_hidden_states=True)  # 进行前向传播,获取输出和隐藏状态

# 创建子图
selected_layers = [0, 6, 12]  # 选择要绘制的层
num_selected_layers = len(selected_layers)
rows = 1
cols = num_selected_layers
fig, axes = plt.subplots(rows, cols, figsize=(15, 5))  # 创建 1 行 3 列的子图

# 绘制每一层的特征图
for idx, layer in enumerate(selected_layers):
    hidden_state = output.hidden_states[layer]  # 获取指定层的隐藏状态
    feature_map = hidden_state.squeeze(0).cpu().numpy()  # 移动到 CPU 并转换为 NumPy 数组
    # 转换为 dB 表示
    feature_map_db = 20 * torch.log10(torch.tensor(feature_map) + 1e-10).numpy()  # 添加小常数以避免对数计算中的问题

    ax = axes[idx]  # 计算当前子图的位置
    im = ax.imshow(feature_map_db.T, aspect='auto', origin='lower', cmap='inferno')  # 转置特征图
    ax.set_title(f'Hidden State {layer} (dB)')
    ax.set_xlabel('Time Frames (250)')
    ax.set_ylabel('Feature Points (1024)')
    ax.set_xticks(range(0, 250, 25))
    ax.set_xticklabels(range(0, 250, 25))
    ax.set_yticks(range(0, 1024, 128))
    ax.set_yticklabels(range(0, 1024, 128))

    # 添加每个子图的颜色条
    cbar = fig.colorbar(im, ax=ax, orientation='vertical', fraction=0.02, pad=0.04)
    cbar.set_label('Feature Value (dB)')

plt.tight_layout()  # 自动调整子图间距
plt.show()

五、 MERT 模型

MERT(Music undERstanding Transformer)采用双教师引导的自监督学习架构,通过融合声学特征和音乐特征实现高效的音乐表示学习。其核心创新在于同时使用RVQ-VAE作为声学教师和CQT作为音乐教师,为掩码语言建模提供多维度伪标签。

5.1 特征提取

MERT的特征提取流程通过多教师监督层级特征编码任务自适应选择三个核心机制,实现了对音乐音频的深度理解。其提取的特征兼具:

  1. 声学精确性:RVQ-VAE保障底层声学细节
  2. 音乐语义性:CQT注入音乐领域知识
  3. 多尺度适应性:不同层级支持不同粒度任务
  4. 计算高效性:轻量架构支持实时应用

5.2 特征提取代码

python 复制代码
import librosa
import torch
from transformers import Wav2Vec2FeatureExtractor, AutoModel

# 加载模型和处理器
model = AutoModel.from_pretrained("m-a-p/MERT-v1-95M", trust_remote_code=True)
processor = Wav2Vec2FeatureExtractor.from_pretrained("m-a-p/MERT-v1-95M", trust_remote_code=True)

# 设置设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
model.eval()


def process_custom_audio(audio_path):
    """
    处理自定义音频文件的主要函数
    """
    # 使用librosa加载音频文件,直接指定采样率为24000Hz
    audio, original_sr = librosa.load(audio_path, sr=24000, mono=True)

    # 转换为PyTorch张量
    audio_tensor = torch.from_numpy(audio).float()

    # 使用处理器预处理音频
    inputs = processor(
        audio_tensor,
        sampling_rate=24000,  # 直接使用24000Hz
        return_tensors="pt",
        padding=True
    )

    # 移动到设备
    inputs = {k: v.to(device) for k, v in inputs.items()}

    # 提取特征
    with torch.no_grad():
        outputs = model(**inputs, output_hidden_states=True)

    # 处理所有隐藏状态
    all_layer_hidden_states = torch.stack(outputs.hidden_states).squeeze()

    # 打印每一层的特征形状
    for i, hidden_state in enumerate(outputs.hidden_states):
        print(f"Layer {i} shape: {hidden_state.shape}")

    return {
        "all_layer_states": all_layer_hidden_states
    }


# 使用示例
if __name__ == "__main__":
    # 替换为您自己的音频文件路径
    custom_audio_path = "test.wav"

    try:
        features = process_custom_audio(custom_audio_path)

        print("特征提取成功!")
        print(f"所有层特征形状: {features['all_layer_states'].shape}")

    except Exception as e:
        print(f"处理音频时出错: {e}")
python 复制代码
Layer 0 shape: torch.Size([1, 749, 768])
Layer 1 shape: torch.Size([1, 749, 768])
Layer 2 shape: torch.Size([1, 749, 768])
Layer 3 shape: torch.Size([1, 749, 768])
Layer 4 shape: torch.Size([1, 749, 768])
Layer 5 shape: torch.Size([1, 749, 768])
Layer 6 shape: torch.Size([1, 749, 768])
Layer 7 shape: torch.Size([1, 749, 768])
Layer 8 shape: torch.Size([1, 749, 768])
Layer 9 shape: torch.Size([1, 749, 768])
Layer 10 shape: torch.Size([1, 749, 768])
Layer 11 shape: torch.Size([1, 749, 768])
Layer 12 shape: torch.Size([1, 749, 768])
特征提取成功!
所有层特征形状: torch.Size([13, 749, 768])

5.3 输出特征详细分析

  1. 音频输入

    • 维度 :输入音频信号通常为一维数组,形状为 (n_samples,),其中 n_samples 是音频样本的总数。
    • 示例 :对于 48 kHz 采样率的 10 秒音频,输入维度为 (480000,)。如果音频经过重采样,例如从 48 kHz 重采样到 24 kHz,音频样本数将减少到 (240000,)
  2. 模型输出

    • MERT 模型的输出包括多个隐藏状态,通常以张量的形式返回。
    • 维度 :输出的隐藏状态的维度为 (L, T, F),其中:
      • L 表示模型的层数。
      • T 表示时间帧的数量,取决于输入音频的长度和处理器的设置。
      • F 表示每个时间帧的特征向量维度。
模型名称 层数 (L) 时间帧数 (T) 特征维度 (F) 输出维度
MERT-v1-95M 13 749 768 (13, 749, 768)
MERT-v1-330M 25 749 1024 (25, 749, 1024)

5.4 特征可视化

python 复制代码
import librosa
import torch
import matplotlib.pyplot as plt
from transformers import Wav2Vec2FeatureExtractor, AutoModel

# 加载模型和处理器
model = AutoModel.from_pretrained("m-a-p/MERT-v1-95M", trust_remote_code=True)
processor = Wav2Vec2FeatureExtractor.from_pretrained("m-a-p/MERT-v1-95M", trust_remote_code=True)

# 设置设备
device = torch.device("mps" if torch.cuda.is_available() else "cpu")
model.to(device)
model.eval()


def process_custom_audio(audio_path):
    """
    处理自定义音频文件的主要函数
    """
    # 使用librosa加载音频文件,直接指定采样率为24000Hz
    audio, original_sr = librosa.load(audio_path, sr=24000, mono=True)

    # 转换为PyTorch张量
    audio_tensor = torch.from_numpy(audio).float()

    # 使用处理器预处理音频
    inputs = processor(
        audio_tensor,
        sampling_rate=24000,  # 直接使用24000Hz
        return_tensors="pt",
        padding=True
    )

    # 移动到设备
    inputs = {k: v.to(device) for k, v in inputs.items()}

    # 提取特征
    with torch.no_grad():
        outputs = model(**inputs, output_hidden_states=True)

    # 处理所有隐藏状态
    all_layer_hidden_states = torch.stack(outputs.hidden_states).squeeze()

    return {
        "all_layer_states": all_layer_hidden_states
    }


def visualize_layers(hidden_states):
    """
    可视化指定层的特征
    """
    layers_to_visualize = [0, 6, 12]  # 要可视化的层
    plt.figure(figsize=(15, 5))

    for i, layer in enumerate(layers_to_visualize):
        # 获取特定层的特征
        layer_features = hidden_states[layer].cpu().numpy()  # 转换为 NumPy 数组

        # 绘制特征图,横坐标为时间帧,纵坐标为特征维度
        plt.subplot(1, len(layers_to_visualize), i + 1)
        plt.imshow(layer_features.T, aspect='auto', origin='lower', cmap='inferno')
        plt.title(f'Layer {layer} Features')
        plt.colorbar()
        plt.xlabel('Time Frames')
        plt.ylabel('Feature Dimension')

    plt.tight_layout()
    plt.show()


# 使用示例
if __name__ == "__main__":
    # 替换为您自己的音频文件路径
    custom_audio_path = "test.wav"

    try:
        features = process_custom_audio(custom_audio_path)

        print("特征提取成功!")
        print(f"所有层特征形状: {features['all_layer_states'].shape}")

        # 可视化特征
        visualize_layers(features['all_layer_states'])

    except Exception as e:
        print(f"处理音频时出错: {e}")

六、 MusicFM 模型

6.1 特征提取

六、MusicFM 模型

6.1 特征提取

MusicFM 是一种基于自监督学习的音乐基础模型,专门设计用于从原始音频中提取多层次音乐表示。其核心特征提取机制基于掩码标记建模(Masked Token Modeling)范式,通过预测被掩码的音频片段来学习丰富的上下文感知表示。

模型采用 Transformer 架构的变体(Conformer 或 BERT-style 编码器)作为骨干网络,通过随机标记化技术将连续音频信号转换为离散标记序列。这一过程无需额外的表示学习阶段,直接从原始音频中学习具有音乐语义的特征表示。

输入预处理流程

  1. 音频加载:支持 WAV、MP3、FLAC 等多种格式,自动统一为 24kHz 采样率的单声道音频
  2. 重采样处理:如果原始采样率不等于目标采样率(24kHz),使用 Librosa 进行高质量重采样
  3. 标准化:对音频振幅进行峰值归一化,确保数值稳定性
  4. 张量转换:将 NumPy 数组转换为 PyTorch 张量,并添加批处理维度(从 (n_samples,) 到 (1, n_samples))

特征提取过程

python 复制代码
# 核心提取步骤(基于6.2节代码)
wav, sr = librosa.load("test.wav", sr=24000)  # 加载和重采样
wav = torch.from_numpy(wav).float().unsqueeze(0)  # 转换为张量并添加批处理维度
logits, hidden_emb = musicfm.get_predictions(wav)  # 获取预测结果

输出特征结构

模型输出包含两个主要组件:

  1. Logits:原始预测输出,用于掩码标记重建任务
  2. 隐藏状态(Hidden States) :13层Transformer编码器的中间表示,每层提供不同抽象级别的特征:
    • 底层(1-4层):捕获低层声学特征(音色、瞬态响应)
    • 中层(5-8层):编码音乐语法(音符、节奏模式)
    • 高层(9-13层):表征高级语义信息(和声进行、音乐结构)

每层隐藏状态的维度为 [1, 250, 1024],分别对应:

  • 批次大小:1(单样本处理)
  • 时间帧数:250(对应10秒音频,时间分辨率为25Hz)
  • 特征维度:1024(每个时间点的特征向量长度)

6.2 特征提取代码

python 复制代码
HOME_PATH = "/Users/bytedance/Desktop/codes/ASAE"  # path where you cloned musicfm

import os
import sys
import librosa
import torch

sys.path.append(HOME_PATH)
from musicfm.model.musicfm_25hz import MusicFM25Hz

# 加载音频文件,采样率设置为 24kHz
wav, sr = librosa.load("test.wav", sr=24000)

# 将音频数据转换为 PyTorch 张量并添加批处理维度
wav = torch.from_numpy(wav).float().unsqueeze(0)  # 添加批处理维度

# load MusicFM
musicfm = MusicFM25Hz(
    is_flash=False,
    stat_path=os.path.join(HOME_PATH, "musicfm", "data", "msd_stats.json"),
    model_path=os.path.join(HOME_PATH, "musicfm", "data", "pretrained_msd.pt"),
)

# to MPS (for Apple Silicon)
if torch.backends.mps.is_available():
    wav = wav.to("mps")  # 将张量移动到 MPS 设备
    musicfm = musicfm.to("mps")  # 将模型移动到 MPS 设备
else:
    print("MPS is not available. Please check your PyTorch installation.")

# get embeddings
musicfm.eval()
logits, hidden_emb = musicfm.get_predictions(wav)

# 打印 hidden_emb 的类型和内容
print(f"Type of hidden_emb: {type(hidden_emb)}")  # 打印 hidden_emb 的类型
print(f"Length of hidden_emb: {len(hidden_emb)}")  # 打印 hidden_emb 的长度

# 打印每一层的形状
for i, emb in enumerate(hidden_emb):
    print(f"Shape of hidden state for layer {i}: {emb.shape}")  # 打印每一层的形状
python 复制代码
Type of hidden_emb: <class 'tuple'>
Length of hidden_emb: 13
Shape of hidden state for layer 0: torch.Size([1, 250, 1024])
Shape of hidden state for layer 1: torch.Size([1, 250, 1024])
Shape of hidden state for layer 2: torch.Size([1, 250, 1024])
Shape of hidden state for layer 3: torch.Size([1, 250, 1024])
Shape of hidden state for layer 4: torch.Size([1, 250, 1024])
Shape of hidden state for layer 5: torch.Size([1, 250, 1024])
Shape of hidden state for layer 6: torch.Size([1, 250, 1024])
Shape of hidden state for layer 7: torch.Size([1, 250, 1024])
Shape of hidden state for layer 8: torch.Size([1, 250, 1024])
Shape of hidden state for layer 9: torch.Size([1, 250, 1024])
Shape of hidden state for layer 10: torch.Size([1, 250, 1024])
Shape of hidden state for layer 11: torch.Size([1, 250, 1024])
Shape of hidden state for layer 12: torch.Size([1, 250, 1024])

6.3 输出特征详细分析

  1. 音频输入

    • 维度 :输入音频信号通常为一维数组,形状为 (n_samples,),其中 n_samples 是音频样本的总数。
    • 示例 :对于 48 kHz 采样率的 10 秒音频,输入维度为 (480000,)。如果音频经过重采样,例如从 48 kHz 重采样到 24 kHz,音频样本数将减少到 (240000,)
  2. 模型输出

    • MusicFM 模型的输出包括多个隐藏状态,通常以张量的形式返回。
    • 维度 :输出的隐藏状态的维度为 (L, T, F),其中:
      • L 表示模型的层数,此处为 13
      • T 表示时间帧的数量,取决于输入音频的长度和处理器的设置,此处为 250。
      • F 表示每个时间帧的特征向量维度,此处为1024。

6.4 特征可视化

python 复制代码
HOME_PATH = "/Users/bytedance/Desktop/codes/ASAE"  # path where you cloned musicfm

import os
import sys
import librosa
import torch
import matplotlib.pyplot as plt

sys.path.append(HOME_PATH)
from musicfm.model.musicfm_25hz import MusicFM25Hz

# 加载音频文件,采样率设置为 24kHz
wav, sr = librosa.load("test.wav", sr=24000)

# 将音频数据转换为 PyTorch 张量并添加批处理维度
wav = torch.from_numpy(wav).float().unsqueeze(0)  # 添加批处理维度

# load MusicFM
musicfm = MusicFM25Hz(
    is_flash=False,
    stat_path=os.path.join(HOME_PATH, "musicfm", "data", "msd_stats.json"),
    model_path=os.path.join(HOME_PATH, "musicfm", "data", "pretrained_msd.pt"),
)

# to MPS (for Apple Silicon)
if torch.backends.mps.is_available():
    wav = wav.to("mps")  # 将张量移动到 MPS 设备
    musicfm = musicfm.to("mps")  # 将模型移动到 MPS 设备
else:
    print("MPS is not available. Please check your PyTorch installation.")

# get embeddings
musicfm.eval()
logits, hidden_emb = musicfm.get_predictions(wav)

# 可视化第 0、6、12 层的特征图
layers_to_visualize = [0, 6, 12]
plt.figure(figsize=(15, 5))

for i, layer in enumerate(layers_to_visualize):
    # 获取特定层的特征
    layer_features = hidden_emb[layer].cpu().detach().numpy()  # 转换为 NumPy 数组

    # 绘制特征图,横坐标为时间帧,纵坐标为特征维度
    plt.subplot(1, len(layers_to_visualize), i + 1)
    plt.imshow(layer_features[0].T, aspect='auto', origin='lower', cmap='inferno')  # 转置以适应绘图
    plt.title(f'Layer {layer} Features')
    plt.colorbar()
    plt.xlabel('Time Frames')
    plt.ylabel('Feature Dimension')

plt.tight_layout()
plt.show()
相关推荐
江畔柳前堤7 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore8 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考10 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX11 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面11 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号12 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽12 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI12 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者14 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者14 小时前
【征程6】校准量化中HistogramObserver解析
算法