はじめに
「Aidemy Premium Plan(AIアプリ開発コース 6ヶ月)」を受講したことについてまとめてみた。
受講期間:2020年10月〜2021年4月
本記事の目次
●自己紹介
●Aidemyを受講した理由
●Aidemyでの学習内容
●最終成果物の作成について振り返り
●受講後の感想
自己紹介
・20代後半(受講時)
・男性(既婚・子1)
・建設業界所属(東証一部上場) ※育児休業期間あり
・地方国立大学、大学院卒業
・大学、大学院時代にR[プログラミング言語]の使用経験あり(少し使える程度)
・入社後、業務効率化のために簡単なプログラムをVBAで作成し活用した
・G検定不合格(2019年11月9日)
Aidemyを受講した理由
・建設業界は効率が悪いことが多く、嫌気がさしていた。
・大学院時代からPythonに興味があり、業務に活かせるのではないかと思った。
・AIブームが来ていたので、興味が増した。
・専門実践教育訓練給付金を使うと受講料の負担が半分程度で済むことを知った。
・将来に不安があったので、出来ることは増やしておきたいと思っていた。
・講義費用を一括で支払える余力が少しあった。
・他のプログラミングスクールよりPythonに強い気がした。
アイデミーでの学習内容
・環境構築
・Python入門
・Numpy
・Pandas
・Matplotlib
・データクレンジング
・機械学習概論
・教師あり学習(分類)
・スクレイピング
・ディープラーニング基礎
・CNN
・男女認識
・HTML/CSS
・Flask入門
・MNISTを用いた手書き文字認識アプリ作成
・アプリ制作
・コマンドライン入門
・Git入門
・デプロイ
最終成果物の作成について振り返り
最終作成物(建設機械判定機)
https://kikai-judgment.herokuapp.com/
判定機作成から公開まで
**1.画像の収集**
**2.モデル構築と保存**
作成したコード※説明付き
# モジュールオブジェクトのインポート
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from keras.utils.np_utils import to_categorical
from keras.layers import Dense, Dropout, Flatten, Input
from keras.applications.vgg16 import VGG16
from keras.models import Model, Sequential
from keras import optimizers
from os import listdir
# イメージサイズの定義をする
image_size = 50
# listdir('./xx/')ファイルの中にある画像を入れる。
path_bh = [filename for filename in listdir('./bh/') if not filename.startswith('.')]
path_bu = [filename for filename in listdir('./bu/') if not filename.startswith('.')]
path_rollar = [filename for filename in listdir('./rollar/') if not filename.startswith('.')]
# 各ファイルを順番に呼び出す。(ファイルにある個数分繰り返す。)
# OpenCVで画像サイズをリサイズして統一する。
# img_にリサイズしたものを加える。
img_bh = []
img_bu = []
img_rollar = []
for i in range(len(path_bh)):
img = cv2.imread('./bh/'+ path_bh[i])
img = cv2.resize(img,(image_size,image_size))
img_bh.append(img)
for i in range(len(path_bu)):
img = cv2.imread('./bu/'+ path_bu[i])
img = cv2.resize(img,(image_size,image_size))
img_bu.append(img)
for i in range(len(path_rollar)):
img = cv2.imread('./rollar/'+ path_rollar[i])
img = cv2.resize(img,(image_size,image_size))
img_rollar.append(img)
X = np.array(img_bh + img_bu + img_rollar) #行列をくっつける。
y = np.array([0]*len(img_bh) + [1]*len(img_bu) + [2]*len(img_rollar)) #0、1、2と種類ごとに番号をつける。
rand_index = np.random.permutation(np.arange(len(X))) #np.arange(x)の配列をランダムに並べ替えてrand_indexに入れる。
X = X[rand_index] #Xをrand_index順に並び替える
y = y[rand_index] #yをrand_index順に並び替える
# データを分割する。
X_train = X[:int(len(X)*0.8)] #トレーニングデータ8割未満
y_train = y[:int(len(y)*0.8)]
X_test = X[int(len(X)*0.8):] #トレーニングデータ以外
y_test = y[int(len(y)*0.8):]
# 各属性を表示する。
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
y_train = to_categorical(y_train) #One-Hotベクトルを作成する。
y_test = to_categorical(y_test) #One-Hotベクトルを作成する。
# 転移学習(VGG16モデル)を活用する。ImageNetで事前学習した重みを読み込む。
input_tensor = Input(shape=(image_size, image_size, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
# 特徴抽出部分以降に新しく他の層を追加するにために、あらかじめVGGとは別のモデル(ここではtop_model)を定義する。
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:])) #VGGを結合する。
top_model.add(Dense(256, activation="sigmoid")) #1つ目の全結合層の出力ユニット数は256,活性化関数はshigmoid.
top_model.add(Dropout(0.5)) #過学習を防ぐ。
top_model.add(Dense(64, activation='sigmoid'))
top_model.add(Dropout(0.5))
top_model.add(Dense(32, activation='sigmoid'))
top_model.add(Dropout(0.5))
top_model.add(Dense(3, activation='softmax')) #ソフトマックス関数を用いて3次元で出力する。
## vgg16とtop_modelを連結してください
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
# 15番目の層までは固定し、それ以降のものを繰り返し学習する。
for layer in model.layers[:15]:
layer.trainable = False
# コンパイルする。
model.compile(loss='categorical_crossentropy', #多クラス分類の損失関数を定義する。
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), #最適化関数を定義する。
metrics=['accuracy']) #評価関数を定義する。
# X_train, y_trainを用いて学習を行う。テストデータは、X_test, y_test。
history = model.fit(X_train, y_train, batch_size=32, epochs=75, verbose=1, validation_data=(X_test, y_test))
# 精度の評価する。
score = model.evaluate(X_test, y_test, batch_size=32, verbose=0)
print('validation loss:{0[0]}\nvalidation accuracy:{0[1]}'.format(score))
# モデルを保存する。
model.save("my_model.h5")
参照したサイト
**3.Flaskを用いたWebアプリケーションの作成**
Flaskとは
Flaskサイド制作で作成したコード※説明付き
# ライブラリとモジュールをインポートする。
import os
from flask import Flask, request, redirect, url_for, render_template, flash
from werkzeug.utils import secure_filename
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.preprocessing import image
import numpy as np
classes = ["バックホウ","ブルドーザー","ローラー"] #分類したいクラス名を定義する。
num_classes = len(classes) #リストの長さを取得し定義する。
image_size = 50 #イメージサイズを定義する。
# UPLOAD_FOLDERはアップロードされたファイルを格納する場所を指定する。
UPLOAD_FOLDER = "uploads"
# アップロードを許可するファイルを指定する。
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__) #Flaskクラスのメソッドを使えるようにする。 例:@app.route、app.run()
# ファイル名が正しいフォーマットになっているかを確認している。
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
model = load_model('./my_model.h5')#学習済みモデルをロードする
@app.route('/', methods=['GET', 'POST']) #URLが受け入れるHTTPメソッドを指定する。
def upload_file():
if request.method == 'POST': #request.methodはページへの接続方式を探知する機能。POSTかを判別する。
if 'file' not in request.files: #ファイルがない場合
flash('ファイルがありません')
return redirect(request.url) # リクエストされたページに転送する。
file = request.files['file']
if file.filename == '': #ファイル名がない場合
flash('ファイルがありません')
return redirect(request.url) #リクエストされたページに転送する。
if file and allowed_file(file.filename):
filename = secure_filename(file.filename) #サニタイズするする。
file.save(os.path.join(UPLOAD_FOLDER, filename)) #ファイルの保存する。
filepath = os.path.join(UPLOAD_FOLDER, filename) #保存先をfilepathに格納する。
#受け取った画像を読み込み、np形式に変換する。
img = image.load_img(filepath, grayscale=False, target_size=(image_size,image_size))
img = image.img_to_array(img)
data = np.array([img])
#変換したデータをモデルに渡して予測する。
result = model.predict(data)[0]
predicted = result.argmax()
pred_answer = "これは " + classes[predicted] + " です"
#render_templateの引数にanswer=pred_answerと渡すことで、index.htmlに書いたanswerにpred_answerを代入する。
#この引数に渡すhtmlファイルはtemlpatesフォルダに置いておく必要がある。
return render_template("index.html",answer=pred_answer)
#POSTリクエストがなされないときはindex.htmlのanswerには何も表示しない。
return render_template("index.html",answer="")
# Pythonスクリプトを実行したときのみ、if __name__ == '__main__':以下の処理を実行させるようにする。
if __name__ == "__main__":
port = int(os.environ.get('PORT', 8080)) #os.environ.getで取得した環境変数の文字列型(str)の値を数値方(int)に変更して代入する。
app.run(host ='0.0.0.0',port = port) #app.run()が実行され、サーバが立ち上げる。
その他(HTML&CSSサイド制作等)
HTML&CSSサイド作成
HTMLのコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>建設機械判定機</title>
<link rel="stylesheet" href="./static/stylesheet.css">
</head>
<body>
<header>
<a class="header-logo" href="#">建設機械判定機</a>
</header>
<div class="main">
<h2> AIが送信された建設機械画像の種類を識別します</h2>
<p>バックホウ ・ブルドーザー・ローラーの3種類のみ識別可能</p>
<div class="sub">
<a href= "https://kcsj.komatsu/products/construction_machine/img/excavator_02_im01.jpg" >バックホウ画像</a>
<a href= "https://kcsj.komatsu/products/construction_machine/img/bulldozer_02_im15.jpg" >ブルドーザー画像</a>
<a href= "https://www.sakainet.co.jp/products/assets_c/2017/12/tz704-thumb-558x380-1284.png" >ローラー画像</a>
</div>
<p>必要があれば上のリンクから画像をダウンロードして送信してください</p>
<form method="POST" enctype="multipart/form-data">
<input class="file_choose" type="file" name="file">
<input class="btn" value="submit!" type="submit">
</form>
<div class="answer">{{answer}}</div>
</div>
<footer>
<small>© 2021 Osaka_taro.</small>
</footer>
</body>
</html>
CSSのコード
header {
background-color: #5d74c0;
height: 60px;
margin: -8px;
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
}
.header-logo {
color: rgb(255, 252, 75);
font-size: 25px;
margin: 15px 25px;
}
.header_img {
height: 25px;
margin: 15px 25px;
}
.main {
height: 480px;
}
h2 {
color: #444444;
margin: 90px 0px 0px 0px;
text-align: center;
}
p {
color: #444444;
margin: 10px 0px 30px 0px;
text-align: center;
}
.sub {
text-align: center;
}
p {
color: #444444;
margin: 60px 0px 30px 0px;
text-align: center;
}
.answer {
color: #000000;
font-size: 32px;
margin: 30px 0px 30px 0px;
text-align: center;
}
form {
text-align: center;
}
footer {
background-color: #c4c1bf;
height: 40px;
margin: -8px;
position: relative;
}
.footer_img {
height: 25px;
margin: 15px 25px;
}
small {
margin: 15px 25px;
position: absolute;
left: 0;
bottom: 0;
}
フォルダの作成等
ターミナル操作手順
$ cd my-project/ #カレントディレクトリにあるファイルに移動する
$ python 〇〇.py
参照したサイト
**4.公開(Herokuへデプロイ)**
Herokuに登録する
Heroku操作手順
ターミナル操作手順
$ heroku login
$ cd my-project/ #カレントディレクトリにあるファイルに移動する
$ git init #初回のみ
$ git add .
$ git commit -am "make it better"
$ git push heroku master
受講後の感想
6ヶ月間受講してPythonの基礎、簡単なアプリの作成について学ぶことができた。
独学でもできないことはないレベルではあると思うが、わからないことがあれば、すぐにSlack等で質問でき、何度でも丁寧に答えてくれるので挫折せずに修了することができた。
また給付金の支給条件としてある、すべての課題を提出しなければならないということも修了の支えとなった。
3ヶ月プランと6ヶ月プランの違いは、受講日数とメンタリングできる回数であり、内容は変わらないので3ヶ月プランにしておけば良かったなと思った。その理由は、内容的には3ヶ月もあれば十分だったこと、Slackでは無限に質問が可能でレスポンスが速いこと、メンタリングは事前予約が必要だったこと等がある。実際、メンタリングは10回も使わなかった。
受講料が高いか安いかは使い方次第だと思う。サービスを使い倒せれば安い。与えられた課題のみをクリアしているだけでは高いというのが私の感想である。受講期間内にコースが修了すれば他のコースの受講が可能であることからもそういえるのではないだろうか。
余談ではあるが、私は一つのコースを早く終わらせて他のコースを受講するために6ヶ月コースに申し込んだが、期間が長いことで気が緩み1コース修了したのが受講修了の1週間前であった。このレベルでは転職して通用するほどのスキルは身についていない。ただ自分の日々の業務を改善するための基礎の力は身についたと思う。
おわりに
少しの出費はあったが、Aidemyで学ぶことができて良かった。
メンターの方は、質問に対して的確に答えてくれた。
こちらが理解できるかどうかは素養もあるので、別だが何回でもわかるまで教えてくれた。
今回学んだことを自分の日々の業務に活かして行きたい。
基礎ができたので、あとは実践で習得していこうと思う。
注:コードやその説明について間違っている可能性がありますので、専門家や他のサイトでの確認をお願いいたします。Aidemyのサービス、教育訓練給付金については最新の情報を確認してください。このサイトの内容については、いかなる保証をするものではなく、一切の責任を負いません。