Rosyjska otwarta mowa do tekstu

Kolekcja próbek mowy z różnych źródeł dźwięku. Ten zestaw danych zawiera krótkie klipy audio w języku rosyjskim.

Uwaga

Firma Microsoft udostępnia zestawy danych Platformy Azure open na zasadzie "tak, jak to jest". Firma Microsoft nie udziela żadnych gwarancji, wyraźnych lub domniemanych, gwarancji ani warunków w odniesieniu do korzystania z zestawów danych. W zakresie dozwolonym zgodnie z prawem lokalnym firma Microsoft nie ponosi odpowiedzialności za wszelkie szkody lub straty, w tym bezpośrednie, wtórne, specjalne, pośrednie, przypadkowe lub karne wynikające z korzystania z zestawów danych.

Zestaw danych jest udostępniany zgodnie z pierwotnymi warunkami, na jakich firma Microsoft otrzymała dane źródłowe. Zestaw danych może zawierać dane pozyskane z firmy Microsoft.

Ten rosyjski zestaw danych zamiany mowy na tekst (STT) obejmuje:

  • Ok. 16 milionów wypowiedzi
  • ~20 000 godzin
  • 2,3 TB (nieskompresowane w formacie .wav w int16), 356G w opus
  • Wszystkie pliki zostały przekształcone w wartość opus, z wyjątkiem zestawów danych weryfikacji

Głównym przeznaczeniem zestawu danych jest trenowanie modeli przekształcających mowę na tekst.

Budowa zestawu danych

Rozmiar zestawu danych jest podawany dla plików wav.

ZESTAW DANYCH WYPOWIEDZI GODZIN GB SECS/CHARS KOMENTARZ ADNOTACJI JAKOŚĆ/SZUM
radio_v4 (*) 7 603 192 10 430 1195 5 s / 68 Przycisk radiowy Align 95% / wyraźne
public_speech (*) 1 700 060 2 709 301 6 s / 79 Przemówienia publiczne Align 95% / wyraźne
audiobook_2 1 149 404 1511 162 5 s / 56 Księgi Align 95% / wyraźne
radio_2 651 645 1 439 154 8 s / 110 Przycisk radiowy Align 95% / wyraźne
public_youtube1120 1 410 979 1104 237 3 s / 34 YouTube Podtytuły 95% / ~wyraźne
public_youtube700 759 483 701 75 3 s / 43 YouTube Podtytuły 95% / ~wyraźne
tts_russian_addresses 1 741 838 754 81 2 s / 20 Adresy Głosy TTS 4 100% / wyraźne
asr_public_phone_calls_2 603 797 601 66 4 s / 37 Rozmowy telefoniczne ASR 70% / zaszumione
public_youtube1120_hq 369 245 291 31 3 s / 37 YouTube HQ Podtytuły 95% / ~wyraźne
asr_public_phone_calls_1 233 868 / 2000 211 23 3 s / 29 Rozmowy telefoniczne ASR 70% / zaszumione
radio_v4_add (*) 92 679 157 18 6 s / 80 Przycisk radiowy Align 95% / wyraźne
asr_public_stories_2 78 186 78 9 4 s / 43 Księgi ASR 80% / wyraźne
asr_public_stories_1 46 142 38 100 3 s / 30 Księgi ASR 80% / wyraźne
public_series_1 20 243 17 2 3 s / 38 YouTube Podtytuły 95% / ~wyraźne
asr_calls_2_val 12 950 7,7 2 2 s / 34 Rozmowy telefoniczne Ręczne adnotacje 99% / wyraźne
public_lecture_1 6 803 6 1 3 s / 47 Wykłady Podtytuły 95% / wyraźne
buriy_audiobooks_2_val 7850 4,9 1 2 s / 31 Księgi Ręczne adnotacje 99% / wyraźne
public_youtube700_val 7311 4,5 1 2 s / 35 YouTube Ręczne adnotacje 99% / wyraźne

(*) Za pomocą plików txt udostępniana jest tylko próbka danych.

Metodologia adnotacji

Zestaw danych został przygotowany za pomocą otwartych źródeł. Długie zdania są dzielone na fragmenty audio za pomocą funkcji wykrywania aktywności głosowej i wyrównywania. Niektóre typy audio są automatycznie oznaczone adnotacjami i weryfikowane statystycznie przy użyciu heurystyki.

Woluminy danych i częstotliwość aktualizacji

Całkowity rozmiar zestawu danych to 350 GB. Łączny rozmiar zestawu danych z etykietami udostępnionymi publicznie wynosi 130 GB.

Sam zestaw danych prawdopodobnie nie zostanie zaktualizowany pod kątem zgodności z poprzednimi wersjami. Postępuj zgodnie z oryginalnym repozytorium testów porównawczych i wyklucz pliki.

W przyszłości mogą zostać dodane nowe domeny i języki.

Normalizacja audio

Wszystkie pliki są znormalizowane w celu łatwiejszego i szybszego rozszerzania środowiska uruchomieniowego. Przetwarzanie jest następujące:

  • Przekonwertowane do formatu mono, jeśli to konieczne
  • W razie potrzeby przekonwertowana na częstotliwość próbkowania 16 kHz;
  • Zapisane jako 16-bitowe wartości całkowite
  • Przekonwertowane do formatu OPUS

Metodologia bazy danych na dysku

Każdy plik audio (wav, binarny) ma skrót. Skrót służy do tworzenia hierarchii folderów w celu uzyskania bardziej optymalnej operacji 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)

Pobieranie

Zestaw danych jest udostępniany w dwóch formularzach:

  • Archiwa dostępne za pośrednictwem usługi Azure Blob Storage i/lub linków bezpośrednich;
  • Oryginalne pliki dostępne za pośrednictwem usługi Azure Blob Storage; Wszystko jest przechowywane w 'https://azureopendatastorage.blob.core.windows.net/openstt/'

Struktura folderów:

└── 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
ZESTAW DANYCH GB, WAV GB, ARCHIWUM ARCHIWUM ŹRÓDŁO MANIFEST
Szkolenie
Przykłady z radia i przemówień publicznych - 11,4 opus i txt - manifest
audiobook_2 162 25,8 opus i txt Internet i wyrównanie manifest
radio_2 154 24,6 opus i txt Przycisk radiowy manifest
public_youtube1120 237 19,0 opus i txt Filmy z serwisu YouTube manifest
asr_public_phone_calls_2 66 9,4 opus i txt Internet i ASR manifest
public_youtube1120_hq 31 4.9 opus i txt Filmy z serwisu YouTube manifest
asr_public_stories_2 9 1.4 opus i txt Internet i wyrównanie manifest
tts_russian_addresses_rhvoice_4voices 80,9 12,9 opus i txt TTS manifest
public_youtube700 75,0 12,2 opus i txt Filmy z serwisu YouTube manifest
asr_public_phone_calls_1 22,7 3.2 opus i txt Internet i ASR manifest
asr_public_stories_1 4.1 0,7 opus i txt Historie publiczne manifest
public_series_1 1,9 0.3 opus i txt Serie publiczne manifest
public_lecture_1 0,7 0.1 opus i txt Internet i ręcznie manifest
Val
asr_calls_2_val 2 0,8 wav i txt Internet manifest
buriy_audiobooks_2_val 1 0.5 wav i txt Książki i ręcznie manifest
public_youtube700_val 2 0,13 wav i txt Wideo z usługi YouTube i ręcznie manifest

Instrukcje pobierania

Pobieranie bezpośrednie

Aby uzyskać instrukcje dotyczące bezpośredniego pobierania zestawu danych, zobacz stronę instrukcji pobierania w usłudze GitHub.

Dodatkowe informacje

Aby uzyskać pomoc lub pytania dotyczące danych, skontaktuj się z autorami danych pod adresem aveysov@gmail.com

Licencja ta pozwala użytkownikom rozpowszechniać, remix, dostosowywać i opierać się na materiale w dowolnym nośniku lub formacie tylko w celach niekomercyjnych i tylko tak długo, jak przypisanie jest podane twórcy. Obejmuje następujące elementy:

  • BY — kredyt musi zostać przyznany twórcy
  • NC — dozwolone są tylko niekomercyjne zastosowania pracy

Licencja CC-BY-NC i użytek komercyjny jest możliwy po zawarciu umowy z autorami zestawu danych.

Dostęp do danych

Azure Notebooks

Funkcje/zależności pomocnika

Kompilowanie pliku libsndfile

Wydajnym sposobem odczytywania plików opus w języku Python, który nie wiąże się ze znaczącym obciążeniem, jest użycie pliku pysoundfile (otoki CFFI języka Python wokół libsoundfile).

Obsługa Firmy Opus została wdrożona w górę, ale nie została prawidłowo wydana. W związku z tym wybraliśmy niestandardową kompilację i stosowanie poprawek małp.

Zazwyczaj należy to uruchomić w powłoce przy użyciu dostępu 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 .

Funkcje/zależności pomocnika

Zainstaluj następujące biblioteki:

pandas
numpy
scipy
tqdm
soundfile
librosa

Manifesty to pliki CSV z następującymi kolumnami:

  • Ścieżka do dźwięku
  • Ścieżka do pliku tekstowego
  • Czas trwania

Okazało się, że jest to najprostszy format uzyskiwania dostępu do danych.

Aby ułatwić korzystanie, wszystkie manifesty są już ponownie wyrootowane. Wszystkie ścieżki w nich są względne. Musisz podać folder główny.

# 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()

Odtwarzanie za pomocą zestawu danych

Odtwarzanie próbki plików

Większość przeglądarek platform obsługuje natywne odtwarzanie dźwięku. Aby wyświetlić nasze dane, możemy użyć odtwarzaczy audio 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)

Odczytywanie pliku

!ls ru_open_stt_opus/manifests/*.csv

Niektóre przykłady pokazujące, jak najlepiej odczytywać pliki wav i opus.

Scipy jest najszybszy dla fal. Pysoundfile jest najlepszym w klasyfikacji generalnej dla opus.

%matplotlib inline

import librosa
from scipy.io import wavfile
from librosa import display as ldisplay
from matplotlib import pyplot as plt

Odczytywanie fali

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)

Odczytywanie parametru 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)

Następne kroki

Wyświetl pozostałe zestawy danych w katalogu Open Datasets (Otwieranie zestawów danych).