Russo Discurso Aberto para Texto
Uma coleção de amostras de voz derivadas de várias origens de áudio. Este conjunto de dados contém clipes de áudio em russo.
Nota
A Microsoft fornece os Conjuntos de Dados Abertos do Azure "no estado em que se encontram". A Microsoft não oferece garantias, expressas ou implícitas, garantias ou condições em relação ao seu uso dos conjuntos de dados. Na medida permitida pela legislação local, a Microsoft se isenta de qualquer responsabilidade por quaisquer danos ou perdas, incluindo diretos, consequenciais, especiais, indiretos, incidentais ou punitivos, resultantes do uso dos conjuntos de dados por parte do cliente.
Este conjunto de dados é disponibilizado de acordo com os termos originais em que a Microsoft recebeu os dados de origem. O conjunto de dados pode incluir dados obtidos junto da Microsoft.
Este conjunto de dados russo de fala para texto (STT) inclui:
- ~16 milhões de declarações
- ~20.000 horas
- 2,3 TB (não comprimido no formato .wav em int16), 356G em opus
- Todos os arquivos foram transformados em opus, exceto para conjuntos de dados de validação
O principal objetivo do conjunto de dados é preparar modelos de voz em texto.
Composição do conjunto de dados
O tamanho do conjunto de dados é fornecido para .wav arquivos.
DATASET | ENUNCIADOS | HORÁRIO | GB | SECS/CHARS | COMENTAR | ANOTAÇÃO | QUALIDADE/RUÍDO |
---|---|---|---|---|---|---|---|
radio_v4 (*) | 7 603 192 | 10 430 | 1195 | 5s / 68 | Botão de opção | Align | 95% / nítido |
public_speech (*) | 1 700 060 | 2709 | 301 | 6s / 79 | Voz pública | Align | 95% / nítido |
audiobook_2 | 1 149 404 | 1511 | 162 | 5s / 56 | Livros | Align | 95% / nítido |
radio_2 | 651 645 | 1439 | 154 | 8s / 110 | Botão de opção | Align | 95% / nítido |
public_youtube1120 | 1 410 979 | 1104 | 237 | 3s / 34 | YouTube | Legendas | 95% / nítido |
public_youtube700 | 759 483 | 701 | 75 | 3s / 43 | YouTube | Legendas | 95% / nítido |
tts_russian_addresses | 1 741 838 | 754 | 81 | 2s / 20 | Endereços | 4 vozes TTS | 100% / nítido |
asr_public_phone_calls_2 | 603,797 | 601 | 66 | 4s / 37 | Chamadas telefónicas | ASR | 70% / ruído |
public_youtube1120_hq | 369 245 | 291 | 31 | 3s / 37 | YouTube HQ | Legendas | 95% / nítido |
asr_public_phone_calls_1 | 233 868 | 211 | 23 | 3s / 29 | Chamadas telefónicas | ASR | 70% / ruído |
radio_v4_add (*) | 92 679 | 157 | 18 | 6s / 80 | Botão de opção | Align | 95% / nítido |
asr_public_stories_2 | 78 186 | 78 | 9 | 4s / 43 | Livros | ASR | 80% / nítido |
asr_public_stories_1 | 46 142 | 38 | 4 | 3s / 30 | Livros | ASR | 80% / nítido |
public_series_1 | 20 243 | 17 | 2 | 3s / 38 | YouTube | Legendas | 95% / nítido |
asr_calls_2_val | 12 950 | 7,7 | 2 | 2s / 34 | Chamadas telefónicas | Anotação manual | 99% / nítido |
public_lecture_1 | 6803 | 6 | 1 | 3s / 47 | Palestras | Legendas | 95% / nítido |
buriy_audiobooks_2_val | 7850 | 4,9 | 1 | 2s / 31 | Livros | Anotação manual | 99% / nítido |
public_youtube700_val | 7311 | 4,5 | 1 | 2s / 35 | YouTube | Anotação manual | 99% / nítido |
(*) Com ficheiros txt, só é fornecida uma amostra dos dados.
Metodologia da anotação
O conjunto de dados é compilado com open source. As sequências compridas são divididas em fragmentos de áudio com deteção de atividade e alinhamento de voz. Alguns tipos de áudio são anotados automaticamente e verificados estatisticamente usando heurística.
Volumes de dados e frequência de atualização
O tamanho total do conjunto de dados é de 350 GB. O tamanho total do conjunto de dados com rótulos compartilhados publicamente é de 130 GB.
Não é provável que o conjunto de dados em si seja atualizado para compatibilidade com versões anteriores. Siga o repositório original para benchmarks e exclua arquivos.
Poderão ser adicionados domínios e idiomas novos no futuro.
Normalização de áudio
Todos os arquivos são normalizados para aumentos de tempo de execução mais fáceis e rápidos. O processamento é o seguinte:
- Conversão em mono, se necessário;
- Conversão para uma taxa de amostragem de 16 kHz, se necessário;
- Armazenamento como números inteiros de 16 bits;
- Conversão em OPUS;
Metodologia de DB em disco
Cada ficheiro de áudio (wav, binário) é transformado em hash. O hash é utilizado para criar uma hierarquia de pastas para um melhor funcionamento do 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)
Transferências
O conjunto de dados é fornecido de duas formas:
- Arquivos disponíveis por meio do armazenamento de blob do Azure e/ou links diretos;
- Arquivos originais disponíveis por meio do armazenamento de blob do Azure; Tudo é armazenado em 'https://azureopendatastorage.blob.core.windows.net/openstt/'
Estrutura da pasta:
└── 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
DATASET | GB, WAV | GB, ARQUIVO | ARQUIVO | ORIGEM | MANIFESTO |
---|---|---|---|---|---|
Treinar | |||||
Amostra de voz de rádio e pública | - | 11,4 | opus+txt | - | manifesto |
audiobook_2 | 162 | 25,8 | opus+txt | Internet + alinhamento | manifesto |
radio_2 | 154 | 24,6 | opus+txt | Botão de opção | manifesto |
public_youtube1120 | 237 | 19,0 | opus+txt | Vídeos do YouTube | manifesto |
asr_public_phone_calls_2 | 66 | 9.4 | opus+txt | Internet + ASR | manifesto |
public_youtube1120_hq | 31 | 4,9 | opus+txt | Vídeos do YouTube | manifesto |
asr_public_stories_2 | 9 | 1.4 | opus+txt | Internet + alinhamento | manifesto |
tts_russian_addresses_rhvoice_4voices | 80,9 | 12,9 | opus+txt | TTS | manifesto |
public_youtube700 | 75.0 | 12,2 | opus+txt | Vídeos do YouTube | manifesto |
asr_public_phone_calls_1 | 22.7 | 3.2 | opus+txt | Internet + ASR | manifesto |
asr_public_stories_1 | 4.1 | 0.7 | opus+txt | Histórias públicas | manifesto |
public_series_1 | 1.9 | 0.3 | opus+txt | Série pública | manifesto |
public_lecture_1 | 0.7 | 0.1 | opus+txt | Internet + manual | manifesto |
Val | |||||
asr_calls_2_val | 2 | 0.8 | wav+txt | Internet | manifesto |
buriy_audiobooks_2_val | 1 | 0.5 | wav+txt | Livros + manual | manifesto |
public_youtube700_val | 2 | 0,13 | wav+txt | Vídeos do YouTube + manual | manifesto |
Instruções de transferência
Download direto
Para obter instruções sobre como baixar o conjunto de dados diretamente, consulte a página de instruções de download do GitHub.
Informações adicionais
Para obter ajuda ou perguntas sobre os dados, entre em contato com o(s) autor(es) dos dados em aveysov@gmail.com
Esta licença permite que os usuários distribuam, remixem, adaptem e construam sobre o material em qualquer meio ou formato apenas para fins não comerciais, e apenas enquanto a atribuição for dada ao criador. Inclui os seguintes elementos:
- BY – O crédito deve ser dado ao criador
- NC – Apenas são permitidas utilizações não comerciais da obra
Utilização comercial e ao abrigo da licença CC-BY-NC disponível após acordo estabelecido com os autores do conjunto de dados.
Acesso a dados
Azure Notebooks
Funções auxiliares / dependências
Construindo libsndfile
Uma maneira eficiente de ler arquivos opus em Python que não incorre em sobrecarga significativa é usar pysoundfile (um wrapper CFFI Python em torno de libsoundfile).
O suporte ao Opus foi implementado a montante, mas não foi lançado corretamente. Portanto, optamos por build personalizado + monkey patching.
Normalmente, você precisa executar isso em seu shell com acesso 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 .
Funções auxiliares / dependências
Instale as bibliotecas a seguir:
pandas
numpy
scipy
tqdm
soundfile
librosa
Manifestos são arquivos csv com as seguintes colunas:
- Caminho para o áudio
- Caminho para o arquivo de texto
- Duração
Eles provaram ser o formato mais simples de acesso aos dados.
Para facilitar o uso, todos os manifestos já estão reenraizados. Todos os caminhos neles são relativos, você precisa fornecer uma pasta raiz.
# 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()
Jogar com um conjunto de dados
Reproduzir uma amostra de ficheiros
A maioria dos navegadores de plataformas suporta reprodução de áudio nativa. Assim, podemos usar players de áudio HTML5 para visualizar nossos dados.
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)
Ler um ficheiro
!ls ru_open_stt_opus/manifests/*.csv
Alguns exemplos mostrando como ler melhor arquivos wav e opus.
Scipy é o mais rápido para wav. Pysoundfile é o melhor geral para opus.
%matplotlib inline
import librosa
from scipy.io import wavfile
from librosa import display as ldisplay
from matplotlib import pyplot as plt
Ler um 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)
Ler 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)
Próximos passos
Exiba o restante dos conjuntos de dados no catálogo Open Datasets.