めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Using Cloud Vision API and Cloud Translation API from Google App Engine

qiita.com

This is a Day 7 entry for TensorFlow Advent Calendar 2016 (in Japanese). It's organized by Japan TensorFlow Users Group (TFUG) :)

Recently I had a chance to create a prototype of a photo album application emulating the auto labeling feature of Google Photo. It's running on Google App Engine and uses Cloud Vision API and Cloud Translation API in the background. Cloud Vision API is used to detect appropriate labels for the uploaded photos and Cloud Translation API is used to translate labels in English to some other languages. The target language is specified by the administrator as a deployment option.

Here's a screenshot of the prototype running in the Italian mode. You can see that the labels (tags) are described in Italian.

The full prototype codes is now available on GitHub. I hope you're gonna love it!

github.com

In this note, I will show how you can use those APIs from Python codes running on the GAE standard environment. The good thing is that you don't have to deal with API keys and credentials since API authentication is automatically done on GAE.

First, since the example uses the google-cloud client library, add the following line in requirements.txt.

requirements.txt

google-cloud==0.21.0

Now here's the code snippet for the label detection and the label translation.

from google.cloud import vision, translate

def get_labels(bucket, filename, num=3):
    vision_client = vision.Client()
    image = vision_client.image(
                source_uri = 'gs://%s/%s' % (bucket, filename))
    return image.detect_labels(limit=num)

def translate_text(text, target='en'):
    if target == 'en':
        return text
    translate_client = translate.Client()
    result = translate_client.translate(text, target_language=target)
    return result['translatedText']

It's super easy, yeay!

To use get_label, you specifies the location of an uploaded photo in Google Cloud Storage with the bucket and file names, and the maximum number of labels you need.

To use translate_text, you pass the text string of a label and specify the target language code from the supported languages.

That's all. More details can be found in the library documentation. Enjoy!

導関数が自分自身と一致する指数関数が存在することの説明

何の話かというと

qiita.com

の3日目の記事

qiita.com

で、指数関数 f(x) = a^x において、

  f(1)=x=1のときの接線の傾きの値」

となる a をさがすと、それが a = e = 2.71828\cdots(ふなひとはちにわ)になるんだよ!

という解説があって、ほほぉー、と思いつつも・・・

「この関係は x=1 のときだけに成り立つものではありません。f(x)=e^x では、x がどんな値の時にでもこの関係式は成り立ちます。」

という部分の(なぜそうなるのかという)説明がなかったので、なぜ、すべての x で成り立つのかという説明を補足してみます。

微分の定義

先の記事では、数値微分の例で説明されていますが、一般に、点 x からちょことだけ離れた点 x+hh は0.000001ぐらいの小さい数だとしてください)を考えて、グラフ上の2点 (x,\, f(x))(x+h,\, f(x+h)) を結ぶ直線の傾きを考えてみます。

 傾き =\frac{f(x+h)-f(x)}{h}

これは、点 x における関数 f(x) の傾きの近似計算になるわけですが、ここで、h をどんどん 0 に近づけていくと、その極限として、厳密な傾きの値、つまり、微分係数が計算されます。

 f'(x) = \lim_{h\to 0}\frac{f(x+h)-f(x)}{h} ―― (1)

ちなみに、いま、「微分係数」といいましたが、(1) では、x をいろいろな値に変化させて、f'(x)x の関数とみなしています。このように、x における微分係数を表わす関数 f'(x) を「関数 f(x) の導関数」と言います。特定の定数 x における傾きが「微分係数」で、x を変数とみなしたものが「導関数」ということになります。

指数関数の微分

それでは、指数関数 f(x)=a^x の微分(導関数)を先の定義にしたがって計算するとどうなるでしょうか。

まず、傾きを表わす式の分子を計算すると、次のようになります。

 f(x+h) - f(x) = a^{x+h} - a^x = a^x(a^h - 1)

面白いことに、全体が a^x でくくれてしまいます。

したがって、これを (1) に代入すると、次のようになります。

 f'(x) = \lim_{h \to 0} \frac{a^x(a^h-1)}{h} = a^x \times \lim_{h\to 0}\frac{a^h-1}{h} ―― (2)

極限操作 h \to 0 では、h の値をだんだん小さくするという操作を考えているわけですが、a^xh に依存しない値なので、極限操作の外に取り出せてしまう所がポイントです。

そして! (2) に残った極限値  \lim_{h\to 0}\frac{a^h-1}{h} の中身をよーく見ると、どこにも変数 x が入っていません。もともと、点 x をいろいろ変化させた時に、微分係数がどのようにかわるか、という視点があったのですが、この部分は、微分(傾き)を計算する点 x に関係なく、いつも同じ値になります。

ただし、これが具体的にいくらになるのかを一般の a に対して計算するのは簡単ではありません。(分子も分母もどっちも0に近づいていく「不定形」というやつですね。)

とは言え、a の値を具体的に一つ決めてしまえば、数値計算で求めることは可能です。ちょっと、Pythonで試してみましょう。

$ python
>>> h = 0.00000000001
>>> a = 2
>>> (a ** h - 1 ) / h
0.6931566431944702

本当は、h をどんどん0に近づけるのですが、ここでは、h=0.00000000001 という極端に小さい値を用いて近似計算を行いました。

つまり、a=2 の時、f(x)=a^x の導関数は、(近似計算で)次になることがわかりました。

 f'(x) = a^x \times 0.693\cdots= f(x) \times 0.693\cdots

これは面白い事実を表しています。一般に、「指数関数 f(x) = a^x の導関数は、自分自身を定数倍したものになる」ということですね。指数関数は値が「指数的に」増えていくと同時に、傾きも「指数的に」増えていくというわけです。



・・・ここで問題です!

それでは、この定数  \lim_{h\to 0}\frac{a^h-1}{h} がぴったり 1 になる a を見つけることはできるでしょうか。

・・・がんばりました。

$ python
>>> h = 0.00000000001
>>> a = 2.71828
>>> (a ** h - 1 ) / h
1.000000082740371

・・・いえ嘘です。

答えを知っているので、それを使いました。実は、a = e = 2.71828\cdots となります。これで、

  f(x) = e^x とする時、すべての x について、f'(x) = e^x となる

ということがわかりました。

やったー。

補足説明

ちなみに、定数  \lim_{h\to 0}\frac{a^h-1}{h} がぴったり 1 になる a を見つけるということをやりましたが、よーーーーーく考えると、 \lim_{h\to 0}\frac{a^h-1}{h} は、指数関数 a^xx=0 における傾きそのものですね。非常におもしろいことに冒頭のエントリーで紹介した、「指数関数 a^xx=1 における傾きが f(1) になる a を見つける」という作業によく似ています。特定の点での傾きを決定することが、「すべての x について、f'(x) = a^x となる a」を探すという作業につながっているわけです。なかなか奥深いですねー。

Jupyter演習環境の準備手順

この手順では、メモリが4GB以上、CPUが4コア以上の環境を前提としています。

macOSを使用する場合

  • macOS用のDockerが対応しているのは、Yosemite以降のバージョンです。ここで紹介する手順は、El Captitanで動作確認をしています。

はじめに、Dockerの公式Webサイトから、macOS用のDockerをダウンロードします。「Getting Started with Docker」のリンクからダウンロードページを開いて、「Download Docker for Mac」をクリックすると、インストーラーファイル Docker.dmgがダウンロードできます。インストーラーを開いて、DockerアイコンをApplicationsフォルダーにコピーした後、ApplicationsフォルダーからDockerを起動します。初回の起動時は、インストール処理のポップアップが表示されますので、指示にしたがって、インストールを完了させてください。

インストールが完了してDockerが起動すると、上部のメニューバーにクジラのアイコンが表示されます。ここからDockerの管理メニューを表示して、「Preferences」を選択した後、「Advanced」のタブから「Memory」を4GB以上に設定します。「CPUs」の指定は任意ですが、サンプルコードの実行時間が極端に長くならないよう、4以上に設定することをおすすめします。最後に「Apply advanced settings」を押して、設定変更を反映します。

macOSに付属のターミナルを開いて、下記のコマンドを実行すると、Docker Hubからイメージをダウンロードして、コンテナ上でJupyterが起動します。「\」はコマンドの途中で改行する際に、入力する記号です。

$ mkdir $HOME/data
$ docker run -itd --name jupyter -p 8888:8888 -p 6006:6006 \
    -v $HOME/data:/root/notebook -e PASSWORD=passw0rd \
    enakai00/jupyter_tensorflow:latest

「-e PASSWORD」オプションには、WebブラウザーからJupyterに接続する際の認証パスワードを指定します。この例では、「passw0rd」を指定しています。この手順でコンテナを起動した場合、Jupyterで作成したノートブックのファイルは、ユーザーのホームディレクトリー(/User/<ユーザー名>)の下にある「data」ディレクトリーに保存されます。

macOSでブラウザーを起動して、URL「http://localhost:8888」にアクセスすると、ログイン画面が表示されるので前述のパスワードを入力してログインします。この後は、最後のセクションにある、動作確認に進んでください。

※ macOSを再起動した場合は、ターミナルから下記のコマンドを実行して、コンテナを再度、起動してください。

$ docker start jupyter

パブリッククラウドの仮想マシンを使用する場合

パブリッククラウドの仮想マシン上でDockerを起動して、環境を用意することも可能です。CentOS7のVMインスタンスを起動してログインした後、rootユーザーから、次の手順でコンテナを起動します。

# yum -y install docker
# systemctl enable docker.service
# systemctl start docker.service
# mkdir $HOME/data
# chcon -Rt svirt_sandbox_file_t $HOME/data
# docker run -itd --name jupyter -p 8888:8888 -p 6006:6006 \
    -v $HOME/data:/root/notebook -e PASSWORD=hogehoge \
    enakai00/jupyter_tensorflow:latest

「-e PASSWORD=」には、Jupyterにアクセスする際のパスワードを任意に指定します。ただし、通信経路の暗号化は行われないため、インターネット経由で直接にアクセスするのは危険です。SSHのトンネル機能を用いて、通信経路の暗号化を行ってください。たとえば、Windowsクライアントの環境であれば、Tera TermなどのSSH端末から、次のように8888番ポートと6006番ポートの転送を指定して、SSH接続します。

macOS、もしくは、Linuxクライアントであれば、次のように、-Lオプションでポート転送を指定してSSH接続します。

$ ssh -L 6006:localhost:6006 -L 8888:localhost:8888 -i .ssh/gcp_enakai enakai@xxx.xxx.xxx.xxx

この後、ローカルのブラウザーから、「http://localhost:8888」にアクセスするとSSHトンネルを経由して、Jupyterに接続することができます。ログイン画面が表示されるので前述のパスワードを入力してログインします。この後は、次のセクションにある、動作確認に進んでください。

※ 仮想マシンを再起動した場合は、SSH接続した後に、rootユーザーで下記のコマンドを実行して、コンテナを再度、起動してください。

$ docker start jupyter

動作確認

Jupyterにログインすると「ノートブックファイル」の一覧画面が表示されますが、今はまだノートブックファイルはありません。

右上のプルダウンメニューから「New」→「Python 2」を選択すると新しいノートブックが開きます。

ノートブック上では、セルにプログラムコードを入力して、「▶」ボタン、もしくは [Ctrl] + [Enter] で実行すると結果が表示されます。マークダウン形式のセルには説明文を記載することができます。

ノートブック全体を最初から実行し直す場合は、メニューから「Kernel」→「Restart & Clear Output」を選択して、これまでの実行内容をクリアします。

空のセルで次のコマンドを実行すると、演習用のノートブックがダウンロードできます。

!git clone https://github.com/enakai00/jupyter_ml4se

ノートブックファイル一覧画面でフォルダー「jupyter_ml4se」を開くと、ノートブックファイルが入っています。

「02-square_error.ipynb」のチェックボックスにチェック入れて、画面上部の「Duplicate」を押すと、ノートブックファイルのコピー「02-square_error-Copy1.ipynb」ができます。これをクリックして、ノートブックを開きます。

メニューから「Kernel」→「Restart & Clear Output」を選択して、これまでの実行内容をクリアした後に、メニューから「Cell」→「Run All」を選択すると、すべてのセルが上から順に自動実行されます。すべてのセルが正しく実行されることを確認しておいてください。たとえば、最後の2つのセルでは、次のようなグラフが表示されます。