Blockchain Applicationの課題について
目的
Ethereumを使ってtotoのようにJリーグに賭けられるアプリケーションを作成している。 まだ設計の段階だがそこで出てきた課題について残しておく
アプリケーションについて
Design Dodcument
Mock
出てくる課題
ethereum blockchainを使った場合、以下が課題として出てきた。
- transatctionの処理に数分かかるときがある(遅い)
- ユーザがtransfer時にgasを支払う必要がある。
- どのデータ、処理をblockchainに置いて、どれをserverに置くか適切に設計する必要がある。
- blockchain上のcontructに置いたデータは単なる変数なので、複雑な検索などはできない。
- データの使いやすさを求め contruct data -> server dbにコピーする場合、タイミング、方法などの検討が必要
設計について
まだ実装はしていないが、数分のデータ表示の遅延が許容されるならば以下のような設計はどうだろうか
ポイントは
- 価値の交換に関する重要なアクション、データのみコントラクトに置く。
- contractに置いたデータは検索性が低いので、RDBに同期する。
- ユーザへのデータ表示はRDB経由のみとする。(アドミン機能は直接contractをみる場合あり)
blockchain上でRDBのように複雑なデータ構造を表現できるようにならないと、全てblockchain上で完結するのは難しそう。
AWS Batchでの起動時間について
概要
新規プロダクト作成において、非同期にデータ収集、加工処理をする必要がありAWS Batchの検討をしたが、起動時間 が問題で使用できなかったのでその情報を残しておく。
AWS Batchとは
フルマネージドのバッチ処理基盤
キューとセットになっているので、SQSを組み合わせたりする必要がなく、ここにjobを放り込むとキュー管理、実行までやってくれる。 裏側としてはEC2が使われているらしく、
想定使用用途
Webサービスからの依頼で、データの収集、加工、送付をしてくれる非同期処理を作成したい。 作成されるデータ量的には5MB - 10MBぐらいでまあ長くても数分で終わる処理想定。
問題点
ダミーのコンテナを作って、動かして見たが処理開始までの起動時間がネックになってきた。 大体はキューを積んでから数十秒以内にrunnable -> starting -> runningとステータスが遷移して、処理されるのだが たまに、runnableのまま数分放置される場合がある。runningしている処理がないにも関わらずだ。
runningなにもない状態
startingも何もない状態
しかしrunnbableにはたくさんキューがある
数分待つと。。。
処理が開始される。キューが積まれてから処理開始まで8分かかっている。
代案
数分で終わる処理において、数分待たされるのはシステム要件的に許されなそうなので以下構成の方が良さそう。 この構成にすると SQSにキューを積むとほぼ同時にlambda functionが起動するので、あとはコンテナを立ち上げる時間だけ。 なんどやっても1分ほどで起動開始されていた。
Blogger -> Hatena Blogへの移行のしかた
Bloggerでブログを書いていたが、コードの貼り付けなどをサポートしていない、マークダウンで書けないなどの理由で Hatena Blogに移行したので、その移行の仕方をのちの人のために残しておく。
直接移行することはできないのだが、一度WordPressを経由することにより export -> input を実現できる。
事前準備
wordperssの環境を用意するためにAWSを利用した。そのためAWSのアカウントが必要になる。
STEP 1 bloggerのデータをwordpress方式でexport
setting -> other から"Back up content"をクリック
xmlファイルを保存するか聞かれるので適当なフォルダに保存
STEP 2 Wordpressの環境を用意して、ログイン
AWSの Amazon Lightsailを使用してWordpressを用意する。
Lightsailの画面までいき"Create instance"をクリック
instanseのサイズは一番小さいものでOK
Pending -> RunningになればOK
passwordを調べるためにconnectから接続
以下のコマンドでパスワードを調べる
ユーザ : user
パスパード : 先ほどログインしたもの
ログインできると以下のような画面になる
STEP 3 ファイルをコンバート
tool -> bloger を選択
blogerからダウンロードしたファイルを選択してインポート
インポート後All Postsを見てみて、今までの投稿があれば成功している。
Tool -> Export で "All Content"を選びExport、適当なフォルダに保存する。
STEP 4 htenablogでファイルをインポート
設定 -> インポートからwordpress 形式を選びインポート
STEP 5 忘れずにAWSのインスタンスを削除
Fine tuning (VGG16モデル) (Keras + Jupyter Notebook + tensorflow)
概要
Keras公式サイトの をやってみる。少ないサンプルからディープラーニングで優位なモデルを作る。ステップとしては、- スクラッチで作る。
- bottleneck featureで学習済みモデル使う
- Fine tuningを使う
- スクラッチで作る。
- bottleneck featureで学習済みモデル使う
- Fine tuningを使う
画像の用意
まず、クラス分けする画像の用意をする。今回は猫と犬のクラス分け。kaggleからcats and dogsのデータをダウンロードする。このデータセットは25000枚あるが、今回は少ないデータセットでのモデル構築が目的なので、トレーニングデータとしてcats, dogs 1000枚ごと、テストデータとして400枚ごと取り出してフォルダに分ける。
- cats_and_dogs_1000 - train - cats (1000枚) - dogs (1000枚) - validation - cats (400枚) - dogs (400枚)
切り分けたコマンド
ll dog* | head -1000 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/train/dogs/
ll cat* | head -1000 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/train/cats/
ll dog* | tail -400 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/validation/dogs/
ll cat* | tail -400 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/validation/cats/
ll dog* | head -1000 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/train/dogs/ ll cat* | head -1000 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/train/cats/ ll dog* | tail -400 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/validation/dogs/ ll cat* | tail -400 | awk '{print $9}' | xargs -i cp -p {} ../../cats_and_dogs_1000/validation/cats/
前処理とデータ増加
画像を少し加工しながらデータを増やす。これには過学習を防いでモデルを、一般化する効果があるらしい。Kerasでは keras.preprocessing.image.ImageDataGenerator class を使ってこれを実現できる。
必要なライブラリのインポート<code>from keras.preprocessing.image import ImageDataGeneratorfrom keras.models import Sequentialfrom keras.layers import Conv2D, MaxPooling2Dfrom keras.layers import Activation, Dropout, Flatten, Densefrom keras import backend as K<code>
画像増やす。<code># this is the augmentation configuration we will use for testing:# only rescalingtest_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary')
validation_generator = test_datagen.flow_from_directory( validation_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary')<code>
スクラッチの畳み込み演算トレーニング
<code>model = Sequential()model.add(Conv2D(32, (3, 3), input_shape=input_shape))model.add(Activation('relu'))model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))model.add(Activation('relu'))model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))model.add(Activation('relu'))model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())model.add(Dense(64))model.add(Activation('relu'))model.add(Dropout(0.5))model.add(Dense(1))model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])<code>
正解率は以下のようになった。
Epoch 50/50
125/125 [==============================] - 13s - loss: 0.4843 - acc: 0.7900 - val_loss: 0.4923 - val_acc: 0.7950
Bottleneck feature
学習済みモデルの最終層を削除して、そのモデルを特徴抽出として使うことをbottleneck featureと呼ぶらしい
ここはよく理解できなかったのでスキップ
Epoch 50/50
125/125 [==============================] - 13s - loss: 0.4843 - acc: 0.7900 - val_loss: 0.4923 - val_acc: 0.7950
Bottleneck feature
ここはよく理解できなかったのでスキップ
Fine Tuning
- VGG16モデルを読み出して、パラメータをロードする。
- 前で作ったモデルをトップに積んで、パラメータをロードする。
- VGG16の層をfreezeする。
- モデルのコンパイル
- トレーニング
必要なKerasのクラスロード
<code>
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.models import Model
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
<code>
使用する変数の定義
<code>
# path to the model weights files.
weights_path = '../keras/examples/vgg16_weights.h5'
top_model_weights_path = 'bottleneck_fc_model.h5'
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = 'images/cats_and_dogs_1000/train'
validation_data_dir = 'images/cats_and_dogs_1000/validation'
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16
<code>
VGG16モデルをロードして、bottleneck featureで作成したモデルをトップに積む。
<code>
# build the VGG16 network
base_model = applications.VGG16(weights='imagenet', include_top= False, input_shape=(150, 150, 3))
print('Model loaded.')
# build a classifier model to put on top of the convolutional model
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid'))
# note that it is necessary to start with a fully-trained
# classifier, including the top classifier,
# in order to successfully do fine-tuning
top_model.load_weights(top_model_weights_path)
# add the model on top of the convolutional base
# model.add(top_model)
model = Model(input= base_model.input, output= top_model(base_model.output))
<code>
最初の25レイヤーはパラメータをアップデートしないようにする。
<code>
# set the first 25 layers (up to the last conv block)
# to non-trainable (weights will not be updated)
for layer in model.layers[:25]:
layer.trainable = False
<code>
モデルのコンパイル
<code>
# compile the model with a SGD/momentum optimizer
# and a very slow learning rate.
model.compile(loss='binary_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
<code>
画像データの用意
<code>
# prepare data augmentation configuration
train_datagen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary')
<code>
モデルの学習
<code>
# fine-tune the model
model.fit_generator(
train_generator,
samples_per_epoch=nb_train_samples,
epochs=epochs,
validation_data=validation_generator,
nb_val_samples=nb_validation_samples)
<code>
結果は以下のようになり、精度が上がったことが確認できた。
Epoch 50/50
125/125 [==============================] - 151s - loss: 0.5791 - acc: 0.9250 - val_loss: 1.1987 - val_acc: 0.8813
参考
- ディープラーニング実践入門 〜 Kerasライブラリで画像認識をはじめよう!
- 公式ドキュメント
- FindYourCandyで転移学習を使ったのでそれ関連の話
- A Comprehensive guide to Fine-tuning Deep Learning Models in Keras (Part I)
- A Comprehensive guide to Fine-tuning Deep Learning Models in Keras (Part II)
- Deep Learning 事始め(第5回 転移学習入門)
- Deep Learning 事始め(第6回[※最終回] 転移学習応用編)
- Clifar10の説明
- Building powerful image classification models using very little data
Android Studio でプロジェクト新規作成、読み込みできない時
Macを新しいものに変えたごAndroid Studioでプロジェクトが新規作成、読み込みできなくなって調べたのでメモ
Web API Mockサーバをサクッと立てたいときのjson-server
フロントの開発や、サーバサイドで他Web APIを叩くときにAPI側の開発が完了してないときや、いろいろな返却値を試したいときがある。
そのときにサクッとMockを立てられるOSSがあったので紹介する。
json-server
node.jsで書かれたWeb API MockサーバでREST APIをコーディングなしでサクッと立てられる。公式に書いてあった
Get a full fake REST API with zero coding in less than 30 seconds (seriously)も嘘でなかった。
環境構築
グローバルに入れたくない場合、まず適当なフォルダを作ってnpm initでパッケージのリスト作る。
jun-mac:json-server jun-ishioka$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
Seenpm help json
for definitive documentation on these fields
and exactly what they do.
Usenpm <span style="color: #dad085;">install</span> <pkg> <span style="color: #e28964;">-</span><span style="color: #e28964;">-</span>save
afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (json-seerver-test) json-server-test
version: (1.0.0)
description: for test
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/jun-ishioka/temp/json-server/package.json:
{
"name": "json-server-test",
"version": "1.0.0",
"description": "for test",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this ok? (yes) yes
jun-mac:json-server jun-ishioka$ npm install --save-dev json-server
いろいろパッケージが入るのでこれで完了
使用方法
{
"users": [
{ "id": 1, "name": "kageki", "genger": "man" },
{ "id": 2, "name": "kageki_2", "genger": "man" }
]
}
以下コマンドで立ち上げ
jun-mac:json-server jun-ishioka$ node node_modules/json-server/bin/index.js -w db.json
{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3000/users
Home
http://localhost:3000
Type s + enter at any time to create a snapshot of the database
Watching...
リクエストを投げてみるとjsonが返却される。
jun-mac:~ jun-ishioka$ curl -O GET http://localhost:3000/users
curl: Remote file name has no length!
curl: try 'curl --help' or 'curl --manual' for more information
[
{
"id": 1,
"name": "kageki",
"genger": "man"
},
{
"id": 2,
"name": "kageki_2",
"genger": "man"
}
]
応用的な使い方
1つのサーバに2つのrailsアプリを共存させる方法
個人で作成しているKindleセール本まとめサイトで、railsアプリを1サーバに共存させる必要が出てきたのでその方法。
概要
環境はUbuntu, Nginx, Unicorn。
手順
cd ~/repos/kinsume_blog
rbenv local install 2.2.7
gem install bundler
bundle install
Unicornの設定ファイルを作成
新しく設定したいアプリの下で、vim config/unicorn.rbでファイルを新規作成。
app_path = File.expand_path(File.dirname(FILE) + '/..')$
$
# workerをいくつ立ち上げるか。ここではCMSであまりアクセスないことを$
# 想定していて、メモリの空きもないので1にしている。$
worker_processes 1$
$
# どのソケットで連携するかNginxの設定ファイルにも書くので覚えておく$
listen app_path + '/tmp/kinsume_blog.sock', backlog: 64$
timeout 300$
working_directory app_path$
$
# この辺もすでに動いているアプリと被らないようにする$
pid app_path + '/tmp/kinsume_blog.pid'$
stderr_path app_path + '/log/kinsume_blog.log'$
stdout_path app_path + '/log/kinsume_blog.log'$
$
preload_app true$
$
GC.respond_to?(:copy_on_write_friendly=) &&$
GC.copy_on_write_friendly = true$
$
before_fork do |server, worker|$
defined?(ActiveRecord::Base) &&$
ActiveRecord::Base.connection.disconnect!$
end$
$
after_fork do |server, worker|$
defined?(ActiveRecord::Base) &&$
ActiveRecord::Base.establish_connection$
end$
railsアプリのルートパスを変える。refinery-cmsのパスを変えるには下記ファイルを変更。
vim config/initializers/refinery/core.rb
# Specify a different Refinery::Core::Engine mount path than the default of "/".$
# Make sure you clear thetmp/cache
directory after changing this setting.$
config.mounted_path = "/kinsume_blog"$
わかりやすくなるように、静的ファイルのパスを元のアプリと変える。
vim config/environments/production.rb
config.assets.prefix = '/static'$
Nginxの設定ファイルは以下
upstream tagosaku{$
server unix:/home/ishioka/repos/tagosaku/tmp/tagosaku.sock fail_timeout=0;$
}$
# 先ほど作成したアプリのソケットファイルをここで指定
upstream kinsume_blog{$
server unix:/home/ishioka/repos/kinsume_blog/tmp/kinsume_blog.sock fail_timeout=0;$
}$
$
server {$
error_log /var/log/nginx/error.log debug;$
listen 80;$
$
root /home/ishioka/repos/tagosaku;$
index index.html index.htm;$
$
keepalive_timeout 300;$
client_max_body_size 4G;$
# kinsume_blogないで使っているgemから走るアクセスパスをどうしても変えられなかったので悲しみのrewriteで対応
rewrite ^/wymiframe$ /kinsume_blog/wymiframe last;$
$
# ここでもkinsume_blogないのgemから走るアクセスを変えられなかったので、いったんassetsを見てふぁいるがなければ/static/を見に行くように変更
location ~ ^/assets/(.*) {$
root /home/ishioka/repos/tagosaku/public/;$
try_files $uri /static/$1 =404;$
}$
$
# staticへのアクセスはkinsume_blogの静的ファイルへのアクセスなのでロケーションを変更
location /static/ {$
root /home/ishioka/repos/kinsume_blog/public/;$
}$
location / {$
# First attempt to serve request as file, then$
# as directory, then fall back to displaying a 404.$
#try_files $uri $uri/ =404;$
$
# Uncomment to enable naxsi on this location$
# include /etc/nginx/naxsi.rules$
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;$
$
# This passes requests to unicorn, as defined in /etc/nginx/nginx.conf$
proxy_set_header Host $http_host;$
proxy_pass http://tagosaku;$
proxy_read_timeout 300s;$
proxy_send_timeout 300s;$
}$
$
location /kinsume_blog {$
# First attempt to serve request as file, then$
# as directory, then fall back to displaying a 404.$
#try_files $uri $uri/ =404;$
$
# Uncomment to enable naxsi on this location$
# include /etc/nginx/naxsi.rules$
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;$
$
# This passes requests to unicorn, as defined in /etc/nginx/nginx.conf$
proxy_set_header Host $http_host;$
proxy_pass http://kinsume_blog;$
proxy_read_timeout 300s;$
proxy_send_timeout 300s;$
}$
$
error_page 500 502 503 504 /500.html;$
$
location = /500.html {$
root /home/ishioka/repos/tagosaku/public;$
}$
}
refinery-cmsのpluginからリクエストされる静的ファイルのパスを/から/kinsume_blogへ変更することができなかったので、nginxのrewriteを駆使して対応。
あまりアクセスパスを変更されることを想定されてない作りっぽいので、PR出していきたい。