Canlı çeviride 700 ms'nin altına nasıl indik
Zor olan model değil, gecikme bütçesi
Herkes konuşma çevirisinde gecikmenin bir model sorunu olduğunu düşünür: daha hızlı bir konuşma tanıma motoru, daha hızlı bir çeviri modeli, daha hızlı bir metinden sese ses seçin, sayı düşsün. Web, iOS ve Android'de çalışan gerçek zamanlı konuşmadan konuşmaya çeviri ürünümüz FluenSync'te model değişiklikleri beklediğimizden az işe yaradı. 14'ün üzerinde dilde 700 milisaniyenin altına inmemizi asıl sağlayan, modellerin etrafındaki hat mimarisiydi.
Konuşma bitmeden parçalamak
Saf yaklaşım konuşmada bir duraklama bekler, tüm cümleyi önce tanımaya, sonra çeviriye, sonra sese gönderir. Her aşama bir öncekinin bitmesini bekler ve duraklamaların kendisi, daha tek kelime işlenmeden bütçeyi tüketir. Biz bunun yerine sabit boyutlu ses parçalarını geldikçe tanıma aşamasına akıtıyoruz, aşamanın sürekli kısmi transkript üretmesine izin veriyoruz. Çeviri, tanıyıcının artık değiştirmeyeceği kararlı parçalar üzerinde başlıyor, nihai transkripti beklemeden. Bütçenin çoğu buradan, herhangi bir modelin daha hızlı olmasından değil bu örtüşmeden geri kazanılıyor.
Bağlantı nerede oturuyor
Üç aşama da oturum başına tek bir WebSocket bağlantısının arkasında oturuyor, üç ayrı istek yerine. WebSocket her parça için yeni bir bağlantı kurma maliyetinden kaçınıyor ve kısmi sonuçları oluştukları anda istemciye itmemizi sağlıyor, istemcinin yoklaması yerine. Mobil istemcide aynı bağlantı hem sesi yukarı hem sentezlenmiş konuşmayı aşağı taşıyor, bu yüzden bütçelenecek gidiş dönüş maliyeti tek.
Gerçekte izlediğimiz bütçe
- Cihazda ses yakalama ve parçalama: tüm cümle değil, küçük ve sabit bir dilim.
- Ağda yukarı yön: parça başına yeni bağlantı değil, tek bir WebSocket çerçevesi.
- Kararlı bir parça üzerinde tanıma: bölüm artık değişmeyecekse hemen döndür.
- O parça üzerinde çeviri: model gecikmesi öngörülebilir kalsın diye yeterince küçük girdi.
- Sentez: bir sonraki parçanın çevirisi bitmeden, çevrilen parça için ses üretmeye başla.
- Ağda aşağı yön ve oynatma: tek dosya değil, akış hâlinde.
Bunların her birinin kendi milisaniye hedefi var. Yalnızca uçtan uca sayıyı değil her birini ayrı ölçüyoruz, çünkü tek bir yavaş aşama ortalamada gizlenir ama çeviriyi bekleyen kişi için çok görünürdür.
Sadece hattı değil, ağı da yönetmek
Sabit bir bağlantıda hızlı olan bir hat, ağın hiç aksamayacağını varsayarsa sahada yine de başarısız olur. Mobil bağlantı kare kaybeder, paket sıralamasını bozar, cümlenin ortasında takılır. Bu yüzden istemcide küçük bir jitter tamponu çalıştırıyoruz, kısa boşlukları oynatmayı durdurmadan emiyor, sesi dosya boyutuna göre ayarlanmış bir kodek yerine düşük bant genişliği için tasarlanmış bir kodekle kodluyoruz. WebSocket oturum ortasında koparsa istemci yeniden bağlanıp oturumu sürdürür, yeni bir oturum başlatmaz. Kısa bir kesinti bir kekemeliğe mal olur, sessizlikten yeniden başlamaya değil. Bunların hiçbiri laboratuvar ağında ölçülen bir sayıda görünmez, ama 700 milisaniyelik bütçenin hareket eden bir trende bir telefonda gerçekten tutup tutmayacağını bu belirler.
Bilinçli olarak yapmadıklarımız
Tek başına en hızlı modelin peşine düşmedik, çünkü tüm cümlenin bitmesini bekleyen marjinal olarak daha hızlı bir model, kısmi bir parça üzerinde başlayabilen biraz daha yavaş bir modele karşı kaybediyor. Spekülatif devamları tahmin ederek öne geçmeyi de denemedik, çünkü yanlış bir tahmin, düzeltmesi kazandıracağı gecikmeden daha pahalıya mal oluyor. Kazanım herhangi bir aşamayı tek başına hızlandırmaktan değil, aşamalar arası boşta bekleme süresini kaldırmaktan geldi.
Bunu kuracak bir ekibe önerimiz
Herhangi bir modeli optimize etmeden önce hattı aşama aşama profilleyin. Akıtılabilen her şeyi akıtın. Bağlantının kendisini, arkasındaki modeller kadar gecikme bütçesinin bir parçası sayın. Gerçek zamanlı bir konuşma ürününde insanların fark ettiği tek bir aşamanın hızı değil, bir aşamanın diğerinin tam bitmesini beklediği her noktanın toplamıdır.