20200330のTensorFlowに関する記事は2件です。

ニューラルネットでの簡単な分類モデル

前回に引続き、ニューラルネットについての勉強をしてみました。

今回は、簡単な分類モデルの構築に挑戦。
以下の2つの変数を準備します。

0 \le x_1,x_2 \le 1

そして、2つの和によって、以下のような分類をしてみる。

t(x_1,x_2) = 
\left\{
\begin{matrix}
0 & (x_1 + x_2 < 1) \\
1 & (x_1 + x_2 \ge 1)
\end{matrix}
\right.

こんなシンプルなモデルを実装してみます。
0層??のニューラル考え方としては、以下の数式を検討します。

y(x_1,x_2) = \sigma(w_1 x_1 + w_2 x_2 + w_0)

ただし、σはシグモイド関数で、そのアウトプットは[0,1]に限定されます。これが本当特徴的で、y<0.5なら分類A、y>0.5なら分類B、のような意味を持たせているようです。実はこれって結構肝の部分な気がします。ニューラルネットでは、w1,w2,w0を調整することで、答えを出すような仕組み。ということで、誤差を見積もるファンクションを検討すると、この場合は交差エントロピーになるようです。具体的には、x1,x2に対して正解tを与えたとき、その交差エントロピーは以下のように表現されます。

E(w_1,w_2,w_0) = - (t \ln y + (1-t) \ln (1-y) )

詳細は、「パターン認識と機械学習」などを参照していただく(p.235あたり)として、ざっくりとしたイメージとしては・・・。0<y<1に注意して

  • yをクラスAの確率と見なす(t=1のとき)
  • 1-yをクラスBの確率と見なす(t=0のとき)

すると、tが与えられたときの確率p(t)は、X^0=1を利用して式を1本化することで

p(t)= y^t  (1-y)^{1-t}

となるようです。あとはログをとれば、E(w1,w2,w0)の式が導出されます。これを各サンプルごとに掛け算するので、各yiに対して

p(t)= \prod_i y_i^t  (1-y_i)^{1-t}

となるので、ログをとって

\ln p(t)= \sum_i (t \ln y_i + (1-t) \ln (1-y_i) )

となります。これは正解率の和のような感じなので、合っているほど値が大きくなります。そこで、最適化(最小化)問題として解くために符号を反転させてEを定義しました。繰り返しますが、以下の交差エントロピーになります。(複数サンプルバージョン)

E(w_1,w_2,w_0) = - \sum_i (t \ln y_i + (1-t) \ln (1-y_i) )

では、実際にソースコードを書いてみます。
まずは、変数部分。

# make placeholder
x_ph = tf.placeholder(tf.float32, [None, 3])
t_ph = tf.placeholder(tf.float32, [None, 1])

x_phは入力部分、本当は2つのはずですが、w0用のダミー変数(1固定)を入れておきました。これはいらないかも?
t_phは出力部分で、正解を与えるためのものです。0か1が入ります。

そして、これに入れるサンプルデータは適当に乱数で設定します。

# deta making???
N = 1000
x = np.random.rand(N,2)

# sum > 1.0 -> 1 : else -> 0
t = np.floor(np.sum(x,axis=1))

# ext x
x = np.hstack([x,np.ones(N).reshape(N,1)])

xを2つ作ったのち、yを作って、その後、ダミー変数を1個追加してます。これによって、xは1サンプルで3次元となっています。yはx1+x2が1以上のときに1、1未満では0となるように、小数点切捨てを利用して作成しています。

そして、ニューラルネットワークの層はとりあえず2つほど準備。

# create newral parameter(depth=2,input:3 > middle:30 > output:1)
hidden1 = tf.layers.dense(x_ph, 30, activation=tf.nn.relu)
newral_out = tf.layers.dense(hidden1, 1, activation=tf.nn.sigmoid)

あとは、交差エントロピーを定義して、最小化するように学習を定義します。単なるコピペですね。収束アルゴリズム設定など、まだよくわかっていません。

# Minimize the cross entropy
ce = -tf.reduce_sum(t_ph * tf.log(newral_out) + (1-t_ph)*tf.log(1-newral_out) )
optimizer = tf.train.AdamOptimizer()
train = optimizer.minimize(ce)

というわけで、上記を適当に組み合わせて、全体のソースを作ってみました。

import numpy as np
import tensorflow as tf

# deta making???
N = 1000
x = np.random.rand(N,2)

# sum > 1.0 > 1 : else > 0
t = np.floor(np.sum(x,axis=1))

# ext x
x = np.hstack([x,np.ones(N).reshape(N,1)])

train_x = x
train_t = t

# make placeholder
x_ph = tf.placeholder(tf.float32, [None, 3])
t_ph = tf.placeholder(tf.float32, [None, 1])
# create newral parameter(depth=2,input:3 > middle:30 > output:1)
hidden1 = tf.layers.dense(x_ph, 30, activation=tf.nn.relu)
newral_out = tf.layers.dense(hidden1, 1, activation=tf.nn.sigmoid)

# Minimize the cross entropy
ce = -tf.reduce_sum(t_ph * tf.log(newral_out) + (1-t_ph)*tf.log(1-newral_out) )
optimizer = tf.train.AdamOptimizer()
train = optimizer.minimize(ce)


# initialize tensorflow session
sess = tf.Session()
sess.run(tf.global_variables_initializer())

for k in range(1001):

    if np.mod(k,100) == 0:
        # get Newral predict data
        y_newral = sess.run( newral_out
                         ,feed_dict = {
                         x_ph: x, # xに入力データを入れている
                         })

        ce_newral = sess.run( ce
                         ,feed_dict = {
                         x_ph: x, # xに入力データを入れている
                         t_ph: t.reshape(len(t),1) # yに正解データを入れている
                         })

        sign_newral = np.sign(np.array(y_newral).reshape([len(t),1]) - 0.5)
        sign_orig = np.sign(np.array(t.reshape([len(t),1])) - 0.5)
        NGCNT = np.sum(np.abs(sign_newral-sign_orig))/2
        # check predict NewralParam
        print('[%d] loss %.2f hit_per:%.2f' % (k,ce_newral,(N-NGCNT)/N))


    # shuffle train_x and train_t
    n = np.random.permutation(len(train_x))
    train_x = train_x[n]
    train_t = train_t[n].reshape([len(train_t), 1])

    # execute train process
    sess.run(train,feed_dict = {
                     x_ph: train_x, # x is input data
                     t_ph: train_t # t is true data
                     })


# test用
x = np.array([0.41,0.5,1]).reshape([1,3])
loss_newral = sess.run( newral_out
                 ,feed_dict = {
                 x_ph: x, # xに入力データを入れている
                 })
# <0.5なら成功かな
print(loss_newral)

これを動かすと以下のようになります。

[0] loss 727.36 hit_per:0.35
[100] loss 587.68 hit_per:0.78
[200] loss 465.78 hit_per:0.89
[300] loss 358.70 hit_per:0.93
[400] loss 282.45 hit_per:0.94
[500] loss 230.54 hit_per:0.96
[600] loss 194.34 hit_per:0.97
[700] loss 168.11 hit_per:0.98
[800] loss 148.34 hit_per:0.98
[900] loss 132.93 hit_per:0.99
[1000] loss 120.56 hit_per:0.99
[[0.27204064]]

lossと書かれたところは、交差エントロピーの値、徐々に減っている様子が分かります。(変数名変えろよ・・・と突っ込み)
そして、hit_perは、学習データに対しての正解率。1.00で100%となりますが、99%の成功率のようです。
最後に、適当なテスト、x1=0.45,x2=0.5を入れたときのニューラルネットのアウトプットを出しています。この場合は、クラスBのt=0のはずなので、アウトプットは0.5より小さければ正解、かつ、0.5に近いほど迷っていると読み取れます。今回は0.27なので結構自信を持って答えてOKそうです。

最後に正解の出し方について、ちょっとだけ書いておきます。ポイントはNGの数を出しているところだと思います。以下一部ピックアップ。

        # get Newral predict data
        y_newral = sess.run( newral_out
                         ,feed_dict = {
                         x_ph: x, # xに入力データを入れている
                         })

        sign_newral = np.sign(np.array(y_newral).reshape([len(t),1]) - 0.5)
        sign_orig = np.sign(np.array(t.reshape([len(t),1])) - 0.5)
        NGCNT = np.sum(np.abs(sign_newral-sign_orig))/2

y_newralには、xから推定した分類情報が[0,1]の範囲で入っています。この数値は、0.5より大きいか小さいかで、どちらの分類に入るか、という意味なので、それを判別できる形に変換する必要があります。そこで、0.5という数値を引いて、[-0.5,0.5]の範囲に平行移動してから、符号だけ取り出して、+1か-1のどちらかが選択されるようにしました。同様の処理を、t(正解)に対しても実施して、+1/-1の正解値を生成。
この二つは同じ値のときに正解、違う値のときには不正解なのですが、パターンを書き出すと、以下のような関係にあります。

推定値 正解値 推定の正しさ 推定値-正解値
1 1 OK 0
1 -1 NG 2
-1 1 NG -2
-1 -1 OK 0

そこで、sum(abs(推定値-正解値))/2を計算することによって、NGの数が数えられます。これを利用することで、正解率???HIT率が計算できました。

めでたく動いたわけですが、ニューラルネットの設定をもっとシンプルに、中間層なしでやると、収束に時間がかかったり、やりすぎて途中でゼロ割???っぽいことが起きるようでした。
例えば以下のような設定で行くと・・・

newral_out = tf.layers.dense(x_ph, 1, activation=tf.nn.sigmoid)

結果は???

[0] loss 761.80 hit_per:0.50
[100] loss 732.66 hit_per:0.50
[200] loss 706.48 hit_per:0.50
[300] loss 682.59 hit_per:0.50
[400] loss 660.61 hit_per:0.50
[500] loss 640.24 hit_per:0.54
[600] loss 621.26 hit_per:0.62
[700] loss 603.52 hit_per:0.70
[800] loss 586.88 hit_per:0.76
[900] loss 571.22 hit_per:0.80
[1000] loss 556.44 hit_per:0.84
[[0.52383685]]

となって、なんだかいまひとつようです。何がどう利いているのか???私もまだまだ理解不足ですが、ある程度中間層があることで、何かが起きて、上手くいっているようです。
どこまで増やせばどんな状態になるのか?その辺りの理論も追々勉強していきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jetson-nano のセットアップ

nv-jetson-nano-sd-card-image-r32.3.1.zip を使った場合の話。

TensorFlow

https://docs.nvidia.com/deeplearning/frameworks/install-tf-jetson-platform/index.html
に従って

sudo apt-get update
sudo apt-get -y install libhdf5-serial-dev hdf5-tools libhdf5-dev zlib1g-dev zip libjpeg8-dev liblapack-dev libblas-dev gfortran python3-pip libatlas-base-dev
sudo pip3 install -U pip testresources setuptools cython
sudo pip3 install -U numpy==1.16.1 future==0.17.1 mock==3.0.5 h5py==2.9.0 keras_preprocessing==1.0.5 keras_applications==1.0.8 gast==0.2.2 futures protobuf pybind11
sudo pip3 install --pre --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v43 tensorflow

でTensorFlowは入った

keras

sudo pip3 install keras

https://github.com/keras-team/keras/blob/master/examples/mnist_mlp.py

OpenCV

import cv2
cv2.__version__

4.1.1が入ってた

cudaのサンプル

cp -r /usr/local/cuda-**/sample ~/
cd ~/sample
make -j4

参考

https://qiita.com/karaage0703/items/b14c249aa33112669ee4

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む