Huggingface - 创建音频数据集(Create an audio dataset)
一、本地文件二、音频文件夹加载脚本三、加载脚本1、创建一个 dataset builder类Multiple configurations2、添加数据集元数据3、下载和定义数据集拆分4、生成数据集5、将数据集上载到 Hub6、(Advanced) 本地提取压缩文件1)下载并定义数据集拆分2)生成数据集
文章目录
翻译自:https://huggingface.co/docs/datasets/audio_dataset
一、本地文件
audio_dataset = Dataset.from_dict({"audio": ["path/to/audio_1", "path/to/audio_2", ..., "path/to/audio_n"]}).cast_column("audio", Audio())
# ***
audio_dataset[0]["audio"]
{'array': array([ 0. , 0.00024414, -0.00024414, ..., -0.00024414,
0. , 0. ], dtype=float32),
'path': 'path/to/audio_1',
'sampling_rate': 16000}
将创建一个 dataset repo,包含你的音频数据集
my_dataset/
├── README.md
└── data/
└── train-00000-of-00001.parquet
二、音频文件夹
AudioFolder是一个数据集生成器,旨在快速加载包含数千个音频文件的音频数据集,而无需编写任何代码。
只要您将有关数据集的任何其他信息 包含在 元数据文件(metadata.csv/metadata.jsonl)中,AudioFolder就会自动加载这些信息,例如转录、说话者口音或说话者意图。
在Hugging Face Hub上创建一个数据集存储库,并按照 AudioFolder 结构上传数据集目录:
my_dataset/
├── README.md
├── metadata.csv
└── data/
最好使用 jsonl 格式文件,以免你的数据 columns 格式复杂,导致出错。
元数据文件应包括一个file_name列,用于将音频文件链接到其元数据:
file_name,transcription
data/first_audio_file.mp3,znowu się duch z ciałem zrośnie w młodocianej wstaniesz wiosnie i możesz skutkiem tych leków umierać wstawać wiek wieków dalej tam były przestrogi jak siekać głowę jak nogi
data/second_audio_file.mp3,już u źwierzyńca podwojów król zasiada przy nim książęta i panowie rada a gdzie wzniosły krążył ganek rycerze obok kochanek król skinął palcem zaczęto igrzysko
data/third_audio_file.mp3,pewnie kędyś w obłędzie ubite minęły szlaki zaczekajmy dzień jaki poślemy szukać wszędzie dziś jutro pewnie będzie posłali wszędzie sługi czekali dzień i drugi gdy nic nie doczekali z płaczem chcą jechać dali
你也可以见数据按一下方式存在文件夹:
metadata.csv
data/first_audio_file.mp3
data/second_audio_file.mp3
data/third_audio_file.mp3
用户现在可以通过在 load_dataset() 中指定 audiofolder 和在 data_dir 中指定数据集目录,来加载数据集和相关元数据:
from datasets import load_dataset
>>> dataset = load_dataset("audiofolder", data_dir="/path/to/data")
>>> dataset["train"][0]
{'audio':
{'path': '/path/to/extracted/audio/first_audio_file.mp3',
'array': array([ 0.00088501, 0.0012207 , 0.00131226, ..., -0.00045776, -0.00054932, -0.00054932], dtype=float32),
'sampling_rate': 16000},
'transcription': 'znowu się duch z ciałem zrośnie w młodocianej wstaniesz wiosnie i możesz skutkiem tych leków umierać wstawać wiek wieków dalej tam były przestrogi jak siekać głowę jak nogi'
}
您还可以使用 audiofolder 加载涉及多个拆分的数据集。为此,您的数据集目录可能具有以下结构:
data/train/first_train_audio_file.mp3
data/train/second_train_audio_file.mp3
data/test/first_test_audio_file.mp3
data/test/second_test_audio_file.mp3
***
请注意,如果音频文件不在元数据文件旁边,则 file_name 列应该是音频文件的完整相对路径,而不仅仅是其文件名。
对于没有任何关联元数据的音频数据集,AudioFolder 会根据目录名自动推断数据集的类标签。
它可能对音频分类任务有用。您的数据集目录可能如下所示:
data/train/electronic/01.mp3
data/train/punk/01.mp3
data/test/electronic/09.mp3
data/test/punk/09.mp3
用 AudioFolder 加载数据集,它将根据目录名(语言id)创建一个标签列:
>>> from datasets import load_dataset
>>> dataset = load_dataset("audiofolder", data_dir="/path/to/data")
>>> dataset["train"][0]
{'audio':
{'path': '/path/to/electronic/01.mp3',
'array': array([ 3.9714024e-07, 7.3031038e-07, 7.5640685e-07, ...,
-1.1963668e-01, -1.1681189e-01, -1.1244172e-01], dtype=float32),
'sampling_rate': 44100},
'label': 0 # "electronic"
}
>>> dataset["train"][-1]
{'audio':
{'path': '/path/to/punk/01.mp3',
'array': array([0.15237972, 0.13222949, 0.10627693, ..., 0.41940814, 0.37578005,
0.33717662], dtype=float32),
'sampling_rate': 44100},
'label': 1 # "punk"
}
如果所有音频文件都包含在一个目录中,或者它们不在同一级别的目录结构中,则不会自动添加标签列。
如果需要,请显式设置 drop_labels=False。
一些音频数据集,比如在Kaggle比赛中发现的数据集,对于每个分割都有单独的元数据文件。
如果每个 split 的元数据功能相同,则可以使用audiofolder一次加载所有拆分。
如果每个split 的元数据特性不同,则应该使用单独的 load_dataset() 调用来加载它们。
加载脚本
- 编写数据集加载脚本,以手动创建数据集。
- 它定义了数据集的拆分和配置,并处理下载和生成数据集示例。
- 脚本应与数据集文件夹或存储库具有相同的名称:
my_dataset/
├── README.md
├── my_dataset.py
└── data/
data文件夹可以是您想要的任何名称,它不必是data。- 此文件夹是可选的,除非您将数据集托管在 Hub 上。
- 此目录结构允许在一行中加载数据集:
from datasets import load_dataset
dataset = load_dataset("path/to/my_dataset")
- 本指南将向您展示如何为音频数据集创建数据集加载脚本,这与为文本数据集创建加载脚本 有点不同。
- 音频数据集通常存储在
tar.gz压缩文件中,这需要一种特殊的方法来支持流模式。 - 虽然不需要流,但我们强烈鼓励在您的音频数据集中支持流,因为:
- 没有大量磁盘空间的用户,可以在不下载数据集的情况下使用数据集。请参阅流媒体指南了解有关流媒体的更多信息:https://huggingface.co/docs/datasets/stream
- 用户可以在数据集查看器中预览数据集。
这是使用 TAR 压缩包的示例:
my_dataset/
├── README.md
├── my_dataset.py
└── data/
├── train.tar.gz
├── test.tar.gz
└── metadata.csv
除了学习如何创建可流化数据集外,您还将学习如何:
- 创建一个数据集生成器类。
- 创建数据集配置。
- 添加数据集元数据。
- 下载并定义数据集 splits。
- 生成数据集。
- 将数据集上载到 Hub。
最好的学习方法是打开一个现有的音频数据集加载脚本,比如 Vivos,然后继续学习!
https://huggingface.co/datasets/vivos/blob/main/vivos.py
本指南展示了如何处理存储在TAR档案中的音频数据,这是音频数据集最常见的情况。
查看注意事项14使用ZIP档案的音频脚本示例的数据集。
为了帮助您入门,我们创建了一个加载脚本模板,您可以将其复制并用作起点!
三、加载脚本
1、创建一个 dataset builder 类
GeneratorBasedBuilder is the base class for datasets generated from a dictionary generator.
Within this class, there are three methods to help create your dataset:
_info存储你的数据集信息,如 description, license, and features._split_generators下载数据集,定义 splits_generate_examplesgenerates the dataset’s samples containing the audio data and other features specified ininfofor each split. 产生数据样例,包含 audio 数据,和每个 split 其他在 info 中定义的特征。
创建你的数据类型,作为 GeneratorBasedBuilder 的子类开始,并添加下面三个方法
现在还不用担心填写这些方法中的每一种,您将在接下来的几节中开发这些方法:
class VivosDataset(datasets.GeneratorBasedBuilder):
"""VIVOS is a free Vietnamese speech corpus consisting of 15 hours of recording speech prepared for
Vietnamese Automatic Speech Recognition task."""
def _info(self):
def _split_generators(self, dl_manager):
def _generate_examples(self, prompts_path, path_to_clips, audio_files):
Multiple configurations
在某些情况下,一个数据集可能具有多个配置。
比如, LibriVox Indonesia 数据集,对于不同语言有几种配置;
为了创建不同的配置,使用 BuilderConfig 类来创建你的数据集的子类;
唯一需要的参数是配置的 name ,它必须传递给配置的超类 __init__() 。
否则,您可以在配置类中指定所需的任何自定义参数。
class LibriVoxIndonesiaConfig(datasets.BuilderConfig):
"""BuilderConfig for LibriVoxIndonesia."""
def __init__(self, name, version, **kwargs):
self.language = kwargs.pop("language", None)
self.release_date = kwargs.pop("release_date", None)
self.num_clips = kwargs.pop("num_clips", None)
self.num_speakers = kwargs.pop("num_speakers", None)
self.validated_hr = kwargs.pop("validated_hr", None)
self.total_hr = kwargs.pop("total_hr", None)
self.size_bytes = kwargs.pop("size_bytes", None)
self.size_human = size_str(self.size_bytes)
description = (
f"LibriVox-Indonesia speech to text dataset in {self.language} released on {self.release_date}. "
f"The dataset comprises {self.validated_hr} hours of transcribed speech data"
)
super(LibriVoxIndonesiaConfig, self).__init__(
name=name,
version=datasets.Version(version),
description=description,
**kwargs,
)
在 GeneratorBasedBuilder 内部的 BUILDER_CONFIGS 类变量中定义配置。
在本例中,作者从他们的存储库中 release_stats.py 文件单独的导入语言,然后循环使用每种语言来创建配置。
release_stats.py : https://huggingface.co/datasets/indonesian-nlp/librivox-indonesia/blob/main/release_stats.py
class LibriVoxIndonesiaConfig(datasets.GeneratorBasedBuilder):
DEFAULT_CONFIG_NAME = "all"
BUILDER_CONFIGS = [
LibriVoxIndonesiaConfig(
name=lang,
version=STATS["version"],
language=LANGUAGES[lang],
release_date=STATS["date"],
num_clips=lang_stats["clips"],
num_speakers=lang_stats["users"],
total_hr=float(lang_stats["totalHrs"]) if lang_stats["totalHrs"] else None,
size_bytes=int(lang_stats["size"]) if lang_stats["size"] else None,
)
for lang, lang_stats in STATS["locales"].items()
]
通常,用户需要指定 load_dataset() 要加载的配置,否则会抛出 ValueError 错误。
您可以通过将默认数据集配置设置为在DEFAULT_CONFIG_NAME中加载来避免这种情况。
现在,如果用户想加载 巴厘岛语(bal)配置,他们可以使用配置名称:
>>> from datasets import load_dataset
>>> dataset = load_dataset("indonesian-nlp/librivox-indonesia", "bal", split="train")
2、添加数据集元数据
添加有关数据集的信息,有助于用户了解更多信息。
DatasetInfo : https://huggingface.co/docs/datasets/v2.11.0/en/package_reference/main_classes#datasets.DatasetInfo
此信息存储在 DatasetInfo 类中由 info 方法返回的类。用户可以通过以下方式访问此信息:
>>> from datasets import load_dataset_builder
>>> ds_builder = load_dataset_builder("vivos")
>>> ds_builder.info
有很多关于数据集的信息可以包括在内,但其中一些重要信息是:
1、description 提供了数据集的简要描述。
2、features 指定数据集列类型。由于您正在创建音频加载脚本,你会需要包含 Audio 特征,和数据集的 sampling_rate 。
3、homepage 提供了到数据集主页的链接。
4、license 指定使用许可证类型定义的数据集的权限。
5、citation: 是BibTeX对数据集的引用。
您会注意到许多数据集信息,是在加载脚本的早期定义的,这可以使其更容易阅读。
您还可以输入其他~Dataset.Features , 所以一定要查看完整的列表 和 features guide 的更多信息;
- features guide : https://huggingface.co/docs/datasets/about_dataset_features
def _info(self):
return datasets.DatasetInfo(
description=_DESCRIPTION,
features=datasets.Features(
{
"speaker_id": datasets.Value("string"),
"path": datasets.Value("string"),
"audio": datasets.Audio(sampling_rate=16_000),
"sentence": datasets.Value("string"),
}
),
supervised_keys=None,
homepage=_HOMEPAGE,
license=_LICENSE,
citation=_CITATION,
)
3、下载和定义数据集拆分
现在您已经添加了一些关于数据集的信息,下一步是下载数据集并定义拆分。
1、使用download() 方法来在 _PROMPTS_URLS 下载元数据文件,在 _DATA_URL 下载语音压缩包。
download() : https://huggingface.co/docs/datasets/v2.11.0/en/package_reference/builder_classes#datasets.DownloadManager.download
此方法返回本地文件/归档文件的路径。
在流模式下,它不下载文件,只返回一个URL来流式传输数据。此方法接受:
- Hub数据集存储库中文件的相对路径(例如,
data/文件夹中) - 托管在其他地方的文件的URL
- 文件名或URL的(嵌套)列表或字典
2、你下载数据集后,使用 SplitGenerator 来组织每个split的音频文件和句子prompts。
SplitGenerator : https://huggingface.co/docs/datasets/v2.11.0/en/package_reference/builder_classes#datasets.SplitGenerator
命名每个 split 一个标准的名字,如 Split.TRAIN, Split.TEST, 和 SPLIT.Validation.
在 gen_kwargs 参数中, 用 prompts_path and path_to_clips 说明文件地址。
对于 audio_files, 你需要使用 iter_archive() 来遍历压缩文件中的语音文件。
这将为您的数据集启用流式传输。
所有这些文件路径都被传递到下一步,在那里您将实际生成数据集。
def _split_generators(self, dl_manager):
"""Returns SplitGenerators."""
prompts_paths = dl_manager.download(_PROMPTS_URLS)
archive = dl_manager.download(_DATA_URL)
train_dir = "vivos/train"
test_dir = "vivos/test"
return [
datasets.SplitGenerator(
name=datasets.Split.TRAIN,
gen_kwargs={
"prompts_path": prompts_paths["train"],
"path_to_clips": train_dir + "/waves",
"audio_files": dl_manager.iter_archive(archive),
},
),
datasets.SplitGenerator(
name=datasets.Split.TEST,
gen_kwargs={
"prompts_path": prompts_paths["test"],
"path_to_clips": test_dir + "/waves",
"audio_files": dl_manager.iter_archive(archive),
},
),
]
此实现不会提取下载的压缩文件。
如果你想在下载后提取文件,你需要额外使用 extract() 方法,查看 (Advanced) Extract TAR archives 部分 :
https://huggingface.co/docs/datasets/audio_dataset#advanced-extract-tar-archives-locally
4、生成数据集
GeneratorBasedBuilder 类的最后一个方法,实际生成数据集中的样例。
它根据 info 方法中的 features 中指定的结构生成数据集。
正如你所看到的,generate_examples 接受前面方法中的 prompts_path、path_to_clips 和 audio_files 作为参数。
TAR的文件是按顺序访问和生成的。
这意味着您需要首先掌握与TAR文件中的音频文件相关联的元数据,以便您可以将其与相应的音频文件一起生成。
examples = {}
with open(prompts_path, encoding="utf-8") as f:
for row in f:
data = row.strip().split(" ", 1)
speaker_id = data[0].split("_")[0]
audio_path = "/".join([path_to_clips, speaker_id, data[0] + ".wav"])
examples[audio_path] = {
"speaker_id": speaker_id,
"path": audio_path,
"sentence": data[1],
}
最后,对 audio_files 中的文件进行迭代,并生成它们及其相应的元数据。
iter_archive()生成一个 (path,f) 元组,其中path是TAR归档中文件的相对路径,f是文件对象本身。
iter_archive(): https://huggingface.co/docs/datasets/v2.11.0/en/package_reference/builder_classes#datasets.DownloadManager.iter_archive
inside_clips_dir = False
id_ = 0
for path, f in audio_files:
if path.startswith(path_to_clips):
inside_clips_dir = True
if path in examples:
audio = {"path": path, "bytes": f.read()}
yield id_, {**examples[path], "audio": audio}
id_ += 1
elif inside_clips_dir:
break
把这两步合在一起, 整个 _generate_examples 方法看起来是这样:
def _generate_examples(self, prompts_path, path_to_clips, audio_files):
"""Yields examples as (key, example) tuples."""
examples = {}
with open(prompts_path, encoding="utf-8") as f:
for row in f:
data = row.strip().split(" ", 1)
speaker_id = data[0].split("_")[0]
audio_path = "/".join([path_to_clips, speaker_id, data[0] + ".wav"])
examples[audio_path] = {
"speaker_id": speaker_id,
"path": audio_path,
"sentence": data[1],
}
inside_clips_dir = False
id_ = 0
for path, f in audio_files:
if path.startswith(path_to_clips):
inside_clips_dir = True
if path in examples:
audio = {"path": path, "bytes": f.read()}
yield id_, {**examples[path], "audio": audio}
id_ += 1
elif inside_clips_dir:
break
5、将数据集上载到 Hub
脚本准备好后, 创建数据集卡 并提交到 Hub
恭喜,您现在可以从 Hub 加载数据集了!🥳
- create a dataset card : https://huggingface.co/docs/datasets/dataset_card
- upload it to the Hub : https://huggingface.co/docs/datasets/share
>>> from datasets import load_dataset
>>> load_dataset("<username>/my_dataset")
6、(Advanced) 本地提取压缩文件
在上面的示例中,下载的压缩文件没有被提取,因此示例不包含关于它们的本地存储信息。
为了解释如何以同样支持流的方式进行提取,我们将通过 LibriVox Indonesia 的加载脚本进行简要介绍。
LibriVox Indonesia : https://huggingface.co/datasets/indonesian-nlp/librivox-indonesia/blob/main/librivox-indonesia.py
1)下载并定义数据集拆分
1、使用 download() 方法来下载 _AUDIO_URL 的音频数据
2、要在本地提取音频要所文件,请使用 extract(). 只能在非流模式下使用此方法 (当dl_manager.is_streaming=False). 这将返回提取的压缩目录的本地路径:
local_extracted_archive = dl_manager.extract(audio_path) if not dl_manager.is_streaming else None
3、使用 iter_archive() 方法 来遍历 audio_path 处的文件,和上述 Vivos 示例一样。
iter_archive() 不会提供任何有关存档文件的完整路径的信息,即使它已被提取。
因此,您需要将 local_extracted_archive 路径传递到下一步的 gen_kwargs ,以便保留有关将存档提取到何处的信息。
生成示例时,这是构造本地文件的正确路径所必需的。
您需要使用 download() 和 iter_archive() 组合, 是因为TAR中的文件无法通过其路径直接访问。
相反,您需要对归档中的文件进行迭代!您只能在 非流模式 使用download_and_textract()和extract()TAR存档,否则会引发错误。
4、使用 download_and_extract() 方法下载定义在_METADATA_URL 中的元数据文件。
此方法在非流模式下返回本地文件的路径。在流模式下,它不会在本地下载文件,而是返回相同的URL。
5、现在使用 SplitGenerator 来组织每个split 中的音频文件和元数据。
使用标准名称命名每个split ,如 : Split.TRAIN, Split.TEST, and SPLIT.Validation.
在 gen_kwargs 参数中, 用 prompts_path and path_to_clips 说明文件地址。
对于 audio_files, 你需要使用 iter_archive() 来遍历压缩文件中的语音文件。
这将为您的数据集启用流式传输。
所有这些文件路径都被传递到下一步,在那里您将实际生成数据集。
def _split_generators(self, dl_manager):
"""Returns SplitGenerators."""
dl_manager.download_config.ignore_url_params = True
audio_path = dl_manager.download(_AUDIO_URL)
local_extracted_archive = dl_manager.extract(audio_path) if not dl_manager.is_streaming else None
path_to_clips = "librivox-indonesia"
return [
datasets.SplitGenerator(
name=datasets.Split.TRAIN,
gen_kwargs={
"local_extracted_archive": local_extracted_archive,
"audio_files": dl_manager.iter_archive(audio_path),
"metadata_path": dl_manager.download_and_extract(_METADATA_URL + "/metadata_train.csv.gz"),
"path_to_clips": path_to_clips,
},
),
datasets.SplitGenerator(
name=datasets.Split.TEST,
gen_kwargs={
"local_extracted_archive": local_extracted_archive,
"audio_files": dl_manager.iter_archive(audio_path),
"metadata_path": dl_manager.download_and_extract(_METADATA_URL + "/metadata_test.csv.gz"),
"path_to_clips": path_to_clips,
},
),
]
2)生成数据集
这里_generate_examples 从之前的方法中接收local_extracted_archive, audio_files, metadata_path, 和path_to_clips 作为参数。
1、TAR文件是按顺序访问和生成的。
这意味着您需要首先掌握与TAR文件中的音频文件相关联的 metadata_path的元数据,以便您可以将其与相应的音频文件一起生成。
with open(metadata_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
if self.config.name == "all" or self.config.name == row["language"]:
row["path"] = os.path.join(path_to_clips, row["path"])
# if data is incomplete, fill with empty values
for field in data_fields:
if field not in row:
row[field] = ""
metadata[row["path"]] = row
2、现在你可以遍历 audio_files 压缩包中的文件
使用 iter_archive() 方法, 将 yielded 一个 (path, f) 元组,当 path 被设置为包文件的相对路径, f 是文件本身。
3、获取本地解压文件的全路径,请连接存档提取到的目录的路径(local_extracted_path)和相对音频文件路径(path):
for path, f in audio_files:
if path in metadata:
result = dict(metadata[path])
# set the audio feature and the path to the extracted file
path = os.path.join(local_extracted_archive, path) if local_extracted_archive else path
result["audio"] = {"path": path, "bytes": f.read()}
result["path"] = path
yield id_, result
id_ += 1
把这两步合在一起, 整个 _generate_examples 方法看起来是这样:
def _generate_examples(
self,
local_extracted_archive,
audio_files,
metadata_path,
path_to_clips,
):
"""Yields examples."""
data_fields = list(self._info().features.keys())
metadata = {}
with open(metadata_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
if self.config.name == "all" or self.config.name == row["language"]:
row["path"] = os.path.join(path_to_clips, row["path"])
# if data is incomplete, fill with empty values
for field in data_fields:
if field not in row:
row[field] = ""
metadata[row["path"]] = row
id_ = 0
for path, f in audio_files:
if path in metadata:
result = dict(metadata[path])
# set the audio feature and the path to the extracted file
path = os.path.join(local_extracted_archive, path) if local_extracted_archive else path
result["audio"] = {"path": path, "bytes": f.read()}
result["path"] = path
yield id_, result
id_ += 1
2023-04-23(一)
更多推荐


所有评论(0)