JWT (JSON Web Token) についてメモ
JWTとは
最近 JWT認証を使う機会があったので, JWTの生成方法についてまとめます.
JWTは, 以下のような構造
{base64Encodingheader}.{base64Encodeingclaim}.{signature}
JWT生成
- base64Encodingheader
{ "alg": 署名アルゴリズム, RSA-SHA256など "typ": "JWT" }
{ "sub": ユーザの識別子 "iat": トークンの発行時間, "exp":トークンの有効期限, ...etc }
- signature(署名)
HeaderとClaimをbase64でエンコードした文字列を . で結合したものと秘密鍵 Keyで署名アルゴリズムによって,ハッシュ化.
signature = RSA-SHA256(Key , "{base64Encodingheader}.{base64Encodeingclaim}")
この工程でJWTが生成できます.
JWT = "{base64Encodingheader}.{base64Encodeingclaim}.{signature}"
JWT の比較
JWTを発行するサーバで既にユーザ1は登録済み時, ユーザ1から受信したJWTがユーザ1のものか比較する.
以下を受診した JWT とする
_JWT = "{_base64Encodingheader}.{_base64Encodeingclaim}.{_signature}"
ユーザ1が持ってる秘密鍵 Keyと送信されたJWTの署名部分以外を用いて, 署名アルゴリズムでhash化.
signature = RSA-SHA256(Key , "{_base64Encodingheader}.{_base64Encodeingclaim}")
そして, 受信された署名と今生成した署名を比較することで同じユーザのものか検証できる.
if signature == _signatture: return 1 else: return 0
React-Django REST FrameWorkのアプリをHerokuにデプロイ
はじめに
React-Django REST FrameWork で作った日報アプリをHerokuにデプロイする時にやることをまとめます.
このアプリについて少し補足すると, ユーザの認証には JSON Web Token (JWT) , 日報の記事管理は REST framework を用いています.
各種version
基盤となるパッケージの version を列挙しておきます.
- npm 7.3.0
- React 17.0.2
- Python 3.7
- Django 3.2.2
- djangorestframework 3.12.4
- django-cors-headers 3.7.0
- heroku 7.53.1
Herokuにデプロイ
今回は React と Django は別々のプロジェクトとして Heroku へデプロイしました.
- まずHerokuにログイン
$ heroku login
DjangoをHerokuへデプロイ
Djangoのプロジェクト作成済みのところから話を進めます. DjangoをHerokuへデプロイするときは, 前準備として色々やることがあります.
Djangoの設定
- 自分のDjangoのプロジェクトに移動
$ cd <ProjectName>
- Herokuの推奨パッケージをインストール
$ pip install gnucorn django-heroku whitenoise dj-database-url
- requirements.txt へ必要なパッケージを書き出し
$ pip freeze > requirements.txt
ファイルに追加記述
- [setting.py] dj-database-url の設定
ALLOWED_HOSTS = ["*"] import dj_database_url db_from_env = dj_database_url.config(conn_max_age=600) DATABASES['default'].update(db_from_env)
- [setting.py] whitenoise の設定
INSTALLED_APPS = [ 'whitenoise.runserver_nostatic', ... ] ... MIDDLEWARE = [ ... 'whitenoise.middleware.WhiteNoiseMiddleware', ... ] ... STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
- [setting.py] djnago-herokuの設定
DEBUG = False if not DEBUG: django_heroku.settings(locals())
- [setting.py] cors の設定
異なるドメイン間で通信するために以下の設定を忘れると, React側でAPIを叩いても, Djangoで拒否されてしまいます.
<front-AppName>
は次の章でReactのアプリをデプロイするHerokuのアプリの名前です.
CORS_ORIGIN_WHITELIST = (
"https://<front-AppName>.herokuapp.com/"
)
- [.gitignore] pushしないファイルを設定
.gitignore
をプロジェクトの root に作成し, gitignore.io から Django で検索する
<django-project-name>/settings/local.py staticfiles/ ### Django ### *.log *.pot *.pyc __pycache__/ local_settings.py db.sqlite3 media ### Python ### # Byte-compiled / optimized / DLL files *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo # Django stuff: # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json
- Procfile を作成 以下を書き込みます
web: gunicorn <ProjectName>.wsgi --log-file -
- static を生成
プロジェクトのルートに static
というフォルダーを作成し, その直下に .gitKeep
のファイルを作成しておきます.
これでHerokuへデプロイするための Django の設定はおしまいで, ここからはHeroku.
- Heroku に App を作成
<back-AppName>
は <back-AppName>.herokuapp.com のようにURLに含まれます
$ heroku create <back-AppName>
- HerokuのAppとDjangoのプロジェクトを結びつける
$ git init $ heroku git:remote -a <back-AppName> <- HerokuのAppName
- build-pack 追加
$ heroku buildpacks:set heroku/python
- Herokuにpush
$ git add . $ git commit -m "hoge" $ git push heroku master
- Heroku でデータベース設定やsuperuser設定
$ heroku run python manage.py migrate $ heroku run python manage.py createsuperuser
- アクセスしてみる
以下を実行し, /admin にアクセスできれば一応成功 (status code 500 になることもある)
$ heroku open
React を Heroku へデプロイ
React のプロジェクトの作成には, 以下を用いました.
$ npx create-react-app <ProjectName> $ cd <ProjectName>
ここで, Reactのプロジェクト内にある package-lock.json
か yarn.lock
のどちらかを削除します. Herokuにnpm, yarnのどちらを使用するか指定するためです. (今回は, package-lock.json
を削除)
また, Reactで叩くAPI のURLを https://<back-AppName>.herokuapp.com
に変更するのをお忘れずに
( <back-AppName>
はDjangoのプロジェクトをデプロイしたHerokuのアプリの名前)
- Heroku に App を作成
<front-AppName>
は <front-AppName>.herokuapp.com のようにURLに含まれます
$ heroku create <front-AppName>
- HerokuのAppとReactのプロジェクトを結びつける
$ git init $ heroku git:remote -a <front-AppName> <- HerokuのAppName
- build-pack 追加
$ heroku buildpacks:set https://github.com/mars/create-react-app-buildpack.git
- Herokuにpush
$ git add . $ git commit -m "hoge" $ git push heroku master
push すると長々と処理が流れ, デプロイに成功すると最後にURLが表示されます. 以下でアプリにアクセス.
$ heroku open
これで自分の場合は React-Django のアプリをHerokuのサーバ上で実行することができました.
参考
ファイルの数行を一斉削除したいとき
大量のテキストファイルがあり、先頭に URLとかいらない文字列が含まれている場合があるときに便利な コマンドをメモ
"0,Nd"は 0~ N行目まで削除し、その同じファイルに上書き保存する。
sed -i -e "0,Nd" ファイル名 ファイル名
大量にファイルがある場合は、以下のコマンドで一斉に処理できる。
for f in `ls` ; do sed -i -e "0,Nd" $f $f ; done rm *.tex-e
機械学習を用いたwebアプリケーション作った by Flask
はじめに
「web上で機械学習モデルにデータを投げて、結果を表示する」というサーバーサイド辺りのロジックを知りたかったので、手軽に使えるFlaskを用いて(toy)webアプリケーションを作っていきます。
(完成までの所要時間2時間程度でした)
環境
何を予測すんの?
機械学習のタスクは、右から Taco と Burrito という食べ物の2値分類です。
これらのデータであらかじめ学習しておき、学習した重みをファイルに保存しときます。
Flaskでのwebアプリ
まず、Flaskを勉強
といっても Flask を触るのは初めてだったので、youtubeやqiitaでさらっと勉強しましたが、結構直感的に使えるので学習コストは低く感じました。
webアプリの概要
今回のFlaskで作成したwebアプリのファイル構成です。
├── classification.py # 予測するスクリプト ├── main.py # Flaskのスクリプト ├── model │ └── resnet.prm # 学習済みモデル ├── static │ └── css ├── templates │ └── home.html ├── data │ ├── buritto │ └── taco └── upload # 入力されたデータを格納するファイル
プロセスの流れ
簡単にこのwebアプリのプロセスの流れは以下のようになります。
- "main.py" を実行するとサーバー起動ので接続
- web上で画像を投げると、"upload"にその画像が保存される。
- "classfication.py" の予測モデルにその"upload"に保存された画像を入力し、予測結果を返す。
- web上にその画像と予測結果を表示する
DEMO
実際に動かしてみると....
ソースコード
ソースコードはこちらです。
RankNetの実装
はじめに
ランク学習に興味が湧いたのでRankNetで遊びます。 ランク学習とは、ある入力データをランクモデルに入力することで、任意の順序に並び替えて出力してくるものです.(らしい)
こちらを参考にPytorchで実装してみようかと思います。
RankNetの概要
まず、2つのデータとそれらに対するランク をサンプリングします。 これを PairWise手法と言うらしいです。ここで、2つのデータのランクの関係が と仮定します。
次に、あるランクモデル\(f\) を用いて2つのデータのスコア を計算します。(上記の仮定より となるような関数 を学習します。)
そして、2つのスコアを用いて となる確率を計算し、このモデルの予測値となります.
直感的には、 が大きい場合入力は正なので確率は大きくなり、逆に が大きい場合入力は負なので、 確率は小さくなることがわかります。
最後におなじみの損失関数(CrossEntropyLoss)を導入し、これを最小化するように学習します。
そして、2つのランクの大小によって以下のようにラベル\(\bar{P_{ij}} \)を定義します。
実験
今回は猫の画像のランクを出力するモデルを構築します。
データセット
オックスフォード大学が公開している動物画像の Visual Geometry Group - University of Oxfordを用います。
このデータセットには12種類(各200枚ずつ)の猫の画像が含まれており、簡潔化のために3種類に絞った物を学習データとします。
(左から、Bengal、Russian Blue、Brimanの3種類)
ランクは、0 : Russian Blue, 1: Brima , 2 : Briman と定義します。なので、ランクモデルにこの3種を入力した時、この順番で出力されることを期待します。
学習モデル
学習モデルも簡潔化のためにResNet18を用いて、最後の全結合層の出力数を1000 → 1 に変えて、転移学習させます。
コードはこちら
結果
テストとして、3種のネコを2枚ずつ合計6枚をランクモデルに入力した結果が以下となります。
定義したランクの通りに出力されました.
まとめ
今回は RankNetと言うランク学習の1つを実験しました。ネットワーク自体は転移学習でしたのでよくあるパターンのもので、一番の肝は誤差関数をどう設計するかでした。RankNetの後に出た ListNet と言うのもあるので、実装してみたいですね。
混合正規分布の推定(Gibbs Sampling)
はじめに
今回はガウス混合分布の平均と精度が未知の場合のギブスサンプリングについてメモしとこうと思います。 また、解釈の間違いなどがあったら教えていただきたいです。
ガウス混合分布
ガウス混合正規分布の数式は以下の通りで、潜在変数とクラスタごと平均と精度行列を導入します。
また、 はカテゴリ分布に従います。
2つのパラメーターに対して事前分布を導入しますが、この場合の共役事前分布はガウス・ウィシャート分布です。
ギブスサンプリング
ギブスサンプリングでは、潜在変数と分布に関連するパラメータの事後分布に分けてサンプリングすることを考えます。
潜在変数の事後分布
ベイズの定理を使って、に関係する項だけをとります。
上記の式に対数を取って展開した上で でまとめると(1項は指数部以外は定数とする)、
よって、カテゴリ分布になります。
パラメータの事後分布
ベイズの定理を用いて変形すると、グラフィカルモデルで考えると分かるのですが、混合率とそれ以外のパラメータの分布は独立に分解できます。
潜在変数と混合率に関連した分布の後方の2項は、ポアソン混合分布のと同じなのでそれを用いて、
今回は前方の2項を計算すれば良いので、
また、以下の関係があるので、最初に平均の分布を求めてから精度を求めます。
平均
に関する項以外は定数とみなして平方完成すると、
よって、正規分布になります。
精度
(1)の関係を変形すると、精度を求められる形になります。
上記の該当する分布を代入し、 に関する項以外を定数とみなして、 でまとめると、
よって、ウィシャート分布になります。
これで、実装に必要な要素は揃いました!
実装
実験で用いるデータは、データ数N = 400、クラスタK = 4、次元D = 2、です。
ソースコード
ポアソン混合分布の時より少し複雑だったので、関数を用いて実装しました。
結果
60回学習を回した結果です。 以下の画像は左から、「元データ」、「元データへの潜在変数によるクラスタリング」、「推定したパラメータによるサンプリング(N=400)」となっています
推定したパラメータによるガウス分布からのサンプリングの結果は、かなり似た値をサンプリングできています。
また潜在変数による色分けは、クラスタ1と3が少し怪しいので試しに個別に見てみると、元データ通りに潜在変数が振り分けられてることがわかります。