【Ethereum】EthereumでPrivateNetworkを作ってみる
仕事の関係でブロックチェーンのプラットフォームであるEthereumを調べることになり、
簡単な動作確認を行うためにプライベートのEthereumのネットワークを作成してみました。
- ※ 調べながらのものなのでところどころ間違っているかもしれません。
- ※ ブロックチェーン、仮想コイン自体の知識も深くないためそちらも認識に齟齬があるかもしれません。
動作環境
OS: ubuntu:14.04 * ※ 僕の環境はMacOSなのですが、試行錯誤なので環境がよごれないようにDockerでubuntuをインストールして試しています。 * ※ Docker周辺の操作自体は割愛させていただきます。
Ethereumとは
Ethereumは、ブロックチェーンを使ったアプリケーションのプラットフォームです。
(Ethereum、ブロックチェーンの技術詳細については、ここでは割愛します。)
ブロックチェーンを使ったアプリケーションを作成する方法は大きく分けて2つあります。
1つは、「ゼロからブロックチェーンのネットワークを構築する方法」、もう一つは「既存のブロックチェーンの技術基盤を利用して構築する方法」です。
Ethereumは後者にあたるもので、Ethereumを利用することでブロックチェーンを利用したアプリケーションを低コストで作成することができます。
Gethをインストールする
EthereumのP2Pネットワークに参加するためにGeth
というクライアントツールが提供されています。
(GethはGo言語製のツールです)
Gethをインストールすることで、
といった操作を行うことができます。 まずは、このツールをインストールします。
sudo apt-get install software-properties-common sudo add-apt-repository -y ppa:ethereum/ethereum sudo add-apt-repository -y ppa:ethereum/ethereum-dev sudo apt-get update sudo apt-get install ethereum
ネットワーク用のディレクトリを作る
mkdir eth_private cd eth_private
※ このテスト実装では、/ethereum
というディレクトリをルートディレクトリとして作業しています。
アカウントをつくる
一番初めのアカウントを定義します。
geth --datadir /ethereum/eth_private account new
datadir
に先程作成したディレクトリを指定します
WARN [07-09|03:57:57] No etherbase set and no accounts found as default Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase:
No etherbase set and no accounts found as default
- この警告はなんでしょう?デフォルトのアカウントがないよという意味のようですが、何もない状態でアカウントを作成しているから?一旦無視します。
パスワードを聞かれるため入力する
- ※ 注意 パスワードを忘れるとあとで確認する方法がないため、忘れない方法で保管しておきます。
Address: {4e2e0ef96802a54c8e1d5c937e38290c42ced5f0}
- 発行されるとアカウントの公開キーが表示されます。(アカウントのアドレスと呼ばれるものです。)
- アカウントの作成が成功すると作業ディレクトリ配下に
keystore
というディレクトリが作成されています。 - さらにその配下にはUTC-xxxから始まるjsonファイルが作成されています。
root@03be5503f430:/ethereum/eth_private# ls -la total 0 drwxr-xr-x 3 root root 102 Jul 9 03:58 ./ drwxr-xr-x 5 root root 170 Jul 9 03:57 ../ drwx------ 3 root root 102 Jul 9 2017 keystore/ root@03be5503f430:/ethereum/eth_private# ls -la keystore/ total 4 drwx------ 3 root root 102 Jul 9 04:04 ./ drwxr-xr-x 3 root root 102 Jul 9 03:58 ../ -rw------- 1 root root 491 Jul 9 03:58 UTC--2017-07-09T03-58-15.183698355Z--4e2e0ef96802a54c8e1d5c937e38290c42ced5f0
{ "address": "4e2e0ef96802a54c8e1d5c937e38290c42ced5f0", "crypto": { "cipher": "aes-128-ctr", "ciphertext": "ee886a6635bc095337d643de774ec86c38c32016a1f56c5f3d1e9fb092993193", "cipherparams": { "iv": "caa069b4c621db2ddd3c9aa11acd9de2" }, "kdf": "scrypt", "kdfparams": { "dklen": 32, "n": 262144, "p": 1, "r": 8, "salt": "8453090efc0f98075afbb046521273909a3c26d6244e2453b83ddae7d6d0540c" }, "mac": "85249864f73dd75ed70e9e8e2123aa0d10d2c5f73d7bfde510fa547804d092d3" }, "id": "a9d3805d-0a8a-4ef4-a89a-1c0949737951", "version": 3 }
- addressは先程作成したアカウントの公開キーと一致するためこれがアカウント情報のようです。(詳細はここでは追いません)
GenesisBlockの設定ファイルを作成する
{ "config": { "chainId": 13, "homesteadBlock": 0, "eip155Block": 0, "eip158Block": 0 }, "difficulty": "200000000", "gasLimit": "2100000", "alloc": { "4e2e0ef96802a54c8e1d5c937e38290c42ced5f0": { "balance": "100000000" } } }
chainId
: 後に指定するネットワークIDと合わせたIDhomesteadBlock
: 0ブロック以降がHomestead
であるという設定homestead
とは、Ethereumのバージョンのことでこのバージョンの前後で処理が異なるみたいです
eip155Block
: 不明eip158Block
: 不明difficulty
: マイニングの難易度。低ければ低い程、短時間でマイニングできるようです。gasLimit
: トランザクションで指定できる最大gasalloc
: 初期Etherの設定。ここで先程作成したアカウントを指定しています。- 単位は
wei
- 単位は
GenesisBlockを初期化する
geth --datadir /ethereum/eth_private init /ethereum/eth_private/CustomGenesis.json
- ここでもネットワークのディレクトリを指定してます。
INFO [07-09|04:15:31] Allocated cache and file handles database=/ethereum/eth_private/geth/chaindata cache=16 handles=16 INFO [07-09|04:15:31] Writing custom genesis block INFO [07-09|04:15:31] Successfully wrote genesis state database=chaindata hash=6aa7ce…33ec9a INFO [07-09|04:15:31] Allocated cache and file handles database=/ethereum/eth_private/geth/lightchaindata cache=16 handles=16 INFO [07-09|04:15:31] Writing custom genesis block INFO [07-09|04:15:31] Successfully wrote genesis state database=lightchaindata hash=6aa7ce…33ec9a
- 上記のように表示されれば正しく初期化がされています。
root@03be5503f430:/ethereum/eth_private# ls -la total 4 drwxr-xr-x 5 root root 170 Jul 9 04:15 ./ drwxr-xr-x 5 root root 170 Jul 9 03:57 ../ -rw-r--r-- 1 root root 288 Jul 9 04:14 CustomGenesis.json drwxr-xr-x 4 root root 136 Jul 9 04:15 geth/ drwx------ 3 root root 102 Jul 9 04:04 keystore/
root@03be5503f430:/ethereum/eth_private# ll geth/ total 0 drwxr-xr-x 4 root root 136 Jul 9 04:15 ./ drwxr-xr-x 5 root root 170 Jul 9 04:15 ../ drwxr-xr-x 7 root root 238 Jul 9 04:15 chaindata/ drwxr-xr-x 7 root root 238 Jul 9 04:15 lightchaindata/
- geth配下には
chaindata
というディレクトリがあり、ここにはブロックチェーンの起源を表すleveldbデータベースファイルと、それが採掘されてブロックチェーンに追加された後のブロックが含まれているようです。 - つまり新しいブロックが作られるとこのDBにデータが追加されていくようです。
Gethを起動(コンソール)
- Gethを起動しネットワークにattachします。
- Gethには対話式のコンソールが用意されています。このコンソールを起動して色々確認してみます。
geth --networkid 13 --datadir /ethereum/eth_private console 2>> /ethereum/eth_private/geth_err.log
instance: Geth/v1.6.6-stable-10a45cb5/linux-amd64/go1.8.1 coinbase: 0x4e2e0ef96802a54c8e1d5c937e38290c42ced5f0 at block: 0 (Thu, 01 Jan 1970 00:00:00 UTC) datadir: /ethereum/eth_private modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 >
- networkidには、Genesisファイルで定義したchainIdを指定します。
- errer出力をlogファイルに書き出しています。
アカウントの確認
> eth.accounts ["0x4e2e0ef96802a54c8e1d5c937e38290c42ced5f0"]
- 先程作成したアカウントが確認できます。
etherbase(coinbase)の確認
> eth.coinbase "0x4e2e0ef96802a54c8e1d5c937e38290c42ced5f0"
- etherbase(coinbase)とは、そのノードで発掘を行った時にその報酬を紐付けるEOAのアドレスを指します。
所持Etherの確認
> eth.getBalance("0x4e2e0ef96802a54c8e1d5c937e38290c42ced5f0") 100000000
- 引数にアカウントのaddressを指定します。
- Genesisファイルで初めに指定したEther(単位はwei)を所持していることが確認できます
Gethを起動(JSON-RPC)
- コンソールを使わずにネットワークにattachします。
geth \ --datadir /ethereum/eth_private \ --mine \ --nodiscover \ --maxpeers 0 \ --networkid 13 \ --rpc \ --rpccorsdomain "*"
mine
: マイニングを許可する。このオプションを指定するとマイニングが始まるようです。nodiscover
: Gethはデフォルトで自動的に(同じネットワークID)のEthereumネットワークのノード(Peer)を探し接続を試みます。プライベート・ネットで未知のノードとの接続を避けるため、このオプションを指定することで自動Peer探索機能を無効にします。maxpeers
ネットワークに接続するノードの最大数(デフォルト25) 0を指定するとネットワークが無効になります。networkid
ネットワークID(デフォルト1) 1を指定するとグローバルのネットワークに接続されます。- 2,3,4も予約されているようです。(2=Morden (disused), 3=Ropsten)
rpc
HTTP-RPC serverとして動作を許可するrpccorsdomain
クロスオリジンを許可するリスト
root@03be5503f430:/ethereum/eth_private# geth --datadir /ethereum/eth_private --mine --nodiscover --maxpeers 0 --networkid 13 --rpc --rpccorsdomain "*" INFO [07-09|06:02:23] Starting peer-to-peer node instance=Geth/v1.6.6-stable-10a45cb5/linux-amd64/go1.8.1 INFO [07-09|06:02:23] Allocated cache and file handles database=/ethereum/eth_private/geth/chaindata cache=128 handles=1024 INFO [07-09|06:02:23] Initialised chain configuration config="{ChainID: 13 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Metropolis: <nil> Engine: unknown}" INFO [07-09|06:02:23] Disk storage enabled for ethash caches dir=/ethereum/eth_private/geth/ethash count=3 INFO [07-09|06:02:23] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2 INFO [07-09|06:02:23] Initialising Ethereum protocol versions="[63 62]" network=13 INFO [07-09|06:02:23] Loaded most recent local header number=0 hash=6aa7ce…33ec9a td=200000000 INFO [07-09|06:02:23] Loaded most recent local full block number=0 hash=6aa7ce…33ec9a td=200000000 INFO [07-09|06:02:23] Loaded most recent local fast block number=0 hash=6aa7ce…33ec9a td=200000000 INFO [07-09|06:02:23] Starting P2P networking INFO [07-09|06:02:23] RLPx listener up self="enode://9df46f04a32634b47ce6fe8203b8077029550890d5f118b6ad88aaee15db9d96ac819f119a3997c5b5c9cecff395b866c7c45c39f830ce3111d63fb7c5853bed@[::]:30303?discport=0" INFO [07-09|06:02:23] IPC endpoint opened: /ethereum/eth_private/geth.ipc INFO [07-09|06:02:23] HTTP endpoint opened: http://127.0.0.1:8545 INFO [07-09|06:02:23] Transaction pool price threshold updated price=18000000000 INFO [07-09|06:02:23] Starting mining operation INFO [07-09|06:02:23] Commit new mining work number=1 txs=0 uncles=0 elapsed=178.695µs INFO [07-09|06:02:28] Generating DAG in progress epoch=0 percentage=0 elapsed=3.764s INFO [07-09|06:02:30] Generating DAG in progress epoch=0 percentage=1 elapsed=6.657s
- gethを起動するとしばらく
Generating DAG in progress
というログが流れる。これはDAGという数Gバイトのデータセットを作成しているログのようです。 - これは
Ethash
というProof of Work
を行うための仕組みで使われるもの。詳しくはここを参照。 - DAGはデフォルトで
$(HOME)/.ethash
配下に作成されています。
INFO [07-09|07:09:58] Successfully sealed new block number=1 hash=ef4ec0…62e718 INFO [07-09|07:09:58] 🔨 mined potential block number=1 hash=ef4ec0…62e718 INFO [07-09|07:09:58] Commit new mining work number=2 txs=0 uncles=0 elapsed=431.601µs
- しばらくすると(1,2時間くらい)マイニングが始まりブロックが作成されます
JSON-RPCで通信してみる
クライアントのバージョン(web3_clientVersion)
curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":"Geth/v1.6.6-stable-10a45cb5/linux-amd64/go1.8.1"
Etherの確認(eth_getBalance)
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x4e2e0ef96802a54c8e1d5c937e38290c42ced5f0", "latest"],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":"0x5f5e100"}
- resultには16進数の値が入っている。これを10進数に変換すると
100000000
となるので正しい値が入っていることがわかります。
参考
Kerasのサンプルソースが何をやっているか読んでみる
前回は、Kerasのインストールを行い機械学習を行うための環境を構築しました。
しかし、今の状態だと何をどうすればどう使えるのかも全く分からないため、とりあえずKerasのサンプルソースを読んで理解を深めていこうと思います。
その前にニューラルネットワークの前提知識が完全にゼロでソースを理解するのはおそらく難しいだろうなと思い、各所で紹介されている以下の書籍を読みました。
ただし、数学や計算処理については、完全に理解するのは大変そうだったため、難しそうな部分はサラッと流しています。
まずは、なんとなく理解したディープラーニングについて自分なりの解釈をまとめます。
※ これは自分の学習用のまとめになります。 ※ 上記のため単語やアルゴリズムの解釈が間違っている。齟齬がある。場合があるかとおもいます。 ※ 理解がない人が初めて触れた時に噛み砕くための解釈として捉えてもられれば幸いです。
MLPとは何なのか?
多重パーセプトロンの略(Multi-Layer Perceptron)。
パーセプトロンとは複数の信号を入力として受取り一つの結果を返す有るゴリスムのこと。
このパーセプトロンの層を複数に重ねたものを多重パーセプトロン
という。
この多重パーセプトロンをニューラルネットワーク
と表現する。
このニューラルネットワークを利用した学習をディープラーニング
と呼ぶ。
Kerasを使ったディープラーニングの大まかな流れ
① 多重パーセプトロンのための層を構築する
- このサンプルでは
Sequential
というモデルを使って構築する
- このサンプルでは
② モデルの最適化アルゴリズムなどの設定(compile)
③ モデルに学習データを与えて学習させる(fit)
④ 損失値(どれだけ精度がでているか)を計算する(evaluate)
※ ② ~ ④を繰り返し、モデルを最適化(損失値を少なく)する
- ⑤ 実際の予測値を算出する(predict)
大枠こんな感じかと思います。
訓練データとテストデータ
機械学習では、学習
と推論
という2つのプロセスがあります。
学習のプロセスでは予め用意したデータを使ってパラメタをモデルに学習させます。
その時に使うデータとして訓練データというものを用意します。
学習が完了したあとは、モデルに対して推論(実際にある値に対しての分類を抽出する)を行い精度を検証していきます。 上記検証に使うデータをテストデータといいます。
サンプルの読み込み
では、サンプルソースを追っていきたいと思います。
サンプルソースには、reuters_mlp.pyというロイターのニュース・トピック分類
のサンプルを使用しています。
このサンプルを選んだ理由としては、自前のMacでは計算にGPUを使えないこともあり、動かして色々と見て見るにはテキストデータの方が計算が早そうだなと思ったためです。
サンプルデータの説明は、こちらのページに載っています。
'''Trains and evaluate a simple MLP on the Reuters newswire topic classification task. ''' from __future__ import print_function import numpy as np import keras from keras.datasets import reuters from keras.models import Sequential from keras.layers import Dense, Dropout, Activation from keras.preprocessing.text import Tokenizer max_words = 1000 batch_size = 32 epochs = 5 print('Loading data...') # ① サンプルデータの読み込み (x_train, y_train), (x_test, y_test) = reuters.load_data(num_words=max_words, test_split=0.2) print(len(x_train), 'train sequences') print(len(x_test), 'test sequences') # ② ラベルの最大値を求める num_classes = np.max(y_train) + 1 print(num_classes, 'classes') # ③ テキストをベクトル化する print('Vectorizing sequence data...') tokenizer = Tokenizer(num_words=max_words) x_train = tokenizer.sequences_to_matrix(x_train, mode='binary') x_test = tokenizer.sequences_to_matrix(x_test, mode='binary') print('x_train shape:', x_train.shape) print('x_test shape:', x_test.shape) # ④ ラベルをバイナリクラス行列に変換する print('Convert class vector to binary class matrix ' '(for use with categorical_crossentropy)') y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) print('y_train shape:', y_train.shape) print('y_test shape:', y_test.shape) # ⑤ モデルを構築する print('Building model...') model = Sequential() model.add(Dense(512, input_shape=(max_words,))) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes)) model.add(Activation('softmax')) # ⑥ 学習の設定 model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # ⑦ 学習の実行 history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.1) # ⑧ 損失値の計算 score = model.evaluate(x_test, y_test, batch_size=batch_size, verbose=1) print('Test score:', score[0]) print('Test accuracy:', score[1])
① サンプルデータの読み込み
(x_train, y_train), (x_test, y_test) = reuters.load_data(num_words=max_words, test_split=0.2)
- 訓練データとテストデータをKerasが用意しているデータ・セットから読み込んでいます
num_words
で指定しているのは単語の最大数です。このサンプルでは1000個の単語を使用するということになります。test_split
では、使用するデータに中でテストデータとして使う割合です。(20%をテストデータとして使用するということ)- (x_train, y_train), (x_test, y_test)はnumpy.arrayのタプルです
- trainには訓練データ、testにはテストデータが返ってきます
- x_train, x_testには、ニュース文字列のインデックス値(文字列を一意に特定する値)が入っています。
- このサンプルだと
8982
の文字列が格納されています。((*, 8982)の2次元配列ということ) - num_wordsで単語の最大数をしているため各配列に格納されている値は、1~1000の値になります。
[1, 2, 699,・・・ 12]
のようなデータが格納されている
- このサンプルだと
- y_train, y_testには、分類のラベルが格納されています。ラベルとは分類される値(正解のようなもの)が格納されています。
- ラベルはIntegerの値で格納されています
② ラベルの最大値を求める
num_classes = np.max(y_train) + 1 print(num_classes, 'classes')
- ラベルの値で使われている最大値を求めます。
- 後述しますが、このラベルの値はKerasの計算においては、0と1の配列として変換する必要がありその要素数として使われます。
- 1を加算するのは、配列の要素は0から始まるため
③ テキストをベクトル化する
print('Vectorizing sequence data...') tokenizer = Tokenizer(num_words=max_words) x_train = tokenizer.sequences_to_matrix(x_train, mode='binary') x_test = tokenizer.sequences_to_matrix(x_test, mode='binary') print('x_train shape:', x_train.shape) print('x_test shape:', x_test.shape)
- Tokenizerというのは、テキストをベクトル化するクラスです。
- ①で取得した単語データの配列(長さ8982の配列)は可変長のためこれを1次元の配列に変換します。
- 例えば、
3
という数値については、[0, 0, 0, 1]という配列に変換します。 - [1, 2]という配列であれば[0, 0, 1, 1]となります
- 例えば、
- Tokenizerの初期化時に
num_words
というパラメタを渡しています。これはnum_words長の配列に変換するということです。- 配列にはmax_wordsの数値しか格納されていないため、最大長をmax_wordsの配列にすれば、全てのデータが1次元配列に変換できるということです。
x_train shape: (8982, 1000) x_test shape: (2246, 1000)
- printの出力は上記になります。最大長が1000(max_words)の配列に変換されていることがわかります。
④ ラベルをバイナリクラス行列に変換する
y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) print('y_train shape:', y_train.shape) print('y_test shape:', y_test.shape)
- ラベルデータについても、③のように0と1の行列データに変換します。(https://keras.io/ja/utils/np_utils/)
num_classes
にはラベルで使用されるデータの最大値が格納されているためnum_classesを要素数とする配列に変換されます。
y_train shape: (8982, 46) y_test shape: (2246, 46)
- printの出力は上記になります。最大長が46(num_classes)の配列に変換されていることがわかります。
⑤ モデルを構築する
print('Building model...') model = Sequential() model.add(Dense(512, input_shape=(max_words,))) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes)) model.add(Activation('softmax'))
- Kerasが用意するSequentialモデルを使用することで複数の層を重ねるモデルが作成できます。
model.add(Dense(512, input_shape=(max_words,)))
- 一番はじめの層で入力する次元数を指定します。
- max_words(=1000)なので1000個の入力を受け取る指定になります
- 第一引数は出力次元数です(512の意味はまだわかってません..)
- Kerasでは2層以降の入力数は指定しなくていいようです。
Activation('relu')
は活性化関数の指定です。(reluはアルゴリズムの方式)Dropout(0.5)
は過学習を防ぐためにニューロンを無効化する処理です。引数はその割合(この場合は半分の値を捨てている)を指します。Dense(num_classes)
で2層目の指定をしています。ここでは出力をnum_classes(=ラベルのクラス数)に指定しています。Activation('softmax')
2層目の活性化関数にはsoftmax
というアルゴリズムを使っています。
⑥ 学習の設定
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
- 層を構築したモデルに対して学習の設定を行います。
loss
は損失関数の指定です。categorical_crossentropy
は交差エントロピー誤差
というアルゴリズムを指定しています。- 損失関数とは、
どれだけ精度が出ているかという指標
として使われる関数で、どれだけ正しくないか?
という値を求めるためのものです。(この結果が小さい=精度が高いと判断できます)
- 損失関数とは、
optimizer
は、パラメタ最適化のための探索アルゴリズムを指定しています。- ニューラルネットワークでは、損失関数ができるだけ小さくなるための最適パラメタを学習によってもとめます。その為に指定するアルゴリズムの手法をここで設定しています。
metrics
は評価を行うためのリストの方式?を指定します。- 一般的に
['accuracy']
を指定する?
- 一般的に
⑦ 学習の実行
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.1)
- モデル層の構築、学習の設定から実際に学習を行います。
- 第一引数は、訓練入力データ
- 第二引数は、訓練ラベル
batch_size
は、同時計算するサンプル数- ニューラルネットワークではある一定のデータ量をまとめて処理することができる。まとめて計算することで計算上のコストを削減させている。
epochs
学習のサイクル数verbose
結果の出力validation_split
ホールドアウト検証として使うデータの割合- 標本から一定数の事例を無作為に選択し、残りを訓練事例として使う。
⑧ 損失値の計算
score = model.evaluate(x_test, y_test, batch_size=batch_size, verbose=1) print('Test score:', score[0]) print('Test accuracy:', score[1])
- 学習完了したモデルからテストデータを使って損失値を計算する
- 第一引数は、テスト入力データ
- 第二引数は、テストラベル
- batch_sizeは、同時計算サンプル数(fitと同じ)
- socoreの0番目には損失値(1-損失値)が入っている
- socoreの1番目には、accuracy(精度)が入っている
- ⑥のmodel.compileの
metrics
で指定した値が入る
- ⑥のmodel.compileの
- ※ lossとaccuracyの使い分けがあまりわかっていません。ココらへんもおいおい。
score: 0.889519923517 Test accuracy: 0.793410507569
- printの出力結果は上記になります。結果としてこのモデルの精度は79%となっています。
まとめ(感想)
ざっくりとやっていることを追っていくとなんとなくどんなことをやっているかは理解できました。 ただ、これらを使って自分がやりたい学習をどう実現するか?どのようなモデルを構築すればよいか?などはまだまだ理解できていません。 自分で学習したいデータを作成する方法など、少しずつ勉強していきたいと思います。
Kerasの環境をMacに構築する
最近、今更ながら機械学習の勉強をしてみようと思い、色々調べていました。
僕は行列計算などの高校数学もほとんどわからないのですが、最近はPythonでのエコシステムがかなり充実してきているようで、頑張れば簡単なもの位は作れるようになるかなと思い、1から勉強しようと思っています。
まずは、Macに環境構築するところから始めます。 機械学習のライブラリとしては、Google製のTensorFlowが有名(僕が知らないだけですが..)ですが、色々みていると、Chainer、Kerasというのが最近の人気のようです。
Chainerは、日本製とのことで日本語の資料が充実しているらしいのですが、今回はKerasを使ってみます。 理由は、GoogleのTensorFlowをバックエンドに使えるということもあり、今後も成熟が期待できそうだからです。
環境構築の方法は、TensorFlowの公式ページなど色々みてみましたが、Dockerを使ったクリーンな環境構築なども推奨されているようです。
ですが、僕自身Dockerの知識がそこまで豊富でないため、Docker周りのトラブルが出ても面倒なのでとりあえず普通にMacにインストールしてみたいと思います。
Pythonのバージョン管理ツールをインストール
brew install pyenv brew install pyenv-virtualenv
パスを通す&初期設定
PYENV_ROOT=~/.pyenv export PATH=$PATH:$PYENV_ROOT/bin eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)"
.bashrc
や.zshrc
にpyenvのパスを通します
Pythonのバージョンインストール
pyenv install anaconda3-4.3.1
- 今回は機械学習の為にPythonを使うため、
Anaconda
という計算系のライブラリがオールインワンになっているディストリビューションをインストールします。- ※ Anacondaの詳細については割愛します
virtualenvで環境を作る
conda create -n keras python=3.6.1 anaconda
※ 追記 一番はじめは以下のようにpyenv-virtualenv
で環境を作っていましたが、コンソールを切り替えた時などに上手く環境が切り替えられずconda
コマンドを使った方法に変更しました
pyenv virtualenv anaconda3-4.3.1 keras
ローカル環境用のディレクトリを作成する
mkdir keras cd keras
- keras用の作業環境を作成するためディレクトリを切ります
ローカル環境を切り替える
pyenv local anaconda3-4.3.1/envs/keras
- keras用の環境設定をローカル環境として設定します
Tenserflowをインストール
pip install tensorflow
kerasをインストール
pip install keras
その他必要なモジュール
pip install h5py
- 学習後の結果を保存するためのファイル(h5形式)を扱うライブラリ
設定ファイル
mkdir ~/.keras echo '{"epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow"}' >> ~/.keras/keras.json
- backendをtensorflowにするための設定ファイルを作成します。
- ※ tensorflowがインストールされている状態だとデフォルトでtenserflowになっているようなので必要ないかも
以上で、インストールは完了です。
動作確認
試しにsampleソースを動かしてみます。
kerasでは、幾つかのサンプルソースが提供されています。
その中でも機械学習のチュートリアルでもよく出てくるMNIST
という手書き数字を認識するためのサンプルを動かしてみました。
https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py
'''Trains a simple deep NN on the MNIST dataset. Gets to 98.40% test accuracy after 20 epochs (there is *a lot* of margin for parameter tuning). 2 seconds per epoch on a K520 GPU. ''' from __future__ import print_function import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout from keras.optimizers import RMSprop batch_size = 128 num_classes = 10 epochs = 20 # the data, shuffled and split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) model = Sequential() model.add(Dense(512, activation='relu', input_shape=(784,))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(10, activation='softmax')) model.summary() model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test)) score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])
このソースを実行します
python mnist_mlp.py
以下が結果です。
Using TensorFlow backend. 60000 train samples 10000 test samples _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 512) 401920 _________________________________________________________________ dropout_1 (Dropout) (None, 512) 0 _________________________________________________________________ dense_2 (Dense) (None, 512) 262656 _________________________________________________________________ dropout_2 (Dropout) (None, 512) 0 _________________________________________________________________ dense_3 (Dense) (None, 10) 5130 ================================================================= Total params: 669,706 Trainable params: 669,706 Non-trainable params: 0 _________________________________________________________________ Train on 60000 samples, validate on 10000 samples Epoch 1/20 2017-06-22 12:47:14.203012: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203031: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203037: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203042: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations. 60000/60000 [==============================] - 8s - loss: 0.2422 - acc: 0.9254 - val_loss: 0.1386 - val_acc: 0.9573 Epoch 2/20 60000/60000 [==============================] - 6s - loss: 0.1014 - acc: 0.9699 - val_loss: 0.0768 - val_acc: 0.9771 Epoch 3/20 60000/60000 [==============================] - 6s - loss: 0.0753 - acc: 0.9771 - val_loss: 0.0798 - val_acc: 0.9758 Epoch 4/20 60000/60000 [==============================] - 6s - loss: 0.0615 - acc: 0.9815 - val_loss: 0.0732 - val_acc: 0.980 Epoch 5/20 60000/60000 [==============================] - 6s - loss: 0.0495 - acc: 0.9850 - val_loss: 0.0902 - val_acc: 0.9783 Epoch 6/20 60000/60000 [==============================] - 6s - loss: 0.0443 - acc: 0.9866 - val_loss: 0.0860 - val_acc: 0.9797 Epoch 7/20 60000/60000 [==============================] - 6s - loss: 0.0380 - acc: 0.9883 - val_loss: 0.0719 - val_acc: 0.9834 Epoch 8/20 60000/60000 [==============================] - 7s - loss: 0.0351 - acc: 0.9900 - val_loss: 0.0869 - val_acc: 0.9822 Epoch 9/20 60000/60000 [==============================] - 8s - loss: 0.0327 - acc: 0.9906 - val_loss: 0.0764 - val_acc: 0.9827 Epoch 10/20 60000/60000 [==============================] - 7s - loss: 0.0308 - acc: 0.9911 - val_loss: 0.0786 - val_acc: 0.9836 Epoch 11/20 60000/60000 [==============================] - 9s - loss: 0.0285 - acc: 0.9918 - val_loss: 0.0814 - val_acc: 0.9835 Epoch 12/20 60000/60000 [==============================] - 7s - loss: 0.0248 - acc: 0.9930 - val_loss: 0.0928 - val_acc: 0.9824 Epoch 13/20 60000/60000 [==============================] - 7s - loss: 0.0259 - acc: 0.9927 - val_loss: 0.1057 - val_acc: 0.9823 Epoch 14/20 60000/60000 [==============================] - 7s - loss: 0.0231 - acc: 0.9933 - val_loss: 0.1030 - val_acc: 0.9820 Epoch 15/20 60000/60000 [==============================] - 7s - loss: 0.0232 - acc: 0.9939 - val_loss: 0.1116 - val_acc: 0.9815 Epoch 16/20 60000/60000 [==============================] - 7s - loss: 0.0204 - acc: 0.9947 - val_loss: 0.1055 - val_acc: 0.9829 Epoch 17/20 60000/60000 [==============================] - 6s - loss: 0.0217 - acc: 0.9947 - val_loss: 0.1281 - val_acc: 0.9821 Epoch 18/20 60000/60000 [==============================] - 7s - loss: 0.0197 - acc: 0.9950 - val_loss: 0.1176 - val_acc: 0.9839 Epoch 19/20 60000/60000 [==============================] - 7s - loss: 0.0229 - acc: 0.9942 - val_loss: 0.1120 - val_acc: 0.9831 Epoch 20/20 60000/60000 [==============================] - 7s - loss: 0.0228 - acc: 0.9944 - val_loss: 0.1078 - val_acc: 0.9834 Test loss: 0.107835494385 Test accuracy: 0.9834
と動いているようです。
The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
あたりの警告は、ソースからコンパイルしていないTenserFlowの場合CPUの拡張オプションが使えないのでスピードアップができないみたいなことみたいです。
とりあえず、よくわかってませんが動く環境をつくるところまでは成功しました。
ここから徐々に機械学習への理解を深めていきたいと思います。
参考
Installing TensorFlow on Mac OS X | TensorFlow
pyenvとanacondaを共存させる時のactivate衝突問題の回避策3種類 - Qiita
Python: Keras/TensorFlow の学習を CPU の拡張命令で高速化する (Mac OS X) - CUBE SUGAR CONTAINER
独自のDockerImageを作成する
Dockerでは、自分で独自のimageを作成することが可能です。 独自のdocker imageを作成する方法は主に2つあります。
① docker container commit
コマンドを使う
② Dockerfileからビルドする
今回は、①の起動中のDockerコンテナから新しいイメージを作成する方法を試してみます。
※ 実行環境は、Docker for Mac
を使っています。
※ 環境構築については過去記事のとおりです。
docker container commit
コマンドを使う
ベースイメージの準備
今回はnginxのイメージを元に独自のイメージを作成してみます。 まずは、ベースとなるnginxのimageをDocker Hubからダウンロードします。
docker image pull nginx:latest
docker image pull <イメージ名>:<タグ名>
- ※ タグ名を
latest
にすると最新のバージョンを取得
イメージを確認してみます。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 46102226f2fd 4 days ago 109 MB
取得したイメージからコンテナを起動します。
docker run -d -p 80:80 --name webserver nginx
docker run -d -p <ポート> --name <コンテナ名> <イメージ名>
-d
: コンテナをバックグラウンドで起動する-p
: ポート指定、<ホストのポート>:<コンテナのポート>で割当を行う。 例: <80>:<12345> コンテナの12345ポートをホストの80ポートに割り当てる--name
: コンテナに名前を割り当てる
localhost
にアクセスして確認します。
nginxが起動してデフォルトのindex.htmlファイルが表示されていることが確認できました。
コンテナの内容を編集
dockerのコンテナにアクセスしてこのindexファイルを編集してみます。
docker exec -it webserver /bin/bash
docker exec -it <コンテナ名> <コマンド>
-i
: コマンド入力後にコンテナの標準入力をホストの標準入力と接続する-t
: コンテナ内の仮想端末と、Dockerホストの標準出力と接続する
cd /usr/share/nginx/html echo "<h1>Welcome my nginx</h1>" > index.html
localhost
に再度アクセスするとindex.htmlの内容が変更されていることが確認できます。
docker imageを作成
index.htmlを編集した状態の今のコンテナからimageを作成します。
docker container commit webserver mynginx:latest
docker container commit <コンテナ名> <イメージ名>:<タグ>
イメージを確認してみます
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE mynginx latest fa7dff65a5ba 5 seconds ago 109 MB nginx latest 46102226f2fd 4 days ago 109 MB
起動中のコンテナを削除して今作ったイメージからコンテナを起動します。
docker stop webserver docker rm webserver
docker stop <コンテナ名>
: コンテナを停止docker rm <コンテナ名>
: コンテナの削除
docker run -d -p 80:80 --name myserver mynginx
localhostにアクセスして確認します。
先程に編集した状態でイメージが起動していることを確認できました。
Docker for Macを使ってみる
現状は、Vagrantを使って開発環境を構築することが多いのですが、最近はDockerを使って開発しているという話をよく聞きます。 DockerだとマシンスペックをVMほど使用しないというのがメリットの一つらしく、素早く軽量に開発環境を整えるため役立つのかな?と思い勉強したいと思います。
Dockerのインストール
公式ページからMacアプリをダウンロードすることもできますが、 今回はHomebrew経由でインストールします。
brew cask install docker
- インストールが完了したらDocker.appを起動
- Docker appがシステムにアクセスするための許可を求められるためOKを押下してパスワードを入力
- 上記画面が表示されるようになってDockerコマンドが使えるようになっていればインストール完了です
docker --version Docker version 1.12.3, build 6b644ec
docker run -d -p 80:80 --name webserver nginx
Dockerコンテナを起動する
- Dockerのチュートリアルの通り2つのイメージを起動してみます。
hello-world
% docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/
docker run
コマンドはdockerイメージからのコンテナを起動するコマンドです。- 上記の出力を見るとローカルにimageが存在しないときは、Docker Hubから該当するimageを探してダウンロードするようです。
nginx
% docker run -d -p 80:80 --name webserver nginx cdea6236c8862e3768b3560034c28c41dd7534a706a1e76b30a25c763962b32c
- 出力されているのは、コンテナの識別IDです。
-d
: コンテナをバックグラウンドで起動する-p
: ポート指定、<ホストのポート>:<コンテナのポート>で割当を行う。 例: <80>:<12345> コンテナの12345ポートをホストの80ポートに割り当てる--name
: コンテナに名前を割り当てる
この状態で、localhost
にブラウザでアクセスするとnginxのデフォルト起動画面が確認できます。
% docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cdea6236c886 nginx "nginx -g 'daemon ..." 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 443/tcp webserver
docker ps
で現在起動中のコンテナを確認できます。
その他のDockerコマンド
イメージの一覧
- ローカルに保存されているDocker imageを確認する
docker images
コンテナの停止
- dockerコンテナを停止する
docker stop <name or ID>
コンテナの削除
- dockerコンテナを削除する
- 同じ名前のコンテナは作成できないため一度削除する必要がある
docker rm <name or ID>
参考
Oracle Database ExpressをCentOSにインストールする
Oracle Databaseは、基本的には商用(有償)のDBMSですが無償で使えるパッケージが有るみたいなので試してみます。
環境
パッケージのダウンロード
- ダウンロードページから
Oracle Database Express Edition 11g Release 2 for Linux x64
をダウンロード ※ ダウンロードには、Oracleのアカウント登録が必要です
sudo yum install -y unzip unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip
インストール
- 必要なコマンドをインストール
sudo yum install -y glibc make gcc binutils libaio libaio-devel bc net-tools
sudo dd if=/dev/zero of=/swap bs=1M count=2048 sudo chmod 600 /swap sudo mkswap /swap sudo swapon /swap cat /proc/swaps
vi /etc/fstab
/swap swap swap defaults 0 0
sudo rpm -ivh Disk1/oracle-xe-11.2.0-1.0.x86_64.rpm
- インストール成功すると最後に
You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.
と表示されている
これはDB構成のコマンドらしいのでそのまま実行
sudo /etc/init.d/oracle-xe configure
- 対話型で設定が聞かれる
Oracle Database 11g Express Edition Configuration ------------------------------------------------- This will configure on-boot properties of Oracle Database 11g Express Edition. The following questions will determine whether the database should be starting upon system boot, the ports it will use, and the passwords that will be used for database accounts. Press <Enter> to accept the defaults. Ctrl-C will abort. // デフォルトのHTTPポート番号 Specify the HTTP port that will be used for Oracle Application Express [8080]: // オラクルのポート番号 Specify a port that will be used for the database listener [1521]: /etc/init.d/oracle-xe: line 405: netstat: command not found // SYSTEMユーザーのパスワード Specify a password to be used for database accounts. Note that the same password will be used for SYS and SYSTEM. Oracle recommends the use of different passwords for each database account. This can be done after initial configuration: Confirm the password: Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]:y Starting Oracle Net Listener...Done Configuring database... Done Starting Oracle Database 11g Express Edition instance...Done Installation completed successfully.
DBへアクセス
- コマンドの読み込み
. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
- sqlplusでアクセス
sqlplus system
- パスワードを聞かれるため、先程設定したものを入力
sqlplus system SQL*Plus: Release 11.2.0.2.0 Production on 日 3月 26 10:49:30 2017 Copyright (c) 1982, 2011, Oracle. All rights reserved. パスワードを入力してください: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production に接続されました。 SQL>
- 正しくログインできれば設定完了
MySQLより説明が少なく少なくイメージがありますね。