Share via


Russian Open Speech To Text

Eine Sammlung von Sprachbeispielen, die aus verschiedenen Sprachquellen stammen. Das Dataset enthält kurze Audiodateien auf Russisch.

Hinweis

Microsoft stellt Datasets der Plattform Azure Open Datasets auf einer „As is“-Basis (d. h. ohne Mängelgewähr) zur Verfügung. Microsoft übernimmt weder ausdrücklich noch stillschweigend die Gewährleistung für Ihre Nutzung der Datasets und sichert keinerlei Garantien oder Bedingungen zu. Soweit nach örtlich anwendbarem Recht zulässig, lehnt Microsoft jegliche Haftung für Schäden oder Verluste ab. Dies schließt direkte, indirekte, besondere oder zufällige Schäden oder Verluste sowie Folge- und Strafschäden und damit verbundene Verluste ein, die sich aus Ihrer Nutzung der Datasets ergeben.

Für die Bereitstellung dieses Datasets gelten die ursprünglichen Nutzungsbedingungen, unter denen Microsoft die Quelldaten bezogen hat. Das Dataset kann Daten von Microsoft enthalten.

Dieses STT-Dataset (Spracherkennung) für Russisch umfasst Folgendes:

  • ~16 Millionen Äußerungen
  • ~20.000 Stunden
  • 2,3 TB (unkomprimiert im WAV-Format in int16), 356G in OPUS
  • Alle Dateien (außer Datasets zur Validierung) wurden ins OPUS-Format konvertiert

Das Dataset dient hauptsächlich dem Trainieren von Spracherkennungsmodellen.

Zusammensetzung des Datasets

Die Datasetgröße wird für WAV-Dateien angegeben.

DATASET ÄUSSERUNGEN STUNDEN GB SEKUNDEN/ZEICHEN COMMENT ANMERKUNG QUALITÄT/RAUSCHEN
radio_v4 (*) 7\.603.192 10.430 1\.195 5 Sek./68 Radio Ausrichten 95 %/klar
public_speech (*) 1\.700.060 2\.709 301 6 Sek/79 Öffentlicher Vortrag Ausrichten 95 %/klar
audiobook_2 1\.149.404 1\.511 162 5 Sek./56 Bücher Ausrichten 95 %/klar
radio_2 651.645 1\.439 154 8 Sek./110 Radio Ausrichten 95 %/klar
public_youtube1120 1\.410.979 1.104 237 3 Sek./34 Youtube Untertitel 95 %/~klar
public_youtube700 759.483 701 75 3 Sek./43 Youtube Untertitel 95 %/überwiegend klar
tts_russian_addresses 1\.741.838 754 81 2 Sek./20 Adressen TTS, 4 Stimmen 100 %/klar
asr_public_phone_calls_2 603.797 601 66 4 Sek./37 Telefonanrufe ASR 70 %/rauschend
public_youtube1120_hq 369.245 291 31 3 Sek./37 YouTube (hohe Qualität) Untertitel 95 %/überwiegend klar
asr_public_phone_calls_1 233.868 211 23 3 Sek./29 Telefonanrufe ASR 70 %/rauschend
radio_v4_add (*) 92.679 157 18 6 Sek/80 Radio Ausrichten 95 %/klar
asr_public_stories_2 78.186 78 9 4 Sek./43 Bücher ASR 80 %/klar
asr_public_stories_1 46.142 38 4 3 Sek./30 Bücher ASR 80 %/klar
public_series_1 20.243 17 2 3 Sek./38 Youtube Untertitel 95 %/überwiegend klar
asr_calls_2_val 12.950 7,7 2 2 Sek./34 Telefonanrufe Manuelle Annotation 99 %/klar
public_lecture_1 6\.803 6 1 3 Sek./47 Vorlesungen Untertitel 95 %/klar
buriy_audiobooks_2_val 7\.850 4,9 1 2 Sek./31 Bücher Manuelle Annotation 99 %/klar
public_youtube700_val 7\.311 4,5 1 2 Sek./35 Youtube Manuelle Annotation 99 %/klar

(*) Nur eine Stichprobe der Daten wird in den TXT-Dateien bereitgestellt.

Annotationsmethodik

Das Dataset wurde aus öffentlichen Quellen zusammengestellt. Lange Sequenzen werden mithilfe von Sprechaktivitätserkennung und -angleichung in kleine Audiodateien aufgeteilt. Einige Audioformate werden automatisch annotiert und statistisch mithilfe der Heuristik verifiziert.

Datenvolumes und Aktualisierungshäufigkeit

Die Gesamtgröße des Datasets beträgt 350 GB. Die Gesamtgröße des Datasets mit öffentlich freigegebenen Bezeichnungen beträgt 130 GB.

Es ist unwahrscheinlich, dass das Dataset in Zukunft hinsichtlich der Abwärtskompatibilität aktualisiert wird. Nutzen Sie das Originalrepository für Benchmarks und zum Ausschließen von Dateien.

Neue Fachbereiche und Sprachen werden in Zukunft ggf. hinzugefügt.

Audionormalisierung

Alle Dateien sind für einfachere und schnellere Anstiege der Runtime normalisiert. Die Verarbeitung erfolgt wie folgt:

  • Bei Bedarf wurden sie in Mono konvertiert.
  • Bei Bedarf wurden sie in eine Samplingrate von 16 kHz konvertiert.
  • Sie wurden als 16-Bit-Integer gespeichert.
  • Sie wurden ins OPUS-Format konvertiert.

Datenbankmethodik auf dem Datenträger

Jede Audiodatei (WAV-Dateien, Binärdateien) wurde gehasht. Der Hash wird verwendet, um eine Ordnerhierarchie für einen verbesserten Betrieb des Dateisystems zu erstellen.

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)

Downloads

Das Dataset wird in zwei Formaten bereitgestellt:

  • Archive, die über Azure Blob Storage und/oder direkte Links verfügbar sind
  • Originaldateien, die über Azure Blob Storage verfügbar sind. Alles wird in https://azureopendatastorage.blob.core.windows.net/openstt/ gespeichert.

Ordnerstruktur:

└── 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, ARCHIV ARCHIVIEREN QUELLE MANIFEST
Trainieren
Stichprobe für Radio und öffentliche Vorträge - 11.4 OPUS- und TXT-Format - manifest
audiobook_2 162 25,8 OPUS- und TXT-Format Internet und Angleichung manifest
radio_2 154 24,6 OPUS- und TXT-Format Radio manifest
public_youtube1120 237 19,0 OPUS- und TXT-Format YouTube-Videos manifest
asr_public_phone_calls_2 66 9.4 OPUS- und TXT-Format Internet und ASR manifest
public_youtube1120_hq 31 4,9 OPUS- und TXT-Format YouTube-Videos manifest
asr_public_stories_2 9 1.4 OPUS- und TXT-Format Internet und Angleichung manifest
tts_russian_addresses_rhvoice_4voices 80.9 12,9 OPUS- und TXT-Format TTS manifest
public_youtube700 75.0 12,2 OPUS- und TXT-Format YouTube-Videos manifest
asr_public_phone_calls_1 22.7 3.2 OPUS- und TXT-Format Internet und ASR manifest
asr_public_stories_1 4,1 0.7 OPUS- und TXT-Format Öffentliche Storys manifest
public_series_1 1.9 0,3 OPUS- und TXT-Format Öffentliche Reihen manifest
public_lecture_1 0.7 0.1 OPUS- und TXT-Format Internet und manuell manifest
Val
asr_calls_2_val 2 0.8 WAV- und TXT-Format Internet manifest
buriy_audiobooks_2_val 1 0,5 WAV- und TXT-Format Bücher und manuell manifest
public_youtube700_val 2 0,13 WAV- und TXT-Format YouTube-Videos und manuell manifest

Downloadanweisungen

Direkter Download

Anweisungen zum direkten Herunterladen des Datasets finden Sie auf der GitHub-Seite mit Anweisungen zum Herunterladen.

Zusätzliche Informationen

Wenn Sie Hilfe oder Fragen zu den Daten haben, wenden Sie sich unter aveysov@gmail.com an die Verfasser der Daten.

Diese Lizenz gewährt es Benutzern, diese Materialien für nicht kommerzielle Zwecke über ein beliebiges Medium und in beliebigem Format zu verbreiten, zu mischen, anzuwenden oder weiterzuentwickeln, sofern eine Zuschreibung an den Ersteller verfasst wird. Sie besteht aus folgenden Elementen:

  • BY: Der Ersteller muss erwähnt werden.
  • NC: Nur die nicht kommerzielle Verwendung der Arbeit ist zulässig.

Die CC-BY-NC-Nutzung und die kommerzielle Nutzung sind nur mit Genehmigung des Datasetautors zulässig.

Datenzugriff

Azure Notebooks

Hilfsfunktionen/Abhängigkeiten

Erstellen von libsndfile

Eine effiziente Möglichkeit zum Lesen von OPUS-Dateien in Python, die keinen erheblichen Mehraufwand verursachen, ist die Verwendung von pysoundfile (ein Python CFFI-Wrapper um libsoundfile).

Die OPUS-Unterstützung wurde upstream implementiert, wurde aber nicht ordnungsgemäß freigegeben. Deshalb haben wir uns für das Erstellen von benutzerdefinierten Builds und Affen-Patches entschieden.

Normalerweise müssen Sie dies in Ihrer Shell mit sudo-Zugriff ausführen:

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 .

Hilfsfunktionen/Abhängigkeiten

Installieren Sie die folgenden Bibliotheken:

pandas
numpy
scipy
tqdm
soundfile
librosa

Manifeste sind CSV-Dateien mit den folgenden Spalten:

  • Pfad zu Audio
  • Pfad zur Textdatei
  • Duration

Sie erwiesen sich als das einfachste Format für den Zugriff auf Daten.

Zur einfacheren Verwendung wurde allen Manifesten bereits ein neuer Stamm zugeordnet. Alle darin enthaltenen Pfade sind relativ. Sie müssen einen Stammordner bereitstellen.

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

Wiedergabe mit einem Dataset

Wiedergabe eines Beispiels von Dateien

Die Browser der meisten Plattformen unterstützen die native Audiowiedergabe. Wir können also HTML5-Audioplayer verwenden, um unsere Daten anzuzeigen.

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)

Lesen einer Datei

!ls ru_open_stt_opus/manifests/*.csv

Einige Beispiele, die veranschaulichen, wie WAV- und OPUS-Dateien am besten gelesen werden.

Scipy ist die schnellste Option für WAV-Dateien. Pysoundfile ist insgesamt am besten für OPUS-Dateien geeignet.

%matplotlib inline

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

Lesen einer WAV-Datei

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)

Lesen einer OPUS-Datei

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)

Nächste Schritte

Machen Sie sich mit den restlichen Datasets im Open Datasets-Katalog vertraut.