简介:本资源是面向歌声合成方向研究者与深度学习工程师的高质量多模态数据集,专为训练和验证基于神经网络或HMM的端到端歌声合成模型而构建。包内共502个文件,涵盖100首完整歌曲的WAV(无损人声录音)、MIDI(精确旋律与节奏结构)、歌词文本(TXT)及音节级时长标注(CSV),另含元信息JSON与系统隐藏文件;971.99MB压缩包结构清晰,各模态数据严格对齐,便于直接用于声学建模、音高预测、时长建模等关键任务。已有836人学习下载,适用于语音合成进阶实践、多语言(含韩语)歌声建模探索及HMM与深度学习融合方法验证。用户可直接加载MIDI+歌词+时长标注构建输入特征,以WAV为目标进行监督训练,快速启动Tacotron/WaveNet/Transformer等主流架构的复现与优化工作。 搞歌声相关项目的人,看到"100首歌声数据集(含midi 歌词 标注时长 wav)"这种压缩包,第一反应通常不是兴奋,而是警惕。因为我见过太多人拿到类似资源后,解压一看,wav文件是有了,midi也对得上,但歌词标注的txt里全是乱码,时长标注跟音频实际长度差了十万八千里,最后只能自己重新洗一遍数据。数据集本身是歌声合成、音乐信息检索、音高分析这些方向最基础也最关键的资产,但"能不能直接用"跟"文件齐不齐"完全是两回事。这篇就把我从验收、清洗到接入训练管线的一整套处理方式拆开讲,给准备拿这套数据动手的朋友一个完整的参考。
先说这100首歌的数据集到底意味着什么。100首wav,按每首平均三分钟算,音频总时长大概是5到6个小时,这个体量对音色克隆、单曲翻唱这类小尺度任务来说是够的,对从零训练歌声合成模型则只能算小型起步集。真正值钱的不是音频数量,而是后半句——midi、歌词、标注时长。这三个东西代表着每一个音符的起点终点、每一句歌词对应的时间位置、旋律的量化表达全都有了。这意味着你拿到的不是一堆裸音频,而是一套打了索引的素材库。
1. 四层文件结构梳理:wav、midi、歌词文本、时长标注分别解决什么问题
很多刚接触音频数据集的人,容易把"文件清单"理解成"文件种类",然后默认每一首歌都应该四件套齐全。但实际整理过数据的人都知道,一个来自网络分享的数据包,最常出现的状况就是四种文件数量对不上,有的歌有midi没歌词,有的歌有wav没标注,这时候不能一股脑全删,得先搞清楚每一层文件在整条流水线里扮演什么角色。
1.1 wav:最容易被高估的一层
wav是歌声的原始载体,也是所有人拿到包之后第一个去听的东西。但很多人忽略了一个关键问题:wav里录的到底是纯人声干声,还是带伴奏的完整混音?这两种东西对后续处理的影响天差地别。如果是纯干声,那你可以直接拿去做音色训练、提取音高、做歌词对齐;如果带伴奏,你就必须先做一次人声分离,质量还未必有保证。
所以拿到wav文件,我不会急于听,而是先看一眼波形图和频谱。纯人声的频谱通常在中低频段有明显的共振峰结构,高频衰减比较自然,伴奏则常有低频打击乐和宽频带锯齿感。这一步用Audacity或者Python里的librosa都能快速完成,不需要多高深的技能,但能帮你省掉后面几个小时的弯路。
1.2 midi:歌声旋律的量化骨架
midi文件在歌声数据集里的作用,经常被新手当成"用来放伴奏的",这是误解。midi记录的是一串音符事件:音高、起始时间、持续时间、力度,甚至歌词在某些标准里也能挂进去。它是歌声旋律的量化表达,跟wav里实际唱出来的声音之间是"谱面"和"演奏"的关系。
拿着midi你能干什么?比如做音高对比,把midi音符转成F0参考曲线,然后跟wav里提取出来的实际基频做对齐,一来可以验证wav里唱的是不是跟谱面一致,二来可以作为训练歌声合成模型的音高标签。这也是为什么很多对齐模型需要midi作为先验输入——它能帮你把歌词、音符、音频三者拉到一个时间坐标系里。
1.3 歌词文本:从"听感"到"可计算"的桥梁
歌词文本单独看只是一堆字,但跟midi、时长标注合在一起,就成了音素级别标注的原材料。比如中文歌词需要考虑字到音素的映射,需要一个分词注音工具把"我们"拆成"wo3 men5",英文歌词则需要考虑连读和弱读,日文还得处理假名和罗马音。没有歌词文本,后续训练TTS或歌声合成模型时你就只能手工补标,那个工作量是灾难级的。
这套数据集号称带歌词,我建议先确认是纯文本文件,还是LRC格式,还是挂在midi里的歌词事件。不同来源处理成本差异很大,纯文本最灵活,LRC自带时间信息但解析容易踩编码坑,midi里的歌词事件要靠mido自己抽取。
1.4 时长标注:整包数据里真正的灵魂
时长标注本质上是一张"时间-内容映射表"。最简单的形态是每句歌词的起止时间,再细一点是每个字的起止时间,最细可以做到音素级别。标注格式常见的有JSON、CSV、TextGrid这几种,但不管格式怎么变,核心字段离不开三样:起始时间、结束时间、对应的文本内容。
我拿到数据集后的第一个习惯,就是找这份标注文件。因为它的质量直接决定了这个数据包是"素材"还是"训练集"。如果时长标注只是粗略标到句子级别,那你要做字级对齐就得再跑一遍强制对齐工具;如果标到了音素级别,那几乎可以直接喂给声学模型。下面一节重点讲讲标注里常见的几种对齐粒度和它们各自适合干什么。
2. 时长标注体系拆解:为什么对齐质量决定模型上限
很多做音频的同行都有过这种经历:调音高、调共振峰、调混响,折腾半天模型效果上不去,最后发现是训练数据的标签本身就对不齐——该从0.5秒开始的音符标到了0.8秒,该持续1.2秒的韵母只标了0.3秒。模型再强,喂进去的是错位标签,出来的预测必然一团糟。这就是为什么我一直强调,时长标注是数据集的upper bound,标注对齐到什么精度,模型就只能学到什么精度。
2.1 三种对齐粒度:句子级、字级、音素级
先说句子级标注。它的格式一般长这样:我们都已经尽力了 | 3.420 | 7.135。这种标注只能告诉你这句话从哪开始在哪结束,适合用来做歌曲段落切分、歌词滚动显示,但没法直接支撑音高预测和音素时长建模。你要是想训练一个能逐字合成歌声的模型,光靠这个粒度远远不够。
字级标注是大多数翻唱和歌声合成项目能接受的最低门槛:我 | 3.420 | 3.781、们 | 3.781 | 4.205。每个字起止时间清清楚楚,配合带音调的拼音标注,就能用于SoVITS这类模型的音素对齐,效果比整句级别的强一个数量级。代价是标注成本直线上升,纯人工标一首三分钟的歌,光字边界就要耗掉半小时以上。
音素级标注是上限:w|o3 | 3.420 | 3.550、m|en5 | 3.550 | 4.205。它把每个字拆成声母韵母,连每个音素持续多少毫秒都标出来了。这类数据可以直接用于DiffSinger、Vocaloid类声学模型的训练,因为模型需要知道每个音素应该唱多长。但音素级标注成本极高,100首歌全标到这一档,已经是一个专业团队干几周的活。
2.2 从标注错误率看数据质量:为什么loss降不下来先查标注
热搜词里有个说法很到位:"错误标注会导致数据标注模型训练集loss降不下来"。这句话我太有体会了。训练集里如果混了10%的对齐错误样本,刚开始训练看不出问题,到了后面就会一直有个顽固的loss尾巴,怎么调参数都压不下去。不是模型容量不够,是它在强行拟合一批标签本身自相矛盾的样本。
所以在接进训练管线之前,我会对时长标注做一次"合理性审计":每句的结束时间必须大于起始时间;相邻两句的时间不能大量重叠或出现明显空档;每句时长跟音频实际长度的差值应在容忍范围。这一套规则用Python写个脚本十几分钟就能跑完,却能提前过滤掉最脏的那批数据。按我的经验,一个网上下载的数据集能一次通过这种审计的比例,经常不到七成。
2.3 标注格式的兼容与归一
不同来源的数据集,时长标注的格式五花八门:有JSON数组,有CSV三列,有TextGrid分层,甚至还有塞在MIDI歌词事件里的。接进自己的项目之前,我会统一转成同一种中间格式,最省心的做法是JSON,每首歌一个文件:
[ { "start": 3.42, "end": 3.781, "text": "我", "phonemes": [{"phone": "w", "start": 3.42, "end": 3.55}, {"phone": "o3", "start": 3.55, "end": 3.781}] } ]这个结构足够灵活,既能表达句子级也能表达音素级,后面切音频、对齐、训练都不用再关心源格式长什么样。归一化这一步虽然无聊,但它是整个数据管线里最值得花时间的地方——统一了格式,后面所有脚本才能复用。
3. 数据验收:从文件名到波形图的逐级体检
我不相信任何网上分享的数据集"到手即用"。这个标题里写的是"100首歌声数据集",但实际操作里,100这个数字很可能有水份——可能是曲目编号有重复,可能是某首歌的wav文件损坏成0字节,也可能是midi文件其实是民乐改编版。所以拿到压缩包的第一时间,我的动作是解压、列清单、体检,而不是急着跑模型。
3.1 文件级清单检查
先在解压后的根目录跑一遍全文件清单,看看整体目录结构长什么样:
find . -type f | sed 's/.*\.//' | sort | uniq -c这个命令能快速统计出每种后缀的文件数量。理想的四件套应该是100个wav、100个midi、至少100份歌词文本、100份标注文件。如果数量对不上,比如只有93个标注文件,那就需要把缺的曲子列出来单独处理,而不是假装没看见。数量对得上的前提下,再看命名是否成体系,最常见的坑是:wav叫track01.wav,midi却叫chinese_song_01.mid,没有统一ID,后面做文件匹配的时候就会很痛苦。
3.2 音频级体检:采样率、声道数、真实时长
文件完整度过关后,接下来对wav挨个体检。这里我习惯用一个ffprobe脚本批量导出音频信息:
for f in wavs/*.wav; do ffprobe -v quiet -show_entries format=duration -show_entries stream=codec_name,sample_rate,channels \ -of csv "$f" | sed "s|^|$f,|" done跑完你就能得到一张csv表,里面是每首歌的时长、采样率、声道数。然后对着检查:这100首的采样率是不是统一?如果是44.1kHz就有训练的时候要重采样的意识;如果混着48kHz和44.1kHz,训练之前必须统一;声道如果有些是立体声有些是单声道,得想清楚处理策略。另一个检查点是时长:标称3分钟的歌,实际长度却只有30秒,这种文件大概率是被截断或者转码出错了。
如果条件允许,我还会抽几首用librosa画出波形和频谱,确认不是噪音或静音文件。一个容易被忽略的细节是,很多网上下载的数据包,wav头部信息正常,但实际音频段被截断了,用人工听一张张验太累,但用波形图看能量分布一眼就能揪出来。
3.3 midi与歌词的交叉核对
midi文件最容易出的问题,是人声主旋律轨和伴奏轨混在一起。一个标准的歌曲midi往往有好几条轨:钢琴、贝斯、鼓、主旋律。而歌声数据集里我们要的,通常只有主旋律轨。拿到midi后我会用mido把轨道列出来,看看每条轨道的音符密度和音域:
import mido mid = mido.MidiFile("song.mid") for i, track in enumerate(mid.tracks): notes = [msg for msg in track if msg.type == "note_on" and msg.velocity > 0] if notes: pitches = [n.note for n in notes] print(f"Track {i}: {len(notes)} notes, pitch range {min(pitches)}-{max(pitches)}")主旋律轨通常音符数跟歌词字数接近,音域也不会跨到超低音区。如果某条轨的音符数远超歌词字数,那多半是伴奏里的分解和弦。这个交叉核对不需要做得多精细,目的只是确认你后面用的midi是"歌声的主旋律",而不是"伴奏的千军万马"。
歌词文本好不好用,主要看编码。中文歌词最常见的坑是UTF-8被错误识别成GBK,打开以后满屏乱码。我一般用file命令先看编码,再写个小脚本统一转成UTF-8。另外还要确认歌词是否带注音或音调标记,纯汉字和带拼音的数据集,在使用难度上完全不是一个档次的。
3.4 时长标注的抽样人工复查
机器能检查的只有格式和逻辑,但端点标注是否真正落在语音边界上,机器暂时还判断不了,只能人工听。抽样复查的姿势是:从100首里随机抽5首,用Python读取标注里的前10个字的时间,然后用ffmpeg把音频按时间切出来,一段段听。
ffmpeg -i song.wav -ss 3.42 -to 3.781 -c copy output_chunk.wav如果切出来的每段音频能跟标注文字一一对应,那代表标注质量有一定保证;如果经常出现切到半个音、句子错位、或者文字和音频对不上,那这批数据的标注就得重新评估,考虑是否放弃这5首,还是扩大到全量检查。我遇到过一个数据集,前面30首标注问题不大,从第31首开始全是偏移的,估计是标注到一半换人干活了,后面就彻底放飞。
4. 接进训练管线:音频标准化与midi解析的实操细节
数据验收通过之后,才能进入正式的预处理。这部分的目标非常明确:把wav和midi转成模型能直接消费的张量,歌词文本转成带音素的符号序列,把时长标注转成对齐矩阵。每个细节都会影响最终模型效果,所以我每条链路都要说得具体一点。
4.1 音频标准化:采样率统一与去静音
训练歌声相关模型,音频采样率的默认选择通常是22050Hz或24000Hz。100首歌如果原生是44.1kHz,直接用librosa重采样也行,但数据量一大我会改用ffmpeg,速度快不少:
ffmpeg -i input.wav -ar 22050 -ac 1 -acodec pcm_s16le output.wav这一条命令完成三件事:采样率转22050Hz、转单声道、编码转16位PCM。转换之前建议先看看数据里有没有已经是单声道的文件,统一处理成单声道可以避免训练时声道不匹配。去静音这步得小心,歌曲首尾的呼吸声和极短的气口不一定要全切掉,我只去掉时长超过0.5秒且能量接近0的长静音段,保留开头的人声进场前一小段,防止切太狠破坏句间连贯性。
4.2 midi解析:把音符事件变成F0曲线
训练歌声合成或做音高对比时,midi里的音符是不能直接用的,需要把它转成帧级F0参考。MIDI音符编号转频率的公式是f = 440 * 2^((n - 69) / 12),这个对应关系是很多算法的基础。我在处理时会用一个固定hop_size,比如512,对应22050Hz下约23ms一帧。
关键细节在音符边界跟帧边界不完全对齐。midi里记录的是"起始tick数和持续tick数",要结合Tempo变化换算成秒,再映射到帧索引。这里最容易踩的坑是忽略速度变化:如果歌曲中途有rubato或变速段,直接用固定bps去换算,后面的音符全部对不上。正确的做法是遍历midi里的Tempo事件,逐段计算累计时间:
import mido import numpy as np mid = mido.MidiFile("song.mid") tempo = 500000 # 默认120BPM对应的微秒/拍 current_time = 0 note_frames = [] for msg in mid: current_time += mido.tick2second(msg.time, mid.ticks_per_beat, tempo) if msg.type == "set_tempo": tempo = msg.tempo elif msg.type == "note_on" and msg.velocity > 0: # 音符起始时间记录下来,note_off再记录结束 note_frames.append((current_time, msg.note))这段代码把Tempo变化考虑进去,遇到变速段才能得到基本准确的绝对时间。把音符序列映射到帧号之后,常见的选择是取每帧的音高作为该帧的F0参考值,没有音符覆盖的帧标记为静音或无音高段。这个音高参考谱,是后面跑时长对齐、音高准确性评估的基础。
4.3 歌词与标注进训练标签
准备好音频和midi之后,下一步是把歌词文本映射成训练标签。首先做字到音素的切分。中文可以用pypinyin或者更专用的G2P工具,英文可以用espeak-ng这类,日语就得用到pykakasi或OpenJTalk。拿音素序列跟时长标注里的文本比对,确认每个字的音素个数和标注里的颗粒度对得上。
训练歌声合成模型时,一个常见需求是生成frame-level的标签序列:每一帧属于哪个音素。实现思路是把标注的每个字区间平铺出来,按帧时间戳判断每一帧落在哪个区间,然后填上对应的音素索引。如果标注是句级而非字级,就得先借助强制对齐工具(比如Montreal Forced Aligner,或基于Whisper的对齐方案)把句级标注细化到字级,这一步成本高,但跳不过。
4.4 标准化后的数据集目录组织
几十个小时的音频和几百份标注文件,如果不重命名、不归档,用起来随时会翻车。我通常会把标准化后的数据组织成下面这种结构:
raw/ # 原始文件,只读,备份 processed/ wavs/ # 统一采样率单声道的音频 mids/ # 解析后的音符序列,npy格式 labels/ # frame级标签,npy格式 metadata.json # 全量索引:曲名、歌手、时长、标注来源metadata.json是整个数据集的入口,每一行记录一首歌的所有文件路径、时长、字数、标注粒度。这样不管后面写训练脚本还是做数据筛选,都只需要读这一个文件,不用反复去翻原始目录。我还会顺手把检查脚本的输出结果存一份csv,方便后面做数据子集划分时参考。
5. 拿这套数据能干什么:歌声合成、MIR研究与衍生应用
数据洗好了、管线通了,接下来才是享受成果的时候。这套"wav+midi+歌词+标注"四件套能支撑的方向,比很多人想象的要宽。
5.1 歌声合成与音色克隆
最直接的应用是拿去训练或微调歌声合成模型。用SoVITS这类工具做单曲音色克隆,100首数据里随便挑几首同一歌手的歌就够了,具体看音色相似度要求。如果你想跑更完整的DiffSinger,那需要的是音素级别标注,这套数据如果只做到字级,就得先行补标音素。
实际操作里,我建议不要一上来就把100首全扔给模型训练。先挑30首质量最高的,跑通整个训练流程,看loss能不能正常下降、合成效果是否稳定。确认链路没问题了,再把剩余数据按质量梯度逐步加进去。这种递进式训练,远比第一次就灌100首,出了问题不知道从哪查起要省时间。
5.2 音乐信息检索与对齐研究
对做MIR方向的人来说,midi+时长标注本身就是金矿。可以拿它训练歌声音符起始点检测模型,用midi音符作为ground truth;也可以做歌声与midi的对齐评测基准,比较不同对齐算法在真实唱歌数据上的表现;歌词标注还能支撑歌词音素识别、歌声语音识别等任务。
这类任务的关键在于评测时千万不能用训练集里的歌,否则模型背答案都能背出高分。建议把100首分成训练、验证、测试三份,比例可以按8:1:1,测试集里的歌在训练时彻底不见。很多公开数据集的悲剧就是划分不当,导致论文指标虚高,复现时集体翻车。
5.3 歌词滚动字幕与卡拉OK
我最近给一个视频项目做自动歌词字幕,发现这套数据里的时长标注稍微改一改就能直接用来生成卡拉OK滚字。原理不复杂:从标注里拿到每句或每字的起止时间,按时间顺序输出LRC格式字幕,或者渲染成带高亮的字幕文件。如果你只想做效果演示,不需要训练模型,这可能是最快见效的玩法。
5.4 作为预训练数据的小规模扩展
100首歌单独训练可能不够,但它可以作为预训练语料,用来初始化模型参数,然后再用目标歌手的少量数据微调。这在TTS和SVS里是常见的迁移学习思路:先用大规模数据学"怎么唱歌"的通识,再用小数据学"这个歌手的音色"。你在网上找到的其他音频数据,只要统一转成同样的采样率、同一种标签格式,就能跟这批数据合并扩充训练集,扩大数据量的同时还能摊平标注噪声。
6. 我实际踩过的坑:编码、漂移、多轨与伴奏残留
最后这部分,是每次处理音频数据都绕不开的四个实战坑。我不保证每一条都会出现在你这份数据上,但提前知道怎么处理,能少走不少弯路。
6.1 中文歌词编码:UTF-8和GBK的修罗场
网上下载的数据,歌词txt文件最常见的死法是用GBK编码保存,被Python按UTF-8读取,结果全是\ufffd替换字符。更隐蔽的是前几个文件是UTF-8,后面某几个变GBK,整体读一遍下来半途报错。
应对方法:读文本之前先用chardet或charset-normalizer探测编码,探测到非UTF-8就转码。还有个更粗暴但实用的土办法,直接检查文件头是不是UTF-8的BOM,有BOM的按UTF-8-sig读,没有BOM的再走detect流程。实际处理时我建议统一转成UTF-8无BOM输出,覆盖原文件或另存一份,避免后面每个脚本都重做一次编码判断。
6.2 时长标注漂移:标注员中途换人不是段子
标注漂移指的是同一首歌里,前半部分标注偏早、后半部分标注偏晚,或者整首歌所有的标签都整体向后偏移了200毫秒。这种问题靠抽样听很难发现,因为单听一个字感觉"差不多",但把整首歌的字边界连起来对比midi音符,立刻就能看出整段错位。
定位漂移的方式,是把标注的每字结束时间跟midi的音符起始时间做差,画出偏差分布。如果偏差曲线在中段出现跳变,或者整体呈线性递增,基本就是漂移。处理办法取决于漂移类型:整体偏移直接加固定修正量;逐段漂移则要用分段映射校正,把标注时间映射到midi时间轴。比较严重的,可以直接把那几首排除训练集,不值得浪费时间去修。
6.3 midi多轨与主旋律选择
我前面提过midi文件多轨的问题,再补充一个细节:即使只有一轨,也未必是主旋律,有些midi会把人声旋律和主奏乐器放在同一轨,音符数量多且密集。选择主旋律轨时,我一般结合歌词字数判断——歌词有多少个字,主旋律音符就大概有多少个,相差超过50%就说明选错了。
有个实用的辅助手段:把各轨的音符转成MIDI可视化,直接在DAW或者Python的pretty_midi里画出钢琴卷帘。人类看一眼就能分辨哪条是主旋律,尤其是音高跨度大、节奏跟着歌词走的,基本就是。筛轨这件事别偷懒,用错轨道会导致后面的音高标签全错,而这种错误不会体现在loss上,只会体现在最终合成的声音离谱上。
6.4 wav里还残留伴奏或和声
即使是标着"干声"的wav,也经常混着轻微伴奏、和声或者混响尾巴。这不能全怪数据分享者,录音条件、后期处理方式都会影响。对训练歌声模型来说,伴奏残留会干扰音高提取,导致标注的F0和实际音频不匹配。
最粗暴的解决方式是用开源的分离工具跑一遍人声分离,UVR5或者Demucs都行,把分离出来的纯人声再跟原音色对比一下,损失小就采用,损失大就放弃或者减权重。如果只是少量伴奏残留,也可以用高通滤波和动态压缩稍微改善,但这治标不治本,对训练数据干净度要求高的话,分离几乎是必经步骤。
处理音频数据这件事,说到底没有一劳永逸的标准答案,每个数据包的毛病都不一样。但有一件事是共通的:把"验收"和"清洗"当回事,后面训练才会顺;省了前面的功夫,迟早会在调试模型的时候加倍还回来。我每次拿到新的歌声数据集,哪怕看起来再规整,也会按这套流程从头到尾走一遍,就当是给自己省心。
本文还有配套的精品资源,点击获取