2018年3月9日金曜日

Kubernetesとは

 Kubernetesはオープンソースの「コンテナオーケストレーション」ツールです。公式サイトのトップページにおいてもそう明示されていますが、「コンテナオーケストレーション」には明確な定義がまだありません。そこで本連載では、コンテナオーケストレーションを「コンテナ型仮想化を本番環境で活用するために必要な機能を提供すること」と定義します。

 
5 Kubernetes公式サイトのトップページ

 実際Kubernetesには、コンテナ型仮想化を本番環境で活用する際の課題に対応するさまざまな機能があります。

 一方でコンテナオーケストレーションツールはKubernetesだけではなく、Docker社が開発した「SwarmKit」や、「Apache Mesos」、Rancher Labsの「Cattle」、既に開発は停止していますがCoreOSの「fleet」などの競合が存在します。では、なぜKubernetesに注目が集まっているのでしょうか。

 それには2つの大きな理由が存在します。1つはKubernetesの起源、もう1つは現時点でKubernetesを取り巻く現状です。

Kubernetesの起源

 Kubernetesの起源をたどる際には、Googleのエンジニアが執筆したサービス管理に関する有名な論文が参考になります。この論文では、「Googleのサービスは、クラスタマネジャー『Borg』上で動作するコンテナを用いて提供されており、Borgと同様の仕組み(+Borgにおける反省を踏まえた対応策)を備えたオープンソースソフトウェアとしてKubernetesを開発した」旨が記載されています。

 Googleのサービスを支えている基盤と同様の仕組みを備えていることから、「KubernetesGoogleで既にその有効性を実証済みである」という意味で大きな注目を浴びたといえるでしょう。

Kubernetesを取り巻く現状

 しかし事例があるのみでは、活用はなかなか広まりづらいものです。Kuberenetesを本格的に活用しようという機運が2017年から急速に高まっている理由は、主に次に挙げるようなものと思われます。

1.     パブリッククラウドによるKubernetesのマネージドサービス提供

2.     DockerKubernetesの統合

3.     CNCFCloud Native Computing Foundation)を中心としたベンダー中立な開発体制

・パブリッククラウドによるKubernetesのマネージドサービス提供

 20182月時点で、既に世界でのシェアが多いパブリッククラウドサービス(Amazon Web ServiceAWS)、Microsoft AzureGoogle Cloud Platformなど)が相次いでKubernetesのマネージドサービスをリリースしています(プレビューを含む)。これまでは「Kubernetesは環境の構築・維持の手間が大きい」という問題がありましたが、パブリッククラウドでマネージドサービスが提供されたことで以前と比較すると容易に利用を開始できるようになりました。

DockerKubernetesの統合

 Kubernetesについては、概念の理解などの点で非常に学習コストが高いことも問題でした。また、先に述べたように環境構築の手間が大きいことが、知識習得に向けたハードルを上げてしまっていました(ローカルでの学習用に「minikube」などのツールは提供されていましたが)。

 しかし、現在は「Docker for Mac with Kubernetes」「Docker for Windows Desktop with Kubernetes」という形で、DockerKubernetesの統合が進んでいます。これによってKubernetesについて学習、理解するためのハードルが大幅に下がり、今後一挙に多くのエンジニアが活用できるようになる可能性が出てきています。

CNCFを中心としたベンダー中立な開発体制

 KubernetesCNCFによって開発が主導されています。CNCFでは、AWSMicrosoftGoogleといった大手クラウドベンダーだけではなく、競合となるコンテナオーケストレーションツールの開発元(DockerMesosphereなど)も参加しています。特定のベンダーのみに依存せずにオープンな形での議論と開発が進められており、開発元の都合で突然利用できなくなるといったリスクが少なくなっています。

 

そもそも、Dockerとコンテナ型仮想化のメリットとは何か

 Dockerとは、Docker社の提供するオープンソースのコンテナ型仮想化ソフトウェアおよび実行環境です。独立した実行環境(=コンテナおよびその集合)の内部にアプリケーションを構築することで、サービス開発/提供のアジリティを向上させることができます。

 サービス開発/提供のアジリティ向上というメリットが得られる理由は、主に下記3つの観点から説明できます。

1.     環境の分離

2.     高速な動作

3.     Dockerのエコシステム

環境の分離

 Dockerは図1のようにアプリケーションの動作環境を「コンテナ」によって分離します。

 
1 Dockerによるアプリケーションの動作環境の分離

 Dockerエンジン以下のレイヤーはコンテナ間で共有しつつ、アプリケーションバイナリの動作に必要なライブラリ環境を分離しています。これによって他のアプリケーションの動作環境から影響を受ける可能性を取り除きます。

高速な動作

 動作環境を分離するという意味では、ハイパーバイザーを用いたサーバ型仮想化でも同様のことが実現できることにお気付きの方もいるかもしれません。両者の違いは、「どこで動作環境を分離しているか」という点にあります。

 
2 Dockerによるコンテナ型仮想化(左)とハイパーバイザーを用いたサーバ型仮想化(右)

 サーバ型仮想化では、OSLinuxカーネルなど)も含めて分離しているため、起動、停止の際にはOSの起動・停止プロセスが含まれます。一方コンテナ型仮想化では、アプリケーションバイナリの実行に必要なライブラリの部分で動作環境が分離されているため、OSの起動・停止プロセスが含まれません。短時間の「独立した動作環境の確保・破棄」「アプリケーションバイナリの起動・停止」が可能になっています。

Dockerのエコシステム

 ここまでで述べた1.2.のアジリティ向上のポイントは、技術的にはDocker以外の他のコンテナ型仮想化ソフトウェア——「chroot」「jail」「Solaris Containers」「LXCLinux Containers)」などでも実現できます(LXCに至ってはかつてDocker自体で利用されていました)。では、なぜDockerばかりが注目されたのでしょうか。大きな違いはエコシステムにあります。

 Dockerの提供するエコシステムには主に「コンテナイメージの配布方法の標準化」「コンテナイメージの構築方法の標準化」の2つのポイントがあります。

  • コンテナイメージの配布方法の標準化

 Dockerでは、コンテナイメージを配布するための仕組みとしてDocker Hubが提供されています。

 
3 Docker Hubの検索ページ

 Docker Hubにアカウントを作り、コンテナイメージをアップロードすれば、世界中の人に利用してもらえます。また、プライベートレジストリを独自に構築し組織内部に閉じた形でコンテナイメージを共有することも可能です。

  • コンテナイメージの構築方法の標準化

 Dockerでは、"どうやってコンテナイメージを構築するか"のDSLDomain Specific Language)も定義されています。一般には「Dockerfile」と呼ばれ、図4のサンプルが示すように、テキストで記述されています。GitHubなどのリポジトリサービスを介してDockerfileを公開することで、コンテナイメージの構築手順をテキストベースで共有できるようになっています。

 
4 Dockerfileの例

 

コンテナ型仮想化の本番活用に向けた課題

 Dockerとそのエコシステムを用いることで、アプリケーションの動作環境の構築を簡略化できるとともに、ネットワークを介してあちらこちらに動作環境を展開できるようになりました。この結果、このような仕組みを「本番環境で活用しよう」とするのは自然なことだと思います。

 しかし、Docker単独では本番環境で動かすのに困難な問題が幾つか存在します。例えば100台のDockerホスト(Dockerを導入済みのサーバ)があり、この上に本番サービスをデプロイすることを考えてみます。その際、次のような課題が生じます。

1.     複数のDockerホストをどう管理するか

2.     どのDockerホストにコンテナ(アプリケーション)を立ち上げるか

3.     コンテナのデプロイ方法をどう定義するか

4.     複数のコンテナ間の連携をどう実現するか

5.     コンテナの死活監視をどうするか

6.     コンテナの保持するデータをどう管理するか

7.     外部ネットワークからコンテナへのアクセス経路をどう設定するか

 

「失敗しないAI開発プロジェクト」の作り方をエンジニアに聞いた

 AIを使った製品やサービスの開発が進んでいる。注目度が高く、優れた予測や業務の自動化などに効果を発揮する製品/サービスが続々と登場してくる一方、開発に行き詰まるケースも聞こえてくる。「AI開発プロジェクトを成功させる条件」とは一体何か。実際にAIの開発に関わり、現場の課題を熟知するエンジニアが語った。

 

 2018131日、人工知能(AI)に特化したWebメディア「Ledge.ai(レッジ・エーアイ)」主催のイベント「THE AI 2018」が東京で開催された。テクノロジー業界の最前線でAIに関わるエンジニアや有識者に交じり、多国籍のエンジニアチームで知られる「Cogent Labs(コージェントラボ)」のAIアーキテクト、デビッド・マルキン(David Malkin)氏とシニア・リサーチ・エンジニアのダビド・クルナポ(David Cournapeau)氏が講演を行った。

 

 Cogent Labsは、手書き文字認識サービス「Tegaki」や自然言語認識、分析技術による文書検索ツール「Kaidoku」など、機械学習や深層学習を活用した製品を次々と開発、市場投入している。同社は、「製品を使っている間はユーザーにAIの存在を感じさせないくらい」(マルキン氏)ユーザー視点の「使いやすさ」を考えた設計に力を入れているという。

 

「いつまでたっても終わらないAI開発プロジェクト」の原因

 

 一方で、同社で開発を行うエンジニアであるクルナポ氏は、「長期間かけても収束しないAI開発プロジェクトが後を絶たない」と話す。

 

 学術機関やエネルギー関連企業など、過去にさまざまな組織でAI開発に関わった同氏によれば、AIに関して専門教育を受けたサイエンティストがモデルを作り、プロジェクトマネジャーを通してエンジニアに引き渡すプロジェクト形式こそが、トラブルを引き起こすという。

 

 「サイエンティストは、とにかく優秀で速いAIを作ろうとするので、性能を上げるためにモデルを複雑化し、細かいカスタマイズを繰り返します。一方のエンジニアは、商品化を意識してモノを作るので、ユーザーの視点から見た使いやすさや業者としてのメンテナンスのしやすさを重視する。前者だけで作ったモデルを後者に引き渡して製品に落とし込ませようとした結果、半年たっても終わらないプロジェクトを見てきました」(クルナポ氏)

 

大部屋で全員が話し合う開発へ

 

 クルナポ氏が提唱するのは、AI専門のサイエンティストがソフトウェアエンジニア、製品テストや仕上げの専門家に交じって話し合いながら進める開発だ。

 

 その重要なメリットは、各自の専門知識を全員の作業過程に反映できる点だという。例えば、ユーザーの声を直接聞く立場のエンジニアは、彼らのニーズや実際に製品を使う際のトラブルなどをくみ取り、モデルを組み上げるサイエンティストにフィードバックできる。サイエンティスト側は、自らの高度な知識をAIのノウハウとしてエンジニアに教えられる。

 

 「例えば、Tegakiを開発していた際、私はあるユーザーから『人の名前や住所の読み取りを自動化したい』という要望を受けました。日本の場合、住所や名前の漢字を1つでも間違えたら、全くの別物になってしまい、業務に悪影響を与えかねません。私たちはその点を理解し、開発にフィードバックすることで、Tegakiにはほぼ100%に近い正確な読み取り精度を実現しました」(クルナポ氏)

 

 講演の終盤、同氏は、AI開発プロジェクトの担当者が「やるべきこと」「やってはいけないこと」のリストを以下のように公開した。

 

1.     やるべきこと

1.     まずはソフトウェアエンジニアリングに詳しい人材を雇う

2.     サイエンティストには、自由に新たなアイデアを出させる

3.     開発する製品の「管理のしやすさ」「安定性」「単純性」に重きを置く

4.     開発チームのエンジニア全員に、予測モデルをアップデートできるだけのトレーニングを施す

2.     やってはいけないこと

1.     サイエンティストにエンジニアがいない状態でコードベースを書かせる

2.     製品のニーズについて詳しく共有していない状態で、サイエンティストにメトリクスを定義させる

3.     製品に平行する形で予測モデルのプロトタイプを作る(実際の製品に反映不可能な変更が生じる恐れ)

4.     予測モデルの「管理のしやすさ」「導入のしやすさ」よりも「正確性」を重視してしまう

5.     「製品化」を念頭に置かないまま予測モデルをチューニングしてしまう

 

「あらゆるエンジニアにとって、機械学習が『ネットワーク』並みの基礎知識になる」

 

 機械学習ではなく「ソフトウェアエンジニアリング」に長けた人材を雇う点は、AIを扱える人材を探すプロジェクト担当者が多い業界にあって、意外に聞こえる。だが、クルナポ氏は「個人的な見地からいえば、機械学習の8割は、工学系の大学を出てから数年の経験しかないエンジニアでも、簡単に習得できる知識やスキルです」と語る。

 

 講演の間、一貫して同氏が強調したのは、「優れた予測モデルを作る」点よりも、むしろ「正確かつ分かりやすく、管理しやすい予測モデルを製品化する」点の難しさだった。

 

 講演後、「理想のAI開発チーム」ついてクルナポ氏は、「エンジニア全員が、AIについて深い知識を備えているチーム」と語った。

 

 「今後、機械学習についての知識は、エンジニアにとって必須になるでしょう。その重要性を理解し、エンジニアが常に最新の機械学習のツールを使って知識やスキルをアップデートできる環境を作れる企業が、今後台頭していくのではないでしょうか」(クルナポ氏)

 

2018年3月5日月曜日

Python版OpenCVで顔検出(Haar Cascade)

この記事では、Python+OpenCVHaar Cascade識別器(分類器)を実装し、画像から顔を検出する方法をソースコード付きで解説します。

Haar Cascade

Haar Cascadeは、Haar-like特徴から作成した複数の強識別器を連結したものです。
Haar Cascade
の詳細は下記事で解説しています。

参考記事

原理はこちら

Haar Cascadeによる顔検出の原理

このアルゴリズムは、OpenCVを使うと簡単に実装できます。
今回はOpenCVの「cv2.CascadeClassifier」「cascade.detectMultiScale」を使って入力画像から顔を検出してみました。

書式

cascade = cv2.CascadeClassifier(path)
face = cascade.detectMultiScale(src, scaleFactor, minNeighbors, minSize)

パラメータ名

説明

path

使用するカスケード識別器のファイルパス

src

入力画像

scaleFactor

画像スケールにおける縮小量

minNeighbors

矩形を要素とするベクトル

minSize

探索窓の最小サイズ(これより小さい対象は無視)

face

探索結果(見つかった場所の左上座標・幅・高さを格納したリスト)

カスケード型識別器のファイル

OpenCVでは、顔・目などを検出できるカスケード識別器の学習済みファイルを事前に用意されています。
学習済みファイルは下記リンク先からダウンロードできます。

URLhttps://github.com/opencv/opencv/tree/master/data/haarcascades

今回は顔検出のために「haarcascade_frontalface_default.xml」を使います。

ファイル名

検出対象

haarcascade_eye.xml

haarcascade_eye_tree_eyeglasses.xml

眼鏡

haarcascade_frontalcatface.xml

猫の顔(正面)

haarcascade_frontalcatface_extended.xml

猫の顔(正面)

haarcascade_frontalface_alt.xml

顔(正面)

haarcascade_frontalface_alt2.xml

顔(正面)

haarcascade_frontalface_alt_tree.xml

顔(正面)

haarcascade_frontalface_default.xml

顔(正面)

haarcascade_fullbody.xml

全身

haarcascade_lefteye_2splits.xml

左目

haarcascade_licence_plate_rus_16stages.xml

ロシアのナンバープレート(全体)

haarcascade_lowerbody.xml

下半身

haarcascade_profileface.xml

顔(証明写真)

haarcascade_righteye_2splits.xml

右目

haarcascade_russian_plate_number.xml

ロシアのナンバープレート(数字)

haarcascade_smile.xml

笑顔

haarcascade_upperbody.xml

上半身

ソースコード(Python3

サンプルプログラムのソースコードです。

# -*- coding: utf-8 -*-
import cv2
 
def main():
    # 入力画像の読み込み
    img = cv2.imread("test.png")
    
    # カスケード型識別器の読み込み
    cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
    
    # グレースケール変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 顔領域の探索
    face = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(30, 30))
    
    # 顔領域を赤色の矩形で囲む
    for (x, y, w, h) in face:
        cv2.rectangle(img, (x, y), (x + w, y+h), (0,0,200), 3)
 
    # 結果を出力
    cv2.imshow("result.jpg",img)
 
    
if __name__ == '__main__':
    main()

実行結果

サンプルプログラムの実行結果です。

 

Python, OpenCVで顔検出と瞳検出(顔認識、瞳認識)

Python, OpenCVでカスケード型分類器を使った顔検出と瞳検出(顔認識と瞳認識)を行う。

以下に公式のチュートリアル(英語)がある。

·         OpenCV: Face Detection using Haar Cascades

ここでは、

·         静止画: 画像ファイルを読み込んで顔検出と瞳検出

·         動画: Webカメラを使ってリアルタイムで顔検出と瞳検出

について説明する。

サンプルコード

まず最初に画像ファイルを読み込んで顔検出と瞳検出を行うサンプルコードを示す。説明およびリアルタイム処理のサンプルコードは後述。

import cv2
 
face_cascade_path = '/usr/local/opt/opencv/share/'\
                    'OpenCV/haarcascades/haarcascade_frontalface_default.xml'
eye_cascade_path = '/usr/local/opt/opencv/share/'\
                   'OpenCV/haarcascades/haarcascade_eye.xml'
 
face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)
 
src = cv2.imread('data/src/lena_square.png')
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
 
faces = face_cascade.detectMultiScale(src_gray)
 
for x, y, w, h in faces:
    cv2.rectangle(src, (x, y), (x + w, y + h), (255, 0, 0), 2)
    face = src[y: y + h, x: x + w]
    face_gray = src_gray[y: y + h, x: x + w]
    eyes = eye_cascade.detectMultiScale(face_gray)
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(face, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
 
cv2.imwrite('data/dst/opencv_face_detect_rectangle.jpg', src)

source: opencv_face_eye_detection.py

カスケード型分類器の読み込み

Machomebrewopencv3をインストールした場合、

·         /usr/local/opt/opencv/share/OpenCV/haarcascades/

に学習済のHaar-like特徴を用いた分類器のデータ(xmlファイル)がある。

xmlファイルの場所がわからない場合は、GItHubのレポジトリからダウンロードして任意の場所に置いてもいい。

·         opencv/data/haarcascades at master · opencv/opencv

以下のようにいくつかの種類のデータが用意されている。

·         正面の顔検出用: haarcascade_frontalface_default.xml

·         瞳検出用: haarcascade_eye.xml

·         笑顔検出用: haarcascade_smile.xml

cv2.CascadeClassifier()でパスを指定してxmlファイルを読み込む。

detectMultiScaleで検出

読み込んだ検出器のメソッドdetectMultiScale()で顔や瞳(目)などを検出する。

検出領域の(左上の点のx座標, y座標, , 高さ)のリスト(配列)が返される。

·         OpenCV: cv::CascadeClassifier Class Reference

上のサンプルコードでは、まず顔を検出し、その顔に対して瞳(目)の検出をしている。

引数としてグレースケール(白黒)の画像データを渡す。カラー画像からグレースケール(白黒)画像への変換はcv2.cvtColor()で行う。

そのほか以下のような引数を指定できる(省略可能)。

·         scaleFactor(初期値1.1

·         minNeighbors(初期値3

detectMultiScale()では様々なスケールで検出を行うが、それぞれのスケールの縮小量を定義するのがscaleFactor

scaleFactorの値が小さいとスケールを細かく変更して検出するため、見落としは少ないが処理時間がかかる。

また様々なスケールで検出した結果、同じエリアで重複して検出される。いくつ重複した場合に真とみなすかを定義するのがminNeighbors

minNeighborsの値が小さいと重複が少ない領域も真とするため、見落としは少ないが誤検出が増える。

scaleFactorminNeighborsも対象となる画像や使用する検出器のデータなどによって最適な値は異なるが、基本的には初期値のままでもある程度は検出できる。

検出領域に対して処理(枠描画、塗りつぶし、モザイク)

上のサンプルコードでは、cv2.rectangle()で検出した領域の枠を描画している。

図形描画については以下の記事を参照。

·         関連記事: Python, OpenCVで図形描画(線、長方形、円、矢印、文字など)

検出した領域を塗りつぶす場合はcv2.rectangle()で塗りつぶしてもいいし、以下のようにも書ける。

faces = face_cascade.detectMultiScale(src_gray)
 
for x, y, w, h in faces:
    src[y: y + h, x: x + w] = [0, 128, 255]
 
cv2.imwrite('data/dst/opencv_face_detect_fill.jpg', src)

source: opencv_face_eye_detection.py

検出した領域にモザイクをかけたりすることもできる。

faces = face_cascade.detectMultiScale(src_gray)
 
ratio = 0.05
 
for x, y, w, h in faces:
    small = cv2.resize(src[y: y + h, x: x + w], None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    src[y: y + h, x: x + w] = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)
 
cv2.imwrite('data/dst/opencv_face_detect_mosaic.jpg', src)

source: opencv_face_eye_detection.py

モザイク処理についての詳細は以下の記事を参照。

·         関連記事: Python, OpenCVで画像にモザイク処理(全面、一部、顔など)

Webカメラを使ってリアルタイムで顔検出と瞳検出

以前、Macの内蔵カメラでキャプチャした動画をリアルタイムで処理した。

·         関連記事: Python, OpenCVMacBook ProFaceTime HD Cameraの動画を処理

カメラでキャプチャした各フレームに対して上述の画像ファイルでの処理を行えば、リアルタイムで顔検出や瞳検出をすることができる。

サンプルコードは以下の通り。

import cv2
 
face_cascade_path = '/usr/local/opt/opencv/share/'\
                    'OpenCV/haarcascades/haarcascade_frontalface_default.xml'
eye_cascade_path = '/usr/local/opt/opencv/share/'\
                   'OpenCV/haarcascades/haarcascade_eye.xml'
 
face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)
 
cap = cv2.VideoCapture(0)
 
while True:
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
    for x, y, w, h in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
        face = img[y: y + h, x: x + w]
        face_gray = gray[y: y + h, x: x + w]
        eyes = eye_cascade.detectMultiScale(face_gray)
        for (ex, ey, ew, eh) in eyes:
            cv2.rectangle(face, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
    cv2.imshow('video image', img)
    key = cv2.waitKey(10)
    if key == 27:  # ESCキーで終了
        break
 
cap.release()
cv2.destroyAllWindows()

source: opencv_face_eye_detection_camera.py