Rosyjski otwarty tekst mowy na tekst

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 Azure Open Datasets na zasadzie "jak jest". Firma Microsoft nie udziela żadnych gwarancji, jawnych ani dorozumianych, ani nie udziela żadnych warunków w odniesieniu do korzystania z zestawów danych. W zakresie dozwolonym przez prawo lokalne Microsoft zrzeka się wszelkiej odpowiedzialności za wszelkie szkody lub straty, w tym szkody bezpośrednie, wynikowe, specjalne, pośrednie, pośrednie, przypadkowe lub karalne wynikające z używania 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 zestaw danych z tekstem w języku rosyjskim obejmuje:

  • Około 16 milionów wypowiedzi
  • Około 20 000 godzin
  • 2,3 TB (nieskompresowane w formacie WAV w int16), 356G w opus
  • Wszystkie pliki zostały przekształcone w 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 podany dla plików wav.

Dataset Wypowiedzi Godzin GB SECS/CHARS COMMENT Adnotacji JAKOŚĆ/SZUM
radio_v4 (*) 7 603 192 10 430 1,195 5 s / 68 Przycisk opcji Wyrównaj 95% / schłod
public_speech (*) 1 700 060 2 709 301 6 s / 79 Przemówienia publiczne Wyrównaj 95% / schłod
audiobook_2 1 149 404 1,511 162 5 s / 56 Książki Wyrównaj 95% / schłod
radio_2 651 645 1 439 154 8 s / 110 Przycisk opcji Wyrównaj 95% / schłod
public_youtube1120 1 410 979 1,104 237 3 s / 34 YouTube Napisy 95% / ~wylicz
public_youtube700 759 483 701 75 3 s / 43 YouTube Napisy 95% / ~wylicz
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% / zaszumij
public_youtube1120_hq 369 245 291 31 3 s / 37 YouTube HQ Napisy 95% / ~wylicz
asr_public_phone_calls_1 233 868 / 2000 211 23 3 s / 29 Rozmowy telefoniczne ASR 70% / zaszumij
radio_v4_add (*) 92 679 157 18 6 s / 80 Przycisk opcji Wyrównaj 95% / cygie
asr_public_stories_2 78 186 78 9 4 s / 43 Książki ASR 80% / usd
asr_public_stories_1 46 142 38 4 3 s / 30 Książki ASR 80% / usd
public_series_1 20 243 17 2 3 s / 38 YouTube Napisy 95% / ~cygie
asr_calls_2_val 12 950 7,7 2 2 s / 34 Rozmowy telefoniczne Ręczne adnotacje 99% / cygałę
public_lecture_1 6 803 6 1 3 s / 47 Wykłady Napisy 95% / cygie
buriy_audiobooks_2_val 7,850 4,9 1 2 s / 31 Książki Ręczne adnotacje 99% / cygałę
public_youtube700_val 7,311 4,5 1 2 s / 35 YouTube Ręczne adnotacje 99% / cygałę

(*) 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 oznaczane adnotacjami i weryfikowane statystycznie przy użyciu heurystycznych.

Woluminy danych i częstotliwość aktualizacji

Łączny rozmiar zestawu danych wynosi 350 GB. Łączny rozmiar zestawu danych z publicznie udostępnioną etykietą wynosi 130 GB.

Sam zestaw danych prawdopodobnie nie zostanie zaktualizowany w celu zapewnienia zgodności z poprzednimi wersjami. Postępuj zgodnie z oryginalnym repozytorium, aby uzyskać wyniki testów porównawczych i wykluczyć pliki.

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

Normalizacja audio

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

  • Przekonwertowane do formatu mono, jeśli to konieczne
  • Przekonwertowane na częstotliwość próbkowania 16 kHz, jeśli to konieczne;
  • 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 dla bardziej optymalne fs operacji.

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 dostarczany w dwóch formach:

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
Dataset GB, WAV GB, ARCHIWUM Archiwum ŹRÓDŁO Manifestu
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 opcji manifest
public_youtube1120 237 19,0 opus i txt Wideo z usługi 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 Wideo z usługi 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 Wideo z usługi 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

Bezpośrednie pobieranie

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

Dodatkowe informacje

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

Ta licencja pozwala użytkownikom rozpowszechniać, remiksować, dostosowywać i tworzyć na podstawie tego materiału w dowolnym nośniku lub formacie wyłącznie do celów niekomercyjnych i tylko tak długo, jak przypisanie autorstwa zostanie nadane twórcy. Obejmuje następujące elementy:

  • BY — twórca musi mieć dostęp do środków
  • NC — dozwolone jest tylko niekomercyjne użycie 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 pomocnika/zależności

Tworzenie 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 py wymiennego (otoki CFFI języka Python wokół pliku lib wyliczenie).

Obsługa procesów opus została zaimplementowana w ramach transmisji nadrzędnej, ale nie została prawidłowo wydana. W związku z tym wybraliśmy niestandardowe kompilowanie i stosowanie poprawek do systemu patch.

Zazwyczaj należy uruchomić to w swojej powłoki z dostępem do programu 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 pomocnika/zależności

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.

W celu ułatwienia obsługi wszystkie manifesty zostały już ponownie przerootowane. 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 z zestawem danych

Odtwarzanie przykładowych plików

Większość przeglądarek platformy obsługuje natywne odtwarzanie dźwięku. Dlatego możemy wyświetlać dane przy użyciu 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

Kilka przykładów pokazujących, jak najlepiej odczytywać pliki wav i opus.

Scipy jest najszybszym w przypadku wav. Plik Py w 2016 r. jest najlepszym rozwiązaniem dla operacyjności.

%matplotlib inline

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

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

Odczyt 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 wykazie Open Datasets danych.