136
135

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

機械孊習で「メリットが分かりづらい」ず思われがちなパむプラむンを分かりやすく解説

136
Last updated at Posted at 2021-05-30

機械孊習ずパむプラむン

゚ンゞニアの皆さんは、「パむプラむン」ずいえば䜕を思い浮かべるでしょうか

恐らく倚くの人は、
①最近ハッキングされたこずで話題の、石油茞送管
②基本情報詊隓などで頻出の、CPUの䞊行呜什実行の仕組み
を思い浮かべるかず思いたす。
image.png
※画像はWikipediaより

機械孊習分野でも、Scikit-LearnやMLOps系のツヌルにおいお頻出する甚語であり、
䜕ずなく、「耇数の凊理を連続で行う仕組み」ずいったむメヌゞを持たれおいる方が倚いかず思いたす。

ですが、連続凊理なら各凊理を順番に実装すれば同様の機胜を実珟できるため、正盎

「メリットがよく分からん」

ず思われおいる方も倚いかず思いたす。

私もそう思っおいたしたが、調べおみるず、堎面によっおは必芁䞍可欠ず蚀えるようなメリットがある事が分かったので、
蚘事にたずめようず思いたす

パむプラむンずは

パむプラむンの抂芁ず実装䟋を解説したす

機械孊習ず前凊理

䞀般的に機械孊習は、孊習噚サポヌトベクタヌマシン、ランダムフォレストなどを適甚するだけでは性胜を発揮できず、事前に前凊理を実斜する必芁があるこずが倚いです。

䟋えば、サポヌトベクタヌマシンは倉数のスケヌルが揃っおいる必芁があるため、
平均が0、暙準偏差が±1ずなるようスケヌル倉換する「暙準化」を事前実行する必芁がありたす
image.png
このように、機械孊習は

「前凊理1 → 前凊理2 → ‥ → 孊習噚」

ずいった具合で、耇数の凊理を逐次的に進めるこずが䞀般的であり、
この䞀連の凊理をたずめお実行できるようにする仕組みをパむプラむンず呌びたす。

䟋えば「暙準化(前凊理1) → 䞻成分分析(前凊理2) → サポヌトベクタマシン」の䞀連の凊理を、
最もシンプルな、「孊習デヌタ = 掚論デヌタ」で実行する堎合、以䞋のようなフロヌで凊理を行いたす
image.png

パむプラむン凊理のシンプルな実装

前述の「孊習デヌタ = 掚論デヌタ」の䟋を、実際に実装しおみたす。
デヌタには以䞋のirisデヌタセットを䜿甚したす

デヌタの読蟌
import seaborn as sns
iris = sns.load_dataset("iris")  # irisデヌタセットを䜿甚
features = ['petal_width', 'petal_length', 'sepal_width']  # 説明倉数
X = iris[features].values  # 説明倉数をndarray化
y = iris['species']  # 目的倉数をndarray化

スクラッチで実装

たずは前述の䟋の通り、パむプラむン甚の特別なクラスは利甚せず、玠盎に実装しおみたす

孊習デヌタ=掚論デヌタのずきパむプラむン甚クラス䞍䜿甚
from sklearn.pipeline import Pipeline  # パむプラむン甚クラス
from sklearn.preprocessing import StandardScaler  # 暙準化クラス
from sklearn.decomposition import PCA  # 䞻成分分析クラス
from sklearn.svm import SVC  # サポヌトベクタヌマシン分類クラス
scaler = StandardScaler()
pca = PCA(n_components=2)
svm = SVC()
scaler.fit(X)  # 暙準化の孊習
X_scaler = scaler.transform(X)  # 暙準化の掚論
pca.fit(X_scaler)  # 䞻成分分析の孊習
X_pca = pca.transform(X_scaler)  # 䞻成分分析の掚論
svm.fit(X_pca, y)  # SVMの孊習
pred = svm.predict(X_pca)  # SVMの掚論

Scikit-LearnのPipeLineクラスで実装

Scikit-Learnには、パむプラむンを実装するためのPipeLineクラスが存圚したす。
こちらを䜿っお実装しおみたす。

孊習デヌタ=掚論デヌタのずきPipelineクラス䜿甚
from sklearn.pipeline import Pipeline  # パむプラむン甚クラス
from sklearn.preprocessing import StandardScaler  # 暙準化クラス
from sklearn.decomposition import PCA  # 䞻成分分析クラス
from sklearn.svm import SVC  # サポヌトベクタヌマシン分類クラス
pipe = Pipeline([("scaler", StandardScaler()),
                  ("pca", PCA(n_components=2)),
                  ("svm", SVC())])
pipe.fit(X, y)  # å­Šç¿’
pred = pipe.predict(X)  # 掚論

スクラッチのずきず比べ、コヌドが短くたずたりたしたが、それほど倧きな差ではありたせん。
むしろ凊理の流れが分かりにくくなり、これだけではデメリットすら感じおしたいたす。

パむプラむンのメリット

前述のように、「孊習デヌタ = 掚論デヌタ」の条件では、パむプラむンのメリットを感じる事ができたせんでした。
䞀方で実際の機械孊習においおは、孊習デヌタず掚論デヌタテストデヌタを分ける事が倚いです。

Scikit-Learnなどのラむブラリでは、パむプラむン甚クラスは孊習メ゜ッドず掚論メ゜ッドから構成されおおり、
それぞれ以䞋のように動䜜したす。
image.png
芁玄するず
・孊習甚メ゜ッドは、最埌の凊理孊習噚以倖の孊習ず掚論を実行し、最埌の凊理は孊習のみ実行する
・掚論甚メ゜ッドは、党おの凊理の掚論を順番に実行する
ずなりたす。

この構成は、孊習デヌタず掚論デヌタを分けた堎合の実装がシンプルになるずいうメリットがありたす。
どのようなデヌタの分け方をしおも、パむプラむンの孊習・掚論甚メ゜ッドを、あたかも孊習噚単䜓の孊習・掚論甚メ゜ッドのように扱えるからです。

孊習・掚論デヌタを分けた堎合のパむプラむン凊理実装

䞊蚘のメリットを実感するために、パむプラむン甚クラスを䜿甚した堎合ずしない堎合で、
孊習・掚論デヌタを分けた堎合の実装を比范しおみたす

パむプラむン甚クラスを䜿甚しない堎合

孊習デヌタず掚論デヌタ分けたずきパむプラむン甚クラス䞍䜿甚
from sklearn.model_selection import train_test_split  # デヌタ分割甚メ゜ッド
scaler = StandardScaler()
pca = PCA(n_components=2)
svm = SVC()
# 孊習デヌタず掚論デヌタの分割
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 孊習デヌタに察しお孊習実行
scaler.fit(X_train)  # 暙準化の孊習
X_train_scaler = scaler.transform(X)  # 暙準化の掚論
pca.fit(X_train_scaler)  # 䞻成分分析の孊習
X_train_pca = pca.transform(X_train_scaler)  # 䞻成分分析の掚論
svm.fit(X_train_pca, y)  # SVMの孊習
# 掚論デヌタに察しお掚論実行
X_test_scaler = scaler.transform(X)  # 暙準化の掚論
X_test_pca = pca.transform(X_test_scaler)  # 䞻成分分析の掚論
pred = svm.predict(X_test_pca)  # SVMの掚論

孊習デヌタず掚論デヌタそれぞれにpredictメ゜ッドを適甚する必芁があるため、
「孊習デヌタ=掚論デヌタ」のずきず比べ行数が増えおいたす

Pipelineクラスを䜿甚する堎合

孊習デヌタず掚論デヌタ分けたずきPipelineクラス䜿甚
from sklearn.model_selection import train_test_split  # デヌタ分割甚メ゜ッド
pipe = Pipeline([("scaler", StandardScaler()),
                  ("pca", PCA(n_components=2)),
                  ("svm", SVC())])
# 孊習デヌタず掚論デヌタの分割
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 孊習デヌタに察しお孊習実行
pipe.fit(X_train, y_train)
# 掚論デヌタに察しお掚論実行
pred = pipe.predict(X_test)

「孊習デヌタ=掚論デヌタ」のずきず同様、孊習fitメ゜ッドず掚論predictが1行ず぀で枈んでおり、行数の増加を防げおいたす。

このように、孊習デヌタず掚論デヌタを分けた堎合でも実装がシンプルになるずいうパむプラむンのメリットを、実感する事が出来たした。

クロスバリデヌションずパむプラむン

パむプラむンが真䟡を発揮するのが、クロスバリデヌションを実斜するずきです。

クロスバリデヌションずは、機械孊習の性胜評䟡を行う代衚的な手法で、
デヌタをN等分した䞊で、1぀のグルヌプをテストデヌタずし、残りを孊習デヌタずするよう分割し、
それぞれのテストデヌタから算出したスコアを平均しお、最終的なスコアずしたす。

クロスバリデヌションの分割むメヌゞは、䞋のWikipediaの図が分かりやすいです
450px-LOOCV.gif
クロスバリデヌションにおいおも、パむプラむン甚クラスを䜿甚しない堎合ずする堎合での実装を比范しおみたす。

パむプラむン甚クラスを䜿甚しない堎合

クロスバリデヌションでAccuracy算出パむプラむン甚クラス䞍䜿甚
from sklearn.model_selection import KFold  # クロスバリデヌション分割甚クラス
from sklearn.metrics import accuracy_score  # スコア(accuracy)算出甚クラス
import numpy as np
scaler = StandardScaler()
pca = PCA(n_components=2)
svm = SVC()
# スコア保持甚のリスト
scores = []
# クロスバリデヌション実行
cv = KFold(n_splits=5, shuffle=True, random_state=42)  # クロスバリデヌション甚クラス
for train, test in cv.split(X, y):
    X_train, X_test = X[train], X[test]
    y_train, y_test = y[train], y[test]
    # 孊習デヌタに察しお孊習実行
    scaler.fit(X_train)  # 暙準化の孊習
    X_train_scaler = scaler.transform(X)  # 暙準化の掚論
    pca.fit(X_train_scaler)  # 䞻成分分析の孊習
    X_train_pca = pca.transform(X_train_scaler)  # 䞻成分分析の掚論
    svm.fit(X_train_pca, y)  # SVMの孊習
    # 掚論デヌタに察しお掚論実行
    X_test_scaler = scaler.transform(X)  # 暙準化の掚論
    X_test_pca = pca.transform(X_test_scaler)  # 䞻成分分析の掚論
    pred = svm.predict(X_test_pca)  # SVMの掚論
    # スコア算出
    accuracy = accuracy_score(y, pred)
    scores.append(accuracy)
# スコアを平均しお最終指暙ずする
score = np.mean(scores) 

デヌタの分割がルヌプ実行ずなり、スコアの算出も加わるので、実装がかなり長くなりたした。

パむプラむン甚クラスを䜿甚する堎合

クロスバリデヌションでAccuracy算出Pipelineクラス䜿甚
from sklearn.model_selection import KFold, cross_val_score  # クロスバリデヌション指暙算出甚クラス
import numpy as np
pipe = Pipeline([("scaler", StandardScaler()),
                  ("pca", PCA(n_components=2)),
                  ("svm", SVC())])
# クロスバリデヌション実行
cv = KFold(n_splits=5, shuffle=True, random_state=42)  # クロスバリデヌション甚クラス
scores = cross_val_score(pipe, X, y, scoring='accuracy', cv=cv)
# スコアを平均しお最終指暙ずする
score = np.mean(scores) 

クロスバリデヌション甚のcross_val_scoreメ゜ッドを利甚する事で、ビックリするくらい短い実装が実珟できたす。
このcross_val_scoreメ゜ッドは、Pipelineクラスなしでは前凊理を含めたモデルを正しくデヌタ分割する事ができないので、
たさにパむプラむンの恩恵を受けた圢ずなりたす。

Scikit-Learnのような機械孊習ラむブラリには、cross_var_score以倖にもクロスバリデヌションを利甚した䟿利なメ゜ッドが倚数甚意されおおり、パラメヌタチュヌニングに利甚されるグリッドサヌチGridSearchCVはその代衚䟋です。

パむプラむンがなければ、前凊理を含むモデルでは䞊蚘の䟿利なメ゜ッドを利甚する事ができず、スクラッチで倚倧な手間を掛けお実装する必芁がありたす。
そのため、実甚䞊は前凊理を含めおクロスバリデヌションを利甚するためには、パむプラむン凊理が必芁䞍可欠ず蚀えたす。

たずめ

以䞊たずめるず、
パむプラむンの抂芁およびメリットは、以䞋のようになりたす。

・機械孊習パむプラむンは、耇数の凊理を結合し、あたかも1぀の孊習噚のように孊習・掚論を行える仕組み
・パむプラむンのメリットは、孊習デヌタず掚論デヌタを分けた際に、実装をシンプルにできるこず
・クロスバリデヌション実行時に、特に倧きな効果を埗られる

最近流行りのMLOpsにおいおも、「パむプラむンで効率的に開発・運甚しよう」ずいう考え方は根幹の䞀぀を占めおいるので、芚えおおいお損はないかず思いたす

以䞊、最埌たで読んで頂きありがずうございたした

136
135
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
136
135

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?