<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>coffee - まったり勉強ノート</title>
	<atom:link href="https://www.mattari-benkyo-note.com/tag/coffee/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.mattari-benkyo-note.com</link>
	<description>shuの日々の勉強まとめ</description>
	<lastBuildDate>Wed, 28 Feb 2024 09:16:24 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
<site xmlns="com-wordpress:feed-additions:1">189243286</site>	<item>
		<title>OptunaのPreferential Optimizationを使ったおいしいコーヒーの淹れ方探索</title>
		<link>https://www.mattari-benkyo-note.com/2023/10/30/optuna_coffee_2023/</link>
					<comments>https://www.mattari-benkyo-note.com/2023/10/30/optuna_coffee_2023/#respond</comments>
		
		<dc:creator><![CDATA[Shuji Suzuki (shu)]]></dc:creator>
		<pubDate>Sun, 29 Oct 2023 21:57:55 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[coffee]]></category>
		<category><![CDATA[optuna]]></category>
		<guid isPermaLink="false">https://www.mattari-benkyo-note.com/?p=2866</guid>

					<description><![CDATA[<p>先日リリースされたOptuna 3.4にPreferential Optimizationという機能がついに入りました！ このPreferential OptimizationはOptunaとOptuna Dashboa [&#8230;]</p>
<p>The post <a href="https://www.mattari-benkyo-note.com/2023/10/30/optuna_coffee_2023/">OptunaのPreferential Optimizationを使ったおいしいコーヒーの淹れ方探索</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>先日リリースされた<a href="https://tech.preferred.jp/ja/blog/announcing-optuna-3-4/" target="_blank" rel="noopener" title="Optuna 3.4">Optuna 3.4</a>にPreferential Optimizationという機能がついに入りました！</p>



<p>このPreferential OptimizationはOptunaとOptuna Dashboardによって、複数のtrialの出力のうちどれがよいかを人が判断して入力し、最適化していく機能です。</p>



<p>この機能がどういうときにうれしいかというと、コーヒーの味の良し悪しのような主観的な評価でしか評価できないとき、二つを比べてどちらがいいのかという評価で最適化を実行することができます。</p>



<p>以前書いたOptunaを使ったおいしいコーヒーの淹れ方を探索するときにはレシピごとに絶対評価のスコアをつける必要がありました。この絶対評価をつけるのがやっかいで、全体を通して矛盾のない評価を人がするのはかなり難しいと考えています。一方、Preferential Optimizationであれば、二つのレシピでどっちがおいしいかを比べればよいだけになり、簡単な評価で探索を行うことができるようになりました。</p>



<p>ちなみに以前のOptunaを使ったコーヒーの淹れ方はこちらになります。</p>



<figure class="wp-block-embed is-type-wp-embed"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="zBS8soI3yW"><a href="https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/">Optunaを使ったおいしいコーヒーの淹れ方探索 (2021年4月版)</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;Optunaを使ったおいしいコーヒーの淹れ方探索 (2021年4月版)&#8221; &#8212; まったり勉強ノート" src="https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/embed/#?secret=scmdlsOauH#?secret=zBS8soI3yW" data-secret="zBS8soI3yW" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<p>今回の記事ではOptunaのPreferential Optimizationを利用してよりよくした新しくなった「おいしいコーヒーの淹れ方探索」の方法について紹介します。</p>



<p>今回のコードはこちらに上げてあります。</p>



<p><a href="https://github.com/shu65/coffee_blog_2023">https://github.com/shu65/coffee_blog_2023</a></p>



<p>普段はGoogle Colabで動くようなコードを作るのですが、今回はOptuna DashboardというOptunaの探索結果をWebUIで確認できるツールもセットで使う必要があるため、localで動かすことを想定したコードを示します。</p>



<h2 class="wp-block-heading">Preferential Optimizationを使ったおいしいコーヒーの淹れ方の概要</h2>



<p>OptunaのPreferential Optimizationを使う場合、コーヒーの淹れ方の探索するには以下の4つのステップを繰り返していきます。</p>



<ol class="wp-block-list">
<li>Optunaに２個になるまでtrial(コーヒーのレシピのこと)を提案してもらう</li>



<li>２つのレシピでコーヒーを淹れる</li>



<li>美味しくなかったほうがどちらなのかOptunaに登録する </li>



<li>次のレシピをOptunaに提案してもらい、2に戻る</li>
</ol>



<p>Preferential Optimizationじゃない普通のOptunaの最適化との違いとしては次の通りです。</p>



<ol class="wp-block-list">
<li>複数のtrialを提案</li>



<li>trailごとにスコアを登録するのではなく、複数のtrailのどれが良いか、悪いかをOptunaに登録する</li>
</ol>



<p>最初にも述べたようにPreferential Optimizationを使うことで絶対評価ではなく、相対的な評価でOptunaの探索ができようになります。</p>



<h2 class="wp-block-heading">コーヒーを淹れるための道具</h2>



<p>Optunaでコーヒーの淹れ方を探索してもらう際、どの道具を使うかで探索できるパラメータが変わります。Preferential Optimizationをするなら個人的には以下のものを使うのが良いと考えているので簡単に紹介します。</p>



<figure class="wp-block-table"><table><tbody><tr><td>商品名</td><td>説明</td></tr><tr><td>フラワードリッパー DEEP27</td><td>話題の1杯用のドリッパー。少量のコーヒーを淹れられるので1日に何杯もコーヒー飲むと気持ち悪くなる人も複数杯飲める</td></tr><tr><td>山善 電気ケトル NEKM-C1280</td><td>温度が1度単位で60-100度まで指定可能。山善はモデルチェンジも早いので今買うなら最新のモデルを買うのがおすすめ</td></tr><tr><td>TIMEMORE X</td><td>細かくコーヒーの挽き目調整ができる。調整も簡単なので使いやすい</td></tr><tr><td>TIMEMOREタイムモア Black Mirror nano</td><td>重さ、時間だけじゃなく流量も測定できるスケール</td></tr></tbody></table><figcaption class="wp-element-caption">コーヒーを淹れるための道具</figcaption></figure>



<p>特徴的な道具として、今回はフラワードリッパー DEEP27を使いました。これは9月に発売したばかりの1杯用のドリッパーで、紹介されている記事や動画を見ると皆さん思い思いのレシピを公開している様子です。このため、個人的には何がいいのかわからん状態なので、探索するにはちょうどいいということで選びました。</p>



<h2 class="wp-block-heading">実際のOptunaのパラメータ探索</h2>



<p>ここからは実際にOptunaを使ったコーヒーの淹れ方のコードを説明していきます。</p>



<p>まずはどのように今回レシピを探索していくのか説明するためにベースとなる淹れ方から説明していきます。</p>



<h3 class="wp-block-heading">ベースのレシピ</h3>



<p>コーヒーのレシピの探索の前にベースとなるレシピを決めます。</p>



<p>ベースのレシピはかなり重要で、ベースとなるレシピに基づいてどの部分をOptunaで探索するかはもちろん、ベースのレシピが難しすぎると同じレシピでも味が不安定なったり、Optunaで探索するパラメータが多すぎてうまく探索できないということが起きます。</p>



<p>今回はかなり簡単に淹れることができる以下の「暮らしとコーヒー」のチャンネルの動画のレシピを参考にベースのレシピを作ります。</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="DEEP27が届いたらすぐにやってほしい超簡単で美味しい抽出レシピ" width="1140" height="641" src="https://www.youtube.com/embed/G7vxam3T5mQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div></figure>



<p>ベースのレシピは以下の通りです。</p>



<ul class="wp-block-list">
<li>豆の量: 12g</li>



<li>お湯の温度: 86℃</li>



<li>抽出量: 150g</li>



<li>&nbsp;ミルのクリック数: 18</li>



<li>&nbsp;蒸らし時間: 20秒</li>



<li>&nbsp;蒸らしのお湯の量: 20g</li>
</ul>



<p>今回のレシピは一定速度でお湯を注ぎ続ければよいので再現しやすいレシピかと思っています。さらに今回使ったスケールのように流量を見れるものであれば、同じレシピであれば毎回似たような味にすることができると思います。</p>



<h3 class="wp-block-heading">探索するパラメータ</h3>



<p>次にベースのレシピに基づいて探索するパラメータについて説明していきます。</p>



<p>基本はベースのレシピの値を中心にある程度の範囲を探索することにします。ただし、豆の量と抽出量に関してだけは二つを同時に探索するのではなく、抽出量を150gに固定したうえで、豆の量(g)/抽出量を探索することにします。こうすることで、探索する項目を一つ減らせ、またできるコーヒーの量が同じになるというメリットがあります。</p>



<p>また、お湯の量や時間は1g、1秒単位できっちりやるのは難しい印象です。このため、10g、5秒単位のようにある程度の幅で探索していきます。</p>



<p>上記のことをコードにすると以下のようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="otpuna_search.py" data-lang="Python"><code>        temperature = trial.suggest_float(&quot;お湯の温度(℃)&quot;, 80, 95, step=1.0)
        bean_per_water = trial.suggest_float(&quot;豆の量 (g)/お湯の量(g)&quot;, 0.053, 0.1, step=0.01) # 8/150-15/150
        click_count = trial.suggest_float(&quot;ミルのクリック数&quot;, 16, 24, step=1.0)
        steaming_time = trial.suggest_float(&quot;蒸らし時間(sec)&quot;, 0, 40, step=5.0)
        steaming_water_weight = trial.suggest_float(&quot;蒸らしのお湯の量(g)&quot;, 10, 30, step=10.0)</code></pre></div>



<p>update 2024/02/28: <code>suggest_int()</code> と <code>suggest_float()</code> が混ざっていると一部のパラメータが毎回同じ値になってしまったのですべて <code>suggest_float()</code> に変更し、<code>step</code> を指定するように変更しました。</p>



<p>これに加えて必ず探索してほしいパラメータとして、ベースのレシピに基づく値を<code>enqueue_trial()</code> で入れておきます。何もしないと、最初から完全にランダムなレシピで探索してしまい、まともなレシピが出てくるまで時間がかかる印象です。このため、一つはまともなレシピを最初に入れておくと、まともなレシピと新しく提案されたレシピの二つを比べるような状態になるので、最初のほうは楽に比較ができる印象です。</p>



<p>コードとしては以下のようになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="optuna_default.py" data-lang="Python"><code>    if len(study.get_trials()) == 0:
        # add default trial.
        # ref: https://www.youtube.com/watch?v=G7vxam3T5mQ&t=68s
        params = {
            &quot;お湯の温度(℃)&quot;: 86,
            &quot;豆の量 (g)/お湯の量(g)&quot;: 12/150,
            &quot;ミルのクリック数&quot;: 18,
            &quot;蒸らし時間(sec)&quot;: 20,
            &quot;蒸らしのお湯の量(g)&quot;: 20,
        }
        study.enqueue_trial(params)</code></pre></div>



<h3 class="wp-block-heading">Optuna Dashboardで表示するnoteの生成</h3>



<p>次に新しいtrialで提案されたパラメータをOptuna Dashboardで表示する部分です。今回は提案されたパラメータからレシピ文章を作り、noteに追加し、noteをOptuna Dashboardで表示するということをします。このnoteの内容を見てコーヒーを淹れることになるので、以下のことを意識してnoteにレシピをまとめることにします。</p>



<ol class="wp-block-list">
<li>提案された値が必要になる順にnoteに列挙する</li>



<li>探索は豆の量 (g)/お湯の量(g)だが、実際に必要なのは豆の量なので、豆の量を計算してnoteに列挙する</li>
</ol>



<p>特に重要なのが1で、コーヒーを淹れる際、例えばお湯を沸かすのは時間がかかるので、最初にお湯の温度が必要になります。これがれnoteの真ん中にあると少し手間取ります。このため、最初に書いてあると私の経験上スムーズなので、お湯の温度は最初に出力します。他のパラメータも同様に必要になる順番で列挙していくことでコーヒーをスムーズに淹れることができ、また間違いが減らせる印象です。</p>



<p>コードとしては以下の通りです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="add_note.py" data-lang="Python"><code>        bean_weight = int(bean_per_water*water_weight)
        note = textwrap.dedent(
            f&quot;&quot;&quot;\
        ## レシピ
        - お湯の温度(℃): {int(temperature)}
        - ミルのクリック数: {int(click_count)}
        - 豆の量(g): {int(bean_weight)}
        - 蒸らしのお湯の量(g): {int(steaming_water_weight)}
        - 蒸らし時間(sec): {int(steaming_time)}
        - 抽出量(g): {int(water_weight)}
        &quot;&quot;&quot;
        )
        save_note(trial, note)</code></pre></div>



<h3 class="wp-block-heading">複数trialの提案</h3>



<p>先ほどまでのパラメータ探索部分は従来のOptunaとほぼ同じでした。ここからPreferential Optimizationのときに必要な部分について説明していきます。まずは複数trialの提案部分です。</p>



<p>Preferential Optimizationは複数のtrialをOptuna Dashboard上でどちらが良かったのかを記録していくので、コード的には新しいtrialを作る<code>ask()</code> を呼んでパラメータを提案させるところまでやり、<code>tell()</code> を呼びません。そして比較のときに必要なtrialの数に足りなければ次のtrialを作り、十分な数があれば待つという動作をすることになります。</p>



<p>コードとしては以下の通りです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-file="optuna_loop.py" data-lang="Python"><code>
    STORAGE_URL = &quot;sqlite:///example.db&quot;
    study = create_study(
        n_generate=2,
        study_name=&quot;GUATEMALA recipe&quot;,
        storage=STORAGE_URL,
        sampler=PreferentialGPSampler(seed=42),
        load_if_exists=True,
    )

    register_preference_feedback_component(study, &quot;note&quot;)
    # add default parameters
    ... 
    while True:
        if not study.should_generate():
            time.sleep(0.1)  # Avoid busy-loop
            continue

        trial = study.ask()

        # Ask new parameters
        ... 
        # Add note
        ...</code></pre></div>



<h3 class="wp-block-heading">実行方法</h3>



<p>ここまでのコードを組み合わせた<code><code>recipe</code></code>_<code>generator.py</code> とOptuna Dashboardを組み合わせて実行します。それぞれ以下のように実行します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-bash" data-file="run.sh" data-lang="Bash"><code>python recipe_generator.py &
optuna-dashboard sqlite:///example.db</code></pre></div>



<p>これで <code>http://127.0.0.1:8080/dashboard/studies/1/</code> にアクセスして以下のような画面がでてくれば成功です。</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="1024" height="561" src="https://www.mattari-benkyo-note.com/wp-content/uploads/2023/10/optuna_dashboard.png" alt="" class="wp-image-2878" srcset="https://www.mattari-benkyo-note.com/wp-content/uploads/2023/10/optuna_dashboard.png 1024w, https://www.mattari-benkyo-note.com/wp-content/uploads/2023/10/optuna_dashboard-300x164.png 300w, https://www.mattari-benkyo-note.com/wp-content/uploads/2023/10/optuna_dashboard-768x421.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Trial 0 が最初に入れたベースのレシピ、Trial 1がOptunaが提案してきた新しいレシピになります。あとはこのレシピに従ってコーヒーを淹れて評価して、美味しくなかったほうを「WORST」にしてまたコーヒーを淹れるというのをひたすら繰り返すだけです。</p>



<h2 class="wp-block-heading">終わりに</h2>



<p>今回はPreferential Optimizationを使ったコーヒーのレシピ探索について書きました。Optunaのデフォルトだと10回まではランダム探索で、まだ探索を開始してから1週間なので実はまだランダム探索の状態です。これから実際に探索が行われてからどうなるか楽しみです。</p>



<p>ある程度探索できたらデータを解析して記事にしようと思います。</p><p>The post <a href="https://www.mattari-benkyo-note.com/2023/10/30/optuna_coffee_2023/">OptunaのPreferential Optimizationを使ったおいしいコーヒーの淹れ方探索</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.mattari-benkyo-note.com/2023/10/30/optuna_coffee_2023/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2866</post-id>	</item>
		<item>
		<title>Optunaを使ったおいしいコーヒーの淹れ方探索 (2021年4月版)</title>
		<link>https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/</link>
					<comments>https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/#comments</comments>
		
		<dc:creator><![CDATA[Shuji Suzuki (shu)]]></dc:creator>
		<pubDate>Wed, 31 Mar 2021 23:52:21 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[coffee]]></category>
		<category><![CDATA[optuna]]></category>
		<category><![CDATA[最適化]]></category>
		<guid isPermaLink="false">https://www.mattari-benkyo-note.com/?p=44</guid>

					<description><![CDATA[<p>昨年終わりに機械学習のハイパーパラメータ探索で良く用いられるOptunaを使って、おいしいコーヒーの淹れ方を探索する方法についてQiitaの記事を書きました。この記事が思ったよりも好評で、これをきっかけに勉強会でも発表さ [&#8230;]</p>
<p>The post <a href="https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/">Optunaを使ったおいしいコーヒーの淹れ方探索 (2021年4月版)</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>昨年終わりに機械学習のハイパーパラメータ探索で良く用いられるOptunaを使って、おいしいコーヒーの淹れ方を探索する方法について<a href="https://qiita.com/shu65/items/68d161b02a91396e854a" target="_blank" rel="noreferrer noopener" title="https://qiita.com/shu65/items/68d161b02a91396e854a">Qiitaの記事</a>を書きました。この記事が思ったよりも好評で、これをきっかけに勉強会でも発表させていただきました。ただ、やっているうちに以下のようなことを考えるようになりました。</p>



<ol class="wp-block-list">
<li>Optunaのドキュメントにはないprivateな関数を使って無理やり実装していて微妙</li>



<li>味に影響する重要なパラメータが使っていた道具の影響で探索できていなかった</li>



<li>探索させるパラメータを工夫したほうが良かった</li>
</ol>



<p>今回はこれらを解決した今現在の2021年4月版のコーヒーの淹れ方の探索を紹介していきたいと思います。Qiitaの記事を読んでない方も多くいらっしゃると思うので、この記事では最初から説明をしていきます。</p>



<h2 class="wp-block-heading">コーヒーの淹れ方の探索方法の概要</h2>



<p>Optunaを使ったコーヒーの淹れ方の探索では以下の4つのステップを繰り返すことで実現します。</p>



<ol class="wp-block-list">
<li>過去のコーヒーの淹れ方とその時の評価値をOptunaに登録</li>



<li>過去の淹れ方の履歴を基に次に試すべき淹れ方をOptunaで提案</li>



<li>提案された淹れ方を実際に試して味を評価</li>



<li>Optunaが提案したパラメータと評価値を記録（今回はGoogleスプレッドシートを利用）</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1000" height="534" src="https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/概要図.png" alt="" class="wp-image-46" srcset="https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/概要図.png 1000w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/概要図-300x160.png 300w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/概要図-768x410.png 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></figure></div>


<p>普通のOptunaを利用例の場合、すべてコンピューター上で完結させますが、今回は人力（3の部分）があるのが特徴的です。</p>



<p>ただ、この特徴的な3の部分の所為で、前回のQiitaの記事ではOptunaのprivateな関数を使って実装せざるをえませんでした。しかし、v2.5.0で追加されたAsk-and-Tellの<code>ask()</code>でこの問題が解決されました。この記事ではAsk-and-Tellも簡単に紹介していきたいと思います。</p>



<h2 class="wp-block-heading">Optunaのv2.5.0の新機能：Ask-and-Tell</h2>



<p>v2.5.0のリリースで追加されたAsk-and-Tellは、簡単にいえばOptunaのパラメータの提案する部分 (<code>ask()</code>)とOptunaに提案されたパラメータのスコアを教える部分(<code>tell()</code>)の2つの部分に分けて実行するためのAPIです。</p>



<p>これにより、従来は面倒だった、あるプロセスでパラメータを提案させて、その後、別のプロセスでスコアを計算してOptunaに登録するというような分離が簡単に書けるようになりました。今回のコーヒーの淹れ方の場合は、パラメータの提案とスコアを出すところがコンピュータ上での実行と人力とで別れているため、このAsk-and-TellはぴったりなAPIになっています。</p>



<p>より詳しくAsk-and-Tellについて知りたい方はOptunaの<a href="https://github.com/optuna/optuna/releases/tag/v2.5.0" target="_blank" rel="noreferrer noopener" title="https://github.com/optuna/optuna/releases/tag/v2.5.0">リリースノート</a>をご覧ください。</p>



<h2 class="wp-block-heading">Optunaで探索する上で必要なものとコーヒーの淹れ方の場合の例</h2>



<p>Optunaでパラメータの探索をする際には主に以下の二つが必要になります。</p>



<ol class="wp-block-list">
<li>パラメータ毎の探索空間</li>



<li>提案されたパラメータを受け取って目的変数の値を返す目的関数</li>
</ol>



<p>パラメータ毎の探索空間とは提案をしてほしいパラメータ毎に提案をしてほしい値の範囲を指定したものになります。Optunaがよく使われているニューラルネットワークの例で言うと、以下のようなものになります。</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>パラメータ</strong></td><td><strong>探索範囲</strong></td></tr><tr><td>隠れ層のユニット数</td><td>1-128</td></tr><tr><td>学習率</td><td>0.001-1.0</td></tr></tbody></table><figcaption class="wp-element-caption">パラメータの探索範囲の例</figcaption></figure>



<p>また、目的関数とは、指定されたパラメータで学習した結果の精度を返す関数となります。</p>



<p>では、コーヒーの淹れ方の場合はパラメータに対応するものと、目的関数をどうすればよいでしょうか？</p>



<p>後ほど詳しく紹介しますが、今回はパラメータとして豆の量やお湯の温度など、コーヒーの淹れ方で重要なものをパラメータとして扱います。探索範囲は各パラメータ毎に基準とした値を中心にして現実的な範囲で広げたものを利用します。</p>



<p>また、目的関数ですが、実際に提案されたパラメータに基づいて自分でいれて、おいしかったかどうかを自分で1-10点で評価して返すという人力のものを利用します。</p>



<h2 class="wp-block-heading">現在のコーヒーの入れる環境</h2>



<p>使う道具によってパラメータとして扱えるものが変化するので、使う道具についても紹介します。</p>



<p>今回は以下の道具で淹れるとして紹介しています。</p>



<ul class="wp-block-list">
<li>ミル： <a href="https://porlex.co.jp/archives/product/menu-344" target="_blank" rel="noopener" title="">ポーレックス コーヒーミル･Ⅱ</a> (調節ねじのクリック数によってコーヒーの粒度を変えられる)</li>



<li>ポット：<a href="https://book.yamazen.co.jp/product/cook/c_others/NEKM-C1280.html" target="_blank" rel="noreferrer noopener" title="https://book.yamazen.co.jp/product/cook/c_others/NEKM-C1280.html">山善 電気ケトル NEKM-C1280 </a>(温度設定可能)</li>



<li>抽出器： <a href="https://www.bodum.com/jp/ja/1923-16j-chambord" target="_blank" rel="noreferrer noopener" title="https://www.bodum.com/jp/ja/1923-16j-chambord">BODUM CHAMBORD</a>（フレンチプレス）</li>
</ul>



<p>前回との大きな変更はミルとポットです。ミルのほうは粒度が安定するようなものに変えました。また、ポットのほうは以前のものだと温度調節ができなかったのですが、温度調節ができるものに変更しました。これにより、コーヒーの粒度の安定性が増し、再現性があがったのに加え、コーヒーで重要なお湯の温度を制御できるようになりました。</p>



<p>また、今回もフレンチプレスを使ったコーヒーの抽出を行います。コーヒーを淹れる方法として有名なものはペーパードリップだと思いますが、ペーパードリップは探索したほうがよさそうなパラメータが多すぎるのと、お湯の注ぎ方など素人では安定させるのが難しい要素が多いという問題があります。このため、素人でも安定して入れられるフレンチプレスを利用します。</p>



<p>フレンチプレスを使った淹れ方をご存知ない方に簡単に説明すると</p>



<ol class="wp-block-list">
<li>挽いた豆をフレンチプレスの中に入れる</li>



<li>（少量のお湯を入れてしばらく置いて蒸らす）</li>



<li>お湯を入れる</li>



<li>（スプーンかき回す）</li>



<li>時間になったら金網フィルターを下ろして完成</li>
</ol>



<p>という流れでコーヒーを抽出します。カッコのところは、淹れ方の説明をいろいろ読むとあったりなかったりする部分です。</p>



<p>もっと詳しく知りたいという方は<a href="https://www.ucc.co.jp/enjoy/brew/frenchpress.html" target="_blank" rel="noreferrer noopener" title="https://www.ucc.co.jp/enjoy/brew/frenchpress.html">こちら</a>のページを参考にしてください。</p>



<h2 class="wp-block-heading">実際のOptunaのパラメータ探索</h2>



<p>ここからは実際にOptunaを使ったコーヒーの淹れ方のコードを説明していきます。今回のコードはこちらに上げてあります。</p>



<p><a href="https://github.com/shu65/coffee-tuning/blob/main/coffee_tuning_2021_04.ipynb">https://github.com/shu65/coffee-tuning/blob/main/coffee_tuning_2021_04.ipynb</a></p>



<h3 class="wp-block-heading">計算環境</h3>



<p>環境としては手軽にできるようにということで以下のサービスを利用します。</p>



<ul class="wp-block-list">
<li>プログラム実行：Google Colab</li>



<li>データ管理：Google スプレッドシート</li>
</ul>



<h3 class="wp-block-heading">Optunaの探索範囲</h3>



<p>今回は基準となる淹れ方を決め、それにある程度範囲を持たせたものを探索範囲とします。</p>



<p>本やネットを参考にして以下のような値を今回の基準としました。</p>



<ul class="wp-block-list">
<li>豆の量 (g): 9</li>



<li>ミルのクリック数: 15</li>



<li>お湯の温度(℃)：92</li>



<li>抽出時間 (sec): 240</li>



<li>蒸らし時間 (sec): 30</li>



<li>お湯の量 (g): 200</li>
</ul>



<p>さて、これを基準にプラスマイナスいくつかの範囲で探索すればいいのですが、豆の量とお湯の量に関しては少し工夫をします。</p>



<p>今回はお湯の量を200gに固定して、「豆の量 (g) / お湯の量 (g)」 という値をOptunaでは探索します。一時期、お湯の量も毎回探索していたのですが、お湯の量を変えると、できるコーヒーの量も変化してしまうという問題がありました。これを防ぐためにお湯の量を固定して、それに合った豆の量をOptunaに提案してもらうという形とするために「豆の量 (g) / お湯の量 (g)」を提案してもらいます。このように豆の量とお湯の量の比にして探索しておくと、お湯の量が微妙に変えたくなったときの探索にも今のデータをそのまま活用することができます。</p>



<p>以上に加え、蒸らしがあったほうがいいかととスプーンでかき混ぜたほうがいいかも探索させます。</p>



<p>これをまとめると以下のような探索範囲になります。</p>



<ul class="wp-block-list">
<li>豆の量 (g) / お湯の量 (g): 0.038-0.08</li>



<li>ミルで豆を挽く時間 (sec): 4-24</li>



<li>お湯の温度(℃)：80-99</li>



<li>抽出時間 (sec): 180-300</li>



<li>スプーンでかき混ぜる：あり or なし</li>



<li>蒸らし：あり or なし</li>



<li>蒸らし時間 (sec): 20-40</li>
</ul>



<h3 class="wp-block-heading">Google スプレッドシートによるデータのまとめ方</h3>



<p>淹れ方とその時の評価値 (スコア) をまとめる方法として今回はGoogle スプレッドシートを利用しました。表としてはこのような形です。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="183" src="https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例-1024x183.png" alt="" class="wp-image-52" srcset="https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例-1024x183.png 1024w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例-300x53.png 300w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例-768x137.png 768w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例-1536x274.png 1536w, https://www.mattari-benkyo-note.com/wp-content/uploads/2021/03/google-スプレッドシート例.png 1845w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Optunaで使わない値に関しても後々のデータ解析ように入れてあります。</p>



<h3 class="wp-block-heading">Optunaによるパラメータ提案</h3>



<p>ここまで準備できればいよいよOptunaで探索範囲に従ってコーヒーの淹れ方を提案してもらいます。</p>



<p>この部分の基本的な流れとしては以下の通りです。</p>



<ol class="wp-block-list">
<li>過去のコーヒーの淹れ方とその時の評価値をOptunaに登録</li>



<li>過去の淹れ方の履歴を基に次に試すべき淹れ方をOptunaで提案</li>
</ol>



<p>順番に説明していきます。</p>



<h4 class="wp-block-heading">1. 過去のコーヒーの淹れ方とその時の評価値をOptunaに登録</h4>



<p>まず、過去のコーヒーの淹れ方とその時の評価値をOptunaの&nbsp;<code>Study</code>&nbsp;に登録していきます。</p>



<p>最初にGoogleスプレッドシートからデータを取ってきます。コードとしては以下の通りです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python" data-show-lang="1"><code># Google スプレッドシートの承認

from google.colab import auth
from oauth2client.client import GoogleCredentials
import gspread

auth.authenticate_user()
gc = gspread.authorize(GoogleCredentials.get_application_default())

# スプレッドシートからデータを取ってくる
import numpy as np
import pandas as pd

ss_name = &quot;mattari-benkyo-note coffee tuning 202104&quot;
workbook = gc.open(ss_name)
worksheet = workbook.get_worksheet(0)
df = pd.DataFrame(worksheet.get_all_records())
df[df == &#39;&#39;] = np.nan
df[&#39;かき混ぜる&#39;] = df[&#39;かき混ぜる&#39;].astype(np.bool)
df[&#39;蒸らし&#39;] = df[&#39;蒸らし&#39;].astype(np.bool)
df = df.set_index(&#39;淹れた日&#39;)
df</code></pre></div>



<p>Google スプレッドシートの承認をしたあと、0番のシートから情報を取ってきて、pandasの<code>DataFrame</code>にするということをしています。その後適切な値や型の変換をします。</p>



<p>その後、読み込んだデータをOptunaの<code>Study</code>を作り、<code>add_trial() </code>を使って登録していきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python" data-show-lang="1"><code>import optuna

study_search_space={
    &quot;豆の量 (g)/お湯の量(g)&quot;: optuna.distributions.UniformDistribution(0.025, 0.08),
    &quot;ミルのクリック数&quot;: optuna.distributions.IntUniformDistribution(4, 26),
    &quot;抽出時間 (sec)&quot;: optuna.distributions.IntUniformDistribution(180, 300),
    &quot;かき混ぜる&quot;: optuna.distributions.CategoricalDistribution([True, False]),
    &quot;蒸らし&quot;: optuna.distributions.CategoricalDistribution([True, False]),
    &quot;蒸らし時間 (sec)&quot;: optuna.distributions.IntUniformDistribution(20, 40),
    &quot;保存方法&quot;: optuna.distributions.CategoricalDistribution([&quot;冷凍&quot;, &quot;冷蔵&quot;]),
    &quot;お湯の温度(℃)&quot;: optuna.distributions.IntUniformDistribution(80, 99),
    }
score_column = &#39;スコア&#39;



sampler = optuna.samplers.TPESampler(multivariate=True, n_startup_trials=10)
study = optuna.create_study(direction=&#39;maximize&#39;, sampler=sampler)

for record_i, record in df.iloc[::-1].iterrows():
  is_record_null = record.isnull()
  params = {}
  trial_search_space = {}
  for key in study_search_space.keys():
    if not is_record_null[key]:
      params[key] = record[key]
      trial_search_space[key] = study_search_space[key]
  if  not is_record_null[score_column]:
    try:
      trial = optuna.trial.create_trial(
        params=params,
        distributions=trial_search_space,
        value=record[score_column])
      study.add_trial(trial)
    except ValueError as e:
      print(&quot;pass trial:&quot;, trial)
      print(e)

print(&quot;sample size:&quot;, len(df))</code></pre></div>



<p><code>Study</code> に登録する際もパラメータの分布が必要になりますが、これは提案するときの分布とは別ものです。<code>add_trial()</code> する際の注意点としては<code>add_trial()</code>の<code>params</code>に入っているパラメータの値が<code>distributions</code>で指定した探索範囲外だとエラーになります。時々お湯を少し多く入れてしまうというようなミスがあるので本来探索するよりも一部広い範囲を利用しています。</p>



<h4 class="wp-block-heading">2. 過去の淹れ方の履歴を基に次に試すべき淹れ方をOptunaでパラメータで提案</h4>



<p>さて、いよいよOptunaのAsk-and-Tellの<code>ask()</code> を使ってパラメータを提案していきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-python" data-lang="Python" data-show-lang="1"><code>trial = study.ask()

new_params = {}
new_params[&quot;蒸らし&quot;] = trial.suggest_categorical(&quot;蒸らし&quot;, [True, False])
if new_params[&#39;蒸らし&#39;]:
  new_params[&quot;蒸らし時間 (sec)&quot;] = trial.suggest_int(&quot;蒸らし時間 (sec)&quot;, 20, 40)

new_params[&quot;豆の量 (g)/お湯の量(g)&quot;] = trial.suggest_uniform(&quot;豆の量 (g)/お湯の量(g)&quot;, 0.038, 0.08)
new_params[&quot;ミルのクリック数&quot;] = trial.suggest_int(&quot;ミルのクリック数&quot;, 4, 24)
new_params[&quot;抽出時間 (sec)&quot;] = trial.suggest_int(&quot;抽出時間 (sec)&quot;, 180, 300)
new_params[&quot;かき混ぜる&quot;] = trial.suggest_categorical(&quot;かき混ぜる&quot;,  [True, False])
new_params[&quot;お湯の温度(℃)&quot;] = trial.suggest_int(&quot;お湯の温度(℃)&quot;,  80, 99)

# わかりやすい順番で表示
water=200
for key in  [&quot;お湯の温度(℃)&quot;, &quot;豆の量 (g)/お湯の量(g)&quot;, &quot;豆の量(g)&quot;, &quot;ミルのクリック数&quot;, &quot;かき混ぜる&quot;, &quot;蒸らし&quot;, &quot;蒸らし時間 (sec)&quot;,&quot;抽出時間 (sec)&quot;]:
  if key in new_params:
    if key == &quot;豆の量 (g)/お湯の量(g)&quot;:
      beans = int(water * new_params[key])
      print(key, new_params[key], beans / water)
      print(&quot;豆の量 (g)&quot;, beans)
    else:
      print(key, new_params[key])&lt;/code&gt;&lt;/pre&gt;</code></pre></div>



<p>これでコーヒーの淹れ方のパラメータを提案できます。試しに現状のパラメータで提案させると次のような結果が得られました。</p>



<pre class="wp-block-code"><code>お湯の温度(℃) 88
豆の量 (g)/お湯の量(g) 0.05400951154389384 0.05
豆の量 (g) 10
ミルのクリック数 9
かき混ぜる True
蒸らし True
蒸らし時間 (sec) 24
抽出時間 (sec) 205</code></pre>



<p>すでに約40trial分のデータがあるので、それっぽいものを提案してきている印象です。</p>



<p>あとは実際に入れてみて評価値をGoogle スプレッドシートに入れて次の提案に活かすということを繰り返しおこなっていくことで、徐々においしいコーヒーの淹れ方を提案してくれるようになります。</p>



<h2 class="wp-block-heading">実際に3か月やってみた感想</h2>



<p>実際に3か月やってみた印象としては、本やネットで調べたものよりもおいしい淹れ方が見つかった印象です。別の記事でデータ解析した結果の際にも紹介すると思いますが、酸味が強い豆と苦味が強い豆とではおいしいと思うパラメータが違うため、この辺りを素人がいろいろ探索する際には役立つかなと思っています。</p>



<p>ただ、コーヒーに詳しい方はおいしくない時にどう変更すればわかるような場合も多いと思われるため、そういう方は必要ないかなという印象です。</p>



<p>あとは、ネットや本で調べた知識に基づくと絶対変というような淹れ方になるときも当然あるのですが、「こんな味になるのか」という驚きがあって面白かったです。</p>



<p>現状でも残っている課題としては、おいしさをどう評価値にするかの部分かなと思っています。味はその日の体調やコーヒーのちょっとした温度の違いでも変化してしまいます。また、実際に同じタイミングで飲み比べているわけではないので、どうしても絶対評価が難しいという問題があります。この部分もいずれ解決できればと思っています。</p>



<h2 class="wp-block-heading">終わりに</h2>



<p>2021年度4月版のOptunaを使ったおいしいコーヒーの淹れ方の探索について紹介しました。</p>



<p>昨年末のころと比較して、大筋はそれほど変化してませんが、使う道具やその道具を使って何のパラメータをOptunaで提案させるかの部分はかなり変化した印象です。</p>



<p>そのうち、Optunaの可視化機能の紹介やそれらを活用したデータ解析を実際の3か月分のデータに適用した記事も書ければと思っています。また、現在はペーパードリップで同じように探索できないか挑戦していますので、そちらもある程度形になったら紹介記事を書きたいと思っています。</p><p>The post <a href="https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/">Optunaを使ったおいしいコーヒーの淹れ方探索 (2021年4月版)</a> first appeared on <a href="https://www.mattari-benkyo-note.com">まったり勉強ノート</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.mattari-benkyo-note.com/2021/04/01/coffee-tuning-202104/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">44</post-id>	</item>
	</channel>
</rss>
