Beruflich Dokumente
Kultur Dokumente
Noch wichtiger ist wohl die Notwendigkeit, neben der Globalisierung auch Informationen zu
demokratisieren. Unabhängig von Ihrer gesprochenen Sprache sollten Sie Zugriff auf dieselben
Open-Source-Veröffentlichungen, Gesundheitsinformationen, Tools und Kenntnisse haben wie
diejenigen, deren Hauptsprache weit verbreitet ist, wie z. B. Englisch.
Ich habe das in Powerpoint gemacht. Es ist schrecklich.
Glücklicherweise gibt es maschinelle Übersetzungen schon seit einiger Zeit - viele von uns haben
Google Übersetzer verwendet, um den Inhalt von etwas online zu bestätigen oder einfach nur
intelligent und weltlich zu klingen. Wenn Sie Übersetzungsanforderungen haben, die eine
Skalierung erfordern, verfügen Azure, AWS und GCP über Verbrauchs-APIs für nur 10 US-
Dollar pro Million Zeichen, die Tausende von Sprachpaaren unterstützen (ein Paar besteht aus
einer Ausgangssprache und einer Zielsprache).
In jüngerer Zeit veröffentlichte Huggingface über 1.000 vorgefertigte Sprachmodelle von der
Universität Helsinki . Für alle, die ihre eigene AWS- oder Google Übersetzungs-API erstellen
möchten, war es nie einfacher. Also dachte ich mir, ich würde von der harten Arbeit anderer
profitieren. Dies ist das funktionale Äquivalent von "Lassen Sie uns maschinelles Lernen in eine
Kolben-API und ein Docker-Image einwickeln", aber was auch immer, es macht Spaß. Machen
wir das.
Dadurch wird das erforderliche Modell heruntergeladen und der Quelltext -> Zieltext übersetzt.
Mit der schieren Menge an unterstützten Sprachen, die in diesem Format verfügbar sind, ist es
super einfach, dies in eine Docker-Flask-App zu werfen und es einen Tag zu nennen, aber wir
müssen zuerst ein bisschen zusätzliche Arbeit erledigen ...
Um dies zu umgehen, können wir den Modelldownload separat behandeln und die Modelle als
Volume bereitstellen. Dies gibt uns auch mehr Kontrolle über die Sprachen, die unser Service
von Anfang an unterstützen soll. Huggingface hostet alle erforderlichen Dateien in S3, sodass wir
dies einfach standardisieren können…
HUGGINGFACE_S3_BASE_URL="https://s3.amazonaws.com/models.huggingface.co/bert/He
lsinki-NLP"
FILENAMES =
["config.json","pytorch_model.bin","source.spm","target.spm","tokenizer_config.json","vocab.j
son"]
MODEL_PATH = "data"
import os
import argparse
import urllib
from urllib.request import urlretrieve
from config import *
parser = argparse.ArgumentParser()
parser.add_argument('--source', type=str, help='source language code')
parser.add_argument('--target', type=str, help='sum the integers (default: find the max)')
def download_language_model(source,target):
model = f"opus-mt-{source}-{target}"
print(">>>Downloading data for %s to %s model..." % (source, target))
os.makedirs(os.path.join("data",model))
for f in FILENAMES:
try:
print(os.path.join(HUGGINGFACE_S3_BASE_URL,model,f))
urlretrieve(os.path.join(HUGGINGFACE_S3_BASE_URL,model,f),
os.path.join(MODEL_PATH,model,f))
print("Download complete!")
except urllib.error.HTTPError:
print("Error retrieving model from url. Please confirm model exists.")
os.rmdir(os.path.join("data",model))
break
if __name__ == "__main__":
args = parser.parse_args()
download_language_model(args.source, args.target)
Cool. Jetzt können wir die benötigten Modelle mit einem einzigen Befehl herunterladen. Nehmen
Sie das folgende Beispiel für Japanisch -> Englisch.
Dadurch werden sie in ein Verzeichnis heruntergeladen, das datastandardmäßig aufgerufen wird.
Überprüfen Sie daher, ob sie vorhanden sind.
Dynamische Sprachübersetzung in Python
Nachdem wir nun eine bessere Möglichkeit haben, die von uns unterstützten Sprachen zu
verwalten, kommen wir zum Kern des Problems, dann zu einer Klasse und den dazugehörigen
Methoden zur Verwaltung unserer Übersetzungen.
Diese Klasse wird mit dem Pfad initialisiert, den wir zum Speichern von Modellen verwenden,
und behandelt den Rest selbst. Wenn wir eine Übersetzungsanforderung erhalten und dieses
Modell nicht im Speicher haben, load_modelswird es aufgerufen, um es in das
self.modelsWörterbuch zu laden . Überprüfen Sie unser dataVerzeichnis, um festzustellen, ob
wir dieses Modell haben, und geben Sie eine Nachricht zurück, um uns mitzuteilen, ob wir dies
tun oder nicht.
import os
from flask import Flask, request, jsonify
from translate import Translator
from config import *
app = Flask(__name__)
translator = Translator(MODEL_PATH)
app.config["DEBUG"] = True # turn off in prod
@app.route('/', methods=["GET"])
def health_check():
"""Confirms service is running"""
return "Machine translation service is up and running."
@app.route('/lang_routes', methods = ["GET"])
def get_lang_route():
lang = request.args['lang']
all_langs = translator.get_supported_langs()
lang_routes = [l for l in all_langs if l[0] == lang]
return jsonify({"output":lang_routes})
@app.route('/supported_languages', methods=["GET"])
def get_supported_languages():
langs = translator.get_supported_langs()
return jsonify({"output":langs})
@app.route('/translate', methods=["POST"])
def get_prediction():
source = request.json['source']
target = request.json['target']
text = request.json['text']
translation = translator.translate(source, target, text)
return jsonify({"output":translation})
app.run(host="0.0.0.0")
Um es zu verwenden, führen Sie es einfach aus python app.pyund rufen Sie den Dienst an. Um
zu überprüfen, ob es funktioniert, können Sie curl localhost:5000etwas Anspruchsvolleres
wie Postman verwenden oder verwenden. Ich verwende hier den Flask-Server, aber Sie möchten,
dass ein Produktions-Webserver diesen überall real verwendet.
Normalerweise würde ich ein kleineres Basis-Image verwenden, aber ehrlich gesagt hatte ich
keine Lust zum Debuggen:
FROM python:3.6
WORKDIR /app
# install requirements first for caching
COPY requirements.txt /app
RUN pip install -r requirements.txt
COPY . /app
CMD python app.py
Ich habe meinen Service in eine kleine Kolben-API verpackt und ihn sogar „richtig“ zu einem
Docker-Container gemacht, der reproduzierbar skaliert werden kann. Ich möchte jedoch einige
Bedenken zu diesem Ansatz äußern.
Diese Übersetzungsmodelle sind ziemlich groß (wie in jedem ist wie 300 MB). Selbst wenn die
Daten / Modelle separat heruntergeladen werden, müssen wir jedes einzelne Sprachpaar, das wir
unterstützen möchten, in den Speicher laden - und das wird für einen einzelnen Container schnell
außer Kontrolle geraten.
Warum also nicht ein konfigurierbares Image erstellen, mit dem wir mithilfe von Docker-
Compose einen Container für jeden Dienst hochfahren können? Auf diese Weise gibt es einen
Dienst pro Sprachpaar, und jedes Paar kann bei steigender Nachfrage individuell skaliert werden.
Anschließend können wir eine einzelne, exponierte API schreiben, die Anforderungen an alle
Container im Netzwerk weiterleitet.
Haftungsausschluss: Zu diesem Zeitpunkt habe ich gerade erst angefangen, es zu erfinden, und
ich bin keineswegs davon überzeugt, dass dies der optimale Ansatz war - aber ich wollte sehen,
wie weit ich es bringen kann.
Zum Auftakt habe ich das Verzeichnis etwas überarbeitet. Um es herauszufinden, kannst du den
Zweig auf Git erkunden, den ich gemacht habe:
.
├── LICENSE
├── README.md
├── docker-compose.yaml
├── proxy
│ ├── Dockerfile
│ ├── app.py
│ └── requirements.txt
└── translation_base
├── Dockerfile
├── app.py
├── config.py
├── download_models.py
├── requirements.txt
└── translate.py
version: '3.3'
services:
translation_proxy:
build:
context: ./proxy
environment:
- MODEL_PATH=data
command: python app.py
ports:
- "5000:5000"
en_fr:
image: translation_base
environment:
- MODEL_PATH=data
- SOURCE_LANG=en
- TARGET_LANG=fr
command: python app.py
volumes:
- ./data:/app/data
fr_en:
image: translation_base
environment:
- MODEL_PATH=data
- SOURCE_LANG=fr
- TARGET_LANG=en
command: python app.py
volumes:
- ./data:/app/data
volumes:
data
Jeder Übersetzungsdienst hat dieselben env-Variablen (ich sollte wahrscheinlich nur eine
.envDatei erstellen), denselben Befehl und dasselbe Volume, das unsere Modelle enthält. Es gibt
wahrscheinlich einen besseren Weg, dies mit yamlAutomatisierung oder ähnlichem zu skalieren,
aber ich bin noch nicht dort angekommen.
Danach mache ich nur noch einige hässliche Arbeiten am /translateEndpunkt meines Proxys,
um den angeforderten Service-Endpunkt bei Bedarf zu erstellen. Wenn Benutzer Anforderungen
an diesen exponierten Dienst stellen, wird eine weitere Anforderung an andere Container
gesendet, die nur innerhalb dieses Netzwerks erreichbar sind.
@app.route('/translate', methods=["POST"])
def get_prediction():
source = request.json['source']
target = request.json['target']
text = str(request.json['text'])
route = f'{source}_{target}'
headers = {
'Content-Type': 'application/json'
}
r = requests.post(f"http://machine-translation-service_{route}_1:5000/translate",
headers = headers,
json={"text":text})
translation = str(r.content)
return jsonify({"output":translation})
cd translation_base
docker build -t translation_base
docker-compose up
Endlich Kubernetes
Ich werde hier nicht näher darauf eingehen, aber der logische nächste Schritt wäre, dies zu
Kubernetes zu bringen, um eine echte Skalierung zu erreichen. Ein einfacher Ausgangspunkt ist
die Verwendung der komposeCLI, um Docker-Compose in Kubernetes YAML umzuwandeln.
Unter macOS:
$brew install kompose
$kompose convert
INFO Kubernetes file "translation-proxy-service.yaml" created
INFO Kubernetes file "en-fr-deployment.yaml" created
INFO Kubernetes file "en-fr-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "fr-en-deployment.yaml" created
INFO Kubernetes file "fr-en-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "translation-proxy-deployment.yaml" created
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.21.0 ()
creationTimestamp: null
labels:
io.kompose.service: fr-en
name: fr-en
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: fr-en
strategy:
type: Recreate
template:
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.21.0 ()
creationTimestamp: null
labels:
io.kompose.service: fr-en
spec:
containers:
- args:
- python
- app.py
env:
- name: MODEL_PATH
value: data
- name: SOURCE_LANG
value: fr
- name: TARGET_LANG
value: en
image: translation_base
imagePullPolicy: ""
name: fr-en
resources: {}
volumeMounts:
- mountPath: /app/data
name: fr-en-claim0
restartPolicy: Always
serviceAccountName: ""
volumes:
- name: fr-en-claim0
persistentVolumeClaim:
claimName: fr-en-claim0
status: {}
Sobald Sie einen konfigurierten Kubernetes-Cluster haben, können Sie kubectl apply -f
$FILENAMEIhre Dienste, Bereitstellungen und dauerhaften Volumenansprüche erstellen.
Natürlich gibt es mehr zu tun und noch mehr Kubernetes-Objekte zu erstellen, aber ich wollte
hier einen einfachen Starter für alle bereitstellen, die tatsächlich etwas Ähnliches skalieren
möchten.
Fazit
Ich hoffe, dass die Tools, die Huggingface weiter entwickelt (zusammen mit den Modellen, die
engagierte Forscher trainieren), weiterhin einen gerechten Zugang zu intelligentem maschinellem
Lernen bieten. Die Bemühungen um eine offene maschinelle Übersetzung tragen nicht nur zum
Forschungsbereich bei, sondern ermöglichen den weltweiten Zugang zu äußerst wichtigen
Ressourcen, die in einer einzigen Sprache verfasst sind.
Ich habe keine Ahnung, ob das Hosten dieser massiven Modelle selbst halb so billig ist wie die
Verwendung einer AWS- oder Google Translate-API, und ich habe auch die Qualität nicht
untersucht. Aber es hat großen Spaß gemacht, sich darauf einzulassen, und bietet hoffentlich
einen Einblick in das, was Sie mit den Tausenden von SOTA-Modellen für maschinelles Lernen
erstellen können, die Ihnen zur Verfügung stehen.