Translate

2018年2月23日金曜日

TesnorFlowの乳がんデータ分類器チュートリアルを翻訳してみた。

Twitterのタイムラインに以下の記事が流れてきた。



ので、読んでみたら、比較的読みやすい内容だったので、
翻訳してみた。
以下、at your own riskで参照してください。
--------

乳がん検出用ニューラルネットを簡単に構築できます


機械学習と人工知能があなたのプログラム方法を変えるでしょう。それは確かに学習に値するコーディングにおける基本的な変化です。最初はちょっと大変です - 物事を行うアルゴリズムを書くのではなく、代わりにマシンを訓練するのですから。

ふつうは、コンセプトカウント、つまり生産性を高めるために理解しなければならない新しいコトの数は、少しばかりなんです。そのことを念頭に置いて、私は、あなたを導くためのチュートリアルを書こうと思っていました。それが、細胞スキャンで乳がんを検出するニューラルネットワークです!

今回はCSVファイルとなっている構造化データを扱います。これは、生検で採取された細胞の画像を精密に検査して生成されたものです。また、画像を直接操作することも可能ですが、ここではこのアプローチを選択しました。このチュートリアルコードを変更すれば、気になる問題を修正することができるからです。癌検出に取り組んでいない可能性があります。うまくいけば、ここで使うテクニックもあなたのためになるでしょう!

私は 悪性または良性細胞の数値を持つ新しい列を作成するためにここで利用できるデータを少し調整して使用しました。修正されたデータセットはここにあります。

私はこのチュートリアルをできるだけシンプルで再利用できるようにしようとしました。他のデータがあれば、このコードを修正してニューラルネットワーク分類器を構築するのは比較的簡単です。


フィーチャーとラベルを理解する

本題に入る前に、「フィーチャー」と「ラベル」について詳しく説明させてください。ちょっと混乱するかもしれませんけど。

「フィーチャ」をデータの属性と考えてください。このチュートリアルで使用する乳癌データベースの場合は、細胞の大きさや形などです。電子メールを扱うのであれば、フィーチャーは送信者、件名、メール本文などになります。

「ラベル」は、予測または分類したいデータの属性と考えることができます。乳がんの場合、細胞が良性か悪性かを知りたいので、これがラベルになります。電子メールの例だと、メールが迷惑メールかどうかをラベルにすることができます。

ニューラルネットをトレーニングするプロセスは非常に簡単です。あなたは、フィーチャーとラベルを含むデータの束を用意します。そして、それをトレーニングセットとテストセットに分割します。

あなたのトレーニングセットから、あなたのフィーチャーを取り分け、対応するラベルが何であるかをニューラルネットに伝えます。損失関数と入力関数(これらについては次のチュートリアルで詳しく説明しています)に基づいて、ラベルを決定するフィーチャを使って学習します。

学習が終わったら、テストセットで試してみましょう。ここでは、ラベルの内容を予測し、正解ラベルの内容と比較します。これから、その正答率(accuracy)を判断することができます。


TensorFlow を使ってニューラルネットワークを構築する

理論的な話は十分ですね、ではコーディングをはじめましょう!それが学ぶための最善の方法の1つなのです。私は TensorFlow を使ってNeural Netをビルドしてテストました。Pythonをメインのプログラミング言語としてトレーニングやテストを実行します。

まず、必要なライブラリをインポートしましょう:


import tensorflow as tf
import pandas as pd
import numpy as np
pandas numpy は大量の数値計算やデータ管理をサポートしてくれるPythonのライブラリです。

次に、プログラムのさまざまな側面についていくつかの変数を作成しましょう。私はコードをより移植性の高いものにするためにこれらを最初に記述することが好きです。


# データはトレーニングセットとテストセットに分割する必要があります
# 80/20を使用するには、トレーニングのサイズを.8に設定します
training_set_size_portion = .8

# トレーニングセットとテストセットに分割する前に、データをシャッフルするには
# この値をTrueに設定します
do_shuffle = True
# 正解率(accuracy)スコアを記録する変数
accuracy_score = 0
# DNNにはユニットが隠されており、ここにその仕様が設定されています
hidden_units_spec = [10,20,10]
n_classes_spec = 2
# モデルとチェックポイントを保持するための一時ディレクトリを定義する
tmp_dir_spec = "tmp/model"
# トレーニングのステップ数
steps_spec = 2000
# epoch数
epochs_spec = 15
# ファイル名 - アップロードする場合はこれを必ず変更してください
file_name = "wdbc.csv"

# ここにフィーチャーセットがあります。
# CSVには、カラムの名前が表示されます。
# ここでは、これらのすべてを使用します(半径とテクスチャ)。
features = ['radius','texture']

# 予測するラベルは次のとおりです -- CSVの列でもあります(診断値)
labels = ['diagnosis_numeric']

# データを提供するファイル名は次のとおりです
data_name = 'wsbc.csv'

# データの入手もとURLは次のとおりです
data_url = 'http://www.laurencemoroney.com/wp-content/uploads/2018/02/wdbc.csv'
私はこのようにしてコードを非常に汎用的にしています。乳がんのデータに興味がない場合  は、これらの値、特にfeature_keyslabel_key、およびデータの場所(data_namedata_url)を変更してください。

では、データをロードしましょう:


file_name = tf.keras.utils.get_file(data_name, data_url)
my_data = pd.read_csv(file_name, delimiter=',')
簡単でしたね。



指定した列に基づいてトレーニングとテストセットを作成する

あなたのデータにはすでに何らかの形の順番があり、これは学習/テストに影響を与える可能性があります。たとえば、乳がんでサイズ別に分類され、最初のd報のデータが良性であり最後の方が悪性である可能性が高い場合は、良性のデータを中心にトレーニングしてしまい、テスト対象がほとんど悪性になってしまいます。トレーニングとテストセットに分割する前に、データをシャッフルすることは、一般的には良いアイデアなのです:

# pandas の DataFrame を使用すると、再インデックスメソッドをシャッフルできます
# Docs: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.reindex.html#pandas.DataFrame.reindex
# doShuffleプロパティがtrueの場合、これをシャッフルします
# 本当にデータの傾向があなたの学習に影響しないことを確認するためにシャッフルするべきですが、
# ここではオプションにしています
if do_shuffle:
 randomized_data = my_data.reindex(np.random.permutation(my_data.index))
else:
 randomized_data = my_data
データをランダム化したら、次に分割します。先ほどトレーニングサイズの部分を指定したので、それに基づいてトレーニングセットに含めるレコードの数を計算し、残りはテストセットにします。このコードは、各セットのサイズを提供しています...

total_records = len(randomized_data)
training_set_size = int(total_records * training_set_size_portion)
test_set_size = total_records = training_set_size
...このコードでは、トレーニングフィーチャとラベルに指定したサイズに基づいて、データをトレーニングフィーチャとラベルセットに分割します。私たちはrandomized_data の'head' (頭) から取っていきます。

# トレーニングフィーチャとトレーニングラベルの構築
training_features = randomized_data.head(training_set_size)[features].copy()
training_labels = randomized_data.head(training_set_size)[labels].copy()
print(training_features.head())
print(training_labels.head())
同様に、 'tail' (お尻)のレコードにはテストセットが含まれています。test_set_size 分を取っていきます。

# テストフィーチャとテストラベルの構築
testing_features = randomized_data.tail(test_set_size)[features].copy()
testing_labels = randomized_data.tail(test_set_size)[labels].copy()


TensorFlow フィーチャカラムを作成する

ニューラルネットワーク分類器は、フィーチャカラムが tf.feature_column 型として指定する必要があります。ろれらのカラムはぜんぶ数値なので、numeric_column 型に設定します。

feature_columns = [tf.feature_column.numeric_column(key) for key in features]

データを分類するために使用されるニューラルネットワークを定義する

私たちがすべてのデータを持っていることを考えれば、データをトレーニングするニューラルネットワークオブジェクトを作成できます。これは、作成したばかりのフィーチャカラムと、ニューラルネットワークの隠れユニットの数を定義するパラメータ、およびクラスの数を引数として取ります。ネットワークをトレーニングするときに、一時ファイルとチェックポイント、および完成したモデルを指定されたモデルディレクトリに保存します。

隠れユニットは、ネットワークがどのように見えるかを直接的に指定したものです。例えば、ここでのデフォルトは [10,20,10] です。つまり、10個のニューロンの層があり、それぞれ20個のニューロンに接続されます。そして次の層である第3層の10個のニューロンに接続されます。

クラスは、私たちが分類しているクラスの(分類)数です。このケースでは、2つのクラスで乳がん分類を行っているので、2つのクラスをトレーニングします。


classifier = tf.estimator.DNNClassifier(
    feature_columns=feature_columns,
    hidden_units=hidden_units_spec,
    n_classes=n_classes_spec,
    model_dir=tmp_dir_spec)


ネットワークをトレーニングする

次のステップは、データ使って分類器をトレーニングすることです。これを行うには、フィーチャー(別名 'x')とラベル(別名'y')を指定する入力関数を作成します  。これは pandas_input_fn として指定することによって行われます。

# トレーニング入力関数の定義
 train_input_fn = tf.estimator.inputs.pandas_input_fn(x=training_features, y=training_labels, num_epochs=epochs_spec, shuffle=True)
そしてニューラルネットワークに、入力関数と、それをトレーニングするために使用したいステップの数を与えることで、トレーニングを開始することができます。異なる結果を得るために異なるステップ数を試してみてください。2000ステップの乳がんデータの場合、私は通常、テストセットに対して 90% 以上の精度を得ることができました。

# 分類器を使ってモデルをトレーニングする
 classifier.train(input_fn=train_input_fn, steps=steps_spec)

ネットワークをテストする

モデルのトレーニングと同様に  テストフィーチャーとテストラベルを渡す以外は、まったく同じ方法で入力関数を指定することで、我々はモデルをテストします:

# テスト入力関数の定義
 test_input_fn = tf.estimator.inputs.pandas_input_fn(x=testing_features, y=testing_labels, num_epochs=epochs_spec, shuffle=False)
つぎに、分類器にテスト入力関数を評価させ、正解率を取得します。テストセットを渡し、分類結果を実際の値と比較し、これを使って正解率(accuracy)を計算し、正確なスコアを表示します:
# 正解率(accuracy) を評価する
 accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"]
 print("Accuracy = {}".format(accuracy_score))
この時点で、ネットワークのトレーニングパラメータを調整して、ネットワークをトレーニングするための最良の値が何であるか把握することができます。場合によっては、適切なフィーチャーカラムをニューラルネットワークに与えていない場合があるかもしれません。また、ステップ数やネットワーク層の設定などを微調整することもできます。これは TensorFlow の素晴らしい点です。このように簡単に作業できます!

ネットワークを使用する

トレーニングを受けたテスト済みのネットワークが完成したので、まだ未投入のさまざまなデータセットを予測するためにどのように反応するかを見たいでしょう。それを実行する方法を実行して、ここで結果を読んでみましょう。

まず、予測セットはフィーチャー列と一致しなくてはなりません。したがって、このチュートリアルでは2つのフィーチャカラムに対してのみトレーニングを行い、しかも両方とも数値でした。このため予測セットで分類したいのであれば、同じ型式のデータをネットワークに渡す必要があります。たとえば、次のコードでは、半径14・テクスチャ25、半径13・テクスチャ26の2つのセルの予測セットを作成しています:


# 予測セットの作成 -- 分類させたい入力フィーチャーのリスト
prediction_set = pd.DataFrame({'radius':[14, 13], 'texture':[25, 26]})
そしてトレーニングやテストと同様に、入力関数を指定しますが、予測を始めるのでラベル(引数'y')がないので、ラベルを戻すことを期待して入力を指定します:
predict_input_fn = tf.estimator.inputs.pandas_input_fn(x=prediction_set, num_epochs=1, shuffle=False)
分類機はこの関数にもとづいてラベルを予測します。

# 予測結果のリストを取得する
predictions = list(classifier.predict(input_fn=predict_input_fn))
この処理はたくさんのデータを返しますが、私たちの分類は'classes'として保存されるので、それらを抽出してprintすることができます:

predicted_classes = [p["classes"] for p in predictions] results=np.concatenate(predicted_classes) print(results)

まとめ

ウィスコンシンのデータベースから乳がんのデータを分類するためにニューラルネットワークをトレーニングしただけでなく、あらゆるCSVファイルの分類を容易に行うことができるコードを作成しています。ぜひためして下のコメント欄にあなたの経験を書いて教えてください(元サイトにはコメント機能がある)!

--------

Estimator、入力関数の時代になったので、本家サイトのチュートリアルもそろそろかわるかもなあ..

0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...