方程式の解法からディープラーニングまで:TensorFlowPythonチュートリアル

公開: 2022-03-11

最近、人工知能の世界では、自動運転車の進歩が公表されていることから、ショパンの模倣品を構成している機械やビデオゲームが本当に得意な機械まで、いくつかの目覚ましい発展が見られます。

これらの進歩の中心となるのは、ディープラーニングやその他の機械学習モデルを導き出すのに役立つ多くのツールであり、その中にはTorch、Caffe、Theanoがあります。 ただし、Google Brainが独自のフレームワークであるTensorFlowを使用して2015年11月にオープンソースに移行して以来、このソフトウェアライブラリの人気が最も人気のあるディープラーニングフレームワークであることがわかりました。

TensorFlow

なぜこれが起こったのですか? 理由には、利用可能な豊富なサポートとドキュメント、その生産準備、さまざまなデバイス間での計算の分散の容易さ、および優れた視覚化ツールであるTensorBoardが含まれます。

最終的に、TensorFlowは、包括的で柔軟な一連の技術機能と非常に使いやすいものを組み合わせることができます。

この記事では、単純なニューラルネットワークの実装による深層学習での使用を紹介する前に、このツールを使用して一般的な数値問題を解決することで、このツールの仕組みを理解します。

あなたが始める前に

機械学習手法の基礎知識を前提としています。 追いつく必要がある場合は、この非常に便利な投稿をチェックしてください。

Python APIのデモを行うので、Numpyを理解することも有益です。

TensorFlowを設定するには、こちらの手順に従ってください。

Windowsを使用している場合は、執筆時点で、2.7ではなくPython3.4以降を使用する必要があることに注意してください。

次に、準備ができたら、次のコマンドでライブラリをインポートできるようになります。

 import tensorflow as tf

TensorFlowソリューションのステップ1/2:グラフを作成する

TensorFlowプログラムの構築は、通常2つの主要なステップで構成されます。最初のステップは、実行したい計算を記述した計算グラフを作成することですが、実際には実行したり、値を保持したりすることはありません。

他のグラフと同様に、ノードとエッジがあります。 エッジはテンソルを表し、テンソルはn次元配列を表します。 たとえば、次元(またはTensorFlowでのランク)が0のテンソルはスカラー、ランク1はベクトル、ランク2は行列などです。

ノードは、必要に応じてテンソルを入力として使用して、出力テンソルを生成する操作を表します。 このような操作には、加算( tf.add )、行列の乗算( tf.matmul )、および定数の作成( tf.constant )が含まれます。

それでは、これらのいくつかを組み合わせて最初のグラフを作成しましょう。

 a = tf.constant([2.5, 2]) b = tf.constant([3, 6], dtype=tf.float32) total = tf.add(a, b)

ここでは、3つの操作を作成しました。そのうちの2つは、定数1-d配列を作成するためのものです。

データ型は、渡されたvalues引数から推測されます。または、 dtype引数でこれらを示すことができます。 bこれを行わなかった場合、 int32が推測され、 tf.addが2つの異なるタイプで加算を定義しようとしたときにエラーがスローされます。

TensorFlowソリューションのステップ2/2:操作を実行します

グラフは定義されていますが、実際にグラフ(またはグラフの一部)で計算を行うには、TensorFlowセッションを設定する必要があります。

 sess = tf.Session()

または、IPythonなどのインタラクティブシェルでセッションを実行している場合は、次を使用します。

 sess = tf.InteractiveSession()

セッションオブジェクトのrunメソッドは、Tensorを評価する1つの方法です。

したがって、上記で定義された加算計算を評価するために、取得するテンソルである「total」を渡します。これは、 tf.addの出力を表します。

 print(sess.run(total)) # [ 5.5 8. ]

ここでは、TensorFlowのVariableクラスを紹介します。 定数はグラフ定義の固定部分ですが、変数は更新できます。 クラスコンストラクターには初期値が必要ですが、それでも、変数に対して他の操作を実行する前に、変数を明示的に初期化する操作が必要です。

変数は特定のセッションでのグラフの状態を保持するため、変数をよりよく理解するには、同じグラフを使用して複数のセッションで何が起こるかを観察する必要があります。

 # Create a variable with an initial value of 1 some_var = tf.Variable(1) # Create op to run variable initializers init_op = tf.global_variables_initializer() # Create an op to replace the value held by some_var to 3 assign_op = some_var.assign(3) # Set up two instances of a session sess1 = tf.Session() sess2 = tf.Session() # Initialize variables in both sessions sess1.run(init_op) sess2.run(init_op) print(sess1.run(some_var)) # Outputs 1 # Change some_var in session1 sess1.run(assign_op) print(sess1.run(some_var)) # Outputs 3 print(sess2.run(some_var)) # Outputs 1 # Close sessions sess1.close() sess2.close()

グラフと2つのセッションを設定しました。

両方のセッションで初期化を実行した後(これを実行せずに変数を評価すると、エラーが発生します)、1つのセッションでのみ割り当て操作を実行します。 ご覧のとおり、変数値は持続しますが、セッション間では持続しません。

数値問題に取り組むためのグラフのフィード

TensorFlowのもう1つの重要な概念は、プレースホルダーです。 変数は状態を保持しますが、プレースホルダーは、グラフが期待できる入力とそのデータ型(およびオプションでその形状)を定義するために使用されます。 次に、計算を実行するときに、これらのプレースホルダーを介してデータをグラフにフィードできます。

TensorFlowグラフは、最終的にトレーニングしたいニューラルネットワークに似始めていますが、その前に、概念を使用して、金融業界の一般的な数値問題を解決しましょう。

次のような方程式でyを見つけたいとします。

v = Ce -0.5y + Ce -y + Ce -1.5y +(C + P)e -2y

与えられたvCPは定数)。

これは、市場価値v 、元本P 、およびクーポンCが半年ごとに支払われるが、継続的な複利でキャッシュフローが割り引かれる債券の満期利回り( y )を計算するための式です。

基本的には試行錯誤しながらこのような方程式を解く必要があり、 yの最終値に焦点を合わせるために二分法を選択します。

まず、この問題をTensorFlowグラフとしてモデル化します。

CPは固定定数であり、グラフの定義の一部を形成します。 yの下限と上限を調整するプロセスが必要です。 したがって、これらの境界( aおよびbで示される)は、 yを推測するたびに変更する必要がある変数( aおよびbの中点と見なされる)の適切な候補です。

 # Specify the values our constant ops will output C = tf.constant(5.0) P = tf.constant(100.0) # We specify the initial values that our lower and upper bounds will be when initialised. # Obviously the ultimate success of this algorithm depends on decent start points a = tf.Variable(-10.0) b = tf.Variable(10.0) # We expect a floating number to be inserted into the graph v_target = tf.placeholder("float") # Remember the following operations are definitions, # none are carried out until an operation is evaluated in a session! y = (a+b)/2 v_guess = C*tf.exp(-0.5*y) + C*tf.exp(-y) + C*tf.exp(-1.5*y) + (C + P)*tf.exp(-2*y) # Operations to set temporary values (a_ and b_) intended to be the next values of a and b. # eg if the guess results in av greater than the target v, # we will set a_ to be the current value of y a_ = tf.where(v_guess > v_target, y, a) b_ = tf.where(v_guess < v_target, y, b) # The last stage of our graph is to assign the two temporary vals to our variables step = tf.group( a.assign(a_), b.assign(b_) )

これで、特定のセッションに対して評価できる操作と変数のリストができました。 これらの操作の一部は、実行される他の操作に依存しているため、たとえばv_guessを実行すると、連鎖反応が開始され、 CPなどの他のテンソルが最初に評価されます。

これらの操作の一部は、値を指定する必要があるプレースホルダーに依存しています。では、実際にその値をどのようにフィードするのでしょうか。

これは、 run関数自体のfeed_dict引数を介して行われます。

a_を評価する場合は、次のように、プレースホルダーv_targetの値をプラグインします。

 sess.run(a_, feed_dict={v_target: 100})

私たちに0.0を与えます。

130のv_targetを接続すると、-10.0になります。

これは「ステップ」操作であり、実際には他のすべての操作を前提条件として実行する必要があり、実際にはグラフ全体を実行します。 これは、セッション全体で実際の状態を実際に変更する操作でもあります。 したがって、ステップを実行すればするほど、変数abyの実際の値に向かって段階的に微調整します。

したがって、方程式のvの値が95に等しいとしましょう。セッションを設定し、その上でグラフを100回実行してみましょう。

 # Set up a session and initialize variables sess = tf.Session() tf.global_variables_initializer().run() # Run the step operation (and therefore whole graph) 100 times for i in range (100): sess.run(step, feed_dict={v_target:95})

ここでyテンソルを評価すると、望ましい答えに似たものが得られます

print(sess.run(y)) # 0.125163

ニューラルネットワーク

TensorFlowの仕組みを理解したので、これをTensorFlowに組み込まれたいくつかの追加の機械学習操作と組み合わせて、単純なニューラルネットワークをトレーニングできます。

ここでは、データポイントが特定の領域(原点を中心とする半径0.5の円)内にあるかどうかに応じて、2D座標系でデータポイントを分類します。

もちろん、これはa^2 + b^2 < 0.5場合、与えられた点(a,b)をチェックするだけで具体的に検証できますが、この機械学習実験の目的のために、代わりにトレーニングセット:一連のランダムなポイントと、それらが目的の領域に該当するかどうか。 これを作成する1つの方法は次のとおりです。

 import numpy as np NO_OF_RANDOM_POINTS = 100 CIRCLE_RADIUS = 0.5 random_spots = np.random.rand(NO_OF_RANDOM_POINTS, 2) * 2 - 1 is_inside_circle = (np.power(random_spots[:,0],2) + np.power(random_spots[:,1],2) < CIRCLE_RADIUS).astype(int)

次の特徴を持つニューラルネットワークを作成します。

  1. これは、2つのノードを持つ入力レイヤーで構成され、「random_spots」内に含まれる一連の2次元ベクトルをフィードします。 これは、トレーニングデータを待機しているプレースホルダーによって表されます。
  2. 出力レイヤーにも2つのノードがあるため、一連のトレーニングラベル(「is_inside_circle」)をスカラーのプレースホルダーにフィードしてから、それらの値をワンホット2次元ベクトルに変換する必要があります。
  3. 3つのノードで構成される1つの隠れ層があるため、重み行列とバイアスベクトルに変数を使用する必要があります。これらは、トレーニングを実行するときに調整する必要がある値です。
 INPUT_LAYER_SIZE = 2 HIDDEN_LAYER_SIZE = 3 OUTPUT_LAYER_SIZE = 2 # Starting values for weights and biases are drawn randomly and uniformly from [-1, 1] # For example W1 is a matrix of shape 2x3 W1 = tf.Variable(tf.random_uniform([INPUT_LAYER_SIZE, HIDDEN_LAYER_SIZE], -1, 1)) b1 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE], -1, 1)) W2 = tf.Variable(tf.random_uniform([HIDDEN_LAYER_SIZE, OUTPUT_LAYER_SIZE], -1, 1)) b2 = tf.Variable(tf.random_uniform([OUTPUT_LAYER_SIZE], -1, 1)) # Specifying that the placeholder X can expect a matrix of 2 columns (but any number of rows) # representing random spots X = tf.placeholder(tf.float32, [None, INPUT_LAYER_SIZE]) # Placeholder Y can expect integers representing whether corresponding point is in the circle # or not (no shape specified) Y = tf.placeholder(tf.uint8) # An op to convert to a one hot vector onehot_output = tf.one_hot(Y, OUTPUT_LAYER_SIZE)

グラフの定義を完了するために、より良い分類器に到達するように変数をトレーニングするのに役立ついくつかの操作を定義します。 これらには、行列計算、活性化関数、およびオプティマイザーが含まれます。

 LEARNING_RATE = 0.01 # Op to perform matrix calculation X*W1 + b1 hidden_layer = tf.add(tf.matmul(X, W1), b1) # Use sigmoid activation function on the outcome activated_hidden_layer = tf.sigmoid(hidden_layer) # Apply next weights and bias (W2, b2) to hidden layer and then apply softmax function # to get our output layer (each vector adding up to 1) output_layer = tf.nn.softmax(tf.add(tf.matmul(activated_hidden_layer, W2), b2)) # Calculate cross entropy for our loss function loss = -tf.reduce_sum(onehot_output * tf.log(output_layer)) # Use gradient descent optimizer at specified learning rate to minimize value given by loss tensor train_step = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)

グラフを設定したら、セッションを設定して「train_step」を実行します(これにより、前提条件の操作も実行されます)。 これらの操作の一部はプレースホルダーを使用するため、それらの値を指定する必要があります。 このトレーニングステップは、学習アルゴリズムの1つのエポックを表しているため、実行するエポックの数にループされます。 情報提供の目的で「損失」テンソルなど、グラフの他の部分を実行できます。

 EPOCH_COUNT = 1000 sess = tf.Session() tf.global_variables_initializer().run() for i in range(EPOCH_COUNT): if i%100 == 0: print('Loss after %d runs: %f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle}))) sess.run(train_step, feed_dict={X: random_spots, Y: is_inside_circle}) print('Final loss after %d runs: %f' % (i, sess.run(loss, feed_dict={X: random_spots, Y: is_inside_circle})))

アルゴリズムをトレーニングしたら、ポイントをフィードして、次のようにニューラルネットワークの出力を取得できます。

 sess.run(output_layer, feed_dict={X: [[1, 1]]}) # Hopefully something close to [1, 0] sess.run(output_layer, feed_dict={X: [[0, 0]]}) # Hopefully something close to [0, 1]

出力ベクトルの最初のメンバーが0.5より大きい場合は、ポイントを円の外側に分類できます。それ以外の場合は、内側に分類できます。

多くのポイントに対してoutput_layerテンソルを実行することにより、学習者がポジティブに分類されたポイントを含む領域をどのように想定しているかを知ることができます。 トレーニングセットのサイズ、学習率、およびその他のパラメーターを試して、意図した円にどれだけ近づくことができるかを確認することをお勧めします。

ほぼ三角形
トレーニングセット:100ポイント
学習率:0.01
エポック:1000

小さな三角形
トレーニングセット:1000ポイント
学習率:0.01
エポック:1000

大きな三角形
トレーニングセット:1000ポイント
学習率:0.01
エポック:10000

ほぼ円
トレーニングセット:1000ポイント
学習率:0.001
エポック:10000

要約

これは、トレーニングセットやエポックの量を増やしても、優れた学習者を保証するものではないという良い教訓です。学習率は適切に調整する必要があります。

うまくいけば、これらのデモンストレーションにより、TensorFlowのコア原則についての優れた洞察が得られ、より複雑な手法を実装するための強固な基盤が提供されます。

TensorboardやGPU全体でのモデルのトレーニングなどの概念については説明していませんが、これらはTensorFlowのドキュメントで詳しく説明されています。 この強力なフレームワークを使用してエキサイティングな深層学習タスクに取り組むことに慣れるのに役立つ多くのレシピがドキュメントにあります。

関連: TensorFlowでの最急降下法の多くのアプリケーション