【AI・人工知能】Dockerで『将来の年収を予測できるWebアプリ』を作ってみた【Mac&Ubuntu共通】



【AI・人工知能】Dockerで『将来の年収を予測できるWebアプリ』を作ってみた【Mac&Ubuntu共通】

今回は流行りの人工知能開発を、Docker で管理する例をご紹介します。 『将来の年収を予測できるWebアプリ』の作り方を、AIやプログラミング初心者の方にも分かりやすいようにまとめてみました。

目次
  1. 【Mac&Ubuntu共通】Dockerで機械学習の開発環境を構築
  2. Dockerで機械学習の開発環境を作成するメリット
  3. Dockerで機械学習の開発環境を作る
  4. 機械学習のベースプログラム
  5. 人工知能として動くDockerコンテナを利用
  6. Dockerで機械学習の開発環境を作成する様子の動画
  7. まとめ

【Mac&Ubuntu共通】Dockerで機械学習の開発環境を構築

Dockerで機械学習の開発環境を作成するメリット


開発内容にもよると思いますが、人工知能や機械学習のアプリケーションを Docker で開発するメリットは以下の 3点でしょう。
作業効率
【Dockerで機械学習を管理するメリット】作業効率
Pythonノーマル 機械学習プログラムの作成 一回
機械学習プログラムの起動 毎回
Docker 機械学習プログラムの作成 一回
機械学習プログラムの起動 一回
例えば Python で機械学習プログラムを実行する場合、まず仮想環境を起動して、それから python api.py と Pythonプログラムを実行。一方 Docker で機械学習のプログラムを管理している場合、一度 Docker コンテナで機械学習プログラムを起動すれば、後はパソコンの起動と同時に Dockerシステムが起動し、機械学習プログラムが動いていつでも利用できる環境が手に入ります。
共有性
【Dockerで機械学習を管理するメリット】共有性
Pythonノーマル Docker
Files requirements.txt 不要
train.py 不要
data.csv 不要
api.py 不要
Commands
virtualenv myenv
docker run -d -p 5555:5555 oshimamasara/api-ml
source activate myenv
pip install -r requirements.txt
python train.py
python api.py

普通機械学習プログラムを共有する場合、 プログラム実行に必要なファイルとそれらを起動するコマンド操作が必要となります。しかし、 Docker の場合、ファイルは不要で、コマンドも一行で OK。同じ内容の AIプログラムを起動するなら Docker が便利という訳。

必用なソフト、環境
【Dockerで機械学習を管理するメリット】ソフト、環境
Pythonノーマル Docker
PythonもしくはAnaconda Docker

普通プログラムファイルを実行する場合、 〇〇.py なら Python、 〇〇.rb なら Ruby と言語毎のソフトが必要。しかし Docker の場合は Python も Ruby も不要で、 Docker があれば OK。 プログラミング言語毎に開発環境を整えなくて良いというメリットが、Dockerにはありますね。

実際に Docker を使って機械学習アプリケーションを作成してみると、利便性を実感できると思います。


Dockerで機械学習の開発環境を作る

今回は在籍年数と年収のデータを元に、数年後の年収を予測するサンプル・アプリを作りました。開発環境とアプリのワークフローは以下のようになります。

開発言語: Python 
機械学習アルゴリズム: 線形回帰
学習用ライブラリ: scikit-learn
フレームワーク: Flask

【プログラム処理の流れ】

画像クリックで拡大

【実行結果】

image

今回のサンプルアプリは、上図のように年収予測値を計算するプログラムと年数を入力し、計算結果を表示するフロント部分の 2パートに別れます。 Docker で管理するパートは、予測値を計算するプログラム部分。まずは「予測値を計算するプログラム部分」を確認しておきましょう。

機械学習のベースプログラム

画像クリックで拡大

先ほどの図をもう少し機械学習部分に集中して図化すると上図のように。

最終的には、入力値に対して予測値を返せるような WEB API として機械学習機能を公開します。

学習を行う元データは以下の様な感じ。

image

元データ 【data.csv】
在籍年数 年収(¥)
0.5 3200000
1 3737585
1.3 4389475
1.5 3584445
2 4134875
2.1 3789645
2.9 5380990
3 5714250
3.2 5172275
3.3 6122275
3.7 5432955
3.9 6005710
4 6300430
4 6410915
4.1 6422695
4.3 6521344
4.5 6900211
4.7 6205545
4.8 6454110
5.1 6272755
5.3 7893360
5.5 7729485
5.5 7272755
5.5 7872223
5.9 7530456
6 7630445
6.1 6872223
6.4 8530456
6.6 8630445
6.7 8543345

データをグラフ化するプログラム 【graph.py】

from matplotlib import pyplot as plt
from matplotlib import style
import numpy as np

style.use('ggplot')

x,y = np.loadtxt('data.csv',unpack= True,delimiter=',')

plt.plot(x,y, 'go')

plt.title('salary chart')
plt.ylabel('salary')
plt.xlabel('years')

plt.show()

今回のデータは、年功序列的な右肩上がりの年収モデル。機械学習アルゴリズムは、線形回帰を使用。訓練データに 75% のデータを使用し、 残り 25%はテストデータとして使用。 そして最終的には訓練されたデータとして model.pkl を出力。ここまでのプログラムをまとめたものは、以下のような内容となります。

【train.py】

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import pickle
import requests
import json

dataset = pd.read_csv('data.csv')
x = dataset.iloc[:, :-1].values
print(x)
y = dataset.iloc[:, 1].values
print(y)

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 1/4, random_state = 0)
regressor = LinearRegression()
regressor.fit(x_train, y_train)
y_pred = regressor.predict(x_test)
pickle.dump(regressor, open('model.pkl','wb'))
model = pickle.load(open('model.pkl','rb'))
print(model.predict([[1]]))
print(model.predict([[3]]))
print(model.predict([[7]]))


そして次は訓練されたデータ model.pkl をもとに、 入力値に対して予測値を返すプログラムを作成しました。 ベースは Pythonフレームワークの Flask を使用し、年数を入力値として受付、それを元に予測値を出力するプログラムです。

【api.py】

import numpy as np
from flask import Flask, request, jsonify
import pickle

app = Flask(__name__)
model = pickle.load(open('model.pkl','rb'))

@app.route('/api', methods=['POST'])
def predict():
    data = request.get_json(force=True)
    prediction = model.predict([[np.array(data['exp'])]])
    output = prediction[0]
    return jsonify(output)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5555 ,debug = True)

今回は、この予測値を計算するプログラムを Docker で管理するため、 出力先のホストとポート番号を指定する必要があります。

先ほどの train.py を実行し、そして api.py を実行、 http://0.0.0.0:5555/api にアクセスすれば年収を予測可能。ここまでの流れを Docker にまとめますので、必要なライブラリやフレームワークを requirements.txt にまとめておきます。

【requirements.txt】

Flask==1.1.1
numpy==1.16.2
pandas==0.24.1
requests==2.21.0
scikit-learn==0.21.1
simplejson==3.16.0
urllib3==1.24.1

image

作成したファイルを確認すると、上図のように 4つになります。今回は API フォルダの中に 4つのファイルを保存しました。

Docker を使わない通常の Python プログラムの実行であれば、 virtualenv 等で仮想環境を作成し、 pip install -r requirements.txt 、 python train.py 、、、、でいくところですが、今回は Docker でここの部分を管理。 pip install -r requirements.txt や python train.py を自分のコマンド操作ではなく、 Docker に行ってもらいます。そのための Dockerfile を用意する必要がありますね。

今回は、 python:3.6 のイメージを元に Dockerfile を作成してみました。

【Dockerfile】

FROM python:3.6
ADD api train

WORKDIR /train
RUN pip install -r requirements.txt
RUN python3 train.py

ENTRYPOINT ["python"]
CMD ["api.py"]

【上記プログラムの解説 】
コード 説明
FROM python:3.6
Docker Hub の python:3.6 を引用、 OS:Debianベースのイメージ。
ADD api train
現在の作業ディレクトリにある api フォルダを コンテナの train フォルダ下に追加
WORKDIR /train
以下のコンテナに対するコマンドは train ディレクトリで実行
RUN pip install -r requirements.txt
pythonプログラムで必用なライブラリやフレームワークを一括ダウンロード
RUN python3 train.py
訓練済データの model.pkl を出力
ENTRYPOINT [“python”]
コンテナ起動時のアプリを指定
CMD [“api.py”]
コンテナ起動時に実行するファイルを指定


ポートの設定とかシェルスクリプトによる処理など、上記コード以外にも色々設定はできますが、今回は必要最低限の処理内容としました。

画像クリックで拡大

次は Dockerfile を実行し、 api .py が上手く起動するか確認。上図のように Dockerfile があるディレクトリで以下のコマンドを実行。

docker build -t api-test .

api-test は任意の名称で、このコマンドを実行することによって 新たな Dockerイメージ api-test が作成されます(下図参照)。

画像クリックで拡大


画像クリックで拡大

そして新しく作成した Dockerイメージを元にコンテナを起動してみます。

docker run -d --name api-test01 -p 5555:5555 api-test

今回目標とする api.py をコンテナで起動させようと思うと、 docker run のオプションに -d と -p を付随する必要があります。 もし -d も -p もつけずにコンテナを起動したい場合は、Dockerfile を適切に編集する必要が。

上記コマンドを実行し、 http://0.0.0.0:5555/api の様子を curl コマンドで確認すると上図のように。コンテナが正常に稼働していることが確認できます。

これで入力値に対して予測値を処理する Docker 部分のプログラム開発は完了。

image

次は Docker で作成した予測プログラムに、データを入出力するためのフロント部分を作成していきます。


人工知能として動くDockerコンテナを利用

今回のような Docker で動いている人工知能アプリケーションを利用する方法としては、以下の 2通りでしょう。

  • curl でアクセスして、データポスト
  • bottle や Flask などのフレームワークを利用して、データポスト

今回は操作画面がわかりやすい 2番目の botte や Flask を利用して使う方法を選択しました。

画像クリックで拡大

今回利用する年収予測アプリケーションのフローは上図に示すとおり。 Flask を利用して Webサーバーを起動し(app.py)、数字を入力する画面を表示(input.html)。そして数字が入力され、ボタンが押されると、 http://0.0.0.0:5555/api にデータが送信。そして計算結果を表示(output.html)、という流れ。

今回は、 app フォルダを作成し、その中に上記のファイル群を保存しました。

image

各ファイルのコードは以下のとおりです。

【app.py】

from flask import Flask, render_template, request
import requests

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('input.html')

@app.route('/calc',methods=['POST'])
def calc():
    years = int(request.form['year'])
    url = 'http://0.0.0.0:5555/api'
    r = requests.post(url,json={'exp':years})
    x = round(r.json())
    return render_template('output.html',calc = x)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5500,debug=True)

上記コードの概要 【app.py】

Pythonフレームワークの Flask を使用。 app.py が実行されると、 input.html ファイルを読み込み。そして input.html ファイルで数値が入力され、ボタンが押されたら calc() の実行。

input.htmlで入力された値は、文字列として扱われているため、一旦整数型に変更、そして変数 years として取り扱い。

そして入力した年数 years を api.py で定義した exp の値(バリュー)としてデータポスト。返ってきた値を x として、今度は x を calc として output.html にデータ挿入。

それと同時に output.html を読み込み、表示、という流れになります。

【input.html】

<!DOCTYPE html>
<html lang="ja">
<head>

</head>
<body>
<h2>数年後の未来の年収</h2>
<h4>数字を入力して下さい</h4>
<hr>
<form method="post" action="/calc">
  <input type="text" name="year" placeholder="5">
  <button type="submit">計算</button>
</form>

</body>
</html>
【output.html】

<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<h2>あなたの年収予測値:</h2>
<h1>{{calc}} 円</h1>
<hr>
<a href="/">もどる</a>
</body>
</html>

今回は app.py をローカル環境で実行しますので、 app.py に必要なライブラリやフレームワークを requirements.txt からインストールします。

【requirements.txt】

Flask==1.1.1
requests==2.21.0
simplejson==3.16.0
urllib3==1.24.1

ローカル環境で Python の仮想環境を以下のように作成し、requirements.txt を実行。

virtualenv env

source activate env

pip install -r requirements.txt

画像クリックで拡大

そして python app.py を実行し、 http://0.0.0.0.:5500 にアクセスすると入力画面が表示されると思います。半角数字で適当な値を入力し、計算ボタンをクリックすると年収予測値が表示(下図参照)。

画像クリックで拡大

これで人工知能機能を持った Docker にアクセスして、アプリケーションを実行できたことが確認できました。


【アプリケーション部分も Docker で管理できないの?】

今回は人工知能部分だけを Docker で管理し、入出力を管理するフロント部分はローカル環境としました。
入出力部分も Docker で管理できないか挑戦してみましたが、以下のエラーをクリアできませんでした。



requests.exceptions.ConnectionError

requests.exceptions.ConnectionError: HTTPConnectionPool(host='0.0.0.0', port=5555): Max retries exceeded with url: /api (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 111] Connection refused',))

このエラーを Web で検索すると、ファイアウォールの設定だったり、Flask の設定だったりいくつかのエラー原因が。
今回は時間の関係で上記のエラー解決を断念し、入出力のフロント部分はローカル環境としました。
それでも冒頭ご紹介した人工知能プログラムを Docker で管理するメリットは十分にあると思います。

Dockerで機械学習の開発環境を作成する様子の動画

Mac & Linux系の方は、上記の動画が参考になると思います。Windowsの方は、 Flask の host の部分が違ってきます。Windows マシンでも上記プログラムが動かないか挑戦しましたが、 hostの設定が悪いか、Windows のセキュリティーの関係か原因は分かりませんが、再現できませんでした。Windowsマシンでは、 host 0.0.0.0 へのアクセスは許可されていません...恐縮ですが、時間の関係もあり、Windows の方はご了承ください。

AIエンジニアに必要なスキルが身に付く

CodeCampの無料体験はこちら

まとめ

Docker のチュートリアルは、 Web アプリケーションに関するものが多いですが、今回ご紹介したように人工知能系アプリケーションの開発にも Docker 使えることが確認できました。

今回 Python で機械学習モデルを使って 簡単な AIアプリを作成したように、プログラミングの基礎があるといろいろな場面で応用が効きます。「基礎学習、一人でやってもつまんないな」「ITエンジニアになりたいけど、具体的なステップアップがイメージできないな」、そんな時は CodeCampGATE を頼ってみませんか? 4か月間短期集中でプログラミング初心者から現場レベルまでスキルアップしてくれる CodeCampGATE、頼りになると思いますよ。もちろん Docker をはじめ、Webアプリケーションに関する基礎を学習。

「プログラミング・スクール、高いんだろうな...」「どうせ通えないし...」できない理由を固める前に、まずは一度無料相談してみませんか? CodeCampGATEではオンラインで無料相談を随時受けてけていますので、気になる方は 公式ページ よりチェックしてみて下さい。

関連記事

オシママサラ
この記事を書いた人
オシママサラ
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp