(仮) ブログ

主にWeb Apps や、Azure PaaS サービス を使う際に役立ちそうなことを書こうと思っています。

新しい App Service 診断を触ってみた

Microsoft Ignite 2018 とともに発表された、新しい App Service Diagnostics ですが、ガラリと UI が変わりました。 以前こちらの記事で紹介したのですが、昔の UI なので改めてみていこうと思います。

keyomura.hatenablog.com

App Service Team のブログ記事はこちら

blogs.msdn.microsoft.com

目次

UI が変わった

まず、UI が大きく変わりました。昔の UI はこんな感じですが、、

f:id:yoshioblog:20180828235631p:plain

新しい UI はこんな感じになってます。おしゃれですね。

f:id:yoshioblog:20180930221536p:plain

カテゴリ別に分かれてる

新しい UI はカテゴリが分かれています。

f:id:yoshioblog:20180930225517p:plain

まずカテゴリを選んだ後 Web App Restarted や、Web App Downなど目的のツールを選ぶようです。

新しい機能が増えてる

以前からあったのかもしれないですが、SSL や、カスタムドメインに関しての機能も追加されていました。証明書の操作もここから追うことができるようです。

f:id:yoshioblog:20180930223425p:plain

直接検索できる

トラブルシューティングのツールを Search App Service Diagnostics から直接検索できるようになりました。ある程度わかっている人であれば UI をぽちぽちするより速いですね。

f:id:yoshioblog:20180930223748p:plain

まとめ

新しくなった UI で、簡単なトラブルであれば自分ですぐに調べて解決できそうだなと感じました。 Best Practice もあるようなので、自分の Web App の状態を見てみるのも面白そうです。

Azure Web Apps の Bring your own Storage を試してみた

Microsoft Ignite 2018 とともに発表された新機能の Bring your own Storage to App Service 、その名の通り Web Apps on Linux や、Web App for Containers に Blob Storage や File Storage をマウントすることができます。

FTP や Git から Web App にファイルをアップロードすることはできますが、大きい画像や動画ファイルを git add するのもレポジトリが肥大化して嫌ですし、ファイルを確認するために FTP や Kudu でいちいちアクセスするのも面倒です。この機能のおかげで大きいファイルは Storage に置いておくだけで済むので便利そうですね。

ちなみに、Azure Web Apps (Linux) は、Azure 側で提供しているランタイム スタックを使用して Linux ベースのアプリケーションのホストが可能なサービスで、Web App for Containers は、自分で作成した Docker コンテナを Web Apps の環境でホストが可能なサービスです。

細かい違いに関してはこちらに載ってます。

azure.microsoft.com

今回は、この機能を試したので紹介していこうと思います。

元のブログ記事はこちら

blogs.msdn.microsoft.com

目次

Web Apps on Linux を作成する

まずは、Web App (Linux) を作成しましょう。Azure ポータルからWeb Apps (Linux) を作成するときは下記のように選択します。 今回はランタイム スタックはなんでもいいと思うので好きなやつを選びましょう。

f:id:yoshioblog:20180926224714p:plain

Azure Cloud Shell からコマンドを実行する

Web App の作成が終わったら、Azure Cloud Shell から早速コマンドを試します。 右上から選択してコンソール画面を開きましょう。

f:id:yoshioblog:20180926225233p:plain

az webapp config storage-account コマンドが実行できることを確認します。できそうですね。

f:id:yoshioblog:20180926225538p:plain

マウントするには、az webapp config storage-account add を利用します。 今回は、Blob Storage をマウントしました。

az webapp config storage-account add 

-g Web App のリソースグループ名
-n Web App 名
-i マッピングの設定名
-t AzureBlob
--account-name ストレージ アカウント名
--share-name ストレージ コンテナ名
-k ストレージ アカウントのキー
--mount-path マウントするパス

実際に実行するとこんな感じ

f:id:yoshioblog:20180926230659p:plain

az webapp config storage-account add -h で各コマンドのより細かい情報が出てきます。オプションがわからなくなったらこれを使いましょう。

f:id:yoshioblog:20180926230905p:plain

SSH でログインして確認する

マウントに成功したようなので、ポータルから SSH をして確認します。事前にファイルをあげるのを忘れずに。

f:id:yoshioblog:20180926233225p:plain

SSH をして確認した結果がこちらです。しっかりマウントできてますね。いらなくなったら、az webapp config storage-account delete で削除しましょう。

f:id:yoshioblog:20180926231217p:plain

まとめ

Bring your own Storage の機能を使うことで、これまで Web Apps にアップロードしていたファイルを減らすことができそう。

特に動画ファイルや画像ファイルの参照が多いアプリに関しては、この機能を使うようにした方が容量も多いし手間も省けそうですね。

現在はプレビューの段階で Web Apps on Linux や、Web App for Containers でしか利用できませんが、そのうち Windows コンテナや普通の Web App (Windows) で使えるようになれば、さらに面白くなりそうです。

Azure Web Apps の再起動を調べる

Azure Web Apps を利用していると、HTTP 5xx エラーが発生していた、もしくはある時から HTTP 5xx エラーが発生し始めたなんてことがあるかと思います。 その場合、よく疑われるのがメンテナンスによるアプリの再起動などです。今回は Web Apps の再起動の確認方法を紹介していきます。

UI が変わったので、その紹介をこちらでしています。

keyomura.hatenablog.com

目次

再起動の確認方法

Azure ポータルの [問題の診断と解決] から、"Web App Restarted" を選択することで、そのアプリが再起動していたか確認することができます。


f:id:yoshioblog:20180819105859p:plain

再起動の理由も

選択すると、Web App の再起動があった時点で棒グラフが出てきます。ここでは、アプリケーション設定を変更したから再起動したと書いてあります。


f:id:yoshioblog:20180819110037p:plain

メンテナンスがあったかどうかも書かれていた気がするので、ちょっとした調査であればこれだけで済みそうです。

ちなみに、メンテナンス Web App や Function App のメンテナンスの仕組みに関してはブログで公開されています。

blogs.msdn.microsoft.com

Auto Heal に関して

他にも、グラフの項目には、Auto Heal Events というものが表示されています。

Auto Heal は HTTP 500 エラーの数やリクエスト数など、あらかじめ設定したメトリックが閾値を超えた場合に自動でアプリを再起動する機能です。便利ですね。

Web.config から設定する方法や、Kudu サイトから設定する方法があります。

Web.config による設定方法

Web.config による設定方法はこちらに書いてあります。

Auto-Healing Windows Azure Web Sites | ブログ | Microsoft Azure

Kudu サイトからの設定方法

Kudu サイトからの設定方法はこちらになります。

Auto Heal your Azure Web App – Microsoft Azure App Service

Proactive Auto Heal について

Auto Heal は自分で設定しない限り有効にはなりませんが、Proactive Auto Heal に関しては既定で有効になっています。

Proactive Auto Heal とは、メモリが枯渇しそうな場合や、レスポンスが極端に遅くなっている場合に Web App を再起動する機能で、あらかじめ有効になっています。

blogs.msdn.microsoft.com

具体的には、下記の条件で再起動が発生します。

  • Percent Memory Rule: Web App のプロセスのメモリ使用率 90 % 以上の状態が 30 秒以上続いた時
  • Percent Request Rule: 処理に 200 秒以上かかったリクエストが80 % 以上になった時 (2 分間で 5 リクエスト以上来ている Web App が対象)

WEBSITE_PROACTIVE_AUTOHEAL_ENABLED を False にすることで無効にできます。

まとめ

ポータル上のメトリックなどで HTTP 5xx を確認した際は、まず再起動があったかを確認し、再起動ではなかった場合は、アプリケーションのログを見ていく必要があると思います。

アプリに依存しますが、メンテナンスによる再起動後、エラーがで続けてしまうアプリにおいて、とりあえず問題を一時的に回避する場合は、HTTP 5xx ステータスでAuto Heal を設定するのがオススメです。

アプリケーション ログの確認方法はこちらで紹介しているので、参考になれば幸いです。

keyomura.hatenablog.com

Web Apps (Windows) でアプリケーションのログを確認する

Web Apps (Windows) でアプリケーションがうまく動かなかった時によく見るのはアプリケーションのログですが、今回はそれぞれの言語に関してどこにログがあるのか紹介していきます。 Web Apps on Linux のログの確認方法に関しては、以前の記事で紹介していますのでこちらを参照してください。

keyomura.hatenablog.com

目次

アプリケーション ログの設定

Web Apps では、[診断ログ] というブレードからログの設定を行うことができます。

f:id:yoshioblog:20180820072018p:plain

ASP.NET アプリケーションの場合、System.Diagnostics.Trace クラスを使用することで記録することができます。

一方、ASP.NET 以外のアプリケーション (Node.js、JavaPHPPython など) の場合それぞれ違う形でログが出力されます。 ※ カスタムのランタイムを利用している場合は、ログの出力は自分で設定してください。

Node.js、JavaPHPPython などのログを Blob へ転送したい場合、[診断ログ] からは設定することができないので、自分で実装する必要があります。

アプリケーションのログ以外の Web サーバー ログの設定などに関してはこちらのドキュメントに詳しく書かれています。

docs.microsoft.com

アプリケーション ログの場所をそれぞれ確認する

ログを確認するためには、Kudu サイトへアクセスしてコンソールから目的のファイルがある場所まで移動します。

Kudu サイトは、Web Apps の管理サイト的な位置付けのサイトとなります。Azure ポータルで、Web Apps を選択したあと [高度なツール] から移動可能です。

画面上部の [Debug console] から CMD へ移動するとこのような画面になります。LogFiles フォルダ以下に各言語のログが出力されます。

f:id:yoshioblog:20180819094912p:plain

PHP

  • D:\home\LogFiles\php_errors.log

Java (Tomcat)

  • D:\home\LogFiles\Application\catalina.InstanceID.yyyy-mm-dd.log

  • D:\home\LogFiles\Application\host-manager.InstanceID.yyyy-mm-dd.log

  • D:\home\LogFiles\Application\ localhost.InstanceID.yyyy-mm-dd.log

  • D:\home\LogFiles\Application\ manager.InstanceID.yyyy-mm-dd.log

Node.js

  • D:\home\LogFiles\Application\logging-errors.txt

Python

  • Web.config に自分で設定します。

Azure App Service Web Apps による Python の構成 | Microsoft Docs

.Net Core

  • Web.config に自分で設定します。

ASP.NET Core モジュール構成リファレンス | Microsoft Docs

※ Instance ID とは、Web Application が動作するインスタンス (仮想 VM) の ID となります。Kudu の [Envrionment] から確認可能です。例えば 2 台にスケール アウトしている場合は、それぞれ別のインスタンス ID が割り当てられます。

Web Apps のインスタンス構成に関してはこちらで詳しく紹介しています。

keyomura.hatenablog.com

Application Insights を使う

Application Insights を使うと、メトリックも含めより詳細に Web Apps の状態を確認することができますが、利用するためにはあらかじめ実装に組み込んでおく必要があります

docs.microsoft.com

なお、ASP.NET の場合は、後からでも設定することが可能です。

docs.microsoft.com

まとめ

アプリケーションでエラーが出た場合、その詳細はアプリケーション内部のログに書かれていることがほとんどです。 大規模なアプリケーションの場合は、Application Insights を利用した方がより詳細にメトリックを確認することができると思います。

CNTK を使い始めてみた その 3 (トレーニング 編)

前回に引き続き、CNTK の手書き文字認識のチュートリアルを細かく確認していきます。 この前は、モデルの構築まで済んだのでついにトレーニングを実施します。

keyomura.hatenablog.com

トレーニングの設定

作成したモデル (z) の学習を行います。モデルの作成方法は前回の記事を参照してください。

f:id:yoshioblog:20180818231106p:plain

チュートリアルでは与えられた損失関数として、cross_entropy_with_softmax交差エントロピーを計算します。 また、分類のエラーは classification_error で計算するようです。

loss = C.cross_entropy_with_softmax(z, label)
label_error = C.classification_error(z, label)

簡単な値を手元で計算するとこんな感じ

C.cross_entropy_with_softmax([[0,1]],[[0,1]]).eval()
# array([[ 0.31326163]], dtype=float32)

C.classification_error([[0,1]],[[0,1]]).eval()
# array([[ 0.]], dtype=float32)

訓練の設定

次にチュートリアルでは、SGD (Stochastic Gradient Descent) を最適化関数として利用していました。

今回は、最適化関数として adam を採用します。 このとき、学習率 (learning_rate) も設定します。最後に、先ほどの loss と label_error を引数に trainer を定義しています。

# Instantiate the trainer object to drive the model training
learning_rate = 0.2
lr_schedule = C.learning_parameter_schedule(learning_rate)
learner = C.adam(z.parameters, lr_schedule,0.99)
trainer = C.Trainer(z, (loss, label_error), [learner])

学習

実際に学習を行います。create_reader 関数を定義して、MinibatchSource クラスを定義します。

# Read a CTF formatted text (as mentioned above) using the CTF deserializer from a file
def create_reader(path, is_training, input_dim, num_label_classes):
    return C.io.MinibatchSource(C.io.CTFDeserializer(path, C.io.StreamDefs(
        labels = C.io.StreamDef(field='labels', shape=num_label_classes, is_sparse=False),
        features   = C.io.StreamDef(field='features', shape=input_dim, is_sparse=False)
    )), randomize = is_training, max_sweeps = C.io.INFINITELY_REPEAT if is_training else 1)

# Create the reader to training data set
reader_train = create_reader(train_file, True, input_dim, num_output_classes)

# Map the data streams to the input and labels.
input_map = {
    label  : reader_train.streams.labels,
    input  : reader_train.streams.features
} 

# Run the trainer on and perform model training
training_progress_output_freq = 500

plotdata = {"batchsize":[], "loss":[], "error":[]}

for i in range(0, int(num_minibatches_to_train)):
    
    # Read a mini batch from the training data file
    data = reader_train.next_minibatch(minibatch_size, input_map = input_map)
    
    trainer.train_minibatch(data)
    batchsize, loss, error = print_training_progress(trainer, i, training_progress_output_freq, verbose=1)
    
    if not (loss == "NA" or error =="NA"):
        plotdata["batchsize"].append(batchsize)
        plotdata["loss"].append(loss)
        plotdata["error"].append(error)

実際に損失関数と、予測誤差をプロットしたのがこちらです。Adam の方が若干盛り上がってますね。

Adam

f:id:yoshioblog:20180819084840p:plain f:id:yoshioblog:20180819084848p:plain

SGD

f:id:yoshioblog:20180819083721p:plain f:id:yoshioblog:20180819083748p:plain

次回は、テストと評価を行おうと思います。

CNTK を使い始めてみた その 2 (モデル構築/可視化 編)

前回に引き続き CNTK の手書き文字認識チュートリアルをやってみたけど、中身がよくわかんなかったので一個ずつ調べていきます。

前回の記事はこっち

keyomura.hatenablog.com

今回は、CNTK のモデルの構築手順を確認していきます。 前回同様、手書き文字認識のチュートリアルがベースになっています。

入力の定義

まず特徴量の次元や、ラベルの数を、input_variable 関数でCNTK で利用可能な型に変換します。

# 28 x 28 の画像をベクトルに変換。0 ~ 9 の手書き文字を識別するため output class は 10
input_dim = 784
num_output_classes = 10

# input_variable へ変換する
input = C.input_variable(input_dim)
label = C.input_variable(num_output_classes)

input_variable の返り値として、Variable 型が返されます。

Input('Input3', [#], [784])
Input('Input4', [#], [10])

この Input3 や Input4 は変数の名前で、変更することもできます。

input = C.input_variable(input_dim,name="myinput")
print(input)
Input('myinput', [#], [784])

モデルの構築

次に、モデルの構築を行いましょう。

今回はチュートリアルの通りこんな感じのモデルを作って、手書き文字の画像認識を行います。

f:id:yoshioblog:20180811213844j:plain

チュートリアル内では、create_model 関数を作ってその中でモデルを作っています。

num_hidden_layers = 2
hidden_layers_dim = 400

def create_model(features):
    with C.layers.default_options(init = C.layers.glorot_uniform(), activation = C.ops.relu):
            h = features
            print(num_hidden_layers)
            for _ in range(num_hidden_layers):
                h = C.layers.Dense(hidden_layers_dim)(h)
            r = C.layers.Dense(num_output_classes, activation = None)(h)
            return r

# Scale the input to 0-1 range by dividing each pixel by 255.
z = create_model(input/255.0)

CNTK では、with 文とともに default_options 関数を実行することで、モデル構築時に設定した値をブロック内にのみ適用しています。 変数の初期化として利用できるのは、glorot_uniform や、he_normal などがあり、他にもいろんな分布が利用できます。 活性化関数としてはrelu の他にも、tanhsigmoid が利用できます。詳しくはこちらのドキュメントをどうぞ。

cntk.initializer module — Python API for CNTK 2.5.1 documentation

cntk.ops package — Python API for CNTK 2.5.1 documentation

今回は、全結合のネットワークを作るので Dense() 関数を利用します。 CNNLSTM の時の利用方法もリンク先に書いてあります。

create_model を実行するとモデルが作成されます。

(おまけ) CNTK で作ったモデルの可視化

実は、このドキュメントによると作ったモデルは画像で出力できるようです。

Using Graphviz for Visualization | Microsoft Docs

モデルの出力には Graphviz と呼ばれるグラフ可視化用のソフトウェアをインストールする必要があります。 Docker コンテナで実行している人は、公式の CNTK のイメージにはインストールされていないので、新たに Graphviz をインストールしたイメージを作成しましょう。今回は、下記のような Dockerfile を作成しました。

# Ubuntu 16.04
FROM microsoft/cntk:2.5.1-cpu-python3.5

# install graphviz
RUN apt-get update && apt-get install graphviz -y

その後、docker build でイメージを作成し、docker run で自分が作成したイメージを指定しましょう。

cd Dockerfile のあるディレクトリ
docker build ./ -t myimage
docker run -d -p 8888:8888 --name cntk-jupyter-notebooks -t myimage
docker exec -it cntk-jupyter-notebooks bash -c "source /cntk/activate-cntk && jupyter-notebook --no-browser --port=8888 --ip=0.0.0.0 --notebook-dir=/cntk/Tutorials --allow-root"

チュートリアルから先ほどのモデル構築完了まで戻ってきたら、下記のコードでモデルの画像を出力できます。

import pydot_ng

graph_description = C.logging.graph.plot(z, "graph.png")
print(graph_description)

display(Image(filename="graph.png"))

出力されるとこんな感じです。図にするとやっぱり見やすいですね。

f:id:yoshioblog:20180811225801p:plain

まとめ

ここまでで CNTK を使って、DNN のモデルの構築や可視化が完了しました。 次回から、トレーニングとテストを実行します。

CNTK を使い始めてみた その 1 (データ読み込み編)

Microsoft には、CNTK という Deep Learning ライブラリがあるのですがあまり世間に認知されておらず、使おうと思った時に調べてもどこにも情報が載っていないです。

CNTK の Github レポジトリにある、 jupyter notebook のチュートリアルをやってみると、画像の判別ができていそうな気になりますが、実際に何をしているのかよくわからない、、

また、日本語の記事はチュートリアルの翻訳が多くて、実際にここの処理はどうなっているみたいな記事があまりないっぽい、、

だったら、自分でやったれということで、今回からこのチュートリアルの中身がそれぞれどういう処理をしているのか確認してみることにしました。

今回から 手書き文字認識のチュートリアルの内容を掘り下げていきます。

この後のお話は、一回手書き文字認識のチュートリアルを終わらせているけど、中身がよくわかんない人向けです。

※ そして、書いていたらとても長くなってしまったので、いくつかの記事に分けることにしました。

目次:

(事前準備) そもそも CNTK ってなんですか

CNTK は The Microsoft Cognitive Toolkit の略称であり、オープン ソースの Deep Learning ライブラリです。商用利用可能であり CNNs や RNNs、LSTMs なども実装されています。

現在、PythonC#C++ のプログラムでサポートされており、Github のページからバイナリのパッケージやチュートリアルがダウンロード可能です。

また、ONNX (Open Neural Network Exchange) にも対応しているため、ONNX 対応の別フレームワークで構築したモデルを CNTK へ渡す、もしくはその逆が可能になります。

(事前準備) まずはインストール

CNTK のライブラリは pip でインストールが可能です。まずはこの記事に従って、CNTK をインストールしてみましょう。

C:\> pip install cntk

自分の手元の環境は Mac なのですが、Mac の場合は Docker コンテナで実行可能です。Linux の場合もコンテナを利用した方が、絶対に楽だと思います。

CNTK Docker Containers | Microsoft Docs

コンテナの場合、上記のドキュメントに沿って実行すると、Jupyter notebook が起動するので、CNTK_103A ~ D のチュートリアルを選んでください。

CNTK のデータ ロード方法

CNTK_103A のチュートリアルを読んでいると、まず手書き文字のデータをダウンロードしてきて、それを Numpy array に変換後、txt ファイルに保存しています。

チュートリアル内では下記の部分になります。

# Functions to load MNIST images and unpack into train and test set.
# - loadData reads a image and formats it into a 28x28 long array
# - loadLabels reads the corresponding label data, one for each image
# - load packs the downloaded image and label data into a combined format to be read later by 
#   the CNTK text reader 

def loadData(src, cimg):
    print ('Downloading ' + src)
    gzfname, h = urlretrieve(src, './delete.me')
    print ('Done.')
    try:
        with gzip.open(gzfname) as gz:
            n = struct.unpack('I', gz.read(4))
            # Read magic number.
            if n[0] != 0x3080000:
                raise Exception('Invalid file: unexpected magic number.')
            # Read number of entries.
            n = struct.unpack('>I', gz.read(4))[0]
            if n != cimg:
                raise Exception('Invalid file: expected {0} entries.'.format(cimg))
            crow = struct.unpack('>I', gz.read(4))[0]
            ccol = struct.unpack('>I', gz.read(4))[0]
            if crow != 28 or ccol != 28:
                raise Exception('Invalid file: expected 28 rows/cols per image.')
            # Read data.
            res = np.fromstring(gz.read(cimg * crow * ccol), dtype = np.uint8)
    finally:
        os.remove(gzfname)
    return res.reshape((cimg, crow * ccol))

def loadLabels(src, cimg):
    print ('Downloading ' + src)
    gzfname, h = urlretrieve(src, './delete.me')
    print ('Done.')
    try:
        with gzip.open(gzfname) as gz:
            n = struct.unpack('I', gz.read(4))
            # Read magic number.
            if n[0] != 0x1080000:
                raise Exception('Invalid file: unexpected magic number.')
            # Read number of entries.
            n = struct.unpack('>I', gz.read(4))
            if n[0] != cimg:
                raise Exception('Invalid file: expected {0} rows.'.format(cimg))
            # Read labels.
            res = np.fromstring(gz.read(cimg), dtype = np.uint8)
    finally:
        os.remove(gzfname)
    return res.reshape((cimg, 1))

def try_download(dataSrc, labelsSrc, cimg):
    data = loadData(dataSrc, cimg)
    labels = loadLabels(labelsSrc, cimg)
    return np.hstack((data, labels))

上で定義した関数を利用して、MNIST のデータをダウンロードし、それを numpy array に保存しています。

# URLs for the train image and label data
url_train_image = 'http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz'
url_train_labels = 'http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz'
num_train_samples = 60000

print("Downloading train data")
train = try_download(url_train_image, url_train_labels, num_train_samples)

# URLs for the test image and label data
url_test_image = 'http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz'
url_test_labels = 'http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz'
num_test_samples = 10000

print("Downloading test data")
test = try_download(url_test_image, url_test_labels, num_test_samples)

https://cntk.ai/pythondocs/CNTK_103A_MNIST_DataLoader.html より

※ MNIST のデータ自体に関しては別の方の記事になりますが、こちらの MNIST データの仕様を理解しようで詳しく解説されていますので参考にしてください。

MNIST のデータが保存されている URL からデータをロードし、numpy array に変換、その後下記のような txt ファイルに変換しています。

|labels 0 0 0 0 0 0 0 1 0 0 |features 0 0 0 0 ...
                                              (784 integers each representing a pixel)

このファイル形式を見てなんだこれ ? となったのですが、CNTK Text Format と呼ばれる独自フォーマット形式のようです。

BrainScript CNTK Text Format Reader | Microsoft Docs

一瞬、毎回こんな形のファイル形式にしないといけないの? と思いましたがそうではないようです。 Read and feed data to CNTK Trainer — Python API for CNTK 2.5.1 documentation を読んでみると、CNTK でのデータの読み取り方法が詳しく書かれていました。
大きく分けるとこの二通りになります。

  1. メモリに乗るデータ量の場合 ( Numpy / SciPy を利用する)
  2. メモリに乗らないデータ量の場合 ( MinibatchSource クラスを利用する)

メモリに乗るデータ量の場合 ( Numpy / SciPy を利用する)

メモリ上に乗るようなデータ量の場合、Numpy Array や、Scipy の sparse matrices (scipy.sparse.csr_matrix) が利用可能です。CNTK の train() や test() にそのまま指定できます。

# Generate your own data
input_dim_lr = 2    # classify 2-dimensional data
num_classes_lr = 2  # into one of two classes

# This example uses synthetic data from normal distributions,
# which we generate in the following.
#  X_lr[corpus_size,input_dim] - input data
#  Y_lr[corpus_size]           - labels (0 or 1), one-hot-encoded
np.random.seed(0)
def generate_synthetic_data(N):
    Y = np.random.randint(size=N, low=0, high=num_classes_lr)  # labels
    X = (np.random.randn(N, input_dim_lr)+3) * (Y[:,None]+1)   # data
    # Our model expects float32 features, and cross-entropy
    # expects one-hot encoded labels.
    Y = scipy.sparse.csr_matrix((np.ones(N,np.float32), (range(N), Y)), shape=(N, num_classes_lr))
    X = X.astype(np.float32)
    return X, Y

# Generating data
X_train_lr, Y_train_lr = generate_synthetic_data(20000)
X_test_lr,  Y_test_lr  = generate_synthetic_data(1024)
print('data =\n', X_train_lr[:4])
print('labels =\n', Y_train_lr[:4].todense())

# Creating Model
x = C.input_variable(input_dim_lr)
y = C.input_variable(num_classes_lr, is_sparse=True)
model = C.layers.Dense(num_classes_lr, activation=None)
loss = C.cross_entropy_with_softmax(model(x), y) # applies softmax to the model output under the hood
print(loss)

learner = C.sgd(model.parameters,
                C.learning_parameter_schedule(0.1))
progress_writer = C.logging.ProgressPrinter(0)


# Training
train_summary = loss.train((X_train_lr, Y_train_lr), parameter_learners=[learner], callbacks=[progress_writer])

https://cntk.ai/pythondocs/Manual_How_to_feed_data.html より

メモリに乗らないデータ量の場合 (MinibatchSource クラスを利用する)

データ量が大きすぎてメモリ上に乗らない場合は、CNTK の場合 MinibatchSource クラスを利用して、データの読み込みを行うことが可能で、これらのことができるようになるそうです。

  • A chunked randomization algorithm that holds only part of the data in RAM at any given time.
  • Distributed reading where each worker reads a different subset.
  • A transformation pipeline for images and image augmentation.
  • Composability across multiple data types (e.g. image captioning).
  • Transparent asynchronous loading so that the GPU is not stalling while a minibatch is read/prepared

Read and feed data to CNTK Trainer — Python API for CNTK 2.5.1 documentation より


データ量が大きい場合は、こちらを使った方が良さそうですね。データに合わせて、これらの関数が用意されています。

  • Text/Basic: CTFDeserializer
  • Image: ImageDeserializer.
  • Speech: HTKFeatureDeserializer, HTKMLFDeserializer

チュートリアルでは MNIST のデータを CNTK text format (CTF) に変換して保存しているので、CTFDeserializer を利用します。

メモリに乗らないデータは毎回 CTF に変換する必要があるの?

そんなことはなさそうです。例えば、Pandas でデータを読み込む際に、chunksize というものが指定できるのですが、これを引数として設定してファイルや SQL を読み込みつつ numpy array に変換して利用すればいいようです。

Pandas is one of the popular framework to read CSV / TSV data (details). We illustrate the use of this IO framework and converting the input to NumPy arrays in the CNTK 106 B tutorial. If one needs to create new features or columns. Leveraging Pandas data frames can save time. CNTK 104 tutorial shows how one can easily facilitate that. A challenge often faced by data scientists is having the need to handle large file which may not fit in memory. Pandas chunk-by-chunk reader provides the capability to read smaller chunks into memory from a larger file on disc. Note: Use of Pandas with CNTK opens the door to reading data from a variety of Text, Binary and SQL based data access.

Read and feed data to CNTK Trainer — Python API for CNTK 2.5.1 documentation より

(おまけ) 実は Fashion MNIST のデータ セットも

実はこの URL を変更するだけで、 Fashion MNIST のデータセットに変換することができます。

Fashion MNIST は、機械学習アルゴリズムベンチマークのテストデータで、手書き文字よりも難しくなっています。

この URL を http://yann.lecun.com/exdb/mnist/ から http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/ へ変更して、Fashion MNIST も試してみましょう。

Fashion MNIST の説明とレポジトリはこちら

fashion-mnist/README.ja.md at master · zalandoresearch/fashion-mnist · GitHub

ここまで

ひとまずデータの読み込み方法だけでまとめてみました。チュートリアルでいきなり CTFDeserializer を使っていたので、一体なんなんだと思いましたが、ちゃんと Numpy array や Scipy でも利用できるようですね。

次回は、CNTK を実際に使う際にどうやって使っていくか見ていきたいと思います。