本文へ移動
cccskills
無料GitHub で公開

audiogear

Annotate speech/TTS datasets with per-clip quality metrics (MOS, SNR, STOI, pitch, bandwidth, speaking rate, WER/CER, gender/emotion), multi-ASR consensus transcription and speaker labeling using the audiogear pipeline; then filter clips by quality and build listenable HTML QA reports. Use when asked to compute audio dataset metrics, build extended_metadata.csv, transcribe unlabeled audio, select clean TTS training data, or QA a speech dataset.

インストール方法を見る

含まれるファイル(109)

  • SKILL.md9.7 KB
  • .env.example360 B
  • .gitignore872 B
  • configs/annotate.yaml3.0 KB
  • configs/config.yaml693 B
  • configs/executor/local.yaml730 B
  • configs/metric/bandwidth.yaml192 B
  • configs/metric/brouhaha_snr_reverb.yaml217 B
  • configs/metric/distillmos.yaml136 B
  • configs/metric/emotion.yaml153 B
  • configs/metric/gender.yaml124 B
  • configs/metric/gigaam_multilingual.yaml743 B
  • configs/metric/gigaam_v3.yaml844 B
  • configs/metric/pitch.yaml631 B
  • configs/metric/speaker.yaml256 B
  • configs/metric/speaking_rate.yaml177 B
  • configs/metric/squim.yaml134 B
  • configs/metric/style.yaml129 B
  • configs/metric/wada_snr.yaml108 B
  • configs/metric/wer.yaml201 B
  • configs/reader/csv.yaml376 B
  • configs/reader/folder.yaml256 B
  • configs/reader/ru.yaml440 B
  • configs/resd.yaml2.8 KB
  • configs/writer/csv.yaml123 B
  • configs/writer/jsonl.yaml120 B
  • docs/multi-node.md3.6 KB
  • docs/README.md641 B
  • docs/storage.md4.1 KB
  • docs/testing.md5.3 KB
  • eval/sanity_distillmos.py3.0 KB
  • examples/filter_clean.py4.4 KB
  • examples/gen_configs.py6.1 KB
  • examples/qa_report.py12.9 KB
  • examples/README.md2.3 KB
  • examples/run_batch.py4.4 KB
  • LICENSE1.1 KB
  • process.py931 B
  • pyproject.toml4.3 KB
  • README.md28.5 KB
  • src/audiogear/__init__.py847 B
  • src/audiogear/audio.py3.7 KB
  • src/audiogear/build.py4.6 KB
  • src/audiogear/data.py1.2 KB
  • src/audiogear/executer/__init__.py0 B
  • src/audiogear/executer/base.py5.7 KB
  • src/audiogear/executer/local.py6.3 KB
  • src/audiogear/io.py9.2 KB
  • src/audiogear/pipeline/__init__.py0 B
  • src/audiogear/pipeline/base.py2.2 KB
  • src/audiogear/pipeline/checkpoint.py3.2 KB
  • src/audiogear/pipeline/metrics/__init__.py0 B
  • src/audiogear/pipeline/metrics/accent.py1.6 KB
  • src/audiogear/pipeline/metrics/bandwidth.py2.3 KB
  • src/audiogear/pipeline/metrics/base.py25.9 KB
  • src/audiogear/pipeline/metrics/brouhaha_snr_reverb.py2.3 KB
  • src/audiogear/pipeline/metrics/distillmos.py2.1 KB
  • src/audiogear/pipeline/metrics/emotion.py1.3 KB
  • src/audiogear/pipeline/metrics/gender.py1.3 KB
  • src/audiogear/pipeline/metrics/gigaam_v3.py6.9 KB
  • src/audiogear/pipeline/metrics/hf.py7.9 KB
  • src/audiogear/pipeline/metrics/models/__init__.py0 B
  • src/audiogear/pipeline/metrics/models/brouhaha_vad.py12.1 KB
  • src/audiogear/pipeline/metrics/models/nisqa/__init__.py0 B
  • src/audiogear/pipeline/metrics/pitch.py6.0 KB
  • src/audiogear/pipeline/metrics/punctuation.py5.9 KB
  • src/audiogear/pipeline/metrics/speaker.py11.6 KB
  • src/audiogear/pipeline/metrics/speaking_rate.py4.6 KB
  • src/audiogear/pipeline/metrics/squim.py2.5 KB
  • src/audiogear/pipeline/metrics/style.py2.1 KB
  • src/audiogear/pipeline/metrics/wada_snr.py4.0 KB
  • src/audiogear/pipeline/metrics/wav2vec_mos.py1.3 KB
  • src/audiogear/pipeline/metrics/wer.py3.5 KB
  • src/audiogear/pipeline/parallel.py5.2 KB
  • src/audiogear/pipeline/readers/__init__.py27 B
  • src/audiogear/pipeline/readers/base.py6.1 KB
  • src/audiogear/pipeline/readers/csv.py3.3 KB
  • src/audiogear/pipeline/readers/folder.py3.9 KB
  • src/audiogear/pipeline/readers/huggingface.py2.8 KB
  • src/audiogear/pipeline/readers/jsonl.py1.9 KB
  • src/audiogear/pipeline/segmenters/__init__.py0 B
  • src/audiogear/pipeline/segmenters/base.py3.7 KB
  • src/audiogear/pipeline/segmenters/whisper.py5.5 KB
  • src/audiogear/pipeline/transcribers/__init__.py415 B
  • src/audiogear/pipeline/transcribers/backends.py4.9 KB
  • src/audiogear/pipeline/transcribers/base.py1.6 KB
  • src/audiogear/pipeline/transcribers/consensus.py6.9 KB
  • src/audiogear/pipeline/writers/__init__.py0 B
  • src/audiogear/pipeline/writers/base_disk.py3.5 KB
  • src/audiogear/pipeline/writers/csv.py4.3 KB
  • src/audiogear/pipeline/writers/jsonl.py708 B
  • src/audiogear/utils/__init__.py0 B
  • src/audiogear/utils/import_utils.py479 B
  • src/audiogear/utils/logging.py1.6 KB
  • src/audiogear/utils/progress.py1.3 KB
  • src/audiogear/utils/runtime.py6.5 KB
  • tests/conftest.py831 B
  • tests/test_checkpoint_resume.py4.7 KB
  • tests/test_csv_roundtrip.py1.4 KB
  • tests/test_csv_writer.py5.5 KB
  • tests/test_merge_dedup.py1.9 KB
  • tests/test_metric_columns.py912 B
  • tests/test_metric_guard.py6.0 KB
  • tests/test_metric_scheduling.py2.7 KB
  • tests/test_progress.py1.3 KB
  • tests/test_punct_transfer.py4.1 KB
  • tests/test_reader_adapter.py1.6 KB
  • tests/test_runtime.py3.2 KB
  • tests/test_wer_normalize.py748 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

audiogear — speech-dataset annotation pipeline

audiogear (https://github.com/lIkesimba9/audiogear) computes per-clip features over a speech dataset: reader → metric blocks → CSV writer, configured with Hydra, sharded across GPUs/nodes. This skill drives it from any project.

Copy this file into the consuming project as .claude/skills/audiogear/SKILL.md. Set AUDIOGEAR_HOME below to wherever the audiogear checkout lives.

Setup (once per machine)

export AUDIOGEAR_HOME=~/audiogear            # adjust; add to the project env
git clone https://github.com/lIkesimba9/audiogear.git "$AUDIOGEAR_HOME" || true
cd "$AUDIOGEAR_HOME"
uv sync --extra ru-pipeline                  # or à-la-carte: --extra mos --extra asr --extra pitch
sudo apt-get install -y espeak-ng            # needed only for SpeakingRateMetric
cp -n .env.example .env                      # put HF_TOKEN= in .env for gated models (pyannote)

Python 3.10–3.12. GigaAM pins torch <2.6 — do not "upgrade" torch inside this venv.

Input contract

One directory per dataset with a |-delimited metadata.csv:

<data_root>/<dataset>/
  metadata.csv        # one row per clip
  audio/...           # referenced by audio_path, relative to the dataset dir

Required columns: id (unique), audio_path, text (may be empty). All other columns pass through untouched; computed metric columns are appended. If the source data has a different shape, first write a converter that produces this layout (see build_betterset-style scripts) — do NOT teach audiogear the foreign schema.

Core workflow

1. Write a dataset config

Create $AUDIOGEAR_HOME/configs/feat_<ds>.yaml. Proven template (mirrors the generated feat_* configs) with CPU∥GPU lanes so DSP metrics hide under GPU time:

defaults:
  - reader: ru          # CsvReader preset: delimiter "|", audio_key=audio_path, id_key=id
  - writer: csv
  - executor: local
  - _self_
hydra:
  job: {chdir: false}
  run: {dir: .}
  output_subdir: null
device: cuda
reader:
  data_folder: /path/to/data_root/<ds>
  glob_pattern: metadata.csv
  limit: -1             # set to 10 for a dry run
writer:
  output_folder: outputs/<ds>
  output_filename: ext_$rank.csv
  sep: "|"
executor:
  tasks: 8              # shards; rows are split round-robin
  workers: 2            # concurrent processes; each pins ONE GPU (rank % gpus)
  skip_completed: true
  logging_dir: logs/<ds>
metrics:
  - _target_: audiogear.pipeline.parallel.ParallelLanes
    lanes:
      cpu:
        - _target_: audiogear.pipeline.metrics.bandwidth.BandwidthMetric
        - _target_: audiogear.pipeline.metrics.wada_snr.SnrMetric
        - _target_: audiogear.pipeline.metrics.speaking_rate.SpeakingRateMetric
          language: ru
      gpu:
        - _target_: audiogear.pipeline.metrics.distillmos.DistillMosMetric
          device: ${device}
        - _target_: audiogear.pipeline.metrics.squim.SquimMetrics
          device: ${device}
        - _target_: audiogear.pipeline.metrics.pitch.CrepePitchMetric
          device: ${device}
          crepe_model: tiny
        - _target_: audiogear.pipeline.metrics.style.StyleMetric   # after pitch (reuses pitch_*)
        - _target_: audiogear.pipeline.metrics.gender.GenderMetric
          device: ${device}

Add WhisperWer to the gpu lane only when text is human-authored.

Lane rules (violating them corrupts data silently):

  • lanes must write disjoint columns;
  • a metric that consumes another's output (StyleMetric ← pitch_mean, WhisperWer/SpeakingRateMetric ← text) goes in the SAME lane, after its producer; a producer needed by both lanes (e.g. ConsensusTranscriber) runs as an ordinary step BEFORE the lanes block.

2. Dry run, then full run

cd "$AUDIOGEAR_HOME"
uv run python process.py --config-name feat_<ds> reader.limit=10   # smoke test, downloads models
uv run python process.py --config-name feat_<ds>                   # full run

Multi-GPU: executor.workers=<n_gpus>. executor.gpus is an int (count), never a list. Never set CUDA_VISIBLE_DEVICES yourself — the executor pins it. Multi-node: launch the same command once per node under SLURM, or set AUDIOGEAR_NODE_RANK/AUDIOGEAR_NUM_NODES; put executor.logging_dir on shared storage.

3. Merge shards → extended_metadata.csv

Each shard writes outputs/<ds>/ext_<rank>.csv. Merge with id-dedup (duplicates appear if executor.tasks changed between an interrupted run and its rerun):

export AUDIOGEAR_DATA_DIR=/path/to/data_root
uv run python examples/run_batch.py <ds>     # run + merge + .FEAT_DONE marker per dataset

For many datasets, examples/gen_configs.py generates the per-dataset configs and examples/run_batch.py sweeps them smallest-first with resume.

4. Filter + QA

uv run python examples/filter_clean.py <ds>   # extended_metadata.csv -> clean_metadata.csv + drop reasons
uv run python examples/qa_report.py <ds>      # -> <data_root>/<ds>/qa_report.html

qa_report.html is self-contained: metric histograms with the filter thresholds drawn in, and playable audio just below/just above each threshold. To calibrate thresholds: listen to both sides — rejected clips sounding fine ⇒ threshold too strict; accepted clips sounding bad ⇒ too loose. Edit TH in examples/filter_clean.py (single source of truth for filter and report) and regenerate. Set HUMAN_TEXT/ASR_TEXT there: the CER filter is only valid where text was written by humans, not by an ASR model.

Metric catalogue

Class (audiogear.pipeline.metrics.*)ColumnsNotes
distillmos.DistillMosMetricdistillmosno-ref MOS, GPU
squim.SquimMetricspyt_stoi, pyt_pesq, pyt_si_sdrGPU, never batched (padding skews scores)
wada_snr.SnrMetricwada_snrblind SNR, CPU
bandwidth.BandwidthMetricbandwidth_hz, is_upsampled_estdetects upsampled audio; container sample_rate lies
pitch.CrepePitchMetric / pitch.PitchMetricpitch_mean, pitch_stdGPU torchcrepe / CPU pyin
style.StyleMetricenergy_db, energy_dynamics, expressivenessCPU; reuses pitch_* if present
speaking_rate.SpeakingRateMetricspeaking_rate, phonemes_per_word, char_rateespeak-ng; NOT thread-safe — leave it serial
wer.WhisperWerwhisper_wer, whisper_cervs text; -1 when no reference. Skip for ASR-derived text (CER≈0, meaningless, expensive)
gigaam_v3.GigaAMv3gigaam3_text, gigaam3_cer, text_punctuated, opt-in words JSONpunctuated-from-audio RU transcript + punctuation transferred onto reference words; model_name: multilingual_ctc for ru/en/kk/ky/uz (no punctuation — set punct_column: null); words_column adds word timestamps
gender.GenderMetric / emotion.EmotionMetricgender_pred / emotion_pred, emotion_score_pred suffix — never overwrite curated columns
hf.HFAudioModelMetricconfigurableany 🤗 audio classification/regression model, config-only
brouhaha_snr_reverb.SnrReverbMetricssnr, c50pyannote, gated (HF_TOKEN)
speaker.SpeakerLabelerspeaker, speaker_conf, speaker_margindataset-level clustering — run with executor.tasks=1
transcribers.consensus.ConsensusTranscribertext, asr_text_*, asr_agreementmulti-ASR medoid; for datasets without transcripts

Reliability semantics (what to expect downstream)

  • Sentinels, not crashes. A corrupt/unscorable clip never kills a run: the per-clip guard writes NaN (or -1 for WER/CER/SQUIM) and continues. Always treat NaN and negative metric values as "no value" when filtering. A long unbroken failure streak (default 50) aborts the shard — that means a systematic problem (model/config), not bad data.
  • Resume is two-level. Completed shards are skipped via markers in logging_dir; inside an unfinished shard, per-metric JSONL checkpoints in <output_folder>/checkpoints/ resume from the last computed clip. Rerunning the same command after any crash is always safe. Checkpoints are keyed by clip id only — after changing a metric's model/parameters, delete <output_folder>/checkpoints/ (or the run reuses stale values). Disable with resume: false in the config.

Pitfalls checklist

  • executor.gpus: 1 (int) — gpus: [0] breaks.
  • Whisper compute_type: int8_float16 when 2 workers share a GPU (halves VRAM).
  • Clips >25 s are truncated by GigaAMv3; SQUIM needs ≥1024 samples (else -1).
  • Audio must be locally readable (torchaudio); CSVs/outputs/logs may be s3://… (fsspec), audio may not — FUSE-mount buckets instead.
  • Models load lazily per worker process — first clips are slow, that's normal.
  • Adding a metric: subclass BaseMetric, implement compute_metric(segment), set metric= to the column name(s). Do NOT add try/except around it — the base class guards every path already. Load models lazily via audiogear.utils.runtime.cached_model.

Programmatic use (no CLI)

from omegaconf import OmegaConf
from audiogear.build import build_pipeline

cfg = OmegaConf.create({...})       # same shape as a yaml config
data = None
for step in build_pipeline(cfg):    # reader -> metrics -> writer
    data = step(data, 0, 1)         # (data, rank, world_size)
# data: list[AudioSegment]; computed values in segment.metadata

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

このスキルの問題を報告する