masalibの日記

システム開発、運用と猫の写真ブログです

TensorFlow アルゴリズム(線形回帰)

「TensorFlow 2.0 Complete Course - Python Neural Networks for Beginners Tutorial」をベースに自分用に説明追加したものになります。

www.youtube.com

この動画は6時間もあるのでご注意

なお、実行したい人は下記のNoteBookから実行できます(要googleアカウント)

https://colab.research.google.com/drive/16GZH-UYe8hF3J4DlUFp2g67mv-iwDYVC

TensorFlowコア学習アルゴリズム

4つの基本的な機械学習アルゴリズムについて説明します。 それぞれの使用例を強調する前に、これらのアルゴリズムをそれぞれ固有の問題とデータセットに適用します。

私たちが焦点を当てるアルゴリズムは次のとおりです。

線形回帰

線形回帰は、機械学習の最も基本的な形式の1つであり、数値を予測するために使用されます。

このNoteBookでは、線形モデルを使用して、タイタニックデータセットから見知らぬ人の生存率を予測します。 このセクションは、次のドキュメントに基づいています

参考URL - https : //www.tensorflow.org/tutorials/estimator/linear

使い方

始める前に、線形回帰アルゴリズムの非常に表面レベルの説明を提供します。

線形回帰は非常に単純な概念に従います。データポイントが線形に関連している場合、 これらのポイントに最適なラインを生成し、それを使用して将来の値を予測できます。

1つのフィーチャと1つのラベルを持つデータセットの例を見てみましょう。

import matplotlib.pyplot as plt
import numpy as np

x = [1, 2, 2.5, 3, 4]
y = [1, 4, 7, 9, 15]
plt.plot(x, y, 'ro')
plt.axis([0, 6, 0, 20])

f:id:masalib:20200425204625p:plain
プロット1

このデータには線形の対応関係があることがわかります。 x値が増加すると、yも増加します。
この関係により、このデータセットに最適なラインを作成できます。
この例では、2つの次元で作業しているため、ラインは1つの入力変数のみを使用します。より多くの特徴を持つより大きなデータセットでは、ラインはより多くの特徴と入力を持ちます。

「最適なラインとは、データポイントの散布図を介して、それらのポイント間の関係を最もよく表すラインを指します。」
https://www.investopedia.com/terms/l/line-of-best-fit.asp

2Dの線の方程式について復習します。


y = mx + b

このグラフに最適な線の例を次に示します。

plt.plot(x, y, 'ro')
plt.axis([0, 6, 0, 20])
plt.plot(np.unique(x), np.poly1d(np.polyfit(x, y, 1))(np.unique(x)))
plt.show()

データセットに対してこのラインを生成したら、その方程式を使用して将来の値を予測できます。予測したいデータポイントの特徴をラインの方程式に渡し、その出力を予測として使用します。

Setup とインポート

始める前に、sklearnをインストールし、次のモジュールをインポートする必要があります。

!pip install -q sklearn #Googleコラボだけです
#pip install -q sklearn #Googleコラボじゃない場合はこっち
%tensorflow_version 2.x  #Googleコラボだけです

#`%tensorflow_version` only switches the major version: 1.x or 2.x.
#You set: `2.x  #Googleコラボだけです`. This will be interpreted as: `2.x`.
#TensorFlow is already loaded. Please restart the runtime to change versions.

from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from six.moves import urllib

import tensorflow.compat.v2.feature_column as fc

import tensorflow as tf

データ

機械学習の主要な部分はデータです!実際、非常に重要なので、 このチュートリアルで行うことのほとんどは、適切なデータの探索、クリーニング、および選択に焦点を当てています。 ここで注目するデータセットは、タイタニックデータセットです。船に乗っている各乗客についての情報がたくさんあります。 最初のステップは、常にデータを理解して調査することです。

以下では、データセットを読み込み、いくつかの組み込みツールを使用してデータセットを探索する方法を学びます。

# Load dataset.
dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv') # training data(トレーニングデータ)
dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv') # testing data(テストデータ)
y_train = dftrain.pop('survived')
y_eval = dfeval.pop('survived')

pd.read_csv()
メソッドは新しいパンダデータフレームを返します。データフレームはテーブルのようなものと考えることができます。実際、テーブルの表現を実際に見ることができます。

データセットから「存続」列をポップして、新しい変数に格納することにしました。この列は、その人が私たちの生き残ったものでなかったかどうかを単に示しています。

データを確認するには
.head()
のメソッドを使用します。これにより、データフレームの最初の5つのアイテムが表示されます。

dftrain.head()

f:id:masalib:20200425205530p:plain
最初の5件

そして、データのより統計的な分析が必要な場合は、この

.describe()

方法を使用できます。

dftrain.describe()

f:id:masalib:20200425205648p:plain
describe

そして、前回でた形状(shape)も表示する

dftrain.shape
#(627, 9)

627のエントリと9つの機能があります。

それでは、生存情報を見てみましょう。

y_train.head()
#0    0
#1    1
#2    1
#3    1
#4    0
#Name: survived, dtype: int64

各エントリが0または1であることに注意してください。どちらが生き残りを意味するか推測できますか?

そして今、ビジュアルは常に価値があるので、データのいくつかのグラフを生成。

dftrain.age.hist(bins=20)

f:id:masalib:20200425205913p:plain
dftrain.age.histのプロット

dftrain.sex.value_counts().plot(kind='barh')

f:id:masalib:20200425210043p:plain
性別のプロット

dftrain['class'].value_counts().plot(kind='barh')

f:id:masalib:20200425210130p:plain
部屋のクラス(グレード)

pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')

f:id:masalib:20200425210243p:plain
生存者の男女

この情報を分析すると、次のことがわかります。

  • ほとんどの乗客は20代か30代です
  • ほとんどの乗客は男性です
  • ほとんどの乗客は「サード」クラスに属しています
  • 女性は生存の可能性がはるかに高い

レーニングデータとテストデータ

上記の2つの異なるデータセットをロードしたことに気づいたかもしれません。
これは、モデルをトレーニングするときに、トレーニングとテストの 2つのデータセットが必要になるためです。
レーニングデータは、それが開発し、学ぶことができるように、私たちはモデルに送り込むものです。
通常、テストデータよりもはるかに大きいサイズです。
テストデータは、私たちがモデルを評価し、それが実行されてどれだけ見るために使用するものです。
モデルを評価するためにモデルがトレーニングされていない
別のデータセットを使用する必要があります。

理由としては
まあ、私たちのモデルのポイントは、これまで見たことのない新しいデータを予測できるようにすることです。
すでに見たデータでモデルを単純にテストすると、
正確さを正確に測定できなくなります。
モデルが単にトレーニングデータを記憶しただけではないのか、確信が持てません。
これが、テストとトレーニングのデータを分離する必要がある理由です。

機能列について

このデータセットには、カテゴリーと数値の 2種類の情報があります。
私たちのカテゴリーデータは数値ではないものです!たとえば、性別の列では数字を使用せず、「男性」「女性」という単語を使用しています。
モデルを作成してトレーニングする前に、カテゴリカルデータ数値データに変換する必要があります。
これを行うには、各カテゴリを整数でエンコードします(例:男性= 1、女性= 2)。

CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',
                       'embark_town', 'alone']
NUMERIC_COLUMNS = ['age', 'fare']

feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
  vocabulary = dftrain[feature_name].unique()  # 指定された機能列からすべての一意の値のリストを取得する
  feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))

for feature_name in NUMERIC_COLUMNS:
  feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))

print(feature_columns)

基本的にここでは、データセットで使用される機能のリストを作成しています。

内の不可解なコード行によりappend()、モデルが「男性」や「女性」などの文字列値を 整数にマッピングするために使用できるオブジェクトが作成されます。 これにより、データフレームを手動でエンコードする必要がなくなります。

参考URL - https://www.tensorflow.org/api_docs/python/tf/feature_column/categorical_column_with_vocabulary_list?version=stable

レーニングプロセス

これで、データセットの準備がほぼ完了しました。 モデルがどのようにトレーニングされているかを説明します。 具体的には、入力データがモデルにどのように供給されるかです。

この特定のモデルのデータは、32の小さなバッチでストリーミングされます。 これは、データセット全体を一度にモデルにフィードするのではなく、 単にエントリの小さなバッチをフィードすることを意味します。

エポックの数に応じて、これらのバッチをモデルに複数回フィードします。

エポックは、単に私たちのデータセット全体の一つのストリームです。 私たちが定義するエポックの数は、 モデルがデータセット全体を見る回数です。

複数のエポックを使用して、同じデータを複数回参照した後、 モデルがそれを推定する方法をより適切に決定できるようにします。

エポックが10個ある場合、モデルは同じデータセットを10回参照します。

データをバッチで複数回フィードする必要があるため、 入力関数と呼ばれるものを作成する必要があります。 入力関数は、データセットが各エポックでバッチに変換される方法を単に定義します。

入力機能

これから使用するTensorFlowモデルでは、 渡すデータが tf.data.Datasetオブジェクトとして渡される必要があります。

つまり、現在のpandaデータフレームを そのオブジェクトに変換できる入力関数を作成する必要があります。

以下に、一見複雑な入力関数が表示されます。 これは、TensorFlowのドキュメント

https://www.tensorflow.org/tutorials/estimator/linear

から直接引用したものです。

わかりやすくするためにできる限りコメントしましたが、 各メソッドの詳細については、ドキュメントを参照することをお勧めします。

def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
  def input_function():  # 内部関数, この部分が返されます
    ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))  # データとそのラベルをもつtf.data.Datasetのオブジェクトを作成する
    if shuffle:
      ds = ds.shuffle(1000)  # データの順序をランダム化する
    ds = ds.batch(batch_size).repeat(num_epochs)  # データセットを32のバッチに分割し、エポック数だけプロセルを繰り返す
    return ds  # データセットのバッチを返す
  return input_function  # 使用する関数オブジェクトを返す

# ここでは、モデルにフィールドできるデータセットオブジェクトを
# 取得するために返された入力関数を呼び出します
train_input_fn = make_input_fn(dftrain, y_train)  
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)

データセットを検査できます。

ds = make_input_fn(dftrain, y_train, batch_size=10)()
for feature_batch, label_batch in ds.take(1):
  print('Some feature keys:', list(feature_batch.keys()))
  print()
  print('A batch of class:', feature_batch['class'].numpy())
  print()
  print('A batch of Labels:', label_batch.numpy())
  
#Some feature keys: ['sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']
#A batch of class: [b'Third' b'Third' b'Third' b'First' b'Third' b'Third' b'First' b'First'
#b'Third' b'Third']
#A batch of Labels: [0 1 0 0 0 0 1 1 0 1]

tf.keras.layers.DenseFeaturesレイヤーを使用して、特定のフィーチャ列の結果を検査することもできます。

age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()

#WARNING:tensorflow:Layer dense_features is casting an input tensor from dtype float64 to the layer's dtype of #float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.
#If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely #only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.
#To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just #this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable #autocasting by passing autocast=False to the base Layer constructor.
#array([[28.],
#       [26.],
#       [48.],
#       [21.],
#       [14.],
#       [17.],
#       [30.],
#       [30.],
#       [28.],
#       [28.]], dtype=float32)

カテゴリカル列を検査するには、まずそれをインジケーター列に変換する必要があります。

gender_column = feature_columns[0]
tf.keras.layers.DenseFeatures([tf.feature_column.indicator_column(gender_column)])(feature_batch).numpy()

#array([[1., 0.],
#       [1., 0.],
#       [1., 0.],
#       [1., 0.],
#       [0., 1.],
#       [1., 0.],
#       [0., 1.],
#       [0., 1.],
#       [0., 1.],
#       [1., 0.]], dtype=float32)

モデルを作成する

このチュートリアルでは、線形推定アルゴリズムを使用して線形回帰アルゴリズムを利用します。

作成はとても簡単です!

linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns)
# 先程、作成した機能列を渡して線形回帰の推定器を作成します

# INFO:tensorflow:Using default config.
# WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmpn6vvticc
# INFO:tensorflow:Using config: {'_model_dir': '/tmp/tmpn6vvticc', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true
# graph_options {
#   rewrite_options {
#     meta_optimizer_iterations: ONE
#   }
# }
# , '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_service': None, '_cluster_spec': ClusterSpec({}), '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

モデルのトレーニン

モデルのトレーニングは、以前に作成した入力関数を渡すのと同じくらい簡単です。

linear_est.train(train_input_fn)  # トレーニング
result = linear_est.evaluate(eval_input_fn)  

clear_output()  # 出力をクリアにする
print(result['accuracy'])  # 結果変数は、単にモデル外の統計の口述です

# 0.7386364

約74%の精度のモデルができました(これは毎回変更されます)。 間違いではありませんが、私たちの最初の試みにはまともです。 次に、このモデルを実際に使用して予測を作成する方法を見てみましょう。

この

.predict()メソッド

を使用して、モデルから生存確率を取得できます。 このメソッドは、テストデータセットの各エントリの述語を格納する辞書のリストを返します。 以下では、いくつかのpandaのメソッドを使用して、予測のグラフをプロットしました。

pred_dicts = list(linear_est.predict(eval_input_fn))
probs = pd.Series([pred['probabilities'][1] for pred in pred_dicts])

probs.plot(kind='hist', bins=20, title='predicted probabilities')

o change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.

INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmp/tmpn6vvticc/model.ckpt-200
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
<matplotlib.axes._subplots.AxesSubplot at 0x7f539113ccf8>

f:id:masalib:20200425211146p:plain
結果のプロット