Ryska öppna tal till text

En samling talprov från olika ljudkällor. Datamängden innehåller korta ljudklipp på ryska.

Anteckning

Microsoft tillhandahåller Azure Open Datasets på "i så fall"-basis. Microsoft ger inga garantier, uttryckliga eller underförstådda, avseende din användning av datamängderna. I den utsträckning som tillåts enligt lokal lagstiftning frånsäger sig Microsoft allt ansvar för eventuella skador eller förluster, inklusive direkta skador, följdskador, särskilda, indirekta, oförutsedda eller oförutsedda skador som uppstår vid användning av datamängderna.

Datamängden tillhandahålls enligt de ursprungliga villkor som gällde när Microsoft tog emot källdatan. Datamängden kan innehålla data från Microsoft.

Den här datamängden för ryska tal till text (STT) innehåller:

  • ~16 miljoner yttranden
  • ~20 000 timmar
  • 2,3 TB (okomprimerat i .wav-format i int16), 356G i mör
  • Alla filer omvandlades till dockor, förutom valideringsdatamängder

Huvudsyftet med datamängden är att träna tal-till-text-modeller.

Sammansättning av datamängd

Datauppsättningens storlek anges för WAV-filer.

DATAMÄNGD UTTALANDEN TIMMAR GB SECS/CHARS COMMENT ANTECKNING KVALITET/BRUS
radio_v4 (*) 7 603 192 10 430 1 195 5 sek/68 Radio Justera 95 % /kant
public_speech (*) 1 700 060 2 709 301 6 sek/79 Offentligt tal Justera 95 % /kant
audiobook_2 1 149 404 1 511 162 5 sek/56 Böcker Justera 95 % /kant
radio_2 651 645 1 439 154 8 sek/110 Radio Justera 95 % /kant
public_youtube1120 1 410 979 1 104 237 3 sek/34 YouTube Undertexter 95 % /~~
public_youtube700 759 483 701 75 3 sek/43 YouTube Undertexter 95 % /~~
tts_russian_addresses 1 741 838 754 81 2 sek/20 Adresser TTS 4-röster 100 %/tydligt
asr_public_phone_calls_2 603 797 601 66 4 sek/37 Telefonsamtal ASR 70 % /brus
public_youtube1120_hq 369 245 291 31 3 sek/37 YouTube HQ Undertexter 95 % /~~
asr_public_phone_calls_1 233 868 211 23 3 sek/29 Telefonsamtal ASR 70 % /brus
radio_v4_add (*) 92 679 157 18 6 sek/80 Radio Justera 95 % /yskad
asr_public_stories_2 78 186 78 9 4 sek/43 Böcker ASR 80 % /klar
asr_public_stories_1 46 142 38 4 3 sek/30 Böcker ASR 80 % /klar
public_series_1 20 243 17 2 3 sek/38 YouTube Undertexter 95 % /~1
asr_calls_2_val 12 950 7,7 2 2 sek/34 Telefonsamtal Manuell anteckning 99 % /klar
public_lecture_1 6 803 6 1 3 sek/47 Föreläsningar Undertexter 95 % /yskad
buriy_audiobooks_2_val 7 850 4,9 1 2 sek/31 Böcker Manuell anteckning 99 % /klar
public_youtube700_val 7 311 4,5 1 2 sek/35 YouTube Manuell anteckning 99 % /klar

(*) Endast ett dataexempel medföljer txt-filerna.

Anteckningsmetod

Datamängden kompileras med öppna källkoder. Långa sekvenser delas upp i ljudsegment med hjälp av identifiering och justering av röstaktivitet. Vissa ljudtyper kommenteras automatiskt och verifieras statistiskt med hjälp av heuristik.

Datavolymer och uppdateringsfrekvens

Datamängdens totala storlek är 350 GB. Den totala storleken på datauppsättningen med offentligt delade etiketter är 130 GB.

Själva datauppsättningen kommer troligen inte att uppdateras för bakåtkompatibilitet. Följ den ursprungliga lagringsplatsen för prestandatest och exkludera filer.

Nya domäner och språk kan komma att läggas till i framtiden.

Ljudnormalisering

Alla filer normaliseras för enklare och snabbare körnings förhöjda körningar. Bearbetningen ser ut så här:

  • Konverteras till mono, om det behövs,
  • Konverteras till 16 kHz-samplingsfrekvens, om det behövs;
  • Lagras som 16-bitars heltal,
  • Konverteras till OPUS,

Databasmetod på disk

Alla ljudfiler (wav, binära) hashkodas. Hashen används för att skapa en mapphierarki för en mer optimal fs-åtgärd.

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)

Nedladdningar

Datamängden tillhandahålls i två former:

  • Arkiv som är tillgängliga via Azure Blob Storage och/eller direktlänkar;
  • Ursprungliga filer som är tillgängliga via Azure Blob Storage; Allt lagras i https://azureopendatastorage.blob.core.windows.net/openstt/ " "

Mappstruktur:

└── 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
DATAMÄNGD GB, WAV GB, ARKIV ARKIV KÄLLA MANIFEST
Träna
Exempel på radio och offentligt tal - 11,4 opus+txt - manifest
audiobook_2 162 25,8 opus+txt Internet + justering manifest
radio_2 154 24,6 opus+txt Radio manifest
public_youtube1120 237 19,0 opus+txt YouTube-videor manifest
asr_public_phone_calls_2 66 9,4 opus+txt Internet + ASR manifest
public_youtube1120_hq 31 4,9 opus+txt YouTube-videor manifest
asr_public_stories_2 9 1.4 opus+txt Internet + justering manifest
tts_russian_addresses_rhvoice_4voices 80,9 12,9 opus+txt TTS manifest
public_youtube700 75,0 12,2 opus+txt YouTube-videor manifest
asr_public_phone_calls_1 22,7 3.2 opus+txt Internet + ASR manifest
asr_public_stories_1 4.1 0,7 opus+txt Offentliga artiklar manifest
public_series_1 1,9 0.3 opus+txt Offentliga serier manifest
public_lecture_1 0,7 0,1 opus+txt Internet + handbok manifest
Val
asr_calls_2_val 2 0,8 wav+txt Internet manifest
buriy_audiobooks_2_val 1 0,5 wav+txt Böcker + handbok manifest
public_youtube700_val 2 0.13 wav+txt YouTube-video + handbok manifest

Nedladdningsanvisningar

Direktnedladdning

Anvisningar om hur du laddar ned datauppsättningen direkt finns på sidan GitHub ladda ned instruktioner.

Ytterligare information

Om du behöver hjälp eller har frågor om data kontaktar du dataförfattare på aveysov@gmail.com

Med den här licensen kan användare distribuera, remixa, anpassa och bygga vidare på materialet i valfritt medium eller format för icke-kommersiella syften, och endast så länge attribution ges till skaparen. Den omfattar följande delar:

  • BY – Kredit måste ges till skaparen
  • NC – Endast icke-kommersiell användning av arbetet tillåts

CC-BY-NC och kommersiell användning är tillgänglig enligt avtal med datamängdens författare.

Dataåtkomst

Azure Notebooks

Hjälpfunktioner/beroenden

Skapa libsndfile

Ett effektivt sätt att läsa filer i Python som inte medför betydande omkostnader är att använda pyfile (en Python CFFI-omserskapare runt libfile).

Supporten har implementerats uppströms, men den har inte släppts korrekt. Därför valde vi anpassad version + apkorrigering.

Vanligtvis måste du köra detta i gränssnittet med sudo-åtkomst:

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 .

Hjälpfunktioner/beroenden

Installera följande bibliotek:

pandas
numpy
scipy
tqdm
soundfile
librosa

Manifest är csv-filer med följande kolumner:

  • Sökväg till ljud
  • Sökväg till textfil
  • Varaktighet

De visade sig vara det enklaste formatet för att komma åt data.

För enkel användning är alla manifest redan rotade. Alla sökvägar i dem är relativa. Du måste ange en rotmapp.

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

Spela med en datauppsättning

Spela upp ett exempel på filer

De flesta plattformars webbläsare stöder intern ljuduppspelning. Så vi kan använda HTML5-ljudspelare för att visa våra data.

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)

Läs en fil

!ls ru_open_stt_opus/manifests/*.csv

Några exempel som visar hur du bäst läser wav- och files-filer.

Scipy är snabbast för wav. Pyfile är den bästa övergripande för pyfile.

%matplotlib inline

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

Läs en 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)

Läs mer

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ästa steg

Visa resten av datauppsättningarna i Open Datasets katalogen.