TransmogrifAIでkaggleのコンペに出た話

TransmogrifAIでkaggleのコンペに出た話

こんにちは!Hacarusインターン生の小金丸と申します。京都で大学院生をしています。

米Salesforce.comがオープンソースで公開している自動化機械学習ライブラリ「TransmogrifAI」。今回はその性能を調べてみました!

1.はじめに

1-1.TransmogrifAIとは

TransmogrifAI(trăns-mŏgˈrə-fī:トランスモグリファイと読みます)はScala言語で作られた自動化機械学習ライブラリで、Apache Spark上で動作します。3条項BSDライセンスの下で公開されていて、上のリンクから入手できます。

自動化機械学習(以下AutoML)は名前の通り、機械学習のモデルを自動生成してくれるという技術のことです。TransmogrifAIを使うことで、機械学習に必要な知識を持たずとも高性能なモデルを作ることができるというわけですね!

AutoMLは近年様々な企業から提供されており、Hacarusでも以前にGoogleの「GCP AutoML Vision」を調べています。良ければご覧ください。

「AutoML Vision β版の真の実力を本気で調査してみた」

1-2.TransmogrifAIで出来ること

機械学習の運用までのフローは通常下図のようになります。目標を設定し、データ収集からモデル評価までを繰り返し、最後に本番運用を行います。

TransmogrifAIを使えば、このフローの手法の選択からモデル評価までの4ステップを自動的に行うことができます!

フローの循環部分において、データさえ用意すればあとは全てやってくれるみたいです。すごいですね。

(※ここでの”モデル構築”はハイパーパラメータの調整、学習などを指します。)

1-3.TransmogrifAIの利点

TransmogrifAIを用いる利点として、公式の紹介には以下のようなことが書かれています。

  1. 自動化によって、1/100程度の時間で手動調整モデルに近い精度を達成できる
  2. データ操作とMLワークフローを分離することで、高い再利用性を実現できる
  3. モデルを評価・考察する指標を提供することで、モデル理解の手助けを行える

1.2も素晴らしいですが、特に3がユーザーには嬉しいですね。自動生成されたモデルを理解しやすくなるのは、機械学習にあまり詳しくないであろうAutoMLユーザーにとって注目の機能だと思います。

1-4.TransmogrifAIのモデル

TransmogrifAIで使えるモデルは右図のようになります。線形回帰をはじめ、データコンペティションで人気のXGBoostまで幅広く実装されています。決定木を用いた手法が多く、深層学習系の手法はありませんが、そうすることで上記のモデルの考察性を得ていると思われます。

ユーザーがこれらのモデルから検証したいものを選ぶと、TransmogrifAIはそれらの中でハイパーパラメータの調整や特徴エンジニアリングなどを行いながら様々なモデルを生成し、最適なモデルを提案してくれます!

2.実際に動かしてみた

では、helloworldのTitanicサンプルコードをもとに、実際にTransmogrifAIを動かしてみました!

環境構築は公式の導入に従いました。環境構築後はReadmeを参考にするとhelloworldフォルダ内のexampleを実行できます。

2-1.手順

TransmogrifAIを使う際の具体的な流れは次のようになります。

学習

  1. 学習データを用意
  2. TransmogrifAIを用いた学習用Scalaコードを書く
  3. コードを実行し、モデルを作成・保存

予測

  1. 予測したいデータを用意
  2. 学習済みモデルを読み込み、新しいデータに適用する予測用Scalaコードを書く
  3. コードを実行し、結果を保存

今回学習に用いるデータはこちらになります。(kaggleのタイタニックコンペティションの学習データと同じものになります。)

2-2.学習用コード

・必要なライブラリをインポート

package com.salesforce.hw
import com.salesforce.op._
import com.salesforce.op.evaluators.Evaluators
import com.salesforce.op.features.FeatureBuilder
import com.salesforce.op.features.types._
import com.salesforce.op.readers.DataReaders
import com.salesforce.op.stages.impl.classification.BinaryClassificationModelSelector
import com.salesforce.op.stages.impl.classification.BinaryClassificationModelsToTry.{OpLogisticRegression, OpRandomForestClassifier, OpGBTClassifier, OpLinearSVC, OpDecisionTreeClassifier, OpNaiveBayes}
import com.salesforce.op.stages.impl.tuning.DataSplitter
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

読み込むCSVデータに対応するケースクラスを定義します。今回はタイタニック号の乗客データのため、乗客の年齢や性別、客室のランクなどが定義されています。

case class Passenger(
  id: Int,
  survived: Int,
  pClass: Option[Int],
  name: Option[String],
  sex: Option[String],
  age: Option[Double],
  sibSp: Option[Int],
  parCh: Option[Int],
  ticket: Option[String],
  fare: Option[Double],
  cabin: Option[String],
  embarked: Option[String]
)

・ケースクラスに対応した特徴量を定義します。乗客の生死を予測するため、”survived”は”asResponse”、その他の特徴量は”asPredictor”として定義しておきます。

val survived = FeatureBuilder.RealNN[Passenger].extract(_.survived.toRealNN).asResponse
val pClass = FeatureBuilder.PickList[Passenger].extract(_.pClass.map(_.toString).toPickList).asPredictor
val name = FeatureBuilder.Text[Passenger].extract(_.name.toText).asPredictor
val sex = FeatureBuilder.PickList[Passenger].extract(_.sex.map(_.toString).toPickList).asPredictor
val age = FeatureBuilder.Real[Passenger].extract(_.age.toReal).asPredictor
val sibSp = FeatureBuilder.Integral[Passenger].extract(_.sibSp.toIntegral).asPredictor
val parCh = FeatureBuilder.Integral[Passenger].extract(_.parCh.toIntegral).asPredictor
val ticket = FeatureBuilder.PickList[Passenger].extract(_.ticket.map(_.toString).toPickList).asPredictor
val fare = FeatureBuilder.Real[Passenger].extract(_.fare.toReal).asPredictor
val cabin = FeatureBuilder.PickList[Passenger].extract(_.cabin.map(_.toString).toPickList).asPredictor
val embarked = FeatureBuilder.PickList[Passenger].extract(_.embarked.map(_.toString).toPickList).asPredictor

・定義した特徴量から自分で新しい特徴量を作成することもできます。特徴量同士の演算は使いやすいように設計されていて、かなり簡潔に書くことができます。

val familySize = sibSp + parCh + 1
val estimatedCostOfTickets = familySize * fare
val pivotedSex = sex.pivot()
val normedAge = age.fillMissingWithMean().zNormalize()
val ageGroup = age.map[PickList](_.value.map(v => if (v > 18) "adult" else "child").toPickL
ist)

・特徴ベクトルを作成します。

val passengerFeatures = Seq(
      pClass, name, age, sibSp, parCh, ticket,
      cabin, embarked, familySize, estimatedCostOfTickets,
      pivotedSex, ageGroup
    ).transmogrify()

・ワークフローを定義します。


val trainDataReader = DataReaders.Simple.csvCase[Passenger](
      path = Option(csvFilePath),
      key = _.id.toString
    )
 val workflow =
      new OpWorkflow()
        .setResultFeatures(survived, prediction)
        .setReader(trainDataReader)

 val fittedWorkflow = workflow.train()
 println(s"Summary: ${fittedWorkflow.summaryPretty()}")

・結果出力!果たして…!

今回はGBT(Gradient Boosting Tree)がモデルとして選択されたようです。

指標一覧。Hold Out Setでも良い値が出ていて、これはテストデータでも良い結果が期待できそうです…!

3.kaggleに提出してみた

上手くモデルを自動生成することができたようなので、今度はテストデータで予測をします!

せっかくタイタニックデータを学習しているので、kaggleのタイタニックテストデータで予測を行い、コンペティションに提出してみました!

(※kaggleは機械学習コンペティションの最大手プラットフォームです)

3-1.予測用コード

・テストデータと2で作成したモデルを読み込みます。

val predictDataReader = DataReaders.Simple.csvCase[Passengers](
      path = Option(csvFilePath),
      key = _.id.toString
    )
    //モデルを読み込みます
val loadedworkflow =
      new OpWorkflow()
        .setResultFeatures(survived, prediction)
        .setReader(predictDataReader)
        .loadModel("/model/Titanic.model")

・予測結果をcsv形式で出力し、kaggleに提出!

var dataSet = loadedworkflow.setReader(predictDataReader).score()
dataSet = dataSet.withColumnRenamed("column_name", "prediction")
dataSet = dataSet.map(row => (row(0).asInstanceOf[String], row(1).asInstanceOf[Double], row(2).asInstanceOf[Map[String, Double]]("prediction")))
dataSet.write.mode(SaveMode.Overwrite).csv("/result/Titanic")

結果はこちら

11056グループ中5730位で、僕のベストスコアとなりました!昔頑張って出したスコアがいとも簡単に抜かれてしまって、喜んでいいのか悲しんでいいのか分かりません…

しかし、サンプルコード+α程度でこの成績はかなりスゴいのではないでしょうか?

事前処理やパラメータの範囲設定など、まだまだ試していない部分も多く、使いこなせれば強力なツールになりそうな気がします!

4.終わりに

簡単なコードで良い結果が出せて、個人的にはとてもびっくりしました。

締めくくりとして、はじめに紹介したHacarusの「GCP AutoML Vision」の記事で述べられている、機械学習に必要な4つの要素

  1. 機械学習の数学的知識
  2. プログラミングスキル
  3. 膨大なデータ
  4. マシンスペック

の観点から、TransmogrifAIのAutoMLとしての性能を考えてみます。

1.機械学習の数学的知識

ほぼ必要ありません。ただモデルの精度を高めるときには、データ加工やチューニングの知識が必要になりそうです。

2.プログラミングスキル

ある程度必要になります。しかし、Scalaに触れたことのなかった僕でもなんとか書けたので、TransmogrifAIを使ってみようという人のほとんどはプログラミングスキルは問題にならないと思います。

3.膨大なデータ

自前で用意する必要があります。代わりにデータからモデル作成まで内部で行うことができるため、クライアントのデータなどからモデル作成をしたい時など、秘匿データを用いる必要がある場合でもTransmogrifAIは使うことができます。

4.マシンスペック

必要になります。ただApache Spark上で動作するため高速分散処理が可能であり、要求されるスペックは最低限に抑えられるのではないかと思います。

以前調べた「GCP AutoML」との比較は以下のようになります。

用途 機械学習の知識 プログラミングスキル データ データの秘匿性 料金  マシンスペック
TransmogrifAI 〇:回帰・分類に幅広く対応 〇:必要なし △:ある程度必要 ×:自分で用意 〇:内部でモデル作成が可能 〇:無料 ×:必要
GCP AutoML △:画像認識・文章認識・翻訳のみ 〇:必要なし 〇:必要なし ×:自分で用意 ×:Google Cloudにあげる必要がある △:プランにより有料 〇:必要なし。Cloud上で動作

 

Scala+Apache Sparkというなじみのない環境で戸惑ったりもしましたが、総合的にみるとTransmogrifAIは機械学習のモデル作成のハードルをグッと下げてくれる、とても優秀なAutoMLだと思います!

「機械学習を使いたい、でもどんなモデルが良いのかわからない…」というユーザーだけでなく「機械学習はよく理解しているが、モデルの検証やパラメータの調整を自動化したい」というユーザーなど、幅広いデータサイエンティストの味方として今後広まったら良いなと感じました。

Takashi Someda

サンマイクロシステムズでエンジニアとしてキャリアをスタート。未踏ソフトウェア創造事業への採択をきっかけに、ベンチャーでのプロダクト開発に携わり続けている。現在はハカルスの CTO として、グローバルな開発チームとともにサービスを成長させるべく日々奮闘中。ソフトウェアとロックと家族を愛する40歳。

ニュースレター購読Newsletter

登録はこちら