mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
16 KiB
16 KiB
In [ ]:
BRANCH = 'v1.0.2'
try:
# Import NeMo Speech Recognition collection
import nemo.collections.asr as nemo_asr
except ModuleNotFoundError:
!python -m pip install git+https://github.com/NVIDIA/NeMo.git@$BRANCH#egg=nemo_toolkit[all]
# check if we have optional Plotly for visualization
try:
from plotly import graph_objects as go
except ModuleNotFoundError:
!pip install plotly
from plotly import graph_objects as go
# check if we have optional ipywidgets for tqdm/notebook
try:
import ipywidgets
except ModuleNotFoundError:
!pip install ipywidgets
# check if CTC beam decoders are installed
try:
import ctc_decoders
except ModuleNotFoundError:
# install beam search decoder
!apt-get install -y swig
!git clone https://github.com/NVIDIA/NeMo -b "$BRANCH"
!cd NeMo && bash scripts/asr_language_modeling/ngram_lm/install_beamsearch_decoders.sh
print('Restarting Colab runtime to successfully import built module.')
print('Please re-run the notebook.')
import os
os.kill(os.getpid(), 9)In [ ]:
import numpy as np
# Import audio processing library
import librosa
# We'll use this to listen to audio
from IPython.display import Audio, displayIn [ ]:
nemo_asr.models.EncDecCTCModel.list_available_models()In [ ]:
asr_model = nemo_asr.models.EncDecCTCModel.from_pretrained(model_name='QuartzNet15x5Base-En', strict=False)In [ ]:
# Download audio sample which we'll try
# This is a sample from LibriSpeech dev clean subset - the model hasn't seen it before
AUDIO_FILENAME = '1919-142785-0028.wav'
!wget https://dldata-public.s3.us-east-2.amazonaws.com/1919-142785-0028.wav
# load audio signal with librosa
signal, sample_rate = librosa.load(AUDIO_FILENAME, sr=None)
# display audio player for the signal
display(Audio(data=signal, rate=sample_rate))
# plot the signal in time domain
fig_signal = go.Figure(
go.Scatter(x=np.arange(signal.shape[0])/sample_rate,
y=signal, line={'color': 'green'},
name='Waveform',
hovertemplate='Time: %{x:.2f} s<br>Amplitude: %{y:.2f}<br><extra></extra>'),
layout={
'height': 300,
'xaxis': {'title': 'Time, s'},
'yaxis': {'title': 'Amplitude'},
'title': 'Audio Signal',
'margin': dict(l=0, r=0, t=40, b=0, pad=0),
}
)
fig_signal.show()
# calculate amplitude spectrum
time_stride=0.01
hop_length = int(sample_rate*time_stride)
n_fft = 512
# linear scale spectrogram
s = librosa.stft(y=signal,
n_fft=n_fft,
hop_length=hop_length)
s_db = librosa.power_to_db(np.abs(s)**2, ref=np.max, top_db=100)
# plot the signal in frequency domain
fig_spectrum = go.Figure(
go.Heatmap(z=s_db,
colorscale=[
[0, 'rgb(30,62,62)'],
[0.5, 'rgb(30,128,128)'],
[1, 'rgb(30,255,30)'],
],
colorbar=dict(
ticksuffix=' dB'
),
dx=time_stride, dy=sample_rate/n_fft/1000,
name='Spectrogram',
hovertemplate='Time: %{x:.2f} s<br>Frequency: %{y:.2f} kHz<br>Magnitude: %{z:.2f} dB<extra></extra>'),
layout={
'height': 300,
'xaxis': {'title': 'Time, s'},
'yaxis': {'title': 'Frequency, kHz'},
'title': 'Spectrogram',
'margin': dict(l=0, r=0, t=40, b=0, pad=0),
}
)
fig_spectrum.show()In [ ]:
# Convert our audio sample to text
files = [AUDIO_FILENAME]
transcript = asr_model.transcribe(paths2audio_files=files)[0]
print(f'Transcript: "{transcript}"')In [ ]:
# softmax implementation in NumPy
def softmax(logits):
e = np.exp(logits - np.max(logits))
return e / e.sum(axis=-1).reshape([logits.shape[0], 1])
# let's do inference once again but without decoder
logits = asr_model.transcribe(files, logprobs=True)[0]
probs = softmax(logits)
# 20ms is duration of a timestep at output of the model
time_stride = 0.02
# get model's alphabet
labels = list(asr_model.decoder.vocabulary) + ['blank']
labels[0] = 'space'
# plot probability distribution over characters for each timestep
fig_probs = go.Figure(
go.Heatmap(z=probs.transpose(),
colorscale=[
[0, 'rgb(30,62,62)'],
[1, 'rgb(30,255,30)'],
],
y=labels,
dx=time_stride,
name='Probs',
hovertemplate='Time: %{x:.2f} s<br>Character: %{y}<br>Probability: %{z:.2f}<extra></extra>'),
layout={
'height': 300,
'xaxis': {'title': 'Time, s'},
'yaxis': {'title': 'Characters'},
'title': 'Character Probabilities',
'margin': dict(l=0, r=0, t=40, b=0, pad=0),
}
)
fig_probs.show()In [ ]:
# get timestamps for space symbols
spaces = []
state = ''
idx_state = 0
if np.argmax(probs[0]) == 0:
state = 'space'
for idx in range(1, probs.shape[0]):
current_char_idx = np.argmax(probs[idx])
if state == 'space' and current_char_idx != 0 and current_char_idx != 28:
spaces.append([idx_state, idx-1])
state = ''
if state == '':
if current_char_idx == 0:
state = 'space'
idx_state = idx
if state == 'space':
spaces.append([idx_state, len(pred)-1])In [ ]:
# calibration offset for timestamps: 180 ms
offset = -0.18
# split the transcript into words
words = transcript.split()
# cut words
pos_prev = 0
for j, spot in enumerate(spaces):
display(words[j])
pos_end = offset + (spot[0]+spot[1])/2*time_stride
display(Audio(signal[int(pos_prev*sample_rate):int(pos_end*sample_rate)],
rate=sample_rate))
pos_prev = pos_end
display(words[j+1])
display(Audio(signal[int(pos_prev*sample_rate):],
rate=sample_rate))In [ ]:
import gzip
import os, shutil, wget
lm_gzip_path = '3-gram.pruned.1e-7.arpa.gz'
if not os.path.exists(lm_gzip_path):
print('Downloading pruned 3-gram model.')
lm_url = 'http://www.openslr.org/resources/11/3-gram.pruned.1e-7.arpa.gz'
lm_gzip_path = wget.download(lm_url)
print('Downloaded the 3-gram language model.')
else:
print('Pruned .arpa.gz already exists.')
uppercase_lm_path = '3-gram.pruned.1e-7.arpa'
if not os.path.exists(uppercase_lm_path):
with gzip.open(lm_gzip_path, 'rb') as f_zipped:
with open(uppercase_lm_path, 'wb') as f_unzipped:
shutil.copyfileobj(f_zipped, f_unzipped)
print('Unzipped the 3-gram language model.')
else:
print('Unzipped .arpa already exists.')
lm_path = 'lowercase_3-gram.pruned.1e-7.arpa'
if not os.path.exists(lm_path):
with open(uppercase_lm_path, 'r') as f_upper:
with open(lm_path, 'w') as f_lower:
for line in f_upper:
f_lower.write(line.lower())
print('Converted language model file to lowercase.')In [ ]:
beam_search_lm = nemo_asr.modules.BeamSearchDecoderWithLM(
vocab=list(asr_model.decoder.vocabulary),
beam_width=16,
alpha=2, beta=1.5,
lm_path=lm_path,
num_cpus=max(os.cpu_count(), 1),
input_tensor=False)In [ ]:
beam_search_lm.forward(log_probs = np.expand_dims(probs, axis=0), log_probs_length=None)In [ ]: