1. 概要

このチュートリアルでは、 Apache SparkMLlibを活用して機械学習製品を開発する方法を理解します。 コアコンセプトを示すために、SparkMLlibを使用して簡単な機械学習製品を開発します。

2. 機械学習の簡単な入門書

機械学習は、人工知能として知られるより広範な傘の一部です。 機械学習とは、パターンと推論に関する特定の問題を解決するための統計モデルの研究を指します。 これらのモデルは、問題空間から抽出されたトレーニングデータを使用して、特定の問題に対して「トレーニング」されます。

この例を取り上げると、この定義が正確に何を意味するのかがわかります。

2.1. 機械学習カテゴリ

アプローチに基づいて、機械学習を教師なしカテゴリに大まかに分類できます。 他のカテゴリもありますが、次の2つを維持します。

  • 教師あり学習は、入力と目的の出力の両方を含むデータセットで機能します。たとえば、プロパティのさまざまな特性と予想される賃貸収入を含むデータセットです。 教師あり学習はさらに、分類と回帰と呼ばれる2つの大きなサブカテゴリに分けられます。
    • 分類アルゴリズムは、プロパティが占有されているかどうかなど、カテゴリ出力に関連しています
    • 回帰アルゴリズムは、プロパティの値など、連続的な出力範囲に関連しています
  • 一方、教師なし学習は、は入力値のみを持つデータのセットで機能します。 これは、入力データに固有の構造を識別しようとすることで機能します。 たとえば、消費行動のデータセットを通じてさまざまなタイプの消費者を見つけることができます。

2.2. 機械学習ワークフロー

機械学習は、真に学際的な研究分野です。 それには、ビジネスドメイン、統計、確率、線形代数、およびプログラミングの知識が必要です。 これは明らかに圧倒される可能性があるため、これに整然とアプローチするのが最善です。これは通常、機械学習ワークフローと呼ばれます。

ご覧のとおり、すべての機械学習プロジェクトは、明確に定義された問題ステートメントから開始する必要があります。 この後に、問題に答える可能性のあるデータに関連する一連の手順を実行する必要があります。

次に、通常、問題の性質を調べてモデルを選択します。 これに続いて、モデルの微調整として知られる一連のモデルのトレーニングと検証が行われます。 最後に、これまでに見られなかったデータでモデルをテストし、問題がなければ本番環境にデプロイします。

3. Spark MLlib とは何ですか?

Spark MLlibは、 Spark Core上のモジュールであり、APIとして機械学習プリミティブを提供します。 機械学習は通常、モデルトレーニングのために大量のデータを処理します。

Sparkのベースコンピューティングフレームワークは大きなメリットです。 これに加えて、MLlibは一般的な機械学習と統計アルゴリズムのほとんどを提供します。 これにより、大規模な機械学習プロジェクトでの作業が大幅に簡素化されます。

4. MLlibを使用した機械学習

これで、機械学習と、MLlibがこの取り組みにどのように役立つかについて十分なコンテキストが得られました。 SparkMLlibを使用して機械学習プロジェクトを実装する基本的な例から始めましょう。

機械学習ワークフローに関する議論を思い出すと、問題の説明から始めて、データに移る必要があります。 幸いなことに、機械学習の「Hello World」、 IrisDatasetを選択します。 これは多変量のラベル付きデータセットであり、さまざまな種のアイリスのがく片と花びらの長さと幅で構成されています。

これは私たちの問題の目的を与えます:がく片と花びらの長さと幅からアイリスの種を予測できますか

4.1. 依存関係の設定

まず、関連するライブラリをプルするために、Mavenで次の依存関係を定義する必要があります。

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-mllib_2.11</artifactId>
    <version>2.4.3</version>
    <scope>provided</scope>
</dependency>

また、Spark APIを使用するには、SparkContextを初期化する必要があります。

SparkConf conf = new SparkConf()
  .setAppName("Main")
  .setMaster("local[2]");
JavaSparkContext sc = new JavaSparkContext(conf);

4.2. データの読み込み

まず最初に、CSV形式のテキストファイルとして利用できるデータをダウンロードする必要があります。 次に、このデータをSparkにロードする必要があります。

String dataFile = "data\\iris.data";
JavaRDD<String> data = sc.textFile(dataFile);

Spark MLlibは、入力データと対応するラベルを表すために、ローカルと分散の両方のいくつかのデータ型を提供します。 最も単純なデータ型はVectorです。

JavaRDD<Vector> inputData = data
  .map(line -> {
      String[] parts = line.split(",");
      double[] v = new double[parts.length - 1];
      for (int i = 0; i < parts.length - 1; i++) {
          v[i] = Double.parseDouble(parts[i]);
      }
      return Vectors.dense(v);
});

ここには、主に統計分析を実行するための入力機能のみが含まれていることに注意してください。

トレーニングの例は通常、複数の入力機能と、クラスLabeledPointで表されるラベルで構成されます。

Map<String, Integer> map = new HashMap<>();
map.put("Iris-setosa", 0);
map.put("Iris-versicolor", 1);
map.put("Iris-virginica", 2);
		
JavaRDD<LabeledPoint> labeledData = data
  .map(line -> {
      String[] parts = line.split(",");
      double[] v = new double[parts.length - 1];
      for (int i = 0; i < parts.length - 1; i++) {
          v[i] = Double.parseDouble(parts[i]);
      }
      return new LabeledPoint(map.get(parts[parts.length - 1]), Vectors.dense(v));
});

データセットの出力ラベルはテキストであり、アイリスの種を示しています。 これを機械学習モデルにフィードするには、これを数値に変換する必要があります。

4.3. 探索的データ分析

探索的データ分析には、利用可能なデータの分析が含まれます。 現在、機械学習アルゴリズムはデータ品質に敏感であるため、高品質のデータは、望ましい結果を提供する可能性が高くなります。

典型的な分析の目的には、異常の除去とパターンの検出が含まれます。 これは、利用可能なデータから有用な機能に到達するための機能エンジニアリングの重要なステップにも役立ちます。

この例のデータセットは小さく、整形式です。 したがって、多くのデータ分析にふける必要はありません。 ただし、Spark MLlibには、かなりの洞察を提供するAPIが装備されています。

簡単な統計分析から始めましょう。

MultivariateStatisticalSummary summary = Statistics.colStats(inputData.rdd());
System.out.println("Summary Mean:");
System.out.println(summary.mean());
System.out.println("Summary Variance:");
System.out.println(summary.variance());
System.out.println("Summary Non-zero:");
System.out.println(summary.numNonzeros());

ここでは、私たちが持っている特徴の平均と分散を観察しています。 これは、機能の正規化を実行する必要があるかどうかを判断するのに役立ちます。 すべての機能を同じスケールで使用すると便利です。 また、モデルのパフォーマンスに悪影響を与える可能性のあるゼロ以外の値にも注意を払っています。

入力データの出力は次のとおりです。

Summary Mean:
[5.843333333333332,3.0540000000000003,3.7586666666666666,1.1986666666666668]
Summary Variance:
[0.6856935123042509,0.18800402684563744,3.113179418344516,0.5824143176733783]
Summary Non-zero:
[150.0,150.0,150.0,150.0]

分析するもう1つの重要なメトリックは、入力データの特徴間の相関です。

Matrix correlMatrix = Statistics.corr(inputData.rdd(), "pearson");
System.out.println("Correlation Matrix:");
System.out.println(correlMatrix.toString());

任意の2つの機能間の高い相関関係は、それらが増分値を追加しておらず、そのうちの1つを削除できることを示しています。 機能がどのように相関しているかは次のとおりです。

Correlation Matrix:
1.0                   -0.10936924995064387  0.8717541573048727   0.8179536333691672   
-0.10936924995064387  1.0                   -0.4205160964011671  -0.3565440896138163  
0.8717541573048727    -0.4205160964011671   1.0                  0.9627570970509661   
0.8179536333691672    -0.3565440896138163   0.9627570970509661   1.0

4.4. データの分割

機械学習ワークフローの説明を思い出すと、モデルのトレーニングと検証を数回繰り返した後、最終テストを行う必要があります。

これを実現するには、トレーニングデータをトレーニング、検証、テストセットに分割する必要があります。 簡単にするために、検証の部分はスキップします。 それでは、データをトレーニングセットとテストセットに分割しましょう。

JavaRDD<LabeledPoint>[] splits = parsedData.randomSplit(new double[] { 0.8, 0.2 }, 11L);
JavaRDD<LabeledPoint> trainingData = splits[0];
JavaRDD<LabeledPoint> testData = splits[1];

4.5. モデルトレーニング

これで、データセットを分析して準備する段階に到達しました。 残っているのは、これをモデルにフィードして魔法を開始することだけです! まあ、言うのは簡単です。 問題に適したアルゴリズムを選択する必要があります。前に説明したさまざまなカテゴリの機械学習を思い出してください。

私たちの問題が監視対象カテゴリ内の分類に当てはまることを理解するのは難しいことではありません。 現在、このカテゴリで使用できるアルゴリズムはかなりあります。

それらの中で最も単純なのはロジスティック回帰です(回帰という言葉が私たちを混乱させないようにします。結局のところ、それは分類アルゴリズムです):

LogisticRegressionModel model = new LogisticRegressionWithLBFGS()
  .setNumClasses(3)
  .run(trainingData.rdd());

ここでは、3クラスのLimitedMemoryBFGSベースの分類器を使用しています。 このアルゴリズムの詳細はこのチュートリアルの範囲を超えていますが、これは最も広く使用されているものの1つです。

4.6. モデル評価

モデルのトレーニングには複数の反復が含まれることを忘れないでください。ただし、簡単にするために、ここでは1つのパスを使用しました。 モデルをトレーニングしたので、テストデータセットでこれをテストします。

JavaPairRDD<Object, Object> predictionAndLabels = testData
  .mapToPair(p -> new Tuple2<>(model.predict(p.features()), p.label()));
MulticlassMetrics metrics = new MulticlassMetrics(predictionAndLabels.rdd());
double accuracy = metrics.accuracy();
System.out.println("Model Accuracy on Test Data: " + accuracy);

では、モデルの有効性をどのように測定するのでしょうか。 使用できるいくつかのメトリックがありますが、最も単純なものの1つはAccuracyです。 簡単に言えば、精度は予測の正しい数と予測の総数の比率です。 モデルの1回の実行で達成できることは次のとおりです。

Model Accuracy on Test Data: 0.9310344827586207

アルゴリズムの確率的性質により、これは実行ごとにわずかに異なることに注意してください。

ただし、一部の問題領域では、精度はあまり効果的な指標ではありません。 その他のより洗練されたメトリックは、適合率と再現率(F1スコア)、ROC曲線、および混同行列です。

4.7. モデルの保存と読み込み

最後に、トレーニング済みのモデルをファイルシステムに保存し、本番データで予測するためにロードする必要があることがよくあります。 これはSparkでは簡単です。

model.save(sc, "model\\logistic-regression");
LogisticRegressionModel sameModel = LogisticRegressionModel
  .load(sc, "model\\logistic-regression");
Vector newData = Vectors.dense(new double[]{1,1,1,1});
double prediction = sameModel.predict(newData);
System.out.println("Model Prediction on New Data = " + prediction);

そのため、モデルをファイルシステムに保存してロードし直しています。 ロード後、モデルをすぐに使用して、新しいデータの出力を予測できます。 ランダムな新しいデータの予測例は次のとおりです。

Model Prediction on New Data = 2.0

5. 原始的な例を超えて

私たちが経験した例は、機械学習プロジェクトのワークフローを幅広くカバーしていますが、それは多くの微妙で重要なポイントを残しています。 ここでそれらを詳細に説明することはできませんが、重要なもののいくつかを確かに説明することができます。

APIを介したSparkMLlibは、これらすべての領域で広範なサポートを提供しています。

5.1. モデルの選択

モデルの選択は、多くの場合、複雑で重要なタスクの1つです。 モデルのトレーニングは複雑なプロセスであり、望ましい結果が得られると確信しているモデルで行う方がはるかに優れています。

問題の性質は、選択する機械学習アルゴリズムのカテゴリを特定するのに役立ちますが、完全に完了しているわけではありません。 分類のようなカテゴリ内では、前に見たように、多くの場合、から選択できるさまざまなアルゴリズムとそのバリエーションがあります。

多くの場合、最善の行動は、はるかに少ないデータセットでのラピッドプロトタイピングです。 Spark MLlibのようなライブラリを使用すると、ラピッドプロトタイピングの作業がはるかに簡単になります。

5.2. モデルのハイパーパラメータ調整

一般的なモデルは、機能、パラメーター、およびハイパーパラメーターで構成されます。 特徴は、入力データとしてモデルに入力するものです。 モデルパラメーターは、モデルがトレーニングプロセス中に学習する変数です。 モデルによっては、経験に基づいて設定し、繰り返し調整する必要がある特定の追加パラメーターがあります。 これらはモデルハイパーパラメータと呼ばれます。

たとえば、学習率は、勾配降下ベースのアルゴリズムの典型的なハイパーパラメータです。 学習率は、トレーニングサイクル中にパラメーターを調整する速度を制御します。 これは、モデルが妥当なペースで効果的に学習できるように適切に設定する必要があります。

経験に基づいてこのようなハイパーパラメータの初期値から始めることはできますが、モデルの検証を実行し、手動で繰り返し調整する必要があります。

5.3. モデルのパフォーマンス

統計モデルは、トレーニング中、過剰適合と過適合の傾向があり、どちらもモデルのパフォーマンスを低下させます。 アンダーフィッティングとは、モデルがデータから一般的な詳細を十分に選択していない場合を指します。 一方、モデルがデータからノイズを拾い始めると、過剰適合が発生します。

過適合と過剰適合の問題を回避するためのいくつかの方法があり、それらはしばしば組み合わせて使用されます。 たとえば、過剰適合に対抗するために、最も採用されている手法には、交差検定と正則化があります。 同様に、アンダーフィッティングを改善するために、モデルの複雑さを増し、トレーニング時間を増やすことができます。

Spark MLlibは、正則化や相互検証など、これらの手法のほとんどを素晴らしいサポートをしています。 実際、ほとんどのアルゴリズムはデフォルトでサポートされています。

6. 比較におけるSparkMLlib

Spark MLlibは機械学習プロジェクトにとって非常に強力なライブラリですが、この仕事に適しているのは確かにそれだけではありません。 さまざまなサポートを備えたさまざまなプログラミング言語で利用できるライブラリがかなりあります。 ここでは人気のあるものをいくつか見ていきます。

6.1. Tensorflow / Keras

Tensorflow は、データフローと微分可能プログラミング用のオープンソースライブラリであり、機械学習アプリケーションに広く採用されています。 高レベルの抽象化であるKerasとともに、機械学習に最適なツールです。 これらは主にPythonとC++で記述され、主にPythonで使用されます。 Spark MLlibとは異なり、ポリグロットの存在はありません。

6.2. テアノ

Theano は、数式を操作および評価するためのもう1つのPythonベースのオープンソースライブラリです。たとえば、機械学習アルゴリズムで一般的に使用される行列ベースの式です。 Spark MLlibとは異なり、Theanoも主にPythonで使用されます。 ただし、KerasはTheanoバックエンドと一緒に使用できます。

6.3. CNTK

Microsoft Cognitive Toolkit(CNTK)は、C ++で記述されたディープラーニングフレームワークであり、有向グラフを介して計算ステップを記述します。 PythonとC++プログラムの両方で使用でき、主にニューラルネットワークの開発に使用されます。 おなじみの直感的な抽象化を提供する、使用可能なCNTKに基づくKerasバックエンドがあります。

7. 結論

要約すると、このチュートリアルでは、さまざまなカテゴリやワークフローなど、機械学習の基本について説明しました。 利用可能な機械学習ライブラリとして、SparkMLlibの基本を学びました。

さらに、利用可能なデータセットに基づいて、簡単な機械学習アプリケーションを開発しました。 この例では、機械学習ワークフローで最も一般的な手順のいくつかを実装しました。

また、典型的な機械学習プロジェクトの高度な手順のいくつかと、SparkMLlibがそれらにどのように役立つかについても説明しました。 最後に、私たちが使用できる代替の機械学習ライブラリのいくつかを見ました。

いつものように、コードはGitHubにあります。