Qgelm

Mozilla DeepSpeech: Speech-to-Text Schritt für Schritt

Originalartikel

Backup

<html> <header class=„article-header“><h1 class=„articleheading“>Mozilla DeepSpeech: Speech-to-Text Schritt f&#252;r Schritt</h1><div class=„publish-info“> Pascal Moll</div></header><figure class=„aufmacherbild“><img src=„https://heise.cloudimg.io/width/700/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/1/0/7/5/4/6/shutterstock_754914430-99670d63283369b8.jpeg“ srcset=„https://heise.cloudimg.io/width/700/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/1/0/7/5/4/6/shutterstock_754914430-99670d63283369b8.jpeg 700w, https://heise.cloudimg.io/width/1050/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/1/0/7/5/4/6/shutterstock_754914430-99670d63283369b8.jpeg 1050w, https://heise.cloudimg.io/width/1500/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/1/0/7/5/4/6/shutterstock_754914430-99670d63283369b8.jpeg 1500w, https://heise.cloudimg.io/width/2300/q75.png-lossy-75.webp-lossy-75.foil1/_www-heise-de_/imgs/18/3/1/0/7/5/4/6/shutterstock_754914430-99670d63283369b8.jpeg 2300w“ alt=„“ class=„img-responsive“ referrerpolicy=„no-referrer“ /><figcaption class=„akwa-caption“>(Bild:&#160;petrmalinak/Shutterstock.com)</figcaption></figure><p><strong>Dieses Tutorial zeigt anhand eines Praxisbeispiels, wie sich ein Sprachassistent mit DeepSpeech auf einem Raspberry Pi erstellen l&#228;sst.</strong></p><p>Intelligente Lautsprecher oder Sprachassistenten sind auf dem Vormarsch. <a href=„https://www.heise.de/meldung/Fast-jeder-Dritte-in-Deutschland-nutzt-Sprachassistenten-4443365.html“><strong>Mehr als ein Drittel [1]</strong></a> aller Deutschen nutzt sie. Doch was passiert eigentlich mit den dadurch erzeugten Daten? Es gibt verschiedene Vermutungen, dennoch l&#228;sst sich nicht sicher sagen, was mit den gesprochenen Informationen geschieht. Um die volle Kontrolle &#252;ber diese Daten zu behalten, entschied sich der Autor, selbst eine Offline-Anwendung mit Java zu entwickeln.</p><p>Dieses Tutorial soll den Speech-to-Text (STT)-Anteil des Entwicklungsprozesses ausschnittsweise vorstellen. Es folgen Einblicke in die Installation der DeepSpeech Engine mithilfe eines Raspberry Pi. Diese Komponenten nehmen Gesprochenes entgegen und &#252;berf&#252;hrt das Gesprochene in Text. Im n&#228;chsten Schritt erfolgt die Einf&#252;hrung des zugeh&#246;rigen Java-Programmcodes, um mit diesem Text zu interagieren und Sprachbefehle zu designen. Der Ausblick zeigt zahlreiche Erweiterungsm&#246;glichkeiten und Einsatzgebiete.</p><h3 class=„subheading“ id=„nav_einf&#252;hrung_in0“>Einf&#252;hrung in Mozilla DeepSpeech</h3><p>Mozillas DeepSpeech ist eine freie Speech-to-Text-Engine. Sie arbeitet mit einem durch Maschine Learning erstellten Sprachmodell, basierend auf den <a href=„https://arxiv.org/abs/1412.5567“ rel=„external noopener“ target=„_blank“><strong>Forschungsergebnissen von Baidu&#8217;s Deep Speech Research Paper [2]</strong></a> und erm&#246;glicht somit, Gesprochenes in Text umzuwandeln. Hier kommt unter anderem Googles Machine-Learning-Framework TensorFlow zum Einsatz, <a href=„https://deepspeech.readthedocs.io/en/r0.9/“ rel=„external noopener“ target=„_blank“><strong>was die Implementierung vereinfachen soll [3]</strong></a>. TensorFlow Lite eignet sich besonders f&#252;r mobile Ger&#228;te, da es deutlich kleinere Sprachmodelle bei vergleichbaren Ergebnissen und Geschwindigkeit mitbringt. Mozilla arbeitet daran, verschiedene Modelle in anderen Sprachen zu generieren. Daf&#252;r nutzen sie das Projekt Common Voice. Das Ziel dieses Crowdsourcing-Projekts ist, eine freie Datenbank mit verschiedenen Sprachen und Sprechern aufzubauen.</p><p>Mitwirkende k&#246;nnen entweder andere Spracheingaben validieren oder selbst Sprachaufnahmen beisteuern. Zur Teilnahme wird lediglich ein Mikrofon ben&#246;tigt. F&#252;r die englische Sprache ist dieses Projekt schon weit entwickelt, so ist die Fehlerquote sehr gering und selbst f&#252;r nicht Muttersprachler mit Dialekt vielseitig anwendbar. Das deutsche Sprachmodell funktioniert ebenfalls gut, hat aber noch Schwierigkeiten bei W&#246;rtern, die &#228;hnlich klingen. Beispielsweise wird „Licht an“ oft als „Lichter“ erkannt.</p><h3 class=„subheading“ id=„nav_ben&#246;tigte1“>Ben&#246;tigte Komponenten und Voraussetzungen</h3><p>F&#252;r das STT-Projekt sind diese Komponenten notwendig:</p><ul class=„rtelist rtelist–unordered“><li>Raspberry Pi 4 (ein PI3 B+ ist ausreichend, kann aber zu Verz&#246;gerungen bei der Ergebnisr&#252;ckgabe f&#252;hren)</li><li>Java 8 mit Maven</li><li>Python 3.5 auf dem Raspi</li><li>Mikrofon (je nach Entfernung empfiehlt sich ein Ringmikrofon)</li></ul><h3 class=„subheading“ id=„nav_deepspeech_als2“>DeepSpeech als Server aufsetzen</h3><p>Zun&#228;chst sollte das Standardbetriebssystem „Raspberry PI OS“ installiert sein. Anschlie&#223;end empfiehlt es sich, die gesamte Speicherkarte als Speicher &#252;ber das Konfigurationsmen&#252; bereitzustellen. Somit entfallen m&#246;gliche Speicherprobleme zu einem sp&#228;teren Zeitpunkt, beispielsweise bei der Verwendung eines gr&#246;&#223;eren Sprachmodells.</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>Aufruf der Config mit sudo raspi-config (Abb. 1)</figcaption></div></figure><p>&#220;ber Advanced Options (Punkt 7) und A1 Expand Filesystem l&#228;sst sich die gesamte Gr&#246;&#223;e der Speicherkarte nutzen. Dar&#252;ber hinaus ist das Aktivieren des Secure File Transfer Protocol (SSH) oder Virtual Network Computing (VNC) zu empfehlen, um nicht immer wieder externe Peripherie f&#252;r die Bedienung anschlie&#223;en zu m&#252;ssen.</p><p>Nach erfolgreichem Abschluss der Grundinstallation gilt es, DeepSpeech zu installieren, was &#252;ber den Konsolenbefehl

pip3 install deepspeech

geschieht. Nach wenigen Minuten Wartezeit sollte die Erfolgsmeldung erscheinen:</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>Erfolgsmeldung: DeepSpeech erfolgreich installiert (Abb. 2)</figcaption></div></figure><p>Mit

pip3 install deepspeech-server

wird nun der Server installiert. Dieser Vorgang kann einige Minuten in Anspruch nehmen.</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>Ben&#246;tigte Sprachmodellkomponenten (Abb. 3)</figcaption></div></figure><p>Anschlie&#223;end ist DeepSpeech installiert, jedoch ist noch kein Sprachmodell hinterlegt. Pre-Trained-Modelle lassen sich <a href=„https://github.com/mozilla/DeepSpeech/releases“ rel=„external noopener“ target=„_blank“><strong>via GitHub herunterladen [4]</strong></a>. F&#252;r das deutsche Modell <a href=„https://drive.google.com/drive/folders/1oO-N-VH_0P89fcRKWEUlVDm-_z18Kbkb“ rel=„external noopener“ target=„_blank“><strong>empfiehlt sich jedoch diese Adresse [5]</strong></a>. Dieses Modell beinhaltet 1582 Sprach-Stunden. Ben&#246;tigt werden das Modell TensorFlow lite und der Scorer.</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>Scorer und Tflite Datei in /home/pi/.local/bin abgelegt (Abb. 4)</figcaption></div></figure><p>Beide Dateien gilt es herunterzuladen und in der Konfiguration zu hinterlegen. Am einfachsten ist dies mit dem VNC Viewer m&#246;glich.</p><p>Im letzten Schritt ist es notwendig, die Konfiguration zu hinterlegen. Hierzu dient eine neue Datei namens <em>config.json</em>.</p><pre class=„rtetx–listing listing“><code>Config.json{ „deepspeech“: { „model“ :„output_graph_de.tflite“, „scorer“ :„kenlm_de.scorer“, „beam_width“: 500, „lm_alpha“: 0.931289039105002, „lm_beta“: 1.1834137581510284 }, „server“: { „http“: { „host“: „0.0.0.0“, „port“: 8080, „request_max_size“: 1048576 } }, „log“: { „level“: [ { „logger“: „deepspeech_server“, „level“: „DEBUG“} ] }}</code></pre><p>Zum Abschluss der Konfiguration ist nun ein Neustart des Raspi erforderlich.</p><h3 class=„subheading“ id=„nav_starten_des3“>Starten des DeepSpeech-Servers</h3><p>Um den Server zu starten, ist im Verzeichnis <em>cd /home/pi/.local/bin</em> der Steuerbefehl

deepspeech-server --config config.json

einzugeben.</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>DeepSpeech-Server erfolgreich gestartet (Abb. 5)</figcaption></div></figure><p>Sollte der Fehler <em>Original error was: libf77blas.so.3: cannot open shared object file: No such file or directory</em> auftauchen, hilft der Befehl:

sudo apt-get install libatlas-base-dev

.</p><p><strong>DeepSpeech-Aufruf</strong></p><p>Um DeepSpeech per Curl aufzurufen, wird die IP des Raspberry-Servers ben&#246;tigt sowie der Curl-Befehl:

curl -X POST --data-binary @testfile.wav http://IP:8080/stt

</p><h3 class=„subheading“ id=„nav_deepspeech4“>DeepSpeech verlangt eine Sounddatei</h3><p>Aktuell existieren keine nativen Java Libraries, um DeepSpeech zu nutzen. Es gibt lediglich eine Android-Bibliothek, die f&#252;r Desktop-Anwendungen jedoch wenig hilfreich ist. Daher ist es erforderlich, DeepSpeech als Server aufzusetzen. Somit l&#228;sst sich eine Verbindung &#252;ber HTTP aufbauen und ein eigenes Java-Programm entwickeln. Der Curl-Befehl l&#228;sst es schon vermuten: DeepSpeech verlangt eine Sounddatei im WAV-Format, die entgegengenommen, interpretiert und dann als Text zur&#252;ckgeliefert wird. Das nachfolgende Programm geht genauso vor.</p><h3 class=„subheading“ id=„nav_blick_in_die5“>Blick in die Bibliothek</h3><p>Zun&#228;chst sind zwei Bibliotheken notwendig. Beide befinden sich im Maven Central Repository und lassen sich einfach ins Project Object Model (POM) einbinden:</p><pre class=„rtetx–listing listing“><code>&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt; &lt;artifactId&gt;httpclient&lt;/artifactId&gt; &lt;version&gt;4.5.13&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;commons-io&lt;/groupId&gt; &lt;artifactId&gt;commons-io&lt;/artifactId&gt; &lt;version&gt;2.8.0&lt;/version&gt; &lt;/dependency&gt;&lt;/dependencies&gt;</code></pre><h3 class=„subheading“ id=„nav_ans_eingemachte6“>Ans Eingemachte mit Java</h3><p>Der nachfolgende Code ist vereinfacht dargestellt: Exception Handling wurde bewusst weitestgehend vernachl&#228;ssigt. Der Client besteht aus den drei Methoden

transcribe()

,

createAudioOutputStream(...)

und

sendDataToServer(...)

.</p><p><strong>&#220;bertragen des Gesprochenen</strong></p><p>Die Methode

transcribe()

&#246;ffnet den Mikrofoneingang und legt gleichzeitig einen Buffer f&#252;r das Gesprochene an.</p><pre class=„rtetx–listing listing“><code>AudioFormat format = new AudioFormat(16000, 16, 1, true, false);</code></pre><p>Die Abtastrate des Eingangssignals wird hiermit auf 16000, die Samplesize auf 16 und die Kan&#228;le auf Mono festgelegt. Der <code>true</code>-Wert gibt an, dass das Eingangssignal signed ist, es kann also sowohl positive als auch negative Werte beinhalten. Das ist notwendig, da Sprachsignale eben solche Werte beinhalten. Der <code>false</code>-Wert steht f&#252;r <code>littleEndian</code> und gibt die Speicherreihenfolge an;<code>true</code> steht f&#252;r <code>bigEndian</code>.</p><p>Diese Einstellungen sind erforderlich, da die hinterlegten Sprachmodelle von DeepSpeech ebenfalls mit diesen Werten abgelegt wurden. Ein Wechsel von mono auf stereo beeinflusst die Erkennung negativ.</p><p>Schlie&#223;lich wird das Mikrofon mit dem vorgegebenen Audioformat ge&#246;ffnet und ist bereit Signale zu empfangen.</p><pre class=„rtetx–listing listing“>

DataLine.Info info = new DataLine.Info(TargetDataLine.class,                                        format);if ( ! AudioSystem.isLineSupported(info)) {        throw new Exception("Mikrofon ist nicht verf&#252;gbar!");}TargetDataLine line = ( TargetDataLine )AudioSystem.getLine(info);line.open(format, line.getBufferSize());

</pre><p>Zum Speichern des Eingangssignales wird noch ein Buffer zur Verf&#252;gung gestellt:</p><pre class=„rtetx–listing listing“><code>ByteArrayOutputStream out = new ByteArrayOutputStream();byte[] data = new byte[line.getBufferSize() / 4];</code></pre><p>Nachdem alle Vorbereitungen abgeschlossen sind, l&#228;sst sich das Signal aufzeichnen und abspeichern:</p><pre class=„rtetx–listing listing“>

System.out.println("StartLine");line.start();long startTime = System.currentTimeMillis();while ( ( System.currentTimeMillis() - startTime ) &lt; 2000) {        int numBytesRead = line.read(data, 0, data.length);        out.write(data, 0, numBytesRead);}System.out.println("ende");

</pre><p>Der Eingang h&#246;rt zwei Sekunden zu und speichert das Gesprochene in dem zuvor festgelegten Buffer. In einem n&#228;chsten Schritt wird der

ByteBuffer

an die Methode

createAudioOutputStream(...)

weitergegeben. Das Ergebnis davon geht an

sendDataToServer(...)

.</p><pre class=„rtetx–listing listing“><code>ByteArrayOutputStream byos = createAudioOutputStream(line, out);return sendDataToServer(byos);</code></pre><p><strong>Ausgabe in die Datei</strong></p><p>Die Methode <code>createAudioOutputStream</code> wandelt den Inhalt des <code>ByteBuffer</code> in eine WAV-Datei um. Dazu berechnet sie die ben&#246;tigte WAV-Gr&#246;&#223;e, liest den <code>ByteBuffer</code> ein und schreibt schlie&#223;lich eine WAV als <code>ByteArrayOutputStream</code> raus:</p><pre class=„rtetx–listing listing“>

private ByteArrayOutputStream createAudioOutputStream(TargetDataLine line,                ByteArrayOutputStream out)    throws IOException {    int frameSizeInBytes = line.getFormat().getFrameSize();    byte audioBytes[] = out.toByteArray();        AudioInputStream audioInputStream = new               AudioInputStream(new ByteArrayInputStream(out.toByteArray()),                       line.getFormat(),                        audioBytes.length / frameSizeInBytes);        ByteArrayOutputStream byos = new ByteArrayOutputStream();        AudioSystem.write(audioInputStream,           AudioFileFormat.Type.WAVE, byos);        audioInputStream.close();        return byos;}

</pre><p><strong>Kommunikation mit DeepSpeech</strong></p><p>Nachdem nun die WAV-Datei als

ByteArrayOutputStream

vorliegt, l&#228;sst sich eine Verbindung zum DeepSpeech Server aufbauen und die Datei dorthin senden:</p><pre class=„rtetx–listing listing“><code>private String sendDataToServer(ByteArrayOutputStream byos) throws IOException, ClientProtocolException { HttpClient httpclient = HttpClients.createDefault(); HttpPost httppost = new HttpPost(SERVERADRESS); ByteArrayEntity bae = new ByteArrayEntity(byos.toByteArray()); httppost.setEntity(bae); HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); if (entity != null) { try (InputStream instream = entity.getContent()) { return IOUtils.toString(instream, „UTF-8“); } } return „Kein Ergebnis“;}</code></pre><p>Die gezeigte Methode baut zun&#228;chst eine Serververbindung auf und setzt anschlie&#223;end einen <code>Post</code>-Befehl ab. Die Serveradresse sieht beispielsweise so aus: <em>http://localhost:8080/stt</em>.</p><p>Das zuvor erstellte <code>ByteArray</code> wird nun in eine Entity verpackt und an den Server gesendet. Zum Abschluss erfolgt das Auslesen der zur&#252;ckgegebenen Response.</p><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>DeepSpeech-Ergebnis von „Hallo Welt“ (Abb. 6)</figcaption></div></figure><figure class=„a-inline-image a-u-inline“><div><figcaption class=„a-caption“>Eclipse Konsolenausgabe von „Hallo Welt“ (Abb. 7)</figcaption></div></figure><h3 class=„subheading“ id=„nav_fazit_und7“>Fazit und Ausblick</h3><p>Der hier vorgestellte Prozess ist nur ein Ausschnitt von dem, was mit DeepSpeech m&#246;glich ist. Der eigene Sprachassistent des Autors ist mittlerweile in der vierten Iteration und erm&#246;glicht es ihm, das Licht zu steuern, Termine aus dem Kalender abzufragen und YouTube zu nutzen.</p><p>Problematisch sind englische Begriffe und Worte, die &#228;hnlich klingen. Auch wurde hier bewusst das Reagieren auf unterschiedliche Lautst&#228;rkepegel vernachl&#228;ssigt. Mit dem Audiodispatcher und Silencelistener der Tarsos-Bibliothek l&#228;sst sich diese Problematik l&#246;sen, da der Sprachassistent erst dann reagiert, wenn ein bestimmter Lautst&#228;rkepegel &#252;berschritten wird und auch erst dann aufh&#246;rt zuzuh&#246;ren, wenn dieser Pegel wieder unterschritten wird. Damit ist eine fixe Zeitangabe f&#252;r das Zuh&#246;ren nicht mehr notwendig.</p><p>Unber&#252;cksichtigt blieben eigene Sprachmodelle. Es besteht auch die M&#246;glichkeit, eigene W&#246;rter oder eigene Modelle zu entwickeln und mit TensorFlow zu trainieren. Dabei lassen sich Entfernungen zum Mikrofon oder Umgebungsger&#228;usche kompensieren. Die M&#246;glichkeiten sind grenzenlos und stehen den g&#228;ngigen Sprachassistenten auf dem aktuellen Markt in nichts nach. Mit diesem Vorgehen lassen sich die Sprachkompetenzen von DeepSpeech auch f&#252;r Java nutzen und nicht mehr nur f&#252;r Python.</p><p>Der vorgestellte Code <a href=„https://github.com/PMO-IT“ rel=„external noopener“ target=„_blank“><strong>findet sich auf GitHub [6]</strong></a>. Auf dem <a href=„http://pmo-it.de/blog/“ rel=„external noopener“ target=„_blank“><strong>eigenen Blog zeigt der Autor [7]</strong></a> unter anderem die M&#246;glichkeiten Philips Hue Leuchten mit Java zu steuern. F&#252;r den Sommer plant er seinen Sprachassistenten auf GitHub zur Verf&#252;gung zu stellen.</p><p><em>Pascal Moll<br />ist freiberuflicher Berater und Java-Entwickler. Seine Schwerpunkte liegen im Bereich des Test-Managements und Testautomatisierung von Web - und Desktopapplikationen insbesondere SAP. Neben seiner Beratert&#228;tigkeit arbeitet er auch als freiberuflicher Trainer f&#252;r Java, Cucumber und Selenium Schulungen. Mehr Informationen finden sich auf <a href=„https://pmo-it.de“ rel=„external noopener“ target=„_blank“><strong>https://pmo-it.de [8]</strong></a>.</em></p><p>() </p><hr /><p><strong>URL dieses Artikels:</strong><br /><small>

https://www.heise.de/-6048698

</small></p><p><strong>Links in diesem Artikel:</strong><br /><small>

<strong>[1]</strong>&#160;https://www.heise.de/meldung/Fast-jeder-Dritte-in-Deutschland-nutzt-Sprachassistenten-4443365.html

</small><br /><small>

<strong>[2]</strong>&#160;https://arxiv.org/abs/1412.5567

</small><br /><small>

<strong>[3]</strong>&#160;https://deepspeech.readthedocs.io/en/r0.9/

</small><br /><small>

<strong>[4]</strong>&#160;https://github.com/mozilla/DeepSpeech/releases

</small><br /><small>

<strong>[5]</strong>&#160;https://drive.google.com/drive/folders/1oO-N-VH_0P89fcRKWEUlVDm-_z18Kbkb

</small><br /><small>

<strong>[6]</strong>&#160;https://github.com/PMO-IT

</small><br /><small>

<strong>[7]</strong>&#160;http://pmo-it.de/blog/

</small><br /><small>

<strong>[8]</strong>&#160;https://pmo-it.de

</small><br /><small>

<strong>[9]</strong>&#160;mailto:mdo@ix.de

</small><br /></p><p class=„printversion__copyright“><em>Copyright &#169; 2021 Heise Medien</em></p> </html>

Cookies helfen bei der Bereitstellung von Inhalten. Diese Website verwendet Cookies. Mit der Nutzung der Website erklären Sie sich damit einverstanden, dass Cookies auf Ihrem Computer gespeichert werden. Außerdem bestätigen Sie, dass Sie unsere Datenschutzerklärung gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information