シェルにログインボーナス機能を追加してみた
はじめに
プログラミングの勉強のために毎日シェルにログインしたいがモチベーションが続かない。
そんな悩みをお持ちではないだろうか?
毎日ログインするぞと決断しては3日で続かなくなる。というのを僕は繰り返していた。
そこで、如何にしてログインをシェルにログインするモチベーションを向上させるかを考えたところ、ソーシャルゲームのようなログインボーナスがあれば毎日ログインする気になるのではないかという結論に至った。
そこで、シェルにログインボーナスを追加するだけの簡易なプログラムをPythonで作ってみた。
デモ
機能は至ってシンプルで、シェルにログインすると、通算・連続・当日のログイン回数を表示する。日本人は数字が好きなのでこれだけでもモチベーションが向上するだろう。
また、特定回数ログインするとお祝いのメッセージが表示される。正直なところボーナスといっても何を与えたら良いのかわからず、祝辞を表示するぐらいしか思い浮かばなかった。とは言え、長期間ログインすると豪華なアスキーアートが表示される。
インストール
動作環境
Python3またはPython2のインストールされたMac、Linuxで動作する。.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の場合
cd ~/LBFS python logger.py cd ~/
Python2の場合
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をニューラルネットワークで学習させたいと思う。
Tensorflowで最もシンプルにAND, ORを学習する
はじめに
機械学習のライブラリになれるためにTensorflowを使ってAND, ORを学習した。
環境はMacOS 10.12.5、Python 3.6.1、tensorflow 1.1.0で行った。
ニューラルネットワーク
ニューラルネットワークについて自身で説明しようと思っていたが、どうも良い文章がかけなかった。もう少し勉強してから書こうと思う。
ANDを実装
Tensorflow読み込み
import モジュール名 as オブジェクト名
とすると、モジュールを自分で名前をつけたオブジェクトとして読み込むことができる。
今回はTensorflowをtfという名前で読み込んでみる。
import tensorflow as tf
ネットワークを定義
ANDは2入力なので入力変数は、要素数2のベクトルと考える。
Tensorflowを利用すると上式のような変数を簡単に作成できる。
tf.placeholder(データ型, [列数, 行数])
とすると、指定したデータ型と大きさの行列をメモリ空間に確保できる。
データ型はtf.float32で問題ないだろう。要素数2のベクトルを作成する。
x = tf.placeholder(tf.float32, [None, 2])
重みは1行2列の行列と考える。
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]))
出力変数は、入力変数に重みを掛けてバイアス項を加えたものに活性化関数をかけたものと考える。
tf.matmul(行列1, 行列2)
とすると、行列の掛け算ができる。また、行列の足し算は「+」演算子をそのまま使用できる。
tf.sigmoid(行列)
とすると、活性化関数としてsigmoid関数をかけることができる。
これらを用いて上式を表す。
z = tf.sigmoid(tf.matmul(x, w) + b)
教師データを格納するために要素数1のベクトルを作成する。
t = tf.placeholder(tf.float32, [None, 1])
損失関数を定義する。オーソドックスに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 | 出力 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
なので以下のような配列で表す。
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 | 出力 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
なので以下の入出力の配列を以下のように変えるだけでよい。
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の学習を行いたい。