Google DeepMind社のディープラーニングを活用したコンピュータ囲碁プログラム「AlphaGo」が韓国の李セドル氏(九段)との五番勝負を4勝1敗で勝ち越したことが大きなニュースとなりました。
これを境に一般のニュースや雑誌などで「ディープラーニング」といった言葉を耳にすることが増えています。Googleではディープラーニングの研究を精力的に行っており、Web検索や機械翻訳の精度向上などに利用されています。
参照:子どものプログラミング教育Scratchについて解説した記事はこちら
キュウリの仕分けにもディープラーニングが活用
国内でも三菱UFJ信託銀行からディープラーニングを活用して株式トレードを行う投資ファンドが売り出されたり、中古車の事業者取引支援を行うオークネットではディープラーニングによってクルマの写真を部位別に自動分類してサイト登録を行うなどと、様々な観点からディープラーニングの活用と実用化が進んでいます。
大手企業ばかりではありません。ディープラーニングによってキュウリの等級を自動で仕分ける機械が静岡県で農家を営む個人によって開発されています。
これにより、用途によっては人の目を超える性能の画像認識を実現でき、例えばネコの品種、クルマの車種、航空機の機種の推定も可能である。ならばキュウリの仕分けはどうだ、と小池さんは考えた。
参照:Google Cloud Platform Japan 公式ブログ:「キュウリ農家とディープラーニングをつなぐ TensorFlow」
大手企業や研究者にかぎらず、個人であってもアイディアを実現できる環境が整ってきています。在宅ワークのなかにも画像の仕分けや変換などを手作業で行うタスクがありますが、それらの大部分を自動化できる未来が近づいているのかもしれません。
そこで今回は、機械学習の手法であるディープラーニングの概要とキュウリの自動仕分け機にも使われているTensorFlowのチュートリアルを用いて、機械学習の雰囲気を掴んでいただければと思います。
機械学習とディープラーニング
ディープラーニングと人工知能(AI)は深い関係がありますが、厳密には異なる概念です。人工知能といえば、自意識をもったロボットやスーパーコンピューターを想像するかもしれませんが、そのような機械は未だに実現できていません。カリフォルニア大学教授のジョン・サール氏は、人工知能について以下の分類をしています。
- 強い人工知能:知能や精神を宿す機械
- 弱い人工知能:人間がその全認知能力を必要としない程度の問題解決や推論を代行
ディープラーニングは「弱い人工知能」において「Aという情報をXと判断するための基準」を機械自身の反復学習によって習得する「機械学習」という分野で用いられる手法のひとつです。ディープラーニングを用いることで、膨大な量の画像やテキストなどのデータを分析して意味を分類することが可能となります。
「AlphaGo」には、様々な機械学習の手法が組み合わされていますが、膨大な組み合わせが起こりうる囲碁の棋譜のもつ意味を認識させるフェイズにおいて、ディープラーニングが活用されています。
判断基準を学習する際に、ひとつの判断基準だけで複雑な状況を判断するのは難しいため、判断基準として利用する要素をいくつも作成してその結果をまとめて判断するようにします。こうして出力された個別の判断結果から、さらに判断を行う層を何階層にも深く(ディープに)重ねて実行することで、最終的に複雑な判断が行えるようにする仕組みがディープラーニングです。
これまでの機械学習では「何を重要視して学習させればよいのか」という観点について、人力での調整や知見が必要となっていましたが、単純な判断を深く組み合わせることで細かな特徴を機械的に見つけて学習できるようになったのがディープラーニングの特長となります。
Googleの提供するTensorFlow Playgroundを動かしてみると、複数の判断基準が複数の層になった結果として複雑な判断ロジックが学習されていることがわかります。
TensorFlowで体験する機械学習
以上までで、ディープラーニングと機械学習の概要を説明しました。Googleの提供する機械学習ライブラリであるTensorFlowを実際に触ってみましょう。
※本稿ではMac OSXのターミナル上でのPythonによる作業を前提としています。その他のプラットフォームでのインストール方法については、「Download and Setup | TensorFlow」を参照してください。 |
MacOSXには標準でPythonが含まれているため、すぐにプログラミングを行うことができます。まずはPython向けの仮想環境を作成するvirtualenvをインストールします。virtualenvを利用することで、OS全体にインストールされたPython環境とは独立してライブラリの管理が行なえます。
$ cd {作業ディレクトリ} $ sudo easy_install pip $ sudo pip install –upgrade virtualenv |
virtualenvからTensorflow用環境を作成してTensorflowをインストールします。 TF_BINARY_URL に設定できる最新モジュールについては、Tensoflowのサイトから確認することが可能です。
$ virtualenv –system-site-packages ./tensorflow $ cd tensorflow $ source bin/activate(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.whl (tensorflow)$ pip install –upgrade $TF_BINARY_URL |
これだけでインストール完了です。仮想環境内にテストプログラムを作成しましょう。
(tensorflow) $ mkdir scripts (tensorflow) $ cd scripts/ (tensorflow) $ touch test.py |
作成した test.py に「Introduction | TensorFlow」のサンプルコードを入力して、pythonで実行します。
(tensorflow) $ python test.py (0, array([-0.2347326], dtype=float32), array([ 0.62995446], dtype=float32)) (20, array([ 0.00153294], dtype=float32), array([ 0.35028648], dtype=float32)) (40, array([ 0.07570834], dtype=float32), array([ 0.31240559], dtype=float32)) (60, array([ 0.09400731], dtype=float32), array([ 0.30306044], dtype=float32)) (80, array([ 0.09852163], dtype=float32), array([ 0.30075499], dtype=float32)) (100, array([ 0.09963533], dtype=float32), array([ 0.30018625], dtype=float32)) (120, array([ 0.09991004], dtype=float32), array([ 0.30004597], dtype=float32)) (140, array([ 0.0999778], dtype=float32), array([ 0.30001137], dtype=float32)) (160, array([ 0.09999453], dtype=float32), array([ 0.30000281], dtype=float32)) (180, array([ 0.09999864], dtype=float32), array([ 0.3000007], dtype=float32)) (200, array([ 0.09999967], dtype=float32), array([ 0.30000019], dtype=float32)) |
なにやら数字がたくさんでてくればTensorflowのインストールに成功しています。
Tensorflowのサンプルコードを解読しよう
このサンプルコードは最初に「y_data = x_data * 0.1 + 0.3」という法則でランダムに生成されたデータから学習して、使われたであろう1次関数を導き出すプログラムです。201回目(※0はじまり)で「y_data = x_data * 0.09999967 + 0.30000019」と正解に近い関数が学習されています。
これだけでは、何をしているのかさっぱり分からないと思いますので、具体的にどのような処理が行われているのかサンプルコードを解読していきましょう。
import tensorflow as tf import numpy as np |
tensorflowとnumpyをインポートしてプログラムから利用することを宣言しています。tensorflowは先程インストールした機械学習ライブラリであり、numpyはPythonで数値計算を行うためのライブラリです。
# Create 100 phony x, y data points in NumPy, y = x * 0.1 + 0.3 x_data = np.random.rand(100).astype(np.float32) y_data = x_data * 0.1 + 0.3 |
numpyを用いて浮動小数型のランダムデータ(0〜1)を100個生成して配列に格納します。配列に格納されたランダム値に対して、「x_data * 0.1 + 0.3」で計算した結果をy_dataの配列に格納しています。
この作業はあくまで、サンプル学習データを作るためのものです。実際に機械学習を行う際には、誰も法則が分からない実データを用いることになります。「x_data * 0.1 + 0.3」の数値をかえて実行すると、学習結果もそれに応じた結果となります。
# Try to find values for W and b that compute y_data = W * x_data + b # (We know that W should be 0.1 and b 0.3, but TensorFlow will # figure that out for us.) W = tf.Variable(tf.random_uniform([1], -1.0, 1.0)) b = tf.Variable(tf.zeros([1])) |
TensorFlowの変数として-1.0〜1.0のランダム数値を入れる変数Wと0がはいった変数bを定義します。「[1]」は「長さ1の一次元配列(=スカラー値)」を表します。変数Wが重み、変数bがバイアスを意味しています。
y = W * x_data + b |
続いて、計算式が記述されていますが、この段階で計算処理がうごくわけではありません。TensorFlowによる処理は、データグラフの定義とデータグラフの実行に分かれており、予めデータグラフ(式)を定義しておくことで、並行実行を可能とします。
# Minimize the mean squared errors. loss = tf.reduce_mean(tf.square(y – y_data)) |
学習方法の定義を行います。lossには以下のデータグラフが定義されています。
- ランダム変数から計算された y と学習データy_data配列の誤差を要素ごとに計算
- 要素ごとの誤差を2乗して、その平均を計算
この計算は平均二乗誤差とよばれ、ランダム値と学習データにどの程度の距離が発生したのかを計算する方法のひとつです。
optimizer = tf.train.GradientDescentOptimizer(0.5) |
optimizerには学習方法が定義されています。GradientDescentOptimizerは「勾配降下法」と呼ばれる、関数の傾きから最小値を探索する学習方法です。
train = optimizer.minimize(loss) |
「学習データとの距離」が最小になるように学習を行うデータグラフを生成します。
# Before starting, initialize the variables. We will ‘run’ this first. init = tf.global_variables_initializer() |
TensorFlow変数の初期化を行うデータグラフです。TensorFlow変数を利用している場合には必須となります。
# Launch the graph. sess = tf.Session() sess.run(init) |
TensorFlowセッションを作成して変数の初期化を行います。
# Fit the line. for step in range(201): sess.run(train) if step % 20 == 0: print(step, sess.run(W), sess.run(b)) # Learns best fit is W: [0.1], b: [0.3] |
定義したデータグラフを引数にして、学習の繰り返し実行を行います。20回実行するごとに変数Wとbを表示します。ランダム初期値から始まったWと0から始まったbが実行ごとに収束して正しい関数になっていく様がわかります。
TensorFlowを用いて手書き数字を認識させよう
以上まででサンプルコードの解説をおこないました。TensorFlowの処理は大きく分けて次のステップがあることが理解いただけたのではないでしょうか。
- 学習データセットの生成・読み込み
- 学習データグラフの定義
- TensorFlowセッションの作成と変数の初期化
- 学習の繰り返し実行
- 結果の表示
それでは実際のデータをもちいて、手書き数字の学習を行います。こちらもGoogleが提供しているサンプルコードをダンロードして処理を実行してみましょう。
(tensorflow) $ python soft_max.py Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes. Extracting /tmp/tensorflow/mnist/input_data/train-images-idx3-ubyte.gz Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes. Extracting /tmp/tensorflow/mnist/input_data/train-labels-idx1-ubyte.gz Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes. Extracting /tmp/tensorflow/mnist/input_data/t10k-images-idx3-ubyte.gz Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes. Extracting /tmp/tensorflow/mnist/input_data/t10k-labels-idx1-ubyte.gz 0.9134 |
ファイルがダウンロードされてきて、最後に数値が表示されました。この数値は作成されたモデルで、答え合わせをした際の正解率を表しています。簡単な処理で手書き数字が90%以上は認識できるようになるのは驚異的ではないでしょうか。
サンプルコードを解読しながら、手書き文字認識学習で行われているを理解しましょう。
mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True) |
まずは学習データセットをダウンロードして読み込んでいます。TensorFlowにはチュートリアル用の学習データセットをダウンロードして利用するライブラリが用意されています。
今回利用されているMNISTとは、28×28ドットの手書き数字の白黒画像70,000個と、画像ごとに「0〜9」のラベルが付与されたデータセットです。全てのサンプルを学習データとして利用すると新しい手描き文字画像の精度がわからなくなってしまうため、学習データと答え合わせデータに分ける手法が使われています。
28×28ドットの白黒画像は、要素ごとに0.0〜1.0の濃淡が格納された28×28=784列の数列で表せるため、この数列をサンプル毎に生成することで、大量のサンプル画像ファイルを画像ファイル数x784列の行列として表現できます。
# Create the model x = tf.placeholder(tf.float32, [None, 784]) |
次に学習データグラフの定義です。「tf.placeholder」は学習セット用の入れ物を定義する関数です。前述の通り、ひとつひとつの画像は784列の浮動小数で表現できるため、それらを格納して計算を実行するための入れ物を準備しておきます。
W = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10])) |
変数Wを784×10の行列、変数bを10列の数列で作成します。ここで10列の定義が行われているのは、判定結果が「0〜9」の10種類存在するためです。それぞれの列には判断を行うためのスコアが格納されており、一番大きいスコアの列番号が答えとして選択されます。
# Define loss and optimizer y_ = tf.placeholder(tf.float32, [None, 10]) |
「0〜9」のラベルを表現するプレースメントホルダーを作成します。学習データは意味ラベルに応じて特定の列のみに1が格納されています。ある画像のラベルが「5」の場合には「[0,0,0,0,0,1,0,0,0,0]」となります。
y = tf.matmul(x, W) + b |
tf.matmulは配列同士の掛け算の定義です。画像認識においても、「y = x * W + b」における最適な変数Wとbを探す作業であることは変わりません。
cross_entropy = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)) train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy) |
続いて、学習方法の定義を行います。今回は、Softmax回帰と呼ばれる手法が使われています。Softmax回帰では与えられた画像のピクセルごとに、「0〜9」のラベルをもつ可能性を配列形式で重み付けしていきます。画像の真ん中に濃いピクセルがあったら「8」である可能性が上昇し、「0」である可能性が下がるといった確率的な学習を行っていきます。
sess = tf.InteractiveSession() tf.global_variables_initializer().run() |
TensorFlowセッションを作成して、変数を初期化します。
# Train for _ in range(1000): batch_xs, batch_ys = mnist.train.next_batch(100) sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) |
MNSTの学習データから100個の画像とラベルを取り出して学習を実行します。プレースメントホルダーには、feed_dictに辞書型で値を格納します。
# Test trained model correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) |
作成された学習結果の精度を検証するためのデータグラフを定義します。判定結果にはラベル毎の確率が格納されているためtf.argmaxで行列yの中から一番大きい値を持つ列番号を返却させます。
前述の通り、学習データおよび学習結果は列番号がそのままラベルの数値となっています。tf.equalを用いて判定結果が正しい場合にはtrueを返却します。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) |
判定結果の正解率を算出するため、ブーリアン型を浮動小数に変換して平均値を取得するデータグラフを定義します。
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})) |
精度検証処理を実行させます。MNSTの正解データから画像とラベルを取り出して、判定結果と正解ラベルの正解率を表示させています。
以上まででコードの解説をおこないましたが、これだけではどのような画像を判定されているのか、イメージしにくいと思いますのでデータセットから画像ファイルを出力させてみましょう。Pythonで画像ファイルを取り扱うためにpillowをインストールします。
(tensorflow) $ pip install pillow |
以下のコードでMNSTから先頭10個の手描き数字画像を取得してファイル出力します。
for i in range(10): a = mnist.test.images[i] b = 255 – a.reshape((28,28)) * 255 from PIL import Image Image.fromarray(b).convert(“”L””).save(“”./image”” + str(i) + “”.png””) |
以下のような画像ファイルが出力されました。
つづいて画像ごとの判定結果を表示させましょう。正解率判定の下側に以下のコードを追加します。
for i in range(10): expected = mnist.test.labels[i].argmax(0) answer = sess.run(tf.argmax(y, 1), feed_dict={x: [mnist.test.images[i]]}) print(expected, answer[0], expected == answer[0]) |
処理を実行します。
(tensorflow) $ python soft_max.py Extracting /tmp/tensorflow/mnist/input_data/train-images-idx3-ubyte.gz Extracting /tmp/tensorflow/mnist/input_data/train-labels-idx1-ubyte.gz Extracting /tmp/tensorflow/mnist/input_data/t10k-images-idx3-ubyte.gz Extracting /tmp/tensorflow/mnist/input_data/t10k-labels-idx1-ubyte.gz 7 7 True 2 2 True 1 1 True 0 0 True 4 4 True 1 1 True 4 4 True 9 9 True 5 6 False 9 9 True |
間違えたのは以下の画像でしたが、これは人間の目からみても読み取りづらいですね。
以上まででTensorFlowのチュートリアルについてご説明しました。この時点では1段階の判別関数であるため、「ディープラーニング」とまでは言えないのですが、このような関数をいくつも生成することで、複雑な判定も可能になっていきます。
まとめ
いかがでしたか、今回はディープラーニングの概要とTensorFlowについて紹介しました。ひとつひとつの画像判別条件をプログラムとして記述するのには膨大かつ複雑な条件の洗い出しが必要となりますが、機械学習を用いることで簡単なコードからでもそれなりに精度の高い関数が自動的に生成されることを実感していただけたのではないでしょうか。
近い将来、ディープラーニングによって様々な作業が削減されていくのだとすれば、働く側にとっても影響があると思われます。
すべての仕事が人工知能に置き換わる未来は考えにくいですが、それぞれのアイディアを持ち寄って機械学習に仕事をアシストするようにしていくことが、抜本的な作業効率化に繋がっていくのだと思われます。そんな未来を感じていただければ幸いです。
参照:子どものプログラミング教育Scratchについて解説した記事はこちら
イラスト:ゆずりは さとし
この記事の著者 by 池田仮名 ITエンジニア/ブロガー 個人ブログ「太陽がまぶしかったから」を運営。 Twitter|@bulldra ブログ|太陽がまぶしかったから |
フリーランスになるために必要な知識やスキルアップの方法等、様々なお役立ち情報を発信していきます。
(リモートワーク案件に強いフリーランスエージェント「クラウドワークス テック」を運営)