読者です 読者をやめる 読者になる 読者になる

がりらぼ

WindowsRuntimeの応援ブログ

Azure Machine LearningとIoTを駆使して室温予測システムを構築してみた

Azure ML Arduino MicrosoftAzure

はじめに

今回は自宅の室温予測システムを構築してみました。
前回はいろいろテキトーに書いてたので今回はかなりまじめに書いていきます。

イメージとしてはNHKNextWorldで描かれてる世界
それをできるだけAzureを駆使して構築してみたいと思います。

システム構成図

システムの構成図はこんな感じ f:id:garicchi:20150301135439p:plain

Arduinoで室温を計測

Azure Mobile Servicesに送信

SQL Azureデータベースに貯めこむ

そのデータを使ってAzure MLであらかじめデータの傾向を学習しておく

Mobile Service Schedulerで毎朝8時にAzure MLからその日の室温の予測値を取得してTweet

Mobile Service Custom APIを使ってWindowsストアアプリに今日の室温予測値を表示

という感じでいきたいと思います。

データ計測部

IoTの定義については人それぞれで違いますが、僕のイメージするIoTとは

今までインターネットに繋がっていなかったデバイスがスタンドアローンにインターネットにつながって、データの計測機器となり、クラウド上にデータを集約させ、機械学習による予測を行い、現実世界にフィードバックを行う

だと思います。

そのためにはパソコンを介することなく、計測機器はスタンドアローンにインターネットにつながってクラウド上にデータを集約させなければいけません。
今回はArduinoとAzure Mobile Servicesを使ってそれを実現してみましょう。

室温を計測するセンサーとしては高精度IC温度センサLM61BIZを使用します。

センサーからの計測値を受け取るマイコンとしてはArduinoを使用します。

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

Arduino単体ではインターネットに接続することはできないのでインターネットに接続してAzure上にデータを貯めこむためにEthernetシールドも使います。

Arduino イーサネットシールド

Arduino イーサネットシールド

f:id:garicchi:20150301140659j:plain

Azure Mobile ServicesにはREST APIというものがあり、HTTP POSTを使うことでデータの挿入など簡単な操作ができる用になっています。
ArduinoEthernetシールドをつけていると、HTTP POSTも可能なので、これでArduinoスタンドアローンにAzureに接続することができます。

millis()関数を利用して1時間に1回、計測データをMobileServiceに送信します。

上記の記事を見ると、センサーの計測値しかデータを送信していません。
室温学習には時間とか日付とかをパラメータとして与えたいのでMobile Serviceのデータ挿入時のスクリプトを編集してデータ挿入時にタイムスタンプをつけるようにしましょう。

これで数時間放置してみると、ArduinoからスタンドアローンにMobile Servicesに計測データが送られていることが確認できます。

f:id:garicchi:20150301142233p:plain

データが足りない問題

さて1時間に1回、Arduinoからクラウド上にデータを集めることができたのであとは2年ぐらい放置すればいい結果が出せそうですね。

はい、そんなに待てません。

というわけで今回は機械学習から予測もしなければいけないので過去データを集めましょう。

ここから気象庁の過去観測データをcsvで取得することができます。

気象庁は外気の温度を測定して僕は室温を測定しているから誤差があるのでは?というツッコミがきそうですが細かいことは気にしちゃいけません。僕の部屋は電気代節約のために常に外気温とほぼ同じです。(たぶん)

csvを落としたらC#のプログラムからMobileServiceへデータを挿入します。
MobileServiceSDKが必要になります。

class temperature
{
    public string Id { get; set; }

    public float value { get; set; }

    public int year { get; set; }
    public int month { get; set; }

    public int day { get; set; }
    public int hour { get; set; }
    public int minute { get; set; }
    public int second { get; set; }

    public string source { get; set; }
}
class Program
{
    public static MobileServiceClient MobileService = new MobileServiceClient(
        "https://***.azure-mobile.net/","{access key}"
        );
    static void Main(string[] args)
    {
        StreamReader reader = new StreamReader("data.csv");

        string line = "";
        int counter = 0;

        var table = Program.MobileService.GetTable<temperature>();


        while ((line = reader.ReadLine()) != null)
        {
            if (counter >= 5)
            {
                try
                {
                    string[] strs = line.Split(',');
                    string[] strs2 = strs[0].Split(' ');
                    string[] dateStr = strs2[0].Split('/');
                    string[] timeStr = strs2[1].Split(':');

                    string temp = strs[1];

                    table.InsertAsync(new temperature
                    {
                        value = float.Parse(temp),
                        year = int.Parse(dateStr[0]),
                        month = int.Parse(dateStr[1]),
                        day = int.Parse(dateStr[2]),
                        hour = int.Parse(timeStr[0]),
                        minute = 0,
                        second = 0,
                        source = "meteorological"
                    }).Wait();
                    Console.WriteLine(line);
                }
                catch (Exception)
                {
                    Console.WriteLine("Error");
                }

            }
            counter++;
        }
        reader.Close();


    }
}

結局Mobile ServiceのデータベースもSQL AzureなのでSQL使えよ!というツッコミがきそうですがSQL Serverにそこまで詳しくないので今回は直接データを送信しまくります。なのでものすごくおそいです。

これで過去3年間の1時間ごとの気温データをMobileServicesに入れることができました。

f:id:garicchi:20150301144208p:plain

機械学習を行う

続いてデータベースに入れた気温データを使ってAzure MLに機械学習をしてもらいます。

全体的なモジュール図?はこんな感じ
f:id:garicchi:20150301144527p:plain

前回の解説があまりにもテキトーだったので今回はガッツリ解説していきたいと思います。

Reader

Readerモジュールは学習と評価に用いるデータをあらゆるところから取得することができるモジュールです。HTTP通信で取得できるCSVやAzureBlobストレージから取得できるcsvからもデータ入力が可能です。
今回用意したデータSQL Azureに入ってるのでSQL Azureから取得してみましょう。

f:id:garicchi:20150301144805p:plain

データベース名やサーバー名、パスワードなどを間違えなければ取得できます。
SQL文を用いて取得するデータを選択することもできます。FROM部には mobileservice名.テーブル名 と指定しないと取得できません。

ProjectColumns

ProjectColumnsとはどのカラムデータを使用するかフィルタリングすることができます。

今回はmonth,day,hour,value (valueは観測室温)の4つを選択します。 f:id:garicchi:20150301145150p:plain

Split

Splitとはデータのレコードを指定した比率で分割するモジュールです。

なぜデータを分割するのかというと、一方は学習に用いて、もう一方は学習したモデルに値を入れて出力された値がどれくらい正しいかを判定する評価に用いるためです。
今回は7割のデータを学習に、3割のデータを評価に使います。

f:id:garicchi:20150301145342p:plain

TrainModelとNeural Network Regression

ここで学習を決定します。
今回は日付と時間から室温を予測するため、予測する値であるvalueをTrainModelで指定します。

f:id:garicchi:20150301145504p:plain

TrainModelのもう一方の入力にはどの学習アルゴリズムで学習するかを決定します。
今回はNeural Network Regressionを用いることにしました。

Regressionとは回帰という意味で、機械学習における回帰とはある要素xをある要素群y,z...から計算する計算式を学習させることにあたります。
つまり今回は室温xを時間と日付から計算する計算式を学習させることになります。

線形回帰であるLinearRegressionなどがありますが、日付と時間に対する気温は必ずしも線形性を持っているとは限らず、非線形性があるため、今回はNeural Network Regressionを用いることにしました。

Score ModelとEvaluate Model

ScoreModelとは一方に学習モデル、もう一方にデータを入力することで学習モデルにデータを入力し、出力することができるモデルです。
今回はもう一方の入力に評価用の3割のデータを入れて、出力します。

Evaluate Modelとは学習評価用のモジュールです。Score Modelから出力された評価用データの出力値と、評価用データの正解値との誤差を出して学習モデルがどれだけ正確に予測できているかを判定します。 f:id:garicchi:20150301150132p:plain

評価結果

では実際に機械学習を動かして評価してみましょう。 f:id:garicchi:20150301150530p:plain

このままだといまいち良い結果なのか悪い結果なのかわからないですよね。
そこで同じデータを使ってLinear Regression(線形回帰)の学習モデルを使って行った評価と比較してみましょう。

やり方はTrainモデルへの入力をLinear Regressionに変更するだけです。
このように機械学習アルゴリズムを一瞬で変更して試せるのもAzure MLの利点ですね。

f:id:garicchi:20150301151900p:plain

Liner Regressionの結果はこんな感じ

f:id:garicchi:20150301151935p:plain

平均絶対誤差は先ほどより大きいし、決定係数は先ほどより小さいです。
よって、Neural Network RegressionはすくなくともLiner Regressionよりは正しく室温予測ができてそうということがわかりました。

学習したモデルをWeb APIとして公開する

学習したモデルはWeb APIとして公開することができます。 f:id:garicchi:20150301152313p:plain

入力はScore Modelに、そして出力もScore Modelからの出力をとることで学習モデルに値を入れて、予測結果を出すことができます。

Web APIとして公開した学習モデルはAPI help pageというものが用意され、HTTP Requestで学習モデルにアクセスする方法が提供されます。

学習モデルに入力する値はHTTPのbodyにjsonとして入れて、POSTします。 f:id:garicchi:20150301152706p:plain

アクセスするためのC#Python、Rのサンプルも用意されます。

f:id:garicchi:20150301152753p:plain

MobileService Schedulerから予測値を取得する

先ほど、API help pageにC#PythonとRのサンプルがありましたがようはHTTP POSTができればAzure MLの学習モデルにアクセスして予測値を取得することができるということです。

というわけで今回はMobile ServiceのSchedulerから定期的にAzure MLに予測値をもらう用にしましょう。

今回のMobile ServiceはJavaScriptバックエンドのため、node.jsによるアクセスになります。

この方法でアクセス可能です。

Schedulerなので定期的にnode.jsのスクリプトを実行できます。

せっかくなので毎朝8時に今日の室温予測値をツイートできるようにしてみましょう。

実際に今日の朝8時に今日の12時の予測室温を自動でつぶやいてました。 f:id:garicchi:20150301153631p:plain

オープンデータとして公開する

さて室温予測値を自分だけのデータとしてためておくのはもったいないのでAzure Custom APIを使ってオープンデータとして公開してみましょう。

先ほどまでに書いたスクリプトからのAzure MLへのアクセス方法を使って、Getリクエストが来た時に今日の室温予測値をすべてjsonで出力してみます。

f:id:garicchi:20150301154157p:plain

これで今流行りのオープンデータにも対応できました。

Windowsストアアプリで現実にフィードバックを行う

データを計測して機械学習しているだけではIoTとはいえません。
適切にユーザーにフィードバックすることで初めて溜め込んだビッグデータ機械学習で予測した予測値は生きていきます。

というわけで先ほどCustomAPIで公開した今日一日の予測値データをアプリでグラフ化してみましょう。

Custom APIでHttp Getさえすれば一日の予測値が出力できるようにしているのでC#からのアクセスも簡単です。

というわけでこんなのを作ってみた。 f:id:garicchi:20150301154517p:plain

右の円がどこかでみたことがある気もするけど気にしない。

今日一日の予測値はいい感じに出てますね。たぶん大体これぐらいだと思います。たぶん

さて、なぜ右の円があるかというと、ただ単に予測値をグラフで表すだけでなく、人工知能っぽく喋らせてみようということで
WindowsRuntimeのSpeechSynthesizerAPIを使って音声合成をしました。

一応こんな言葉を喋らせています

「predict completed. I think... Today expect cold day. Would you wear a coat?」

今回用意したしゃべるパターンは1種類ですが予測室温に対応させていろいろなパターンを用意するとすごく人工知能っぽくなって近未来感でてきますよね。

おわり

今までIoTの時代だIoTの時代だって言って僕はマイコン使ってLチカしてるだけでしたが今回Azureを使って、MicrosoftクラウドとIoTで実現したいんじゃないかなーみたいなことをちょこっとやってみました。

ひとりでに動作するスタンドアローンなセンサーがインターネットにつながってビッグデータを収集。それをクラウド上にある機械学習プラットフォームが解析して今日の室温を予測。

今日が寒くなりそうなら「寒くなりそうだよ?コート着てみたら?」と人工知能がアドバイスをしてくれる。

NHKのNextWorldに描かれた世界に近いものを頑張って作ってみましたが以外に面白かったです。

Azureってすごいですね。(小並