Riconoscimento vocale aperto in russo
Raccolta di campioni di parlato derivati da diverse origini audio. Il set di dati contiene brevi clip audio in russo.
Nota
Microsoft fornisce i set di dati aperti di Azure così come sono e non fornisce né garanzie, esplicite o implicite, né specifica alcuna condizione in relazione all'uso dei set di dati. Nella misura consentita dalla legge locale, Microsoft declina tutte le responsabilità per eventuali danni o perdite, incluse dirette, consequenziali, speciali, indirette, accidentali o irreversibili, risultanti dall'uso dei set di dati.
Questo set di dati viene fornito in conformità con le condizioni originali in base alle quali Microsoft ha ricevuto i dati di origine. Il set di dati potrebbe includere dati provenienti da Microsoft.
Questo set di dati del riconoscimento vocale aperto (STT) in russo include:
- ~16 milioni di espressioni
- ~20.000 ore
- 2,3 TB (non compresso in formato .wav in int16), 356G in opus
- Tutti i file sono stati trasformati in opus, ad eccezione dei set di dati di convalida
Lo scopo principale del set di dati consiste nell'eseguire il training dei modelli di riconoscimento vocale.
Composizione del set di dati
Le dimensioni del set di dati sono indicate per i file .wav.
DATASET | ESPRESSIONI | ORE | GB | SECS/CHARS | COMMENT | ANNOTAZIONE | QUALITÀ/RUMORE |
---|---|---|---|---|---|---|---|
radio_v4 (*) | 7.603.192 | 10.430 | 1.195 | 5s/68 | Pulsante di opzione | Align | 95%/nitido |
public_speech (*) | 1.700.060 | 2.709 | 301 | 6s/79 | Discorso pubblico | Align | 95%/nitido |
audiobook_2 | 1.149.404 | 1.511 | 162 | 5s/56 | Libri | Align | 95%/nitido |
radio_2 | 651.645 | 1.439 | 154 | 8s/110 | Pulsante di opzione | Align | 95%/nitido |
public_youtube1120 | 1.410.979 | 1.104 | 237 | 3s/34 | YouTube | Sottotitoli | 95%/abbastanza nitido |
public_youtube700 | 759.483 | 701 | 75 | 3s/43 | YouTube | Sottotitoli | 95%/abbastanza nitido |
tts_russian_addresses | 1.741.838 | 754 | 81 | 2s/20 | Indirizzi | Sintesi vocale a 4 voci | 100%/nitido |
asr_public_phone_calls_2 | 603.797 | 601 | 66 | 4s/37 | Telefonate | ASR | 70%/disturbato |
public_youtube1120_hq | 369.245 | 291 | 31 | 3s/37 | YouTube HQ | Sottotitoli | 95%/abbastanza nitido |
asr_public_phone_calls_1 | 233.868 | 211 | 23 | 3s/29 | Telefonate | ASR | 70%/disturbato |
radio_v4_add (*) | 92.679 | 157 | 18 | 6s/80 | Pulsante di opzione | Align | 95%/nitido |
asr_public_stories_2 | 78.186 | 78 | 9 | 4s/43 | Libri | ASR | 80%/nitido |
asr_public_stories_1 | 46.142 | 38 | 4 | 3s/30 | Libri | ASR | 80%/nitido |
public_series_1 | 20.243 | 17 | 2 | 3s/38 | YouTube | Sottotitoli | 95%/abbastanza nitido |
asr_calls_2_val | 12.950 | 7,7 | 2 | 2s/34 | Telefonate | Annotazione manuale | 99%/nitido |
public_lecture_1 | 6.803 | 6 | 1 | 3s/47 | Lezioni | Sottotitoli | 95%/nitido |
buriy_audiobooks_2_val | 7.850 | 4,9 | 1 | 2s/31 | Libri | Annotazione manuale | 99%/nitido |
public_youtube700_val | 7.311 | 4,5 | 1 | 2s/35 | YouTube | Annotazione manuale | 99%/nitido |
(*) Con i file TXT viene fornito solo un campione dei dati.
Metodologia di annotazione
Il set di dati viene compilato con dati open source. Le sequenze lunghe vengono suddivise in blocchi di audio usando il rilevamento attività vocale e l'allineamento. Alcuni tipi di audio sono annotati automaticamente e verificati statisticamente utilizzando l'euristica.
Volumi di dati e frequenza di aggiornamento
Le dimensioni totali del set di dati sono 350 GB. La dimensione totale del set di dati con etichette condivise pubblicamente è di 130 GB.
È improbabile che il set di dati venga aggiornato per garantire la compatibilità con le versioni precedenti. Seguire il repository originale per i benchmark ed escludere i file.
È possibile che nuove lingue e nuovi domini vengano aggiunti in futuro.
Normalizzazione dell'audio
Tutti i file vengono normalizzati per ottenere incrementi di runtime più semplici e veloci. L'elaborazione è la seguente:
- Conversione in mono, se necessario.
- Convertito in frequenza di campionamento a 16 kHz, se necessario;
- Archiviazione come integer a 16 bit.
- Conversione in OPUS.
Metodologia di database su disco
Ogni file audio (WAV, binario) include hash. L'hash viene usato per creare una gerarchia di cartelle per un'operazione fs più ottimale.
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)
Download
Il set di dati viene fornito in due forme:
- Archivi disponibili tramite l'archiviazione BLOB di Azure e/o collegamenti diretti;
- File originali disponibili tramite l'archiviazione BLOB di Azure; Tutto viene archiviato in 'https://azureopendatastorage.blob.core.windows.net/openstt/'
Struttura di cartelle:
└── 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, ARCHIVIO | ARCHIVE | ORIGINE | MANIFESTO |
---|---|---|---|---|---|
Esecuzione del training | |||||
Campione di audio radio e di discorso pubblico | - | 11,4 | opus+txt | - | manifest |
audiobook_2 | 162 | 25,8 | opus+txt | Internet e allineamento | manifest |
radio_2 | 154 | 24,6 | opus+txt | Pulsante di opzione | manifest |
public_youtube1120 | 237 | 19,0 | opus+txt | Video YouTube | manifest |
asr_public_phone_calls_2 | 66 | 9.4 | opus+txt | Internet e ASR | manifest |
public_youtube1120_hq | 31 | 4.9 | opus+txt | Video YouTube | manifest |
asr_public_stories_2 | 9 | 1.4 | opus+txt | Internet e allineamento | manifest |
tts_russian_addresses_rhvoice_4voices | 80,9 | 12,9 | opus+txt | Sintesi vocale | manifest |
public_youtube700 | 75.0 | 12,2 | opus+txt | Video YouTube | manifest |
asr_public_phone_calls_1 | 22,7 | 3.2 | opus+txt | Internet e ASR | manifest |
asr_public_stories_1 | 4.1 | 0,7 | opus+txt | Storie pubbliche | manifest |
public_series_1 | 1,9 | 0,3 | opus+txt | Serie pubbliche | manifest |
public_lecture_1 | 0,7 | 0,1 | opus+txt | Internet e manuale | manifest |
Val | |||||
asr_calls_2_val | 2 | 0,8 | wav+txt | Internet | manifest |
buriy_audiobooks_2_val | 1 | 0.5 | wav+txt | Libri e manuale | manifest |
public_youtube700_val | 2 | 0,13 | wav+txt | Video di YouTube e manuale | manifest |
Istruzioni per il download
Download diretto
Per istruzioni su come scaricare direttamente il set di dati, vedere la pagina delle istruzioni di download di GitHub.
Informazioni aggiuntive
Per informazioni o domande sui dati contattare gli autori di dati al aveysov@gmail.com
Questa licenza consente agli utenti di distribuire, remixare, adattare e costruire sul materiale in qualsiasi mezzo o formato solo per scopi non commerciali e solo a condizione che sia data attribuzione al creatore. Include gli elementi seguenti:
- BY - Il credito deve essere dato al creatore
- NC - Sono consentiti solo usi non commerciali dell'opera
CC-BY-NC e utilizzo commerciale disponibili solo a seguito di accordo con gli autori del set di dati.
Accesso ai dati
Azure Notebooks
Funzioni helper/dipendenze
Compilazione di libsndfile
Un modo efficiente per leggere i file opus in Python che non comporta un sovraccarico significativo consiste nell'usare pysoundfile (un wrapper CFFI Python intorno a libsoundfile).
Il supporto per Opus è stato implementato a monte, ma non è stato rilasciato correttamente. Pertanto, abbiamo optato per una costruzione personalizzata + patch monkey.
In genere, è necessario eseguirlo nella shell con accesso 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 .
Funzioni helper/dipendenze
Installare le librerie seguenti:
pandas
numpy
scipy
tqdm
soundfile
librosa
I manifesti sono file CSV con le colonne seguenti:
- Percorso audio
- Percorso del file di testo
- Durata
Si sono rivelati il formato più semplice per accedere ai dati.
Per facilitare l'uso, tutti i manifesti sono già radicati. Tutti i percorsi in essi contenuti sono relativi, è necessario fornire una cartella radice.
# 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()
Riprodurre con un set di dati
Riprodurre un esempio di file
La maggior parte delle piattaforme browser supporta la riproduzione audio nativa. Quindi è possibile utilizzare i lettori audio HTML5 per visualizzare i dati.
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)
Leggere un file
!ls ru_open_stt_opus/manifests/*.csv
Alcuni esempi che illustrano come leggere meglio i file wav e opus.
Scipy è il più veloce per wav. Pysoundfile è il migliore per opus.
%matplotlib inline
import librosa
from scipy.io import wavfile
from librosa import display as ldisplay
from matplotlib import pyplot as plt
Leggere un 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)
Leggere 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)
Passaggi successivi
Visualizzare il resto dei set di dati nel catalogo dei set di dati aperti.