ラムダ技術部 / Yoidea

不真面目な技術について

シェルにログインボーナス機能を追加してみた

はじめに

プログラミングの勉強のために毎日シェルにログインしたいモチベーションが続かない

そんな悩みをお持ちではないだろうか?

毎日ログインするぞと決断しては3日で続かなくなる。というのを僕は繰り返していた。

そこで、如何にしてログインをシェルにログインするモチベーションを向上させるかを考えたところ、ソーシャルゲームのようなログインボーナスがあれば毎日ログインする気になるのではないかという結論に至った。

そこで、シェルにログインボーナスを追加するだけの簡易なプログラムをPythonで作ってみた。

github.com

デモ

機能は至ってシンプルで、シェルにログインすると、通算・連続・当日のログイン回数を表示する。日本人は数字が好きなのでこれだけでもモチベーションが向上するだろう。 f:id:yoidea:20170716234754p:plain

また、特定回数ログインするとお祝いのメッセージが表示される。正直なところボーナスといっても何を与えたら良いのかわからず、祝辞を表示するぐらいしか思い浮かばなかった。とは言え、長期間ログインすると豪華なアスキーアートが表示される。 f:id:yoidea:20170716234805p:plain f:id:yoidea:20170716234817p:plain

インストー

動作環境

Python3またはPython2のインストールされたMacLinuxで動作する。.bash_profileが利用できる環境であればWindowsでも動作するだろう。

Pythonのバージョンを確認するには、

$ python -V

として、「Python 3.x.x」と表示されればPython3、「Python 2.x.x」と表示されればPython2であることがわかる。「-bash: python: command not found」と表示された場合はPython自体がインストールされていない。

ダウンロード

まずはGitでリポジトリからダウンロードする。

$ git clone https://github.com/yoidea/login_bonus_for_shell.git
$ cd login_bonus_for_shell

自動インストー

install.shを実行する。

$ sh install.sh

「インストール完了」と表示されれば無事インストール完了。

手動インストー

任意の名前のディレクトリ(例: ~/LBFS)を作成して、そのなかにファイルをコピーする。

$ mkdir ~/LBFS
$ cp ./* ~/LBFS
Python3の場合

.bash_profileに以下を追加してインストール完了

cd ~/LBFS
python logger.py
cd ~/
Python2の場合

.bash_profileに以下を追加してインストール完了

cd ~/LBFS
python logger_for_python2.py
cd ~/

カスタマイズ

祝辞や定型文はjson形式で保存されており、それを変更することでオリジナルのメッセージに変更することができる。 祝辞はバリエーションが貧弱なのでオリジナルメッセージを追加することを推奨する。

祝辞

eventlist.json内にお祝いの条件とメッセージが一覧で保存されている。

{
    "events": [
        {
            "condition": "continuous",
            "value": 3,
            "message": "🎉おめでとうございます🎉\n連続3日目のログインです!"
        },

定型文

message.json内に定型文が保存されている。

{
    "head": "*---*---*---* ログインボーナス *---*---*---*\n継続は力なり!毎日ログインしましょう",
    "total": {
        "info": " +   通算 <",
        "unit": "> 日目"
    },
    "continuous": {
        "info": " +   連続 <",
        "unit": "> 日目"
    },
    "today": {
        "info": " +   本日 <",
        "unit": "> 回目"
    },
    "foot": "*---*---*---*---*---*--*---*---*---*---*---*"
}

MacにPyenvとTensorflowをインストールする

はじめに

卒業研究で機械学習を利用した研究を行うことになった。最近話題のTensorflowを使いたいが、手元のMacはPython2がプリインストールされており、まず環境構築から始める必要があったのでその過程を記録しておく。

現在インストールされているPython2を消してPython3をインストールする方法もあるが、Python2が必要になることもあるかもしれないので、Pyenvを使ってバージョンを切り替えられるようにしようと思う。

環境はMacOS 10.12.5、Homebrew 1.2.2で行った。

Pyenvのインストー

インストー

PyenvはPythonのバージョン管理ができるツールだ。インストールはHomebrewから簡単にできる。

$ brew update
$ brew install pyenv

初期化設定

Terminalログイン時にPyenvを初期化するようにする。

$ vi ~/.bash_profile

.bash_profileの最後の行に以下を追加すればよい。

eval "$(pyenv init -)"

内容をすぐに適用させたいので.bash_profileを読み込む。

$ source ~/.bash_profile

Python3のインストー

PyenvからPythonをインストールする。現時点で最新のPython3.6にする。

$ pyenv install 3.6.1

インストールできたら、

$ pyenv versions

として、

* system
  3.6.1 (set by /Users/ユーザ名/.pyenv/version)

となっていることを確認する。

$ pyenv global 3.6.1

を実行してPythonのバージョンを3.6に切り替える。

すぐに試したいので、

pyenv rehash

として設定内容を適用する。

これでPythonのインストールは完了、Pythonを実行して、

Python 3.6.1 (default, May 11 2017, 19:41:23) 
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

と表示されれば成功。

pipのインストー

これまたEasy Installを使うと簡単にインストールできる。

easy_install pip

念のために確認で、

$ pip -V

として、

$ pip 9.0.1 from /Users/ユーザ名/.pyenv/versions/3.6.1/lib/python3.6/site-packages (python 3.6)

が表示されていれば問題なし。

Tensorflowのインストー

これもpipから一瞬でインストールできる。

$ pip install tensorflow

インストールできたらPythonを実行し無事importできれば完了。

$ python
Python 3.6.1 (default, May 11 2017, 19:41:23) 
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow
>>> 

今後の課題

次回はTensorflowになれるために、AND, ORをニューラルネットワークで学習させたいと思う。

yoidea.hatenablog.com

Tensorflowで最もシンプルにAND, ORを学習する

はじめに

機械学習のライブラリになれるためにTensorflowを使ってAND, ORを学習した。

環境はMacOS 10.12.5、Python 3.6.1、tensorflow 1.1.0で行った。

yoidea.hatenablog.com

ニューラルネットワーク

ニューラルネットワークについて自身で説明しようと思っていたが、どうも良い文章がかけなかった。もう少し勉強してから書こうと思う。

ANDを実装

Tensorflow読み込み

import モジュール名 as オブジェクト名

とすると、モジュールを自分で名前をつけたオブジェクトとして読み込むことができる。

今回はTensorflowをtfという名前で読み込んでみる。

import tensorflow as tf

ネットワークを定義

ANDは2入力なので入力変数は、要素数2のベクトルと考える。

 \displaystyle
  \mathbf{x} = \begin{pmatrix} x_{1} \\ x_{2} \end{pmatrix}

Tensorflowを利用すると上式のような変数を簡単に作成できる。

tf.placeholder(データ型, [列数, 行数])

とすると、指定したデータ型と大きさの行列をメモリ空間に確保できる。

データ型はtf.float32で問題ないだろう。要素数2のベクトルを作成する。

x = tf.placeholder(tf.float32, [None, 2])

重みは1行2列の行列と考える。

 \displaystyle
  W = \begin{pmatrix} W_{1} & W_{2} \end{pmatrix}
tf.random_normal([列数, 行数])

とすると、指定した大きさの乱数の入った行列を作成できる。

tf.Variable()の引数に、1行2列の乱数配列を格納して重み変数を作成する。

w = tf.Variable(tf.random_normal([2, 1]))

また、バイアス項として1行1列の乱数配列を作成する。

b = tf.Variable(tf.random_normal([1, 1]))

出力変数は、入力変数に重みを掛けてバイアス項を加えたものに活性化関数をかけたものと考える。

 \displaystyle
  \mathbf{z} = sigmoid(\mathbf{y})
 \displaystyle
  \mathbf{y} = W \mathbf{x} + B
tf.matmul(行列1, 行列2)

とすると、行列の掛け算ができる。また、行列の足し算は「+」演算子をそのまま使用できる。

tf.sigmoid(行列)

とすると、活性化関数としてsigmoid関数をかけることができる。

これらを用いて上式を表す。

z = tf.sigmoid(tf.matmul(x, w) + b)

教師データを格納するために要素数1のベクトルを作成する。

t = tf.placeholder(tf.float32, [None, 1])

損失関数を定義する。オーソドックスに2乗誤差の合計でいいだろう。

 \displaystyle
  l = \sum_{i = 1}^{4} (t_{i} - y_{i})^{2}
tf.reduce_sum(行列)

で合計を求められる。

tf.pow(行列, 指数)

でべき乗を求められる。

tf.subtract(行列1, 行列2)

で差を求められる。

これらを用いて二乗誤差を計算する。

l = tf.reduce_sum(tf.pow(tf.subtract(t, y), 2))

入力値・出力値の宣言

入力値と出力値の組み合わせを配列に格納する。すべての入力パターンに対する出力値なので2次元配列になる。

ANDの場合は、

入力1入力2出力
000
010
100
111

なので以下のような配列で表す。

inputs = [[0, 0], [0, 1], [1, 0], [1, 1]]
outputs = [[0], [0], [0], [1]]

最適化方法の設定

Tensorflowで最適化のメソッドが用意されているため、1行の記述で簡単に最適化方法が設定できる。

tf.train.GradientDescentOptimizer(学習レート).minimize(損失)

とすると、損失を小さくするように最急降下法で最適化される。

適当な変数を宣言して損失関数についてこれを適用する。

train = tf.train.GradientDescentOptimizer(0.1).minimize(l)

セッションの作成・初期化

sess = tf.Session()

として、セッションを作成する。

sess.run()の引数によって様々な操作ができる。

sess.run(tf.initialize_all_variables())

とすると、変数が初期化される。どうやら学習を開始するには初期化が必要なようだ。

学習ループ

最適化を繰り返し行い学習をしていく。

sess.run(最適化関数, 入力変数)

とすると、最適化処理が実行される。入力変数はfeed_dict = {x: inputs, t: outputs}という形で入力値・出力値を対応させる。

念のため10000回ループさせてみる。

for step in range(10000):
    sess.run(train, feed_dict = {x: inputs, t: outputs})

途中経過が知りたいので1000回に1回学習過程を表示するようにしたい。

sess.run(損失, 入力変数)

とすると、現在の損失の値が得られる。

sess.run(出力, 入力変数)

とすると、入力に対する現在の出力が得られる。

for step in range(10000):
    sess.run(train, feed_dict = {x: inputs, t: outputs})
    if step % 1000 == 0:
        print("step : " + str(step))
        print("loss = " + str(sess.run(l, feed_dict = {x: inputs, t: outputs})))
        for i in inputs:
            print("x = " + str(i) + " : y = " + str(sess.run(z, feed_dict = {x: [i]})))

これで途中経過が観察できるはずだ。

完成したソースコードは以下のようになった。

import tensorflow as tf

x = tf.placeholder(tf.float32, [None, 2])
w = tf.Variable(tf.random_normal([2, 1]))
b = tf.Variable(tf.random_normal([1, 1]))
z = tf.sigmoid(tf.matmul(x, w) + b)
t = tf.placeholder(tf.float32, [None, 1])
l = tf.reduce_sum(tf.pow(tf.subtract(z, t), 2))

inputs = [[0, 0], [0, 1], [1, 0], [1, 1]]
outputs = [[0], [0], [0], [1]]

train = tf.train.GradientDescentOptimizer(0.1).minimize(l)

sess = tf.Session()
sess.run(tf.initialize_all_variables())

for step in range(10000):
    sess.run(train, feed_dict = {x: inputs, t: outputs})
    if step % 1000 == 0:
        print("step : " + str(step))
        print("loss = " + str(sess.run(l, feed_dict = {x: inputs, t: outputs})))
        for i in inputs:
            print("x = " + str(i) + " : y = " + str(sess.run(z, feed_dict = {x: [i]})))

ORを実装

ORの場合は、

入力1入力2出力
000
011
101
111

なので以下の入出力の配列を以下のように変えるだけでよい。

inputs = [[0, 0], [0, 1], [1, 0], [1, 1]]
outputs = [[0], [1], [1], [1]]

実行結果

AND学習結果

$ python tensorflow_and.py
step : 0
loss = 1.10273
x = [0, 0] : y = [[ 0.30137503]]
x = [0, 1] : y = [[ 0.06085767]]
x = [1, 0] : y = [[ 0.86426908]]
x = [1, 1] : y = [[ 0.48888674]]
step : 1000
loss = 0.0606695
x = [0, 0] : y = [[ 0.00442047]]
x = [0, 1] : y = [[ 0.13255274]]
x = [1, 0] : y = [[ 0.13271405]]
x = [1, 1] : y = [[ 0.84041691]]
step : 2000
loss = 0.0287164
x = [0, 0] : y = [[ 0.00124461]]
x = [0, 1] : y = [[ 0.09150107]]
x = [1, 0] : y = [[ 0.09150464]]
x = [1, 1] : y = [[ 0.89059579]]
step : 3000
loss = 0.0183822
x = [0, 0] : y = [[ 0.00059863]]
x = [0, 1] : y = [[ 0.07328387]]
x = [1, 0] : y = [[ 0.07328429]]
x = [1, 1] : y = [[ 0.91258895]]
step : 4000
loss = 0.0133999
x = [0, 0] : y = [[ 0.00035929]]
x = [0, 1] : y = [[ 0.06260382]]
x = [1, 0] : y = [[ 0.06260396]]
x = [1, 1] : y = [[ 0.9254263]]
step : 5000
loss = 0.0104966
x = [0, 0] : y = [[ 0.00024315]]
x = [0, 1] : y = [[ 0.05542824]]
x = [1, 0] : y = [[ 0.0554283]]
x = [1, 1] : y = [[ 0.93403047]]
step : 6000
loss = 0.00860571
x = [0, 0] : y = [[ 0.00017737]]
x = [0, 1] : y = [[ 0.05020063]]
x = [1, 0] : y = [[ 0.05020065]]
x = [1, 1] : y = [[ 0.94028848]]
step : 7000
loss = 0.0072804
x = [0, 0] : y = [[ 0.00013618]]
x = [0, 1] : y = [[ 0.04618241]]
x = [1, 0] : y = [[ 0.04618241]]
x = [1, 1] : y = [[ 0.94509327]]
step : 8000
loss = 0.00630194
x = [0, 0] : y = [[ 0.00010851]]
x = [0, 1] : y = [[ 0.04297351]]
x = [1, 0] : y = [[ 0.04297351]]
x = [1, 1] : y = [[ 0.94892669]]
step : 9000
loss = 0.00555099
x = [0, 0] : y = [[  8.89249277e-05]]
x = [0, 1] : y = [[ 0.04033687]]
x = [1, 0] : y = [[ 0.04033687]]
x = [1, 1] : y = [[ 0.95207453]]

OR学習結果

$ python tensorflow_or.py
step : 0
loss = 0.885255
x = [0, 0] : y = [[ 0.7940169]]
x = [0, 1] : y = [[ 0.8566581]]
x = [1, 0] : y = [[ 0.61242062]]
x = [1, 1] : y = [[ 0.7101258]]
step : 1000
loss = 0.0355569
x = [0, 0] : y = [[ 0.14283016]]
x = [0, 1] : y = [[ 0.91314256]]
x = [1, 0] : y = [[ 0.91276491]]
x = [1, 1] : y = [[ 0.99848747]]
step : 2000
loss = 0.0154843
x = [0, 0] : y = [[ 0.09367228]]
x = [0, 1] : y = [[ 0.94210422]]
x = [1, 0] : y = [[ 0.94205385]]
x = [1, 1] : y = [[ 0.99960953]]
step : 3000
loss = 0.0096981
x = [0, 0] : y = [[ 0.07396416]]
x = [0, 1] : y = [[ 0.9540332]]
x = [1, 0] : y = [[ 0.95401716]]
x = [1, 1] : y = [[ 0.99981457]]
step : 4000
loss = 0.00700942
x = [0, 0] : y = [[ 0.06280303]]
x = [0, 1] : y = [[ 0.96085531]]
x = [1, 0] : y = [[ 0.96084803]]
x = [1, 1] : y = [[ 0.99988878]]
step : 5000
loss = 0.00546895
x = [0, 0] : y = [[ 0.05542986]]
x = [0, 1] : y = [[ 0.96538645]]
x = [1, 0] : y = [[ 0.96538246]]
x = [1, 1] : y = [[ 0.99992454]]
step : 6000
loss = 0.00447474
x = [0, 0] : y = [[ 0.05011057]]
x = [0, 1] : y = [[ 0.96866691]]
x = [1, 0] : y = [[ 0.96866459]]
x = [1, 1] : y = [[ 0.99994481]]
step : 7000
loss = 0.00378169
x = [0, 0] : y = [[ 0.04604707]]
x = [0, 1] : y = [[ 0.97117931]]
x = [1, 0] : y = [[ 0.97117776]]
x = [1, 1] : y = [[ 0.99995744]]
step : 8000
loss = 0.00327177
x = [0, 0] : y = [[ 0.04281572]]
x = [0, 1] : y = [[ 0.97318089]]
x = [1, 0] : y = [[ 0.97317988]]
x = [1, 1] : y = [[ 0.99996603]]
step : 9000
loss = 0.00288129
x = [0, 0] : y = [[ 0.0401685]]
x = [0, 1] : y = [[ 0.97482318]]
x = [1, 0] : y = [[ 0.9748224]]
x = [1, 1] : y = [[ 0.99997211]]

大体いい感じに学習できているのが確認できた。

今後の課題

次回は2層のニューラルネットワークでは解決できないXORの学習を行いたい。