Çeşitli ses kaynaklarından toplanan konuşma örnekleri koleksiyonu. Veri kümesi Rusça kısa ses klipleri içerir.
Büyük olasılıkla şu ana kadarki en büyük genel Rusça STT veri kümesi:
- yaklaşık 16 milyon ifade;
- yaklaşık 20.000 saat;
- 2,3 TB (
int16
olarak.wav
biçiminde sıkıştırılmamış),.opus
biçiminde 356 GB; - Şimdi doğrulama veri kümeleri hariç tüm dosyalar opus’a dönüştürüldü;
Veri kümesinin temel amacı konuşmayı metne dönüştürme modellerini eğitmektir.
Veri kümesi bileşimiVeri kümesi boyutu .wav
dosyaları için verilmiştir.
Veri kümesi | İfadeler | Saat | GB | Sn/karakter | Yorum | Ek Açıklama | Kalite/gürültü |
---|---|---|---|---|---|---|---|
radio_v4 (*) | 7.603.192 | 10.430 | 1.195 | 5 sn / 68 | Radyo | Hizala | %95 / net |
public_speech (*) | 1.700.060 | 2.709 | 301 | 6 sn / 79 | Genel konuşma | Hizala | %95 / net |
audiobook_2 | 1.149.404 | 1.511 | 162 | 5 sn / 56 | Kitaplar | Hizala | %95 / net |
radio_2 | 651.645 | 1.439 | 154 | 8 sn / 110 | Radyo | Hizala | %95 / net |
public_youtube1120 | 1.410.979 | 1.104 | 237 | 3 sn / 34 | YouTube | Alt yazılar | %95 / ~net |
public_youtube700 | 759.483 | 701 | 75 | 3 sn / 43 | YouTube | Alt yazılar | %95 / ~net |
tts_russian_addresses | 1.741.838 | 754 | 81 | 2 sn / 20 | Adresler | TTS 4 sesleri | %100 / net |
asr_public_phone_calls_2 | 603.797 | 601 | 66 | 4 sn / 37 | Telefon aramaları | ASR | %70 / gürültülü |
public_youtube1120_hq | 369.245 | 291 | 31 | 3 sn / 37 | YouTube HQ | Alt yazılar | %95 / ~net |
asr_public_phone_calls_1 | 233.868 | 211 | 23 | 3 sn / 29 | Telefon aramaları | ASR | %70 / gürültülü |
radio_v4_add (*) | 92.679 | 157 | 18 | 6 sn / 80 | Radyo | Hizala | %95 / net |
asr_public_stories_2 | 78.186 | 78 | 9 | 4 sn / 43 | Kitaplar | ASR | %80 / net |
asr_public_stories_1 | 46.142 | 38 | 4 | 3 sn / 30 | Kitaplar | ASR | %80 / net |
public_series_1 | 20.243 | 17 | 2 | 3 sn / 38 | YouTube | Alt yazılar | %95 / ~net |
asr_calls_2_val | 12.950 | 7,7 | 2 | 2 sn / 34 | Telefon aramaları | El ile ek açıklama | %99 / net |
public_lecture_1 | 6.803 | 6 | 1 | 3 sn / 47 | Konuşmalar | Alt yazılar | %95 / net |
buriy_audiobooks_2_val | 7.850 | 4,9 | 1 | 2 sn / 31 | Kitaplar | El ile ek açıklama | %99 / net |
public_youtube700_val | 7.311 | 4,5 | 1 | 2 sn / 35 | YouTube | El ile ek açıklama | %99 / net |
(*) Txt dosyalarıyla yalnızca örnek veriler sağlanır.
Ek açıklama metodolojisiVeri kümesi açık kaynaklar kullanılarak derlenmiştir. Uzun diziler ses etkinliği algılama ve hizalama kullanılarak ses öbeklerine ayrılır. Bazı ses türlerine otomatik olarak ek açıklama eklenir ve bunlar istatistiksel olarak / buluşsal olarak doğrulanır.
Veri Hacimleri ve Güncelleştirme SıklığıTüm veri kümesinin toplam boyutu 350 GB’tır. Herkese açık şekilde paylaşılan etiketler ile veri kümesinin toplam boyutu 130 GB’tır.
Veri kümesinin geriye dönük olarak uyumlu olması için güncelleştirilmesi öngörülmemektedir. Karşılaştırmalar ve hariç tutma dosyaları için lütfen özgün depoyu takip edin.
Gelecekte yeni etki alanları ve diller eklenebilir.
Ses normalleştirme
Tüm dosyalar daha kolay / daha hızlı çalışma zamanı geliştirmeleri ve işlemeleri için aşağıdaki gibi normalleştirilir:
- Gerekirse monoya dönüştürülür;
- Gerekirse 16 kHz örnekleme hızına dönüştürülür;
- 16 bit tamsayılar olarak depolanır;
- OPUS’a dönüştürülür;
Disk üzerinde veritabanı metodolojisi
Her ses dosyasına (wav, ikili) karma işlemi uygulanır. Karması, daha iyi fs işlemi için bir klasör hiyerarşisi oluşturmak üzere kullanılır.
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)
Veri kümesi 2 biçimde sağlanır:
- Azure blob depolama ve / veya doğrudan bağlantılar aracılığıyla kullanılabilen arşivler;
- Azure blob depolama aracılığıyla kullanılabilen özgün dosyalar;
Her şey https://azureopendatastorage.blob.core.windows.net/openstt/
içinde depolanır
Klasör yapısı:
└── 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
Veri kümesi | GB, wav | GB, arşiv | Arşiv | Kaynak | Bildirim |
---|---|---|---|---|---|
Eğitim | |||||
Radyo ve genel konuşma örneği | - | 11,4 | opus+txt | - | bildirim |
audiobook_2 | 162 | 25,8 | opus+txt | İnternet + hizalama | bildirim |
radio_2 | 154 | 24,6 | opus+txt | Radyo | bildirim |
public_youtube1120 | 237 | 19,0 | opus+txt | YouTube videoları | bildirim |
asr_public_phone_calls_2 | 66 | 9.4 | opus+txt | İnternet + ASR | bildirim |
public_youtube1120_hq | 31 | 4,9 | opus+txt | YouTube videoları | bildirim |
asr_public_stories_2 | 9 | 1.4 | opus+txt | İnternet + hizalama | bildirim |
tts_russian_addresses_rhvoice_4voices | 80,9 | 12,9 | opus+txt | TTS | bildirim |
public_youtube700 | 75.0 | 12,2 | opus+txt | YouTube videoları | bildirim |
asr_public_phone_calls_1 | 22.7 | 3.2 | opus+txt | İnternet + ASR | bildirim |
asr_public_stories_1 | 4.1 | 0.7 | opus+txt | Genel hikayeler | bildirim |
public_series_1 | 1.9 | 0.3 | opus+txt | Genel seriler | bildirim |
public_lecture_1 | 0.7 | 0.1 | opus+txt | İnternet + el kitabı | bildirim |
Val | |||||
asr_calls_2_val | 2 | 0.8 | wav+txt | İnternet | bildirim |
buriy_audiobooks_2_val | 1 | 0,5 | wav+txt | Kitaplar + el kitabı | bildirim |
public_youtube700_val | 2 | 0.13 | wav+txt | YouTube videoları + el kitabı | bildirim |
Doğrudan
Lütfen şuraya başvurun: https://github.com/snakers4/open_stt#download-instructions
Azure blob depolama bağlayarak
Lütfen “Veri Erişimi” Sekmesindeki not defterine bakın
KişilerVeriler hakkında yardım veya sorularınız için lütfen aveysov@gmail.com üzerinden veri yazarlarıyla iletişime geçin
LisansBu lisans, malzemeleri yeniden kullanan kişilerin malzemeleri yalnızca ticari olmayan amaçlarla ve yalnızca oluşturucuya atıfta bulunularak herhangi bir ortamda veya biçimde yeniden dağıtmasına, yeniden oluşturmasına, uyarlamasına ve ekleme yapmasına olanak sağlar. Bu, aşağıdaki öğeleri içerir:
* BY: Oluşturucuya atıfta bulunulmalıdır
* NC: Çalışmanın yalnızca ticari olmayan kullanımlarına izin verilir
CC-BY-NC ve ticari kullanım, veri kümesi yazarlarıyla anlaşma yapıldıktan sonra gerçekleştirilebilir.
Başvurular / daha fazla bilgiÖzgün veri kümesi
- https://github.com/snakers4/open_stt
İngilizce makaleler
- https://thegradient.pub/towards-an-imagenet-moment-for-speech-to-text/
- https://thegradient.pub/a-speech-to-text-practitioners-criticisms-of-industry-and-academia/
Çince makaleler
- https://www.infoq.cn/article/4u58WcFCs0RdpoXev1E2
Rusça makaleler
- https://habr.com/ru/post/494006/
- https://habr.com/ru/post/474462/
Access
Available in | When to use |
---|---|
Azure Notebooks | Quickly explore the dataset with Jupyter notebooks hosted on Azure or your local machine. |
Select your preferred service:
Azure Notebooks
!pip install numpy
!pip install tqdm
!pip install scipy
!pip install pandas
!pip install soundfile
!pip install librosa
!pip install azure-storage-blob
# 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()
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)
!ls ru_open_stt_opus/manifests/*.csv
%matplotlib inline
import librosa
from scipy.io import wavfile
from librosa import display as ldisplay
from matplotlib import pyplot as plt
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)
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)