AndroidでgRPCクライアント

AndroidでgRPCクライアントの実装をしようと思ってチュートリアル読んだけど、すっと分からなかったのでメモ。まずは、Goで簡単なgRPCサーバーとクライアントを実装、その後クライアントをAndrodアプリとして実装する、というのをやってみました。

実装してみたソースコードはここです↓

github.com

gRPCがどんなものなのか触る

まず、Goで実装してみる。以下の記事が進めやすかったです、ありがとうございます。

zenn.dev

この記事の通りに進める。

  • protoファイルでクライアント・サーバー間のインタフェースを定義する
  • protocコマンドでprotoファイルからクライアントとサーバーの通信部分についてコード自動生成する
  • 自動生成したコードを利用するサーバーとクライアントを実装し動かして雰囲気を掴む

クライアントをAndroidアプリで実装する

上記のGoで実装したクライアントはCLIを持つプログラム。このクライアントをAndroidアプリにしてみる。

gRPC公式のQuick start

まずはgRPCの公式ドキュメントのAndroidのページを見に行く。

Quick start | Kotlin for Android | gRPC

以下のプロジェクトを使って説明されている。確認したときの最新のtagは v1.3.0

grpc-kotlin/examples at v1.3.0 · grpc/grpc-kotlin

このプロジェクトはgradleで構成されている。色々あってどこを見ればいいかすぐに分からなかったけど、AndroidアプリでgRPCクライアントについては3つのディレクトリ(Gradleのモジュール)だけを見れば良い。

examples/protos はprotoファイルが置いてあるモジュール。 examples/android はgRPCクライアントとなるAndroidアプリのモジュール。

では example/stub-android は?

stub

example/stub-android は、protoファイルからクライアントコードを自動生成するためのモジュール。生成されたクライアントコードをstubと呼ぶ。クライアントとなるAndroidアプリのソースコードからstubのメソッドを普通のメソッドとして呼び出すが、stubが提供しているメソッドの実態はサーバー側で実装されている。つまり、RPCとなる。

ユニットテストで仮の実装としてスタブという言葉を使うことがあるけど、仮の実装というわけではない。

stubについて、gRPC公式で軽く触れられている

Androidアプリつくる

上記のexampleを参考に作ってみた。

github.com

project_root/app がAndroidアプリで、公式exampleの android に相当する。

このAndroidアプリは client_stub モジュールに依存する。他にもgRPC関連のライブラリにも依存する。

dependencies {
    implementation(project(path: ":client_stub"))
    ...

    // gRPC
    implementation("io.grpc:grpc-kotlin-stub:$grpc_kotlin_version")
    implementation("com.google.protobuf:protobuf-kotlin-lite:$protobuf_version")
    implementation("io.grpc:grpc-android:$grpc_android_version")
    implementation("io.grpc:grpc-okhttp:$grpc_android_version")
}

app/build.gradle

client_stub はprotoファイルからコード自動生成するモジュール。Android Libraryモジュールとする。

公式exampleの build.gradle を参考に色々いじってみる。

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:$protobuf_version"
    }
    plugins {
        java {
            artifact = "io.grpc:protoc-gen-grpc-java:$grpc_version"
        }
        grpc {
            artifact = "io.grpc:protoc-gen-grpc-java:$grpc_version"
        }
        grpckt {
            artifact = "io.grpc:protoc-gen-grpc-kotlin:$grpc_kotlin_version:jdk7@jar"
        }
    }
    ...
}

client_stub/build.gradle

以下の3つそれぞれとprotocコマンドとの対応をイメージすると把握しやすい。Java実装のstubを自動生成しないといけないというのが最初とっつきづらかった。

  • com.google.protobuf:protoc
    • protoc コマンド自体
  • io.grpc:protoc-gen-grpc-java
    • Javaで実装されたstubを生成
    • Goの例で言うと protoc コマンドのオプション --go-grpc_out--go-grpc_opt
  • io.grpc:protoc-gen-grpc-kotlin
    • Kotlinで実装された上記のJava実装stubのラッパー

protocから自動生成したstubをAndroid Libraryモジュールとして、 project_root/app から参照できれば、あとは公式exampleのandroidを見ながら実装すれば良い。

おしまい

protocコマンドで生成できるととっつきやすいのですが、Android Libraryモジュールにしたい場合はGradleでやれると楽ですねぇ。今回は client_stub を同一プロジェクトにしましたが、別リポジトリとしてaarをpublishするのが良さそうです。

確率木って便利ですよね・・・?

この記事は統計学 Advent Calendar 2022 24日目の記事です!

確率木というのを Head First Statistics という本で知りました。

条件付き確率とベイズの定理について確率木を使うとすごく分かりやすいなぁと思ったのですが、この本以外では見かけたことがなく何か良くない点もあるのでしょうか・・・?もしあるなら知りたい・・・!

確率木を使ってみる

例として、統計Webの問題をやってみます。

3つの袋があり、次のように赤い玉と白い玉が入っています。

  • 袋1:赤い玉4つ、白い玉1つ
  • 袋2:赤い玉3つ、白い玉3つ
  • 袋3:赤い玉2つ、白い玉4つ

いずれかの袋から玉を1つ取り出したところ、白い玉でした。この玉が袋2から取り出された確率はいくらでしょうか。

10-4. ベイズの定理 | 統計学の時間 | 統計WEB

まず3つの袋のどれかを選びます。次にそれぞれの袋について赤or白を選びます。これを以下のような木で表現します。

確率木の枝に、その枝が選ばれる確率を書きます。袋はどれを選ぶ確率も同じ  1/3 です。

枝の確率をすべて足すと  1 になりますね。

確率木は1つの節から生えている枝の確率をすべて足すと  1 になります。例えば、袋1から生えている各枝の確率をすべて足すと  1 です。

袋1には、赤い玉4つ、白い玉1つ、全部で5つ入ってます。袋1から玉を1つ取り出すとき、赤い玉の確率は  4/5 、白い玉の確率は  1/5 です。袋2, 3についても同じように確率が分かるので、それぞれ確率木に書き込みます。

根から袋1の枝の確率は  P(袋1) = 1/3 、袋1から白の枝の確率は  P(白|袋1) = 1/5 です。葉の位置する「袋1かつ白」となる確率  P(袋1 \land 白) は葉に至るルートの確率をすべて掛け算すればいいことになります。

白玉を選ぶ場合の確率をすべて書き込みます。

知りたいことは、 いずれかの袋から玉を1つ取り出したところ、白い玉でした。この玉が袋2から取り出された確率はいくらでしょうか。 なので以下の条件付き確率を求めます。

 \displaystyle
P(袋2|白) = \dfrac{P(袋2 \land 白)}{P(白)}

分子の値はすでに分かっています。分母の  P(白) 、つまり白玉を取り出す確率は、確率木を見ると白玉を選ぶ葉の確率を全部足せば良いのですぐに分かります。

 \displaystyle
\dfrac{P(袋2 \land 白)}{P(袋1 \land 白) + P(袋2 \land 白) + P(袋3 \land 白)}\\
= \dfrac{1/6}{1/15 + 1/6 + 2/9}\\
\fallingdotseq 0.366

これで求めることができました。

おしまい

最後の式はベイズの定理  P(B_i | A) = \dfrac{P(B_i)P(A|B_i)}{\sum_{j=1}^{k}P(B_j)P(A|B_j)} に当てはめた形になっているわけですが、公式はあんまり覚えてないし、ベン図での定理の説明も分かった気はしているのだけどスッと解けないみたいな状態でした。

確率木に出会ったことで直感的に腑に落ちたように感じることができて、とても良かったです!

苦戦しながら統計検定2級に合格した

統計検定2級に合格したのだけど、ググると出てくるような「合格する方法!」のようにはいかず大変でした、という日記です。

きっかけ

統計学をちゃんと勉強したことがなく苦手意識がとても強かったのです。過去に簡単そうな書籍を読んだことはありましたが、なんとなく分かった気になるが何も分かっていない、という状態のままであり苦手意識はずっと残ったままでした。

統計検定を受けようと思ったきっかけは、ソフトウェアの品質についてもっと工学的にアプローチできるようにしたいなぁと書籍や論文をチラ見している中で統計学の話が出てくると読み進めることができず、「これは苦手意識を克服する必要があるぞ」と決心し勉強を始めました。

どれくらい勉強すれば良いのか見当がつかなかったので、資格試験に合格するというのが分かりやすいと思いマイルストーンとして置きました。

結果

4月5月に結構勉強しました。過去問を大体解けるようになってきたので6月に受験。しかし、時間が全然足りない・・・!そう、ちゃんと時間を測って通しで過去問をやっていなかったのです。こんなに時間が足りないとは・・・。まぁいけるんじゃないかなぁと思っていたのでショックを受けていったん勉強を止めてしまいました。

しかし、10月中旬になり、勉強を止めてしまったことにモヤモヤし始めてきたので、もう一度チャレンジすることにしました。ここでグッと理解度が深まったような気がしています。そして11月に合格!!

このように、一度挫折したのですが最終的には持ち直しました。はー、よかった。

勉強したこと

まず 数学ガールの秘密ノート/やさしい統計 を読みました。平均や分散、標準偏差、期待値という言葉の意味、それから記述統計と推測統計の違い、これらのことを理解しました。過去に別の本で読んで分かった気になってちゃんと分かっていなかったことの輪郭が徐々に見え始めてきました。本の最後の方で仮説検定の話題が出てきますが、よく分からないまま読み飛ばしました。

次に、改訂版 日本統計学会公式認定 統計検定3級対応 データの分析 を読みます。受験するのは2級ですが、まずは3級の公式テキストで勉強を始めました。練習問題を解きながらじっくりと。条件付き確率とベイズの定理のところが若干引っかかるものの練習問題はとりあえず解けるという感じ。区間推定と仮説検定もなんとなくこんな感じかなーというところで先へ進みます。

本じゃなくて 統計Web というサイトの「Step1. 基礎編」をやります。統計Webには本当にお世話になりました!過去問を解いていてなんだっけ?となったら読み直すというのを何度も何度もやりました。スマホでも見れるのが良い!

そして、日本統計学会公式認定 統計検定 2級 公式問題集[2018〜2021年]。2級の過去問集です。上記の3つを一通り読み通りしてから過去問をやりました。理解が浅いところは復習して解き直します。

ここまでで過去問は大体解ける!と思ったのですが、先述した通りいざ試験を受けると時間が全く足りず不合格。一度やる気を失いしばらく時間が空きます。

再度勉強しよう!となって読み始めたのがHead First Statistics ―頭とからだで覚える統計の基本です。オライリーなら良さそう、しかも Head First C が良かった思い出があるのでこれも良いはず、という気持ちでなんとなく読み始めました。この本は推定と仮説検定については入り口くらいまでしか書かれていないのですが、確率と確率分布、期待値、分散といった話題がとても丁寧に書いてあり、やる気を失う前に勉強したことを思い出しつつさらに理解を深めるのにとても良かった。ちなみに、この本で知った確率木のおかげで条件付き確率とベイズの定理はすごく分かるようになりました。

そこから再び過去問と統計Webを行ったり来たりするわけですが、参考書籍として統計学入門 (基礎統計学Ⅰ)も読み始めます。この書籍は通称赤本として色々なサイトでも紹介されてました。どうにも腹落ちしないなぁという部分はこの赤本をじっくり読むとなるほどねー!となりました。

おしまい

最初の不合格でやる気を失ったあと諦めなくてよかったです。合格するほどの知識は身についていなかったけど、なんかすごい、面白いぞ、という感情が芽生えるくらいには学習できていたのが良かったのかもしれません。苦手意識があることを補強できるかどうかは、チャレンジし始めてから頑張れている間に何となく面白そうだぞとポイントを見つけられるかどうかが大事なのかもしれないな〜。