#mel #whisper #streaming #spectrogram #cpp #reference

mel_spec

与whisper.cpp、pytorch和librosa参考实现的结果对齐的Mel谱图,适合流式音频

9个版本

新版本 0.2.5 2024年8月22日
0.2.4 2024年8月20日
0.2.3 2024年5月23日
0.2.2 2023年8月1日
0.1.2 2023年7月22日

#98音频 中排名

Download history 8/week @ 2024-05-03 20/week @ 2024-05-10 127/week @ 2024-05-17 45/week @ 2024-05-24 37/week @ 2024-05-31 85/week @ 2024-06-07 58/week @ 2024-06-14 13/week @ 2024-06-21 11/week @ 2024-07-05 20/week @ 2024-07-26 78/week @ 2024-08-02 14/week @ 2024-08-09 318/week @ 2024-08-16

430 每月下载量
2 crates 中使用

MIT 许可证

175KB
841

Mel Spec

Mel Spec是一个Rust语言的实现,它将Mel谱图与whisper.cpp、pytorch和librosa的参考实现结果对齐,适用于流式音频。

使用方法

要使用库的主要功能

use mel_spec::prelude::*

与librosa相匹配的Mel滤波器组

与librosa和whisper GGML模型嵌入的滤波器在1.0e-7范围内相同的Mel滤波器组。

    let file_path = "./testdata/mel_filters.npz";
    let f = File::open(file_path).unwrap();
    let mut npz = NpzReader::new(f).unwrap();
    let filters: Array2<f32> = npz.by_index(0).unwrap();
    let want: Array2<f64> = filters.mapv(|x| f64::from(x));
    let sampling_rate = 16000.0;
    let fft_size = 400;
    let n_mels = 80;
    let f_min = None;
    let f_max = None;
    let hkt = false;
    let norm = true;
    let got = mel(sampling_rate, fft_size, n_mels, f_min, f_max, hkt, norm);
    assert_eq!(got.shape(), vec![80, 201]);
    for i in 0..80 {
        assert_nearby!(got.row(i), want.row(i), 1.0e-7);
    }

使用短时傅里叶变换进行谱图

与pytorch和whisper.cpp相匹配的 overlap-and-save STFT。

该实现适用于处理流式音频,并在返回FFT结果之前积累正确数量的数据。

    let fft_size = 8;
    let hop_size = 4;
    let mut spectrogram = Spectrogram::new(fft_size, hop_size);

    // Add PCM audio samples
    let frames: Vec<f32> = vec![1.0, 2.0, 3.0];
    if let Some(fft_frame) = spectrogram.add(&frames) {
        // use fft result
    }

STFT谱图到Mel谱图

MelSpectrogram将预计算的滤波器组应用于FFT结果。结果与whisper.cpp和whisper.py相同

    let fft_size = 400;
    let sampling_rate = 16000.0;
    let n_mels = 80;
    let mut mel = MelSpectrogram::new(fft_size, sampling_rate, n_mels);
    // Example input data for the FFT
    let fft_input = Array1::from(vec![Complex::new(1.0, 0.0); fft_size]);
    // Add the FFT data to the MelSpectrogram
    let mel_spec = stage.add(fft_input);

从音频创建Mel谱图。

该库包含基本的音频辅助工具和一个用于处理PCM音频并创建可以发送到whisper.cpp的Mel谱图的管道。

它还具有使用边缘检测(可能是一种新颖的方法)进行语音活动检测的功能,以实时识别词/语音边界。

    // load the whisper jfk sample
    let file_path = "../testdata/jfk_f32le.wav";
    let file = File::open(&file_path).unwrap();
    let data = parse_wav(file).unwrap();
    let samples = deinterleave_vecs_f32(&data.data, 1);

    let fft_size = 400;
    let hop_size = 160;
    let n_mels = 80;
    let sampling_rate = 16000.0;

    let mel_settings = MelConfig::new(fft_size, hop_size, n_mels, sampling_rate);
    let vad_settings = DetectionSettings::new(1.0, 10, 5, 0, 100);

    let config = PipelineConfig::new(mel_settings, Some(vad_settings));

    let mut pl = Pipeline::new(config);

    let handles = pl.start();

    // chunk size can be anything, 88 is random
    for chunk in samples[0].chunks(88) {
        let _ = pl.send_pcm(chunk);
    }

    pl.close_ingress();

    while let Ok((_, mel_spectrogram)) = pl.rx().recv() {
      // do something with spectrogram
    }

保存Mel谱图到文件

Mel谱图可以保存为Tga格式 - 一种由OSX和Windows支持的未压缩图像格式。

由于这些图像直接编码了量化的Mel谱图数据,因此它们代表了音频数据的“照片负片”,whisper.cpp可以在无需直接音频输入的情况下开发和打印。

tga文件在库的大部分测试中代替实际音频使用。这些文件在语音到文本方面是无损的,它们编码了模型在原始音频视图中所能获取的所有信息,并将产生相同的结果。

请注意,时域中的频谱图必须具有偶数列,否则Whisper将会产生幻觉。如果使用核心方法,库会处理这个问题。

     let file_path = "../testdata/jfk_full_speech_chunk0_golden.tga";
     let dequantized_mel = load_tga_8bit(file_path).unwrap();
     // dequantized_mel can be sent straight to whisper.cpp
❯ ffmpeg -hide_banner -loglevel error -i ~/Downloads/JFKWHA-001-AU_WR.mp3 -f f32le -ar 16000 -acodec pcm_f32le -ac 1 pipe:1  | ./target/debug/tga_whisper -t ../../doc/cutsec_46997.tga
...
whisper_init_state: Core ML model loaded
Got 1
 the quest for peace.

image 和平的追求。

语音活动检测

我想到使用Sobel算子来完成这个任务,因为在梅尔频谱图中,语音的梯度是清晰的。

总体思路是在频谱图中勾勒结构,然后找到适合切割的垂直间隙 - 以便在近乎实时地将新的频谱图传递给模型。

更多详细信息请参阅主仓库中的README。

依赖关系

~13MB
~217K SLoC