ウォンツテック

技術的な話や会社設立に関わる話などを適当にしていきます

TensorFlowを使ってみる 1

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

この本を読み終わったので機械学習を実験してみようと思います。

ライブラリはGoogleが公開しているTensorFlowを使います

www.tensorflow.org

日本のPFI社が開発したChanierあたりも気になっているのでそのうち触ってみたいです

TensorFlowのインストール

PythonをAnacondaでインストールしているので以下のようにインストール

$ conda create -n tensorflow python=3.5

その次に環境を切り替えます

$ source activate tensorflow

ここで、私の環境ではシェルごと落ちる問題が発生しました。
調べると

pyenvとanacondaを共存させる時のactivate衝突問題の回避策3種類 - Qiita

pyenvのactivateと衝突しているらしいので、

export PATH="$PYENV_ROOT/versions/anaconda3-2.4.0/bin/:$PATH"

をshellの設定ファイルに追記しておきます 「eval "$(pyenv init -)" 」より後に記述

プロンプトが切り替わったら以下を実行
※CPUでしか使わない人は実行するらしい

(tensorflow)/Users/sode% conda install -c conda-forge tensorflow

TensorFlowを使った簡単な計算

Basic Usage  |  TensorFlow

このサイトに載ってる簡単な計算が動くか試しておきました。

Graph

import tensorflow as tf

matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.], [2.]])
product = tf.matmul(matrix1, matrix2)

sess = tf.Session()
result = sess.run(product)

print(result)

sess.close()

TensorFlowを算数で理解する - Qiita

このサイトの説明によると、TensorFlowはNodeとedgeで構成されていて、それをGraphと呼んでいる
Graphの計算はSessionが管理している。
このコード例だとmatrix1とmatrix2がedgeでmatmul(行列積)がNode、これらを組み合わせたproductがGraphって事ですね。

計算はSessionのrunメソッドで実施し、内部的には高度な最適化がされてそう。

Interactive Session

import tensorflow as tf
sess = tf.InteractiveSession()

x = tf.Variable([1.0, 2.0])
a = tf.constant([3.0, 3.0])
x.initializer.run()

sub = tf.sub(x, a)
print(sub.eval())

sess.close()

続いての例はtensorflowのeval使ってインタラクティブに(いちいちSession.runせずに)計算させたい時に使うっぽい。

Variables

import tensorflow as tf

state = tf.Variable(0, name="counter")

one = tf.constant(1)
new_value = tf.add(state, one)
update = tf.assign(state, new_value)

init_op = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init_op)
    print(sess.run(state))

    for _ in range(3):
        sess.run(update)
        print(sess.run(state))

Variableは変数。assignもNodeの1種でSessionのrunで計算するまで評価されない。updateを評価(run)する際にassignとaddが走りstateが更新される。

Fetches

input1 = tf.constant([3.0])
input2 = tf.constant([2.0])
input3 = tf.constant([5.0])
intermed = tf.add(input2, input3)
mul = tf.mul(input1, intermed)

with tf.Session() as sess:
  result = sess.run([mul, intermed])
  print(result)

Sessionのrunは同時に複数のGraphを渡し、同時に計算する事が可能

Feeds

import tensorflow as tf

input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.mul(input1, input2)

with tf.Session() as sess:
  print(sess.run([output], feed_dict={input1:[7.], input2:[2.]}))

GraphのEdgeは型だけ用意しておいて評価時(run)に実体を渡してもいいよという事

rails5 + puma + nginx で AWSテスト環境を構築してみる

puma

railsのAPサーバとWebサーバですが、昨今ではrails5にpumaが標準になったり、herokuがpumaを推奨したりとpumaがおすすめらしいので私のサービスのテスト環境もpumaで構築することとしました。

github.com


ざっくりとした手順は以下のような感じです

  1. railsの設定(ここは割愛します)
  2. puma.rbの編集
  3. puma起動ファイルの編集(/etc/init.d/puma)
  4. nginxのインストール&編集

ちなみに私のAWSubuntuで構築してます

pumaのコンフィグファイル修正

rails5でアプリを作るとアプリケーションがあるディレクトリのconfig/以下にpuma.rbってのが出来ています。
以下の項目を追記します

# アプリケーションがあるディレクトリと各種ファイルを生成するディレクトリを指定する
# tmpディレクトリは存在していないが、手動で作成するか起動時のスクリプトで作成するようにする
#  socketやlogやpidファイルを格納するディレクトリも存在していないので手動かスクリプトで作成
#  存在しないと起動出来ずに落ちます
app_dir = File.expand_path("../..", __FILE__)
tmp_dir = "#{app_dir}/tmp"

# 環境変数を指定する。起動時に変数があればそれを見る。無ければテスト環境である"staging"としている
rails_env = ENV['RAILS_ENV'] || "staging"
environment rails_env

# socketでbindする。nginxからsocket経由で接続するため
bind "unix://#{tmp_dir}/sockets/puma.sock"

# ログ出力ファイルの指定
stdout_redirect "#{tmp_dir}/logs/puma.stdout.log", "#{tmp_dir}/logs/puma.stderr.log", true

# pidとstateファイルの格納
pidfile "#{tmp_dir}/pids/puma.pid"
state_path "#{tmp_dir}/pids/puma.state"

pumaの起動ファイルの作成

pumaの起動ファイルについてはサーバが再起動しても自動で立ち上がるようにinit.dに書きます
upstartなどで書いてもいいいです

各種ディレクトリの生成(無ければ)と、起動ユーザーを気をつけて、起動時の環境変数に気をつけましょう

sudo vi /etc/init.d/puma

#!/bin/bash

NAME=puma
USER=ubuntu
APP_NAME=app
APP_DIR=/home/$USER/$APP_NAME
TMP_DIR=$APP_DIR/tmp
PID_DIR=$TMP_DIR/pids
SOCKET_DIR=$TMP_DIR/sockets
LOG_DIR=$TMP_DIR/logs
PUMA_BIN=/home/$USER/.rbenv/shims/puma

RAILS_ENV=staging

sudo -u $USER -H sh -c "mkdir -p $PID_DIR"
sudo -u $USER -H sh -c "mkdir -p $SOCKET_DIR"
sudo -u $USER -H sh -c "mkdir -p $LOG_DIR"

PIDFILE=$PID_DIR/puma.pid


start() {
  cd $APP_DIR;
  sudo -u $USER -H sh -c "echo \$\$ > $PIDFILE; RAILS_ENV=$RAILS_ENV $PUMA_BIN -C $APP_DIR/config/puma.rb -d"
}

stop() {
  echo -n "Stopping puma"
  kill -s SIGTERM `cat $PIDFILE`
}

restart() {
  stop
  start
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    restart
    ;;
  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart}" >&2
    exit 1
    ;;
esac

これで sudo chmod +x /etc/init.d/puma をして sudo /etc/init.d/puma start でpumaを立ち上げてみましょう。

ps axu|grep pumaで

ubuntu   27220  0.0  1.6 343440 16468 ?        Sl   04:26   0:00 puma 3.7.0 (unix:///home/ubuntu/app/tmp/sockets/puma.sock) [app]
ubuntu   27227  0.1 10.3 830828 105096 ?       Sl   04:26   0:02 puma: cluster worker 0: 27220 [app]
ubuntu   27230  0.1 16.0 892820 162328 ?       Sl   04:26   0:02 puma: cluster worker 1: 27220 [app]

こんな感じで立ち上がっていなかったら失敗です。
tmp, sockets, pids, logsディレクトリが存在しているかと所有者やパーミションが起動ユーザーで問題ないか確認しましょう。

ちなみにですが、bundle.jsの生成など事前に各種ファイルのprecompileはしておきましょう。

nginxのインストールと設定

nginxのインストールは以下のサイトを参考にしました

How To Deploy a Rails App with Puma and Nginx on Ubuntu 14.04 | DigitalOcean

$ sudo apt-get install nginx

続いて設定ファイルの編集

$ sudo vi /etc/nginx/sites-available/default

/etc/nginx/sites-available以下にアプリ用のファイルを新規作成してsites-enabled以下にシンボリックリンクを張ってもよいです。

upstreamのところで先ほどpumaで生成したsocketに接続する設定をしています

upstream app {
    # Path to Unicorn SOCK file, as defined previously
    server unix:/home/ubuntu/app/tmp/sockets/puma.sock fail_timeout=0;
}

server {
    listen  80;
    server_name app.jp;
    keepalive_timeout 300;

    client_max_body_size 4G;

    root /home/ubuntu/app/public;

    try_files $uri/index.html $uri @app;

    location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_set_header X-Forwarded_Proto $scheme;
          proxy_redirect off;
          proxy_pass http://app;
          proxy_read_timeout 300s;
          proxy_send_timeout 300s;
    }

    # You can override error pages by redirecting the requests to a file in your
    # application's public folder, if you so desire:
    error_page 500 502 503 504 /500.html;
    location = /500.html {
            root /home/ubuntu/app/public;
    }
}

あとは sudo /etc/init.d/nginx start で起動し、上記のserver_nameで指定したドメイン(もしくはIP)に接続出来れば成功です。

Deep Learning

# Deep Learning 5

逆誤差伝搬法の数学的お勉強

高卒でもわかる機械学習 (5) 誤差逆伝播法 その1 | 頭の中に思い浮かべた時には

前回見たスライドはスライド48のあたりがイマイチ分からなかったので上記で読み直し
さらに分かりやすいです

逆誤差伝搬法は計算量を如何にして減らすかという事で、N層パーセプトロンがある場合は
N層、N-1層、N-2層と逆順に、重みの微小変化(その層の重みによる勾配法で損失関数を減少させる)をみていきます。k-1層の計算時点でk層の計算結果を利用出来るようになっているとうのがキモ


本のp.148 (5.13)の補足
 \frac{\partial L}{\partial {\bf X}} = \frac{\partial L}{\partial {\bf Y}} \cdot {\bf W}^T

この式の1要素目に着目し、図5-24のX → X・W → Yの1要素目の計算の流れを見てみると

 (x_1, x_2) \cdot (w_{11}, w_{12})^T x_1 w_{11} + x_2 w_{12} y_1

となっていてYへの出力に関しては
 \frac{\partial L}{\partial x_1} = \frac{\partial L}{\partial y_1} \frac{\partial y_1}{\partial x_1} + \frac{\partial L}{\partial y_2} \frac{\partial y_2}{\partial x_1} + \frac{\partial L}{\partial y_3} \frac{\partial y_3}{\partial x_1}

となっていて
 y_1 = x_1 w_{11} + x_2 w_{12}
 y_2 = x_1 w_{21} + x_2 w_{22}
 y_3 = x_1 w_{31} + x_2 w_{32}
を代入すると

 \frac{\partial L}{\partial x_1} = \frac{\partial L}{\partial y_1} w_{11} +  \frac{\partial L}{\partial y_2} w_{21} +  \frac{\partial L}{\partial y_3} w_{31}
 =  ( \frac{\partial L}{\partial y_1},  \frac{\partial L}{\partial y_2},  \frac{\partial L}{\partial y_3}) \cdot (w_{11}, w_{21}, w_{31})
 =  \frac{\partial L}{\partial {\bf Y}} \cdot W^T
と書ける。
W^Tは3行2列中の1列目のみ

これを他の要素( x_2)に関しても導くと 5.13 の上の式が導ける。下の式も同様な感じで導ける

商標登録の出願

個人で作っているWebサービスのサービス名(ロゴではなく文字のみ)の商標登録出願をやってみた

結論から言うと出願自体はすごく簡単。

やりかたをざっくり書くと


1. 特許庁の商標登録出願のpdfを熟読

http://www.jpo.go.jp/shiryou/kijun/kijun2/pdf/syutugan_tetuzuki/05_01.pdf#page=5
これのp.548 ~ p.557あたりまでを熟読する


2. 出願用のwordファイルを探す

上記pdfのp.552のフォーマットのwordファイルを探す(このフォーマットを一から作ってもよい)

3. 出願用のwordを書く

個人で出願する場合は以下を記載すればOK

  • 書類名
  • 整理番号
  • 提出日
  • あて先
  • 商標登録を受けようとする商標
  • 標準文字

(上記「商標登録を受けようとする商標」の枠の下側に【標準文字】とだけ記載)

  • 指定商品又は指定役務並びに商品及び役務の区分
  • 区分(【第42類】等)
  • 指定商品(指定役務)
  • 商標登録出願人
  • 住所又は居所
  • 指名又は名称

(名前の横に自分の名前の判子を押印。印鑑登録してなくても大丈夫)

  • 電話番号

全て全角(数字も)で記載し、フォントサイズは10〜12、左右の空白は2〜2.3cmとする(一番左側や右側に位置している文字からの余白)

指定商品(指定役務)の部分は以下のサイトなどから区分に該当する箇所を抜き出してくる(全部書いてもよい)
商標登録: 指定役務リスト


4. でかめの郵便局又は特許庁で特許印紙を買う

印紙代は以下のサイトを参考に。(ちなみに2区分で出願する場合は20600円)
産業財産権関係料金一覧(2016年4月1日時点) | 経済産業省 特許庁

5. 特許庁で最終確認してもらう

出願時に足りない箇所等あれば教えてもらえるので聞く

6. 出願

問題なければ印紙を貼り付けて出願。
紙で提出した場合は電子化代が必要で郵送で送られてくるそう。それを郵便局で支払う。
※電子化代はまだ払っていないが出願時にもらう紙によると1200円+(700円x枚数)との事なのでおそらく1900円。


以上終わり
おそらく弁理士に頼むメリットとしては出願しても申請が通らないケースがあるのでそれの判定や
適切な出願範囲(間違えると範囲外の権利を主張出来ない)を考えてもらえる事がある。
自分みたいにとりあえず適当な範囲でいいので出願したい場合は要らなかった。

Deep Learning

# Deep Learning 4

誤差逆伝搬法の勉強

前の章で実装した損失関数の勾配の微分計算はとてつもない時間が掛かるのでそれを早くしましょうっていう話。

計算グラフで説明するとの事だったので概要を理解したく以下のスライドを読んでみた

www.slideshare.net

かなり分かりやすい

Deep Learning

Deep Learning 勉強 3

勾配法

前回勉強した損失関数は訓練データが如何にテストデータ(正解)に近づいたかを示す関数で、2乗和誤差や交差エントロピー誤差などは0に近いほどテストデータに近いと定義されている。

最終的な目標は認識精度を上げる事なので、3.6.2 ニューラルネットワークの推論処理でやった最終的な正解の割合(accuracy)を指標としても良さそうですが、これだとパラメータ(重みとバイアス)の微小な変化に対してほとんどが変化しない事が問題となるそうです。

言い換えるとパラメータを入力、推論結果(accuracy)を出力とする関数を考えるとほとんどの入力で微分が0となり、0に近いパラメータをさがす事が事実上出来なくなる。

これらを解消するため損失関数という入力に対して連続な(微分可能な)関数を選んでいます。

勾配法はこの損失関数を入力で微分偏微分)し、最小となる入力パラメータを探す方法の一つで
4.4.1では最急降下法というアルゴリズムが用いられていて

 x_(n+1) = x_n - \eta \frac{\partial f}{\partial x_n}

となってます。
この方法は極小値を探すのには向いてますが、最小値を探す場合は様々な初期値で試す必要があるとの事。

Deep Learning

Deep Learning 勉強 2

損失関数

訓練データがテストデータのに如何に近づいたかを図るための関数
損失関数の結果が0に近いほど正解に近い。
損失関数には以下の二つがあるらしい

2乗和誤差: \frac{1}{2} \sum_k (y_k - t_k) ^2
交差エントロピー誤差: - \sum_k t_k log y_k

4.2 損失関数の交差エントロピー誤差

cross_entropy_errorで微小な値を追加しているので少し考察

 log(y + delta) = log(y ( 1 + delta/y))]
  = log y + log ( 1 + delta/y )

ここでdeltaは微小な値なので 1+ delta/yは限りなく1に近い
これより  log (1 + delta/y)は限りなく0に近いことになるため

 log (y + delta) \fallingdotseq log y

といえる。

4.2.4 バッチ対応版交差エントロピー誤差の実装

tがラベル表現だったらの箇所の意味がいまいちわからなかったけど
バッチサイズが5だとすると、tがone_hot表現の時は

t1 = [[0, 0, 0, 1],
      [1, 0, 0, 0],
      [0, 1, 0, 0],
      [1, 0, 0, 0],
      [0, 0, 1, 0]]

という表現で行が各々のテストデータの結果で、列が出力の数。
tがラベル表現の時は

t2 = [3, 0, 1, 0, 2]

というように各々のテストデータの結果の正解インデックスの値ということ