（２）30代後半で”WEB App”を作る（作成の全体的な流れ）

Aidemyの「WEBアプリ開発コース」で学んだことをまとめます。

こちらの記事では、
「作成までの大まかな流れ」を説明します。

何かの参考に使って頂ければ幸いです。


次回の記事で

「習った理論のまとめ」と
「自分が作ったアプリ」の振り返りをします。


———————————————————————————
<h2>＜Aidemyで学ぶ段階の感想と要約＞</h2>



すごい大雑把にですが、このアプリを作成するまでの3ヶ月についての
感想と流れを書いておきます。


Aidemyの学習は、完全にオンラインで、
分からない時には「チャット」か「WEB通話」で相談ができます。

（WEB通話での相談は、時間と回数制限があります。）



仕事をしながらどこまで学習時間が捻出できるか、
若干の不安はありましたが
早朝の仕事に行く前に勉強する習慣ができたのでとてもよかったです。


各学習単元の要点がまとまっていて、
おおよそWEBアプリを作る工程の最初から最後まで実際に手を動かして行うので、
ちゃんと「動いた瞬間」には結構感動があります！！


カリキュラムもかなり細かくステップバイステップで進むので、
ものすごく「行き詰まった」と言うことは自分はなかったです。



とはいえ、

自分は歩みが遅いので１つの「WEBアプリ」を作成するまでに3ヶ月かかりましたが、
他の受講生の方のブログなどを見ていると若い方は1ヶ月とかで作成しているのも
ちょくちょく見かけます。



^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
個人的な感覚ですが、

週に5日：1日　１時間から２時間の学習　＞アプリ作るまで3ヶ月

週に3日以上：1日　８時間以上　学習可能　＞アプリ作るまで1ヶ月

でいけると思います。

学習し放題なので、ガンガン学習できる人の方が有利ですね。
チャットで都度質問もできるので。

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


実際に自分でも”四苦八苦”しながらアプリを作るわけですが、
他の方の完成したWEBアプリを見ても「マジ天才か！？」と思うものも多いです。。



さらにその「学習が早いすごい若い方」に教える先生や、
実社会の現場でエンジニアの方達によって自分たちは「IT」を使ってるんやなあ
としみじみ感じます。




ものすごい世界ですね。

コマンド１つ間違うとシステムが動かなくなるモノの
集合体ですからね。。。。

感謝です。



何はともあれ、

ある程度「若くなくても」3ヶ月でWEBアプリを作れる
と言うのが結論です！！！


———————————————————————————
【自分が今回作ったアプリ　３つ】
――――――――――――――――
１：＜ボタン電池の識別アプリ＞
https://masa2021-battery-testapp.herokuapp.com
――――――――――――――――
２：＜龍涎香（りゅうぜんこう）識別アプリ＞
https://masa2021-stone-testapp.herokuapp.com
――――――――――――――――
３：＜ヒアリの識別アプリ＞
https://masa2021-ants-testapp.herokuapp.com
――――――――――――――――

アプリそれぞれの作ってみた感想は
次の記事（３）で取り上げます。


———————————————————————————
<h2>＜WEBアプリを作る段階について＞</h2>


大まかには、

１：どんな「画像識別のWEBアプリ」を作るか決める

２：実際に作れそうなテーマに絞る

３：画像を集める

４：画像の下処理をする

５：「ディープラーニングのモデル」（アプリの中身）を作る

６：WEBアプリの「外側」を作る（HTML＋CSS）

７：デプロイする（WEB上に公開する）

８：完成


という流れです。



———————————————————————————
<h4>１：どんな「画像識別のWEBアプリ」を作るか決める</h4>

AidemyではCNNという画像識別の手法を学ぶので、
どんな「識別アプリ」を作るか決めます。

顔や表情の識別
動物など生き物の識別
車など工業製品の識別
ラーメンなど料理の識別

などなど

正直「２項対立」で識別したいだけなら
そんなにアイデアを出すのに難しくは無いと思うのですが、

自分なりに「こういう使い方したら実生活でも役に立つかもなー」
と考えるのに時間がかかりました。

「画像の識別」と言っても世の中には思いも寄らない
応用方法があるのだと思います。

———————————————————————————
<h4>２：実際に作れそうなテーマに絞る</h4>

（上記の１に含まれる項目でもあるのですが）

自分の実力で作れるのはどこまでか
自分が集められる素材はどんなものか
500枚から1000枚の「画像数」が集まるのかを考える。

今回は画像ですが、
画像認識以外の場面でもデータを集める場面はあると思います。

テキスト、音声、機械の状態とか、生体的な状態とか、
効率的にオリジナルデータを集める方法は何か？と言うことですね。


今回の場合、

先生から聞いた話では、
１つの項目につき「画像を1000枚くらい」

あと

「水増し」（集めた画像を左右反転とかして増やす方法）は
あくまでも「おまけ」で行うものくらいに思っておいてください。

とのことでした。

まあ、水増しに頼りすぎると「オリジナルデータ」の精度が
どんどん下がっていきますからね。

———————————————————————————
<h4>３：画像を集める</h4>

著作権とかってどうなってるのだろうと
思ってましたが先生がこれ　↓　を教えてくれました。

https://storialaw.jp/blog/4936


検証用のアプリであれば問題ない様子です。

自分的には結構気になったポイントでした。

———————————————————————————
<h4>４：画像の下処理をする</h4>


大きさと形を揃えます。

今回の場合は「正方形」ですね。

画像サイズは「どの程度」が良いという基準があるのかを

先生に聞いたところ、
「ケースバイケース」なので一概に言えない
とのことでした。

自分の試した範囲では、
小さい（128×128）よりは大きめ（224×224）の方が、
精度はガンッと上がりました。

ただ、

モデルを作るまでの所用時間もガンッと上がりました。。。。
このあたりは当然トレードオフですね。

———————————————————————————
<h4>５：「ディープラーニングのモデル」（アプリの中身）を作る</h4>

これ　↓　で作ります。

https://note.com/mc_kurita/n/n2a7c8682d965


自分がどうやって「画像を読み込んだらええんや！！」と
結構困ったので　↓  参考資料もつけておきます。

大まかには

１：画像をグーグルドライブにアップロード

２：Colab　に画像を接続（マウント）する

３：Colab で　ディープラーニング用のPythonコードを走らせる

４：「学習モデル」のファイルを取り出して、それをアプリに組み込む

です。

https://kenko-keep.com/google-colab-mount/

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

【今回学習に使ったコード】

```python

import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Dense, Dropout, Flatten, Input
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras import optimizers

# ファイルパス

path_SideA = os.listdir('ファイルパス')
path_SideB = os.listdir('ファイルパス')

img_SideA = []
img_SideB = []

for i in range(len(path_SideA)):
    img = cv2.imread('ファイルパス' + path_SideA[i])
    img = cv2.resize(img, (224,224))
    img_SideA.append(img)

for i in range(len(path_SideB)):
    img = cv2.imread('ファイルパス' + path_SideB[i])
    img = cv2.resize(img, (224,224))
    img_SideB.append(img)
    
X = np.array(img_SideA + img_SideB)
y =  np.array([0]*len(img_SideA) + [1]*len(img_SideB))

rand_index = np.random.permutation(np.arange(len(X)))
X = X[rand_index]
y = y[rand_index]


# データの分割

X_train = X[:int(len(X)*0.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):]


y_train = to_categorical(y_train)
y_test = to_categorical(y_test)


# 転移学習・畳み込み

input_tensor = Input(shape=(224, 224 , 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

top_model = Sequential()
top_model.add(Flatten())
top_model.add(Dense(256, activation='relu'))
top_model.add(Dense(128, activation='relu'))
top_model.add(Dense(128, activation='sigmoid'))
top_model.add(Dropout(rate=0.5))
top_model.add(Dense(2, activation='softmax'))

model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

for layer in model.layers[:17]:
    layer.trainable = False

model.compile(optimizer = optimizers.SGD(lr=1e-4, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy'])

model.fit(X_train, y_train, batch_size=100, epochs=20)


# 画像を一枚受け取り、どちらかを判定する関数

def pred_gender(img):
    
   img = cv2.resize(img, (128, 128))
   pred = np.argmax(model.predict(np.array([img])))
 
   if pred == 0:
       return 'SideA'
   else:
       return 'SideB'


# 精度の評価

scores = model.evaluate(X_test, y_test, verbose=1)

print('Test loss:', scores[0])
print('Test accuracy:', scores[1])


#　resultsディレクトリを作成

result_dir = 'results'
if not os.path.exists(result_dir):
    os.mkdir(result_dir)


# 重みを保存

model.save(os.path.join(result_dir, 'model.h5'))
files.download( '/content/results/model.h5' ) 

```

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

こんな感じで結果が出ます。

結構時間がかかりますが、
マシン性能が上がるとこの学習速度が格段に上がるんだろうなー
としみじみ感じる部分です。

少しずつ少しずつ学習が進む様子を見つつ、待ちます。。

今回のモデルでは１つのモデルを作るのに５時間〜６時間学習させました。


```

Epoch 1/20
17/17 [==============================] - 880s 51s/step - loss: 1.0885 - accuracy: 0.5082
Epoch 2/20
17/17 [==============================] - 862s 51s/step - loss: 0.8431 - accuracy: 0.5294
Epoch 3/20
17/17 [==============================] - 860s 51s/step - loss: 0.7671 - accuracy: 0.5737
Epoch 4/20
17/17 [==============================] - 867s 51s/step - loss: 0.6882 - accuracy: 0.6097
Epoch 5/20
17/17 [==============================] - 858s 50s/step - loss: 0.5999 - accuracy: 0.6798
Epoch 6/20
17/17 [==============================] - 858s 50s/step - loss: 0.5732 - accuracy: 0.6996
Epoch 7/20
17/17 [==============================] - 856s 50s/step - loss: 0.5537 - accuracy: 0.7106
Epoch 8/20
17/17 [==============================] - 857s 50s/step - loss: 0.4767 - accuracy: 0.7751
Epoch 9/20
17/17 [==============================] - 858s 50s/step - loss: 0.4559 - accuracy: 0.7733
Epoch 10/20
17/17 [==============================] - 859s 50s/step - loss: 0.4153 - accuracy: 0.7906
Epoch 11/20
17/17 [==============================] - 861s 51s/step - loss: 0.3922 - accuracy: 0.8261
Epoch 12/20
17/17 [==============================] - 864s 51s/step - loss: 0.3624 - accuracy: 0.8511
Epoch 13/20
17/17 [==============================] - 862s 51s/step - loss: 0.3246 - accuracy: 0.8575
Epoch 14/20
17/17 [==============================] - 865s 51s/step - loss: 0.2971 - accuracy: 0.8914
Epoch 15/20
17/17 [==============================] - 861s 51s/step - loss: 0.2691 - accuracy: 0.9102
Epoch 16/20
17/17 [==============================] - 858s 50s/step - loss: 0.2635 - accuracy: 0.9004
Epoch 17/20
17/17 [==============================] - 862s 51s/step - loss: 0.2680 - accuracy: 0.9000
Epoch 18/20
17/17 [==============================] - 858s 50s/step - loss: 0.2450 - accuracy: 0.9209
Epoch 19/20
17/17 [==============================] - 858s 50s/step - loss: 0.2238 - accuracy: 0.9261
Epoch 20/20
17/17 [==============================] - 856s 50s/step - loss: 0.2013 - accuracy: 0.9457
14/14 [==============================] - 207s 15s/step - loss: 0.2138 - accuracy: 0.9496
Test loss: 0.2137904018163681
Test accuracy: 0.9496402740478516

```

———————————————————————————
<h4>６：WEBアプリの「外側」を作る（HTML＋CSS）</h4>

超簡単な作りなのでここは割愛します。

ホームページの外側をHTMLとCSSで作ります。

———————————————————————————
<h4>７：デプロイする（WEB上に公開する）</h4>

Flask（フラスク）という

Python上で動く「マイクロウェブアプリケーションフレームワーク」
を使ってWEB上に「小さなアプリ」を作ります。

アプリケーションフレームワークは、
自分の中では「全自動（車のオートマ）ロケット」みたいなイメージです。

個別設定を１から組み立てなくても、
事前に組まれている「もの（フラスク）」に乗せてWEBに上げるみたいな。


最終的に「Heroku」↓ に　WEBアプリを公開して完成です。 

https://ja.wikipedia.org/wiki/Heroku


「Heroku」はアプリケーションを実行する環境を提供してくれるサービスです。

小さなアプリを公開できる「無料枠」があり、
もっと使いたい方は有料プランへどうぞという感じのサービスですね。



^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

【アップロード用のコード】


```python

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
import cProfile

classes = ["「CR2016」","「CR1632」"]
num_classes = len(classes)
image_size = 224

UPLOAD_FOLDER = "uploads"
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])

app = Flask(__name__)

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

model = load_model('./model.h5')

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if 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)

            
            img = image.load_img(filepath, 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] + " です"

            return render_template("index.html",answer=pred_answer, images=filepath)

    return render_template("index.html",answer="")

if __name__ == "__main__":
    app.run()

```

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



———————————————————————————
<h4>８：完成</h4>


何回もテストして、動作確認しアップ完了で終了。

あー、終わったああ

って感じます。


———————————————————————————

今回の「WEBアプリ」作成の経緯は以上です。
（次回（３）では作ったアプリの紹介です。）

読んでもらい有り難うございました。mm

では、また！！