OCR auf Edge Compute
Auf dieser Seite
Moderne Technik ist inzwischen alltäglich geworden, und Computer Vision gilt als unverzichtbares Werkzeug mit vielen Einsatzgebieten.
Sie erkennt Objekte, Muster, Menschen, Pflanzen und Haustiere, liefert Nutzern nützliche Einblicke, hilft bei Entscheidungen und macht es leichter, riesige Datenmengen zu durchforsten.
Dazu kommt der wachsende Bedarf an Echtzeitanalyse und niedrigen Latenzen. Edge Compute ist deshalb der beste Ort, um dein trainiertes Modell auszuliefern.
Was ist OCR?
Optical Character Recognition (OCR) wandelt Bilder von Text in maschinenlesbaren Text um. Üblicherweise macht man damit aus Bildern von Dokumenten Text, den man durchsuchen und indexieren kann.
Du kannst damit Dokumente, Quittungen, Visitenkarten und mehr einlesen. Bei Blinq siehst du sofort, warum das nützlich ist.
Was ist Edge Compute?
Edge Compute heißt, deinen Code so nah wie möglich beim Nutzer auszuführen. Meist läuft er dafür auf einem CDN, etwa Cloudflare Workers oder AWS Lambda@Edge.
Bei klassischer Cloud-Compute läuft dein Code dagegen in einem Rechenzentrum, das meist weit vom Nutzer entfernt steht.
Warum Edge Compute?
Du kannst dein Modell auch auf dem Gerät laufen lassen. Am Edge hat es trotzdem ein paar Vorteile:
- Niedrige Latenz: Das Modell sitzt näher am Nutzer, die Antwort kommt schneller. Es fühlt sich an, als läge es auf dem Gerät.
- Niedrige Kosten: Du zahlst nicht für Rechenressourcen, um das Modell zu betreiben, sondern nur für die Anfragen.
- Einfach zu aktualisieren: Du kannst das Modell tauschen, ohne die App zu aktualisieren. Das hilft besonders, wenn viele Nutzer ältere App-Versionen haben.
Bei Blinq pflegen wir einen langen Schwanz an mobilen App-Versionen. Das Modell ohne App-Update austauschen zu können, ist für uns ein riesiger Gewinn.
So lässt du dein Modell am Edge laufen
Edge-Runtimes wie Cloudflare Workers und Lambda@Edge unterscheiden sich stark von klassischen Runtimes wie Node.js und Golang. Sie sind auf Geschwindigkeit und geringes Gewicht ausgelegt, deshalb haben sie nicht dieselben Bibliotheken und APIs.
Sie ähneln eher dem Code im Browser. Du kannst deinen Code also nicht einfach kopieren und erwarten, dass er läuft.
Das Modell
Für dieses Beispiel nehme ich ein einfaches OCR-Modell: Keras OCR. Es ist ein TensorFlow-Modell, das ein Bild entgegennimmt und den darin gefundenen Text zurückgibt.
Außerdem setze ich auf Cloudflares Feature Constellation (in der Beta). Damit kannst du ONNX-Modelle am Edge ausführen. Das ist eine gute neue Option, weil du so Modelle laufen lassen kannst, die TensorFlow.js nicht unterstützt, und das 10-MB-Limit für Cloudflare Workers nicht greift.
Lambda@Edge hat deutlich höhere Limits. Trotzdem lohnt es sich, das Modell so klein wie möglich zu halten, um den Cold Start zu verkürzen.
Für dieses Beispiel habe ich das Modell crnn_kurapan verwendet, das du hier findest.
Keras in ONNX umwandeln
Zuerst wandelst du das Keras-Modell in ONNX um. Das ist ziemlich einfach, braucht aber ein paar Schritte. Ich gehe davon aus, dass Conda installiert ist und du Python 3.10 nutzt.
Auf Apple Silicon brauchst du zusätzlich:
tensorflow-macos
Lege zuerst eine Conda-Umgebung an.
$ conda create -n edge-onnx python=3.10 pip
$ conda activate edge-onnx
Installiere dann die Abhängigkeiten.
$ python -m tensorflow tf2onnx keras-ocr
Auf Apple Silicon installierst du tensorflow-macos statt tensorflow.
$ python -m pip install tensorflow-macos
Zum Schluss wandelst du das Modell mit diesem Snippet um.
import tf2onnx
import onnx
import keras_ocr
recognition = keras_ocr.recognition.Recognizer(
alphabet='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', weights='kurapan')
output_path = 'crnn_kurapan.onnx'
model_proto, _ = tf2onnx.convert.from_keras(
recognition.model, opset=None, output_path=output_path)
onnx.save(model_proto, output_path)
Damit entsteht im aktuellen Verzeichnis ein ONNX-Modell unter crnn_kurapan.onnx.
Das Modell am Edge ausführen
Um das ONNX-Modell auf Edge Compute auszuführen, nutze ich Cloudflare Constellation, weil das Modell für Cloudflare Workers viel zu groß ist.
Das geht über das Cloudflare-Dashboard oder die CLI. Ich nehme die CLI, weil sie sich leichter automatisieren lässt.
Zuerst legen wir ein Projekt an.
$ npx wrangler constellation project create "ocr" ONNX
$ npx wrangler constellation project list
Notiere dir die Projekt-ID.
Lade als Nächstes das Modell hoch:
$ wrangler constellation model upload ocr crnn_kurapan crnn_kurapan.onnx
$ npx wrangler constellation model list ocr
Notiere dir die Modell-ID.
Dann richtest du das Projekt ein und initialisierst wrangler.
$ npm create cloudflare@2
Ich habe das Projekt ocr genannt und das Template „Hello World“ genommen.
Füge in der Datei wrangler.toml das Constellation-Binding hinzu und aktiviere node_compat.
name = "ocr"
main = "src/index.js"
node_compat = true
workers_dev = true
compatibility_date = "2023-07-01"
constellation = [
{binding = 'OCR', project_id = '{{ project ID from earlier }}'},
]
Installiere abschließend den Constellation-Client samt Abhängigkeiten, um Bilder ins Modell zu streamen.
npm install --save @cloudflare/constellation string-to-stream pngjs
Jetzt schreiben wir den Code, der das Modell ausführt.
import str from 'string-to-stream';
import { PNG } from 'pngjs/browser';
import { Tensor, run } from '@cloudflare/constellation';
const MODEL_ID = '{{ model ID from earlier }}';
function normalizeImage(data) {
return new Promise(async (resolve, reject) => {
const stream = str(data);
const png = new PNG({ filterType: 4 });
stream
.pipe(png)
.on('parsed', function () {
const [r, g, b] = new Array(3).fill([]);
for (let i = 0; i < this.data.length; i += 4) {
r.push(this.data[i] / 255.0);
g.push(this.data[i + 1] / 255.0);
b.push(this.data[i + 2] / 255.0);
}
resolve({
input: [...r, ...g, ...b],
shape: [3, this.height, this.width, 3],
});
})
.on('error', function (error) {
reject({ err: error.toString() });
});
});
}
export default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
const formData = await request.formData();
const image = formData.get('image');
if (!image) {
return new Response('No image found', { status: 400 });
}
const buffer = await image.arrayBuffer();
try {
const normalized = await normalizeImage(buffer);
if (!normalized) {
return new Response('Unable to normalize image', { status: 500 });
}
const input = new Tensor(
'float32',
normalized.shape,
normalized.input,
'input_1'
);
const output = await run(env.OCR, MODEL_ID, input);
return new Response(JSON.stringify(output), { status: 200 });
} catch (err) {
return new Response(err, { status: 500 });
}
},
};
Solange Constellation in der Beta ist, musst du die Warnungen eventuell mit export NO_CONSTELLATION_WARNING=true abschalten.
Wenn du bereit zum Deployen bist, führst du einfach wrangler deploy aus.
Das Modell testen
Jetzt kannst du dem Worker eine HTTP-Anfrage schicken und das Modell testen.
$ curl -X POST -F "
image=@/path/to/image.png" https://ocr.example.workers.dev
Du bekommst eine JSON-Antwort mit der Modellausgabe zurück.
{
"output_1": [...]
}
Die Ausgabe des Modells ist ein Array mit Wahrscheinlichkeiten für jedes Zeichen. Um daraus Text zu machen, kannst du etwas wie dieses Snippet verwenden.
const charset =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const text = output
.map((probabilities) => {
const max = Math.max(...probabilities);
const index = probabilities.indexOf(max);
return charset[index];
})
.join('');
Wozu das Ganze?
Ich wollte wissen, ob sich ein ziemlich großes Modell am Edge betreiben lässt. Und ich wollte sehen, wie gut es sich schlägt.
Dieses Modell kommt wohl kaum in Produktion. Es zeigt aber gut, was mit Cloudflare Workers und Constellation möglich ist. Größere OCR-Modelle sind in der Regel besser, kleinere gehen aber auch, wenn du bei der Genauigkeit Abstriche machst. Dafür kannst du übrigens immer Tesseract.js nehmen.
Performance
Das Modell braucht am Edge etwa 1,5 Sekunden. Das ist viel langsamer als lokal, aber noch schnell genug für die Produktion. In der Praxis kannst du außerdem Angebote von Google und Amazon Web Services nutzen, die deutlich genauer sind. Dafür sind sie auch deutlich teurer.
Genauigkeit
Das Modell ist ziemlich genau, aber nicht perfekt. Bei manchen Schriften hat es Probleme, und Text in Bildern mit viel Rauschen erkennt es schlecht. Außerdem verarbeitet es nur kleine Bilder. Das lässt sich mit einem Sliding Window verbessern.
Probier es selbst aus
Cloudflare entwickelt Constellation aktiv weiter, und es steckt noch in der Beta. Wenn du es ausprobieren willst, kannst du dich hier für die Beta anmelden.
Es gibt auch einen praktischen Discord-Kanal, in dem du Fragen stellen und dir vom Cloudflare-Team helfen lassen kannst.