Technique

Entraîner, évaluer, monitorer, déduire : Machine Learning de bout en bout dans la Suite Elastic

Au cours des dernières années, les pipelines de Machine Learning ont beaucoup évolué. Avec une large variété d'outils et d'infrastructures disponibles pour simplifier la construction, l'entraînement et le déploiement, le délai de développement du modèle de Machine Learning s'est considérablement amélioré. Cependant, même avec toutes ces simplifications, il y a toujours une courbe d'apprentissage difficile associée à beaucoup de ces outils. Mais pas avec Elastic.

Afin d'utiliser le Machine Learning dans la Suite Elastic, tout ce dont vous avez vraiment besoin, c'est que vos données soient stockées dans Elasticsearch. Ensuite, pour extraire les précieuses informations de vos données, il vous suffit de cliquer sur quelques boutons dans Kibana. Le Machine Learning est intégré dans la Suite Elastic, ce qui vous permet de construire facilement et intuitivement un pipeline de Machine Learning de bout en bout entièrement opérationnel. Et c'est ce que nous allons faire dans ce blog.

Pourquoi choisir Elastic ?

En tant qu'entreprise centrée sur la recherche, Elastic est créée pour traiter efficacement de grandes quantités de données. Il est devenu simple de rechercher et de regrouper des données pour analyse grâce au Query DSL d'Elasticsearch. Il est possible de visualiser de grands ensembles de données de différentes façons dans Kibana. L'interface Machine Learning d'Elastic permet une sélection facile des fonctionnalités et des modèles, l'entraînement des modèles et le réglage des hyperparamètres. Et après avoir formé et réglé votre modèle, Kibana peut également être utilisé pour évaluer et visuellement monitorer les modèles. Cela fait de la Suite Elastic l'emplacement centralisé idéal pour le Machine Learning au niveau de la production.

Exemple d'ensemble de données : EMBER 2018

Nous allons faire une démonstration du Machine Learning de bout en bout dans la Suite Elastic à l'aide de l'ensemble de données EMBER, lancé par Endgame pour activer la détection de malwares à l'aide des fonctionnalités statistiques dérivées des fichiers exécutables portables (PE). Aux fins de cette démonstration, nous utiliserons l'ensemble de données EMBER (Endgame Malware BEnchmark for Research) de 2018, qui représente une collecte open source d'1 million d'échantillons. Chaque échantillon inclut le hachage sha256 de l'exemple de fichier, le mois où le fichier a été vu la première fois, un terme et les fonctionnalités dérivées du fichier. 

Pour cette expérience, nous sélectionnerons 300 000 exemples (150 000 malveillants et 150 000 sans risque) de l'ensemble de données EMBER 2018. Afin de mener un apprentissage supervisé sur les exemples, nous devons d'abord sélectionner certaines fonctionnalités. Les fonctionnalités de l'ensemble de données sont des fonctionnalités statiques dérivées du contenu des fichiers binaires. Nous avons décidé d'expérimenter les informations générales, les en-têtes de fichier et les informations de section, les chaînes et les histogrammes bytes afin d'étudier les performances des modèles lors de l'utilisation des différents sous-ensembles de fonctionnalités de l'ensemble de données EMBER. 

Machine Learning de bout en bout dans la Suite Elastic : présentation

Aux fins de cette démonstration, nous utiliserons le Client Python Elasticsearch pour insérer les données dans Elasticsearch, la fonctionnalité d'analyse des trames de données du Machine Learning d'Elastic pour créer des tâches d'entraînement et Kibana pour monitorer visuellement les modèles après l'entraînement. 

Nous créerons deux tâches supervisées, une utilisant les informations générales, les en-têtes de fichier et les informations de section ainsi que les chaînes, et une autre utilisant juste les histogrammes d'octets comme fonctionnalités. Cela afin de démontrer plusieurs entraînements de modèle en même temps dans la suite et la visualisation de plusieurs modèles de candidats ultérieurement.

Configuration d'Elasticsearch

Afin d'utiliser le Machine Learning dans la Suite Elastic, nous devons d'abord lancer Elasticsearch avec un nœud de Machine Learning. Pour cela, nous pouvons commencer un essai gratuit de 14 jours d'Elastic Cloud qui est disponible pour tous. Notre exemple de déploiement a les paramètres suivants :

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

Nous avons également besoin de créer des clés d'API et de leur assigner les privilèges appropriés pour interagir avec Elasticsearch à l'aide du Client Python Elasticsearch. Pour notre présentation, nous insérerons des données dans l'index ember_ml, de manière à créer une clé comme suit :

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

Ingestion des données

Une fois que nous avons la configuration de notre instance Elasticsearch, nous commencerons par ingérer des données dans un index Elasticsearch. Tout d'abord, nous créerons un index appelé ember_ml, puis nous ingérerons les documents qui constituent notre ensemble de données à l'aide du Client Python Elasticsearch. Nous ingérerons toutes les fonctionnalités requises pour les deux modèles dans un seul index, à l'aide du Streaming Bulk Helper afin d'ingérer de façon groupée les documents dans Elasticsearch. Le code Python pour créer l'index ember_ml et pour ingérer de façon groupée les documents est le suivant :

import elasticsearch 
import certifi 
from elasticsearch import Elasticsearch, helpers 
# Longue liste de documents à insérer dans Elasticsearch, en en montrant un comme exemple 
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" 
# Initialiser le client Elasticsearch 
es = Elasticsearch( 
        url, 
        api_key=(api_id, api_key), 
        use_ssl=True, 
        ca_certs=certifi.where() 
    ) 
# Créer un index 
es.indices.create(index="ember_ml") 
# Ingérer de façon groupée les documents dans 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")

Notez que les vecteurs de fonctionnalités doivent être lissés, c'est-à-dire que chaque fonctionnalité doit être un champ distinct d'un type de données pris en charge (numérique, booléen, texte, mot-clé ou IP) dans chaque document, étant donné que l'analyse des trames de données ne prend pas en charge les tableaux avec plus d'un élément. Veuillez également noter que le champ "appeared" (première détection) dans l'ensemble de données EMBER a été modifié pour correspondre au format de date compatible avec Elasticsearch afin de faire des visualisations d'analyses chronologiques. 

Afin de nous assurer que toutes nos données sont ingérées au bon format dans Elasticsearch, nous exécutons les requêtes suivantes dans la Console d'outils de développement (Management [Gestion] -> Dev Tools [Outils de développement]) :

Pour obtenir le nombre de documents :

GET ember_ml/_count

Pour rechercher les documents dans l'index et s'assurer qu'ils sont au bon format :

GET ember_ml/_search

Après avoir vérifié que les données dans Elasticsearch ont l'apparence prévue, nous sommes désormais prêts à créer nos tâches d'analyse. Cependant, avant de créer les tâches, nous devons définir un modèle d'indexation pour la tâche. Les modèles d'indexation indiquent à Kibana (et, par conséquent, à la tâche) quels index Elasticsearch contiennent les données avec lesquelles vous souhaitez travailler. Nous créons le modèle d'indexation ember_* pour correspondre à notre index ember_ml.

Entraînement des modèles

Après avoir créé le modèle d'indexation, nous créerons deux tâches d'analyse avec les deux sous-ensembles de fonctionnalités, comme mentionné plus haut. Cela peut être effectué via l'application Machine Learning dans Kibana. Nous configurerons notre tâche de la façon suivante :

  • Type de tâches : nous sélectionnerons "classification" pour prédire si un binaire donné est malveillant ou sans risque. Le modèle de classification sous-jacent dans le Machine Learning d'Elastic est un type d'accélération des performances appelé "régression d'arborescence optimisée", qui combine plusieurs modèles faibles dans un modèle composite. Il utilise les arbres de décision pour apprendre à prédire la probabilité qu'un point de données appartienne à une certaine classe.
  • Variable dépendante : "terme" dans notre cas, 1 pour malveillant et 0 pour sans risque.
  • Champs à inclure : nous sélectionnons les champs que nous souhaiterions inclure dans l'entraînement. 
  • Pourcentage d'entraînement : il est recommandé d'adopter une approche itérative de l'entraînement, en particulier si vous travaillez avec un grand ensemble de données (c'est-à-dire, commencer par créer une tâche d'entraînement avec un pourcentage d'entraînement plus petit, évaluer les performances et décider s'il est nécessaire d'augmenter le pourcentage d'entraînement). Nous commencerons par un pourcentage d'entraînement de 10 % puisque nous travaillons avec un ensemble de données assez grand (300 000 documents).
  • Options d'informations supplémentaires : nous laisserons les valeurs par défaut comme elles sont, mais nous pouvons choisir de définir les hyperparamètres pour les tâches d'entraînement à ce moment.
  • Détails de la tâche : nous assignerons un ID de tâche et un index de destination approprié à la tâche.
  • Création d'un modèle d'indexation : nous désactiverons cette option, car nous allons créer un modèle d'indexation unique pour correspondre aux index de destination pour nos deux tâches d'entraînement afin de visualiser les résultats regroupés. 

Nous créerons deux tâches d'analyse en suivant le processus décrit ci-dessus, une avec seulement l'histogramme bytes comme fonctionnalités (index de destination : bytes_preds) et une avec tout sauf l'histogramme bytes comme fonctionnalités (index de destination : main_preds). La tâche d'analyse détermine les meilleurs encodages pour chaque fonctionnalité, les fonctionnalités les plus performantes et les hyperparamètres optimaux pour le modèle. Il est possible de suivre la progression de la tâche dans l'application Machine Learning :

Suivi de la progression de la tâche dans l'application Machine LearningSuivi de la progression de la tâche dans l'application Machine Learning

Suivi de la progression de la tâche dans l'application Machine Learning

Évaluation du modèle

Après avoir terminé les tâches, nous pouvons voir les résultats de prédiction en cliquant sur le bouton View (Afficher) à côté de chaque tâche terminée. En cliquant sur ce bouton, nous obtenons une vue de type trame de données du contenu de l'index de destination et de la matrice de confusion du modèle. Chaque ligne de la trame de données (représentée ci-dessous) indique si un exemple a été utilisé dans l'entraînement, la prédiction du modèle, le terme et la probabilité de la classe, ainsi que le score :

Vue de la trame de données de l'index de destination main_preds

Vue de la trame de données de l'index de destination main_preds

Nous utilisons les matrices de confusion pour évaluer et comparer les performances des deux modèles. Chaque ligne de la matrice de confusion ici représente les instances de la classe actuelle, et chaque colonne représente les instances de la classe prévue, donnant ainsi une mesure des vrais positifs, des faux positifs (ligne du haut), des faux négatifs et des vrais négatifs (ligne du bas).

Matrice de confusion du modèle avec les informations générales, l'en-tête de fichier et les informations de section, ainsi que les chaînes comme fonctionnalités

Matrice de confusion du modèle avec les informations générales, l'en-tête de fichier et les informations de section, ainsi que les chaînes comme fonctionnalités

Matrice de confusion du modèle avec les histogrammes bytes comme fonctionnalités

Matrice de confusion du modèle avec les histogrammes bytes comme fonctionnalités

Nous voyons que les deux modèles ont une précision assez bonne (du moins pour une démonstration !), donc nous décidons de ne pas faire d'entraînement supplémentaire du réglage des hyperparamètres. Dans la prochaine section, nous verrons comment comparer visuellement les deux modèles dans Kibana et décider du modèle à déployer.

Monitoring de modèle

Une fois que nous aurons les prédictions pour les deux modèles dans leurs index de destination respectifs, nous créerons un modèle d'indexation (*_preds, dans ce cas) pour faire correspondre les deux afin de créer des tableaux de bord de monitoring de modèle dans Kibana. Pour cet exemple, le tableau de bord de monitoring a deux objectifs :

  • comparer les performances du modèle d'histogramme bytes uniquement avec l'autre modèle. Nous utilisons les visualisations TSVB pour cela ;
  • suivre les différents indicateurs du modèle le plus performant. Nous utilisons les visualisations de la barre verticale pour visualiser les probabilités de prédiction et les nombres d'exemples sans risque et malveillants ainsi que TSVB pour suivre le taux de faux positifs et le taux de faux négatifs.

Taux de faux négatifs des deux modèles entraînés au fil du tempsTaux de faux positifs des deux modèles entraînés au fil du temps

Taux de faux négatifs et taux de faux positifs des deux modèles entraînés au fil du temps

En observant le taux de faux négatifs et le taux de faux positifs des deux modèles sur une période de temps importante, et en regardant les matrices de confusion indiquées dans la section précédente, nous concluons que le modèle entraîné sur les informations générales, l'en-tête de fichier et les informations de section ainsi que les chaînes est le modèle le plus performant. Nous déterminons ensuite différents indicateurs que nous souhaiterions suivre pour ce modèle, en supposant que c'est celui que nous souhaitons déployer et monitorer après le déploiement.

Tableau de bord des différents indicateurs de performances des modèles créés dans Kibana

Dans les cas d'utilisation du monde réel, il est possible d'utiliser ces tableaux de bord de monitoring pour comparer les modèles candidats pour la production et, une fois qu'un modèle a été déployé, pour identifier les indicateurs de perte de modèle (ex. : rafale de faux positifs) dans les environnements de production et déclencher des réponses pertinentes (ex. : entraînement d'un nouveau modèle). Dans la prochaine section, nous verrons comment déployer le modèle que nous avons choisi d'utiliser dans un pipeline de production du Machine Learning.

Déploiement de notre modèle supervisé pour enrichir les données au moment de l'ingestion

En plus de l'entraînement et de l'évaluation des modèles, la Suite Elastic permet également aux utilisateurs d'utiliser les modèles entraînés dans les pipelines d'ingestion. Cela ouvre la voie à l'utilisation des modèles de Machine Learning pour enrichir vos données au moment de l'ingestion. Dans cette section, nous verrons comment vous pouvez faire exactement cela avec le modèle de classification de malveillants que nous avons entraîné ci-dessus !

Supposons que, dans ce cas, nous avons un flux entrant de données extraites de binaires que nous souhaitons classer comme malveillants ou sans risque. Nous ingérerons ces données dans Elasticsearch via un pipeline d'ingestion et référencerons notre modèle de classification malveillant entraîné dans un processeur d'inférence. 

Tout d'abord, créons notre processeur d'inférence et notre pipeline d'ingestion. La partie la plus importante du processeur d'inférence est le modèle entraîné et son model_id, que nous pouvons rechercher avec l'appel API REST suivant dans la console Kibana :

GET _ml/inference

Cette action nous renverra une liste de modèles entraînés dans notre cluster et, pour chaque modèle, cela affichera les caractéristiques comme le model_id (dont nous devons prendre note pour l'inférence), les champs utilisés pour l'entraînement du modèle, quand le modèle a été entraîné, etc.

L'exemple de sortie d'un appel pour récupérer les informations sur les modèles entraînés affiche le model_id, qui est requis pour configurer les processeurs d'inférence

L'exemple de sortie d'un appel pour récupérer les informations sur les modèles entraînés affiche le model_id, qui est requis pour configurer les processeurs d'inférence

Si vous avez un grand nombre de modèles entraînés dans votre cluster, il pourrait être utile d'exécuter l'appel API ci-dessus avec une requête à caractères génériques basée sur le nom de la tâche d'analyse des trames de données qui a été utilisé pour entraîner le modèle. Dans ce cas, les modèles dont nous parlons ont été entraînés avec des tâches appelées ember_*, alors nous pouvons exécuter 

GET _ml/inference/ember_*

pour rapidement limiter nos modèles à ceux souhaités. 

Après avoir pris note du model_id, nous pouvons créer la configuration de notre pipeline d'ingestion. L'intégrité de la configuration est indiquée ci-dessous. Prenez note du bloc de configuration intitulé inference. Cela fait référence au modèle que nous souhaitons utiliser pour enrichir nos documents. Cela spécifie également un target_field (que nous avons, dans ce cas, défini sur is_malware), qui sera utilisé comme préfixe dans les champs ML qui seront ajoutés lorsque le document est traité par le processeur d'inférence. 

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
          }
        }
      }
    }
  ]
}

Maintenant, supposons que nous ingérons les documents avec des fonctionnalités de binaires et que nous souhaitons enrichir ces données avec des prédictions de malveillance de chaque binaire. Un exemple de document abrégé est donné ci-dessous :

{ 
          "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 
]

Nous pouvons ingérer ce document en utilisant l'un des API d'index et le canal via le pipeline malware-classification que nous avons créé ci-dessus. Un exemple d'appel API qui ingère ce document dans un index de destination appelé main_preds est donné ci-dessous. Pour gagner de la place, le document a été abrégé. 

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, 
...

Par conséquent, dans notre index de destination main_preds, nous avons désormais un nouveau document qui a été enrichi avec les prédictions de notre modèle entraîné de Machine Learning. Si nous visualisons le document (par exemple, en utilisant l'onglet Discover [Découvrir]), nous verrons que, selon notre configuration, le processeur d'inférence a ajouté les prédictions du modèle entraîné de Machine Learning au document. Dans ce cas, notre document (qui représente un binaire inconnu que nous souhaitons classer comme malveillant ou sans risque) a été attribué classe 1, ce qui indique que notre modèle prédit ce binaire comme étant malveillant. 

Un extrait des documents ingérés montre l'enrichissement de notre modèle entraîné de Machine Learning

Un extrait des documents ingérés montre l'enrichissement de notre modèle entraîné de Machine Learning

Comme de nouveaux documents avec des prédictions sont ajoutés à l'index de destination, ils seront automatiquement pris en charge par les tableaux de bord Kibana, donnant une idée de comment le modèle entraîné s'exécute sur de nouveaux exemples au fil du temps.

Conclusion

Dans les environnements de production, la responsabilité ne s'arrête pas (ou ne doit pas s'arrêter !) au déploiement du modèle. Le pipeline doit avoir une façon d'évaluer efficacement les modèles avant qu'ils atteignent l'environnement client et de les monitorer de près après leur déploiement. Cela aide les équipes de science des données à anticiper les problèmes et à prendre les mesures nécessaires lorsqu'une perte de modèle est indiquée.

Dans cet article de blog, nous avons étudié pourquoi la Suite Elastic est une plateforme exceptionnelle pour gérer ce type de pipeline de Machine Learning de bout en bout, étant donné qu'elle a des capacités de stockage exceptionnelles, un entraînement de modèle, un réglage intégré et une suite complète d'outils de visualisation dans Kibana.