(以下内容搬运自 PaddleSpeech)
PaddleSpeech TTS 内使用的数据格式,数据处理惯例的说明。
DataTable: 表头即 parser
在经历过一些开发实践之后,Parakeet 还是采用了先预处理数据再加载预处理好的数据进行训练的方式。此前我们曾经思考过把预处理写在 Dataset 的 __getitem__
里面,在访问到某一跳样例的时候进行再预处理,我们曾经这么实践过,但是遇到了一些问题。
首先是效率问题,在 Paddle 还没有用上多进程处理数据的时候,这么做很慢,即使 Paddle 有异步加载数据的设计,但是当 batch size 大的时候,每条样例都需要预处理,然后还要组 batch, 事实上花费的时间很多,甚至会严重拖慢训练过程。
其次是数据筛选问题,某些筛选条件依赖处理后的样例的特征,比如说根据文本长度来过滤太短的样本,但是如果我只有 __getitem__
之后才能知道文本的长度,那么筛选一次就需要把整个数据集处理一遍,那么懒惰加载的有点就消失了。另外,如果不预先筛选,在 __getitem__
中遇到长度太短的文本时抛异常,则会引起整个数据流异常,这样又不可行,因为 collate_fn
会预设每条样例的获取都能正常,这样才能正常工作。即使通过一些特殊标记,比如 None 来标记数据获取失败,让 collate_fn
跳过,也会导致出现 batch_size 变化这样的问题。因此把预处理完全放在__getitem__
来做并不现实。
因此,我们还是倾向于使用先预处理,再加载预处理后的数据这样的方式。在预处理的过程中,我们可以做筛选,然后也可以保存更多的中间特征,比如说文本长度,音频长度等,这些可以用于后续筛选。然后出于 TTS 方向的习惯,数据仍然常常以多个文件的方式存储,处理后的结果常用 npy 的格式存储起来。
我们此前不太愿意预处理是因为对于预处理产生的结果需要做一定的规范才方便使用,如果每个实验预处理的方式都不同,那么对于用户也会造成很多困扰,写 README 也会写得很麻烦。但是规定怎样的格式最合适这件事情,我们又不太敢给一个定论,因为可能后面会遇到表现力不足的问题。不过或来出于效率的问题,我们还是把预处理单独作为一个阶段,但是对于预处理后的文件组织方式没有一个很一贯的规定。
曾经一度是通过从一个文件夹中以一定的文件名 pattern 的方式筛选文件的方式来读取预处理后的数据集,但是最近经过最近参考其他的 repo, 以及参考了 kaldi 的 scp 格式。我们认为更好的方式是用一个类似列表的方式哦存储元数据,把文件路径存储在里面,这样就可以不受文件具体的存储位置制约,只要有元数据(文件清单)就可以按图索骥。除了文件路径之外ÿ