現場工具の識別

1.初めに

建築や土木の現場で使用する工具はとてもバリエーションが多く、特に従事したての方は、上司に「〇〇もってこい!」と言われてもなんのこっちゃ状態になります。

そこで画像認識の力を借りて、「〇〇持ってきました!」と自信をもって道具を渡して上司に褒められるように、工具の識別webアプリを作成してみました。
以下がURLになります。

https://mnist-practice.onrender.com/


2.モデル構築

工具の判別モデルの作成は以下の流れで行いました。
データの収集→データの前処理→モデルの構成→CNNを用いて学習→モデルの評価

2-1.実行環境

〇環境・使用サービス
・google colab(モデル学習をする環境)
・Visual Studio Code(WEBアプリ開発エディタ)
・render(WEBアプリ実行環境)

〇pythonライブラリ
python==3.9.16
tensorflow==2.10.0
numpy==1.22.4
openCV==4.7.0
flask==2.0.1

2-2.データの収集

工具の画像データの収集には、「icrawler」を使用しました。
icrawlerとはwebクローラーのフレームワークで、集めたい画像名と枚数を指定するだけで各種検索エンジンを使用して簡単に画像データを集めることが出来ます。
実行環境はgoogle colabで行いました。

!pip install icrawler

from icrawler.builtin import BingImageCrawler
from google.colab import drive

#検索ワード
search_words = ["ラチェット", "モンキーレンチ", "インパクトドライバー", "ソケットレンチ", "メガネレンチ", "ボックスレンチ", "ラチェットドライバー", "ラジオペンチ"]

#収集した画像の保存
drive.mount('/content/drive/')

for search_word in search_words:

    exp_dir = 'Colab Notebooks/aidemy/datasetsub/'
    path = '/content/drive/My Drive/' + exp_dir + search_word

    crawler = BingImageCrawler(storage = {'root_dir' : path})
    crawler.crawl(keyword = search_word, max_num = 300)

2-3.データの前処理

画像データを学習させる前に、データのサイズ変更、ラベリング、データセットの分割を行いました。以下コードです。

import cv2
from google.colab.patches import cv2_imshow
import matplotlib.pyplot as plt
from google.colab import drive
import numpy as np
import glob

#googledriveのマウント
drive.mount('/content/drive/')

search_words = ["ラチェット", "モンキーレンチ", "インパクトドライバー", "ソケットレンチ", "メガネレンチ", "ボックスレンチ", "ラチェットドライバー", "ラジオペンチ"]

dataset = []
classes = search_words
num_classes = len(classes)
img_size = 50
num_testdata = 25

X_train = []
X_test  = []
y_train = []
y_test  = []
#openCVでの読み込み
for index, search_word in enumerate(search_words):
    #print(search_word)
    exp_dir = 'Colab Notebooks/aidemy/dataset/'
    files = glob.glob('/content/drive/My Drive/' + exp_dir + search_word + '/*jpg')
    #print(files)
    for img_count, file in enumerate(files):
        img = cv2.imread(file, cv2.IMREAD_UNCHANGED)

        #openCVで読み込んだデータを加工して配列に格納する
        my_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        #my_img = cv2.cvtColor(my_img, cv2.COLOR_RGB2GRAY)
        my_img = cv2.resize(my_img, (img_size, img_size))

        data = np.asarray(my_img)
        #print(data)
        if img_count < num_testdata:
            X_test.append(data)
            y_test.append(index)
        else:
            X_train.append(data)
            y_train.append(index)
    
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)

2-4.モデル構成

データの準備後、モデルの構成に入ります。
画像認識をするには、CNNという畳み込み層を使用して特徴抽出を行うニューラルネットワークを用いるとより高い性能が発揮できるとのことなので、これを使用してモデルを構成しました。以下コードです。

from keras.datasets import mnist
from keras.layers import Dense, Dropout, Flatten, Activation
from keras.layers import Conv2D, MaxPooling2D
from keras.models import Sequential, load_model
from keras.utils.np_utils import to_categorical
from keras.utils.vis_utils import plot_model
import numpy as np
import matplotlib.pyplot as plt

#モデルの保存
import os
from google.colab import files

# データの準備

#データの用意。Convレイヤー用に4次元配列にする
X_train = X_train.reshape(-1, 50, 50, 3)
X_test = X_test.reshape(-1, 50, 50, 3)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# モデルの定義
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(3, 3),input_shape=(50,50,3)))
model.add(Activation('relu'))
model.add(Conv2D(filters=64, kernel_size=(3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(8))
model.add(Activation('softmax'))


model.compile(loss='categorical_crossentropy',
              optimizer='adadelta',
              metrics=['accuracy'])

model.fit(X_train, y_train,
          batch_size=128,
          epochs=50,
          verbose=1,
          validation_data=(X_test, y_test))

# 精度の評価
scores = model.evaluate(X_test, y_test, verbose=1)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])

# データの可視化(検証データの先頭の10枚)
for i in range(10):
    plt.subplot(2, 5, i+1)
    plt.imshow(X_test[i].reshape((50,50,3)))
plt.suptitle("10 images of test data",fontsize=20)
plt.show()

# 予測(検証データの先頭の10枚)
pred = np.argmax(model.predict(X_test[0:10]), axis=1)
print(pred)

model.summary()

#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' ) 

2-5.モデルの評価

上記コードを実行した結果の抜粋を添付します。


Epoch 50/50 11/11 [==============================] - 0s 29ms/step - loss: 2.5182 - accuracy: 0.1419 - val_loss: 2.0804 - val_accuracy: 0.1250 
7/7 [==============================] - 0s 5ms/step - loss: 2.0804 - accuracy: 0.1250 
Test loss: 2.080420732498169 
Test accuracy: 0.125

accracy(テストデータを使用した正答率)が12.5%しかでていません…
50%にはなっていないため、学習が出来ていないわけではないとは考えられますが、データが足りないのでしょうか。


3.転移学習を活用

データの数が足りないと仮定して、今度は転移学習を使用して再度モデルの構築を行いました。
転移学習とは、すでに作成された画像認識モデルを使用して、別のデータの学習に適用させる技術です。
利点としては、大量のデータを使用して構築されたモデルを転用することで、データ不足を補えることです。
早速使用してみましょう。以下コードです。

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

#モデルの保存
import os
from google.colab import files

#データの用意。Convレイヤー用に4次元配列にする
X_train = X_train.reshape(-1, 50, 50, 3)
X_test = X_test.reshape(-1, 50, 50, 3)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# vgg16のインスタンスの生成

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

top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dense(8, activation='softmax'))

# モデルの連結
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

# vgg16の重みの固定
for layer in model.layers[:19]:
    layer.trainable = False

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

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

# 予測(検証データの先頭の10枚)
pred = np.argmax(model.predict(X_test[0:10]), axis=1)
print(pred)

model.summary()

#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' ) 

上記コードを実行した結果の抜粋を添付します。

14/14 [==============================] - 0s 32ms/step - loss: 0.7480 - accuracy: 0.8171
7/7 [==============================] - 1s 67ms/step - loss: 2.7836 - accuracy: 0.6250
Test loss: 2.7835853099823
Test accuracy: 0.625

正答率62.5%まで上がりました!

まとめ

現場では、他業界よりアナログな手法で仕事が進められてると感じます。
このような技術を取り入れることによって、少しでも現場が働きやすい環境になることを目指していきたいです。
全ての現場に幸あれ

この記事が気に入ったらサポートをしてみませんか?