Engineering

Trainieren, evaluieren, überwachen, inferieren: End-to-End-Machine-Learning in Elastic

Machine-Learning-Pipelines haben sich in den letzten Jahren massiv entwickelt. Dank der Vielzahl unterschiedlicher Tools und Frameworks auf dem Markt, die das Erstellen, Trainieren und Bereitstellen vereinfachen, geht die Entwicklung von Machine-Learning-Modellen heute viel, viel schneller als noch vor wenigen Jahren. Aber trotz all dieser Vereinfachungen sind etliche dieser Tools immer noch mit einer steilen Lernkurve verbunden. Nicht so bei Elastic.

Für die Nutzung von Machine Learning im Elastic Stack müssen Ihre Daten lediglich in Elasticsearch gespeichert sein. Sobald die Daten dort sind, reichen ein paar Klicks in Kibana, und schon erhalten Sie wertvolle Erkenntnisse. Machine Learning ist vollständig in den Elastic Stack integriert, sodass sich voll funktionsfähige End-to-End-Machine-Learning-Pipelines einfach und intuitiv erstellen lassen. Und genau das machen wir im Folgenden.

Warum Elastic?

Elastic ist ein Suchunternehmen und bietet damit allerbeste Voraussetzungen dafür, dass auch große Datenmengen effizient verarbeitet werden können. Für das einfache und intuitive Suchen und Aggregieren von Daten für Analysezwecke steht die Elasticsearch Query DSL zur Verfügung, und zur vielfältigen Visualisierung großer Datensätze kann Kibana verwendet werden. Die Elastic Machine Learning-Benutzeroberfläche vereinfacht das Auswählen von Features und Modellen, das Trainieren von Modellen und das Feinjustieren von Hyperparametern. Und nachdem Sie das Modell trainiert und feinjustiert haben, kann Kibana auch zum Evaluieren und visuellen Überwachen des Modells verwendet werden. Damit ist der Elastic Stack perfekt für alle Aspekte des Machine Learning in Produktionsumgebungen geeignet.

Beispiel-Datensatz: EMBER 2018

Zur Demonstration des End-to-End-Machine-Learnings im Elastic Stack werden wir den Datensatz EMBER verwenden. Dies ist ein Datensatz, den Endgame für die Erkennung von Malware anhand statischer, aus Portable-Executable(PE)-Dateien abgeleiteter Features veröffentlicht hat. Im Rahmen dieser Demonstration greifen wir auf die 2018er-Version des EMBER-Datensatzes zurück (EMBER steht für „Endgame Malware BEnchmark for Research“). Dieser Datensatz ist eine Open-Source-Sammlung von 1 Million Datenproben, wobei jede Datenprobe den sha256-Hash der Datenprobendatei, den Monat, in dem die Datei zuerst aufgetreten ist, ein Label und die aus der Datei abgeleiteten Features enthält. 

Für dieses Experiment werden 300.000 Datenproben (150.000 bösartig und 150.000 gutartig) aus EMBER 2018 ausgewählt. Um überwachtes Lernen auf Basis der Datenproben zu ermöglichen, müssen wir zunächst ein paar Features auswählen. Die Features im Datensatz sind statische Features, die aus dem Inhalt von Binärdateien abgeleitet wurden. Zur Evaluierung der Modell-Performance bei verschiedenen Teilmengen der Features aus EMBER haben wir uns entschieden, mit allgemeinen Informationen, Datei-Header-Informationen und Abschnittsinformationen sowie Zeichenfolgen und Byte-Histogrammen als Features zu experimentieren. 

End-to-End-Machine-Learning im Elastic Stack: Schritt für Schritt

Für diese Demonstration nutzen wir den Python-Elasticsearch-Client, um Daten in Elasticsearch einzufügen, das Elastic-Machine-Learning-Feature „Data Frame Analytics“, um Trainings-Jobs zu erstellen, und Kibana, um die trainierten Modelle visuell zu überwachen. 

Wir werden zwei überwachte Jobs erstellen: einen mit allgemeinen Informationen, Datei-Header-Informationen und Abschnittsinformationen sowie Zeichenfolgen als Features und einen nur mit Byte-Histogrammen als Features. Auf diese Weise können wir das gleichzeitige Trainieren mehrerer Modelle im Stack und das anschließende Visualisieren mehrerer infrage kommender Modelle demonstrieren.

Einrichten einer Elasticsearch-Instanz

Um im Elastic Stack mit Machine Learning arbeiten zu können, müssen wir zunächst Elasticsearch mit einem Machine-Learning-Knoten einrichten. Dazu können wir das Angebot nutzen, Elastic Cloud 14 Tage lang kostenlos auszuprobieren. Für unser Beispiel-Deployment nutzen wir die folgenden Einstellungen:

  • Cloud Platform: Amazon Web Services
  • Region: US West (N. California)
  • Optimization: I/O Optimized
  • Customize Deployment: Enable Machine Learning

Außerdem müssen wir mit dem Python-Elasticsearch-Client API-Schlüssel erstellen und ihnen entsprechende Berechtigungen für die Interaktion mit Elasticsearch zuweisen. Für unsere Demonstration fügen wir Daten in den Index ember_ml ein und erstellen wie folgt einen Schlüssel:

POST /_security/api_key 
{ 
  "name": "my_awesome_key", 
  "role_descriptors": { 
    "role_1": { 
      "cluster": ["all"], 
      "index": [ 
        { 
          "names": ["ember_*"], 
          "privileges": ["all"] 
        } 
      ] 
    } 
  } 
}

Ingestieren von Daten

Nachdem wir unsere Elasticsearch-Instanz eingerichtet haben, beginnen wir damit, Daten in einen Elasticsearch-Index zu ingestieren. Als Erstes erstellen wir einen Index namens ember_ml und ingestieren dann mit dem Python-Elasticsearch-Client die Dokumente, aus denen unser Datensatz besteht, in diesen Index. Mit dem Streaming Bulk Helper werden wir alle für beide Modelle benötigten Features in einen gemeinsamen Index ingestieren. Das ermöglicht ein stapelweises Ingestieren von Dokumenten in Elasticsearch. Der Python-Code zum Erstellen des Index ember_ml und zum stapelweisen Ingestieren von Dokumenten in diesen Index sieht wie folgt aus:

import elasticsearch 
import certifi 
from elasticsearch import Elasticsearch, helpers 
# Lange Liste von Dokumenten, die in Elasticsearch eingefügt werden sollen, mit einem als Beispiel 
documents = [ 
  { 
    "_index": "ember_ml", 
    "_id": "771434adbbfa2ff5740eb91d9deb51828e0f4b060826b590cd9fd8dd46ee0d40", 
    "_source": { 
      "sha256": "771434adbbfa2ff5740eb91d9deb51828e0f4b060826b590cd9fd8dd46ee0d4b", 
      "appeared": "2018-01-06 00:00:00", 
      "label": 1, 
      "byte_0": 0.1826012283563614, 
      "byte_1": 0.006036404054611921, 
      "byte_2": 0.003830794943496585, 
      "byte_3": 0.004225482698529959, 
      "byte_4": 0.004388001281768084, 
      "byte_5": 0.0036218424793332815, 
      "byte_6": 0.0035289747174829245, 
      "byte_7": 0.004666604567319155, 
      "byte_8": 0.004225482698529959, 
      "byte_9": 0.0029253342654556036, 
      "byte_10": 0.0034361069556325674, 
      "byte_11": 0.003993313293904066, 
      "byte_12": 0.004039747174829245, 
      "byte_13": 0.0029253342654556036, 
      "byte_14": 0.0030182020273059607, 
      "byte_15": 0.0036450594197958708, 
      "byte_16": 0.004573736805468798, 
      "byte_17": 0.002693164860829711, 
      "byte_18": 0.002507429337128997, 
      "byte_19": 0.0026699479203671217, 
      "byte_20": 0.003505757777020335, 
      "byte_21": 0.0022056091111153364, 
      "byte_22": 0.0032503714319318533, 
      "byte_23": 0.0025770801585167646, 
      "byte_24": 0.005363112781196833, 
      "byte_25": 0.002600297098979354, 
      "byte_26": 0.0025538632180541754, 
      "byte_27": 0.0031807206105440855, 
      "byte_28": 0.0034593238960951567, 
      "byte_29": 0.0022288260515779257, 
      "byte_30": 0.002507429337128997, 
      "byte_31": 0.0025770801585167646, 
      "byte_32": 0.004921990912407637, 
      "byte_33": 0.0028092495631426573, 
      "byte_34": 0.0017877042992040515, 
      "byte_35": 0.0033664561342447996, 
      "byte_36": 0.002437778515741229, 
      "byte_37": 0.0021359582897275686, 
      "byte_38": 0.0016716195968911052, 
      "byte_39": 0.0020430905278772116, 
      "byte_40": 0.003227154491469264, 
      "byte_41": 0.0025770801585167646, 
      "byte_42": 0.0017644873587414622, 
      "byte_43": 0.0032039375510066748, 
      "byte_44": 0.003296805312857032, 
      "byte_45": 0.003134286729618907, 
      "byte_46": 0.0028324665036052465, 
      "byte_47": 0.003505757777020335, 
      "byte_48": 0.0038772288244217634, 
      "byte_49": 0.0035521916579455137, 
      "byte_50": 0.0031110697891563177, 
      "byte_51": 0.00417904881760478, 
      "byte_52": 0.004225482698529959, 
      "byte_53": 0.0032503714319318533, 
      "byte_54": 0.0035289747174829245, 
      "byte_55": 0.003320022253319621, 
      "byte_56": 0.0030878528486937284, 
      "byte_57": 0.003575408598408103, 
      "byte_58": 0.002182392170652747, 
      "byte_59": 0.0029021173249930143, 
      "byte_60": 0.002344910753890872, 
      "byte_61": 0.0020430905278772116, 
      "byte_62": 0.0015555348945781589, 
      "byte_63": 0.0020198735874146223, 
      "byte_64": 0.004016530234366655, 
      "byte_65": 0.004457652103155851, 
      "byte_66": 0.0036450594197958708, 
      "byte_67": 0.0036218424793332815, 
      "byte_68": 0.0038075780030339956, 
      "byte_69": 0.0033432391937822104, 
      "byte_70": 0.004852340091019869, 
      "byte_71": 0.004039747174829245, 
      "byte_72": 0.00480590621009469, 
      "byte_73": 0.002971768146380782, 
      "byte_74": 0.002693164860829711, 
      "byte_75": 0.0039468794129788876, 
      "byte_76": 0.0036450594197958708, 
      "byte_77": 0.0034361069556325674, 
      "byte_78": 0.0028324665036052465, 
      "byte_79": 0.0028324665036052465, 
      "byte_80": 0.005664933007210493, 
      "byte_81": 0.0029949850868433714, 
      "byte_82": 0.0031110697891563177, 
      "byte_83": 0.004527302924543619, 
      "byte_84": 0.003923662472516298, 
      "byte_85": 0.0029949850868433714, 
      "byte_86": 0.004016530234366655, 
      "byte_87": 0.004573736805468798, 
      "byte_88": 0.004109397996217012, 
      "byte_89": 0.003296805312857032, 
      "byte_90": 0.0033664561342447996, 
      "byte_91": 0.0034593238960951567, 
      "byte_92": 0.0031110697891563177, 
      "byte_93": 0.0022984768729656935, 
      "byte_94": 0.0022288260515779257, 
      "byte_95": 0.002275259932503104, 
      "byte_96": 0.002855683444067836, 
      "byte_97": 0.0035986255388706923, 
      "byte_98": 0.0026699479203671217, 
      "byte_99": 0.0037843610625714064, 
      "byte_100": 0.004364784341305494, 
      "byte_101": 0.004016530234366655, 
      "byte_102": 0.004713038448244333, 
      "byte_103": 0.003505757777020335, 
      "byte_104": 0.005479197483509779, 
      "byte_105": 0.0032503714319318533, 
      "byte_106": 0.00366827636025846, 
      "byte_107": 0.004016530234366655, 
      "byte_108": 0.005061292555183172, 
      "byte_109": 0.005014858674257994, 
      "byte_110": 0.0039468794129788876, 
      "byte_111": 0.004109397996217012, 
      "byte_112": 0.004596953745931387, 
      "byte_113": 0.0021127413492649794, 
      "byte_114": 0.0046433876268565655, 
      "byte_115": 0.004086181055754423, 
      "byte_116": 0.005664933007210493, 
      "byte_117": 0.005293461959809065, 
      "byte_118": 0.0039468794129788876, 
      "byte_119": 0.0038075780030339956, 
      "byte_120": 0.0035289747174829245, 
      "byte_121": 0.004480869043618441, 
      "byte_122": 0.00183413818012923, 
      "byte_123": 0.0032503714319318533, 
      "byte_124": 0.0027163818012923002, 
      "byte_125": 0.002066307468339801, 
      "byte_126": 0.003505757777020335, 
      "byte_127": 0.002252042992040515, 
      "byte_128": 0.0033432391937822104, 
      "byte_129": 0.0032039375510066748, 
      "byte_130": 0.001741270418278873, 
      "byte_131": 0.003923662472516298, 
      "byte_132": 0.003830794943496585, 
      "byte_133": 0.0033664561342447996, 
      "byte_134": 0.0034361069556325674, 
      "byte_135": 0.0014162332518026233, 
      "byte_136": 0.002600297098979354, 
      "byte_137": 0.00304141896776855, 
      "byte_138": 0.0022984768729656935, 
      "byte_139": 0.0037147102411836386, 
      "byte_140": 0.0051773772574961185, 
      "byte_141": 0.003296805312857032, 
      "byte_142": 0.0031575036700814962, 
      "byte_143": 0.0015555348945781589, 
      "byte_144": 0.003064635908231139, 
      "byte_145": 0.002693164860829711, 
      "byte_146": 0.0012304977281019092, 
      "byte_147": 0.0015555348945781589, 
      "byte_148": 0.003830794943496585, 
      "byte_149": 0.0028092495631426573, 
      "byte_150": 0.00208952440880239, 
      "byte_151": 0.0014626671327278018, 
      "byte_152": 0.0026699479203671217, 
      "byte_153": 0.004388001281768084, 
      "byte_154": 0.0019502228824421763, 
      "byte_155": 0.0017644873587414622, 
      "byte_156": 0.004086181055754423, 
      "byte_157": 0.0017180534778162837, 
      "byte_158": 0.003412890015169978, 
      "byte_159": 0.002252042992040515, 
      "byte_160": 0.002507429337128997, 
      "byte_161": 0.002437778515741229, 
      "byte_162": 0.002623514039441943, 
      "byte_163": 0.0022288260515779257, 
      "byte_164": 0.0020430905278772116, 
      "byte_165": 0.0022984768729656935, 
      "byte_166": 0.0017180534778162837, 
      "byte_167": 0.0010911960853263736, 
      "byte_168": 0.002159175230190158, 
      "byte_169": 0.0015091010136529803, 
      "byte_170": 0.003227154491469264, 
      "byte_171": 0.0025770801585167646, 
      "byte_172": 0.0027628156822174788, 
      "byte_173": 0.0029253342654556036, 
      "byte_174": 0.0013697993708774447, 
      "byte_175": 0.001648402656428516, 
      "byte_176": 0.003134286729618907, 
      "byte_177": 0.0016019687755033374, 
      "byte_178": 0.002437778515741229, 
      "byte_179": 0.001927005941979587, 
      "byte_180": 0.0027163818012923002, 
      "byte_181": 0.004016530234366655, 
      "byte_182": 0.003227154491469264, 
      "byte_183": 0.00241456157527864, 
      "byte_184": 0.0025538632180541754, 
      "byte_185": 0.00208952440880239, 
      "byte_186": 0.001648402656428516, 
      "byte_187": 0.002275259932503104, 
      "byte_188": 0.0025538632180541754, 
      "byte_189": 0.0028092495631426573, 
      "byte_190": 0.0021359582897275686, 
      "byte_191": 0.0027395987417548895, 
      "byte_192": 0.0030878528486937284, 
      "byte_193": 0.0027395987417548895, 
      "byte_194": 0.00208952440880239, 
      "byte_195": 0.002878900384530425, 
      "byte_196": 0.0021359582897275686, 
      "byte_197": 0.00208952440880239, 
      "byte_198": 0.0027395987417548895, 
      "byte_199": 0.0019734397064894438, 
      "byte_200": 0.003064635908231139, 
      "byte_201": 0.002066307468339801, 
      "byte_202": 0.0012304977281019092, 
      "byte_203": 0.00183413818012923, 
      "byte_204": 0.003389673074707389, 
      "byte_205": 0.00304141896776855, 
      "byte_206": 0.0029021173249930143, 
      "byte_207": 0.0024609954562038183, 
      "byte_208": 0.0029021173249930143, 
      "byte_209": 0.002507429337128997, 
      "byte_210": 0.0022288260515779257, 
      "byte_211": 0.0019734397064894438, 
      "byte_212": 0.0023913446348160505, 
      "byte_213": 0.0017180534778162837, 
      "byte_214": 0.0032735883723944426, 
      "byte_215": 0.0023216938134282827, 
      "byte_216": 0.003412890015169978, 
      "byte_217": 0.0025538632180541754, 
      "byte_218": 0.002530646277591586, 
      "byte_219": 0.004550519865006208, 
      "byte_220": 0.003320022253319621, 
      "byte_221": 0.002437778515741229, 
      "byte_222": 0.003389673074707389, 
      "byte_223": 0.002855683444067836, 
      "byte_224": 0.0031575036700814962, 
      "byte_225": 0.0018109212396666408, 
      "byte_226": 0.002182392170652747, 
      "byte_227": 0.003737927181646228, 
      "byte_228": 0.0036218424793332815, 
      "byte_229": 0.0014626671327278018, 
      "byte_230": 0.0024609954562038183, 
      "byte_231": 0.002600297098979354, 
      "byte_232": 0.0024609954562038183, 
      "byte_233": 0.0015323179541155696, 
      "byte_234": 0.001137629966251552, 
      "byte_235": 0.004341567400842905, 
      "byte_236": 0.004782689269632101, 
      "byte_237": 0.0024609954562038183, 
      "byte_238": 0.0016716195968911052, 
      "byte_239": 0.0028092495631426573, 
      "byte_240": 0.0036218424793332815, 
      "byte_241": 0.00183413818012923, 
      "byte_242": 0.0035289747174829245, 
      "byte_243": 0.002623514039441943, 
      "byte_244": 0.0022984768729656935, 
      "byte_245": 0.001741270418278873, 
      "byte_246": 0.003296805312857032, 
      "byte_247": 0.003412890015169978, 
      "byte_248": 0.003134286729618907, 
      "byte_249": 0.0023913446348160505, 
      "byte_250": 0.0012304977281019092, 
      "byte_251": 0.0067561292089521885, 
      "byte_252": 0.005943536292761564, 
      "byte_253": 0.0031575036700814962, 
      "byte_254": 0.004480869043618441, 
      "byte_255": 0.038958024233579636, 
      "strings_0": 488, 
      "strings_1": 7.477458953857422, 
      "strings_2": 3649, 
      "strings_3": 0.011784050613641739, 
      "strings_4": 0.0043847630731761456, 
      "strings_5": 0.003562619909644127, 
      "strings_6": 0.005206905771046877, 
      "strings_7": 0.004110715351998806, 
      "strings_8": 0.003014524467289448, 
      "strings_9": 0.003562619909644127, 
      "strings_10": 0.005755001213401556, 
      "strings_11": 0.006029048934578896, 
      "strings_12": 0.003014524467289448, 
      "strings_13": 0.0019183338154107332, 
      "strings_14": 0.010961906984448433, 
      "strings_15": 0.006577144376933575, 
      "strings_16": 0.006851192098110914, 
      "strings_17": 0.008769526146352291, 
      "strings_18": 0.013428336940705776, 
      "strings_19": 0.011784050613641739, 
      "strings_20": 0.012058097869157791, 
      "strings_21": 0.014250479638576508, 
      "strings_22": 0.013428336940705776, 
      "strings_23": 0.01315428875386715, 
      "strings_24": 0.01068785972893238, 
      "strings_25": 0.01315428875386715, 
      "strings_26": 0.012880241498351097, 
      "strings_27": 0.010139764286577702, 
      "strings_28": 0.010413811542093754, 
      "strings_29": 0.0027404767461121082, 
      "strings_30": 0.006029048934578896, 
      "strings_31": 0.004658810794353485, 
      "strings_32": 0.0021923815365880728, 
      "strings_33": 0.0027404767461121082, 
      "strings_34": 0.004110715351998806, 
      "strings_35": 0.005755001213401556, 
      "strings_36": 0.01589476503431797, 
      "strings_37": 0.011784050613641739, 
      "strings_38": 0.01397643145173788, 
      "strings_39": 0.010413811542093754, 
      "strings_40": 0.016168814152479172, 
      "strings_41": 0.015346670523285866, 
      "strings_42": 0.012332146055996418, 
      "strings_43": 0.013428336940705776, 
      "strings_44": 0.01452452689409256, 
      "strings_45": 0.00986571703106165, 
      "strings_46": 0.016442861407995224, 
      "strings_47": 0.014798575080931187, 
      "strings_48": 0.012058097869157791, 
      "strings_49": 0.01068785972893238, 
      "strings_50": 0.010413811542093754, 
      "strings_51": 0.015620717778801918, 
      "strings_52": 0.010139764286577702, 
      "strings_53": 0.013428336940705776, 
      "strings_54": 0.015072622336447239, 
      "strings_55": 0.014250479638576508, 
      "strings_56": 0.011510002426803112, 
      "strings_57": 0.012880241498351097, 
      "strings_58": 0.01397643145173788, 
      "strings_59": 0.012332146055996418, 
      "strings_60": 0.01068785972893238, 
      "strings_61": 0.00931762158870697, 
      "strings_62": 0.00986571703106165, 
      "strings_63": 0.005206905771046877, 
      "strings_64": 0.003014524467289448, 
      "strings_65": 0.003014524467289448, 
      "strings_66": 0.003562619909644127, 
      "strings_67": 0.0043847630731761456, 
      "strings_68": 0.01397643145173788, 
      "strings_69": 0.010413811542093754, 
      "strings_70": 0.017539052292704582, 
      "strings_71": 0.017539052292704582, 
      "strings_72": 0.02000548131763935, 
      "strings_73": 0.016442861407995224, 
      "strings_74": 0.014250479638576508, 
      "strings_75": 0.01452452689409256, 
      "strings_76": 0.01260619331151247, 
      "strings_77": 0.011510002426803112, 
      "strings_78": 0.013428336940705776, 
      "strings_79": 0.014798575080931187, 
      "strings_80": 0.016442861407995224, 
      "strings_81": 0.01452452689409256, 
      "strings_82": 0.017813099548220634, 
      "strings_83": 0.015072622336447239, 
      "strings_84": 0.00931762158870697, 
      "strings_85": 0.01452452689409256, 
      "strings_86": 0.014250479638576508, 
      "strings_87": 0.015620717778801918, 
      "strings_88": 0.014250479638576508, 
      "strings_89": 0.012332146055996418, 
      "strings_90": 0.013702384196221828, 
      "strings_91": 0.01397643145173788, 
      "strings_92": 0.00986571703106165, 
      "strings_93": 0.006303096655756235, 
      "strings_94": 0.004110715351998806, 
      "strings_95": 0.0027404767461121082, 
      "strings_96": 0.0027404767461121082, 
      "strings_97": 0.0024664292577654123, 
      "strings_98": 0.007399287540465593, 
      "strings_99": 6.4175848960876465, 
      "strings_100": 0, 
      "strings_101": 0, 
      "strings_102": 0, 
      "strings_103": 3, 
      "general_info_0": 43072, 
      "general_info_1": 110592, 
      "general_info_2": 0, 
      "general_info_3": 0, 
      "general_info_4": 5, 
      "general_info_5": 0, 
      "general_info_6": 1, 
      "general_info_7": 0, 
      "general_info_8": 0, 
      "general_info_9": 0, 
      "file_header_0": 1142459136, 
      "file_header_1": 0, 
      "file_header_2": 0, 
      "file_header_3": 0, 
      "file_header_4": 0, 
      "file_header_5": 0, 
      "file_header_6": 1, 
      "file_header_7": 0, 
      "file_header_8": 0, 
      "file_header_9": 0, 
      "file_header_10": 0, 
      "file_header_11": 0, 
      "file_header_12": 0, 
      "file_header_13": -1, 
      "file_header_14": 0, 
      "file_header_15": -1, 
      "file_header_16": -1, 
      "file_header_17": 0, 
      "file_header_18": 0, 
      "file_header_19": 0, 
      "file_header_20": 0, 
      "file_header_21": 0, 
      "file_header_22": 0, 
      "file_header_23": 0, 
      "file_header_24": 0, 
      "file_header_25": 0, 
      "file_header_26": 0, 
      "file_header_27": 0, 
      "file_header_28": 1, 
      "file_header_29": 0, 
      "file_header_30": 0, 
      "file_header_31": 0, 
      "file_header_32": 0, 
      "file_header_33": 0, 
      "file_header_34": 0, 
      "file_header_35": 0, 
      "file_header_36": 0, 
      "file_header_37": 0, 
      "file_header_38": 0, 
      "file_header_39": 0, 
      "file_header_40": 0, 
      "file_header_41": 0, 
      "file_header_42": -1, 
      "file_header_43": 0, 
      "file_header_44": 0, 
      "file_header_45": 0, 
      "file_header_46": 0, 
      "file_header_47": 0, 
      "file_header_48": 0, 
      "file_header_49": 0, 
      "file_header_50": 0, 
      "file_header_51": 0, 
      "file_header_52": 0, 
      "file_header_53": 2, 
      "file_header_54": 48, 
      "file_header_55": 4, 
      "file_header_56": 0, 
      "file_header_57": 4, 
      "file_header_58": 0, 
      "file_header_59": 32768, 
      "file_header_60": 4096, 
      "file_header_61": 4096, 
      "sections_0": 3, 
      "sections_1": 1, 
      "sections_2": 0, 
      "sections_3": 1, 
      "sections_4": 3, 
      "sections_5": 0, 
      "sections_6": 0, 
      "sections_7": 0, 
      "sections_8": 0, 
      "sections_9": 0, 
      "sections_10": 0, 
      "sections_11": 0, 
      "sections_12": 0, 
      "sections_13": 0, 
      "sections_14": 0, 
      "sections_15": 0, 
      "sections_16": 0, 
      "sections_17": 0, 
      "sections_18": 0, 
      "sections_19": 0, 
      "sections_20": 0, 
      "sections_21": 0, 
      "sections_22": 0, 
      "sections_23": 0, 
      "sections_24": 0, 
      "sections_25": 0, 
      "sections_26": 0, 
      "sections_27": 0, 
      "sections_28": 0, 
      "sections_29": 0, 
      "sections_30": 0, 
      "sections_31": 0, 
      "sections_32": 0, 
      "sections_33": 0, 
      "sections_34": 0, 
      "sections_35": 0, 
      "sections_36": 0, 
      "sections_37": 0, 
      "sections_38": 0, 
      "sections_39": 0, 
      "sections_40": 0, 
      "sections_41": 0, 
      "sections_42": 0, 
      "sections_43": 0, 
      "sections_44": 0, 
      "sections_45": 0, 
      "sections_46": 0, 
      "sections_47": 0, 
      "sections_48": 0, 
      "sections_49": 0, 
      "sections_50": 0, 
      "sections_51": 0, 
      "sections_52": -42048, 
      "sections_53": 0, 
      "sections_54": 0, 
      "sections_55": 0, 
      "sections_56": 0, 
      "sections_57": 0, 
      "sections_58": 0, 
      "sections_59": 0, 
      "sections_60": 0, 
      "sections_61": 0, 
      "sections_62": 0, 
      "sections_63": 0, 
      "sections_64": 0, 
      "sections_65": 0, 
      "sections_66": 0, 
      "sections_67": 0, 
      "sections_68": 0, 
      "sections_69": 0, 
      "sections_70": 0, 
      "sections_71": 0, 
      "sections_72": 0, 
      "sections_73": 0, 
      "sections_74": 0, 
      "sections_75": 0, 
      "sections_76": 0, 
      "sections_77": 0, 
      "sections_78": 0, 
      "sections_79": 0, 
      "sections_80": 0, 
      "sections_81": 0, 
      "sections_82": 0, 
      "sections_83": 0, 
      "sections_84": 0, 
      "sections_85": 0, 
      "sections_86": 0, 
      "sections_87": 0, 
      "sections_88": 0, 
      "sections_89": 0, 
      "sections_90": 0, 
      "sections_91": 0, 
      "sections_92": 0, 
      "sections_93": 0, 
      "sections_94": 0, 
      "sections_95": 0, 
      "sections_96": 0, 
      "sections_97": 0, 
      "sections_98": 0, 
      "sections_99": 0, 
      "sections_100": 0, 
      "sections_101": 0, 
      "sections_102": -11.691457748413086, 
      "sections_103": 0, 
      "sections_104": 0, 
      "sections_105": 0, 
      "sections_106": 0, 
      "sections_107": 0, 
      "sections_108": 0, 
      "sections_109": 0, 
      "sections_110": 0, 
      "sections_111": 0, 
      "sections_112": 0, 
      "sections_113": 0, 
      "sections_114": 0, 
      "sections_115": 0, 
      "sections_116": 0, 
      "sections_117": 0, 
      "sections_118": 0, 
      "sections_119": 0, 
      "sections_120": 0, 
      "sections_121": 0, 
      "sections_122": 0, 
      "sections_123": 0, 
      "sections_124": 0, 
      "sections_125": 0, 
      "sections_126": 0, 
      "sections_127": 0, 
      "sections_128": 0, 
      "sections_129": 0, 
      "sections_130": 0, 
      "sections_131": 0, 
      "sections_132": 0, 
      "sections_133": 0, 
      "sections_134": 0, 
      "sections_135": 0, 
      "sections_136": 0, 
      "sections_137": 0, 
      "sections_138": 0, 
      "sections_139": 0, 
      "sections_140": 0, 
      "sections_141": 0, 
      "sections_142": 0, 
      "sections_143": 0, 
      "sections_144": 0, 
      "sections_145": 0, 
      "sections_146": 0, 
      "sections_147": 0, 
      "sections_148": 0, 
      "sections_149": 0, 
      "sections_150": 0, 
      "sections_151": 0, 
      "sections_152": -102464, 
      "sections_153": 0, 
      "sections_154": 0, 
      "sections_155": 0, 
      "sections_156": 0, 
      "sections_157": 2, 
      "sections_158": 0, 
      "sections_159": 0, 
      "sections_160": 0, 
      "sections_161": 0, 
      "sections_162": 0, 
      "sections_163": 0, 
      "sections_164": 2, 
      "sections_165": 0, 
      "sections_166": 0, 
      "sections_167": 2, 
      "sections_168": 0, 
      "sections_169": 0, 
      "sections_170": 0, 
      "sections_171": 0, 
      "sections_172": 0, 
      "sections_173": 0, 
      "sections_174": 0, 
      "sections_175": 0, 
      "sections_176": 0, 
      "sections_177": 0, 
      "sections_178": 0, 
      "sections_179": 0, 
      "sections_180": 0, 
      "sections_181": 2, 
      "sections_182": 0, 
      "sections_183": 0, 
      "sections_184": 0, 
      "sections_185": 0, 
      "sections_186": 0, 
      "sections_187": 0, 
      "sections_188": 0, 
      "sections_189": 0, 
      "sections_190": 0, 
      "sections_191": 0, 
      "sections_192": 0, 
      "sections_193": 0, 
      "sections_194": 0, 
      "sections_195": 0, 
      "sections_196": 0, 
      "sections_197": 0, 
      "sections_198": 0, 
      "sections_199": 0, 
      "sections_200": 0, 
      "sections_201": 0, 
      "sections_202": 0, 
      "sections_203": 0, 
      "sections_204": 0, 
      "sections_205": 2, 
      "sections_206": 0, 
      "sections_207": 0, 
      "sections_208": 0, 
      "sections_209": 0, 
      "sections_210": 0, 
      "sections_211": 0, 
      "sections_212": 0, 
      "sections_213": 0, 
      "sections_214": 0, 
      "sections_215": 0, 
      "sections_216": 0, 
      "sections_217": 0, 
      "sections_218": -1, 
      "sections_219": 0, 
      "sections_220": 0, 
      "sections_221": 0, 
      "sections_222": 0, 
      "sections_223": 0, 
      "sections_224": 0, 
      "sections_225": 0, 
      "sections_226": 0, 
      "sections_227": 0, 
      "sections_228": 3, 
      "sections_229": 0, 
      "sections_230": 0, 
      "sections_231": 0, 
      "sections_232": 0, 
      "sections_233": 0, 
      "sections_234": 0, 
      "sections_235": 0, 
      "sections_236": 0, 
      "sections_237": 0, 
      "sections_238": 0, 
      "sections_239": 0, 
      "sections_240": 0, 
      "sections_241": 0, 
      "sections_242": 3, 
      "sections_243": 0, 
      "sections_244": 0, 
      "sections_245": 0, 
      "sections_246": 0, 
      "sections_247": 0, 
      "sections_248": 0, 
      "sections_249": 0, 
      "sections_250": 0, 
      "sections_251": 0, 
      "sections_252": -1, 
      "sections_253": 0, 
      "sections_254": 0 
    } 
  } 
] 
url = "YOUR_ELASTICSEARCH_ENDPOINT_URL" 
api_key = "YOUR_API_KEY" 
api_id = "YOUR_API_ID" 
# Elasticsearch-Client initialisieren 
es = Elasticsearch( 
        url, 
        api_key=(api_id, api_key), 
        use_ssl=True, 
        ca_certs=certifi.where() 
    ) 
# Index erstellen 
es.indices.create(index="ember_ml") 
# Stapelweises Ingestieren von Dokumenten in Elasticsearch 
try: 
    for success, info in helpers.streaming_bulk(es, documents, chunk_size=2500): 
        if not success: 
            print("A document failed:", info) 
except elasticsearch.ElasticsearchException: 
    print("Failed to insert")

Beachten Sie, dass die Feature-Vektoren aus ihren Hierarchien geholt werden müssen, d. h., dass jedes Feature in jedem Dokument ein eigenes Feld mit einem unterstützten Datentyp (numerisch, Boolean, Text, Keyword oder IP-Adresse) sein muss, da „Data Frame Analytics“ keine Arrays mit mehr als einem Element unterstützt. Außerdem sei darauf hingewiesen, dass das Feld „appeared“ im Datensatz EMBER, das angibt, wann das Feld zum ersten Mal aufgetaucht ist, für anschließende Zeitreihenvisualisierungen an das Elasticsearch-kompatible Datumsformat angepasst wurde. 

Um zu prüfen, ob alle unsere Daten im richtigen Format ingestiert wurden, starten wir in der „Dev Tools“-Konsole („Management“ -> „Dev Tools“) die folgenden Abfragen:

Ermitteln der Zahl der Dokumente:

GET ember_ml/_count

Suchen nach Dokumenten im Index und Prüfen, ob sie das richtige Format haben:

GET ember_ml/_search

Nachdem wir uns davon überzeugt haben, dass die Daten in Elasticsearch so aussehen wie erwartet, sind wir jetzt für das Erstellen unserer Analytics-Jobs bereit. Zuvor müssen wir jedoch noch ein Indexmuster für den Job erstellen. Anhand der Indexmuster kann Kibana (und damit der Job) feststellen, welche Elasticsearch-Indizes die Daten enthalten, mit denen Sie arbeiten möchten. Für unseren Index ember_ml erstellen wir das Indexmuster ember_*.

Trainieren des Modells

Nachdem wir das Indexmuster erstellt haben, machen wir uns ans Erstellen zweier Analytics-Jobs mit den beiden oben erwähnten Feature-Teilmengen. Dabei hilft uns die Kibana-App Machine Learning. Wir konfigurieren unseren Job wie folgt:

  • „Job type“: Wir wählen „classification“ aus, weil vorhergesagt werden soll, ob die jeweilige Binärdatei bösartig oder gutartig ist. Das zugrundeliegende Klassifizierungsmodell beim Machine Learning in Elastic ist ein Algorithmus namens „Boosted Tree Regression“, der mehrere schwache Modelle in einem zusammengefassten Modell kombiniert. Dieses Modell nutzt Entscheidungsbäume, um die richtige Vorhersage der Wahrscheinlichkeit zu trainieren, dass ein Datenpunkt zu einer bestimmten Klasse gehört.
  • „Dependent variable“: In unserem Fall ist dies „label“ mit einem Wert von „1“ für bösartig und von „0“ für gutartig.
  • „Fields to include“: Wir wählen die Felder aus, die beim Training berücksichtigt werden sollen. 
  • „Training percentage“: Es empfiehlt sich, das Training iterativ zu gestalten, besonders dann, wenn der Datensatz groß ist. Das heißt, Sie sollten zunächst einen Trainings-Job mit einem kleineren Trainingsprozentsatz erstellen, sich die Performance ansehen und dann entscheiden, ob es nötig ist, den Trainingsprozentsatz zu erhöhen. Da wir mit einem doch recht großen Datensatz (300.000 Dokumente) arbeiten, beginnen wir mit einem Trainingsprozentsatz von 10 %.
  • „Additional information options“: Wir lassen die Standardwerte unverändert, aber Sie könnten an dieser Stelle auch Hyperparameter für den Trainings-Job auswählen.
  • „Job details“: Wir weisen eine entsprechende Job-ID und einen Zielindex für den Job zu.
  • „Create index pattern“: Diese Option deaktivieren wir, da wir für beide Trainings-Jobs nur ein Indexmuster für die Zielindizes erstellen werden, damit wir die Ergebnisse zusammen visualisieren können. 

Wir nutzen die oben beschriebenen Schritte, um zwei Analytics-Jobs zu erstellen: einen mit lediglich dem Bytes-Histogramm als Features (Zielindex: bytes_preds) und einen mit allem anderen als Features (Zielindex: main_preds). Vom Analytics-Job hängt ab, welche Verschlüsselung für jedes einzelne Feature die beste ist, welche Features am besten performen und welche Hyperparameter für das Modell verwendet werden sollten. In Machine Learning kann auch der Job-Fortschritt verfolgt werden:

Verfolgen des Job-Fortschritts in der App Machine LearningVerfolgen des Job-Fortschritts in der App Machine Learning

Verfolgen des Job-Fortschritts in der App Machine Learning

Evaluieren des Modells

Wenn die Jobs fertig sind, können wir uns die Vorhersageergebnisse ansehen, indem wir neben jedem fertigen Job auf die Schaltfläche „View“ klicken. Nach dem Klicken auf „View“ werden eine Dataframe-artige Ansicht des Inhalts des Zielindex sowie die Wahrheitsmatrix für das Modell angezeigt. Die Zeilen im Dataframe (siehe unten) geben Auskunft über die Modellvorhersage, das Label, die Klassenwahrscheinlichkeit und den Score sowie darüber, ob die Datenprobe im Training verwendet wurde:

Dataframe-Ansicht des Zielindex „main_preds“

Dataframe-Ansicht des Zielindex „main_preds“

Wir nutzen die Wahrheitsmatrizen, um uns die Performance beider Modelle anzuschauen und sie zu vergleichen. Jede Zeile in der Wahrheitsmatrix steht für Instanzen in der tatsächlichen Klasse, und jede Spalte steht für Instanzen in der vorhergesagten Klasse. Das ermöglicht es zu ermitteln, welche Ergebnisse richtig positiv oder falsch positiv (obere Zeile) bzw. falsch negativ oder richtig negativ (untere Zeile) waren.

Wahrheitsmatrix für ein Modell mit allgemeinen, Datei-Header- und Abschnittsinformationen und Zeichenfolgen als Features

Wahrheitsmatrix für ein Modell mit allgemeinen, Datei-Header- und Abschnittsinformationen und Zeichenfolgen als Features

Wahrheitsmatrix mit Byte-Histogramm als Features

Wahrheitsmatrix mit Byte-Histogramm als Features

Wir sehen, dass beide Modelle recht akkurat sind (zumindest für Demozwecke), weshalb wir auf eine weitere Trainingsrunde oder eine Hyperparameter-Feinjustierung verzichten. Im nächsten Abschnitt schauen wir uns an, wie man die beiden Modelle in Kibana visuell vergleicht und entscheidet, welches Modell bereitgestellt werden soll.

Überwachen der Modelle

Nachdem wir die Vorhersagen für beide Modelle in ihren jeweiligen Zielindizes haben, erstellen wir ein Indexmuster (in unserem Fall *_preds), um beide miteinander abzugleichen und so Monitoring-Dashboards in Kibana erstellen zu können. In diesem Beispiel hat das Monitoring-Dashboard einen doppelten Zweck:

  • Vergleichen der Performance des Nur-Byte-Histogramm-Modells mit dem anderen Modell – hierfür kommen TSVB-Visualisierungen zum Einsatz
  • Verfolgen verschiedener Metriken für das Modell mit der besseren Performance – zur Visualisierung der Vorhersagewahrscheinlichkeiten und der Werte für die gutartigen und die bösartigen Datenproben nutzen wir Balkendiagramme und zur Darstellung der Entwicklung der Falsch-positiv- und der der Falsch-negativ-Quote nutzen wir TSVB-Visualisierungen.

Falsch-negativ-Quoten der beiden trainierten Modelle im ZeitverlaufFalsch-positiv-Quoten der beiden trainierten Modelle im Zeitverlauf

Falsch-negativ- und Falsch-positiv-Quoten der beiden trainierten Modelle im Zeitverlauf

Aufgrund der beobachteten Entwicklung der Falsch-negativ- und Falsch-positiv-Quoten der beiden Modelle über einen signifikanten Zeitraum hinweg und der im vorherigen Abschnitt vorgestellten Wahrheitsmatrizen kommen wir zu dem Schluss, dass das Modell, das mit allgemeinen, Datei-Header- und Abschnittsinformationen sowie Zeichenfolgen trainiert wurde, die bessere Performance aufweist. Daher entscheiden wir uns, dieses Modell bereitzustellen und nach der Bereitstellung zu überwachen. Zu diesem Zweck plotten wir verschiedene Metriken, die für dieses Modell überwacht werden sollen.

Kibana-Dashboard zur Visualisierung verschiedener Performance-Metriken für das Modell

In der Praxis können solche Monitoring-Dashboards zum Vergleichen von Modellkandidaten für den Produktionseinsatz verwendet werden. Und nach Bereitstellung des Modells können die Dashboards auch dazu verwendet werden, Anzeichen für Modelldrift in Produktionsumgebungen zu ermitteln (z. B. plötzlicher starker Anstieg der Falsch-positiv-Quote) und entsprechende Gegenmaßnahmen einzuleiten (z. B. erneutes Trainieren des Modells). Im nächsten Abschnitt beschäftigen wir uns damit, wie wir das ausgewählte Modell in einer Machine-Learning-Produktionspipeline bereitstellen können.

Bereitstellen unseres überwachten Modells zur Datenanreicherung beim Ingestieren

Zusätzlich zum Trainieren und Evaluieren von Modellen bietet der Elastic Stack dem Nutzer auch die Möglichkeit, trainierte Modelle in Ingestionspipelines einzusetzen. Das wiederum ebnet den Weg zur Nutzung von Machine-Learning-Modellen für das Anreichern von Daten beim Ingestieren. In diesem Abschnitt sehen wir uns am Beispiel des oben trainierten Modells zur Malware-Klassifizierung an, wie dies gelingen kann.

Nehmen wir an, dass bei uns aus Binärdateien extrahierte Daten eingehen, die wir als bösartig oder als gutartig klassifizieren möchten. Wir werden für das Ingestieren dieser Daten in Elasticsearch eine Ingestionspipeline nutzen und unser trainiertes Modell zur Malware-Klassifizierung in einem Inferenzprozessor referenzieren. 

Dazu müssen wir zunächst den Inferenzprozessor und die Ingestionspipeline erstellen. Der wichtigste Teil des Inferenzprozessors ist das trainierte Modell und dessen Modell-ID, die wir mit dem folgenden REST API-Aufruf in der Kibana-Konsole ermitteln können:

GET _ml/inference

Daraufhin erhalten wir eine Liste trainierter Modelle in unserem Cluster, die für jedes Modell wichtige Angaben enthält, darunter auch die Modell-ID (model_id), die Felder, die für das Trainieren des Modells verwendet wurden, den Trainingszeitpunkt und so weiter. Wir notieren uns die Modell-ID, weil wir sie für den Inferenzprozessor benötigen.

Beispielausgabe eines Aufrufs zum Anzeigen von Informationen zu trainierten Modellen mit der Modell-ID, die wir für die Konfiguration des Inferenzprozessors benötigen

Beispielausgabe eines Aufrufs zum Anzeigen von Informationen zu trainierten Modellen mit der Modell-ID, die wir für die Konfiguration des Inferenzprozessors benötigen

Wenn Sie sehr viele trainierte Modelle in Ihrem Cluster haben, empfiehlt es sich, beim API-Aufruf einen Platzhalter auf Basis des Namens des „Data Frame Analytics“-Jobs zu verwenden, mit dem das Modell trainiert wurde. In diesem Fall wurden die uns interessierenden Modelle mit ember_*-Jobs trainiert, weshalb wir die auszugebenden Modelle ganz einfach mit dem Aufruf 

GET _ml/inference/ember_*

einschränken können. 

Da wir jetzt die Modell-ID zur Hand haben, können wir mit dem Erstellen unserer Ingestionspipeline beginnen. Die vollständige Konfiguration wird unten gezeigt. Achten Sie auf den Block mit dem Titel inference. Er referenziert das Modell, das wir zum Anreichern unserer Dokumente verwenden möchten. In ihm wird außerdem ein Zielfeld (target_field) definiert, das frei konfiguriert werden kann. Wir setzen es in unserem Fall auf is_malware, um dort die bösartigen Datenproben einzusortieren. Das Zielfeld wird genutzt, um die ML-Felder, die bei der Verarbeitung des Dokuments durch den Interferenzprozessor hinzugefügt werden, mit einem entsprechenden Präfix zu versehen. 

PUT _ingest/pipeline/malware-classification
{
  "description": "Classifies incoming binaries as malicious or benign",
  "processors": [
    {
      "inference": {
        "model_id": "ember_main-1598557689011",
        "target_field": "is_malware",
        "inference_config": {
          "classification": {
            "num_top_classes": 2
          }
        }
      }
    }
  ]
}

Nehmen wir an, wir möchten Dokumente mit Features von Binärdateien ingestieren und diese Daten für jede Binärdatei mit Vorhersagen zur Bösartigkeit anreichern. Dazu dieses gekürzte Beispieldokument:

{ 
          "appeared" : "2020-04-01 00:00:00", 
          "byte_0" : 0.1622137576341629, 
          "byte_1" : 0.007498478516936302, 
          "byte_2" : 0.003992937505245209, 
          "byte_3" : 0.00546838915720582, 
          "byte_4" : 0.007421959958970547, 
          ... 
          "byte_253" : 0.0019106657709926367, 
          "byte_254" : 0.003551538335159421, 
          "byte_255" : 0.1782810389995575, 
          "strings_0" : 3312.0, 
          "strings_1" : 24.97675132751465, 
          "strings_2" : 82723.0, 
          "strings_3" : 0.07208394259214401, 
          "strings_4" : 8.099319529719651E-4, 
          "strings_5" : 0.005427753087133169, 
           ... 
          "strings_100" : 0.0, 
          "strings_101" : 39.0, 
          "strings_102" : 0.0, 
          "strings_103" : 9.0, 
          "general_info_0" : 1130496.0, 
          "general_info_1" : 1134592.0, 
          "general_info_2" : 1.0, 
          "general_info_3" : 0.0, 
          "general_info_4" : 247.0, 
          "general_info_5" : 1.0, 
          "general_info_6" : 1.0, 
          "general_info_7" : 1.0, 
          "general_info_8" : 1.0, 
          "general_info_9" : 0.0, 
          "file_header_0" : 1.511340288E9, 
          "file_header_1" : 0.0, 
          "file_header_2" : 0.0, 
          "file_header_3" : 0.0, 
          "file_header_4" : 0.0, 
          "file_header_5" : 0.0, 
          "file_header_6" : 1.0, 
          "file_header_7" : 0.0, 
          "file_header_8" : 0.0, 
          "file_header_9" : 0.0, 
           ... 
          "file_header_59" : 262144.0, 
          "file_header_60" : 1024.0, 
          "file_header_61" : 4096.0, 
          "sections_0" : 5.0, 
          "sections_1" : 0.0, 
          "sections_2" : 0.0, 
          "sections_3" : 1.0, 
          "sections_4" : 1.0, 
          "sections_5" : 0.0, 
           ... 
          "sections_253" : 0.0, 
          "sections_254" : 0.0 
]

Wir können dieses Dokument mithilfe einer der Index-APIs indexieren und durch die oben erstellte malware-classification-Pipeline laufen lassen. Das folgende ist ein Beispiel für einen API-Aufruf, der dieses Dokument in einen Zielindex namens main_preds ingestiert. Aus Platzgründen stellen wir das Dokument in verkürzter Form dar. 

POST main_preds/_doc?pipeline=malware-classification 
{ 
          "appeared" : "2020-04-01 00:00:00", 
          "byte_0" : 0.1622137576341629, 
          "byte_1" : 0.007498478516936302, 
          "byte_2" : 0.003992937505245209, 
          "byte_3" : 0.00546838915720582, 
          "byte_4" : 0.007421959958970547, 
          "byte_5" : 0.0025378242135047913, 
          "byte_6" : 0.002135345945134759, 
          "byte_7" : 0.001892974367365241, 
          "byte_8" : 0.007126075681298971, 
          "byte_9" : 0.001768250367604196, 
          "byte_10" : 0.0055223405789583921, 
          "byte_11" : 0.001283507444895804, 
          "byte_12" : 0.008042919423431158, 
          "byte_13" : 0.001533839968033135, 
          "byte_14" : 0.0010570581071078777, 
          "byte_15" : 0.006860705558210611, 
...

Wir haben jetzt in unserem Zielindex main_preds ein neues Dokument, das mit den Vorhersagen aus unserem trainierten Machine-Learning-Modell angereichert wurde. Wenn wir uns das Dokument ansehen (beispielsweise über den Tab „Discover“), sehen wir, dass der Inferenzprozessor gemäß unserer Konfiguration die Vorhersagen des trainierten Machine-Learning-Modells zum Dokument hinzugefügt hat. In diesem Fall wurde unserem Dokument (das für eine unbekannte Binärdatei steht, die wir als bösartig oder gutartig klassifizieren möchten) die Klasse 1 zugewiesen, was bedeutet, dass das Modell diese Binärdatei als bösartig eingestuft hat. 

Auszug aus dem ingestierten Dokument mit Klassifizierung durch unser trainiertes Machine-Learning-Modell

Auszug aus dem ingestierten Dokument mit Klassifizierung durch unser trainiertes Machine-Learning-Modell

Wenn dem Zielindex neue Dokumente mit Vorhersagen hinzugefügt werden, werden diese automatisch in die Kibana-Dashboards aufgenommen, wo sie Aufschluss darüber geben, wie das trainierte Modell im Laufe der Zeit bei neuen Datenproben performt.

Fazit

In Produktionsumgebungen reicht es nicht (oder sollte es nicht reichen), es mit dem Bereitstellen eines Modells bewenden zu lassen. Die Pipeline muss in der Lage sein, Modelle effektiv zu evaluieren, bevor sie in der Kundenumgebung bereitgestellt werden, und sie nach der Bereitstellung genau zu überwachen. Dies hilft Data-Science-Teams dabei, mögliche Probleme in der Praxis vorherzusehen und entsprechende Maßnahmen zu ergreifen, sollte es Anzeichen für Modelldrift geben.

In diesem Blogpost haben wir uns damit beschäftigt, warum sich der Elastic Stack angesichts seiner Speicherkapazitäten, der Möglichkeiten zum Modelltraining, der integrierten Feinjustierungsfunktionen und des umfassenden Angebots an Visualisierungstools in Kibana hervorragend für die Verwaltung einer solchen End-to-End-Machine-Learning-Pipeline eignet.