機械学習パイプラインは、この数年で凄まじい進化を遂げています。開発、教育、デプロイをシンプル化する多種多様なツールとフレームワークが登場し、機械学習モデルの開発にかかる時間は劇的に短縮されました。しかし、どれほどシンプル化ツールが充実しても、大量のツールを扱うための険しい学習曲線が消えるわけではありません。ところが、Elasticのプロダクトにはそのような問題がありません。
Elastic Stackで機械学習を使うために必要な作業は、データをElasticsearchに格納することだけです。格納後は、Kibanaのボタンをいくつかクリックするだけでデータから価値あるインサイトを抽出でき、とても簡単です。機械学習機能はElastic Stackに深く統合されています。したがってユーザーは簡単に、直感的な操作で全面的に運用可能なエンドツーエンドの機械学習パイプラインを構築することができます。このブログ記事では、その手順を具体的にご紹介します。
Elasticが選ばれる理由
Elasticは検索の会社です。つまり、Elasticのテクノロジーを使えば大量のデータを効率的に扱うことができます。Elasticsearch Query DSLは、シンプルかつ直感的な手順でデータ分析のための検索やアグリゲーションを実行できるクエリ言語です。Kibanaを使うと、大規模なデータセットから多彩な可視化を生成できます。使いやすく設計されたElasticの機械学習インターフェースから、モデル選択やモデル教育、ハイパーパラメーター調整を実行できます。構築したモデルの教育と調整を完了したら、引き続きKibanaでモデルの評価や視覚的な監視を行うことができます。このように操作がシンプルなElastic Stackは、機械学習を運用レベルで活用するための完全な“ワンストップショップ(よろず屋)”となります。
サンプルデータセット“EMBER 2018”
今回はEndgameがリリースしているEMBERデータセットを使い、Elastic Stackの機械学習でportable executable(PE)ファイル由来の静的な特徴を活用したマルウェア検知を有効化する手順をエンドツーエンドに実演します。このデモンストレーションで使用するEMBER(Endgame Malware BEnchmark for Research)2018データセットは、100万個のサンプルを収集したオープンソースです。各サンプルはサンプルファイルのsha256ハッシュと、ファイルが最初に確認された年月、ラベル1つ、ファイルから得た特徴を含みます。
今回はEMBER 2018データセットから30万個のサンプル(悪意のあるサンプルが15万、無害なサンプルが15万)を選んで使用します。このサンプルを使って教師あり学習を実践するには、はじめに特徴をいくつか選択する必要があります。このデータセットの特徴は、バイナリファイルのコンテンツから得る静的特徴です。そこで、一般的な情報、ファイルヘッダー情報、セクション情報、文字列、バイトヒストグラムを使う実験により、EMBERデータセットのさまざまな特徴サブセットを使ったモデルパフォーマンスを学習させることにしました。
Elastic Stackで機械学習をエンドツーエンドにウォークスルー
このデモンストレーションでは、Elasticsearchにデータを取り込むためにPython Elasticsearch Clientを使用します。さらにElasticの機械学習のデータフレーム分析機能を用いて教育ジョブを作成し、Kibanaを使って教育済みのモデルを視覚的に監視する、という流れで進めます。
教師ありジョブについては、一般的な情報、ファイルヘッダー情報、セクション情報、文字列を使うジョブを1つと、バイトヒストグラムのみを特徴として使用するジョブを1つ、合計で2つのジョブを作成します。手順の後半では、この2つのジョブを使ってスタック内で複数のモデル教育を同時に実行し、複数の候補モデルを可視化する様子をデモンストレーションします。
Elasticsearchをセットアップする
Elastic Stackの機械学習を使用するには、はじめにElasticsearchの機械学習ノードを立ち上げる必要があります。Elastic Cloudの14日間無料トライアルを利用すれば、誰でもこのノードを作成することができます。本記事のサンプルデプロイでは、以下の設定を使用しました。
- Cloud Platform(クラウドプラットフォーム):Amazon Web Services
- Region(リージョン):US West(北カリフォルニア)
- Optimization(最適化):I/O Optimized(I/O最適化)
- Customize Deployment(デプロイのカスタマイズ):Enable Machine Learning(機械学習を有効化)
また、Python Elasticsearch Clientを使ってElasticsearchとやり取りするためのAPIキーを作成し、適切な権限を割り当てる必要があります。今回のウォークスルーではember_ml
インデックスにデータを挿入します。したがって、以下のようにキーを作成します。
POST /_security/api_key { "name": "my_awesome_key", "role_descriptors": { "role_1": { "cluster": ["all"], "index": [ { "names": ["ember_*"], "privileges": ["all"] } ] } } }
データインジェスト
これでElasticsearchインスタンスが立ち上がりました。次は、Elasticsearchインデックスへのデータインジェストです。はじめにember_ml
というインデックスを作成し、Python Elasticsearch Clientを使ってデータセットを用意するドキュメントのインジェストを実行します。今回は、2つのモデルに必要な特徴をすべてインジェストするため、Streaming Bulk Helperを使用します。これでドキュメントをElasticsearchにバルクインジェストできます。以下の通り、このPythonコードはember_ml
インデックスを作成し、そこにドキュメントをバルクでインジェストします。
import elasticsearch import certifi from elasticsearch import Elasticsearch, helpers # Elasticsearchに取り込まれるドキュメントの長いリストが続きます。以下はその一例です 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クライアントを初期化します es = Elasticsearch( url, api_key=(api_id, api_key), use_ssl=True, ca_certs=certifi.where() ) # インデックスを作成します es.indices.create(index="ember_ml") # ドキュメントを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")
特徴ベクトルをフラット化する必要がある点に留意してください。つまり、各ドキュメント内で、各特徴はサポートされるデータタイプ(数値、ブール、テキスト、キーワード、IPのいずれか)の個別のフィールドである必要があります。これは、データフレーム分析が1つ以上の要素を持つ配列をサポートしないためです。また、EMBERデータセットに登場していた(はじめに確認された)フィールドが、Elasticsearch互換のデータフォーマットにマッチする形に変換されている点にも注目しましょう。この変換は後ほど、時系列の可視化を作成するために行われています。
すべてのデータが適切なフォーマットでElasticsearchにインジェストされたか確認するため、Dev Tools Console(開発ツールコンソール。[Management](管理)>[Dev Tools](開発ツール)よりアクセス)で、以下のクエリを実行します。
次のクエリで、ドキュメントの数を数えます。
GET ember_ml/_count
次のクエリで、インデックス内のドキュメントを検索し、正しい形式となっていることを確認します。
GET ember_ml/_search
データがElasticsearchに期待値通りインデックスされたことを確認したら、分析ジョブを作成する準備が整ったことになります。しかし、ジョブを作成する前にもう一仕事あります。ジョブのインデックスパターンを定義する必要があります。インデックスパターンを使うと、Kibana(と、結果的にそのジョブ)に対し、作業するデータをどのElasticsearchインデックスに入れるか指示することができます。このデモでは、ember_*
というインデックスパターンを作成し、使用するember_ml
インデックスにマッチさせます。
モデル教育
インデックスパターンの作成を完了したところで、先ほど説明した2つの特徴サブセットを使って2つの分析ジョブを作成しましょう。この手順は、Kibanaの機械学習アプリで実行します。ジョブの設定は、以下の要領で行います。
- Job type(ジョブタイプ):“分類”を選択肢、所与のバイナリが悪意あるものか、無害なものかを推定します。Elasticの機械学習でベースとなる分類モデルはブーストの一種で、ブーストツリー回帰とよばれます。ブーストツリー回帰を使うと複数の弱いモデルを組み合わせ、混成モデルを作成することができます。ブーストツリー回帰は、データポイントが特定のクラスに属する確立を予測する決定木を使用します。
- Dependent variable(従属変数):今回は“ラベル”を使用し、1を“悪意がある”、0を“無害”とします。
- Fields to include(含めるフィールド):教育に含めるフィールドを指定します。
- Training percentage(教育パーセンテージ):特に大規模なデータセットで作業する場合、反復的な教育アプローチ(例:教育パーセンテージの低い教育ジョブの作成から開始し、パフォーマンスを検証する。そこで、教育パーセンテージを引き上げる必要があるか判断する、といったアプローチ)が推奨されます。今回はかなり大規模なデータセット(30万のドキュメント)で作業するので、10%の教育パーセンテージで開始します。
- Additional information options(その他の情報オプション):デモではデフォルトのままにしていますが、この段階で教育ジョブのパイパーパラメーターを設定することもできます。
- Job details(ジョブの詳細):ジョブに、適切なジョブIDと送信先インデックスを割り当てます。
- Create index pattern(インデックスパターンを作成):無効にします。今回は2つのジョブの結果を一緒に可視化するため、単一のインデックスパターンを作成して両方の教育ジョブの送信先インデックスを一致させます。
上述のプロセスに続いて、バイトヒストグラムのみを特徴として使用するジョブ(送信先インデックスはbytes_preds
)を1つ、バイトヒストグラム以外のすべての情報を特徴として使用するジョブ(送信先インデックスはmain_preds
)を1つ、合計で2つの分析ジョブを作成します。この分析ジョブは、このモデルで各特徴に最適なエンコードと、最もパフォーマンスの良い特徴、および最適なハイパーパラメーターを判断します。ジョブの進行状況はMachine Learning(機械学習)アプリでも追跡できます。
モデル評価
ジョブが完了したら、完了したジョブの横に表示される[View](表示)ボタンをクリックして予測結果を確認できます。[View](表示)ボタンをクリックすると、送信先インデックスのコンテンツがデータフレームスタイルで表示されるほか、モデルの混同行列を確認できます。データフレーム(下の画像参照)の各行は、サンプルが教育やモデル予測、ラベル、クラスの確立とスコアリングに使用されたかどうかを示しています。
混同行列を使うと、双方のモデルのパフォーマンスを評価、および比較できます。このデモのケースでは、混同行列の各行が実際のクラスのインスタンスを示し、各列が予測されたクラスのインスタンスを示します。つまり、真の陽性、偽陽性(最上位行)、偽陰性、真の陰性(最下位行)の評価基準として使うことができます。
少なくともこのデモンストレーションの目的においては、どちらのモデルも非常に精度が高いことがわかります。そこで教育をもう1ラウンド実施する、つまりハイパーパラメーター調整を行ってみたいと思います。次のセクションでは、2つのモデルをKibanaで視覚的に比較し、どちらのモデルをデプロイするか判断します。
モデルの監視
個々の送信先インデックス内に双方のモデルの予測を入れたところで、次の手順です。この手順でインデックスパターン(今回は(*_preds
)を作成して双方をマッチさせ、モデル監視ダッシュボードをKibana上に作成します。今回のケースで、監視ダッシュボードを使う目的は2つあります。
- バイトヒストグラムのみのモデルと、もう1つのモデルのパフォーマンスを比較する目的。比較は、TSVBの可視化を使用して実施する。
- さまざまなメトリックを追跡し、モデルのパフォーマンスを向上させる目的。水平バーの可視化を使って予測確率のほか、無害なサンプルと悪意があるサンプルの数を視覚的に表現し、またTSVBで偽陽性率と偽陰性率を追跡する。
2つのモデルの偽陰性率と偽陽性率を優位な時間範囲にわたって観測した結果と、前のセクションで混同行列を調査した結果を見ると、一般的な情報、ファイルヘッダー情報、セクション情報、文字列で教育したモデルの方がパフォーマンスにすぐれるという結論を導くことができます。次に、このモデルをデプロイし、ポストデプロイの監視を行うと仮定し、このモデルに関して追跡するさまざまなメトリックをプロットします。
実際のユースケースでは、運用候補となるモデルを比較する目的でこうした監視ダッシュボードを使うこともできます。またいずれかのモデルをデプロイした後は、運用環境内でモデル崩壊の兆候(例:偽陽性の群発)を特定し、有意義な対応(例:新規モデルの教育)をトリガーする目的にも役立ちます。次のセクションでは、機械学習の運用パイプラインに選択したモデルをデプロイする手順を説明します。
教師ありモデルをデプロイし、インジェスト時にデータをエンリッチする
Elastic Stackではモデルの教育と評価を実行できるほか、インジェストパイプラインで教育済みモデルを使用することもできます。インジェスト時にデータをエンリッチするという機械学習モデルの活用法を可能にする仕様です。このセクションでは、さきほど教育したマルウェア分類モデルをデータエンリッチに使用する手順を実践します。
前提として、悪意があるか無害であるかを分類したバイナリから抽出したデータがストリーミングされているものとします。このデータをインジェストパイプライン経由でElasticsearchにインジェストし、推論プロセッサー内で先ほど構築した教育済みマルウェア分類モデルを参照させる、という作業になります。
最初の手順は、推論プロセッサーとインジェストパイプラインの構築です。推論プロセッサーで最も重要な部分は、教育済みモデルとそのmodel_id
です。Kibanaのコンソールで、これを以下のREST APIコールを使ってルックアップします。
GET _ml/inference
このREST APIコールでクラスター内の教育済みモデルのリストが返され、また各モデルについて、これは推論を実行するために必要になる model_id
や、モデルの教育に使用したフィールド、モデルが教育した日時などの特徴が表示されます。
クラスター内に多数の教育済みモデルがある場合、モデルの教育に使用したデータフレーム分析ジョブの名前を入れたワイルドカードクエリでAPIコールを実行するとわかりやすい場合があります。今回のケースでは、ember_*
というジョブでモデルの教育を行いました。そこで、以下のコールを実行することで、
GET _ml/inference/ember_*
目的のモデルをすばやく絞り込むことができます。
model_id
の特記事項の作成が完了したところで、次はインジェストパイプラインのconfigの作成です。configの全文は以下の通りです。inference
というタイトルの設定ブロックに注目してください。このブロックは、ドキュメントのエンリッチに使用するモデルを参照します。またこのブロックはtarget_field
(このデモではis_malware
に設定していますが、好みに応じて設定できます)を指定します。このフィールドは推論プロセッサーがドキュメントを処理した場合に、機械学習フィールドのプリフィックスを追加する目的で使用されます。
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 } } } } ] }
さて、今、バイナリの特徴を含んだドキュメントのインジェストを実行中だとします。私たちの目的は、このデータを各バイナリの悪質性の予測でエンリッチすることです。以下に、サンプルドキュメントの要約を示します。
{ "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 ]
Index APIの1つを使ってこのドキュメントをインジェストしてから、先ほど作成したmalware-classification
パイプラインを通過させましょう。このデモでドキュメントを送信先インデックスmain_preds
にインジェストするAPIコールを以下に示します。スペースの都合上、ドキュメントは要約されています。
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, ...
この結果、送信先インデックスmain_preds
に、教育済み機械学習モデルの予測でエンリッチされた新しいドキュメントが生成されました。ドキュメントを見てみると([Discover]タブなどから表示できます)、作成したconfigに基づき、推定プロセッサーが教育済み機械学習モデルの予測をドキュメントに追加していることがわかります。このケースでは、ドキュメント(悪意の有無を推測したい未知のバイナリを示す)に“1”のクラスが割り当てられました。この“1”は、モデルがそのバイナリに悪意があると予測していることを示します。
予測を含む新しいドキュメントが送信先インデックスに追加されると、Kibanaのダッシュボードに自動でピックアップされます。ダッシュボードは、新しいサンプルで教育済みモデルが発揮するパフォーマンスに関するインサイトを時系列で示します。
まとめ
運用環境において、モデルのデプロイ責任を取ることはできません(取るべきでもありません)。つまりパイプラインには、顧客環境にリーチする以前に効果的にモデルを評価する仕組みが必要です。またデプロイ後は、モデルを厳密に監視しなければなりません。こうした取り組みは、データサイエンスチームが未知の問題を予測し、モデル崩壊の兆候がある場合に必要な措置を講じる上で役立ちます。
この記事では、優秀なストレージとしての性質を備え、モデル教育と内蔵の調整機能、およびKibanaの包括的な可視化ツールスイートを搭載したElastic Stackがこのような機械学習パイプラインをエンドツーエンドに管理するすぐれたプラットフォームとなる理由を説明しました。