2017年6月13日火曜日

深層学習を使ってツイッター画像のラベル付けができるまで(3)

深層学習のラベル精度向上のためにやったこと 


前の記事で、無事マルチラベルのラベル付けができる学習モデルが作成できるようになりました。ただ、その精度は納得できるレベルではなかったので、その改善のために「やったこと」と「起きたこと」を説明します。

やったこと1: 教師データを増やす。

精度が低いのは教師データが少ないからだろう、ということで「教師データを増やす」→「学習モデルを作る」→「ラベル付けする」を繰り返します。
するとあることが起きます。それは…
  • トレーニング用データのファイル作成ができなくなる。
エラーログを元に調べてみると、こんな記事を発見。これによると、macのPython3.4で、トレーニング用データをファイル出力するときのライブラリpickleに不具合があることが発覚!

そこでちょっと工夫して、教師データの上限を決めてランダムに選択するようにしてみたがかえって精度が悪くなる結果に。
苦肉の策として画像サイズを128→96にしてみたところ、精度もそれほど大きな違いがなかったのでこちらを採用して教師データを増やすことにしました。
その時の結果はこんな感じ。
  • loss= 0.503688128473
  • accuracy= 0.937188613881


やったこと2: 教師データを見直す。

過去に作成した教師データはラベル付けの基準が今と少し違うのが気になっていたので、改めて教師データを見直して修正。
しかし、見直したあとに作成した学習モデルでも大きな改善はみられず。(loss、accuracyの記録なし)


やったこと3: 期待から外れている画像の教師データを追加する。

毎日ラベル付けを行うようにして、その結果を閲覧、期待から外れている画像を補正のための教師データとして登録。
こうすればもっと精度が高くなることを期待しましたが、意外と精度は上がらず。
逆に大きく外れてしまう(特定のラベルが出やすくなる)事象が発生。


やったこと4: 合議制を導入。

画像サイズをもっと大きくしたり、層を増やしたり、…などが王道だと思われますが、残念ながら現在自宅の旧型mac-miniで頑張っているためマシンパワーは不足しており、さらに、上記の通りmac版のライブラリ不具合が判明しているのでちょっと小細工することに。
癖がある学習モデルから3つを選び、それぞれの分析結果を平均化して0.5以上(つまり、2つのモデルが判定したラベル)を採用することにしました。

現在は、自分としては70点くらいの結果は出ているかな、と思っています。
とは言っても、現在判定できるのは「イラスト」「文字」「ポスター・プラカード」くらいで「写真」の判定ができないのが残念なところです…


■最後に: 今後やりたいこと。

今後、精度改善としてやりたいこと。
  1.  画像サイズを大きくする。純粋にマシンパワーの問題なのでGCP上にTensorFlowで作り直してみたいです。ただ、データ量がそれなりにあるので個人の道楽にしてもいくらになるのか気になるところ。
  2. トレーニング用データのチューニング。現在の教師データはかなり偏りがあるので調整が必要と感じています。やり方はまだわかりませんが。
  3. 画像の別の情報を組み合わせた機械学習。例えば「写真」の判定は、色のスペクトルを取ればある程度判定できるのでは、と思ったり。
深層学習を自分でやってみた結果、細かいパラメータチューニングや、教師データの作成はほとんどブラックボックスなので職人芸が必要なように感じました。そういう意味では、ビジネスチャンスの匂いがします。ちょっと前にこんな記事がありましたし。

また何か実験してみたら報告します。

2017年6月12日月曜日

深層学習を使ってツイッター画像のラベル付けができるまで(2)

深層学習によるマルチラベルのラベル付け


前の記事で、ツイッター画像へのラベル付けの流れを説明しました。
今回は、特に重要なポイントになるラベル付けのための学習モデルをどのように改善していったか説明します。

画像の深層学習には畳み込みニューラルネットワーク(CNN: Convolutional Neural Networks)を使います。(ここでは深層学習については詳しく説明しません。前の記事で紹介した本やこの記事で学習して下さい)


1. まずは動かす。

Pythonによるスクレイピング&機械学習」の7-3をベースに教師データからトレーニング用データを作成し、そのトレーニング用データから学習モデルを作成するコードを作成します。
この時、以下のパラメータをそのまま採用しました。
  • 活性化関数: ReLU、softmax(最後のみ)
  • ドロップアウト: 0.25、0.5(最後のみ)
  • ロス関数: binary_crossentropy
  • optimizer: rmsprop
その他のパラメータは以下で設定。
  • 画像サイズ: 128
  • バッチサイズ: 64
  • エポック(学習回数): 10

■学習モデルのテスト結果

  • loss= 0.263982442949
  • accuracy= 0.917964078352

■サンプル画像でのラベル付け(抜粋)

サンプル画像のファイル名に、期待しているラベルを付けている。
  • sample-calendar01.jpg
    • illust: 1.0
  • sample-capture_text01.jpg
    • text: 3.62731e-12
    • capture: 1.0
  • sample-icon01.jpg
    • icon: 1.0
  • sample-icon06.jpg
    • illust: 3.1109e-17
    • text: 1.0
  • sample-illust_calendar05.jpg
    • illust: 1.0
    • text: 2.97645e-10
そこそこよい感じだが、マルチラベルでの判定になっていない。(実質、一つのラベルになっている)

■マルチクラスとマルチラベル

一つの入力に対して複数(3以上)の分類先がある問題を「マルチクラス問題」と呼ぶそうです。機械学習のサンプルでよく使われるMNISTは、「手書き数字の画像」を0から9のどれかに分類するので、典型的なマルチクラス問題です。
一方、マルチラベルは、一つの入力に複数のラベルがつく問題です。ツイッター画像には「イラスト」「文字」「写真」など一つの画像に複数のラベルが付けたいのでマルチラベルに適したアルゴリズムが必要っぽいです。

2.マルチラベル問題のための設定

単純に教師データが少ないためかと思い教師データを増やしたが変わらず。ドロップアウトのパラメータを変更してみたが変わらず。
ロス関数をbinary_crossentropyからcategorical_crossentropyに変えてみたところ、loss、accuracyの値は変わりましたが、結果はやはりマルチラベルからは程遠い…
また、このサイトの情報によると

  • categorical_crossentropy: 1-of-N (one-hot)  → for multiclass
  • binary_crossentropy: 1-or-more 0/1 labels  → for multilabel
のようです。なのでbinary_crossentropyが正解です。

マルチラベルについて調べたところ、以下のようなメモを発見。
他にソフトマックスではなくてシグモイドに通してloss関数に binary_crossentrpy などfchollet/keras#741予測する時は確率が0.5以上なら採用
ということで、最後のロス関数をsoftmaxからsigmoidに変更したところ、マルチラベルの結果が得られるようになりました!!
※ただ、sigmoidを使う方が良い理由は分からないので、ご存知の方がいましたら教えていただけると嬉しいです。

■学習モデルのテスト結果


  • loss= 0.427535426005
  • accuracy= 0.945025641674 

■サンプル画像でのラベル付け(抜粋)

  • sample-capture_text05.jpg
    • illust: 1.0
    • text: 1.0
  • sample-illust_calendar07.jpg
    • text: 1.0
    • placard: 1.0
  • sample-illust_text01.jpg
    • illust: 1.0
  • sample-illust02.jpg
    • illust: 1.0
    • text: 1.0
    • placard: 1.0
  • sample-placard01.jpg
    • text: 1.0
    • placard: 1.0
  • sample-text01.jpg
    • illust: 1.0
    • text: 1.0
次は精度を高めるための工夫について続きます。

2017年6月11日日曜日

深層学習を使ってツイッター画像のラベル付けができるまで(1)

最近はすっかりAIブームですね。
ということで、流行りの「深層学習」を使って何かやってみよう!と半年くらい色々と試行錯誤してましたが、ある程度形になったので、その時に困ったことなどの技術メモを残します。
これから同じようなことをやってみたい方の参考になれば幸いです。

なお、深層学習の専門家ではないので、用語などの間違いはご容赦下さい。
教えていただけると助かります m(_ _)m

テーマと結果

やったこと

やったことの流れと概要を以下に記載します。
  1. ツイートの収集: Twitter APIを使ってツイートを収集する。ツイートはmongoDBに保存。
  2. ツイート画像のダウンロード: 収集したツイートの中のentities.media.media_urlのURLから画像ファイルをローカルPCにダウンロードして保存。ツイートを見ると画像があるのにmedia_urlの存在しないツイートがあるため全ての画像が取れるわけではない。
    ※本当は全画像を分析したいのですが…誰かご存知の方、教えて下さい。
  3. 教師データの作成: 手作業で画像一つ一つにラベル付けを行う。ラベル付けのためのツールをnode.jsのアプリとして作成。(Google Cloud Vision APIを使って教師データを作る方法を考えたが、残念ながら自分の期待したラベルがつかなかった。教師データ作成は深層学習の課題になりそう。)
  4. トレーニング用データの作成: 学習モデルを作成するために、リサイズした画像データとラベルのペアにして一つのファイルにまとめる。「トレーニング用」と「テスト用」に分ける。ランダムで分けるコードにしているため、複数回実行すると毎回異なる(はず)。
    オリジナル画像の縦横比は気にしないで全て1:1になるようにリサイズする(これでも上手くいっているように見えるのが不思議…)
  5. 学習モデルの作成: 参考テキストの「第5章 深層学習に挑戦しよう」を参考にしてKeras(裏で動くライブラリはTensorFlow)を使ってコーディングし、学習モデルを作成。
  6. サンプル画像のラベリング(学習モデルの確認): 特徴的な画像をサンプルとして用意しておき、作成した学習モデルでのラベリング結果をみる。
  7. ツイート画像への適用: サンプル画像のラベリング結果でOKと判断した場合、ツイート画像へ適用する。
最初は「よい学習モデル」ができなかったため、工夫して3〜6を繰り返し、学習モデルの改善をしていきました。

この改善ノウハウついて次回説明します。




2015年3月8日日曜日

Offlineでもgeolocationが使えるWebViewを使ったAndroidアプリを作る

前の記事で書いた通り、「AndroidのWebブラウザでは、電波のないところでの位置情報取得は基本的には不可」です。そこで、Webアプリを表示するWebViewだけを持つネイティブアプリを作り、HTML5の機能が動作する設定をすることでWebアプリ側を改修せずにAndroidでも使えるようになります。その作り方を紹介します。


1. Webアプリを読み込むAndroidアプリを作成

  • Android Studioでプロジェクトを作成する。
    • Blank Activityをベースにした場合、APIレベル14(Android4.0)以降で作るとActionBarActivityを継承するが、アクションバーは使用しな場合はActivityの継承に変更するのがオススメです。
  • ネットアクセスのpermissionを設定する。
    • AndroidManifest.xmlにpermissionを追加
  <uses-permission android:name="android.permission.INTERNET" />
  • 回転できないように縦方向で固定する。
    • AndroidManifest.xml内の要素activityの属性に"android:screenOrientation="portrait"を追加
<activitiy ...
    android:screenOrientation="portrait"  >
 ...
  • アプリ起動時にjavascriptを有効にしてWebアプリを読み込む。
    • WebViewを配置 (id = webView)
    • 起動時のActivityクラス(Javaファイル)のonCreateメソッドに以下を追加
    WebView myWebView;
    String urlTop = "http://www.example.com";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        setContentView(R.layout.activity_trek_log_view);
        myWebView = (WebView) findViewById(R.id.webView);
        WebSettings webSettings = myWebView.getSettings();
        //javascriptを有効にする
        webSettings.setJavaScriptEnabled(true);
        myWebView.setWebViewClient(new WebViewClient());
        myWebView.loadUrl(urlTop+"index.html");
    }
※参考:Androidのwebviewとか。

これでWebアプリをAndroidのネイティブアプリとして起動できます。
ただ、このままではHTML5の機能が使用できないため追加の実装を行います。

2.HTML5の機能を有効化する

  • HTML5のlocalStorageとapplication cacheを有効にする。
    • ActivityクラスのonCreateメソッドに以下を追加
        //localStorageが使用できるようにする
        webSettings.setDomStorageEnabled(true); 
        //application cacheを有効にする
        webSettings.setAppCacheEnabled(true); 
        //application cacheのキャッシュ先を指定
        webSettings.setAppCachePath("/appcache/"); 
        //引数は「キャッシュが存在する場合はそれを使用、ない場合はネットワーク経由で取得」
        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  
  • 位置情報取得を有効にする。
    • AndroidManifest.xmlにpermissionを追加
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission
        android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    • ActivityクラスにInterface「LocationListener」を実装する
public class TrekLogView extends Activity
    implements LocationListener{
    • LocationListenerで実装が必要なメソッドをオーバーライドする
    @Override
    public void onLocationChanged(Location location) {}
    @Override
    public void onProviderDisabled(String provider) {}
    @Override
    public void onProviderEnabled(String provider) {}
    @Override
    public void onStatusChanged(
        String provider, int status, Bundle extras) {}
    • HTML5のgeolocation APIを有効化
        webSettings.setGeolocationEnabled(true);
        myWebView.setWebChromeClient(new WebChromeClient(){
          @Override
          public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                callback.invoke(origin, true, false);
          }
        });
  • アプリ初回起動時(onCreate)に位置情報取得を起動
    LocationManager locationManager;
    String bestProvider;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        initLocationService();
   }
    //初回起動時に実行する
    protected void initLocationService() {
        locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
        bestProvider = locationManager.getBestProvider(criteria, true);
    }
  • アプリ復帰時(onResume)に位置情報取得を再開、停止時(onPause)に停止する
    @Override
    protected void onResume() {
        super.onResume();
        locationManager.requestLocationUpdates(bestProvider, 60000,1, this);
    }
    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

これでapplication cache/localStorage/geolocation APIを使ったWebアプリをAndroidのネイティブアプリとして起動できます。

※参考:
  1. WebView で Web Storage / Web SQL Database を利用する設定
  2. AndroidのWebViewをできるだけ速く表示する(キャッシュ・先読み編)
  3. AndroidのWebView内でgeolocationを使う
  4. 条件にあう位置情報プロバイダから、位置情報を利用する簡単な例

3.WebViewを使ったWebアプリの使い勝手を改善

WebアプリをAndroidアプリにしたことで使い勝手が悪いところがあるため改善します。
  • Android端末の「戻るボタン」でWebアプリの「戻る」を割り当てる。
    • ActivityクラスのonKeyDownメソッドにオーバーライドする
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) &&  myWebView.canGoBack()) {
                myWebView.goBack();
                return true;
            }
            return super.onKeyDown(keyCode, event);
        }
    

  • 特定のURLを持つサイト(map.html)は外部アプリを起動(Intent)する。
    • Activityクラスに以下を追加、変更。
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    myWebView.setWebViewClient(new MyWebViewClient());
    ...
}
...
private class MyWebViewClient extends WebViewClient {
   @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        boolean isMyLogPublicHost = Uri.parse(url).getHost().equals("www.example.com");
        boolean isMyTestHost = Uri.parse(url).getHost().equals("www.test.com");
        boolean isMyHost = isMyPublicHost || isMyTestHost;

        // 特定ホスト名、かつ、特定文字列を含むURLの場合はWebView内で画面遷移させる
        if (isMyHost && Uri.parse(url).getPath().indexOf("map.html") == -1) {
                return false;
        }
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

これで一通り使えるようになりました。
※参考: Building Web Apps in WebView

4.まとめ

最後に、今回作ったソースコードをまとめて載せておきます。
  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.appspot.yamanobo.myapplication" >
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission
        android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
  • MainAcitivity.java
package com.example.myapplication;

import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;


public class MainActivity extends Activity implements LocationListener {

    WebView myWebView;
    String urlTop = "http://trek-log.appspot.com/";
    LocationManager locationManager;
    String bestProvider;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setContentView(R.layout.activity_main);
        myWebView = (WebView) findViewById(R.id.webView);
        WebSettings webSettings = myWebView.getSettings();
        //javascriptを有効にする
        webSettings.setJavaScriptEnabled(true);

        //localStorageが使用できるようにする
        webSettings.setDomStorageEnabled(true);
        //application cacheを有効にする
        webSettings.setAppCacheEnabled(true);
        //application cacheのキャッシュ先を指定
        webSettings.setAppCachePath("/appcache/");
        //引数は「キャッシュが存在する場合はそれを使用、ない場合はネットワーク経由で取得」
        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

        webSettings.setGeolocationEnabled(true);
        myWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                callback.invoke(origin, true, false);
            }
        });

        myWebView.setWebViewClient(new MyWebViewClient());
        myWebView.loadUrl(urlTop+"index.html");

        initLocationService();
    }

    //初回起動時に実行する
    protected void initLocationService() {
        locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
        bestProvider = locationManager.getBestProvider(criteria, true);
    }

    @Override
    protected void onResume() {
        super.onResume();
        locationManager.requestLocationUpdates(bestProvider, 60000,1, this);
    }
    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

    @Override
    public void onLocationChanged(Location location) {}
    @Override
    public void onProviderDisabled(String provider) {}
    @Override
    public void onProviderEnabled(String provider) {}
    @Override
    public void onStatusChanged(
            String provider, int status, Bundle extras) {}

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) &&  myWebView.canGoBack()) {
            myWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            boolean isMyPublicHost = Uri.parse(url).getHost().equals("www.trek-log.com");
            boolean isMyTestHost = Uri.parse(url).getHost().equals("www.trek-log-dev.com");
            boolean isMyHost = isMyPublicHost || isMyTestHost;

            // 特定ホスト名、かつ、特定文字列を含むURLの場合はWebView内で画面遷移させる
            if (isMyHost && Uri.parse(url).getPath().indexOf("map.html") == -1) {
                return false;
            }
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(intent);
            return true;
        }
    }
}
  • 調査/開発用のAndroid端末としては ASUS ZenFone5 (Android 4.4.2)を使用しています。

5.残りの課題

まだ一部未解決のものがあります。
  • Offline時にはトップページのツイッターボタンは非表示としているが表示されてしまう。
  • 左上のロゴからトップに戻るとレイアウトが不完全になることがある。(初回使用時に発生しやすい。キャッシュが不完全の可能性がある)
また、application cacheの更新の検証はしていないので、引き続き確認したいと思います。

2015年3月7日土曜日

Offline時のWebアプリでの位置情報取得について

山登りが趣味なので、手軽に位置情報と一緒にメモを記録するアプリを作りました。
iOS/Androidの両方で使えるようにHTML5のアプリケーションキャッシュを使ってOfflineでも使えるようにしました。
で、せっかくなので二つのイベントに応募しました。
ただ、自分はiPhoneユーザーなのでiPhoneでの動作確認はできていたのですが、動作確認用にAndroid端末を購入して試したところ動作しない(位置情報がほとんどとれない)ことが判明。そこで調査を行いました。

結論から言うと、

「AndroidのWebブラウザでは、電波のないところでの位置情報取得は基本的には不可」

です。ただ、WebViewだけの簡単なAndroidアプリにすれば位置情報がとれることがわかりました。そこで技術メモとして公開します。

Offline位置情報取得の問題点

山では電波の通じないところがほとんどなので、このWebアプリは(Webアプリなのに)Offlineで使う前提になります。また位置情報を取得するためにGPSの情報を取得する必要があります。
なので、Webアプリのキモになる技術は、HTML5の
  • geolocation API
  • application cache
  • localStorage API
になります。それぞれの機能は特別ではなく、ググればたくさん情報が見つかるため、基本的な機能は実装できるのですが、いざ山で使ってみると位置情報が取れない、正しくない、などの事態が発生。geolocation APIが曲者でした。

iPhoneでの注意点

iPhoneでも少しクセがあったのでメモしておきます。
  • 「機内モード」ではGPS機能も停止してしまう
    → バッテリー消耗をきにする場合は「機内モード」ではなく「モバイルデータ通信」と「Wi-Fi」をOFFにすること(もちろん、「位置情報サービス」はON)
  • 位置情報はキャッシュされてしまう様子。そのため、正しい位置情報が記録されない
    → 位置情報取得を3回実行して、3回目の結果を採用する ※あくまで暫定対応なので改善の余地あり。
これらは原因がわかったのでまだよかったのですが、Androidではほとんど位置情報がとれませんでした。(たまにとれることはありました)

Androidでの調査結果

そこでAndroidについて色々調べてみたところ、Stack Overflowでも同じような質問が出ていました。
他にも「html5 offline geolocation」でググると色々出てきますが解決策は特に見当たりませんでした。(ほとんど英語なので見落としてたかもしれませんが…)
なので、自分で端末を実際にいじって調査しました。結果は以下の通りです。
  1. Google Mapを起動するとステータスバーにGPSマークが出て、アプリを閉じるとマークが消える。
  2. Webブラウザでgeolocation APIを実行しても、ステータスバーにGPSマークが出ない。
    ※Androidの位置情報モードを「端末のみ(GPSで現在地を特定する)」にしていても同様。
  3. 位置情報を使用するネイティブアプリ(以下、サンプルアプリ)を作成して実行したところ、Google Mapと同じようにGPSマークが表示される。 ※参考:条件にあう位置情報プロバイダから、位置情報を利用する簡単な例
  4. サンプルアプリで、アプリがバックグラウンドに行った時にも位置情報取得を継続するようにしておく(つまり、OnPause()時に何もしない)と、このアプリを閉じてもステータスバーのGPSマークは残ったままになる。この状態でWebブラウザでgeolocation APIを実行すると位置情報がとれる!
  5. Androidの「設定>位置情報」に表示される「最近の位置情報リクエスト」では、ブラウザ(Chrome)は「低い電池使用量」だが、Google Mapやサンプルアプリは「高い電池使用量」である。
※調査用のAndroid端末としては ASUS ZenFone5 (Android 4.4.2)を使用しています。

これから、

「AndroidのWebブラウザでは、電波のないところでの位置情報取得は基本的には不可」

と結論づけました。しかし、4.の結果からWebViewだけの簡単なAndroidアプリを作ったところ位置情報を取ることができました。

ただ、WebViewでHTML5の機能を使ったり、ネイティブアプリとして操作できるようにするには少し工夫が必要だったため、それはまた次回紹介します。

2012年3月17日土曜日

inputタグのpatternについて


HTML5で追加されたinputタグの属性patternでは正規表現で入力文字チェック出来るとのこと。このサイトにサンプルコードがあるので試してみた。
http://www.htmq.com/html5/input_pattern.shtml


チェックのタイミングはsubmitの時なんですね。。。
buttonにクリックイベントつけてjavascript使う場合はチェックしてくれない。残念ながら使えないなぁ。
入力時に即時チェックしてくれることを期待してたのですが。

あと、Chromeで実装されているけど、Safari5.1.3(mac)では実装されてませんでした。


深層学習を使ってツイッター画像のラベル付けができるまで(3)

深層学習のラベル精度向上のためにやったこと  前の記事 で、無事マルチラベルのラベル付けができる学習モデルが作成できるようになりました。ただ、その精度は納得できるレベルではなかったので、その改善のために「やったこと」と「起きたこと」を説明します。 やったこと1: 教師...