MOB-LOG

モブおじの記録 (Programming, 統計・機械学習)

Coffee調達 in Finland #3—ハンドドリップ編—

はじめに

本記事は 海外TUT Advent Calendar 2023 の20日目に寄せた記事です(大遅刻)。

FIは物価が高く、おいしいものを摂取するには高いお金を払わなければなりません。ならば普段飲むコーヒーはできる限り旨くQoLをキープして、最低限文化的な留学を送りましょうというシリーズです。今回はハンドドリップ抽出のレシピを改善する記事です。

TL;DR

フィンランドでいろいろなコーヒー豆を試して美味しいハンドドリップコーヒーを飲むためにレシピ最適化アプリを作った。」

コーヒーのハンドドリップ抽出のレシピを考えるとき、できるだけ美味しくなるようにヒトのセンスでパラメータを変更して改善しますが、

  1. 豆ごと(産地・焙煎度合い)に抽出する方法は異なるはずだが、それぞれの豆に合わせてレシピを考えるのが困難、
  2. ひとりの味覚・個人のセンスでレシピを改善していて果たして最善のレシピにたどり着けるのか、

という問題があります。そこで、個人の味覚に依らず統計的にレシピを改善するモバイルアプリを開発することにしました(Human in the Coffee Loop: HitCL)。ハイパーパラメータ最適化手法を使ってレシピを自動提案し、個人の味の評価に合わせて最適化していきます(いずれユーザー間でデータを統合して個人の味覚に依らない最適のレシピを作りたい)。なので人間は提案されたレシピに従ってコーヒーを淹れその味の評価を行うだけで、何も考えず旨いコーヒーを淹れて飲むマシンと化します。

現状は一般未公開ですが(かつ1つのユーザのデータに依存して最適化)、いずれ公開し、ユーザからのデータを集めることで複数ユーザの嗜好を基に最高の1杯を作り上げるつもりです。

背景

ハンドドリップで淹れるのが自由度が高くコスパが良い方法です。ただし豆によってはえぐみが強かったりするので、抽出時間やら湯温を変えレシピを整える必要があります。つまり美味しく入れようとすると面倒なので、ひとによっては続かずに断念してしまいます。またせっかくロースターから買った美味しい豆を淹れ方次第でまずくするのは非常に残念です。

ハンドドリップ (hand pouring) を面倒にする要素はおよそ以下の3つ

  1. 豆を自分で挽くのが面倒。 セラミックのミルだと確かにめっちゃ時間が掛かる(挽くのが時間が掛かるからインスタントに戻ったという人もいる)
  2. 器具が高い。 しっかりとしたミルを用意すると 15,000JPY やら 電動なら高くて60,000 JPYする。
  3. レシピを考えるのが面倒。 メモして味見して変更して、というのを頭で考えるのは非常に面倒。忙しい人には無理。

1は豆で買うことを前提としていますが(レギュラーより豆の方が旨いので)、 高い金属ミルを使えば何とかなります (KinGrinder K, P、TimeMore C、Commandante 、ミルっこ、Kalita Next G、など)。なので実質1は2と実質等しいですが、1万円を超える手動ミルは一生ものなので償却されません(つまり資産!!親から子へ引き継ぎましょう)。

つまり最終的にはレシピを考えるのに時間的、精神的に面倒だという部分がネックになります。でそもそもレシピってなんだ、ということですが、まず淹れ方の流儀が様々で例えば第15代ワールドバリスタチャンピオン(2012年)である井崎英典さんが薦めているのは、3回に分けてお湯を注ぎ、注ぐタイミングと湯量を調整するというものです。(1回で全部注いでええやろ、とか4回だとかいろいろな淹れ方がありますが、今回は井崎式のみを考えます)

お湯の温度、蒸らし時間、3回分の投入タイミング・量、スピニング・リンスの有無、豆と出来上がり量の比など、パラーメータの数が15項目ほどあります。私は毎日最低400gのコーヒーを淹れますが、忙しいのでそんなに考えている暇はありません(次第に適当になって、豆に関わらずバリスタおすすめのプリセットで済ませたりすることになります)。ともあれもっとおいしいコーヒーが飲みたいので「何にも考えないで美味しいレシピが欲しい」がふんわりとした要求になります。

ある豆に関してコーヒーレシピの最適なパラメータを求める問題は、単純においしさを最大にする最適解を求める問題は、$\bold{X}_\mathrm{awesome}= \underset{\bold{X}}{\mathrm{arg}} \mathrm{min} f(\bold{X},b)$と表せます(豆$b$についてパラメータ$\bold{X}$からおいしさ$y=f(\bold{X},b)$を最大化する。$f(\sdot)$はブラックボックス(世界の心理)なので深く考えません)。つまり既存の統計・機械学習のアプローチで解決できるって話です。後はヒトが使いやすいインターフェースを作るだけ、ということで作りました。

手法

ヒトが手軽に触れるインターフェースとして、モバイルアプリとして実装します。今回はGoogleさんのFlutterを使用します *1。そしてパラメータの最適化にはOptunaというパッケージを使います(Preferred Networks)。Genetic algorithmであったり焼き鞣し法のような他の典型的な手法でもいいんじゃないかという話がありますが、Optunaを利用すると比較的簡単に実装できるため、これを使用します*2

(開発の詳細、技術面は 『コーヒードリップレシピのパラメータ最適化 Human in the Coffee Loop (HitCL) モバイルアプリ』 にあります)

細かいことは以下の通り。

  • 評価方法:酸味・苦味・うま味・香り・えぐみを7段階で評価する。
  • 最適化条件:コーヒー豆別、ユーザー別で、評価値(=酸味+苦味+うま味+香り-えぐみ)を最大化する。
  • 器具:(今のところ) ドリッパーはV60、グラインダーはTIMEMORE C3で固定。温度調整できるコーヒーケトルと0.1g刻みで重さをはかるスケールが必要。
  • 最適化するパラメータ:
    • (お湯の注ぎ量の総量は400g=2杯分で固定)
    • 豆の挽きの細かさ(グラインダーのクリック数)
    • 湯温(℃)
    • リンスするかどうか(ペーパーフィルターをお湯ですすぐやつ)。
    • お湯対コーヒー豆の重量比 [g/g] (コーヒーの濃さが変わる)
    • 1投目(蒸らし):
      • 注ぎ量 [g]
      • 注ぎ時間 [sec](0秒—何秒までで上の注ぎ量をそそぐか)
      • 蒸らし時間(0秒から2投目まで時間)
      • スピニングをするかどうか(boolean)
    • 2投目:
      • (注ぎタイミング:蒸らし時間と同じ)
      • 注ぎ量 [g]
      • 注ぎ時間 [sec]
    • 3投目:
      • 注ぎタイミング [sec]
      • 注ぎ量 [g]
      • 注ぎ時間 [sec]
      • スピニングするかどうか(boolean)

アプリ概要 (Human in the Coffee Loop)

ヒトがやることは

  1. 淹れるコーヒー豆を選んで、
  2. レシピをリクエストし、
  3. レシピ通りコーヒーを淹れて、
  4. 飲んで評価する、

だけです。後は勝手にコーヒーがおいしくなっていきます。

メリットとデメリットは以下の通り。

  • なにも考えずに毎日コーヒーを淹れるドリップマシンになれる(レシピを考えなくていい)。
  • 最適化の速度が遅いため(ベストにたどり着くことはあるのか?)、淹れすぎ飲みすぎてしまうこと(カフェイン量を考えると毎日400gを2試行までしか回せないのでもどかしい)。
  • ハンドドリップは時間が掛かる(慣れたので自分は感じないが、面倒な人はいそう)。

レシピを考える時間が省略されたのと、確実にそれなりに美味しいコーヒーが淹れられるようになるので、ハンドドリップに手を出すハードルは下がったように思います。

アプリの様子は以下の通り(スクリーンショット)。

コーヒー豆の登録、レシピの一覧、レシピのサジェスト(reject or accept)、レシピの評価画面

結果

PualigのCafe New Yorkを使ってアプリの使用感を検証しました。[浅煎りの酸味が強い豆。FIでは浅煎りの方が一般的らしいので]これを30回以上入れた結果、体感ですが徐々に旨いコーヒーが出来上がっているように思います (n=1)。

試行ごの評価の改善具合(おいしくなっているか)

評価をプロットすると、試行ごと(trial)に全体的な評価が向上していることが分かります(トレンドが上向き)。ただ、開発者である自分が淹れて評価してを繰り返した結果なので、確実にバイアスが載っているはずです(徐々に旨くなるはずと思い込んでいるので評価に影響している可能性が高い)。

試行ごとのレシピ評価値(New York, Paulig. N=1, 75 trials)

最強のレシピ(暫定)

暫定の最高のレシピは以下の通り。強い酸味・うま味でえぐみが全くないめちゃくちゃ旨いコーヒーでした(誰か試してみて下さい)。

  1. コーヒー豆 28.8 g を 12-click で挽く (TIMEMORE C3を使用)
  2. 85℃のお湯を用意する
  3. リンスはしない(←ペーパーフィルターに湯をかけるやつ)
  4. タイマーをスタート、ドリップ開始:

    00:00-00:59 1投目 (蒸らし):

    • 94 g まで湯 94 g を 16 sec 程で注ぐ
    • スピニングなし
    • 蒸らしのために 59 sec 待つ

    00:59-01:26 2投目: 209 g まで

    • 115 g を 27 sec 程で注ぐ

    01:50-02:15 3投目: 379 g まで

    • 170 g を 25 sec ほどで注ぐ
    • スピニングする
  5. 湯が落ちたらドリッパーを外し、 残りの湯 (21 g) をポッドに直接加える (加水: 400 g まで)

パラメータの重要度

パラメータごとの重要度を比較すると、

  • 3回目の注ぎ時間
  • 豆・お湯の総量費(コーヒーの濃さ)
  • 蒸らし(1投目)の注ぎ量

などが評価に影響していることが分かります。湯温 (Temperature[℃])は体感はめちゃくちゃ重要なはずですが、思いのほか重要度が低く見積もられています。もしかしたら、どんな湯温でも淹れ方次第(注ぎ量・タイミング・時間など)で美味しくなるということかもしれません(要検証)。 それにしてもSpinningやらRinseやらの重要度は低く、味には影響しないように見えます。湯温と同様に淹れ方次第なのかもしれませんし(蒸らし時のスピニングは重要な気がしないんでもない。A/Bテストなどで検証すれば確実にわかるはず)、ドリップ時にどや顔でやっている小技はそこまで味に影響しないないのかも(挽く前に豆を湿らせるのは意味があります)。

パラメータごとの重要度(New York, Paulig. N=1, 75 trials)*3

展望

直近:

  • 器具と流派を条件付けできるようにしたい(異なるグラインダーだとやはり結果が違うしクリック数とかが異なる。井崎式だけじゃないし、ネルドリップしたい人もいるはず)
  • とりあえず一般公開したい(現在Androidの内部テスト版をPlay Storeで配信中。iPhoneは配信方法が面倒なので未公開)。

近い未来:

  • (特に地域のロースターが販売している豆について)コーヒー豆の販売者が「この豆にはこのレシピがおすすめです。理論値(我々の実験上)これくらい美味しくなります。」というアドバイスや味の目安(リファレンス)が示され、消費者が豆を選びやすくなる。
  • FIのハンドドリップ愛好家に布教する(現地のロースターとか)。
  • ユーザーが増えてデータが貯まったらコーヒーのレシピと嗜好について何かしら論文などで発表したいし、データセットを公表してKaggleコンペとかやりたい(レシピ評価値の予測など)。

遠い未来:

  • 評価・パラメータの改善機能を備えたコーヒーマシンを作りたい(スマホで操作してレシピを選んで評価を行う)。

おわりに

コーヒーのレシピを考える時間が省けて簡単にコーヒーを享受できるようになりました。どんな豆でも数十試行後にはそれなりに旨いコーヒーがので、いろいろな高価な豆に挑戦することができます(無駄にしたくない)。FIの現地のロースターを周って美味しい豆を買いに出かけましょう。

実験環境(おまけ)

仕様器具は下のとおり。

  • フィルター:HARIO V60 (VDMR-02-HSV, ステンレスの1—4杯分のやつ)
  • グラインダー:TIMEMORE C3
  • コーヒースケール:適当なやつ(400gまで計れて0.1g刻みであればよい。タイマー付きだけどタイマー自体はスマホとかで十分)。
  • コーヒーポッド:1℃単位で温度調整ができて、注ぎ口がいい感じのやつ(これ)。

*1:特にアクセス数が爆発するように思えないのでGCP=Google Cloud Platformで十分だろうというのと(初心者)、私はモバイルアプリエンジニアではないのでマルチプラットフォームで開発できる(iPhone版とAndroid版を一緒につくれる)という点で選びました]

*2:自身が深層学習のプロジェクトでハイパーパラメータチューニング目的で使用していたのでちょうどいい、という理由もありますBayesianであればXGBoostでもええやろとも言えますが、OptunaにはAsk-and-Tellという機能があり使いやすそうだったので。

*3:このプロットの値について詳しくは関知していませんが、ANOVAによる結果の様子なので、分散の小ささや主効果に関する値なのかもしれません