Открытая речь в текст на русском языке
Коллекция образцов речи из различных аудиоисточников. Набор данных содержит короткие аудиоклипы на русском языке.
Примечание.
Корпорация Майкрософт предоставляет Открытые наборы данных Azure как есть. Корпорация Майкрософт не предоставляет никаких гарантий (явных или подразумеваемых) и не определяет никаких условий в связи с использованием этих наборов данных. В рамках, допускаемых местным законодательством, корпорация Майкрософт отказывается от ответственности за ущерб и убытки (в том числе прямые, косвенные, специальные, опосредованные, случайные и штрафные), понесенные в результате использования вами этих наборов данных.
Этот набор данных предоставляется на тех же условиях, на которых корпорация Майкрософт получила исходные данные. Этот набор может включать данные, полученные от корпорации Майкрософт.
Этот набор данных русской речи в текст (STT) включает:
- ~ 16 миллионов высказываний
- ~ 20 000 часов
- 2,3 ТБ (без сжатия в формате .wav в int16), 356 ГБ в opus
- Все файлы преобразованы в opus, за исключением проверочных наборов данных
основное назначение набора данных — обучение моделей преобразования речи в текст.
Состав набора данных
Размер набора данных указан для файлов .wav.
НАБОР ДАННЫХ | РЕЧЕВЫЕ ФРАГМЕНТЫ | ЧАСЫ | ГБ | СЕКУНД/СИМВОЛОВ | КОММЕНТАРИЙ | ПРИМЕЧАНИЕ | КАЧЕСТВО/ШУМ |
---|---|---|---|---|---|---|---|
radio_v4 (*) | 7 603 192 | 10 430 | 1195 | 5 с / 68 | Radio | Align | 95% / четко |
public_speech (*) | 1 700 060 | 2709 | 301 | 6 с / 79 | Публичные выступления | Align | 95% / четко |
audiobook_2 | 1 149 404 | 1511 | 162 | 5 с / 56 | Книги | Align | 95% / четко |
radio_2 | 651 645 | 1439 | 154 | 8 с / 110 | Radio | Align | 95% / четко |
public_youtube1120 | 1 410 979 | 1104 | 237 | 3 с / 34 | YouTube | Субтитры | 95% / ~четко |
public_youtube700 | 759 483 | 701 | 75 | 3 с / 43 | YouTube | Субтитры | 95% / ~четко |
tts_russian_addresses | 1 741 838 | 754 | 81 | 2 с / 20 | Адреса | 4 голоса для преобразования текста в речь | 100 % / четкое |
asr_public_phone_calls_2 | 603 797 | 601 | 66 | 4 с / 37 | Звонки | ASR | 70% / noisy |
public_youtube1120_hq | 369 245 | 291 | 31 | 3 с / 37 | YouTube, высокое качество | Субтитры | 95% / ~четко |
asr_public_phone_calls_1 | 233 868 | 211 | 23 | 3 с / 29 | Звонки | ASR | 70% / noisy |
radio_v4_add (*) | 92 679 | 157 | 18 | 6 с / 80 | Radio | Align | 95% / четко |
asr_public_stories_2 | 78 186 | 78 | 9 | 4 с / 43 | Книги | ASR | 80% / crisp |
asr_public_stories_1 | 46 142 | 38 | 4 | 3 с / 30 | Книги | ASR | 80% / crisp |
public_series_1 | 20 243 | 17 | 2 | 3 с / 38 | YouTube | Субтитры | 95% / ~четко |
asr_calls_2_val | 12 950 | 7,7 | 2 | 2 с / 34 | Звонки | Заметки вручную | 99% / четко |
public_lecture_1 | 6 803 | 6 | 1 | 3 с / 47 | Лекции | Субтитры | 95% / четко |
buriy_audiobooks_2_val | 7 850 | 4,9 | 1 | 2 с / 31 | Книги | Заметки вручную | 99% / четко |
public_youtube700_val | 7 311 | 4,5 | 1 | 2 с / 35 | YouTube | Заметки вручную | 99% / четко |
(*) Для TXT-файлов предоставляется только пример данных.
Методология создания заметок
Набор данных собран из открытых источников. Все длинные аудиофрагменты разбиваются на блоки с учетом интенсивности голоса и выравнивания. Некоторые типы аудио аннотируются автоматически и проверяются статистически с помощью эвристики.
Объемы данных и частота обновления
Общий размер набора данных составляет 350 ГБ. Общий размер набора данных с общедоступными метками составляет 130 ГБ.
Сам набор данных вряд ли будет обновлен для обеспечения обратной совместимости. Следуйте исходному репозиторию для тестов и исключите файлы.
В будущем будут добавляться новые предметные области и языки.
Нормализация звука
Все файлы нормализованы для упрощения и ускорения дополнений во время выполнения. Процесс обработки происходит следующим образом:
- Преобразование в моно при необходимости.
- При необходимости конвертируется в частоту дискретизации 16 кГц;
- Сохранение в формате 16-разрядных целых чисел.
- Преобразование в формат OPUS.
Применяется метод базы данных на диске.
Каждый аудиофайл (WAV и двоичные файлы) хэширован. Хеш используется для создания иерархии папок для более оптимальной работы fs.
target_format = 'wav'
wavb = wav.tobytes()
f_hash = hashlib.sha1(wavb).hexdigest()
store_path = Path(root_folder,
f_hash[0],
f_hash[1:3],
f_hash[3:15] + '.' + target_format)
Скачиваемые файлы
Набор данных предоставляется в двух формах:
- Архивы доступны через хранилище BLOB-объектов Azure и/или по прямым ссылкам;
- Исходные файлы доступны в Хранилище BLOB-объектов Azure; все хранится здесь: https://azureopendatastorage.blob.core.windows.net/openstt/
Структура папок
└── ru_open_stt_opus <= archived folders
│ │
│ ├── archives
│ │ ├── asr_calls_2_val.tar.gz <= tar.gz archives with opus and wav files
│ │ │ ... <= see the below table for enumeration
│ │ └── tts_russian_addresses_rhvoice_4voices.tar.gz
│ │
│ └── manifests
│ ├── asr_calls_2_val.csv <= csv files with wav_path, text_path, duration (see notebooks)
│ │ ...
│ └── tts_russian_addresses_rhvoice_4voices.csv
│
└── ru_open_stt_opus_unpacked <= a separate folder for each uploaded domain
├── public_youtube1120
│ ├── 0 <= see "On disk DB methodology" for details
│ ├── 1
│ │ ├── 00
│ │ │ ...
│ │ └── ff
│ │ ├── *.opus <= actual files
│ │ └── *.txt
│ │ ...
│ └── f
│
├── public_youtube1120_hq
├── public_youtube700_val
├── asr_calls_2_val
├── radio_2
├── private_buriy_audiobooks_2
├── asr_public_phone_calls_2
├── asr_public_stories_2
├── asr_public_stories_1
├── public_lecture_1
├── asr_public_phone_calls_1
├── public_series_1
└── public_youtube700
НАБОР ДАННЫХ | ГБ, WAV | GB, АРХИВ | АРХИВ | ИСТОЧНИК | МАНИФЕСТ |
---|---|---|---|---|---|
Обучение | |||||
Примеры радиотрансляций и публичных выступлений | - | 11,4 | opus+txt | - | manifest |
audiobook_2 | 162 | 25,8 | opus+txt | Интернет + выравнивание | manifest |
radio_2 | 154 | 24,6 | opus+txt | Radio | manifest |
public_youtube1120 | 237 | 19,0 | opus+txt | Видеозаписи YouTube | manifest |
asr_public_phone_calls_2 | 66 | 9,4 | opus+txt | Интернет + ASR | manifest |
public_youtube1120_hq | 31 | 4,9 | opus+txt | Видеозаписи YouTube | manifest |
asr_public_stories_2 | 9 | 1.4 | opus+txt | Интернет + выравнивание | manifest |
tts_russian_addresses_rhvoice_4voices | 80,9 | 12,9 | opus+txt | TTS | manifest |
public_youtube700 | 75,0 | 12,2 | opus+txt | Видеозаписи YouTube | manifest |
asr_public_phone_calls_1 | 22,7 | 3.2 | opus+txt | Интернет + ASR | manifest |
asr_public_stories_1 | 4,1 | 0,7 | opus+txt | Общедоступные истории | manifest |
public_series_1 | 1,9 | 0,3 | opus+txt | Общедоступные серии | manifest |
public_lecture_1 | 0,7 | 0,1 | opus+txt | Интернет + руководства | manifest |
Val | |||||
asr_calls_2_val | 2 | 0,8 | wav+txt | Интернет | manifest |
buriy_audiobooks_2_val | 1 | 0,5 | wav+txt | Книги + руководства | manifest |
public_youtube700_val | 2 | 0,13 | wav+txt | Видео на YouTube + руководство | manifest |
Инструкции по загрузке
Прямая загрузка
Инструкции по загрузке набора данных напрямую см. на странице инструкций по загрузке GitHub.
Дополнительная информация:
Для получения помощи или вопросов о данных свяжитесь с авторами данных по адресу aveysov@gmail.com
Эта лицензия позволяет пользователям распространять, ремикшировать, адаптировать и использовать материал на любом носителе или в любом формате только в некоммерческих целях и только при условии указания авторства. Она включает следующие элементы:
- BY — обязательно указание авторства
- NC — разрешено только некоммерческое использование
CC-BY-NC и коммерческое использование допускаются по согласованию с авторами набора данных.
Доступ к данным
Записные книжки Azure
Вспомогательные функции/зависимости
Сборка libsndfile
Эффективный способ чтения файлов opus в Python, который не требует значительных накладных расходов, - это использовать pysoundfile (оболочка Python CFFI вокруг libsoundfile).
Поддержка Opus была реализована в апстриме, но не была выпущена должным образом. Поэтому мы выбрали кастомную сборку + партизанское латание.
Как правило, вам нужно запустить это в своей оболочке с доступом sudo:
apt-get update
apt-get install cmake autoconf autogen automake build-essential libasound2-dev \
libflac-dev libogg-dev libtool libvorbis-dev libopus-dev pkg-config -y
cd /usr/local/lib
git clone https://github.com/erikd/libsndfile.git
cd libsndfile
git reset --hard 49b7d61
mkdir -p build && cd build
cmake .. -DBUILD_SHARED_LIBS=ON
make && make install
cmake --build .
Вспомогательные функции/зависимости
Установите следующие библиотеки:
pandas
numpy
scipy
tqdm
soundfile
librosa
Манифесты представляют собой файлы csv со следующими столбцами:
- Путь к аудио
- Путь к текстовому файлу
- Duration
Они оказались самым простым форматом доступа к данным.
Для удобства использования все манифесты были заведомо перенастроены. Все пути в них относительные, вам необходимо указать корневую папку.
# manifest utils
import os
import numpy as np
import pandas as pd
from tqdm import tqdm
from urllib.request import urlopen
def reroot_manifest(manifest_df,
source_path,
target_path):
if source_path != '':
manifest_df.wav_path = manifest_df.wav_path.apply(lambda x: x.replace(source_path,
target_path))
manifest_df.text_path = manifest_df.text_path.apply(lambda x: x.replace(source_path,
target_path))
else:
manifest_df.wav_path = manifest_df.wav_path.apply(lambda x: os.path.join(target_path, x))
manifest_df.text_path = manifest_df.text_path.apply(lambda x: os.path.join(target_path, x))
return manifest_df
def save_manifest(manifest_df,
path,
domain=False):
if domain:
assert list(manifest_df.columns) == ['wav_path', 'text_path', 'duration', 'domain']
else:
assert list(manifest_df.columns) == ['wav_path', 'text_path', 'duration']
manifest_df.reset_index(drop=True).sort_values(by='duration',
ascending=True).to_csv(path,
sep=',',
header=False,
index=False)
return True
def read_manifest(manifest_path,
domain=False):
if domain:
return pd.read_csv(manifest_path,
names=['wav_path',
'text_path',
'duration',
'domain'])
else:
return pd.read_csv(manifest_path,
names=['wav_path',
'text_path',
'duration'])
def check_files(manifest_df,
domain=False):
orig_len = len(manifest_df)
if domain:
assert list(manifest_df.columns) == ['wav_path', 'text_path', 'duration']
else:
assert list(manifest_df.columns) == ['wav_path', 'text_path', 'duration', 'domain']
wav_paths = list(manifest_df.wav_path.values)
text_path = list(manifest_df.text_path.values)
omitted_wavs = []
omitted_txts = []
for wav_path, text_path in zip(wav_paths, text_path):
if not os.path.exists(wav_path):
print('Dropping {}'.format(wav_path))
omitted_wavs.append(wav_path)
if not os.path.exists(text_path):
print('Dropping {}'.format(text_path))
omitted_txts.append(text_path)
manifest_df = manifest_df[~manifest_df.wav_path.isin(omitted_wavs)]
manifest_df = manifest_df[~manifest_df.text_path.isin(omitted_txts)]
final_len = len(manifest_df)
if final_len != orig_len:
print('Removed {} lines'.format(orig_len-final_len))
return manifest_df
def plain_merge_manifests(manifest_paths,
MIN_DURATION=0.1,
MAX_DURATION=100):
manifest_df = pd.concat([read_manifest(_)
for _ in manifest_paths])
manifest_df = check_files(manifest_df)
manifest_df_fit = manifest_df[(manifest_df.duration>=MIN_DURATION) &
(manifest_df.duration<=MAX_DURATION)]
manifest_df_non_fit = manifest_df[(manifest_df.duration<MIN_DURATION) |
(manifest_df.duration>MAX_DURATION)]
print(f'Good hours: {manifest_df_fit.duration.sum() / 3600:.2f}')
print(f'Bad hours: {manifest_df_non_fit.duration.sum() / 3600:.2f}')
return manifest_df_fit
def save_txt_file(wav_path, text):
txt_path = wav_path.replace('.wav','.txt')
with open(txt_path, "w") as text_file:
print(text, file=text_file)
return txt_path
def read_txt_file(text_path):
#with open(text_path, 'r') as file:
response = urlopen(text_path)
file = response.readlines()
for i in range(len(file)):
file[i] = file[i].decode('utf8')
return file
def create_manifest_from_df(df, domain=False):
if domain:
columns = ['wav_path', 'text_path', 'duration', 'domain']
else:
columns = ['wav_path', 'text_path', 'duration']
manifest = df[columns]
return manifest
def create_txt_files(manifest_df):
assert 'text' in manifest_df.columns
assert 'wav_path' in manifest_df.columns
wav_paths, texts = list(manifest_df['wav_path'].values), list(manifest_df['text'].values)
# not using multiprocessing for simplicity
txt_paths = [save_txt_file(*_) for _ in tqdm(zip(wav_paths, texts), total=len(wav_paths))]
manifest_df['text_path'] = txt_paths
return manifest_df
def replace_encoded(text):
text = text.lower()
if '2' in text:
text = list(text)
_text = []
for i,char in enumerate(text):
if char=='2':
try:
_text.extend([_text[-1]])
except:
print(''.join(text))
else:
_text.extend([char])
text = ''.join(_text)
return text
# reading opus files
import os
import soundfile as sf
# Fx for soundfile read/write functions
def fx_seek(self, frames, whence=os.SEEK_SET):
self._check_if_closed()
position = sf._snd.sf_seek(self._file, frames, whence)
return position
def fx_get_format_from_filename(file, mode):
format = ''
file = getattr(file, 'name', file)
try:
format = os.path.splitext(file)[-1][1:]
format = format.decode('utf-8', 'replace')
except Exception:
pass
if format == 'opus':
return 'OGG'
if format.upper() not in sf._formats and 'r' not in mode:
raise TypeError("No format specified and unable to get format from "
"file extension: {0!r}".format(file))
return format
#sf._snd = sf._ffi.dlopen('/usr/local/lib/libsndfile/build/libsndfile.so.1.0.29')
sf._subtypes['OPUS'] = 0x0064
sf.SoundFile.seek = fx_seek
sf._get_format_from_filename = fx_get_format_from_filename
def read(file, **kwargs):
return sf.read(file, **kwargs)
def write(file, data, samplerate, **kwargs):
return sf.write(file, data, samplerate, **kwargs)
# display utils
import gc
from IPython.display import HTML, Audio, display_html
pd.set_option('display.max_colwidth', 3000)
#Prepend_path is set to read directly from Azure. To read from local replace below string with path to the downloaded dataset files
prepend_path = 'https://azureopendatastorage.blob.core.windows.net/openstt/ru_open_stt_opus_unpacked/'
def audio_player(audio_path):
return '<audio preload="none" controls="controls"><source src="{}" type="audio/wav"></audio>'.format(audio_path)
def display_manifest(manifest_df):
display_df = manifest_df
display_df['wav'] = [audio_player(prepend_path+path) for path in display_df.wav_path]
display_df['txt'] = [read_txt_file(prepend_path+path) for path in tqdm(display_df.text_path)]
audio_style = '<style>audio {height:44px;border:0;padding:0 20px 0px;margin:-10px -20px -20px;}</style>'
display_df = display_df[['wav','txt', 'duration']]
display(HTML(audio_style + display_df.to_html(escape=False)))
del display_df
gc.collect()
Воспроизведение с помощью набора данных
Воспроизведение образца файлов
Браузеры большинства платформ поддерживают собственное воспроизведение звука. Таким образом, мы можем использовать аудиоплееры HTML5 для просмотра ваших данных.
manifest_df = read_manifest(prepend_path +'/manifests/public_series_1.csv')
#manifest_df = reroot_manifest(manifest_df,
#source_path='',
#target_path='../../../../../nvme/stt/data/ru_open_stt/')
sample = manifest_df.sample(n=20)
display_manifest(sample)
Чтение файла
!ls ru_open_stt_opus/manifests/*.csv
Некоторые примеры, показывающие, как лучше всего читать файлы wav и opus.
Scipy является наиболее быстрым вариантом для wav. Pysoundfile - лучший вариант для opus.
%matplotlib inline
import librosa
from scipy.io import wavfile
from librosa import display as ldisplay
from matplotlib import pyplot as plt
Чтение wav
manifest_df = read_manifest(prepend_path +'manifests/asr_calls_2_val.csv')
#manifest_df = reroot_manifest(manifest_df,
#source_path='',
#target_path='../../../../../nvme/stt/data/ru_open_stt/')
sample = manifest_df.sample(n=5)
display_manifest(sample)
from io import BytesIO
wav_path = sample.iloc[0].wav_path
response = urlopen(prepend_path+wav_path)
data = response.read()
sr, wav = wavfile.read(BytesIO(data))
wav.astype('float32')
absmax = np.max(np.abs(wav))
wav = wav / absmax
# shortest way to plot a spectrogram
D = librosa.amplitude_to_db(np.abs(librosa.stft(wav)), ref=np.max)
plt.figure(figsize=(12, 6))
ldisplay.specshow(D, y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Log-frequency power spectrogram')
# shortest way to plot an envelope
plt.figure(figsize=(12, 6))
ldisplay.waveplot(wav, sr=sr, max_points=50000.0, x_axis='time', offset=0.0, max_sr=1000, ax=None)
Чтение opus
manifest_df = read_manifest(prepend_path +'manifests/asr_public_phone_calls_2.csv')
#manifest_df = reroot_manifest(manifest_df,
#source_path='',
#target_path='../../../../../nvme/stt/data/ru_open_stt/')
sample = manifest_df.sample(n=5)
display_manifest(sample)
opus_path = sample.iloc[0].wav_path
response = urlopen(prepend_path+opus_path)
data = response.read()
wav, sr = sf.read(BytesIO(data))
wav.astype('float32')
absmax = np.max(np.abs(wav))
wav = wav / absmax
# shortest way to plot a spectrogram
D = librosa.amplitude_to_db(np.abs(librosa.stft(wav)), ref=np.max)
plt.figure(figsize=(12, 6))
ldisplay.specshow(D, y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Log-frequency power spectrogram')
# shortest way to plot an envelope
plt.figure(figsize=(12, 6))
ldisplay.waveplot(wav, sr=sr, max_points=50000.0, x_axis='time', offset=0.0, max_sr=1000, ax=None)
Следующие шаги
Ознакомьтесь с другими наборами в каталоге Открытых наборов данных.