2018年8月31日金曜日

ディープラーニングを体感しよう:第8章(体験してみて)


こんにちは。よっしーです。

これまでの記事:
ディープラーニングを体感しよう:第1章(まずは環境構築)
ディープラーニングを体感しよう:第2章(Python環境を構築する)
ディープラーニングを体感しよう:第3章(プログラムを動かしてみよう)
前回はプログラムコードの内容を最後まで見ました。

今回は、一通りディープラーニングというものを体験してみて
感じたことをまとめていきたいと思います。


〇 データ集めが大変 〇

今回は公開されているサンプルデータを使用したため、問題にはならなかったですが、
自分がやりたいことをやろうとすると、それに対する学習用データとテスト用データを
自身で用意することとなります。

機械学習にはある程度のサンプル数が必要になります。今回の使用したプログラムで言うと6000サンプル使いました。
6000個のデータとそれに対する答えのセットを用意するだけでも、なかなかの苦労です。

また、学習に適したサンプルデータ(似たようなデータではなく、ある程度の差があるけど答えは同じなど)でなければ、
学習しても上手く判断してくれずに、正解率がまったくあがらない。ということにもなりかねません。

量も質も大切ですので、なかなか大変な作業です。


〇 設定(ハイパーパラメータ)を自分で組むのは難しい 〇

正直なところ、一から自分で組んだとして、今の知識だけでは、
ハイパーパラメータを自在にチューニング出来るとは考えられないです。

解説でもアルゴリズムについてはかなり省略して書きましたが、
それぞれどういった特性があって、こういう場面で使うべき。
というのをしっかりと理解しておく必要があります。

少しでも設定を間違うと、学習を進めてもいまいちの結果となったり、


まったく意味のわからない結果が出たりと、


期待する線形にするには、どのような設定を行うのがよいのか。
なかなか一筋縄ではいかないと思います。


〇 自在に組むことが出来たらめっちゃ面白そう 〇

今回は、手書き画像の認識を例でやってみましたが、
いろいろな形で応用出来そうです。

顔写真をデータとして与えて「顔認証」とか、
株価の動きをデータとして与えて「株価予測」とか、

以下の動画はロボットアームが部品を上手く掴むようにディープラーニングで
学習させるものですが、こういうものが組めるととても面白そうです。




実現出来るライブラリは、すでにいろいろと揃っていますので、
みなさんも興味があれば、ぜひチャレンジしてみてはと思います。

今回で「ディープラーニングを体感しよう」の連載は終了となります。
長い間、ありがとうございました。ではまた~。

2018年8月24日金曜日

ディープラーニングを体感しよう:第7章(プログラムコードを見ていこう3)


こんにちは。よっしーです。

これまでの記事:
ディープラーニングを体感しよう:第1章(まずは環境構築)
ディープラーニングを体感しよう:第2章(Python環境を構築する)
ディープラーニングを体感しよう:第3章(プログラムを動かしてみよう)
前回は前々回に引き続き、プログラムコードの内容を見ていきました。

ニューラルネットワークを作成し、3層を構成、ノード間で情報を伝達し、
答えを導き出すための準備をしました。

残りももう少しなので、引き続き内容を見ていきます。


sgd = optimizers.SGD(lr=0.1)
model.compile(optimizer=sgd, loss="categorical_crossentropy", metrics=["accuracy"])

history = model.fit(X_train, y_train, batch_size=500, epochs=5, verbose=1, validation_data=(X_test, y_test))


1行目の処理で、学習に必要な最適化パラメータを作成しています。
SGDというのはアルゴリズムの種類で「確率的勾配降下」というものです。

他にもいろいろとアルゴリズムの種類があるようで、
この種類を変えることで、学習速度や学習精度が変わってきます。

これも、前回少し解説した、活性化関数のようなもので、
アルゴリズムを追っていくと、難解な数式が出てきます。
なので、今回も内容については深追いはしません。

2行目の処理で、これまで設定してきた内容の学習処理を構築しています。
これでニューラルネットワークの作成が完了です。

そして4行目の処理で、作成したニューラルネットワークへ、
学習用データ、テスト用データを渡し、学習とテストを行っています。

batch_sizeというパラメータで、一度に渡すデータの数を指定しています。
この単位で、正解、不正解の「重み」をつけています。

また、epochs(エポック)というパラメータで、反復学習させる回数を指定しています。
ここでは6000データを5セット学習することとなります。

plt.plot(history.history["acc"], label="acc", ls="-", marker="o")
plt.plot(history.history["val_acc"], label="val_acc", ls="-", marker="x")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()

そして、これらの処理でテストした結果をグラフ化し、画面へ表示しています。


横軸がエポックになっており、右へ進むほど反復学習を繰り返していることを表しています。
縦軸は正解率になっており、反復学習を繰り返すことで、正解率が上がっていく。
ということがグラフから読み取れます。

折れ線グラフが2本ありますが、
「val_acc」 が学習用データに対する正解率。
「acc」 がテスト用データに対する正解率になります。

テスト用データは、学習用データに含まれていないものなので、
正解率はテスト用データよりも落ちていますが、
学習を繰り返すことで、正解率が上昇していることが分かると思います。

ちなみに、このプログラムの実行結果ですが、実行する度、違う結果が表示されます。
(グラフは同じようなものになりますが、若干数値に差が出ます)

ニューラルネットワークを作成する際に設定したパラメータ(このことをハイパーパラメータという)によって、
ランダム性も取り入れられ、機械的ではなく、本当に人間思考のような形で、答えを得ることが出来ています。

なかなか面白いですね。

今日はこのあたりで。ではまた~。

2018年8月17日金曜日

サイボウズLiveのデータをサイボウズ Officeに取り込んでみた!

社内の連絡ツールとして長らく「サイボウズLive」を使用してきましたが、残念ながら来年4月にサービスが終了してしまいます。
いろいろ検討した結果、「サイボウズ Office」を利用することになりました。

乗り換えセミナーで、サイボウズLiveのデータを完全には移行できないことが分かりましたし、また、よくよく考えると過去のデータの必要性も高くありません。ただ、そんな中でも、メンバー名簿とマイカレンダーだけは再利用したいので、移行にチャレンジしてみました。


メンバー名簿


グループのメンバーデータを「cybozu.com用CSV」としてエクスポートします。
このファイルをそのままcybozu.comでインポートすると、エラーになります。
というのも、必須項目である「新ログイン名」と「パスワード」が、インポートしたデータでは空だからです。
一件ずつ手で編集するのは面倒なので、変換プログラムを作成しました。

import sys
import csv
import random
import string

contents = []

r_filename = sys.argv[1]
with open(r_filename, 'r') as f:
    r = csv.reader(f, delimiter=',')
    for i, row in enumerate(r):
       if i > 0:
           # 新ログイン名
           row[2] = row[0]
           # パスワード
           row[3] = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
       contents.append(row)

w_filename = sys.argv[2]
with open(w_filename, 'w', newline='') as f:
    w = csv.writer(f, delimiter=',', quoting=csv.QUOTE_ALL)
    w.writerows(contents)


これでエラーなくユーザー情報を取り込むことができました。


マイカレンダー


マイカレンダーの「csvで出力する」からデータをエクスポートします。
出力したCSVファイルを読み込み、スケジュールの項目との関連付けを行います。
この時、サイボウズLiveの「タイトル」は「予定」ではなく「予定詳細」に関連付けた方がいいでしょう。


というのも、「予定」は「会議」「外出」といったリスト項目であり、「予定詳細」の方に訪問先など具体的な内容を表示させたいからです。(「予定」に関連付けてもエラーになるわけではなく、タイトルの内容がリスト項目に追加されます。)


















サイボウズ Officeのスケジュールをしばらく使用してみて、サイボウズLiveに比べて不満な点が二つあります。

一つは、非公開予定の表示方法です。
サイボウズLiveは公開予定の方にアイコンが付いてスマートに表示されていたのですが、サイボウズ Officeでは非公開予定が「XXXXX(非公開)」と表示されます。私はプライベートの予定も登録しているので、非常に見づらくなってしまいます。

もう一つは、公開予定の公開範囲です。
サイボウズLiveではメモまでは公開されません。例えば、出張予定では搭乗便の時刻、座席番号だけでなく予約番号を、訪問予定では打ち合わせした内容などを、メモに登録していました。そうした情報までは他人に公開したくないので、その点は予定詳細までしか公開しないサイボウズLiveの方が良かったなあと思います。

またいつか、どこかで。

2018年8月9日木曜日

ディープラーニングを体感しよう:第6章(プログラムコードを見ていこう2)



こんにちは。よっしーです。

これまでの記事:
ディープラーニングを体感しよう:第1章(まずは環境構築)
ディープラーニングを体感しよう:第2章(Python環境を構築する)
ディープラーニングを体感しよう:第3章(プログラムを動かしてみよう)
前回は、プログラムコードの内容を見ていきました。

・ライブラリのインポート処理
・手書き数字のデータセット取得
・学習用データ、テスト用データの整形

について解説しましたので、

今回も、前回に引き続き、プログラムコードを見ていきたいと思います。


model = Sequential()
model.add(Dense(256, input_dim=784))
model.add(Activation("sigmoid"))
model.add(Dense(128))
model.add(Activation("sigmoid"))
model.add(Dropout(rate=0.5))
model.add(Dense(10))
model.add(Activation("softmax"))


ここの処理で、ニューラルネットワークを作成しています。
正直、このコードだけ見ても、なかなかイメージが沸きません。

1行目の Sequential() は、
Sequentialモデルというニューラルネットワークの層を積み重ねたモデルを使用することを表しています。

その後の add() で、ニューラルネットワーク層を構築しています。
ここでは3層の作られており、

784(入力層) → 256(隠れ層) → 128(隠れ層) → 10(出力層)

という形でが形成されます。(※入力層はカウントされないため3層となります。)
で、この数値はノードを表しています。

文字だけで書くと「チンプンカンプン」なので絵にしてみましょう。


イメージとしてはこのような構成となります。
実際に入力と出力を紐付けると、以下のような形となります。



層を進むにつれて、ノード間で情報を渡し、出力内容を導き出すといった形となります。
ここでは、「シグモイド」と「ソフトマックス」いう活性化関数を利用して、パターン検出しています。

これらの活性化関数については、数学の難しい公式を利用して結果を得ています。
正直、数学好きでないと内容についていけないレベルです。

なので、私は深追いせず、そういった名前のロジックを使っているんだな。
という程度で理解しています。


今日はこのあたりで。ではまた~。

2018年8月2日木曜日

ディープラーニングを体感しよう:第5章(プログラムコードを見ていこう1)



こんにちは。よっしーです。

これまでの記事:
ディープラーニングを体感しよう:第1章(まずは環境構築)
ディープラーニングを体感しよう:第2章(Python環境を構築する)
ディープラーニングを体感しよう:第3章(プログラムを動かしてみよう)

前回は、ディープラーニングについて説明しました。

今回は、実際にプログラムコードの内容について見ていきたいと思います。

以下が実行したプログラムになります。

import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import mnist
from keras.layers import Activation, Dense, Dropout
from keras.models import Sequential, load_model
from keras import optimizers
from keras.utils.np_utils import to_categorical

(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train = X_train.reshape(X_train.shape[0], 784)[:6000]
X_test = X_test.reshape(X_test.shape[0], 784)[:1000]
y_train = to_categorical(y_train)[:6000]
y_test = to_categorical(y_test)[:1000]

model = Sequential()
model.add(Dense(256, input_dim=784))
model.add(Activation("sigmoid"))
model.add(Dense(128))
model.add(Activation("sigmoid"))
model.add(Dropout(rate=0.5))
model.add(Dense(10))
model.add(Activation("softmax"))

sgd = optimizers.SGD(lr=0.1)
model.compile(optimizer=sgd, loss="categorical_crossentropy", metrics=["accuracy"])

history = model.fit(X_train, y_train, batch_size=500, epochs=5, verbose=1, validation_data=(X_test, y_test))

plt.plot(history.history["acc"], label="acc", ls="-", marker="o")
plt.plot(history.history["val_acc"], label="val_acc", ls="-", marker="x")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()


これだけ見てもさっぱりわからないので、ちょっと解説していきたいと思います。


このプログラムでは以下3つのライブラリを使っています。

numpy : 数値計算を効率的に行うためのライブラリ。
matplotlib : 各種グラフを作成しデータの可視化が可能とするライブラリ
keras : ニュートラルネットワークを扱うためのライブラリ

これらを使うためのインポート処理が以下です。

import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import mnist
from keras.layers import Activation, Dense, Dropout
from keras.models import Sequential, load_model
from keras import optimizers
from keras.utils.np_utils import to_categorical

で、次の処理で手書き数字データセットを取得しています。

(X_train, y_train), (X_test, y_test) = mnist.load_data()

ネット上から手書き数字データセットのダウンロードを行い、X_train, y_train, X_test, y_test へ展開しています。

この1行だけ見てもまったくわからないので、どんなデータかを解説すると、

X_train:学習用の画像データ
X_test:テスト用の画像データ

画像データは、28x28 pixel の グレースケール生値です。
0 ~ 9 の手書き数字の画像となっています。

イメージしやすいように1データ抜き出してみました。

[[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   3  18  18  18 126 136 175  26 166 255 247 127   0   0   0   0]
 [  0   0   0   0   0   0   0   0  30  36  94 154 170 253 253 253 253 253 225 172 253 242 195  64   0   0   0   0]
 [  0   0   0   0   0   0   0  49 238 253 253 253 253 253 253 253 253 251  93  82  82  56  39   0   0   0   0   0]
 [  0   0   0   0   0   0   0  18 219 253 253 253 253 253 198 182 247 241   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0  80 156 107 253 253 205  11   0  43 154   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0  14   1 154 253  90   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0 139 253 190   2   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0  11 190 253  70   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0  35 241 225 160 108   1   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0  81 240 253 253 119  25   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0  45 186 253 253 150  27   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  16  93 252 253 187   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0 249 253 249  64   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0  46 130 183 253 253 207   2   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0  39 148 229 253 253 253 250 182   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0  24 114 221 253 253 253 253 201  78   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0  23  66 213 253 253 253 253 198  81   2   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0  18 171 219 253 253 253 253 195  80   9   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0  55 172 226 253 253 253 253 244 133  11   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0 136 253 253 253 212 135 132  16   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]]

なんとなく、数字「5」の画像ということがわかりますね。

y_train:学習用の画像データに対する答え
y_test:テスト用の画像データに対する答え

画像データの対となっていて、0 ~ 9 の数値(答え)が入っています。

こちらもイメージしやすいように10件ほどデータを抜き出してみました。

[5 0 4 1 9 2 1 3 1 4]

1つめの画像の答えは「5」。2つめの画像の答えは「0」・・・
という感じのデータになります。

学習用のデータは全部で60000データの配列になっており、
テスト用のデータは全部で10000データの配列になっています。


次の処理は、データを整形しています。

X_train = X_train.reshape(X_train.shape[0], 784)[:6000]
X_test = X_test.reshape(X_test.shape[0], 784)[:1000]

reshape メソッドで28x28の2次元配列を784の1次元配列に変換し、
学習用データは先頭の6000件以降を切り捨て。
テスト用データは先頭の1000件以降を切り捨て。
という処理になっています。


次の処理も、データを整形しています。

y_train = to_categorical(y_train)[:6000]
y_test = to_categorical(y_test)[:1000]

これは、答えのデータをベクトルデータに変換しています。

イメージしやすいように例で書くと、答えのデータが「5」だった場合、
以下のようなベクトルデータに変換しています。

[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]

こちらも学習用データは先頭の6000件以降を切り捨て。
テスト用データは先頭の1000件以降を切り捨て。
という処理になっています。

※データを切り捨てているのは、データ量が多すぎて時間がかかってしまうからだと思います。

ちょっと長くなってきましたので、続きは次回とします。

今日はこのあたりで。ではまた~。