Deep LearningのなかでもTransfer Learning(転移学習)を用いたオリジナル画像認識AIを、アプリケーションに組み込むためのAPI開発と実装方法を解説します。
MicrosoftのMicrosoft Cognitive Toolkit (CNTK)を使い、ソリューションを組み立てましょう。
Deep Learningの世界では理論と実装に大きな隔たりがありますが、丁寧に仕組みを追っていけばデータサイエンティストでなくてもAIの技術は使うことが出来ます。本セッションを通して、システムに人口知能APIを実装できるようになりましょう。
このチュートリアルではPythonでモデルをトレーニングし、C#でWebにそれをデプロイしていきます。
26. 初期設定
26
try_set_default_device(gpu(0))
デバイス設定部分
✓ CPUを利用するかGPUを利用するかを決められます。CPUの場合は cpu()とします。
✓ ただし、このコードには現状GPUのみに対応しているコードが含まれているため、GPUでないと実行できません。
if not (os.path.exists(_base_model_file) and os.path.exists(_train_map_file) and os.path.exists(_test_map_file)):
print("Please run 'python install_data_and_model.py' first to get the required data and model.")
exit(0)
ベースのモデルの有無を確認
✓ モデルとデータの有無を確認します。
✓ ファイルが存在しない場合はユーザーに python install_data_and_model.py を実行するように促します。
✓ install_data_and_model.py を実行すると花などのサンプル写真がダウンロードされ、また今回のモデルのベースにな
るResNet18のモデルがダウンロードされます。
54. TransferLearning.py をもっと便利に使う
マップファイルを作成します
55
def create_map_file_from_folder(root_folder, class_mapping, include_unknown=False):
map_file_name = os.path.join(root_folder, "map.txt")
lines = []
for class_id in range(0, len(class_mapping)):
folder = os.path.join(root_folder, class_mapping[class_id])
if os.path.exists(folder):
for entry in os.listdir(folder):
filename = os.path.join(folder, entry)
if os.path.isfile(filename) and os.path.splitext(filename)[1] in file_endings:
lines.append("{0}¥t{1}¥n".format(filename, class_id))
if include_unknown:
for entry in os.listdir(root_folder):
filename = os.path.join(root_folder, entry)
if os.path.isfile(filename) and os.path.splitext(filename)[1] in file_endings:
lines.append("{0}¥t-1¥n".format(filename))
lines.sort()
with open(map_file_name , 'w') as map_file:
for line in lines:
map_file.write(line)
return map_file_name
マップファイルをフォルダ名・ファイルパスから作成する。
マップファイルをフォルダ名・ファイルパスから作成します
61. TransferLearning.model をデプロイ
モデルをロードし、インプット/アウトプット値を抽出
65
DeviceDescriptor device = DeviceDescriptor.CPUDevice;
Function modelFunc = Function.Load(modelFilePath, device);
// Get input variable. The model has only one single input.
// The same way described above for output variable can be used here to get input variable by name.
Variable inputVar = modelFunc.Arguments.Single();
// Get shape data for the input variable
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
int imageChannels = inputShape[2];
int imageSize = inputShape.TotalSize;
// The model has only one output.
// If the model have more than one output, use the following way to get output variable by name.
// Variable outputVar = modelFunc.Outputs.Where(variable => string.Equals(variable.Name, outputName)).Single();
Variable outputVar = modelFunc.Output;
var inputDataMap = new Dictionary<Variable, Value>();
var outputDataMap = new Dictionary<Variable, Value>();
実行部分
✓デバイスをGPUかCPUか指定します。
✓Function.load()でモデルを抽出し、配列からモデルが持つインプット値、アウトプット値を取り出します。
62. TransferLearning.model をデプロイ
画像を抽出し、モデルが求めるインプットサイズに変換
66
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
// Transform the image
System.Net.Http.HttpClient httpClient = new HttpClient();
Stream imageStream = await httpClient.GetStreamAsync(imageUrl);
Bitmap bmp = new Bitmap(Bitmap.FromStream(imageStream));
var resized = bmp.Resize((int)imageWidth, (int)imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
画像抽出とリサイズ
✓URLのイメージをリサイズします。
✓今回求められているインプットは 3(RGB) x 224(width) x 224(height)です。
✓リサイズしたら、それぞれのパラメータを浮動小数点のリストとして変数に代入します。
✓今回の分類をするうえでは、画像が横に伸びていても大きな問題はありません。
64. TransferLearning.model をデプロイ
画像を抽出し、モデルが求めるインプットサイズに変換
68
// Create input data map
var inputVal = Value.CreateBatch(inputVar.Shape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Create ouput data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
outputDataMap.Add(outputVar, null);
インプット/アウトプットデータマップを定義
✓インプットの値を指定します。今回作成したResNetベースのTransferLearningの分類モデルで要求されるインプットは1つなので
CreateBatch()は1回行い、inputDataMapの配列も1つのインプット値セットで大丈夫です。
✓例として、GitHubのCNTK公式リポジトリにあるFast R-CNNのサンプルのように2個のインプットが必要な際には、インプットの値は以下
の様にする必要があります。
Variable inputVar_1 = modelFunc.Arguments.First();
Variable inputVar_2 = modelFunc.Arguments.Last();
var inputVal_1 = Value.CreateBatch(inputVar_1.Shape, resizedCHW, device);
inputDataMap.Add(inputVar_1, inputVal_1);
var inputVal_2 = Value.CreateBatch(inputVar_2.Shape, your_data, device);
inputDataMap.Add(inputVar_2, inputVal_2);
例:インプットが2つある場合
65. TransferLearning.model をデプロイ
画像を抽出し、モデルが求めるインプットサイズに変換
69
// Start evaluation on the device
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
string json = JsonConvert.SerializeObject(outputData);
return json;
評価
✓最後にEvaluate()で関数を評価し、json変換をして値を返します。
デプロイ
このプログラムをデプロイし、
http://localhost:3469/api/values
{“url”:”http://hogehoge.com/hoge.jpg”}
のjsonをPOSTで渡すと配列がレスポンスとして返ってきます。