Dieser Artikel ist der zweite Tagesartikel von ABEJA Adventskalender 2019.
Im letztjährigen ABEJA Platform Advent Calendar heißt es: "[Zusammenfassung der ABEJA Platform-Zertifizierung](https://qiita.com/ishikawa@github/items/ Ich habe die Authentifizierung von API-Aufrufen in ABEJA Platform unter dem Titel "150a0705d9581c1000c6)" eingeführt, aber ich habe sie auch in diesem Jahr in ABEJA Platform-Material geschrieben.
Leider unterstützt die ABEJA-Plattform Elixir nicht, sodass der gesamte Code in Python geschrieben ist.
Gepostet im Juli 2019 von @yushin_n "[ABEJA-Plattform + Cloud-Funktionen + LINE-Bot zum Erstellen einer App für maschinelles Lernen](https: // qiita. com / yushin_n / items / 0d115efa705579a53cfe) "
Das Thema war, durch Kombinieren eine serverlose App für maschinelles Lernen zu erstellen.
Dieses Mal werde ich das Verfahren zur Verbesserung dieser App für maschinelles Lernen vorstellen und ** LINE Bot nur auf der ABEJA-Plattform ohne Verwendung von Google Cloud-Funktionen entwickeln **.
Zu diesem Zweck werden in diesem Artikel die folgenden drei Funktionen der ABEJA-Plattform verwendet:
Die ABEJA-Plattform ist grob unterteilt in 18.10 und 19.x series. Wir bieten zwei Arten von Bildern an (/model-handler-19.04/). In der 19.x-Serie werden nicht nur neuere Bibliotheken und Frameworks installiert, sondern auch die Implementierungsmethode der API für maschinelles Lernen wurde überarbeitet, damit eine flexiblere Verarbeitung implementiert werden kann.
Die ABEJA-Plattform bietet Lern- und Inferenzvorlagen für einige maschinelle Lernaufgaben. Mit dieser Vorlage können Sie nicht nur Modelle für maschinelles Lernen lernen und ableiten, ohne eine einzige Codezeile zu schreiben, sondern sie eignet sich auch für die Geschäftsdomäne (diesmal LINE-Bot für die Bildklassifizierung), die Sie durch Ändern des Codes implementieren möchten. Kann verbessert werden.
Sie können die Authentifizierungsmethode für die bereitgestellte API auswählen. Sie können nicht nur zwischen integrierter Benutzerauthentifizierung und API-Schlüsselauthentifizierung wählen, sondern auch die Authentifizierung selbst deaktivieren und Ihre eigene Verarbeitung implementieren. Die LINE-Bot-Implementierung verwendet diese Funktion, um die Authentifizierung zur Signaturüberprüfung zu implementieren.
In "Modell des maschinellen Lernens ohne Programmierung mit der ABEJA-Plattformvorlage lernen" wurde das Netzwerktraining bereits abgeschlossen und die daraus resultierenden Parameter Wird als "Modell" der ABEJA-Plattform gespeichert.
Ich möchte den Inferenzcode nicht von Grund auf neu schreiben, daher werde ich den Code in der Inferenzvorlage der ABEJA-Plattform ändern. In der Inferenzvorlage
Da die Verarbeitung implementiert ist, sollten Sie hier die für den LINE-Bot spezifische Verarbeitung hinzufügen (Details werden später beschrieben).
Um den Code für die Inferenzvorlage zu generieren, müssen Sie eine "Bereitstellung" erstellen, bei der es sich um den Container handelt, der den Code (und die bereitgestellten Dienste) verwaltet. Erstellen Sie eine neue Bereitstellung über die Schaltfläche "Bereitstellung erstellen" im Bildschirm Bereitstellungsliste.
Die neu erstellte Bereitstellung sollte als "0-Modellversion" aufgeführt sein. Über diesen Link gelangen Sie zum Codeverwaltungsbildschirm.
Auf dem Bildschirm Codeverwaltung können Sie den Code, der zu dieser Bereitstellung gehört, versionieren. Erstellen Sie sofort eine neue Codeversion unter "Version erstellen" oben rechts.
Dieses Mal möchte ich den Code der Vorlage ändern, also wählen Sie "Vorlage" auf der Registerkarte und wählen Sie "Bildklassifizierung (CPU)".
Dies ist die neu erstellte Codeversion "0.0.1". Klicken Sie auf den Link, um zum einzelnen Bildschirm zu gelangen.
Sie können die Quellcode-Zip-Datei über den Link "Download" auf dem einzelnen Bildschirm der Codeversion herunterladen.
Wenn Sie die heruntergeladene Zip-Datei entpacken, sollte eine Verzeichnisstruktur wie die folgende angezeigt werden.
$ ls -l
total 96
-rw-r--r--@ 1 user staff 1068 10 30 01:31 LICENSE
-rw-r--r--@ 1 user staff 4452 10 30 01:31 README.md
-rw-r--r--@ 1 user staff 1909 10 30 01:31 predict.py
-rw-r--r--@ 1 user staff 12823 10 30 01:31 preprocessor.py
-rw-r--r--@ 1 user staff 82 10 30 01:31 requirements-local.txt
-rw-r--r--@ 1 user staff 25 10 30 01:31 requirements.txt
-rw-r--r--@ 1 user staff 4406 10 30 01:31 train.py
drwxr-xr-x@ 6 user staff 192 10 30 01:31 utils
Lesen Sie den Originalartikel und fügen Sie die erforderlichen Bibliotheken zu require.txt
hinzu.
line-bot-sdk
googletrans
...
Und Predict.py
ist eine Datei, die die Inferenzverarbeitung implementiert. Hier ist jedoch die für den LINE-Bot erforderliche Verarbeitung.
Es ist notwendig, zusätzlich zu implementieren.
Setzen Sie zuerst die Datei "Predict.py", wenn diese Implementierungen abgeschlossen sind. Wir ändern die "Handler" -Funktion, die der Einstiegspunkt für die Anfrage ist.
import os
import io
import linebot
import linebot.exceptions
import linebot.models
import googletrans
from keras.models import load_model
import numpy as np
from PIL import Image
from preprocessor import preprocessor
from utils import set_categories, IMG_ROWS, IMG_COLS
# Initialize model
model = load_model(os.path.join(os.environ.get(
'ABEJA_TRAINING_RESULT_DIR', '.'), 'model.h5'))
_, index2label = set_categories(os.environ.get(
'TRAINING_JOB_DATASET_IDS', '').split())
# (1) Get channel_secret and channel_access_token from your environment variable
channel_secret = os.environ['LINE_CHANNEL_SECRET']
channel_access_token = os.environ['LINE_CHANNEL_ACCESS_TOKEN']
line_bot_api = linebot.LineBotApi(channel_access_token)
parser = linebot.WebhookParser(channel_secret)
def decode_predictions(result):
result_with_labels = [{"label": index2label[i],
"probability": score} for i, score in enumerate(result)]
return sorted(result_with_labels, key=lambda x: x['probability'], reverse=True)
def handler(request, context):
headers = request['headers']
body = request.read().decode('utf-8')
# (2) get X-Line-Signature header value
signature = next(h['values'][0]
for h in headers if h['key'] == 'x-line-signature')
try:
# parse webhook body
events = parser.parse(body, signature)
for event in events:
# initialize reply message
text = ''
# if message is TextMessage, then ask for image
if event.message.type == 'text':
text = 'Bitte senden Sie mir ein Bild!'
# (3) if message is ImageMessage, then predict
if event.message.type == 'image':
message_id = event.message.id
message_content = line_bot_api.get_message_content(message_id)
img_io = io.BytesIO(message_content.content)
img = Image.open(img_io)
img = img.resize((IMG_ROWS, IMG_COLS))
x = preprocessor(img)
x = np.expand_dims(x, axis=0)
result = model.predict(x)[0]
sorted_result = decode_predictions(result.tolist())
# translate english label to japanese
label_en = sorted_result[0]['label']
translator = googletrans.Translator()
label_ja = translator.translate(label_en.lower(), dest='ja')
prob = sorted_result[0]['probability']
# set reply message
text = f'{int(prob*100)}%Mit einer Wahrscheinlichkeit von{label_ja.text}ist!'
line_bot_api.reply_message(
event.reply_token,
linebot.models.TextSendMessage(text=text))
except linebot.exceptions.InvalidSignatureError:
raise context.exceptions.ModelError('Invalid signature')
return {
'status_code': 200,
'content_type': 'text/plain; charset=utf8',
'content': 'OK'
}
Die Teile, die sich auf die Implementierung des LINE-Bots beziehen, sind in den Kommentaren nummeriert. Schauen wir uns das Schritt für Schritt an. Der andere als der hier beschriebene Code ist die Inferenzvorlage und der Originalartikel wie er ist.
# (1) Get channel_secret and channel_access_token from your environment variable
channel_secret = os.environ['LINE_CHANNEL_SECRET']
channel_access_token = os.environ['LINE_CHANNEL_ACCESS_TOKEN']
line_bot_api = linebot.LineBotApi(channel_access_token)
parser = linebot.WebhookParser(channel_secret)
Hier verwenden wir das LINE Bot SDK, um den API-Client und den Nachrichten-Parser zu initialisieren. Es wird angenommen, dass die für die Initialisierung erforderlichen Parameter (privater Schlüssel und Zugriffstoken) als Umgebungsvariablen übergeben werden.
# (2) get X-Line-Signature header value
signature = next(h['values'][0]
for h in headers if h['key'] == 'x-line-signature')
try:
# parse webhook body
events = parser.parse(body, signature)
Überprüfen Sie die im HTTP-Anforderungsheader übergebene Signatur "X-Line-Signature" mit dem SDK. Der HTTP-Anforderungsheader wird in dem an die Handlerfunktion übergebenen "request" -Dikt gespeichert.
# (3) if message is ImageMessage, then predict
if event.message.type == 'image':
message_id = event.message.id
message_content = line_bot_api.get_message_content(message_id)
img_io = io.BytesIO(message_content.content)
img = Image.open(img_io)
img = img.resize((IMG_ROWS, IMG_COLS))
Ruft den Inhalt der Nachricht ab und konvertiert sie in ein PIL-Image-Objekt.
Lassen Sie uns nun den resultierenden Quellcode in eine neue Codeversion komprimieren.
Zeigen Sie im vorherigen Codeverwaltungsbildschirm den Bildschirm zur Erstellung der neuen Codeversion an und laden Sie die Zip-Datei hoch. Setzen Sie zu diesem Zeitpunkt die Laufzeit (Container-Image) auf "** abeja-inc / all-cpu: 19.10 **" und legen Sie die erforderlichen Umgebungsvariablen fest.
Stellen Sie die API wie unter "Bereitstellen eines maschinellen Lernmodells ohne Programmierung mit ABEJA Platform-Vorlagen" beschrieben bereit. Wiederholen Sie sie daher nicht. Hmm.
Wie ich zu Beginn erklärt habe, habe ich jedoch einen neuen Endpunkt erstellt, um die Anforderung vom LINE-Bot ohne "Authentifizierung" weiterzuleiten.
Sie können die URL des neu erstellten Endpunkts über das Schülersymbol in der Serviceliste überprüfen.
Es sollte das Format "https: // {ORGANIZATION_NAME} .api.abeja.io / deployments / {DEPLOYMENT_ID}" haben. Registrieren Sie dies als LINE Bot Webhook.
Um den Vorgang zu überprüfen, habe ich einige Fotos auf dem LINE-Bot gepostet, den ich dieses Mal erstellt habe. [^ 1]
Unabhängig von der Wahrheit des Ergebnisses scheint es als (?) LINE-Bot zu funktionieren.
[^ 1]: Die Fotos, die ich für diesen Beitrag verwendet habe, sind wie folgt. Sonnenblume von Aiko, Thomas & Juliette + Isaac, [Rose von Waldemar Jan](https://www.flickr.com/photos/128905059@ N02 / 22138314909 /), Blumenkohl von Liz West
Recommended Posts