2020年11月30日

UiPath AI FabricとAction Centerでの
モデルファインチューニング

2020年11月30日

UiPath AI FabricとAction Centerでの
モデルファインチューニング

0:事前準備

1:AI FabricとAction Centerの連携概要

Action Centerの機能をAI Fabricと連携させることで

  • AIの結果の人間による確認
  • 学習データの作成

をUiPathプラットフォーム内で完結させることができます。

AI-Fabric

ラベル付けされていない元データをAction Centerを利用してバリデーションし、MLモデルの精度向上に利用できます。

AI-Action-Center

2:サンプルケース

実際のMLモデルの作成、Action Centerを使ったトレーニングデータセットの作成、MLモデルのトレーニング、トレーニング後の分類と分類信頼度による人間のチェックまでをサンプルユースケースを通してやってみましょう。

今回は「コンクリートの画像にひび割れがあるか確認する画像分類モデル」を作成してみます。

2-1: Action Centerによるトレーニングデータセットの作成

Action Centerを使うことでだれでも容易にデータの分類からトレーニング用のデータの作成、ラベル付けを行うことができます。

Model

2-2: 信頼度閾値によるAction Centerでの人間チェック工程

2-1で作成したMLモデルを実際に利用した際に信頼度が低いものだけAction Cnterでの人間チェック工程に回すことができます。

Action-Center-Integration

3:Datasetの作成

それでは実際にコンクリート画像にひび割れがあるか無いかを分類するML PackageをするためにまずはDatasetを作成します。

3-1: 画像データを用意

Mendeley Dataのこちらのデータを利用します。正常なものとひび割れのあるコンクリート画像がそれぞれ20000枚用意されています。

利用する元画像データ:https://data.mendeley.com/datasets/5y9wdsg2zt/2

2018 – Özgenel, Ç.F., Gönenç Sorguç, A. “Performance Comparison of Pretrained Convolutional Neural Networks on Crack Detection in Buildings”, ISARC 2018, Berlin.Lei Zhang , Fan Yang , Yimin Daniel Zhang, and Y. J. Z., Zhang, L., Yang, F., Zhang, Y. D., & Zhu, Y. J. (2016). Road Crack Detection Using Deep Convolutional Neural Network. In 2016 IEEE International Conference on Image Processing (ICIP). https://doi.org/10.1109/ICIP.2016.7533052

3-2: Action Centerでデータセットを作成するUiPathロボットワークフロー

こちらの赤枠部分になります。

このセクション3で最終的に以下のようなデータセットが作成でき、AI FabricのDatasetとしてアップロードします。

DataSet--
    |--crack
      |--画像
    |--normal
      |--画像
  • 事前にオーケストレーターにStorage Bucketを作成します。

    今回は「ImageBucket」という名称で登録します。

  • このサンプルワークフローをダウンロードしてUiPath Studioで開いてください。

    AI-Fabric_Action-Center_Integration.zip

  • ワークフローを実行すると“TargetImages”のフォルダーにある6枚の画像を人間が分類するためにAction CenterにそれぞれのTaskが作成されます。

  • それぞれのタスクを開くとFormに対象画像と「正常」「破損」のボタンが表示されますので、画像に対して分類してください。

  • すべてのTaskを完了させてください。

  • タスク完了まで待機しているロボット処理を「再開」させます。

  • ”DataSet”フォルダー配下の”crack”または”normal”に各画像が分類されます。※事前に200枚づつ分類してあります。作成するモデルの精度を上げる場合データセットを利用してトレーニング用画像の枚数を増やしてください。

3-3: DatasetをAI Fabricにアップロード

  • 新規Dataset “concrete images”を作成

  • Upload folderを選択

  • 3-2で作成した「AIFabric_Action Center_Integration\DataSet」のフォルダーを選択し「Upload」

これでトレーニング用のデータセット準備は完了です。

4:ML Packageの作成

次にML Packageを作成します。

4-1: 初期モデルの準備

トレーニングする前の初期のモデルを準備します。今回はImageNet データセットで学習させたResNet50をKeras Applicationから利用します。

# train.py
from keras.applications.resnet50 import ResNet50
ResNet = ResNet50(include_top=False, weights='imagenet', input_tensor=input_tensor)

https://keras.io/api/applications/resnet/#resnet50-function

 

4-2: train.pyの作成

  • セクション5以降でFull Pipelineを利用するため、process_data(), evaluate(), train()のFunctionを作成します。

各Functionの用途とFull pipelineを実行した際に実行される順序は以下の通りです。

# Function 用途
1 process_data() データセットをTraining用、evaluation用に分ける
2 evaluate() 1回目のevaluationの実行
3 train() Training実行
4 evaluate() 2回目のevaluationの実行
# train.py

class Main(object):
  def __init__(self):
    self._run_config = RunConfig() #環境変数の設定

  def train(self, directory):
    # directoryは環境変数の"training_data_directory"に設定された値
    # evaluationの実行

  def evaluate(self, directory):
    # directoryは環境変数の"evaluation_data_directory"に設定された値
    # evaluationの実行

  def process_data(self, directory):
    # directoryは元のデータセットPath
    # データをTrain用とEvaluation用に分割
  • 各Functionの引数は以下の通りです。
Function Directory引数 Default
process_data(self, directory) DatasetのBase Directory /data/dataset
evaluate(self, directory) 環境変数の"evaluation_data_directory"に設定された値 /data/dataset/test
train(self, directory): 環境変数の"training_data_directory"に設定された値 /data/dataset/training
  • ResNet50のBaseモデルに対して画像データをトレーニングするサンプルです。
# train.py

import glob
import os
import shutil
import random
from functools import partial
import splitfolders

from keras.applications.resnet50 import ResNet50
from tensorflow.python.keras.models import Sequential, Model, load_model
from tensorflow.python.keras.layers import Input, Flatten, Dense
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array
from keras import optimizers

from aiflib.utils import RunConfig, Logger
from aiflib.data_loader import DataLoader


def _get_base_model(CLASSES, IMAGE_RESIZE):
    img_width, img_height = IMAGE_RESIZE, IMAGE_RESIZE
    input_tensor = Input(shape=(img_width, img_height, 3))
    ResNet = ResNet50(include_top=False, weights='imagenet',input_tensor=input_tensor)

    top_model = Sequential()
    top_model.add(Flatten(input_shape=ResNet.output_shape[1:]))
    top_model.add(Dense(len(CLASSES), activation='softmax'))
    model = Model(ResNet.input, top_model(ResNet.output))

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

class Main(object):
    def __init__(self):
        self._run_config = RunConfig()
        self.logger = Logger(__name__)
        self.model_path = './model/resnet50.h5'

        self.CLASSES = ['crack', 'normal']
        self.IMAGE_RESIZE = 224

    def train(self, directory):
        train_data_dir = directory

        loader = DataLoader(train_data_dir)
        contents = loader.get_path_contents()
        self.logger.info(f'The contents of the directory are {contents}')

        train_samples = glob.glob(train_data_dir + '/*/*.jpg')

        img_width, img_height = self.IMAGE_RESIZE, self.IMAGE_RESIZE

        train_datagen = ImageDataGenerator(
            rescale=1.0 / 255,
            zoom_range=0.2,
            horizontal_flip=True)

        train_generator = train_datagen.flow_from_directory(
            train_data_dir,
            target_size=(img_width, img_height),
            color_mode='rgb',
            classes=self.CLASSES,
            class_mode='categorical',
            batch_size=10)

        cb_early_stopper = EarlyStopping(
            monitor="val_loss",
            min_delta=0,
            patience=0,
            verbose=0,
            mode="auto")
        cb_checkpointer = ModelCheckpoint(
            filepath = '../tm/best.hdf5',
            monitor = 'val_loss',
            save_best_only = True,
            mode = 'auto',
            period=1)

        model = _get_base_model(self.CLASSES, self.IMAGE_RESIZE)
        history = model.fit(
            train_generator,
            steps_per_epoch= 20,
            epochs=1,
            callbacks=[cb_checkpointer, cb_early_stopper]
            )
        self.model = model


    def evaluate(self, directory):
        if os.path.isfile(self.model_path):
            model = load_model(self.model_path)
        else:
            model = _get_base_model(self.CLASSES, self.IMAGE_RESIZE)

        loader = DataLoader(directory)
        contents = loader.get_path_contents()
        self.logger.info(f'The contents of the directory are {contents}')

        validation_data_dir = directory
        val_samples = glob.glob(validation_data_dir + '/*/*.jpg')

        img_width, img_height = self.IMAGE_RESIZE, self.IMAGE_RESIZE

        validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
        validation_generator = validation_datagen.flow_from_directory(
            validation_data_dir,
            target_size=(img_width, img_height),
            color_mode='rgb',
            classes=self.CLASSES,
            class_mode='categorical',
            batch_size=10)

        result= model.evaluate_generator(validation_generator)
        self.logger.info(f'Loss:{result[0]} / Accuracy:{result[1]}')

    def save(self):
        self.model.save(self.model_path)

    def process_data(self, directory):
        loader = DataLoader(directory)
        contents = loader.get_path_contents()
        self.logger.info(f'The contents of the directory are {contents}')

        splitfolders.ratio(os.path.join(directory, "DataSet"), output=os.path.join(directory, "output"), ratio=(.8, .2), group_prefix=None)
        os.rename(os.path.join(directory, "output/train/"), os.path.join(directory, "training"))
        os.rename(os.path.join(directory, "output/val/"), os.path.join(directory, "test"))
        shutil.rmtree(os.path.join(directory, "DataSet"))

4-3: main.pyの作成

ML SkillとしてUiPathロボットから実行するためにmain.pyにpredict()を作成します。手順 「7:ML Skillの実行」の際に呼び出されます。

import json
import glob
import io
from PIL import Image

import numpy as np
import keras
from keras.preprocessing.image import img_to_array, load_img


class Main(object):
  def __init__(self):
      self.model = keras.models.load_model('./model/resnet50Best.h5') #事前に十分な画像データ枚数でトレーニング済のモデルになります。

  def predict(self, file_bytes):
      classes = ['crack', 'normal']
      img = Image.open(io.BytesIO(file_bytes))
      rgb_im = img.convert('RGB')
      x = rgb_im.resize((224,224), Image.NEAREST)
      x = img_to_array(x)/255
      x = x[None,...]
      ratings = self.model.predict(x)[0]
      top_ratings_indices = ratings.argsort()[-1:][::-1]

      result = {}
      for r in top_ratings_indices:
          result['class'] = classes[r]
          result['score'] = str(round(ratings[r], 9))

      return json.dumps((result))

4-4: zipの作成とML Packagesへのアップロード

  • ML PackageとしてAI Fabricにアップロードできる形式にします。

    Concrete_Crack_Classification.zip

  • 「ML Packages」→「Upload zip file」

  • Create new Packageで、「Concrete_Crack_Classification.zip」をアップロード、Input typeは「file」、「Python37」を選択し、「Enable Training」を「オン」にします。

  • 「Undeployed」のステータスでML Packageが作成されます。

5:Pipelineの実行

続いてPipelineを実行します。Full pipelineを選択するとTraining(及びモデルのSave)とEvaluationが実行されます。

「Full pipeline run」を選択、手順4で作成したML Packageを選択、「major version = 1」,「 minor version = 0」,そして、Datasetに手順3で作成した「Dataset」を選択します。

 

  • Pipelineの実行が「Packaging」から「Queued」ステータスでスケジュールされ、

  • 15分程度で完了します。

  • Pipelineの詳細ログは各Pipelineの「Details」からダウンロードできます。

6:ML SkillのDeploy

  • ML PackageをPipeline実行しトレーニングが完了したらML SkillとしてDeployし、UiPathロボットから利用できるようにします。
    ML Skillsで”Create new”をクリックし、以下の画面で”Skill_Concrete_Crack_Classification”の名前で、先程学習したパッケージ”Concrete_Crack_Classification”のバージョン”1.1”でML Skillsを作成します。

  • Deployが始まります。

  • 「Available」になりUiPathロボットから利用できるようになります。

7:ML Skillの実行

UiPathロボットからML Skillを実行し、いくつかの画像ファイルを実際に分類してみます。その際、モデルからの分類結果の信頼度が低いものについてはAction Centerを利用し人間が確認するフローにしてみます。

7-1: MLスキルアクティビティ

MLスキルアクティビティを使い、手順6でDeployしたML Skillを選択します。今回はInputの項目にはFileパスを入れてください。

7-2: Action Centerにタスクを作成

  • ML Skillの信頼度スコアが例えば95%以下ならばAction Centerにタスクを作成し、人間のチェックに回します。

  • サンプルのワークフローになりますので、手順3-2と同じように実行してください。

    AI-Fabric_Action-Center_Verify.zip

事前にOrchestratorのStorage Bucketに「ImageBucket」という名称でStorage Bucketを作成します。このストレージに画像ファイルが格納されます。

そしてML スキルアクティビティで手順6で作成したMLスキル(Skill_Concrete_Crack_Classification)を選定します。

ワークフローを実行するとMLスキルの出力のスコア(確度)が一定以下の画像ファイル(今回は95%を閾値にしています)については人間の確認工程に回すためにタスクが作成されます。

割り当てられたタスクについては正しい結果にAction Centerで振り分け、再度学習データに回すことができます。

Action Centerでの確認が終わった画像データはResultフォルダから正しいラベルでDataSetフォルダー配下に振り分けられ、再学習用データとして活用できます。

以上です。今回ご紹介した画像分類以外でも様々なユースケースでの利用が考えられます。みなさまもぜひAI FabricとAction Centerを使ってRPA×AIによる業務自動化を行ってみてください。


by Kaoru Oshita

TOPICS: AI Fabric, UiPath Action Center

Show sidebar