Я хочу создать модель распознавания речи с нуля без использования существующей модели. Я уже успешно использовал Whisper, но мне нужно создать модель, которую я могу тренировать себя, чья производительность может быть измерена против шепота. Я даже пытался переполнить его в один файл и проверить его в одном файле, но, похоже, не дает никаких выходов. Я использовал набор голосовых данных Mozilla Common и преобразовал файлы MP3 в файлы .wav с скоростью дискретизации 16000 Гц < /p>
import os
import string
import pandas as pd
import torch
import torchaudio
import torch.nn as nn
import torch.nn.functional as Fn
from torch.utils.data import Dataset, DataLoader, random_split
# ---------- Feature Extraction ----------
mel_spec = torchaudio.transforms.MelSpectrogram(
sample_rate=16000,
n_fft=400,
win_length=400,
hop_length=160,
n_mels=80
)
amp_to_db = torchaudio.transforms.AmplitudeToDB()
def extract_features(wav_path):
waveform, sr = torchaudio.load(wav_path)
if sr != 16000:
waveform = torchaudio.functional.resample(waveform, sr, 16000)
spec = mel_spec(waveform)
log_spec = amp_to_db(spec)
# optional: remove normalization if unstable
# log_spec = (log_spec - log_spec.mean()) / (log_spec.std() + 1e-8)
return log_spec.squeeze(0).transpose(0, 1) # (T, 80)
# ---------- Vocabulary & Tokenizer ----------
english_chars = list(string.ascii_lowercase + " '")
vocab = [''] + sorted(set(english_chars))
char2idx = {c: i for i, c in enumerate(vocab)}
idx2char = {i: c for c, i in char2idx.items()}
def text_to_indices(text):
return [char2idx[c] for c in text.lower() if c in char2idx]
def collapse_tokens(pred_ids, idx2char):
tokens = []
prev = None
for p in pred_ids:
if p != prev and p != 0:
tokens.append(idx2char[p])
prev = p
return ''.join(tokens)
# ---------- Dataset ----------
class SpeechDataset(Dataset):
def __init__(self, df: pd.DataFrame, wav_dir: str):
df_new = df.sample(400)
self.wavs = df_new['clip'].tolist()
self.texts = df_new['sentence'].tolist()
self.wav_dir = wav_dir
def __len__(self):
return len(self.wavs)
def __getitem__(self, idx):
wav_path = os.path.join(self.wav_dir, self.wavs[idx])
spec = extract_features(wav_path)
labels = torch.tensor(text_to_indices(self.texts[idx]), dtype=torch.long)
return spec, labels
# ---------- Collate Function with Debug ----------
def collate_fn(batch):
specs, labels = zip(*batch)
spec_lens = [s.size(0) for s in specs]
label_lens = [len(l) for l in labels]
print("▶ batch label lengths:", label_lens[:5])
max_spec = max(spec_lens)
max_lab = max(label_lens)
batch_spec = torch.zeros(len(batch), max_spec, 80)
batch_lab = torch.zeros(len(batch), max_lab, dtype=torch.long)
for i, (s, l) in enumerate(zip(specs, labels)):
batch_spec[i, :s.size(0), :] = s
batch_lab[i, :l.size(0)] = l
return batch_spec, torch.tensor(spec_lens), batch_lab, torch.tensor(label_lens)
# ---------- Load DataFrame & Split ----------
full_df = pd.read_excel("transcripts_with_wav_clips.xlsx")
wav_dir = "cv-corpus-21.0-delta-2025-03-14/en/wav/"
dataset = SpeechDataset(full_df, wav_dir)
# 80/10/10 split
total = len(dataset)
n_train = int(0.8 * total)
n_val = int(0.1 * total)
n_test = total - n_train - n_val
train_ds, val_ds, test_ds = random_split(dataset, [n_train, n_val, n_test])
train_loader = DataLoader(train_ds, batch_size=32, shuffle=True, collate_fn=collate_fn)
val_loader = DataLoader(val_ds, batch_size=32, shuffle=False, collate_fn=collate_fn)
test_loader = DataLoader(test_ds, batch_size=32, shuffle=False, collate_fn=collate_fn)
# ---------- Model Definition ----------
class SpeechRecognitionModel(nn.Module):
def __init__(self, n_mels=80, hidden=256, vocab_size=len(vocab), num_layers=2):
super().__init__()
self.cnn = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d((1, 2)) # reduce mel bins by 2
)
self.fc_in = nn.Linear(32 * (n_mels // 2), hidden)
self.lstm = nn.LSTM(hidden, hidden, num_layers=num_layers,
bidirectional=True, batch_first=True)
self.classifier = nn.Linear(hidden * 2, vocab_size)
def forward(self, x, lengths):
B, T, F = x.size()
x = x.unsqueeze(1) # (B,1,T,F)
x = self.cnn(x) # (B,32,T,F/2)
x = x.permute(0, 2, 1, 3).reshape(B, T, -1) # (B,T,32*F/2)
x = Fn.relu(self.fc_in(x)) # (B,T,hidden)
x = nn.utils.rnn.pack_padded_sequence(x, lengths, batch_first=True, enforce_sorted=False)
x, _ = self.lstm(x)
x, _ = nn.utils.rnn.pad_packed_sequence(x, batch_first=True)
logits = self.classifier(x)
return logits.log_softmax(dim=-1)
# ---------- Setup Training ----------
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = SpeechRecognitionModel().to(device)
ctc_loss = nn.CTCLoss(blank=0, zero_infinity=True)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
# ---------- Evaluation Function ----------
def evaluate(loader):
model.eval()
total_loss = 0
with torch.no_grad():
for specs, spec_lens, labs, lab_lens in loader:
specs, labs = specs.to(device), labs.to(device)
out = model(specs, spec_lens).permute(1, 0, 2)
total_loss += ctc_loss(out, labs, spec_lens, lab_lens).item()
return total_loss / len(loader)
# ---------- Training Loop ----------
for epoch in range(1, 21):
model.train()
train_loss = 0
for specs, spec_lens, labs, lab_lens in train_loader:
specs, labs = specs.to(device), labs.to(device)
optimizer.zero_grad()
out = model(specs, spec_lens).permute(1, 0, 2)
loss = ctc_loss(out, labs, spec_lens, lab_lens)
loss.backward(); optimizer.step()
train_loss += loss.item()
train_loss /= len(train_loader)
val_loss = evaluate(val_loader)
print(f"Epoch {epoch:2d} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f}")
# ---------- Final Test Decoding & WER ----------
# decode tokens for a batch, compute WER using jiwer
from jiwer import wer
def decode_and_evaluate(loader):
model.eval()
ground_truths, predictions = [], []
with torch.no_grad():
for specs, spec_lens, labs, lab_lens in loader:
specs = specs.to(device)
logits = model(specs, spec_lens)
pred_ids = logits.argmax(-1).cpu().tolist()
for p_ids, t_ids in zip(pred_ids, labs.tolist()):
predictions.append(collapse_tokens(p_ids, idx2char))
ground_truths.append(collapse_tokens(t_ids, idx2char))
return wer(ground_truths, predictions)
test_wer = decode_and_evaluate(test_loader)
print(f"Test WER: {test_wer:.3f}")
< /code>
Окончательная эпоха имеет следующую потерю: < /p>
Epoch 20 | Train Loss: 2.9548 | Val Loss: 3.0483
< /code>
и вывод: < /p>
▶ batch label lengths: [52, 89, 81, 102, 35]
▶ batch label lengths: [91, 51, 54, 101, 65]
Test WER: 1.000
< /code>
Я затем попытался переполнить этот код в один файл, чтобы увидеть, работает ли он, но он все еще ничего не предсказывает. < /p>
def transcribe_file(path):
# 1) Extract & shape spec
spec = extract_features(path).unsqueeze(0) # (1, T, 80)
# 2) Move ONLY the spectrogram to the device
spec = spec.to(device)
# 3) Build lengths as a CPU int64 tensor
length = torch.tensor([spec.size(1)], dtype=torch.int64)
# 4) Run through the model (length stays on CPU)
model.eval()
with torch.no_grad():
logits = model(spec, length)[0] # (T, V)
# 5) Greedy decode
pred_ids = logits.argmax(-1).cpu().tolist() # still on CPU for argmax
# 6) Collapse repeats/blanks
return collapse_tokens(pred_ids, idx2char)
# Pick a single sample from train_ds:
spec, labels = train_ds[0]
# Create a tiny DataLoader
from torch.utils.data import DataLoader
one_loader = DataLoader([(spec, labels)], batch_size=1, collate_fn=collate_fn)
# Train for 200 epochs on just that one example
model = SpeechRecognitionModel().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(1, 201):
model.train()
for specs, spec_lens, labs, lab_lens in one_loader:
specs, labs = specs.to(device), labs.to(device)
optimizer.zero_grad()
out = model(specs, spec_lens).permute(1,0,2)
loss = ctc_loss(out, labs, spec_lens, lab_lens)
loss.backward(); optimizer.step()
if epoch % 20 == 0:
print(f"Epoch {epoch}, Loss: {loss.item():.4f}")
# Now decode it
pred = transcribe_file(os.path.join(wav_dir, train_ds.dataset.wavs[train_ds.indices[0]]))
gt = collapse_tokens(labels.tolist(), idx2char)
print("GT :", gt)
print("PRED:", pred)
< /code>
и вывод: < /p>
Epoch 200, Loss: 2.4376
GT : the busineses are listed in the indonesian and singapore stock exchanges
PRED:
Подробнее здесь: https://stackoverflow.com/questions/796 ... -in-python
Как создать модель распознавания речи с нуля в Python ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Как постепенно обучать модель распознавания лиц без переобучения с нуля?
Anonymous » » в форуме Python - 0 Ответы
- 28 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Запустите приложение с помощью Siri, чтобы создать заметку с помощью распознавания речи.
Anonymous » » в форуме IOS - 0 Ответы
- 67 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как мне дать время прослушивания библиотеки распознавания речи Python?
Anonymous » » в форуме Python - 0 Ответы
- 8 Просмотры
-
Последнее сообщение Anonymous
-