TECH PLAY

株式会社Insight Edge

株式会社Insight Edge の技術ブログ

174

こんにちは! 分析チームの梶原(悠)です。今回はクラス間不均衡問題について議論します。 目次 クラス間不均衡問題とは 問題の定式化にまつわる議論 比較シミュレーションの設定 比較シミュレーションの結果 考察 クラス間不均衡問題とは 実務で扱われる多くの分類問題はクラス間のサイズに偏りがあります。 いくつかのクラスのデータが他のクラスよりも著しく多いとき、分類器は小さなクラスを無視しやすくなります。 これは、クラス間不均衡問題と呼ばれます。 問題の定式化にまつわる議論 クラス間不均衡問題は、「分類問題の構造の複雑さ」「訓練データの大きさ」「クラス間のサイズの偏り」などの条件が絡みあって起きます [1] 。 一方で、Lingらは、学習器が正解率(accuracy)の最大化を目標として訓練される分類タスクの設定自体に問題があると指摘しています [2] 。 そして不均衡問題には、ビジネスコストを考慮した学習で効果的に対処できると主張しています。また、訓練データが小さいことの悪影響は、不均衡とは別の問題であるとする立場をとっています。 本稿では「クラス間不均衡問題への対処にあたって、ビジネスコストを正確に考慮する必要があるか?」という論点を実務寄りの観点から検討してみます。 比較シミュレーションの設定 実務上は、ビジネスインパクトに強く影響する要因が重要で、影響しない要因は無視できます。 今回は、きわめて単純化された仮想企業の損益を、乱数実験によりシミュレートし、クラス間不均衡問題への対処手法のビジネスインパクトを比較してみます。 仮想企業Y社のビジネス設定. 仮想企業Y社は、農作物の種子を売り掛け販売し、一定の支払猶予期間ののち、代金を回収するビジネスを営んでいます。 Y社は、種子のメーカーZ社から単価95円で種子を調達し、顧客企業に単価120円で販売します。 顧客企業Z社は、購入した種子から花を育てて花市場で販売し、得られた売上からY社に代金の支払いを行います。 顧客企業Z社は、花の不作や価格下落により資金繰りができなくなるとY社に代金を支払うことなく倒産します。 仮想企業Y社は、1,000社の顧客企業のそれぞれと月に数回の頻度で取引をします。倒産による貸し倒れの割合は1%です。 仮想企業Y社のビジネスプロセス ダミーデータの生成. 乱数シミュレーションにより、上記設定のY社と顧客企業との契約データを生成しました。 ビジネスインパクトの評価. 契約時点のデータから倒産による貸し倒れを予測するモデルを構築します。 倒産が予測される場合は、業務に介入し、契約を未然に取り止めます。 介入しない場合と比較した貸し倒れや機会損失の影響を考慮すると、種子1個あたりのビジネスコストは以下になります。 実績="継続" 実績="倒産" 予測="継続" 0円 0円 予測="倒産" +(120-95)円 -95円 このコストを累積したものは、介入あり・なしの累積損益の差に一致します。 これを介入のビジネスインパクト(pl_impact)とします。 ビジネスインパクト=累積損益(介入あり)-累積損益(介入なし) 不均衡対応の手法 倒産の予測モデルはすべてlightGBMで作成し、不均衡対応は以下の5手法を比較しました。なお、説明変数は、「種子の個数」「支払い猶予期間」「花の市場価格」の3つのみを用います。 クラス間不均衡に対処しない. (NAIVE) モデルの出力した倒産確率をビジネスインパクトが最大になる閾値で切る. (OPTIMIZED_THRESHOLD) サンプルの重みによるコスト考慮学習で対処する. (COST_SENSITIVE_LEARNING) [4] SMOTE (Synthetic Minority Oversampling Technique)で前処理する. (SMOTE) [5] 損失関数をFocal lossにする. (FOCAL_LOSS) [6] 学習・検証データ分割 学習データは顧客企業500社との契約データからランダムサンプリングし、 検証データは残り500社の顧客企業との契約データの全量とします。 比較シミュレーションの結果 不均衡問題の確認. 不均衡に対処しないモデル(NAIVE)による予測の精度を確認します。今回のデータとモデルはかなり構造が単純ですが、不均衡の悪影響が見られます。また、学習データが小さくなると、不均衡問題の悪影響も強まっています。(各値は、学習における乱数シードを変えた20回の試行の中央値。) 学習サンプルサイズ 倒産確率 (実績値) 倒産確率 (推定値) MCC 正解率 (Accuracy) 再現率 (Recall) Cohen's kappa AUC Brier score 500 個 0.014 0.011 0.620 0.991 0.556 0.604 0.775 0.0088 20,000 個 0.014 0.011 0.715 0.993 0.649 0.712 0.823 0.0060 手法のビジネスインパクトの比較 ビジネスインパクトの比較では、ビジネス構造の知識を持たないSMOTEが、コスト考慮学習よりも良い結果となりました。この事例の不均衡データでは、タスクの定式化にビジネス構造を取り込むことよりも、訓練データが小さいことへの対処の方が、実務上重要であると考えられます。(各値は、学習における乱数シードを変えた20回の試行の中央値。) 各手法のビジネスインパクト 考察 今回はダミーデータが小さすぎて確認できませんでしたが、訓練データのサイズを大きくしていけば、漸近的には、どの手法のビジネスインパクトも同じになると期待されます。すなわち、漸近的にはビジネス構造の知識を持つ手法と持たない手法は同等になるはずです。 一方、訓練データのサイズが小さい非漸近的な領域では、ビジネス構造の知識を持たないSMOTEの方が、コスト考慮学習より大きなビジネスインパクトを持つ現象が確認できました。この事例においては、不均衡問題の本質が、分類タスクの定式化におけるビジネス構造の不在ではなく、マイナークラスの少数データ問題側にあることを示唆すると思われます。 だとすると、コスト考慮学習による方向を追求しても、実務上の意味のある形で不均衡問題への視座を得ることはできないのではないか、という疑いを覚えます。Jamalらはクラスの均衡化をドメイン適応の問題として捉える視点を紹介しています [3] 。クラス不均衡問題の正しい定式化は、あるいは、こうした方向にロバスト性が加えられたようなものかもしれないと想像します。 [1] Japkowicz, N., & Stephen, S. (2002). The class imbalance problem: A systematic study. Intelligent data analysis, 6(5), 429-449. [2] Ling, C. X., & Sheng, V. S. (2008). Cost-sensitive learning and the class imbalance problem. [3] Jamal, M. A., Brown, M., Yang, M. H., Wang, L., & Gong, B. (2020). Rethinking class-balanced methods for long-tailed visual recognition from a domain adaptation perspective. In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (pp. 7610-7619). [4] Elkan, C. (2001, August). The foundations of cost-sensitive learning. In International joint conference on artificial intelligence (Vol. 17, No. 1, pp. 973-978). Lawrence Erlbaum Associates Ltd [5] Chawla, N. V., Bowyer, K. W., Hall, L. O., & Kegelmeyer, W. P. (2002). SMOTE: synthetic minority over-sampling technique. Journal of artificial intelligence research, 16, 321-357. [6] Lin, T. Y., Goyal, P., Girshick, R., He, K., & Dollár, P. (2017). Focal loss for dense object detection. In Proceedings of the IEEE international conference on computer vision (pp. 2980-2988).
アバター
Introduction こんにちは、住友商事のDXを加速する為の技術専門会社である Insight Edge にてデータサイエンティストをしております佐藤優矢です。 今回は、前職のメガベンチャーで担当していたレコメンドエンジンを、その歴史的経緯を踏まえて、協調フィルタリングからニューラルネットを用いたモデルの構築•評価までご紹介したいと思います。 目次 初期のレコメンドエンジン 協調フィルタリングの改善策 協調フィルタリングを超える精度のレコメンドエンジン 独自アルゴリズムの精度評価基盤の構築方法 レコメンドエンジンの精度を測る指標 まとめ 初期のレコメンドエンジン レコメンドエンジン初期は協調フィルタリングによるレコメンドが主な方法でした。 概要としては、ユーザーとアイテムからなるマトリックスを作成し、このユーザーがこのアイテムを購入したなどの情報をマトリックスに埋めていく方法をとります。 よく使われるのは、Alternating Least Square という最適化アルゴリズムであり、このソルバーがpythonで使えるので、それを用いると推定スコア(おすすめ度)が得られます。 長所としては、手軽に精度の良いレコメンドエンジンが作れることで、短所としては、特にマトリックスがスパースな状況では精度が悪いことです。 協調フィルタリングの改善策 歴史的に、協調フィルタリングには様々な改善策が考えられています。 アイテムベクトルによる類似度と混ぜてみる アイテムの説明文をベクトル化するなど アイテムの類似度と、協調フィルタリングによるおすすめ度を混ぜ合わせる形でおすすめ度を算出する。「正係数による距離の重み付け和はまた距離になる」に近い考え方で算出する 私が試したところ、あまり効果はなかった ユーザーベクトルによる類似度と混ぜてみる ユーザーのbioをベクトル化するなど 私が試したところ、これもあまり効果はなかった ちなみに、協調フィルタリングをナイーブにニューラルネット化したモデルでは精度が逆に落ちることがわかっています。 協調フィルタリングを超える精度のレコメンドエンジン 最近になって、Variational Auto-Encoder を用いたモデルなど、協調フィルタリングを超える精度のニューラルネットベースのレコメンドエンジンが開発されてきています。 それらを一気に試すフレームワークにRecBoleがあり、メガベンチャーの人と話したところ、多くのメガベンチャーの会社が使っているようでした。 使い方は、クックパッドでの 紹介記事 に詳しく載っています。 どのモデルを選べば良いかですが、データによって異なるので一概には言えません。ただ、マトリックスがスパースな時に精度が良かったモデルは、グラフニューラルネットを使ったモデルでした。ユーザーに繋がっているアイテムがあり、それに繋がっているユーザーがあるという形に連結していき、同じものを購入したユーザー同士を繋げるようなアルゴリズムになっています。 これらは先のクックパットの結果と大きく異なり、データによって最適な手法は異なることを表しています。 独自アルゴリズムの精度評価基盤の構築方法 最新のアルゴリズムはRecBoleにアップデートされることが多いですが、if-thenなどの独自アルゴリズムを後処理として付け加える(フィルターなど)ことが考えられます。その際は独自に評価基盤を整えます。 特定の精度指標による評価をアルゴリズムとして実装し、その評価指標による精度をもとに、モデルがいままでより良いものかどうかを判断していきます。 指標は Precision@k と Recall@k がよく用いられます。 レコメンドエンジンの精度を測る指標 Precision@k と Recall@k の定義の違いを考えると、異なる部分は分母のうち、正解データに絞るかどうかという点です。 専門書などでも触れられているのをみたことはありませんが、Precision@kだと、取れた正解データ(実際のユーザーの遷移データなどから取ってきます)の量が少ないと小さく見積もられてしまいます。データの量に応じて精度が変わってくるということが起こるわけです。 それに対して、Recall@kではその影響が抑えられています。なので、レコメンドエンジンのモデルの精度を測る時の指標はRecall@kがよく用いられるということかと思います。 まとめ 本稿では、歴史的によく用いられてきた協調フィルタリングから、ニューラルネットによるモデルのツールによる実装、またその最新モデルをカスタムした状況で必要になる評価基盤についてざっと振り返りました。この記事からさらに深い議論が起こると嬉しいです。
アバター
目次 導入 動画紹介1 動画紹介2 動画紹介3 動画紹介4 まとめ 導入 こんにちは。InsightEdgeのデータサイエンティストの小柳です。 本記事では前回の記事で紹介したPyMCの使い方を学ぶ一環として、PyMConの紹介をしようと思います。 突然ですが、PyMCに限らずモジュールの使い方を学ぶ際にはいくつか困難がありますよね。 PyMC固有の話とそうでない話を混ぜて挙げてみると 使う人があまり多くない。機械学習ならいざしらず、統計系の人は組織に少なくなりがち。したがって詳しい人が近くにおらずあまり人に聞けない。 公式ドキュメントを読んでもなんだかよくわからなかったり、なぜ例としているコードになったのかがわからないことがある。使用例のコードがない時もある。 教科書がない。あったとしても新しくて効率的な構文のキャッチアップができないことが多い。 これらを克服するためには忍耐強くデモコードを読み解いたり、実装を遡る必要があり大変です。 今回取り上げるベイズ統計用のMCMCサンプラーであるPyMCはコミュニティ作りを意識的にしており、PyMConウェブシリーズという名前でYouTubeに動画投稿をしています。 このシリーズの動画はPyMCの開発者や世界中で活躍するエンジニア、学校の先生たちがケーススタディー的に教えてくれていてすごくありがたいです。最新の機能のキャッチアップにもなります。 今回はこの動画シリーズの紹介をしようと思います。自分のやりたい分析に近いものがあったら見てみると新たな発見があるかもしれません。 PyMConは2020年位に始まったWebシリーズで、2020年に投稿されたものは'PyMCon 2020'とサムネに書いてあリますが、それ以降のやつは年度を切るのをやめてしまったみたいです。 全部紹介しているときりがないので、2023年に投稿されたものをいくつか紹介していきます。 動画紹介1 リンク: https://www.youtube.com/watch?v=0B3xbrGHPx0 テーマ:Automatic Probability スピーカー:Ricardo Vieira (PyMC Labs所属) Automatic Probabilityは自動微分のアナロジーです。 自動微分は偏微分を実行するルーティンであり、チェインルール、指数の微分ルール、積や商の微分ルール等を用いて機械的に微分を計算します。機械学習には必須で、最適化の勾配法やMCMCのNUTS、変分法に使われます。 一方自動確率は確率を自動で計算できるようにしたルーティンのセットで、列挙や、変数の交換などなどを行い確率を計算します。ベイズ統計には必須であり当然PyMCの内部でも使われている技術で、その紹介動画です。 内容はPyMCとそのバックエンドであるPyTensorを使った単純な分布の確率密度の計算や、変数変換時の確率密度計算、打ち切り分布の密度計算、条件付き確率密度の計算、混合分布の確率密度計算等です。 いくつか例示してみます。例えば確率密度の計算は以下の通りです。\ ->のところは出力だと思ってください。 import pymc as pm x = pm.Normal.dist() z = x + 5 def prob(rv, value): return pm.logp(rv, value).exp() prob(x,0.98146052).eval() -> array(0.24645622) prob(z,5.98146052).eval() -> array(0.24645622) このように、zの分布を指定していないのに変数変換ができています。 これは正規分布が平行移動しているだけなので難しくないですがそうでない場合も対応可能です。 例えば1対1変換で import pytensor.tensor as pt x = pm.Normal.dist() z = pt.exp(x) prob(x,-1.18149583).eval() -> array(0.1985122) prob(z,0.30681945).eval() -> array(0.64700006) と計算できます。ヤコビアンをかけてきちんと変数変換できているか確認してみましょう。 import numpy as np prob(z,0.30681945).eval()*np.exp(-1.18149583) -> 0.19851219823788108 うまくいっていますね。 次は多対1変換。実はこれもできます。 x = pm.Normal.dist(0,1) z = pt.abs(x) np.isclos( prob(x,0.3).eval(), (prob(z,0.3) /2).eval() ) -> True 打ち切り変換もできます。 rv = pm.Normal.dist(shape=(3,)) clipped_rv = pt.clip(rv, -1, 2) censored_rv = pm.Censored.dist(rv, lower=-1, upper=2) clipped_value = [-1, 0.5, 2] print( prob(clopped_rv, clipped_value).eval(), prob(censored_rv, clipped_value).eval(), sep="/n" ) ->[0.159 0.352 0.023] ->[0.159 0.352 0.023] 確率変数が2つ以上の時の確率密度や、条件付き確率密度も算出できます。 import pytensor import pytensor.tensor as pt from pymc.logprob.basic import conditional_logp x = pm.Normal.dist() y = pm.Normal.dist() z = x-y def conditional_prob(rvs_to_values: dict, fn=True): logps = conditional_logp(rvs_to_values).values() probs = [logp.exp() for logp in logps] if fn: values = list(rvs_to_values.values()) return pytensor.function(values, probs) else: return probs x_value = pt.scalar('x_value') y_value = pt.scalar('y_value') z_value = pt.scalar('z_value') prob_fn = conditional_prob({x: x_value, y:y_value}) print(prob_fn(x_value=0.5, y_value=0.9)) ->[array(0.35206533), array(0.26608525)] prob_fn = conditional_prob({x: x_value, z:z_value}) print(prob_fn(x_value=0.5, z_value=0.9+0.5)) ->[array(0.35206533), array(0.26608525)] prob_fn = conditional_prob({y: y_value, z:z_value}) print(prob_fn(y_value=0.9, z_value=0.5-0.9)) ->[array(0.26608525), array(0.35206533)] このような感じで、条件付き分布の確率密度が柔軟に計算できます。 直接使う方法はすぐには出てきませんが、PyMCとPyTensorの柔軟性を垣間見られて面白いかと思います。 動画紹介2 リンク: https://www.youtube.com/watch?v=b47wmTdcICE&t=1455s テーマ:Bayesian Causal Modeling スピーカー:Thomas Wiecki (PyMC Labs所属) 最近界隈で盛り上がっている因果推論系がテーマです。前半は実際にベイズを使った因果推論ですが、後半は最近出たPyMCシリーズのマーケティング用ツールPyMC-Marketingを使ったケーススタディで、ベイズとMMMを使って広告効果モデリングをした話です。 動画の詳細欄を見ればわかるのですが、スライドとコードが公開されているので詳細には立ち入らずちょっとした紹介程度にします。 前半はオーソドックスな因果推論の話で、扱う題材も広告効果です。 背景としてある商品の売上を上げるために、Google Adsでネット広告とTVCMを行った時に、本当にGoogle Adsに効果があるのかを知りたいという状況を考えます。 Google Adsを打った時と打っていない時での架空の売上のヒストグラムは以下の通りで、 引用: https://www.pymc-labs.com/blog-posts/causal-analysis-with-pymc-answering-what-if-with-the-new-do-operator/ t検定やベイズ的検定のどれを使ってもバッチリ差があると判定される結果です。 実はこのデータは人工的に作られたもので、その生成過程的には効果なしと出て欲しいものです。 さて、この状況に対し3つの変数とそれらの生成過程を以下のようにを考えます。 C:TVCM費用。連続値を取る。売上に影響を及ぼすし、相乗効果を狙うためGoogle Adsのオンオフにも影響を与える。 Z:Google Adsのオンオフ。0か1の二値を取る。売上に影響を与える。 Y:売上。連続値を取る。 この時のデータ生成過程を以下のように考えます。 このモデルに対し適当な事前分布をおいてやり、 の事後分布を見てやれば良いわけです。 今回の話は本来それで終わらせられるのですが、PyMCは5.8から因果推論系の機能を足したようでdo-operator等が紹介されています。本動画はそれを用いており、モデルの書き方は以下のようになります。ここまでは通常のモデリングと同じです。 with pm.Model() as model: # CからY,Zへの効果の事前分布 beta_c = pm.Normal('beta_c', shape=3) # ZからYへの効果の事前分布 beta_z = pm.Normal('beta_z', shape=2) # Yの観測ノイズ sigma_y = pm.HalfNormal('sigma_y') c = pm.Normal('c', mu=0, sigma=1, observed=tv_spend) z = pm.Bernoulli('z', p=pm.invlogit(beta_z[0] + beta_z[1]*c), observed=search_spend) y_mu = pm.Deterministic('y_mu', beta_c[0] + (beta_c[1] * z) + (beta_c[2] * c)) y = pm.Normal('y', mu=y_mu, sigma=sigma_y, observed=sales) idata = pm.sample() これに対して、do-operatorを用いてzをCから切り離して決定するモデルを定義しさらにそこからYをサンプリングするのは以下のコードになります。 from pymc_experimental.model_transform.conditioning import do model_z0 = do(model, {'z': 0}) model_z1 = do(model, {'z': 1}) with model_z0: idata_z0 = pm.sample_posterior_predictive(idata) with model_z1: idata_z1 = pm.sample_posterior_predictive(idata) そして、平均介入効果の計算も簡単です。 ATE = idata_z1.predictions - idata_z0.predictions このように非常に簡単にATEが計算できるようになっています。実際にこのデータでATEを算出すると、-0.1から0.1のあたりに分布しており、無事効果がないことがわかります。 今回挙げたような線形な関係性であればこれを使う必要はありませんが、非線形な効果が絡んでくるようなモデルを考える場合は便利になりそうです。 後半はMMMをベイズと組み合わせ分析のケーススタディになっています。実はここで紹介されているものはPyMC Labsが分析した事例で、PyMCon2020の動画に詳しい説明があるので興味があればご覧ください。 あまりMMMに詳しくないので、この事例では通常固定値とされるMMMのパラメータ時間とともに推移するようにモデリングしたようで、同様のモデルがPyMC-Marketingで使えるようです。 PyMC-Marketingは名前の通り広告効果分析に特化していて、ROAS(広告の費用対効果らしいです)や広告費を事後的にあの時いくらにしていたら的な分析、CLV(Customer Lifetime Value)推定等マーケティングで知りたくなりそうな分析は揃っているようです。 動画紹介3 リンク: https://www.youtube.com/watch?v=2dGrN8JGd_w テーマ:A Soccer-Factor-Model スピーカー:Maximilian Goebel (Università Bocconi所属) そもそもサッカーファクターモデルとは何でしょうか? 私は聞いたことがありませんでした。 これは金融業界で使われるファクターモデルというものから派生したものだそうです。 ファクターモデルとはリスク資産のリターンのモデルで、資産iのリターンを 1.その資産固有のリターン、2.すべての資産に影響を与える複数の要因の影響の線形結合、3.エラー項の3つの和として分解したもののようです。 サッカーファクターモデルよりは知名度があるようで、ファクターモデルでGoogle検索すると このページ を筆頭にいくつもヒットしますし、Wikipediaにも ページ があります。サッカーの方はヒットしません。 そのファクターモデルを使うことのご利益は2つあります。1つ目はファンドが市況の影響をどのように受けるかが推定できることです。そして2つ目はファンドのパフォーマンスから市況の影響を除去することでマネージャーがどれだけ優秀か=どれだけリターンを高められるかを推定できることです。 この2つ目のご利益を横展開して、チームスポーツにおいて個人の強さを推定してやろうというのが今回の動画のテーマです。 本動画ではサッカーをモチーフに各選手が試合でゴールを決める確率をモデリングします。 この が以下の確率を持つベルヌーイ分布に従うようなモデルを考えます。 これの各パラメータ、特に を見ることで、その選手のパフォーマンスから例えばチーム全体の調子や、チームのアシスト力のような要素を除去し本来のパフォーマンスを測ることができるのだそうです。 当然この手法の応用先は別にサッカーに限らず、チームスポーツだったり営業チームのパフォーマンスだったりと様々な例が考えられそうです。 モデルの良し悪しはROC、LogProb、RMSE等で測定していましたが、これは取り扱うテーマ次第でしょう。 分析に関してはそれほど難しい話ではないので省略します。 アイデアの面白さや応用先の広さ、ファクターをどうするか等を考えると分析者の力量が出そうなトピックでした。 動画紹介4 リンク: https://www.youtube.com/watch?v=ri5sJAdcYHk テーマ: Introduction to Hilbert Space GPs in PyMC スピーカー:Bill Engels(PyMC Labs所属) この動画のテーマはヒルベルト空間ガウス過程です。 私はそこまでガウス過程に詳しくないので正直このまとめはあまり自信がありません。 この動画ではそんなガウス過程初心者のために通常のガウス過程の特徴や長短所そしてその短所の乗り越え方としてのHSGP(Hilbert Space Gauss Process)を解説してくれています。といっても別に理論を詳細に扱うわけではありません。 ガウス過程の長所として 柔軟なモデリング。線形モデルもニューラルネットワークも可能 解釈可能。モデリング次第だが解釈可能なモデルも作れる。 不確実性の定量化。各地点の分散も計算可能 一方圧倒的な短所として 遅い。計算量が 。 が挙げられます。この短所に対して多くのアプローチが提案されており、その1つが今回の動画で紹介されているヒルベルト空間ガウス過程です。もちろんいつでも使えるわけではなく、 PPL(Probabilistic Programming Language:確率的プログラミング言語)を使う必要あり 入力変数次元は最大4 カーネル関数に制限あり 等の制約があります。このような特徴なので他のPPLでも実装できて、StanやBRMS、NumPyroで実施した例があるようです。 さて、PyMCでの実装です。まず通常のガウス過程をPyMCで実施する際には以下のようにします。 (注意:このコードはこのままでは動きません。詳細は https://github.com/bwengals/hsgp/blob/main/cherry_blossoms_hsgp.ipynb を参照ください。動画と同じコードがあります。) with pm.Model(coords=coords) as model: # Set prior on GP hyperparameters eta = pm.Exponential("eta", lam=0.25) ell_params = pm.find_constrained_prior( pm.InverseGamma, lower=10, upper=200, init_guess={"alpha": 2, "beta": 20}, ) ell = pm.InverseGamma("ell", **ell_params) # Specify covariance function and GP cov = eta**2 * pm.gp.cov.Matern52(1, ls=ell) gp = pm.gp.Latent(cov_func=cov) f = gp.prior("f", X=df["year"].values[:, None], dims="year") これをHSGPにするには gp = pm.gp.HSGP(m=[400], c=2.0, cov_func=cov) とするだけで、非常に簡単です。 PyMCを使ってHSGPを行うことにはいくつか長所があります。 インプットデータの次元を変えるのが簡単でpm.gp.HSGPの引数mを変えればよいだけ。 共分散関数を加法的に定義できる。covを2つ書いてHSGPの引数にcov_func=cov1+cov2をとるだけ。 好きなカーネル関数が書きやすい。よく使われる二乗指数カーネル、指数カーネル、Maternカーネルあたりはすでに実装されていますが、変わったものが使うことも可能。 基底と共分散を線形化した形で出力できる。これを使うことで予測時に高速に計算可能。 私があまりガウス過程に詳しくないのでこの機能の素晴らしさや使いやすさが伝えきれなかったかもしれませんが、ガウス過程の理解に役立てば幸いです。 まとめ 本記事ではPyMConの紹介をするための動画をいくつか紹介しました。各動画のテーマはバラエティに富んでいて、この記事を読むような方々なら恐らくどれかにはご興味いただけるかと思いますし、新しい知識を得るのに非常に役立ちそうな予感は感じられると思います。 PyMC界隈、特に日本語コミュニティはまだまだ活発になる余地は十分にあると思います。本記事がその一助になれば幸いです。 Insight EdgeではPyMCに限らず、様々な技術に興味を持っているデータサイエンティス・エンジニアを募集しています! カジュアル面談も行っていますので、興味がある方は以下サイトを御覧ください! recruit.insightedge.jp
アバター
こんにちは。Insight EdgeでDeveloperをしている熊田です。 昨今はインフラ環境を構築する際に、Infrastructure as Code(IaC)を検討することが多くなっているかと思います。 これまで私自身はIaCに触れてきませんでしたが、Terraformを使ってWebアプリを構築してみたいとは常々思っていました。 そんなときに、Streamlitフレームワークで開発したアプリをGCP上に構築する機会がありましたので、そのとき使用したコード等を本記事で紹介したいと思います。 目次 Streamlitについて インフラ/セキュリティ要件 構築してみた Terraformで構築する つまずきポイント まとめ/感想 Streamlitについて Streamlitをご存知でない方に向けての説明になりますが、StreamlitはPythonのWebアプリケーションフレームワークです。一番の特徴は、フロントエンドもPythonで書けることかと思います。 加えて、直感的にUI実装できるので学習コストが低く、幅広くチャートライブラリをサポートしています。そのような特徴から、データ分析結果をお手軽にダッシュボードで可視化したいときに便利です。 そういった利点があり、データサイエンティストを多く抱える弊社では、Streamlitを使ったアプリ開発が増えてきています。 以下はStreamlitを使ったサンプルコードです。 ### main.py ### import streamlit as st import pandas as pd import numpy as np # タイトル st.title( "Streamlit Sample" ) # サイドバー with st.sidebar: st.title( "[MENU]" ) option = st.sidebar.radio( "表示形式を選択してください" , ( "折れ線グラフ" , "棒グラフ" , "面グラフ" , "テーブル" )) # ランダムなデータを生成 chart_data = pd.DataFrame(np.random.randn( 20 , 3 ), columns=[ "a" , "b" , "c" ]) # チャートを表示 if option == "折れ線グラフ" : st.line_chart(chart_data) elif option == "棒グラフ" : st.bar_chart(chart_data) elif option == "面グラフ" : st.area_chart(chart_data) elif option == "テーブル" : st.table(chart_data) アプリ画面 インフラ/セキュリティ要件 Webアプリを構築するにあたってのインフラ要件を確認していきます。 Webアプリ開発の前段であるデータ分析にてGCPのサービスが使われており、Webアプリも同クラウドプラットフォーム上で完結させたかったため、今回はGCPで構築します。 StreamlitがWebSocket通信をするため、コンテナ実行環境はWebSocket通信をサポートしているCloud Runを利用することとしました。 セキュリティ要件としては、HTTPS通信、DDos対策、ユーザ認証を行う必要がありました。 加えて、今回のアプリは弊社開発メンバとエンドユーザの双方がアクセスするのですが、以下のような制約がありました。 弊社開発メンバ エンドユーザ Googleアカウントあり Googleアカウントなし VPNなし (固定IPなし) VPNあり (固定IPあり) そのため、弊社開発メンバとエンドユーザの認証方法を分けることにし、弊社開発メンバはSSO認証、 エンドユーザはEmail/PW認証&IP制限を設けて、セキュリティ要件を満たすようにしました。 セキュリティ対策では、GCPの以下サービスを利用して構築します。なお、本記事では各サービス機能の説明はしませんので、ご了承ください。 Load Balancer Cloud Armor Identity-Aware Proxy(IAP) Identity Platform 全体のインフラ構成図は以下の通りです。 構成図 構築してみた 実際に使用したコードをお見せして、つまづいたポイントなどを紹介したいと思います。 ### Dockerfile ### FROM --platform=linux/amd64 python:3.10 RUN pip install streamlit COPY src /app/src WORKDIR /app/src CMD ["streamlit", "run", "main.py"] ### docker-build.sh ### PROJECT_ID = < your-project-id > REGION = < your-region > PREFIX = < your-prefix > REPOSITORY = $REGION -docker.pkg.dev/ $PROJECT_ID / $PREFIX -repo IMAGE =streamlit-image TAG =latest APP = $PREFIX -app docker image build -t $IMAGE : $TAG . docker tag $IMAGE : $TAG $REPOSITORY / $IMAGE : $TAG docker push $REPOSITORY / $IMAGE : $TAG gcloud run deploy $APP \ --project $PROJECT_ID \ --image $REPOSITORY / $IMAGE : $TAG \ --platform managed \ --region $REGION \ --ingress internal-and-cloud-load-balancing \ --allow-unauthenticated \ --memory 2Gi \ --cpu 1 \ --max-instances 1 \ --timeout 900 \ --concurrency 80 \ --port 8501 Cloud Runをデプロイするために、Dockerfileとshellスクリプトを作成しています。 初期構築時はTerraformからshellスクリプトを実行します。初期構築後、Cloud Runをデプロイし直したい時はshellスクリプトのみを実行することを想定しています。 なお、外部ネットワークからCloud Runへ直接アクセスさせず、必ずLoad Balancerを経由させたいので、 gcloud run deploy のオプションに --ingress internal-and-cloud-load-balancing を指定しています。 Terraformで構築する Terraformを使って構築するにあたり、以下作業を行うことを前提としています。  1. Terraform実行用サービスアカウントの作成  2. ドメインの取得、DNSレコードの設定  3. Google Cloud APIsをコンソールから有効化  4. OAuth同意画面をコンソールから設定(こちらの記事の OAuth同意画面を設定する を参考にしました)  5. Identity Platformの設定(こちらの ユーザ作成 まで参照ください) 実行するTerraformコード(ver:1.4.7)は以下の通りです。 ### variables.tf ### variable "project_id" { description = "project id" type = string default = <your-project-id> } variable "project_number" { description = "project number" type = string default = <your-project-number> } variable "default_region" { description = "The default region for resources" default = <your-region> } variable "credentials_file" { description = "The path to the credentials file" default = <your-credentials-file> } variable "prefix" { description = "The prefix to use for all resources" default = "streamlit-app" } variable "oauth_domain" { description = "The domain to use for oauth" default = <your-oauth-domain> } variable "non_oauth_domain" { description = "The domain to use for non-oauth" default = <your-non-oauth-domain> } ### main.tf ### ## Provider ## provider "google" { credentials = file (var.credentials_file) project = var.project_id region = var.default_region } data "google_cloud_run_service" "default" { name = "$ { var.prefix } -app" location = var.default_region depends_on = [ google_artifact_registry_repository.my-repo ] } ## Artifact Registry ## resource "google_artifact_registry_repository" "my-repo" { location = var.default_region repository_id = "$ { var.prefix } -repo" description = "docker repository" format = "DOCKER" provisioner "local-exec" { command = "sh docker-build.sh" } } ## SSL Certificate ## resource "google_compute_managed_ssl_certificate" "default" { name = "$ { var.prefix } -ssl-certificate" managed { domains = [ var.oauth_domain, var.non_oauth_domain, ] } } ## Network Endpoint Group ## resource "google_compute_region_network_endpoint_group" "default" { name = "$ { var.prefix } -neg" region = var.default_region network_endpoint_type = "SERVERLESS" cloud_run { service = data.google_cloud_run_service.default.name } } ## Load Balancer Backend Service ## resource "google_compute_backend_service" "oauth" { name = "$ { var.prefix } -oauth-backend-service" timeout_sec = 30 backend { group = google_compute_region_network_endpoint_group.default.id } iap { oauth2_client_id = google_iap_client.oauth_client.client_id oauth2_client_secret = google_iap_client.oauth_client.secret } depends_on = [ google_iap_client.oauth_client ] } resource "google_compute_backend_service" "non-oauth" { name = "$ { var.prefix } -non-oauth-backend-service" timeout_sec = 30 backend { group = google_compute_region_network_endpoint_group.default.id } iap { oauth2_client_id = google_iap_client.non-oauth_client.client_id oauth2_client_secret = google_iap_client.non-oauth_client.secret } security_policy = google_compute_security_policy.non-oauth.id } ## Load Balancer ## resource "google_compute_url_map" "default" { name = "$ { var.prefix } -url-map" default_service = google_compute_backend_service.oauth.id host_rule { hosts = [ var.non_oauth_domain ] path_matcher = "non-oauth" } path_matcher { name = "non-oauth" default_service = google_compute_backend_service.non-oauth.id } } ## Load Balancer Proxy ## resource "google_compute_target_https_proxy" "default" { name = "$ { var.prefix } -https-proxy" url_map = google_compute_url_map.default.id ssl_certificates = [ google_compute_managed_ssl_certificate.default.id ] } ## Load Balancer Forwarding Rule ## resource "google_compute_global_forwarding_rule" "oauth" { name = "$ { var.prefix } -oauth-forwarding-rule" target = google_compute_target_https_proxy.default.id ip_address = google_compute_global_address.oauth.address port_range = "443-443" } resource "google_compute_global_forwarding_rule" "non-oauth" { name = "$ { var.prefix } -non-oauth-forwarding-rule" target = google_compute_target_https_proxy.default.id ip_address = google_compute_global_address.non-oauth.address port_range = "443-443" } ## IP Address ## resource "google_compute_global_address" "oauth" { name = "$ { var.prefix } -oauth-global-address" } resource "google_compute_global_address" "non-oauth" { name = "$ { var.prefix } -non-oauth-global-address" } ## IAP OAuth Client ## resource "google_iap_client" "oauth_client" { display_name = "IAP OAuth Client" brand = "projects/$ { var.project_number } /brands/$ { var.project_number } " } resource "google_iap_client" "non-oauth_client" { display_name = "IAP Non OAuth Client" brand = "projects/$ { var.project_number } /brands/$ { var.project_number } " } ## IAP IAM ## resource "google_iap_web_backend_service_iam_binding" "default" { web_backend_service = google_compute_backend_service.oauth.name role = "roles/iap.httpsResourceAccessor" members = [ "domain:<your-domain>" , "user:<your-user>" , ] } ## Cloud Armor ## resource "google_compute_security_policy" "non-oauth" { name = "$ { var.prefix } -non-oauth-security-policy" description = "non-oauth security policy" rule { action = "allow" priority = 0 match { versioned_expr = "SRC_IPS_V1" config { src_ip_ranges = [ "<your-ip>" ] } } description = "allow rule" } rule { action = "deny(403)" priority = 2147483647 match { versioned_expr = "SRC_IPS_V1" config { src_ip_ranges = [ "*" ] } } description = "default deny rule" } } 上記Terrafomコードですが、IAPのEmail/PW認証に関する設定が不十分な(いま現在、Terraformがサポートしていない)ため、 ここからはコンソール上で設定していきます。まずは、外部IDの承認をします。 外部ID承認 認証ページ設定 これにより、Email/PWを利用しての認証ページが自動作成されます。アクセスしてみると以下画面になります。 認証ページ なお、システム管理者のみにユーザ追加、削除させたいのでIdentity Platformの設定をコンソールから変更しています。 Identity Platform設定 手っ取り早く外部IDを利用した簡単な認証を作成できるのが良いですね。 Email以外にもMicrosoftアカウントやX(旧Twitter)アカウントなども選択できるので、いつか試してみたいです。 つまずきポイント Terrafom実行でつまずいたところは色々ありましたが、大きなところでいうと2点です。 まず1点目は、OAuth同意画面の設定です。前提④で実行した内容ですが、 当初は google_iap_brand を利用してTerraformで設定しようと考えていました。しかし、applyしようとすると Error 400: Support email is not allowed のエラーが出てしまいました。 調べてみても有効な解決策を見つけられませんでしたが、どうやらOAuth同意画面の設定はTerraformでの管理に向かないようです。 というのも、APIを介してのOAuth同意画面の変更、削除はできないとのことです。変更するにはコンソールから操作する必要があります。 であれば、Terraformで管理することは必須でありませんので、コンソール上から設定することにしました。 ※調査の際は、こちらの記事を参考にさせていただきました。 Terraform で IAP 設定する 2点目は、Terraform構築が無事完了しアクセスしてOAuth認証も成功して、 アプリのトップ画面を開こうとすると The IAP service account is not provisioned のエラーが出たところです。 公式ドキュメント によると、 IAPサービスアカウントを作成しないとCloud Runを起動できず、このエラーになるようです。 gcloud beta services identity create --service=iap.googleapis.com --project=<your-project-id> 上記を実行したところ無事アプリを開くことができました。以前にコンソールでIAPを有効化したときは実施していなかったので戸惑いましたが、 公式ドキュメントをよく読むと、APIを介してIAPを有効化した際は、上記コマンドでIAPサービスアカウントを作成する必要があるようです。 まとめ/感想 以上、Terraformを使ってGCP上にでセキュアなアプリを構築してみたときのお話でした。 認証機能を自前で実装となるとかなり大変なので、こういったIAPやAWS Cogniteのような認証サービスを利用できるのはとてもありがたいですね。 ただ、今回はIAP周りのIaC化がとてもややこしく手間どりました。触ってみて、IAP周りのTerraformおよびGCP APIは両方とも現在も開発中っぽく、ここの部分については無理にIaC化しなくても良さそうと感じましたが、必要作業について自分なりに整理できたのでやってみてよかったです。 社内に限らず、社外でもStreamlitを使ったアプリ開発が今後増えていくと思われますので、この記事が参考になれば幸いです。 参考 Cloud Run+Cloud SQL構成をTerraformで管理する GCP上でセキュアなCloud Runを構築する方法(Terraform事例有)
アバター
こんにちは!リードプロジェクトマネージャーの加藤です。つい先日までは残暑に四苦八苦しておりましたが、いつの間にか、金木犀の香りが漂う季節となり、とても過ごしやすい季節になりましたね。皆様いかがお過ごしでしょうか? さて、今回の記事では、タイトルにある通り、Insight EdgeでのPM/PL採用について言及してみたいと思います。背景としてはInsight Edgeが設立4年を経過し、組織拡充に向けてより採用を強化している点も理由の1つにあるのですが、私が入社して丁度1年が経過しようとしており、その1年過ごした実績を踏まえ、PM/PL採用の応募要項では伝えきれないリアルな求める人物像について語りたい点が理由としては大きいです。具体性を持って赤裸々に語れればと思いますので、最後までどうぞお付き合い頂ければ幸いです。 (当社の業務内容、及びそれを踏まえた私が考えるプロジェクトマネジメント業務そのものの要諦については 前回記事 もご参照ください) techblog.insightedge.jp 前回記事のおさらい 先ずは前回記事のおさらいからになりますが、当社業務の主軸となるのはDXを通じた企業価値向上、ないしは新規事業創出、業務オペレーションの変革等々と言った、所謂デジタルを介した企業/業務変革と称しても過言ではありません。その中でPM/PLとしての活動領域の中心となるのは企画/構想段階におけるマネジメント、及び開発段階での開発マネジメントとなる点は前回もお伝え致しました。具体的な業務プロセスについては前回触れておりますので、今回はそれぞれの具体的な情景から実体験も踏まえ、どのような人物像がPM/PLとして相応しいか(我こそは、と言う人に是非応募して欲しい!) を記載したいと思います。 多岐に亘るステークホルダーを主体的に巻き込み、業務推進可能な事 Insight Edgeで対応している各DX案件の何よりの特徴として、関係者が非常に多岐に亘る点が挙げられます。基本的にDX案件では、これまで取り扱っていない未知の事業領域に参入する、ないしはこれまで行ってきた業務を様々な事業戦略に基づき変革を試みる事が要求される為、該当案件のビジネスオーナーとなる事業部(事業会社)だけではなく、協業先の事業部(事業会社)、リスクや法務での関連部署、特定の技術提供を行うパートナー会社、実顧客等々、多種多様なステークホルダーと協業する必要があります。また、住友商事、及び住友商事グループ各社で取り扱っている事業領域の多寡にも起因し、A案件では金属業界、B案件ではエネルギー等、アサイン状況によっては全く異なる業界のDX案件の推進を複数任せられるケースもあります。この様に担当案件によって、全く異なる業界、且つ担当案件に如何に関わらず、非常に大勢の関係者との協業が求められる為、特定期間に集中して関係者を巻き込んで着実に案件推進を成功裡に収める必要があります。PM/PLとしては基本ではありながらも、関係者それぞれの思惑や意向が異なる中でプロジェクト奏功に向けて、各位のそれらを纏め上げる事に対して前向きに取り組める人物が相応しいと感じております。 リーダーシップを発揮し、如何なる困難にも屈せず立ち向かう姿勢 上記の関係者の多寡にも掛かる話ではありますが、関係者全員のデジタル素養、開発経験と言ったITリテラシーやプロジェクトマネジメントの知見も異なる点から、関係者毎に適切なレベル感での情報共有を行いながら、主体的にリードしていく気概も非常に重要です。再掲となりますが、基本的には前例や経験のない事業戦略立案がDX案件には内包されている為、各々が考える期待値の相違やどう進めていけばいいのか、ないしはリテラシーの濃淡によっては、そもそも一方が意図する事が適切に伝わらず、意思統率の時点でそれが困難になるケースも散見されます。更に言えば、前例がないからこそ、企画/構想としてはある程度煮詰まってきた段階で、ビジネス・技術何れかの要因で、これまで検討してきた方針では立ち行かなくなる可能性が生じるノックアウトファクターに直面し、推進が難航するケースもあり得ます。プロジェクトマネジメントの観点で言えば、共通言語としてのプロジェクト憲章やコミュニケーション定義書、用語集やコンティンジェンシープランを事前に策定し関係者合意を図る事が重要でありながらも、こうした状況に陥ったとしても諦めるのではなく、常にリーダーシップを発揮しながら、時にはプロジェクト外の有識者や社内メンバー等、凡ゆるネットワークを駆使し、問題解決に向けて愚直に歩みを進められる・進めていこうと言う姿勢こそが必須と私は考えます。 エンジニア・ユーザと適切にコミュニケーションを取りながら、前向きに前進出来る事 ここからは主に実開発のマネジメント経験を踏まえての記載となります。手前味噌な記載で恐縮ながら、入社して一番想像通りであり、実際に目の当たりにした際に感嘆とした点が、Insight Edgeに所属する各社員の専門性、及び技術力の高さです。実際のエンジニアリング能力もさることながら、技術領域に対する知見の深みは目を見張るものがあり、具体見当が進んでいない柔らかい状態で技術相談をしても、真摯、且つ即座に具体案の提示やそれに伴うリスク等の開示も行なって頂ける為、その点は本当に有難いです。一方で、開発案件を進めていく中では時には技術観点ではより高度な手法を取るべき所を、ビジネス観点ではコストや期間見合いで一旦は見送りたい、または折衷案の採択を行いたいケースが出てくる場合も散見されます。逆も然りで、ビジネス観点で実現したい事と実際に技術的に出来る限界値、または技術あり気ではなく、ビジネス観点での協力や歩み寄りによってのみ実現出来る要件等、現時点の技術で実現出来る範囲と実際にユーザが技術で実現したい点でギャップが生じるケースもあります。PM/PLとしては、各々の背景や意向を具に確認した上で、双方が納得する折衷案の検討や、そもそも両者が共通で掌握出来るレベル感に情報粒度を統一して開示する必要もあります。こうした事から、主体的に適切なコミュニケーションを適宜実施し、単なる情報の橋渡し役に留まらず、常に当事者意識を持って全体の納得感を得ながらプロジェクト推進を行える姿勢も求められます。 QCDを適切に調整・折衝可能である事 Insight Edgeで取り扱う開発案件の多くがPoC案件となります。商用開発前の実証実験の段階になる為、ユーザとしては極力コストを抑えながら、如何に早く出来上がったプロダクトを実際に触りながら検証を行えるか、を求められるケースが多々有ります。一方であまりにもコスト・納期に傾倒し過ぎると品質がおざなりになり、そもそも検証に耐えうるプロダクトにならなかった、または余計な追加コスト・期間が計上されてしまうリスクも出てきてしまう為、QCDの按分を見極め、適切な開発スコープ策定、及び体制とスケジュール検討をする点はPM/PLとして非常に腕の見せ所となる部分です。もう少し踏み込んで言えば、その後の開発リスクを勘案して企画/構想段階より、それらQCDの調整を実現案ベースにリスク事項を含め可視化し、適切に関係者間で合意形成を図れる事が非常に重要で有り、求められる要素だと考えております。 本気で技術の力で世界を”Re-Design”したいと思えるかどうか 最後の記載は具体経験とは異なり、採用過程で言うところの所謂、志望動機や熱意になります。私が入社を志した理由の一つに、様々な業界、産業分野の社会課題を技術の力でDXを通じて一つでも多く解決したいと考えていた点が有ります。この点については、入社前も入社後も変わらず、当社の同僚、及び住友商事/住友商事グループ各社における関係者全ての人も上記飽くなき情熱を持って、業務遂行に励んでいます。個人的には職種毎にある程度のスキル・経験・(会社の求める)パーソナリティの一致、と言うのは重要と考える一方で、一番大事なのは組織全体が追い求める全社ミッションや理念に心から賛同し、同じ志を持てるかどうか、だと考えています。 最後に 如何でしたでしょうか?今回はInsight Edgeで求めるPM/PL人物像の詳細について記載させて頂きました。冒頭でも触れた通り、Insight Edgeは設立4年を経過し、当社が抱えるミッション達成をより高度化・加速化させるべく、組織拡充を担い、採用を強化しております。PM/PL募集についてもこれまで以上に採用強化していく予定につき、上記具体情景を踏まえ、我こそは!と言う方には是非ともご応募頂きたく、何卒よろしくお願い致します!一緒に働ける事を楽しみにしております!!
アバター
こんにちは、Insight Edge(以下、IE)のData Scientistの石倉です。私はIEにジョインしてから約1年が経ったところで、振り返るとまだ1年かと思う時もあれば、もう1年かと思うこともある不思議な感覚です。最近は様々なプロジェクトに携わっており、ChatGPT (LLM)活用プロジェクトもその1つです。今回は、IE内のChatGPT活用の一部を紹介しようと思います! 目次 はじめに 従来のテキストマイニング ChatGPTを用いた分析 Streamlit for LLM まとめ 参考文献 はじめに 皆さん既にご存知の通り、ChatGPTをはじめとした大規模言語モデル(以降LLM)が最近注目を集めており、本Tech Blog内でも既にいくつかChatGPT関連の記事を出しています。 総合商社ビジネスにおける生成AI活用 - Insight Edge Tech Blog ChatGPT(LLM)のビジネス現場での活用に向けた技術的な課題と取り組み - Insight Edge Tech Blog Insight Edgeは住友商事グループ各社(国内外約900社ほど)のDXを推進するために設立された企業で、生成AIのビジネス活用もその一部です。本稿では、従来のテキストマイニングで行ってきた分析タスクをChatGPT(LLM)を用いてどのようなことができるか処理プロセスの比較も含めてお話しできればと思います。 従来のテキストマイニング テキストマイニングは、大量のテキストデータの中からパターンやトレンドを識別することを目的としており、以下が主要なプロセスとなります。 データ収集: データはウェブページ、社内文書、SNSの投稿、レビューなど、さまざまなソースから収集され、目的に応じて異なります。 前処理: 収集したテキストデータは、しばしばノイズや不要な情報が混じっているため、それをクリーニングする必要があります。このステップでは、トークン化、ストップワードの除去、ステミングや形態素解析、正規化などの処理が行われます。 特徴量の抽出: テキストから特徴を形成します。例として、TF-IDF(Term Frequency-Inverse Document Frequency)やWord2Vec、BERTなどの深層学習ベースの手法が挙げられます。 データ探索: 統計的な手法やビジュアル化を利用して、データ内のパターンやトレンドを探るためのステップです。 統計的分析: テキストデータの頻度分析や共起分析などを行い、どの単語やフレーズが多く使われているのか、どの単語が他の単語と一緒によく現れるのかを調査します。 可視化: ワードクラウドや共起ネットワークの可視化などを利用して、テキストデータの特性を直感的に理解する。 モデリング: データ探索で得られた知識を基に、特定のタスクを達成するためのモデルを構築するステップです。 テキスト分類: サポートベクトルマシン(SVM)、ランダムフォレスト、深層学習(CNN、RNN、Transformerベースのモデルなど)を用いて、テキストを定義されたカテゴリに分類します。例えば、感情分析やスパムメールの識別などがこのタスクに該当します。 クラスタリング: K-meansや階層的クラスタリング、トピックモデリングなどの手法を用いて、テキストを自然にグループ化します。これは、カテゴリが事前に定義されていない場合や新しいトピックを発見したいときに役立ちます。 関連性分析: コサイン類似度やJaccard係数などのメトリクスを用いて、テキスト間の距離や関連性を測定し、レコメンデーションや変数間の関連性の探索などに使用されます。 評価: 生成されたモデルのパフォーマンスを評価します。モデルの精度や再現性を確認し、必要に応じてモデリング段階に戻って改善を図ります。 前処理/特徴量抽出/モデル作成/評価などのステップが多く、モデル評価後でも、収集されたデータを処理にかける度にビジネス側のユーザーが分析の視点を持って都度出てきた結果を解釈する必要があります。 ChatGPTを用いた分析 上記で触れたテキストマイニングを行なってどの様な活用をしたいかは各企業/ユーザーによって異なりますが、世間を賑わせているChatGPT(LLM)を用いて、従来行われていたテキストマイニングの処理/解釈プロセスを大幅に削減できる可能性があります。本記事ではChatGPTを用いた分類と要約タスクを行なってどの様なことができるのかを紹介しようと思います。 イメージしやすいようにテーマとしてはとある旅館の口コミを分析することを想定します。 ※本例で取り扱うもの(口コミや分類カテゴリ)は全てChatGPTを用いて生成したもので、架空のものです。 分類タスク 以下の例では、口コミを与えられた分類カテゴリに分けています。従来のテキストマイニングでは前処理/特徴量の抽出/関連性分析などのプロセスによって与えられたカテゴリとの類似度を計測し、ある程度の分類は可能です。また、クラスタリングを行うことでテキストデータのグルーピングが可能です。しかし、関連性分析やクラスタリングなどで詳細なラベル付や解釈は難しく試行錯誤の時間を要します。そのような点で、以下の例では、ChatGPTを用いることにより階層構造のカテゴリにも十分に対応できていることが見て取れ、大幅な分析タスクの簡略化が見込めそうです。 分類タスク 分類結果 要約タスク 要約については、過去のTech blogにもある通り、Map ReduceやRefineなどの手法を用いて要約が可能です。しかし、一言で”要約”と言えど、以下の様に注意すべき点は多いと思います。 情報の抽出:本質的な情報を正確に抽出し、不要な情報を省く必要がある。 コンテキストの理解:コンテキストを理解し、本質的な情報を適切に伝える必要があります。コンテキストを見失うと、要約が誤解を招く恐れがあります。 長さの制約:情報を簡潔に伝えるために、一定の長さに制約されます。重要な情報を省略せずに、分かりやすく伝えるのは難しい場合があります。 対象者の認識:要約の対象者やその知識レベル、ニーズに応じて、要約の内容やスタイルを適切に調整する必要があります。 バイアスの排除:要約者の主観やバイアスが要約に影響を与えないように、客観性と公平性を保つ必要があります。 LLM関連論文の出稿が最近多く、幅広く追いかけることが難しくなっている今日この頃ですが、難しい要約タスクについてプロンプトエンジニアリングのみで質の向上を図った比較的実装も容易そうなものを見つけたのでご紹介しようと思います! 論文紹介 ~ From Sparse to Dense: GPT-4 Summarization with Chain of Density Prompting 本稿ではOpenAIの提供するGPT-4を用いて、「Chain of Density(CoD)プロンプト」と呼ぶ方法を提案し、要約の質の向上を図ったものになります。 既にGPT-4で要約タスクを試されたことある方はご存じかと思いますが、シンプルな”以下の文を要約してください。”といったプロンプトを投げるだけでは冗長な要約文が生成されることが多く、情報として十分な場合はあるものの、質的観点からはあまり良しとはされていません。 今回提案されたCoDプロンプトの手法では、最初に冗長な要約を生成したのち、文の長さを増やさずに欠けている重要な要素を反復的に加えていきます。CoDによって生成された要約は、標準的なプロンプトによって生成されたGPT-4の要約と比較して、より抽象的かつ、より情報統合されており、冒頭部分への偏りが少ないという結果が出ています。 Chain of Density prompt しかし、情報過多になりすぎると人間の好みとはかけ離れていくことについて言及されており、明瞭さと情報量のトレードオフの関係を対象者に応じて変更させて調整する必要があると考えられます。本手法のメリットはChain of Density stepにより明瞭さと情報量をコントロールできることを示唆していると思われ、開発側でプロンプトを試行錯誤しながら要約内容を都度確認し、ユーザーの求める要約の状態まで上手く生成できるように都度調整する手間が省けそうです。 本論文ではニュース記事のみを取り扱っているとのことでした。現状のままだと、入力する記事のトークン数が非常に大きくなりやすく、実装する上でボトルネックになる可能性があります。しかし、プロンプトエンジニアリングだけでここまでのことができるとは大変興味深いです。 CoD step Streamlit for LLM 去年にIE社内の勉強会でStreamlitを触り始めてから、色々と遊んでいたのですが、最近は案件でプロトタイプ提供のために使う機会も増えてきました。既にご存知の方も多いと思うので Streamlit の詳細はここでは割愛します。 触り始めてから今に至るまで次々と新しいバージョンがリリースされ、最近のLLMブームの影響を受けてか、 LLM用の機能 も新たに追加されています(まだ少々扱いづらい点はありますが早期に改善されていくと思います。)。 下図はStreamlitを用いた試作です。前節の分析にて一度分類タスクが完了すると、カテゴリ毎の件数などの可視化も容易になります。また、生成AIの得意とする要約などの要素も追加することで、ユーザー側での解釈性の大幅な向上が期待でき、従来のワードクラウドや共起ネットワークによる分析解釈をする必要がなくなりそうです。さらに、Retrieval-augmented generation (RAG)の機能も追加することでユーザー側でチャットボットとして対話をすることも可能になります。 streamlit まとめ 今回はChatGPTの活用例について紹介しましたが、従来のテキストマイニングのプロセスと比較するとかなり短縮でき、ユーザー側でも十分な解釈性の向上が期待できそうです。まさに生成AIブーム真っ只中にいる私たちですが、生成AIのできるタスクを複合的に組み合わせることで様々な便利サービスを作ることができそうです。そのためにも技術のキャッチアップを怠らず、日々注視していきたいと思います!(最近論文の出稿が多すぎてついていけるか不安です 笑) 参考文献 Griffin Adams, Alexander Fabbri, Faisal Ladhak, Eric Lehman, Noémie Elhadad "From Sparse to Dense: GPT-4 Summarization with Chain of Density Prompting"
アバター
Introduction こんにちは、データサイエンティストの善之です。 Insight Edgeでは社内のコミュニケーション活性化を目的として定期的にシャッフルランチを開催しています。 企画の全体像については以前ntさんに投稿いただいた 社員同士の距離を縮める!シャッフルランチ会開催レポート をご覧ください。 今回は、ntさんの記事で詳しく触れていなかった「グループ分けを最適化するアルゴリズム」の詳細をご紹介したいと思います。 目次 実現したいことと課題 要件の整理 アルゴリズムの概要 Pythonで実装 実行結果 引き継ぎのためにStreamlitでUIを作成 まとめ 実現したいことと課題 ランチ会の目的は以前の記事にも記載の通り、コミュニケーション活性化のために社員同士の接点を増加させることでした。 したがって、 普段あまり接点がない人どうしをランチ会でできる限り巡り合わせる ことが最大のミッションでした。 さらに、企画の要件から次の制約条件もありました。 各社員が3回参加(月に1回、3ヶ月間) 1グループあたり4-5名 参加者は31名 これらの制約を満たしながら、普段あまり接点がない人どうしの接点を最大化させる必要があったのですが、全て手作業で決めるのは至難の業です。 手作業でもある程度良い組み合わせは見つけられるかもしれませんが、労力がかかるうえに最適解よりも接点がない人どうしの組み合わせ数が少なかったり、 制約を一部満たせなかったりするかもしれません。 そこで、今回はPythonで遺伝的アルゴリズムを使って最適解を探索し、組み合わせを自動で決定するアルゴリズムを開発しました。 要件の整理 あらためて、今回の要件を整理したいと思います。 最大化する目的関数 普段あまり接点のない人どうしが同じグループになる回数 (ただし、重複も1回とカウント。たとえば普段あまり接点のない同一ペアが3回とも同じグループになっても1回とカウント) 制約条件 企画段階から決まっていた要件 各社員が3回参加(月に1回、3ヶ月間) 1グループあたり4-5名 参加者は31名 アルゴリズムを作成する過程で加えた方が良いと判断した制約 マネージャーどうしは同じグループにはならない(普段から接点が非常に多いので) メンバーの中身がほとんど同じチームは2回以上できない(今回はチームのうち3人以上が他の回と同じ組み合わせになるチームを除外) 3回とも同じ人と同じチームにはならない 今回はこれらの条件を満たすアルゴリズムを開発しました。 アルゴリズムの概要 基本的なアイデア まずは基本的なアイデアを紹介します。 今回は1-3月に毎月1回ずつランチ会を開催しましたので、はじめに全メンバー(31名)のリストを計3回分作ります(3×31の2次元配列になります)。 そして、月ごとにメンバー31名の順番をランダムに並べ替えておきます(①) 次にこのリストを左から順に5人→5人→5人→4人→4人→4人→4人に区切って分割します(②) これで月ごとに全31名を5人グループ×3と4人グループ×4に分割できました。 あとは、ランダムな並べ替えパターン全通りの中から制約条件を満たすパターンだけに絞り込み、 その中で普段あまり接点のない人どうしが同じグループになる回数が最大のものを抽出すれば完了になります。 ですが、今回はこのパターン数が膨大なので、計算に時間がかかり過ぎてしまいます。 実際に月ごとにメンバーの順番をランダムに並べ替えるとすると、全パターンが 31!×31!×31!=5.56e+101通りあり、とても計算できないです。 もう少しスマートに、ランダムな並べ替えではなくメンバーの組み合わせパターンのみを考えることで試行数は減らせますが それでも計算量は膨大です(1ヶ月分の組み合わせだけでも9.96e+19通りあります) そこで、今回は 遺伝的アルゴリズム を使って効率的に解を探索することにしました。 遺伝的アルゴリズム 遺伝的アルゴリズムとは、自然進化の原理をもとにした最適化技術であり、選択・交差・突然変異といったステップを通じて解の質を逐次的に向上させるアルゴリズムです。 (解の効率的な探索手法であって、必ずしも最適解が求まるとは限らないことに注意が必要です) アルゴリズムの概要を図にまとめました。 このアルゴリズムの手順は ① 初期個体をランダムにN個生成 ② N個の個体から、目的関数のスコアが良い個体Best2を選択 ③ ②で選定した2つの個体から、交叉と変異を用いて新しい個体をN個生成 ④ ③で生成されたN個の個体を新たに②のインプトットとして、②-③の手順をM回繰り返す(このMは世代数と呼ばれる) となります。 ただし、今回は最適化したい配列が1次元ではなく、3ヶ月分の3次元の配列ですので、このアルゴリズムをそのまま適用できません。 そこで今回は、遺伝的アルゴリズムをカスタマイズして実装しました。 実装した方法を図に示します。 基本的なアイデアは先ほどと同じですが、交叉と変異は月ごとのメンバー全員の配列ごとに行いました。 なお、②の個体の選択では、1-3月の合計スコアから最良の個体を判定しています。 以上が今回実装した遺伝的アルゴリズムになります。 制約条件の反映 さて、ここまでのアイデアを実装すれば - 各社員が3回参加(月に1回、3ヶ月間) - 1グループあたり4-5名 - 参加者は31名 これらの制約を満たしつつ、普段あまり接点のない人どうしが同じグループになる回数をできる限り最大化できそうです。 一方で、以下の制約については別途考える必要があります。 - マネージャーどうしは同じグループにはならない(普段から接点が非常に多いので) - メンバーの中身がほとんど同じチームは2回以上できない(今回はチームのうち3人以上が他の回と同じ組み合わせになるチームを除外) - 3回とも同じ人と同じチームにはならない これらの条件については、満たさないケースでは目的関数の値を大きく減らすことで、 極力これらの制約を満たさないものは選ばれないように工夫しました。 具体的には、制約を満たさないケースがある個体(たとえば、マネージャーどうしが同じグループになるケースがある個体)は、 条件を満たさなかったケースごとに目的関数のスコアを-100するようにしました。 Pythonで実装 では、ここまで説明してきたアルゴリズムをPythonで実装していきます。 1. 事前準備 まず事前準備として、組み合わせをExcelにしてまとめておきます。 図のような表形式で、普段あまり接点がなさそうな人どうしの組み合わせに◯をつけていきました (○はマネージャー陣につけてもらいました)。 なお、画像は本記事のために作成したダミーデータです。○は乱数をもとにつけています。 2. 必要なモジュールのimport ではPythonでの実装に入ります。まず必要なモジュールをimportしておきます。 今回は遺伝的アルゴリズムも自前で実装するため、pandas以外に外部ライブラリは用いません。 import itertools import random import sys from collections import Counter import pandas as pd 3. チーム分け用関数の作成 はじめに、メンバーの配列を5人チームと4人チームに分割する関数を作成します。 基本的なアイデア における「② 各月で左から順に5人グループと4人グループに分割」の部分です。 たとえば、 people = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] の場合は [["A", "B", "C", "D", "E"], ["F", "G", "H", "I"]] のように、引数 people を4人と5人のグループに分割した配列が返却されます。 def divide_teams (people): n = len (people) result = [] # 4人チームの最大数 max_fours = n // 4 # 5人チームと4人チームの組み合わせを検討する valid_division = False for i in range (max_fours + 1 ): if (n - i * 4 ) % 5 == 0 : four_person_teams = i five_person_teams = (n - i * 4 ) // 5 valid_division = True break if not valid_division: raise ValueError (f "この人数({n}人)は4人チームと5人チームに分割できません" ) # 5人チームの分割 for _ in range (five_person_teams): team = people[: 5 ] result.append(team) people = people[ 5 :] # 4人チームの分割 for _ in range (four_person_teams): team = people[: 4 ] result.append(team) people = people[ 4 :] return result 4. 普段あまり接点がない人どうしをカウントする関数の作成 ここでは、生成されたグループのうち、普段あまり接点がない人どうしの組み合わせが何回発生しているかを計算します。 この値を最大化するのが、今回の目的になります。引数 groups は、 divide_teams 関数で生成された配列です。 また、 count_good_combinations の引数 good_pairs は1.事前準備で作成したExcelにおいて○がついていたメンバーの組み合わせを格納したタプルとなっています。 def make_unique_pairs_from_groups (groups): # 全グループでのメンバー同士のユニークな全組み合わせを作成 pairs = [] for group in groups: pairs += list (itertools.combinations(group, 2 )) # タプルの順番を問わずに重複ペアを削除 unique_pairs = list ( set ( tuple ( sorted (pair)) for pair in pairs)) return unique_pairs def count_good_combinations (groups, good_pairs): # 新しい組み合わせ数を計算する関数 # 全体のペアをユニークに取得 unique_pairs = make_unique_pairs_from_groups(groups) # まだ話したことがない組み合わせの数を計算 count = 0 for pair in unique_pairs: if pair in good_pairs: count += 1 return count 5. 制約条件の追加 次に制約条件を追加していきます。 各制約条件を 満たさない ケースをカウントする関数になります。 まずは、マネージャーどうしが同じグループになっている件数をカウントする関数です。 引数 to_divide_members には、マネージャーの名前が入っている想定です。 def count_to_divide_combinations (groups, to_divide_members): # グループごとにペアを作成 pairs = [] for group in groups: pairs += list (itertools.combinations(group, 2 )) # タプルの中身をsort sorted_pairs = list ( tuple ( sorted (pair)) for pair in pairs) # 分割したい人たちのペアを作成 to_divide_pairs = [ tuple ( sorted (pair)) for pair in itertools.combinations(to_divide_members, 2 ) ] # countする count = 0 for sorted_pair in sorted_pairs: if sorted_pair in to_divide_pairs: count += 1 return count 次に、メンバーの中身がほとんど同じチームの件数をカウントする関数です。 def count_overlap_groups_over_threshold (groups, threshold): # メンバーの重複がthreshold以上のグループをカウントする # たとえば、thresholdが3の場合、3人以上が被っているグループがいくつあるかをカウント count = 0 for i in range ( len (groups)): for j in range (i + 1 , len (groups)): # 重複要素を見つける overlap_set = set (groups[i]) & set (groups[j]) # threshold以上の重複がある場合、カウントを増やす if len (overlap_set) >= threshold: count += 1 return count 最後に、3回とも同じ人と同じチームになった件数をカウントする関数です。 def count_multi_pairs_over_threshold (groups, threshold): # グループごとにペアを作成 pairs = [] for group in groups: pairs += list (itertools.combinations(group, 2 )) # タプルの中身をsort sorted_pairs = list ( tuple ( sorted (pair)) for pair in pairs) # 重複をカウント # threshold以上同じグループになったペアをカウント counter = Counter(sorted_pairs) return sum ( 1 for count in counter.values() if count >= threshold) 以上の関数をもとに、これらのケースができる限り起こらないような目的関数を作成していきます。 6. 制約を加えた目的関数の設定 それでは、制約を加えた最終的な目的関数を定義します。遺伝的アルゴリズムでは、このスコアが最大になるように解を探索していきます。 制約条件を満たさない場合は、 penalty_score を乗算して1件につきスコアを-100する設計にしています。 これによって、これらの制約条件をできる限り満たしながら、普段あまり接点がない人どうしの組み合わせを最大化できます。 なお、後ほど引数で渡しますが、今回 multi_pair_threshold は3(3回とも同じ人と同じになることは避ける)、 overlap_threshold も3(3人以上同一メンバーが含まれるチームの生成は避ける)にしています。 def calculate_score ( groups, good_pairs, to_divide_members, multi_pair_threshold, overlap_threshold, penalty_score= 100 , ): # 普段あまり接点がない人どうしの組み合わせをカウント good_count = count_good_combinations(groups, good_pairs) # 分割したい人たち(マネージャー陣)のペアをカウント to_divide_count = count_to_divide_combinations(groups, to_divide_members) # 一定回数以上同じペアをカウント(例: ランチ会3回中3回とも同じ人と同じ) multi_pair_count = count_multi_pairs_over_threshold( groups, multi_pair_threshold ) # ほとんど同じグループをカウント(例: メンバー4人中3人が、前回と同じ人たち) overlap_groups_count = count_overlap_groups_over_threshold( groups, overlap_threshold ) return ( good_count - to_divide_count * penalty_score - multi_pair_count * penalty_score - overlap_groups_count * penalty_score ) 7. 遺伝的アルゴリズムの実装 これで準備が整いましたので、遺伝的アルゴリズムを実装していきます。 まず、遺伝的アルゴリズムの計算に必要な要素となる関数を定義します。 def initialize_population (size, employee_list, lunch_session_times): # 初期の個体群をランダムに生成。「① 初期個体をランダムにN個生成」に相当。 return [ [ random.sample(employee_list, len (employee_list)) for i in range (lunch_session_times) ] for _ in range (size) ] def evaluate_solution ( solution, good_pairs, to_divide_members, multi_pair_threshold, overlap_threshold, ): # 個体のスコアを評価する groups = [] for solution_per_session in solution: groups += divide_teams(solution_per_session) return calculate_score( groups, good_pairs, to_divide_members, multi_pair_threshold, overlap_threshold, ) def select_parents (population, scores): # ベストスコアの2個体を選別 # 「② N個の個体からスコアの良い個体を2個選択」に相当 parents = sorted ( zip (population, scores), key= lambda x: x[ 1 ], reverse= True ) return [parents[i][ 0 ] for i in range ( 2 )] def crossover (parent1, parent2): # 実施月ごとに交差を実施 child1 = [] child2 = [] for session_time in range ( len (parent1)): # 一点で交叉 idx = random.randint( 0 , len (parent1[session_time]) - 1 ) child1.append( parent1[session_time][:idx] + [ x for x in parent2[session_time] if x not in parent1[session_time][:idx] ] ) child2.append( parent2[session_time][:idx] + [ x for x in parent1[session_time] if x not in parent2[session_time][:idx] ] ) return child1, child2 def mutate (child, mutation_rate): # 一定の確率で2点間の位置をスワップ for session_time in range ( len (child)): for i in range ( len (child[session_time])): if random.random() < mutation_rate: swap_idx = random.randint( 0 , len (child[session_time]) - 1 ) child[session_time][i], child[session_time][swap_idx] = ( child[session_time][swap_idx], child[session_time][i], ) return child では、いよいよこれらの関数を用いて遺伝的アルゴリズムを実行しましょう。 # 設定値 population_size = 100 # 世代ごとに生成する個体数。 generations = 1000 # 変異と交叉を繰り返す回数 mutation_rate = 0.01 # 変異が発生する確率 lunch_session_times = 3 # ランチセッションの開催回数 overlap_threshold = 3 # N人以上重複するグループを避ける際のN # 実行 population = initialize_population( population_size, employee_list, lunch_session_times ) best_solution = None best_score = -sys.maxsize for generation in range (generations): scores = [ evaluate_solution( solution, good_pairs, to_divide_members, lunch_session_times, overlap_threshold, ) for solution in population ] if max (scores) > best_score: best_score = max (scores) best_solution = population[scores.index(best_score)] parents = select_parents(population, scores) new_population = [] for i in range (population_size // 2 ): child1, child2 = crossover(parents[ 0 ], parents[ 1 ]) new_population.append(mutate(child1, mutation_rate)) new_population.append(mutate(child2, mutation_rate)) population = new_population この計算によって、制約条件をできる限り満たしながら、普段あまり接点がない人どうしの組み合わせをできる限り最大化した結果が得られました。 それでは、次のセクションで実行結果をご紹介します。 実行結果 ここでは、本記事用のダミーデータでの実行結果を記載します。 マネージャーはAさん~Gさんの7名と想定しています。 実際に分割されたメンバーリスト まずは、遺伝的アルゴリズムで得られたグループを見てみましょう。 マネージャーは 太字 にしています 第1回(1月) グループ メンバー1 メンバー2 メンバー3 メンバー4 メンバー5 グループ1 Rさん Gさん Wさん Uさん Xさん グループ2 Tさん Kさん Lさん Vさん Eさん グループ3 Bさん Oさん Zさん Sさん Yさん グループ4 cさん eさん Pさん Cさん グループ5 Mさん Fさん Nさん aさん グループ6 Jさん Iさん Qさん Dさん グループ7 bさん dさん Hさん Aさん 第2回(2月) グループ メンバー1 メンバー2 メンバー3 メンバー4 メンバー5 グループ1 Vさん Kさん Gさん Sさん Hさん グループ2 Aさん Oさん Xさん Jさん Pさん グループ3 aさん Tさん Yさん Cさん Qさん グループ4 eさん bさん Bさん Mさん グループ5 Lさん Rさん Iさん Fさん グループ6 dさん Wさん Uさん Dさん グループ7 Nさん Zさん cさん Eさん 第3回(3月) グループ メンバー1 メンバー2 メンバー3 メンバー4 メンバー5 グループ1 Nさん Sさん Pさん Gさん Jさん グループ2 Aさん Kさん Zさん Mさん Qさん グループ3 Yさん Dさん Lさん Vさん Rさん グループ4 Uさん Tさん Bさん Hさん グループ5 aさん dさん Cさん eさん グループ6 Xさん Eさん Iさん bさん グループ7 Oさん Fさん cさん Wさん マネージャーが毎回7チームに分散しており、同じようなチームもなく、うまくチーム分けがなされているように見えます。 検算したところ、実際にこのチーム分けは、制約条件を全て満たしていました。 更に全194件の普段あまり接点がない人どうしの組み合わせのうち、118件の組み合わせを実現できています! 最適化の時間推移 では、最適化によってスコアがどのように推移したかを見てみましょう。 横軸は学習ステップ数(世代数)、縦軸は学習スコア(各世代のbest_score)を表しています。 序盤に大きくスコアが改善し(制約条件を満たさないケースが淘汰されています)、200ステップ以降はほとんどスコアに変動がありません。 今回のケースでは、200世代程度でも十分に良い解が導けていたということになります。 ランダム探索との比較 では、今回の学習で遺伝的アルゴリズムを利用せず、ランダムに探索した場合は結果がどうなるかを検証して結果の考察を終えたいと思います。 ここではランダムにメンバーをシャッフルした個体を評価し、最もスコアの高い個体を選択します。 今回は各世代の個体が100で、世代が1,000だったため、100×1,000=100,000通りをランダムに探索してみました。 その結果、遺伝的アルゴリズムが実現できた普段あまり接点のない人どうしの組み合わせは 118件 だったのに対し、ランダムに探索した場合は 77件 となりました (制約条件は全て満たせていました)。 遺伝的アルゴリズムの方が 35% も実現できた組み合わせ数が多く、解の効率的な探索に有効であったことがわかります。 引き継ぎのためにStreamlitでUIを作成 今回は私が実際にPythonコードを動作させて組み合わせを決めましたが、今後もランチ会を実施する際に非エンジニアでもこのアルゴリズムを動かせるように、StreamlitでUIを実装しました。 コードの詳細は省略しますが、簡単にUIをご紹介したいと思います。 まず、普段接点がなさそうな人の組み合わせに◯をつけたExcelファイルをアップロードします。 次に、マネージャーを選択します。選択肢はアップロードしたExcelファイルに含まれる人名が表示されます。 最後にランチ会の開催回数を入力して、計算実行ボタンを押すと最適化計算が開始されます。 計算中は学習が進む様子をビジュアルで確認できるようにしました。 計算が終わると、アルゴリズムが導き出した最適なグループのリストが表形式で表示されます。 (以降のグループは省略) このように簡易なUIにすることで、非エンジニアの方でも気軽にグループ分けを実施できるようになりました。 まとめ かなりボリュームのある記事になりましたが、最後までお読みいただきありがとうございます。 もし同じような課題を抱えている方がいれば、本記事を参考にしていただけると嬉しいです。 また、Insight Edgeはランチ会のグループ分けでも技術的なチャレンジが自由にできる、データサイエンティストの技術を存分に発揮できる環境です。 Insight Edgeに興味を持たれた方は、ぜひ 公式サイト の採用ページからカジュアル面談をお申し込みください!
アバター
こんにちは!Insight Edgeコンサルタントの山田です。最近体重増加が著しく、16項目の計測が可能なAnkerの体重計を購入したのですが、毎朝データを取り、日々の変化をグラフ化することでダイエットのモチベーションが維持できています。改めてデータの可視化の重要性を実感しているところです。 さて、この記事では例にもれず生成AIをテーマに、総合商社における生成AI活用についてまとめたいと思います。Insight Edgeは住友商事グループの内製エンジニア組織ですが、グループ全体のCoE組織である 「SC-AI Hub」 の中核を担っており、生成AI関連だけでも現在数十件のプロジェクトを推進しています。住友商事グループの生成AI活用に向けた取り組みを一部紹介しているので、是非ご覧ください。 生成AIのビジネス活用 総合商社が生成AI活用するインパクト ビジネスドメインの多様性 蓄積された豊富な情報 住友商事グループにおける活用事例 社内情報検索 問い合わせチャットボット VoC(Voice of Custmor)分析 経営の意思決定サポート まとめ、今後の展望 生成AIのビジネス活用 生成AI技術のアップデートのスピードはすさまじく、毎日どこかで新たな発表がされているような状況です。同時にビジネスシーンにおいても紙面で生成AIの文字を見ない日はないほど、生成AIの導入・活用が当たり前となっています。 私が現在担当するプロジェクトも、6~7割が生成AI関連となっており、実感としても業界業種問わず活用への機運が急速に上昇している印象があります。 8/4付の日本経済新聞の記事では、調査対象とした約100社のうち7割の企業が具体的な労働時間削減の効果を見込んでおり、社員の生産性向上に寄与すると期待されています。同時に、機密情報漏洩や著作権侵害など懸念される事項もあり、各社導入とルール整備を急速に進めているフェーズです。 生成AIで企業の7割時短 100社調査 - 日本経済新聞 総合商社が生成AI活用するインパクト 業界業種を問わず大きなインパクトをもたらしている生成AIですが、実際に住商グループの生成AI活用をリードする立場としてプロジェクトを進める中で、総合商社は活用ポテンシャルが特に大きい業態の一つと感じています。その理由は大きく以下2点です。 ビジネスドメインの多様性 ご存知の通り総合商社は、資源化学品、エネルギー、輸送機、インフラ、消費財、小売り、不動産、金融、IT、物流、ヘルスケア等、多岐にわたるビジネスを展開していますが、生成AIの実装という観点で見ると、それぞれのビジネスで共通なユースケースと業界特有のユースケースがあります。情報検索や高度なタスクの自動化など、共通ユースケースの実装が比較的先行しますが、業界特有のユースケースも、着眼点次第で活用方法は多岐に渡り、ブレイクスルーをもたらす可能性があります。多様なビジネスドメインにおいて同時並行で活用アイデアを探ることができるのは大きな強みと感じます。 蓄積された豊富な情報 上記に派生するポイントでもありますが、総合商社は多数のステークホルダーやマーケットから日々膨大な情報を収集しており、社内に長年のナレッジとして蓄積されています。これら情報を活用し、また時には業界を横断したデータ活用により、新しいビジネスアイデアを生み出すことができます。また、過去の情報からビジネスの成功要因や失敗要因を把握し、新しいビジネスの成功確度を高めることも期待できます。(後述の意思決定支援ツールの事例にも通じます) 住友商事グループにおける活用事例 特にビジネスドメインの多様性による強みは大きいと感じており、社内情報検索や問い合わせ対応など代表的なユースケースはもちろん、業界特有のペインポイントを生成AIで解決するようなユニークな活用方法があるはずで、そのアイデアやニーズにいち早くアクセスできる点は非常に強みと感じます。 一方で、ビジネス面・技術面の両輪での試行錯誤がきわめて重要となるこの領域において、ビジネスアイデアを高速で形にしながらトライ&エラーができる環境も同時に重要であり、この点はInsight Edgeが内製エンジニア組織として価値を発揮しているポイントでもあります。 以降では、ビジネス現場とInsight Edgeがともに試行錯誤しながら取り組む具体事例をいくつかご紹介します。 生成AIのユースケース分類 社内情報検索 LLM自身が持つ情報だけでなく、企業内のクローズドなデータを組み合わせて、企業や部署専用の情報検索ツールとして活用する方法で、企業利用における最も代表的なユースケースの一つです。RAG(Retrieval Augmented Generation)などが有名な手法です。あらかじめ参照したい社内外の情報をデータベース(ベクトルストア)に用意しておき、ユーザーからの質問に対してベクトルストアの中で類似度の高い文書を検索し、その文書を質問と合わせてプロンプトとして入力することで、既存のLLMだけでは回答できない質問にも精度高く回答できるようにする使い方です。 企業の規模が大きくなるほど、社則や業務ルールも膨大になり、かつ主管部署も異なることも多々あり、求める情報にたどり着くまでに時間を要することも少なくありません。本来は時間をかけるべきでない作業を削減し、より価値のある業務に時間を使えるようにすることは、生成AIを積極的に活用するべき最大の理由でしょう。 Insight Edgeでは社内情報検索ソリューションのβ版をリリースし、住友商事をはじめ、複数のグループ企業に導入するべく目下準備を進めています。 社内情報検索ソリューションの画面イメージ。住友商事の一部メンバーを対象にトライアル導入中。 問い合わせチャットボット 生成AIを活用したFAQチャットボットも、代表的なユースケースです。①の情報検索の仕組みと同様に、業務マニュアルや過去のQ&A履歴、それに対する主管部署の回答などをベクトルストアに用意しておくことで、従来のルールベースのAIチャットボットよりも回答精度の高いFAQシステムができることが期待できます。 このユースケースも、確認すべき業務ルールが多いほど、また業務遂行に際し社内ルールだけでなく、法令や業法など一般的なルール順守が求められる場合にも、一次回答を迅速に得るための強力な武器になりえます。(法令や業法など参照する場合は正確性が求められるため、ハルシネーションの理解には注意が必要で、ユーザーのリテラシーが問われます) 特に人事や総務、法務、情シスなど、コーポレート機能を担うメンバーの問い合わせ対応工数を大きく削減できる可能性があります。 VoC(Voice of Custmor)分析 VoC分析は、顧客の意見やフィードバックを収集、分析することで、顧客満足度向上や製品・サービス改善を目指す手法です。toCビジネスも数多く手掛ける商社では、VoC分析の重要性は非常に高く、ここにも生成AIは活用できます。 日々寄せられる大量のVoCをカテゴリごとに分類・要約することはもちろん、そこから示される顧客感情の示唆、ポジネガ分析、さらには改善に向けたアクション提案などが可能となります。 従来のAI技術でもある程度のVoC分析は可能でしたが、例えば感情分析において業界や企業ごとに判断基準が異なり、VoCの内容に対して、一概にポジティブかネガティブかの判断が難しい場合がありました。一方生成AIでは、プロンプトに判断基準の例を示すことで、業界や企業ごとに重視する観点を反映した分析が可能となります。専門知識や経験が乏しくても、筋のいい分析をするためのサポートツールになりえます。 経営の意思決定サポート 総合商社における生成AI活用の本命の一つが、経営判断における意思決定支援だと思います。総合商社はトレーディングから事業投資/事業経営へとビジネスを拡大してきましたが、社内には投資判断を行うための調査資料や分析レポート、意思決定にあたってのマネジメントの所感・コメント等が残されています。 これらを活用し、新規投資案件など意思決定が必要な場面において、過去に類似の案件がなかったか、その際にはどのような観点やリスクが議論され、結果としてどうなったかなどの情報を生成AIにより抽出・要約することで、意思決定において重要となる情報提供が可能となります。 決断までをAIに委ねる未来は恐らく来ることはないですが、意思決定における強力なサポートアイテムになるのではと期待しています。 Insight Edgeでも住友商事のリスクマネジメント部と連携し、意思決定支援ツール開発のプロジェクトを進めています。 意思決定支援ツールを活用した質問例 これら事例は、下記メディアでも取り上げて頂いているので、よければこちらもご一読ください。 5大商社はChatGPTをどう活用?伊藤忠は「同僚化」、住商は鋼管取引と投資判断に【プロンプト実例紹介】 | コピーですぐに使える!ChatGPT100選 職種別・業種別・部署別 | ダイヤモンド・オンライン まとめ、今後の展望 総合商社は過去100年にわたって、トレーディングから事業投資、事業経営と、常に時流を読み柔軟にその姿を変えてきました。そして現在においては、先端テクノロジーをいかにビジネスに適用し付加価値を創造できるかが強く求められています。 生成AIの登場という、これまでにないエポックメイキングな技術革新の中においても、常に市場を先取りし新しいビジネスを開拓し続ける住友商事グループの内製エンジニア企業として、Insight Edgeもワンチームとして生成AIの社会実装に貢献していきたいと思っています。
アバター
こんにちは!Insight Edgeの塩見です。 2023年7月11日(火)~13日(木)の3日間、東京ビッグサイトにて「AI World 2023」が初開催されました。本展示会では、ChatGPTを活用したソリューションが数多く展示されていたため、その内容をご紹介したいと思います。 AI Worldとは? ChatGPTとは? 各社のChatGPTソリューション紹介 株式会社AVILEN 「研修、アイディアソン、ソリューション開発」 株式会社ギブリー 「法人GAI・行政GAI」 パーソルプロセス&テクノロジー株式会社 「TIMO Meeting」 Allganize Japan株式会社「Alli」 まとめ AI Worldとは? AI Worldは、ビジネス変革と業務効率化をテーマとした大型展示会です。この展示会では、DX(デジタルトランスフォーメーション)、業務効率化、チャットボット、機械学習、画像・音声認識、自然言語処理、対話AIを始めとする最新のAIソリューションが一堂に展示されます。商談を求める企業にとっては、課題解決のための貴重なヒントを手に入れることができ、またAI技術の最先端を一目で確認することができる場となっています。  AI World 2023 さらに、この展示会はリアルな場所での展示の他、オンラインでのセミナー視聴や製品資料のダウンロードも可能です。これにより、遠方からの参加者や、展示会場に来ることができない方でも情報収集が容易になっています。 場所としては、東京ビッグサイト(西1・2ホール)を使用して開催され、展示製品数は同時開催された他展示会と合わせると、日本最大級とされる約870製品が出展されました。また、デジタル庁や総務省、東京都などの公的機関からの後援を受けており、その規模と重要性を物語っています。実際、来場者数は計22,295名であり、業界関係者やビジネスパーソンからの高い関心が伺えます。 ChatGPTとは? ChatGPTは、OpenAIによって開発された大規模な言語モデルを活用したAIチャットサービスです。ユーザーとの対話形式で情報提供や問い合わせ応答が可能であり、その高度な自然言語処理能力により、様々なビジネスやサービスに応用されています。ChatGPTは2022年末に公開され、その後、急速に利用者数が増加しました。 2023年2月、本展示会と類似内容の展示会であるDX EXPOが開催され、その場でも多くのAIソリューションが展示されていましたが、ChatGPTの公開から間もない為、ChatGPTに関連したソリューションを展示していた企業は1社程度しかありませんでした。 一方、本展示会では、10を超えるChatGPTソリューションが展示されており、多くの企業がChatGPT公開後に関連サービスの開発を進めていたことがわかります。実際、これらのソリューションは展示会見学者の注目を多く集めており、企業だけでなくユーザの期待値も高いことが想定できます。 各社のChatGPTソリューション紹介 ここからは、AI Worldにて展示されていたChatGPTソリューションを一部ご紹介します。各ソリューションの詳細が記載されたWebページへのURLリンクも併せて載せていますので、こちらもご参照ください。 株式会社AVILEN 「研修、アイディアソン、ソリューション開発」 株式会社AVILENでは、ChatGPTをビジネス活用する上で、各社の課題やフェーズに応じたソリューションを一気通貫で支援するサービスを提供していました。 具体的には、以下の支援サービスがあります。 ChatGPTビジネス研修 ChatGPTアイディアソン ChatGPTソリューション開発(Chat Mee, Chat Mee Pro) ビジネス研修では、「そもそもChatGPTで何ができるのかわからない」というユーザ向けに、ChatGPTの基礎知識をE-ラーニングで学習してもらいながら、ChatGPTを実際に体験するワークを実施します。 アイディアソンでは、「ChatGPTを自社でどのように活用できるかアイディアが欠けている」と感じるユーザ向けに、企画立案から実行まで、コンペ形式でAVILENがサポートします。 ソリューション開発では、「ChatGPT導入・開発に必要なノウハウやリソースが不足している」と感じるユーザ向けに、ChatGPTに精通したデータサイエンティストが課題の明確化から開発、保守まで一気通貫で支援します。 現在、ChatGPTの利用は日本国内でも増加していますが、まだChatGPTを利用したことがないユーザが大多数であることを考えると、ChatGPTの基礎教育・業務課題やユースケースの整理・ソリューション開発といった一連の流れをサポートするこのサービスは、非常に有益だと感じました。 株式会社AVILEN ChatGPT活用支援サービスの詳細はこちら 株式会社ギブリー 「法人GAI・行政GAI」 株式会社ギブリーでは、法人・行政でChatGPTを安全に使用できるGAIサービスを展開しています。ChatGPTを法人・行政内で使用する場合、機密情報が漏洩する可能性がありますが、これらのGAIサービスでは、情報が外部に漏洩するリスクをなくしつつ、ChatGPTを法人・行政内で使用することが可能です。 その他、NGワードの登録、ユーザの利用状況をモニタリングできるダッシュボード機能、実務における様々な利用シーンを想定したプロンプトレシピ機能等、ChatGPTを実務で活用する上での利便性の高い機能を多く揃えています。 セキュアな環境でChatGPTを活用する為のサービスは、直近続々とリリースされている印象がありますが、プロンプトレシピやダッシュボード機能など、ユーザに選んでもらう上では、プラスアルファの機能が重要になってくるのかなと思います。 株式会社ギブリー 法人GAIの詳細はこちら 株式会社ギブリー 行政GAIの詳細はこちら パーソルプロセス&テクノロジー株式会社 「TIMO Meeting」 TIMO Meetingは、会議プロセスのデジタル化を通じて、生産性向上を実現する国内初のミーティングマネジメントツールです。本ツールにもChatGPTが活用されており、「AIアシスタント」と「AIアドバイザリー」の2つの機能があります。 AIアシスタントでは、会議予定に添付された資料を読み込み、資料を元にして、会議の目的・背景・論点などを端的にまとめてくれます。これにより、会議参加者は事前にこの会議がどのようなものかを理解することができ、会議の効率性や効果の改善に繋がります。 AIアドバイザリーでは、会議予定の添付資料に関する質問をチャット形式で投げかけることで、資料内容を要約してもらう等、AIからの様々なアドバイスを受けることができます。 TIMO Meetingでは、自社独自ソリューションにChatGPTを組み込み、他社と差別化を計りつつソリューション価値を向上することが出来ている良い事例かと思います。 パーソルプロセス&テクノロジー株式会社 TIMO Meetingの詳細はこちら Allganize Japan株式会社「Alli」 Allganize Japan株式会社は、AIチャットボットのAlliを展示していました。就業規則などの社内資料を元に、ユーザの質問に対して、ChatGPTの自然な応答を元に回答をしてくれるようです。 Allganize Japan株式会社は、2023年2月に開催されたDX EXPOでも自社ソリューションの展示を行っていましたが、DX EXPOの中で唯一、ChatGPTを活用したソリューションの展示を実施していました。この時の展示スペースはとても小さかったのですが、今回は非常に大きなスペースでAlliの紹介をしていました。 スタッフの方にお話を伺ったところ、前回の展示会以降、ChatGPTに関する問い合わせが大きく増え、今回ブースをさらに拡大することになったようです。ChatGPTのサービスリリースは昨年末でしたので、わずか1~2ヶ月で展示会にソリューションを出展したことになります。この迅速な対応は非常に印象的であり、今回のAI Worldでも、多くのユーザから注目を集めていました。 Allganize Japan株式会社 Alliの詳細はこちら まとめ 近年、ChatGPTの活用範囲は日本国内でも拡大しており、多くの企業が各社独自のビジネスモデルにChatGPTを取り入れて、自社サービスの成長を促進しようとしています。 今回の展示会では、セキュアな環境でChatGPTを使用できるソリューションが数多く展示されていました。実際、このようなソリューションへのニーズは増加しているように感じます。 一方で、2023年8月にはOpenAIから法人向けのChatGPT Enterpriseが発表され、更なる付加価値を持つChatGPTソリューションの提供が開始されました。このような状況下、ChatGPTの単なる機能提供を行うソリューションでは、今後の差別化は難しいと感じられます。 パーソルプロセス&テクノロジー株式会社のTimo Meegingのように、自社独自ツールの価値を向上させるためにChatGPTを活用する、または株式会社AVILENのように、ChatGPTのユースケース整理やコンサルティングサービスを提供する、といった取り組みが重要であると感じました。これは、今回の展示会を通じて得た私の個人的な感想です。 今後もChatGPTの進化と、それを取り入れる企業の斬新なアイディアに注目していきたいと思います。
アバター
はじめに  データサイエンティストの五十嵐です。今回は「帰納バイアスと理論研究」というタイトルでお送りします。  機械学習のモデルは、与えられたデータからパターンを学習し、未知のデータに対する予測を行います。この機械学習モデルにおいて、帰納バイアスが存在する場合があり、多くのモデルではそれらの帰納バイアスを上手く利用することにより様々な成果を上げてきています。しかし、近年のLLM (Large Language Model)では、帰納バイアスの弱い手法により大きな成果を上げており、大量のデータセットを利用可能な場合、帰納バイアスが弱くても高い性能を発揮することができることが明らかになってきました。しかし、これらは実験的に得られた知見、すなわち経験則である場合が多く、その理論研究は十分には進展していないのが現状です。そこで、本記事では帰納バイアスについて簡単に紹介した後、今年の6月にarxivに掲載された帰納バイアスの理論研究について踏み込んだ論文、 “Scaling MLPs: A Tale of Inductive Bias“ について紹介しようと思います。  本記事により、帰納バイアスに関する今後の理論研究についての動向を探る一助になれれば嬉しいです。 帰納バイアス(Inductive Bias)とは  帰納バイアスとは、学習モデルや学習アルゴリズムが学習する際の前提や仮定、構造上生じるバイアスのことを指します。これは、モデルがデータから一般的なルールを導き出す際のバイアスや傾向を形成します。  例えば、決定木はデータ階層的に分割するというバイアスをもち、ロジスティック回帰では特徴空間において線形の決定境界を保つため、データが線形に分離可能であるという前提をおいています。また、入力特徴が互いに独立であるという仮定も持っています。CNN(Convolutional Neural Network)は局所結合により構成されており、局所特徴を層ごとに集約するという帰納バイアスがあります。  このように、様々な手法・モデルは多くの帰納バイアスを持ちます。(尚、上記で紹介した学習モデルについて、紹介した以外にも帰納バイアスは存在します。) 帰納バイアスの影響  帰納バイアスは、モデルの一般化能力に大きな影響を与えます。  帰納バイアスにより、得られるメリットには下記のようなものがあります。 計算効率の向上.  帰納バイアスにより、学習すべき仮説空間が制限されるために計算効率が向上します。無限の仮説空間から最適なモデルを見つけ出すのは難しいですが、制約されることにより難易度が低下します。 一般化能力の向上.  適切な帰納バイアスを持つことで、未知のデータに対するモデルの予測性能、すなわち、一般化能力が向上する可能性があります。帰納バイアスが実際のデータ生成プロセスに近い場合、新しいデータに対する予測精度が向上します。 知識の事前組み込み.  特定の分野やタスクに関する専門的な知識を帰納バイアスとしてモデルに組み込むことで、学習の効率や精度を向上させることができます。 解釈可能性の向上.  一部の帰納バイアスが、モデルの解釈性を向上させる効果があります。例えば、線形モデルや決定木などのシンプルなモデルは、その構造上の帰納バイアスによって、結果の解釈が容易になります。 学習に必要なデータ数の削減.  これについて詳細は後述しますが、適切な帰納バイアスを用いることで学習に必要なデータ数が帰納バイアスが弱い場合よりも少なくて済むことが知られています  このように、学習モデルや学習アルゴリズムは帰納バイアスを上手く利用しているのです。 帰納バイアスについて  近年、LLM (Large Langage Model)が話題ですが、これらのLLMはTransformerが用いられています。このTransformerは先述したような仮定を置いていないので、帰納バイアスが弱いです。帰納バイアスが弱いということは、帰納バイアスの恩恵を受けられないということなので、データが大量に存在しない場合は帰納バイアスが強いモデルに比べて高い精度が出しにくい可能性が考えられます。実際、ViT (Vision Transformer)で有名な論文 "An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale (2021)" では、データ量が大規模でない場合は帰納バイアスの強い従来のCNNベースのモデルの方が強く、データ量が大規模な場合は帰納バイアスが弱いViTの方が強い、ということが示されています。  また、Transformerの性能はモデルサイズ(パラメータ数)、データサイズ、計算能力の3変数に依存する冪乗則に従うこと( "Scaling Laws for Neural Language Models (2020)" )も知られており、データ量が大きくなる程、性能が向上することが示唆されています。  これらのことから、学習データが大規模な場合、帰納バイアスが弱い学習モデルを用いた方が良いことが示唆されます。しかし、このことを理論的に解明しようとしている研究はまだあまり多くありません。 本記事で紹介する論文  前置きが長くなりました。本記事で紹介する論文は “Scaling MLPs: A Tale of Inductive Bias“ です。 この論文の概要を下記に記します。 概要  2023年6月23日にarXivに掲載されました。著者はスイス連邦工科大学所属です。  この論文は、これまで経験的に示されてきた、帰納バイアスが小さい場合データセットや計算の能力、モデルサイズが大きい方が性能がよくなるという事象を理論的に解明する足掛かりを作るため、深層学習の最も基本的な構成要素であるMLP (Multi Layer Perceptron)を用いて実験を行っています。  MLPを用いることで数学的に単純にできるため、MLPは深層学習の理論分野では主に使われています。これは、より複雑な構造で観察される現象をシンプルな構造で説明するという発想で、理論分野ではよく用いられています。MLPは帰納バイアスが非常に弱いという点からも理想的です。 実験設定  本論文では、帰納バイアスを理解することが容易であることからvisionタスクで実施しています。 利用したデータセットは下記です。 CIFAR10 CIFAR100 STL10 TinyImageNet ImageNet1k ImageNet21k など事前学習でおなじみのデータセットです。  また、activation function、skip connection、regularization、data augmentation、inverted bottleneckなど、通常用いられる工夫は都度利用しています。 実験結果  上表からデータ数やモデルサイズが大きい方が精度が高くなっていることがわかります。モデルについては、B-L / Wi-mという形式で表現されています。。Bはボトルネック(今回はinverted bottleneck)、Lはネットワークの深さ(ブロック数)、Wi-mはネットワークの幅(各ブロックのノード数)です。  上表はモデルとパラメータ数です。これらのモデルを用いて、CIFAR10とImageNet1kに関して、計算能力毎の性能を評価したグラフが下図です。  上図は、先述したモデルごとのLinear Evaluation Errorを示したグラフです。左図はCIFAR10、右図はImageNet1kについてのTest errorを表しており、横軸は計算能力です。この結果から、MLPに関しても性能はそのスケールや計算能力により劇的に改善することが分かります。 結論  MLPの性能はそのスケールとともに劇的に改善することがわかりました。これは、帰納バイアスがなくてもスケールによりカバーできることを示しています。つまり、大量のデータと十分な計算能力があれば帰納バイアスが重要ではないことを示唆されています。  また、MLPは実際に使われているようなモデルによって示されている経験的な進歩を反映しているとも考えられます。つまり、MLPが深層学習における理論の理解においては重要であることを示しています。 まとめ  本記事では帰納バイアスについての説明と理論研究論文の紹介を行いましたので、全体をまとめます。 データが大規模な場合、帰納バイアスが弱い学習モデルの方が良いことが実験的に示されてきてはいたが、理論研究はあまり進んでいない “Scaling MLPs: A Tale of Inductive Bias“ では、深層学習の基本的な構成要素であるMLPを用いて、visonタスクで同様の傾向が示されるのか研究を行った MLPの性能はそのスケールとともに劇的に改善することが示され、大量のデータと十分な計算能力があれば帰納バイアスは重要でないことを示唆された MLPは実際に使われているようなモデルによって示されている経験的な進歩を反映しているとも考えられる。つまり、MLPが深層学習における理論の理解には重要であることが示唆されている 最後に  最後まで読んでくださりありがとうございました。  色々前置きを書きましたが、人工知能研究の最終達成目標の一つであろう汎用人工知能(AGI)の達成には、間違いなく帰納バイアスが非常に弱いモデルや手法が必要不可欠かと思います。そのためには、理論研究が必須なので、この分野の研究動向は今後も探っていこうと思います。Transformerがより発展していくのか、全く別の手法が開発されるの個人的には非常に楽しみな分野です。
アバター
こんにちは。ビジネスイノベーションスペシャリストの森です。 最近コードを書くときは、Github CopilotとGPT-4を使っていますが、実装スピードが10倍(体感)になりました。 微妙な部分を書き換えながら使うので、初心者がコーディングできるようになるのは難しいと思いますが、 コーディングの単純作業部分を全部任せられるのは非常に便利です。 こんなこともあり、Tech業界は最近生成AI一色です。Insight Edgeでも、数多くのChatGPT(LLM)活用プロジェクトに取り組んでいます。 この記事では、本格的なLLMのビジネス現場活用に向け、日々取り組んでいるテーマと、その技術的な課題を紹介します。 また、本記事のタイトル含め、LLMと記載すべきところをChatGPTという単語を使っている箇所があります。 OpenAI社のChatGPTというサービス名称ではなく、概念(一般名詞)としてChatGPTという言葉の使い方をしていることを予め補足します。 目次 はじめに LLMを業務に活用する場合の課題 外部データの取り込み 出力形式の指定 (Function Calling) パイプラインの管理 終わりに はじめに 2023年3月のGPT-4リリース以降、ChatGPTをはじめとした大規模言語モデル(以降LLM)が注目されています。 Insight Edgeとしても、住友商事グループの生成AI活用に向けたグループ横断のワーキンググループである SC-AI HUB に参画し、生成AIのビジネス活用に取り組んでいます。 企業や組織におけるLLMの活用では、いわゆる「セキュアなChatGPT」の取り組みが有名です。多くの企業や自治体が、Microsoft社のAzure OpenAI Serviceで提供されているエンタープライズ用途のChatGPTを用いたセキュアなChatGPTの導入を進めています。 一方、セキュアなChatGPT以外の大規模な本格導入例は、ほとんど出てきていません。 一時期話題となったAutoGPTなどエージェント機能を組み合わせるアイデアや、ChatGPT Pluginで色々なサービスを利用する機能もリリースされていますが、 現状、アーリーアダプターがX(旧:Twitter)で使い方を紹介するくらいで、大規模に実用されるまでは至っていません。 企業活動において最も期待されているユースケースとして、企業内のデータを組み合わせてLLMを使う用途があります。 RAG(Retrieval Augmented Generation) や REALM(Retrieval Augmented Language Model) などの論文で提案された手法を使って実現することが有名ですが、本記事では説明を割愛します。 Microsoft Azureでも、このユースケースを実現するために Add Your Data や、 Cognitive Search のベクトルサーチ対応など、新しい機能を積極的にリリースしています。 しかしながら、企業内の情報検索のユースケースとして、ビジネス現場で活用されている例は、ほとんど出てきていません。 Insight EdgeもこのユースケースのPoCに数多く取り組んでいますが、ビジネス現場での実運用に向けては様々な課題に直面しています。 例えば、元データのPDFがスキャン画像だったり、テキスト化が難しいフローチャートや表に重要な情報が含まれていたりと、アルゴリズム以前に元データの整備が必要なケースがあります。 また、Stuffと呼ばれる最もシンプルな情報検索のパイプラインでは対応できない質問が業務上想定されるユースケースだったりもします。 後述しますが、与えた文書に対する要約と質問の両方を自然に回答することですら、割と難しかったりします。 現在リリースされているほとんどのサービスは、最もシンプルな情報検索のユースケースしか実装されていない状況です。 少し凝ったことをやろうとすると、Langchainやsemantic kernelを使って、スクラッチで実装する必要があります。 LLMを業務に活用する場合の課題 外部データの取り込み ChatGPT PluginsのPopular Pluginsを見てみると、上位3件はPDFの取り込みプラグインです。 エンタープライズ用途同様に、ChatGPTに独自の情報を加えるユースケースは、一般的にも最も注目されているようです。 実際にPDFを取り込むプラグインを使って、課題を説明します。 Insight EdgeでPoCを実施する中で困っていることの1つが、ユーザーは文書に対する質問(情報検索)と要約を意図せずに利用することです。 OpenAIなど、LLMをクラウド型で提供するサービスでは、一度のリクエストで取り込めるトークン数(文字数)の制限があります。そのため、情報検索と要約は同じ処理では実現できません。 情報検索は、文書中の該当部分だけを抽出してChatGPTにプロンプトとして入力します。 要約は、全文を参照する必要がありますが、全文を一定文字数ごとに区切って、順番に入力して処理をしていきます。要約を実現する処理パイプラインとしては、Map Reduce型と、Refine型に大別されます(後述)。 つまり、ユーザーからのリクエストが情報検索か要約かによって、システム側で処理を切り替える必要がでてきます。 ChatGPTの人気プラグインが、この問題にどうやって対処しているのか確認してみましょう。 一番人気のプラグインである「AI PDF」を使って、全体で20ページほどの論文の要約を指示してみます。 ChatGPT Pluginでは、以下のように、APIにどのようなリクエストが飛んだかを確認できます。 実際のリクエストを確認してみると、要約の指示をしたのにも関わらず、APIリクエストには文書の冒頭2ページ分しか入力されていませんでした。 幸い論文だと、冒頭にAbstractがあるため何となく良さそうな結果が返ってきますが、他のデータだとうまくいかなそうです。 実行結果の抜粋が以下になります。 やはり、明らかに冒頭2ページしか参照していません。つまり、このプラグインでは要約の処理は実装されておらず、要約の指示であっても質問回答用の処理しか実行されないことがわかりました。 人気のプラグインであっても、この程度のようです。まだまだこのユースケースの実用にはハードルがあることがわかります。 特に、冒頭2ページしか読み込んでいないのに、全文を処理しましたと出力する仕様となっているのは、ちょっといただけません。 補足ですが、Azureでは、Azure OpenAI Studio Add Your Dataというサービスでこのユースケースをサポートしています。 しかし、現状Azure OpenAI StudioのUI経由でしか利用できないため、システムに組み込みたい場合や、企業内ユーザーへの公開用途には使えません。 また、 Bing Chat Enterprise では、 ユーザーがPDFデータをアップロードする機能が搭載されています。 上述したOpenAIのPlugin同様、まだ実用に課題はあるものの、ビジネス用途で利用できるサービスの一つです。 このBing Chat Enterpriseは、セキュアなChatGPT用途にも使用することができます。 冒頭記載した通り、多くの企業でセキュアなChatGPTの導入が進んでいます。 元々、ベンダーへの委託を含め自社で開発する選択肢しかありませんでしたが、今ではBing Chat Enterpriseのような外部サービスをそのまま利用する選択肢もあります。 住友商事では、セキュアなChatGPTをはじめ、シンプルなユースケースには外部のサービスを利用し、 業務に特化した複雑なユースケースをInsight Edgeを中心に開発する取組み方をしています。 出力形式の指定 (Function Calling) ChatGPTを含むLLMからの回答を使って、別の処理を実施したい場合、プロンプトで回答形式を指定することが一般的です。 しかし、jsonなど決まったフォーマットで出力させようとしても、思ったように出力できないことが多いです。 体感ですが、GPT3.5を使った場合、上手く出力できる確率は良くて5割程度、GPT4だと8~9割です。 パラメータ数の少ないLLMでは、Finetuneしない場合、決まったフォーマットでの出力は絶望的です。 また、決まったフォーマットでの回答ニーズは、通常のチャット用途においても高まっています。 Chain-of-Thought Prompting や、 メタ認知プロンプティング のように、LLMに段階的に推論をさせることで回答の精度を上げる手法が考案されています。 これらの手法は、以下の画像のように、LLMに対して思考の過程をプロンプトで定義します。 このように、段階的な思考の指示することで、回答の精度を向上・担保します。 この手法を使う場合、段階的な推論の全てのログをユーザーに表示してしまうと、回答量が多くなりUXを損ねる場合があります。 多くの場合において、ユーザーに提示するのは段階的な推論の最終段階の結果のみで十分です。 つまり、システムへの組み込み用途だけでなく、LLMからの回答精度を上げる場合にも、出力形式の指定が必要となります。 ChatGPTでは、出力を決まった形式に指定するための機能として、Function Callingというサービスを提供しています。 これだけでも他のLLMではなくChatGPTを使う理由となるくらい、今後重要となる可能性があるサービスだと思います。 パイプラインの管理 セキュアなChatGPT用途では、単にAPIにユーザーからの質問を投げて、APIからの回答をそのままユーザーに提示するだけの処理で実現できます。 しかしながら、社内情報を使った回答の用途を含め、業務的に実用レベルのユースケースを実現しようとすると、 単にAPIに質問を投げて回答を取得するだけの処理では実現できません。 以下に一般的なパイプラインを紹介します。 外部情報を組み合わせたユースケースで最もシンプルなパイプラインは、 Stuff Documents パイプラインです。 仕組みは簡単で、プロンプトと参考情報をセットにしてAPIにリクエストを投げるパイプラインです。 上述の通り、外部情報を取り込める既存サービスのほとんどは、このStuffが実装されています。 一方、これまでのプロジェクトの経験上、Stuffを実装しただけではユーザーに提供できるクォリティの回答が得られません。 セキュアなChatGPT以降の事例が出てこない理由の1つはここにあると思っていて、 いろいろな企業がこのStuffを試し始めているものの、なかなか上手くいってないのではないかと思います。 文書の要約では、別のパイプラインが必要です。 Stuffは、文書の必要な部分を渡す処理ですが、要約では、全文を取り込む必要があります。 しかし、文字数の多い文書の場合は、一度のAPIリクエストで全文を取り込むことができないため、パイプラインで工夫する必要があります。 Map Reduceは、一定量ごとに区切った文書(chunk)をそれぞれ1回要約して、最後に全ての要約結果を集約して2回目の要約を実施する処理です。 1回目の要約部分は並列処理できるので、速度重視の場合はこのパイプラインを選びます。 Azure OpenAI Serviceなど、クラウド提供型のLLMの場合、Rate Limitが厳しいため、 Rate Limitの問題をケアして実行する必要があります。 要約では、Refineというパイプラインも選択肢として考えられます。 Refineは、一定量ごとに区切った文書(chunk)を順番に読み込んでいき、都度要約を繰り返す方式です。 処理が直列なので、Map Reduceと比較すると時間がかかります。 上述しましたが、このように、情報検索と要約は同じパイプラインで実現できません。 利用者の立場からすると、意図せずに情報検索と要約の両方を質問することに加え、要約の後に質問を続けたいという利用ニーズもあります。 この他にも、回答精度を上げようとしたり、利用者の業務ニーズに応じて複雑なパイプラインが必要となります(prompt chaining)。 プロジェクトでは、パイプラインが複雑になるにつれて、開発したエンジニアしか処理内容を把握していない状況になりがちです。 継続的な運用を考えると、パイプラインの設計や管理を実施する必要が出てきます。 Microsoft Azureでは、prompt flowというパイプライン管理ツールを提供しています。 一見ローコードツールのような外見ですが、肝心の処理自体はpythonで記述する必要があり、 Airflowやkedroのように、パイプライン管理の用途を想定して作られていると思います。 まだプレビュー版で、prompt flowも実用的なレベルではありませんが、LLMops領域のサービスは重要となってきそうです。 終わりに 本記事では、本格的なLLMのビジネス現場活用に向け、日々取り組んでいるテーマと、その技術的な課題を紹介しました。 現状では、スクラッチでトライアンドエラーしながら開発できるエンジニアがいないと、LLMを活用してやりたいことを実現するのは難しいです。 LLMを本格的にユーザー企業が活用して成果を出すには、まだまだ技術的なハードルが高いように感じています。 例えばディープラーニングも、色々なツールが徐々に整備され、今では誰でもちょっとした学習ならできるようになりましたが、 LLMの活用もディープラーニングの黎明期と同じような雰囲気を感じます。 現在、アカデミア含め、ものすごいスピードで目下の技術課題が解決されています。 最新技術のキャッチアップを欠かさずに、着実にできることを増やしていきたいと思っています。
アバター
MathJax = {tex: {inlineMath: [['$', '$']]}}; Insight Edgeのデータサイエンティストのki_ieです。 今日の記事ではJupyter notebookをはてなブログで公開できるマークダウンに変換する方法を紹介します。 はじめに 数式とコード、さらにコードの実行結果を含む技術的な記事を書くには、Jupyter notebookが便利です。 しかしJupyter notebookは、そのままでははてなブログに公開できる形ではありません。 下書きだけJupyter notebookで行って最後は手作業でmarkdownに移行して仕上げる という方法もありますが、ソースが2つできてしまい記事の修正時が大変です。 notebookファイルだけをソースとして、ブログ記事は変換スクリプト一発生成できる方が望ましいですよね! 本記事では、この変換を実現するスクリプトを紹介します。 変換スクリプト 想定環境 実験は以下の環境で行いました。 Pythonのバージョンあまり依存しないと想定しています。 jupyterのバージョンによっては、正しく動作しない可能性があります。 Python: 3.11 jupyter: nbformat: 5.8.0 notebook: 6.5.4 スクリプト スクリプトは以下の通りです。 # FILENAME: nb_hatena_converter.py """ Usage: python nb_hatena_converter.py YOUR_NOTEBOOK.ipynb OUTPUT.md """ import nbformat, nbconvert import sys import re bs = " \\ " nl = " \n " NO_CONV_TAG = "<!-- NO_NB_HATENA_CONVERSION -->" special_chars = r"\*_`#+-.!{}[]()^" # backslash は文字列末尾には置かない ("がエスケープされるため) math_range_re = re.compile( r"(\${1,2}[^\$]+\${1,2})" ) special_chars_re = re.compile( "" .join([ '[' ] + [bs + ch for ch in special_chars] + [ ']' ]) ) mathjax_html_tag = r''' <script> MathJax = {tex: {inlineMath: [['$', '$']]}}; </script> <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script> ''' # 参考URL: https://o-treetree.hatenablog.com/entry/mathjaxexample def convert_str (s: str , cell, cell_no) -> str : # 数式部分またはそれ以外の部分の文字列 s を入力とし、必要な変換を施します。 full_match = math_range_re.fullmatch(s) res = s # 特に変換がなかった場合、もとの入力を返します。 # セルが NO_CONV_TAG で始まる場合、そのセルは変換しません。 if cell.source.find(NO_CONV_TAG) == 0 : pass # s が数式部分でない場合、変換しません。 elif not full_match: pass # s が数式部分の場合、特殊文字をエスケープします。 elif full_match: res = special_chars_re.sub(repl= lambda match_obj: bs + match_obj.group( 0 ), string=s) if res != s: print (f '{s} --> {res} @ {cell_no=} beginning with {cell.source[:15].replace(nl, bs + "n")}' ) else : raise NotImplementedError () assert isinstance (res, str ) return res def main (path_to_input, path_to_output): # 1. ノートブックを読み込みます。 notebook = nbformat.reads( open (path_to_input).read(), as_version= 4 ) md_exporter = nbconvert.MarkdownExporter() # 2. ノートブックのセルを, convert_str を使って書き換えます。 # (メモリ上での操作なので、ファイルに変更は加わりません) print ( 'Substitutions: ' ) for cell_no, cell in enumerate (notebook.cells): # markdown セルのみ変換処理の対象です。 if cell.cell_type == 'markdown' : # 2.1. cell の内容を、数式部分とそうでない部分に分割します。 # 例: source = "abc $d$ ef $$g$$" # --> # substrs = ["abc ", "$d$", " ef ", "$$g$$"] substrs = math_range_re.split(cell.source) # 2.2. 各部分に対して、 convert_str で必要なエスケープ変換を施します。 new_source = '' .join([convert_str(s, cell, cell_no) for s in substrs]) cell.source = new_source else : pass # 3. nbconvert.MarkdownExporter を使って、markdown に変換します。 # この変換処理は MarkdownExporter のデフォルトの処理を利用します。 converted_md, md_info = md_exporter.from_notebook_node(notebook) # 4. MathJax を利用できるように、ファイルの最初に HTML タグを追加します result_md = ' \n ' .join([mathjax_html_tag, converted_md]) # 5. 出力します with open (path_to_output, 'w' ) as f: f.write(result_md) if __name__ == '__main__' : main(sys.argv[ 1 ], sys.argv[ 2 ]) 使い方 1. jupyter notebookの準備 notebookに特別な工夫は不要です。数式を含むnotebookを用意しましょう。数式は、インラインでも、別行立て数式でも大丈夫です。 ここでは、以下の数式がどのように変換されるか確認しましょう $n = p \cdot q$ $$f(x)=\frac{{\sum_{i \in I} |x_i|}^2}{\sum_{i \in I} x_i^2}$$ 2. 変換 以下の方法でプログラムを起動し、変換結果のmarkdownファイルを得ます。 python nb_hatena_converter.py YOUR_NOTEBOOK.ipynb OUTPUT.md 3. 変換結果の確認 先程の数式は以下のように変換されます: $n = p \cdot q$ $$f(x)=\frac{{\sum_{i \in I} |x_i|}^2}{\sum_{i \in I} x_i^2}$$ (この記事自体も nb_hatena_converter.py で生成されたものです。上記の数式がはてなブログで正しく表示されているなら、それはこのスクリプトが正しく動作した結果です!) 4. 仕様 仕様概要は次の通りです。詳細は、プログラムとコメントを確認してください。 変換対象 markdownセルだけが変換対象です。codeやrawセルは変換されません。 markdownセルで数式部分と判定された部分に対して、変換処理が施されます。 セル単位のスキップ <!-- NO_NB_HATENA_CONVERSION --> で始まるmarkdownセルは変換を受けません。 このタグが含まれていても、セルの最初でなければ変換の対象となります。 数式部分の判別 $ または $$ で囲まれた部分を数式部分だと認識しています(詳細: math_range_re )。大雑把な判別なので、必要に応じて適宜改造してください。 変換処理の概要 はてな上での表示とjupyter notebook上での表示のずれは特殊記号の処理の優先順位が異なるため発生します。 このスクリプトは数式部分内に存在するmarkdown上の特殊記号をエスケープすることで、特殊記号が数式部分の開始/終了記号( $ , $$ )よりも優先されて処理されることを防いでいます。 おわりに このスクリプトで数式のあるブログ執筆のハードルが少しでも下がったら幸いです👍
アバター
こんにちは!小林と申します。この間、九州縦断旅をしたのですがどこに行っても温泉があって毎日のように温泉に入れて幸せでした。 つい先日、社内のAWS・GCPのインフラコストの削減施策を担当いたしました。この経験を通じて、コストがどこで発生し、どのようにそれを削減できるかについて深く理解する機会を得ました。 そこで、これらの知見を共有し皆さんが同様の課題を抱えてしまった際の参考になることを目指して、今回ブログで紹介させていただきます。 目次 インフラコスト削減施策の目的 調査 AWS のコスト GCP のコスト 実施項目 インスタンス自動起動停止ツール インスタンスごとの利用料金を監視・通知 AWS の場合 GCP の場合 EBS 棚卸し まとめ 結果 振り返り reference インフラコスト削減施策の目的 当社では、開発チームがAWSやGCPについて自由に検証できるよう、検証用アカウントを提供しています。しかし、このような自由度の高い環境では、不要なリソースが放置され、それが過剰なコストとなってしまうという問題がありました。 特に、高価なインスタンスが利用されていないのにも関わらず、起動し続けられていることがしばしばありました。 これらの問題に対応するため、以下の2つの施策を当初の目標として設定し、コスト削減に取り組みました 利用金額が一定の閾値を超えた場合に、その情報を通知する仕組みを導入し、過剰なリソースの使用を抑制する。 週末や使用が予想されない時間帯に、リソースを自動的に停止する機能を追加し、無駄なコストを削減する。 以上の施策により、リソースの最適化とコスト削減を達成することを目指しました。 調査 実際の取り組みへの着手前に、現状のコストが何に発生しているのかを詳細に調査し、インスタンス以外にもコスト削減の余地がないか探ります。AWSとGCPの両方で調査を実施しました。 AWS のコスト CostExplorerを利用して施策前のコスト分布を確認しました。たとえば、2023年3月時点の当社のコスト内訳を見ると、EC2インスタンス関連のコスト(EC2インスタンス、EC2その他)が月額コストの50%を占めていることが分かります。したがって、まずはEC2インスタンスに対して今回の施策を適用するのが有効であると推察できます。さらに、「EC2その他」という項目も非常に高額であることが明らかになりました。この項目には、EIP(AWS Eastic IPアドレス)やEBS(Amazon EBS)が含まれます。 EIPやEBSはインスタンスが停止している場合でも課金が発生し続ける特性を持っています。それゆえ、使用されていないEIPやEBSが存在する可能性も考慮に入れるべきです。この結果を踏まえ、AWSについては、インスタンスだけでなくEIP・EBSについても棚卸し等の施策が必要となりそうです。 図1 GCP のコスト 続いて、GCPのコスト状況についても確認します。 GCPについても全体のコストのうち半分ほどがCompute Engine(図2のグラフ青色部分)によって占められています。 AWSと同様にインスタンスに対する削減施策を実施する必要がありそうです。 図2 実施項目 調査結果から、当初の目的であったインスタンスのコスト削減施策が有効であると考えられました。さらに、AWSではEBSの棚卸しも行うことを決定しました。したがって、今回の取り組みは以下の3点となります。 インスタンス自動起動停止の仕組み作り 土日にインスタンスを自動で起動・停止できるようにし、インスタンスの管理を容易にする。 インスタンスごとの利用料金を監視・通知 インスタンスごとの利用料金を算出する仕組みを整え、規定値を超えた場合に通知するシステムを導入する。 EBS(ボリューム)の棚卸しを実施 あまり使用されていないインスタンスにアタッチされているEBSボリュームを確認し、必要ないものは削除する。 次に、それぞれの取り組みについて詳細を説明します。 インスタンス自動起動停止ツール まず、インスタンスを自動的に起動・停止する手段について考えてみましょう。 AWSのインスタンス自動起動停止には一般的に、Amazon EventBridge + Lambda、EventBridge Scheduler、またはInstance Schedulerのようなアーキテクチャが用いられます。 GCPではデフォルトでインスタンススケジューラを設定できます。 しかし、これらのアーキテクチャでは、新たにインスタンスを作成するごとにスケジュールを設定する必要があり、これが開発者の負担となってしまいます。理想的には、ユーザがインスタンスを作成した際に、自動的に設定された自動起動・停止される仕組みが欲しいです。 そこで今回は、スプレッドシートとGASを用いてインスタンスの自動起動・自動停止するツールを開発し、それを利用することにしました。スプレッドシートを利用する利点としては、ユーザが使い慣れていることと、一覧性があり、管理しやすいという点が挙げられます。 また、今回作成するツールには自動起動・停止するだけでなく、より管理しやすくするため、以下のような機能を追加しました。 インスタンスの利用者名を記載する 誰が責任を持ってインスタンスを利用しているのかを明確にする インスタンスの起動時刻を記載する 起動状態で長期間放置されていないかをチェックする インスタンスタイプを表示する 長期間稼働しているインスタンスが高額なものでないかを確認する ツールの使い方・仕様は、以下の通りです。 定期的に一覧を自動更新する 常に最新のインスタンス状況が確認できるようにする ユーザが手動でインスタンスリストを更新できるようにする 追加したばかりのインスタンスについて、手動で更新し、すぐに設定できるようにする 自動起動・自動停止欄にチェックをつけることでそれぞれ定時に自動で実施される インスタンス作成時のデフォルトでは自動停止のみチェックされる インスタンスの停止忘れによる無駄な課金を防ぐ 以下は作成したツールのイメージです。 図3 最後に、ツールの作成手順を簡単に説明します。 インスタンスを管理するためのIAM/サービスアカウントを作成する ただし、アカウントは誰でも利用できる状態になるので、必要最低限の権限のみを付与します。 スプレッドシートとGASを作成する スプレッドシートは図を参照ください。今回、 GASの作成には、以前当社のブログでも紹介されたClaspを利用しました。(参考: リンク ) トリガーを設定する 今回GASを起動するトリガーとしては、自動起動(定時にインスタンスを起動する)・自動停止(定時にインスタンスを停止する)・更新(インスタンス一覧を更新する)を用意しました。 インスタンスごとの利用料金を監視・通知 インスタンスごとの利用料金を監視・通知するためにどのような技術を利用したかをAWS・GCPそれぞれ紹介します。 AWS の場合 AWSにおいて、インスタンスごとの利用料金を把握するためには、コスト配分タグの利用が効果的です。設定したタグを利用して、以下のような内訳を確認可能です。ただし、コスト配分タグを利用する際は以下の点に注意してください。 利用できるのはOrganizationsの管理アカウントのみ タグの有効化には1日程度かかる場合がある 月の途中でタグを付与した場合、その月の残り期間はタグ未付与とみなされる。 次に、コストの通知について説明します。今回は、AWS LambdaとSlackを組み合わせて通知機能を実現しました。具体的な開発方法については、以下の参考記事などをご覧ください。 https://dev.classmethod.jp/articles/notify-slack-aws-billing/ なお、今回設定した通知の閾値は当社での利用額に対して、少し大きめの額で設定しました。あくまで異常な課金の発生を発見するために設定した値となります。 GCP の場合 GCPはAWSと異なり、コスト分配タグのような機能がないため、Compute Engineに設定できるラベルを用いることにしました。ラベル付は、インスタンス自動起動停止ツールのGAS内で自動に行いました。 ラベル付された結果は、課金のレポートから確認ができます。 ラベル付には こちら のAPIを利用しました。 EBS 棚卸し EBS(Elastic Block Store)ボリュームとは、EC2インスタンスに接続され、データを永続的に保存するためのブロックレベルのストレージデバイスです。EC2インスタンスから物理的に分離されているため、インスタンスを停止または終了してもデータは保持されます。EBSボリュームは確保した容量に対して料金が発生します。そのため、長期間使用されていないインスタンスに接続されているEBSボリュームでも、料金は継続的に発生します。 このような背景から、以下の条件を満たすEBSボリュームについては棚卸しを実施しました。 利用されてから1年以上経過していること 容量が100GiB以上であること 具体的な棚卸しの手順は次の通りです。 対象となるEBSボリュームがアタッチされているインスタンスの利用者に連絡をする EBSボリュームのスナップショットをとる EBSボリュームをデタッチする もしくは インスタンスを削除する EBSボリュームを削除する なお、スナップショットを作成しないとデータは完全に復元できなくなります。したがって、データの保持が必要な場合はスナップショットの作成を忘れないようにしてください。 まとめ 結果 EC2インスタンスの利用料金については、月ごとの使用状況により大きく変動するため、7月度は高額になってしまいましたが、5月と6月では施策導入前よりも大幅に低く抑えることができました。 また、特にEC2その他のコストについて、EBSの棚卸しとともにEIP(Elastic IP)についても棚卸しを実施した結果、当初の半額程度まで削減できました。 GCPについては、Compute Engineの使用料が一定水準を保っており、大幅なコスト増は抑えられていると言えます。 特に注目すべきは、EC2のその他のコストです。これは長期間放置されているとかなり高額になるため、今まで特に組織的に棚卸しをしていなかった分削減効果が大きくなりました。 振り返り この施策を通じて、ツール自体の効果以上に、それぞれのリソースがどれほどのコストを生じているかを理解し、自分自身でコストに対する意識を持つことができました。 さらに、今回の試作を通して運用面での課題も明らかになりました。 定期的な棚卸しの必要性 年単位で放置されているようなリソースが存在し、その所在が分からないものもあります。そのため、棚卸しの手順を繰り返し行えるように準備する必要があります。 アカウントの管理方法の課題 検証用アカウントを共用する方式では、誰がどのリソースを使用すればよいのか判断が難しいです。これに対する対策として、タグ付けのルール化などが考えられますが、検証用アカウントに多くのルールを設けるとメンバーへの負担が大きくなります。ユーザー個人ごとに検証用アカウントを発行する手段もありますが、管理が複雑化するなどの課題もあります。 また、自身でコスト削減を試みるだけでなく、Trusted Advisorのようなツールを利用する手段も検討できます。 この施策を通じて得られた新たな学びは多いです。今後は、より効率的なコスト管理を実現するために、システムを整備していきたいと思います。 reference 社内開発用 EC2 インスタンス料金を節約したい cron で時間指定して ec2 インスタンスを自動起動・停止する AWS のコストをサクッと削減 ~ EBS 編 ~ AWS コスト配分タグを使ってみよう AWS コスト配分タグの運用に入門してみた AWS のコスト配分タグを正しく理解する Lambda x Amazon SNS で、AWS の請求額を毎日メールで通知する AWS Trusted Advisor で無駄なコストを見つける
アバター
目次 はじめに ブランチ戦略 Git Flow GitLab Flow GitHub Flow 開発チームのブランチ戦略 GitHub Flowの採用理由 運用の基本ルール 実際にGitHub Flow運用してみて 良かったこと 悪かったこと まとめ はじめに Insight EdgeのLead Engineerの三澤です。 Insight Edgeでは開発プロジェクトに応じてその時々でチームを編成し、プロジェクトの内容に合わせてチーム単位で技術やアーキテクチャや開発ルールの選定・決定をしています。 今回は直近の開発で運用してきた開発ルール(ブランチ戦略)の1つGitHub Flowについて、実際の運用方法や良かった点・悪かった点をご紹介したいと思います。 本記事ではGitとブランチを既知のものとして進めることにご了承ください。 ブランチ戦略 GitHub Flowの話へいきなり入る前に、まずはなぜブランチ戦略を考える必要があるのかを考えてみます。 皆さんもGitを用いて複数人で開発を進めることがあるかと思いますが、その際には各自がブランチを作成し開発を進めるのが一般的です。しかしこの時、もしブランチ戦略を決めずに各開発者が勝手にブランチを作成してしまうとどうなるでしょうか?各ブランチの意味が不明瞭になるだけでなく、ルールを決めずに開発を進めますので各ブランチのコードをマージするのも一苦労になります。さらに、ブランチが乱立することになりますので、どのブランチが正しく動くソースコードなのかが分からなくなるといった問題を引き起こす可能性があります。ブランチ戦略は、そのような問題に対してルールを定めそれに則って開発を進めることによって解決を図るものです。 ここでは3つの代表的なブランチ戦略を簡単にご紹介します。 Git Flow Git Flow は、Vincent Driessenが2010年に提案したブランチモデルです。masterを安定ブランチとして、そこから分岐したdevelopブランチを開発用のブランチとして開発を進めます。開発者はdevelopブランチから機能毎にfeatureブランチを作成して開発を進め、developブランチへマージを繰り返すというのが基本動作です。その後、developブランチで一定の機能開発やバグフィックスが完了するとreleaseブランチを作成します。このreleaseブランチではリリースの準備としてコードの整理やテストなどが行われます。ここで問題がないことを確認できたらいよいよreleaseブランチの内容をmasterブランチへマージされ本番環境へリリースされます。このようにブランチを用途によって適宜使い分けながらタスクやリリースの管理や安定性の確保しますので、各ブランチの役割が明確になるというメリットがあります。一方で、パッと見てわかる通りブランチの種類が多く管理が複雑になるというデメリットがあります。 GitLab Flow GitLab Flow は、GitLabが提唱するブランチ戦略です。Productionブランチモデル、Environmentブランチモデル、Releaseブランチモデルといったいくつかのパターンがあるのですが、ここではEnvironmentブランチモデルを紹介します。GitLab Flowでの機能開発はGit Flowと異なりdevelopではなくmasterブランチから分岐したfeatureブランチで行います。featureブランチでの開発が完了すると、その内容をmasterへマージし検証環境でテストするという作業を繰り返します。その後、ある程度開発が進んだタイミングでリリース準備を行います。リリース準備はmasterブランチから分岐したpre-productionブランチで行い、問題がなければ本番環境へリリースされます。このリリースしたコードはproductionブランチにマージされ、終了するという流れです。Git Flowほどの厳密なリリース管理が不要になるというメリットがありますが、それでもやはりまだ複雑というデメリットがあります。 GitHub Flow GitHub Flow は、GitHubが提唱するGitLab Flowよりもさらにシンプルなブランチ戦略です。開発はmainブランチから派生したfeatureブランチで行います。featureブランチで開発が完了するとmainブランチにマージされ、このマージされた内容が本番環境へリリースされます。このmainブランチには常にデプロイ可能な安定したソースコードが格納されていることを前提としているのが特徴です。ブランチが2本しか存在しないのでとても理解しやすく、mainブランチにマージしたことを基本としてリリースされるので、開発した内容を短いサイクルでリリースにつなげられることがメリットになります。一方でmainブランチの内容が常にリリースとなることから、検証環境へのリリースやリリースバージョン管理が出来ないというデメリットがあります。なお、我々のチームではGitHub Flowをベースに一部改変することでそのデメリットを克服しています。その内容については後ほど紹介します。 開発チームのブランチ戦略 GitHub Flowの採用理由 タイトルにも書いている通り、我々のチームではGitHub Flowを採用しています。一方で、私の開発経験としてはこれまでGit Flowのブランチ戦略を採用することが多かったです。そのためGit Flowで進めるという選択肢もありました。では、なぜ我々のチームがGitHub Flowを採用したかというと、Insight Edgeでは小回りの効く比較的小規模なチームで素早く開発をすることが多かったから、が理由になります。Git Flowのような厳密な管理をするブランチ戦略は、先の説明の通りリリースまでの工程や確認が多くなります。そのため、こまめに機能をリリースしながらシステムをアップデートしていくというアジャイル的な我々の開発スタイルにミートしませんでした。GitHub Flowのようにシンプルでこまめにリリースを重ねていける開発スタイルが小規模チームは適していると考えました。 一方で先にも触れた通り、GitHub Flowはmainブランチの内容が常にリリースとなることから、検証環境へのリリースやリリースバージョン管理が出来ないというデメリットがあります。そのために我々はGitHub Flowに一部改変を加えています。ここでもしかすると、リリース管理を行うGitLab Flowでも良いのではないかという疑問が湧いてくるかもしれません。しかし、こちらについては管理するブランチ数はなるべく減らしたいこと、リリース管理自体はproductionブランチがなくてもタグで代用できることから採用を見送りました。 運用の基本ルール Insight EdgeではGitHubをプラットフォームとして採用していますので、以降は基本的にGitHubでの用語を用いて我々の開発ルールを説明します。 開発環境 リリースする環境としては、以下の3つを準備しています。 dev 開発者がいつでも任意のタイミングでリリースして良い開発環境。 stg mainブランチへのマージ後に必ずリリースされる本番適用前の検証環境。 prod stgでの検証後にリリースされる本番用環境。 ブランチ 作成するブランチは下記の2本になります。 mainブランチ 安定ブランチです。常にリリース可能なソースコードを管理します。 feature/xxxxブランチ mainブランチから切ります。開発する機能に応じて作成します。xxxxには開発する機能の内容が書かれます。 Pull Request featureブランチで開発が完了するとmainブランチにマージするためPull Requestを開発者が発行します。レビューはリポジトリ管理者と、開発メンバの2人で実施します。2人のレビューによるレビューで問題がなければマージされますが、このマージはfeatureブランチの作成者が行うのではなくリポジトリの管理者が責任を持って行います。 手順 以下が簡単な開発の流れになります。 mainブランチからfeatureブランチを作成 featureブランチで開発完了後、mainブランチへPull Request featureブランチの内容をレビュー。問題なければmainブランチにリポジトリ管理者がマージ mainブランチにマージ後、stg環境へリリース stg環境にてマージされた内容の動作を確認 stg環境で問題なければリポジトリ管理者がリリースバージョンを示すtagを付与 (前回の本番環境へのリリース内容と今回のリリース内容の差分を示すリリースノートを作成) tagの付与されたコミットをprd環境へリリース 通常のGitHub Flowは、手順1-4の流れを繰り返しますが、我々は6以降の手順を追加して運用しています。tagを活用することによって追加のブランチを作成する必要が無くなりますし、prd環境へのリリースバージョンが明確になるという嬉しさがあります。 手順7についてはプロジェクトによっては作成しないこともあるためカッコ付きとしています。我々の開発では、GitHub Actionsで前回のtagと差分を取得しリリースノートを自動作成するようにしています。tagと一緒にリリースノートも作成することで前回との差分が一目瞭然となるため非常に便利です。 また、stg環境へのリリースもGitHub Actionsでmainブランチへのマージをトリガーとしてリリースされるようにしています。prd環境へのリリースについてもGitHub Actionsでリリース出来るようにしていますが、こちらについては最後に人手の承認を挟んでからリリースするようにしています。 上記の手順でそれぞれどの環境にどの内容がリリースされているのかを示したのが下記の図になります。mainにマージされたものは全てstgにリリースされますが、prdへはtagのついたものだけがリリースされます。 その他、開発時のポイント GitHub Flowだからというわけではありませんが、次のような点にも気をつけて開発を進めています。 レビュアーのレビュー負荷を下げるために Pull Requestのサイズはなるべく小さくしています。目安は1-2時間でレビュー出来る分量です。 lintに加えてSonarCloudによるソースコードの静的解析をPull Request時に適用しています。静的解析が通らないとマージできないようにしており、一定の品質が保たれるようにしています。 実際にGitHub Flowを運用してみて GitHub Flowの採用により現在のところ大きな課題はなく運用ができていると感じています。もちろん今後開発の規模が大きくなった時等には新たな課題が出てくることが予想されますが、小規模チームで高速にプロダクトをリリースしていくのに良くフィットした開発ルールと言えます。 最後に運用してみて良かったこと、悪かったことを紹介して終わろうと思います。 良かったこと シンプルな運用フローであるため学習コストが低い 小さい単位でのPull Requestとコードレビューにより、品質管理とフィードバックのサイクルがスムーズになった 悪かったこと こまめにPull Requestを発行するのでレビュー頻度が高くなりがち。特にレビューはリポジトリ管理者に集中し負荷が高い状態が続いてしまった 対策:Pull Requestの発行時に、変更内容の詳細やレビューしてほしい観点を細かく記載することで認知負荷を下げる。チーム編成時のコーディングルールの事前すり合わせを徹底する ブランチが2本しかないのでmainブランチへのマージ時にコンフリクトが発生することがあった 対策:こまめにPull Requestとは言うものの、その単位が大きいことがしばしばあったため、変更を小さな単位で頻繁にレビュー・マージすることを徹底することで、マージ時の競合の範囲を減らしていく まとめ 小規模開発チームが取るべきブランチ戦略としてGitHub Flowに着目し、我々のチームがどのように運用してきたかをご紹介しました。GitHub Flowは素早くプロダクトがリリースできることからPoCなど、価値検証を高速に回していくことが求められる開発現場に特にフィットすることが確認できました。 Insight Edgeでは一緒に変革しながら価値検証ループを高速に回していけるメンバを募集中です!技術選定はもちろん、このような開発ルールについても柔軟に変革できる環境となっていますので、興味がある方はカジュアルにお話させて頂ければと思います。お気軽に 公式サイト の採用ページからお申し込みください!
アバター
こんにちは。Insight Edgeでデータサイエンティストをしている伊達です。 皆さんの会社では、どのような交流施策を導入されていますか? 新型コロナが5類感染症に移行され、弊社メンバーの出社頻度は徐々に増えてきたものの、現状はハイブリッドワークが基本となっています。 ハイブリッドワークだと、各自が好きな出社頻度を決められる反面、全員が常にオフィスにいるわけではないため、組織内での交流や情報交換の場をうまく作らないと、メンバー同士の会話はプロジェクトの定例やミーティングのみになってしまいます。 今回は、私がこれまでに在籍した分析組織で試した交流施策を紹介します。 大学院の研究室 ゼミ ランチ会(論文紹介) 雑談 前職:金融機関子会社のデータ分析系部署 もくもく会(兼雑談会) 最近の論文/ニュース/講演をチェックする会 現在:総合商社のDX内製化組織 勉強会 分析チームLT会 論文読み会 まとめ 大学院の研究室 ゼミ 大学院で所属していたのはコンピュータビジョン系の研究室で、画像認識、3次元復元、SLAMなどの研究をしている学生が多かったです。 研究室であればどこもやっていると思いますが、私が所属した研究室でも毎週1時間ほど、学生が自分の研究内容を紹介するゼミを開催していました。 特色は、学生の約半数が留学生だったため、発表・議論が英語だったことです。 自分の研究内容を英語で他人に発表し、議論する訓練を日々できたことは、国際学会等に参加するための準備として大いに役立ちました。 一方で、まだ研究を始めたばかりで英語の苦手意識がある学部生は割と辛そうでした。 ランチ会(論文紹介) 週に一度、有志の学生で集まり、先生が提供してくれたお弁当を食べながら、それぞれ最近見つけて気になっている論文を紹介する会です。 当時(2017〜2019年頃)は、画像認識系の深層学習手法の研究が急速に進んでおり、毎週面白そうな論文が出ていてネタに尽きなかった、という思い出があります。 こういう論文読み会/紹介を開く場合は、参加メンバーの興味がある程度近い必要があるかなと思います。 自分たちの場合は全員コンピュータビジョン分野の研究をしていたので、「こういう論文もあるぞ」と話が派生していったり、参加メンバーから手法の価値や実験結果の妥当性についてツッコミが入ることもあり、盛り上がりました。 雑談 当時は学生だったので勤務時間という概念がなく、(集中してなさそうな人の)デスクに行って雑談したり、研究室の共有スペースにあるソファでコーヒーを飲みながら、だらだら雑談していました(これを交流施策と読んで良いのか分かりませんが)。 やはり研究生活ではしんどい日もあるので、誰かと他愛のない話をしたいこともありますよね…? こういう場では、かっちりした研究の話はあまりせず、ぼんやりとした課題意識、人生、就活、趣味といったことをみんなと話せて、割と大事な時間でした。 こういう「ムダ」に見える時間も実は大事だと思っていますが、仕事中に長々と雑談していると怒られそうなので、社会人になるとなかなか難しいところですね。 前職:金融機関子会社のデータ分析系部署 もくもく会(兼雑談会) 同じ部の若手3〜4人程度で、毎日夕方に30分程度web会議でマイクオン&ビデオオフにしたまま、作業しながら雑談をする会を開いていました。 普段のプロジェクトの定例やミーティングだと上司や顧客がいるため、そういった場であまり話せないような柔らかい質問、ぼんやりとした課題意識、その他相談ができる場でした。 目的としては大学院の時の雑談と似ていて、「わざわざ会議を開くほどではないけど、できれば聞いておきたいことや確認しておきたいこと」を話したり、仕事とはあまり関係ない話もできたりすることで、個人的には良い場だったと思っています。 一応もくもく会という体で作業をしている(ように見える)ので、会社の勤務時間中でも、こういう場は開催しやすいかもしれません。 最近の論文/ニュース/講演をチェックする会 週に1回、各自気になった論文・記事・ニュースを共有したり、最近の学会等の講演の動画をみんなで視聴して議論したりする会です。 AIやクラウドは日々新たな手法やツールが発表され、一人での情報収集には限界があるため、こういった場で、自分が見落としていたが社内の他の人が見つけた良い論文や記事などを発見でき、良かったです。 紹介内容については、がっつりスライドを作るというより、論文や記事を画面共有しながら雑談する感じなので、あまり準備に時間がかからなくて良かったです。 一応毎週アウトプットの場があるので、日々目にする情報を意識的にスクリーニングし、紹介するに値するかどうか考える習慣がつきます。 現在:総合商社のDX内製化組織 勉強会 弊社では業務時間の10%を自己研鑽に充てることが認められており、その一環として、特定のトピックに興味を持ったメンバー同士で集まって、定期的に勉強会を開催しています。 トピックは開発系、分析系、デザイン系など色々で、トピックによっては異なるチームからの参加があり、チームの垣根を超えた交流や知見共有の機会にもなっています。 自分が最近参加したのは、デザイン経営勉強会、時系列分析勉強会、Kaggle勉強会、MLOps勉強会でした。 分析チームLT会 これまで分析チーム内のデータサイエンティストの知見共有の場があまりなかったため、社内のメンバーが立ち上げてくれました。 LT会なので時間は30分で、毎週1人、最近の分析案件や興味を持って調べたことなどを共有しています。 組織の中で学びを共有し、最新の技術にみんなでキャッチアップしていくために、こういう場は重要だと思っています。 論文読み会 これは上記の分析チームLT会で、私が大学院の時の論文読み会について紹介したところ、他のメンバーが立ち上げてくれた会です。 毎週ランチの時間に30分程度、発表担当者が調べた論文について発表し、みんなで議論します。 トピックによっては論文だけではなく、実務における分析に役立ちそうなものであれば、Kaggleコンペの解法やブログ記事を紹介することもあります。 まとめ 今回は、私がこれまでに在籍した分析組織で試した交流施策を紹介しました。 私が紹介した交流施策を目的別に整理すると、下記のようになるかなと思います。 最新技術をざっくり知りたい → 論文紹介、ニュースや講演のチェック 特定のトピックや技術を深く知りたい → ゼミ、勉強会 社内交流 → 雑談、もくもく会(兼雑談会) 交流施策は「これをどの組織も導入した方が良い」という絶対的なものはなく、各組織のありたい姿や課題によって適切にデザインし、導入していくべきだと考えています。 今回の記事が皆さんの組織における交流施策の検討・導入のきっかけになれば幸いです。
アバター
こんにちは、Insight EdgeでData ScientistのKNです。Insight Edgeでは多種多様なDX案件を手掛けており、その多くでは機械学習や統計解析を用いた分析コードを作成することが求められます。 分析チームの開発言語は基本的にPythonが使われています。PoCの段階ではJupyter Notebookを用いてEDAや可視化、モデル構築がよく行われます。そして、PoCを終え期待した効果が確かめられた場合はPoCで作成したコードをそのまま採用せずに、長期運用を前提としたproduction-readyなコードに書き換える必要があります。 本記事では、主にデータ分析で使われるPythonコードを対象として、adhocな分析コードを実運用を見据えたコードに書き換える際役に立つと考えている取り組みについて紹介します。 また、本記事の内容はリファクタリングに関連はしていますが、設計方針やプログラミングスタイルについては取り上げません。それらは良いコードを書く上では重要ですが、すでに優れた書籍が数多く存在し、習得するのも時間がかかります。今回はPythonに特化して、即効性が高く、始めやすいtipsについての紹介になります。 目次 なぜ分析コードを修正する必要があるのか 型情報の付与、フォーマッターとリンターの活用 バリデータの活用 テストの活用 まとめ なぜ分析コードを修正する必要があるのか 結論から述べると、「コードの信頼性を向上させ、運用コストを下げるため」です。ここでの運用コストとは様々な意味合いが含まれます。 例えば、コードの可読性が低いと、コードの理解に時間がかかり、バグを誘発する原因にになります。また、ロジックの正しさの保証が不十分だと、変更の際に追加の確認作業が発生します。 さらに、データ分析では大量のデータ処理をする特徴があります。もし不正なデータが入力された場合、プログラムの挙動が問題になることがあります。実行過程でエラーが発生するならまだいいのですが、エラーが出ないまま間違った処理をしてしまい、分析の結論に影響を与えた結果、間違った意思決定を促す可能性があります。これらの問題点から、次の観点に沿ってコードを改善することが重要だと考えます。 図1:コードの改善軸と実現するための手段 「コードの可読性」、「データの保証」、「ロジックの保証」という3つの改善軸があり、それぞれに対して、「型情報の付与、フォーマッターとリンターの活用」、「バリデータの活用」、「テストの活用」で対応できると考えます。 もちろん、それぞれの関係は互いに独立ではありません。型情報を与え、型チェックを行うことでロジックやデータに対する保証は向上します。テスト前提のコードを書くことで、適度にコンポーネント化されたプログラムは可読性が高くなります。そういった相乗効果はありますが、寄与度の高さを踏まえると図のような関係になるかと思います。 以下、それぞれの項目について詳しく紹介します。 型情報の付与、フォーマッターとリンターの活用 型情報の付与 Pythonは型が無い動型言語です。それ故に、気軽に始められ、少ない記述量で動作可能なものを作成できます。データ分析現場では大変便利なツールとして、重宝されています。一方で、正しく動作可能かどうかは実際に動かして見るまで分からない面があるので、コードの可読性が低くなりがちです(ダックタイピングと呼ばれる所以です)。 Pythonは3.6以降、「型ヒント」と言って型情報を追記できる機能が追加されました。型ヒントを追加することで、コードの可読性を向上させ、コードの理解にかかる時間を減少させることができます。また、型ヒントを追加することで、IDEの補完機能を活用でき、開発効率も向上します。 # 型ヒント例 # 型ヒント追加前 def convert (texts): ... # 型ヒント追加後 # 関数シグネチャの情報だけでコードの挙動が理解できるようになる。 def convert (texts: List[ str ]) -> Documents: ... また、既存のコードに型情報を追加する際に、もし型情報を書きづらい箇所があった場合、そこにはリファクタリングする余地のある可能性が高いです。 # 型ヒントがうまく書けない例 data = { 1 : 'c' , 'a' : 2 , '1' : [ 'd' , 'e' ]} # Anyは任意の型を許す # これは極端な例だが、辞書型でKeyやValueが異質な型の場合、可読性が著しく落ちる def process (data: Dict[Any, Any]) -> Dict[Any, Any]: ... process(data) ただし、型ヒントは型情報を追加するだけで、実際には型チェックを行いません。型チェックを行うためには、mypyという解析ツール(リンター)を用いる必要があります。mypyは、型ヒントを追加したコードを解析し、型チェックを行うツールです。mypyを用いることで、型ヒントの追加漏れや、型ヒントと異なる型の値を代入している箇所を検出できます。 mypyは大変便利なツールですが、mypyを使うことで静的言語のような型保証が得られるかと言えば、それは疑わしいかと思います。mypyはあくまで型ヒントが互いに矛盾なく使われていることを保証するのみで、実行時に型ヒントとは異なる値が変数に代入されたとしても問題にはならないからです。 また、mypyを厳密に適用すると(オプションで --strict と設定)、かなり冗長に型情報を追加する必要があり、反対に可読性が低下する可能性もあります。シンプルに書きつつPythonを使用するメリットが減少してます。 さらに、自分のコードに厳密に型ヒントを強制したとしても、インポートしているサードバーティ製のライブラリに型ヒントが追加されていない場合がよくあります。代表的なライブラリでは、型情報ファイルをダウンロードできたり、型情報ファイルを自動生成できるものもありますが、手間の割に効果が限定的です。 どの程度の厳密性を適用するかは組織の方針やプロジェクトの性質から判断する必要があると感じます。また、既存のコードに対しいかにmypyを適用していくかは 本家のドキュメント に記述がありますので参考にしてみてください。 フォーマッターとリンターの活用 フォーマッターとは、コードスタイルを整えてくれるツールです。代表的なPythonのフォーマッターは、Blackというツールです。Blackは、PEP8に準拠したコードを自動生成してくれます。PEP8は、Pythonのコーディング規約です。Blackを使うことで、コードのスタイルを統一できます。それによって、コードの可読性を向上させ、コードのフォーマットでの意見の違い等余計なことに悩む必要も無くなります。また、isortと呼ばれるモジュールのインポート順をフォーマットしてくれるツールもあります。 リンターはソースコードを(実行前に)静的解析して、エラー等をチェックしてくれるツールです。先ほど紹介したmypyも型チェックのリンターでした。それ意外の代表的なリンターとしてFlake8があります。Flake8はコードのエラーチェックを行うpyflake、PEP8スタイルに準拠しているかチェックをするpycodestyle, コードの複雑度をチェックするmccabeをバンドルしたものになります。注意点としては、あくまでチェックツールなので自動的に修正してくれるわけではありません。そのため、コードスタイルの補正を先にBlackとisortで行ってから、Flake8でチェックするのが良いかと思います。 基本的にこれらのツールの適用に発生するコストは低いため、極力活用することが望ましいです。 バリデータの活用 PoCの作業中では、データにどのような値が含まれているか観察しながら分析をするので、データの正しさに対する注意、関心が怠りやすくなるかと思います。しかし、実際の本番導入以降でどのようなデータが投入されるかは未知数です。たとえ、データの内容について事前に確約していたとしても、必ずしも守られるとは限りません。 バリデータを活用することで、投入されるデータの正しさについて完全とはいかなくても、十分な保証を得ることができます。特に、実行過程のなるべく早い段階で適用することが望ましいです。早い段階でデータの不当性を見つけることで、副作用を伴う処理(DBへの書き込み等)を防ぐことができます。また、事前にデータの正当性を保証することにより、冗長なデータをチェックする処理を省き、ロジックコードは本質的な処理がメインになリます。その結果、可読性も向上し、データチェックのエラーハンドリングも減少します。 まず紹介するツールは、 pydantic になります。pydanticは型情報やメタ情報を使って、実行時にデータのバリデーションを行ってくれるツールです。実行時のデータチェックを伴うデータクラスと見なすとイメージつきやすいかと思います。 # pydantic例 from pydantic import BaseModel, PositiveInt, ValidationError class User (BaseModel): id : int name: str = 'John Doe' signup_ts: datetime | None tastes: dict [ str , PositiveInt] # この場合、idがintでない、signup_tsが無いという理由でエラーとなる external_data = { 'id' : 'not an int' , 'tastes' : {}} try : User(**external_data) except ValidationError as e: ... 次に、 pandera の紹介になります。panderaは、pandasのデータフレームに対して、スキーマを定義してバリデーションを行うことができます。データ分析の際には、表形式のデータを扱うことが多いので便利です。 # pandera例 schema = DataFrameSchema( { "性別" : Column( str , checks=Check( lambda s: s.isin([ "男性" , "女性" ]))), "年齢" : Column( float , nullable= True , checks=Check.gt( 0 )), "身長" : Column( float , nullable= True , checks=Check.gt( 0 )), } ) df = base_list_schema.validate(df) テストの活用 テストコードを書くことのメリットは色々なところで語り尽くされているので、異論はないかと思います。 ただし、通常のシステム開発と異なり、データ分析や機械学習領域では、テスト駆動開発や実装とテストをほぼ同時に進めるやり方は主流でないと(個人的には)感じています。 データ分析や機械学習のPoCの段階では、ほとんどの場合、より良いKPI(予測精度)の達成が目的となります。その実現手段は何でも良いため、様々な特徴量加工やモデル構築を試し、最も良いアプローチのみを採用し、それ以外のほとんどは無駄になることが多いです。試行錯誤中のコードに対してテストを書いて確認はできますが、結局は無駄になるコードへのテストは中々行われづらいの実情かと思います。 しかしながら、運用が決まった後は、テストコードを必ず書いたほうが良いです。なぜなら、データ加工やモデル構築の処理が確定したので、その処理の正しさを保証する必要があるからです。これは、特にリファクタリングや機能追加を行う際に重要です。本来の機能が壊れていないかことを容易に確認しながら、作業できるため信頼度が高くなります。また、他の人がコードを読む際にも、テストコードがあることでコードの意図を理解しやすくなります。これらの効果はコードの規模が大きくなるほど顕著になります。 一方で、テストはロジックの正しさをある程度保障するものですが、完全ではありません。あくまで限られたテストケースのみにおいて正しさを保障するに過ぎません。また、テストを書くこともコストかかりますし、量が増えてくるとコードの変更ごとのテスト実行の時間も無視できなくなります。さらに、プログラムの仕様を大幅に更する場合(データ分析ではよくありますが)、既存テストも書き直す必要が発生するので、変更への負荷が重くなります。 テストを全く書かないというのはありえないですが、テストをどの程度充実させるかどうかはPJの規模や性質によって変わってくると思います。私は後段の理由もあり、テストの充実度は通常のシステム開発よりも低くなっても良いと思います。データ分析、機械学習領域のテスト方針については私自身十分に結論が出ていないので、今後も検討していきたいと思います。 機械学習の場合の注意点 機械学習の場合の厄介な問題として、データ自体が流動的なため、たとえコードの処理に問題がなくても、精度悪化する場合があります。これは結果としてアプリケーションの本来の機能が達成できていないという点で問題です。 精度劣化の問題に対処するには、継続的にPJのKPIやモデルの精度を監視する体制が必要です。この作業をスポットで行う場合は手動でも問題ないかもしれませんが、日々の業務サイクルに組み込もうとすると、MLOpsの構築が必要なってきます。 テストコードでは精度の保証はできないので、ある程度のテストコードでロジックの正しさを保証しつつ、精度監視をを行うことで機械学習アプリケーションの品質を担保できます。 テストフレームワークについて 代表的なPythonのテストフレームワークは pytest です。標準ライブラリのunittestもありますが、それよりもシンプルで柔軟にテストコードを書くことができます。pytestの使い方については公式ドキュメントを参照してみてください。 最近では、ChatGPTに聞いてもそれなりの回答をしてくるので活用しない手はないです。ただし、業務コードで聞く場合は社内ポリシーに従ってください。 図2: 素数判定のテストコードをchatgptに聞いた結果 まとめ データ分析、機械学習コードの品質を上げるために、「コードの可読性」、「データの保証」、「ロジックの保証」という3つの改善軸があることを紹介しました。 コードの可読性を容易に実現する手段として、「型情報の付与、フォーマッターとリンターの活用」を紹介しました。フォーマッターやリンターは手間が掛からず実行できるので積極的に使うべきです。mypyは厳密に適用すると大変で却って可読性が落ちるので、PJの規模や性質に応じて適用範囲を決めると良いです。 データの保証をするためのツールとして、pydanticとpanderaを紹介しました。両者ともより細かい制約を設定できます。外部データの読み込み時に適用することで、初期段階で不正を検知できますし、コードもよりシンプルになります。 プログラムのロジックを保証するために、テストを書くことが重要であることを述べました。テストを書くことで、早い段階でプログラムのエラーが検知でき、コードの変更に伴うリグレッションも防ぎ、コードの品質を担保することに繋がります。テストの充実度はPJの規模や性質に応じて決めるべきですが、テストだけではデータ分析や機械学習の品質の保証はできないので、そのためにはMLOps等のアプローチを検討することも必要です。 参考文献 ロバストPython ―クリーンで保守しやすいコードを書く
アバター
こんにちは!Insight Edge で Developer をしている Kobori です。 本記事では、Amazon Cognito と Nest.js を使用した認証認可について、調査で得た使い方とノウハウを紹介します! 初めて使用される人でも、本記事を見てユーザープールの設定からユーザー認証まで一通りの機能が使えるようになればと思いを込めて書きました。 ぜひ、最後までご覧いただけたらと思います。 この記事でわかること Cognito のユーザープールの作り方 Nest.js の Guard でのユーザー認証方法 Cognito とは? AWS のユーザー認証、ユーザーの管理ができるサービスです。 ユーザー認証に関わる下記のような充実した機能があります。 実装面においても、AWS ライブラリが用意されているので、フロントエンド、バックエンド問わず、工数を削減してセキュリティの高い機能を実装できます。 Cognito のユーザープールとは? Cognito ユーザープールは、Cognito のサービスの一部でありユーザー管理、属性管理、認証するサービスです。 ユーザー情報(ID、パスワード、メールアドレスなど)やグループ情報の保持、トークン管理、アクセス制限などの設定ができます。 開発者は、ユーザー認証に係る機能を代替えして使用することで、よりアプリ開発に注力することが可能となります。 詳しくは、 Amazon Cognito プール 参照 Cognito の主な提供機能 サインアップ サインイン パスワードリセット パスワード変更 ユーザー属性の管理 JWT トークン(アクセストークン、リフレッシュトークン、リフレッシュトークン)発行 ユーザー固有の UUID 発行 多要素認証 リスクの検出 Cognito の利用料金 月間 50,000 アクティブユーザまで無料で使用できます。 ※ リスクの検出の機能である「高度なセキュリティ」については、追加の料金が発生します。 詳しくは、 Amazon Cognito 料金 参照 Cognito ユーザープールの作成 Cognito でユーザー管理をするには、ユーザープールの作成が必要です。 ステップ別の主な設定内容 ステップ 1:サインイン時に使用するメールアドレス、電話番号の有無の設定 ステップ 2:パスワード要件や多要素認証の有無、アカウント復旧方法の設定 ステップ 3:サインアップ時の確認方法やユーザーに付与する属性情報の設定 ステップ 4:Cognito から送信する E メールの設定 ステップ 5:ユーザープール名、認証方式、トークンの有効期限の設定 作成時の各種設定 ステップ 1:サインインエクスペリエンスを設定 ステップ 2:セキュリティ要件を設定 Authenticator アプリケーション、SMS メッセージでの確認も可能 ステップ 3:サインアップエクスペリエンスを設定 デフォルトのまま次へ ステップ 4:メッセージ配信を設定 一時的な設定として、Cognito での動作確認を優先するのであれば「Cognito で E メールを送信」を選択 SES で E メール送信を行う場合は、AWS SES の設定が必要です ステップ 5:アプリケーションを統合 ユーザープール名の入力 「Cognito のホストされた UI を使用」にチェックと「ドメイン」の指定 アプリケーションクライアント名の入力 ユーザープールにユーザー作成 「E メールで招待を送信」を選択すると仮パスワードが送信される ※ 招待を送信しない場合、仮パスワードの設定をする コマンド で認証確認 サインイン 下記コマンド実行でユーザー名とパスワードを使ってサインインできる クライアント ID クライアントアプリケーションの ID を指定 この ID は、Cognito のコンソール画面のアプリケーションの統合のタブで確認できる ユーザー名 サインインするユーザーのユーザー名を指定します。 パスワード サインインするユーザーのパスワードを指定します。 aws cognito-idp initiate-auth --client-id ”クライアントID” --auth-flow USER_PASSWORD_AUTH --auth-parameters USERNAME=”ユーザー名”,PASSWORD=”パスワード” 初期パスワード変更 初回サインイン時に返された「Session」を使って初期パスワードを変更する aws cognito-idp respond-to-auth-challenge --client-id "クライアントID" --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD="新しいパスワード",USERNAME="ユーザー名" --session "初回サインイン時に返されたsession" ログアウト 下記コマンド実行でログアウトできる aws cognito-idp global-sign-out --access-token "アクセストークン" Nest.js で認証と認可 トークンを使ったアプリ側での認可 Cognito では、コマンドや API でサインインした際に 3 つのトークンが発行され返されます。 サインインでユーザー認証し、レスポンス(ユーザー情報)に含まれるアクセストークンを使用し、ユーザーの有無やトークンの有効期限を判定してアプリ側での認可をします。 リフレッシュトークンを使うと有効期限の切れたアクセストークンを再発行できるので、有効期限が切れた場合に再ログインさせるか、自動で再発行するかアプリ側で使い分けができます。 取得できるトークンの種類 アクセストークン アクセス制限や、ユーザーの認可に使用するトークン グループ情報も含まれている 有効期限は、5分~1日 ID トークン ユーザーの属性情報(例:ユーザー名、メールアドレス)が含まれるトークン 有効期限は、5分~1日 リフレッシュトークン(更新トークン) 再認証なしでアクセストークンと ID トークンの再発行を取得するためのトークン 有効期限は、60分~10年 事前準備 下記をインストール npm install @aws-sdk/client-cognito-identity-provider 下記を import import { AdminInitiateAuthResponse } from 'aws-sdk/clients/cognitoidentityserviceprovider'; サインイン JavaScript でのサインイン処理例 const cognito = new CognitoIdentityServiceProvider(); const data = await cognito .initiateAuth({ AuthFlow: 'USER_PASSWORD_AUTH', ClientId: "クライアントID", AuthParameters: { USERNAME: "ログインユーザー名", PASSWORD: "ログインパスワード", }, }) .promise(); data.AuthenticationResult.AccessToken; ログアウト JavaScript でのログアウト処理例 const cognito = new CognitoIdentityServiceProvider(); await cognito .globalSignOut({ AccessToken: "アクセストークン", }) .promise(); Guard を使ったユーザー検証 Nest.js の Guard でユーザー検証する アクセストークンを使ったユーザー取得をすることで、ユーザーの有無とアクセストークンの有効期限が検証できる ※ユーザーが取得できない場合やアクセストークンの有効期限切れの場合は、例外が発生します const cognito = new CognitoIdentityServiceProvider(); this.user = await cognito .getUser({ AccessToken: "アクセストークン", }) .promise(); Nest.js の Guard でユーザーのグループ検証する グループ情報は、アクセストークンに含まれるのでデコードすることでユーザーに設定したグループ情報が取得できる 下記のように取得後に対象のグループが含まれているか判定をすることで、グループの検証ができる jsonwebtoken のインストール npm install jsonwebtoken アクセストークンをデコードしてグループ情報取得 import jwt from 'jsonwebtoken'; ・・・ const decodedToken = jwt.decode("アクセストークン"); return decodedToken ? decodedToken["cognito:groups"] : []; Cognito を使ってみた感想 難しそうと思っていた認証部分ですが、Cognito の導入により必要な機能を補うことができるので、開発者は、心置きなくアプリ開発に専念できると思いました。 また、ユーザー認証に必要な基本的な機能が揃っており、無料から使える点やライブラリや UI が用意されているため 手軽かつスピーディーな開発に繋がるでしょう。
アバター
はじめに  こんにちは。Insight Edge, Data Scientistのnakanoです。  これまで機械学習モデルを使用する際は、データの前処理、特徴量エンジニアリング、モデルの選択、 ハイパーパラメータの調整といった複雑な手順を専門知識を持つデータサイエンティストが手作業で行う必要がありました。 しかし最近は、クラウドベンダーが提供しているAutoMLサービスの認知度も上がり、 サービスに料金を支払うことでモデル構築プロセスを自動化することが身近になりつつあります。 そのため、技術者として機械学習モデルを構築する業務はだいぶ楽になってきた一方で、 サービスへの課金額を考慮しなければならなくなりました。  私自身、Vertex Forecast(Google Cloudが提供する時系列予測向けのAutoMLサービス)を使う際にどれだけ課金すれば良いのか迷った経験があります。 そこで今回は、その経験を元にVertex Forecastの課金額の決定方法やノウハウを説明します。 はじめに Vertex Forecastとは Vertex Forecastの料金体系 ケース:1000店舗の1週間後までの客数予測モデル トレーニング時間の課題 トレーニング時間の決定方法 トレーニング時間の目安 コンテキストウィンドウの目安 私見 経験 所感 結論 Vertex Forecastとは  Vertex Forecastとは、Google Cloudが提供している時系列データ向けのAutoMLサービスです。 2021年5月にプレビュー版が公開され、2022年6月にGA版が公開されました。 AWSのAmazon Forecastが2019年8月にGA版が公開されていることを考えると、比較的新しいサービスといえます。 Amazon Forecastに比べて設定できるパラメータが少ないこともあり、非技術者でも使いやすく作られたサービスと感じます。 Vertex Forecastの料金体系  まずVertex Forecastの料金体系を紹介します。 Vertex Forecastでは、学習と予測の2つのプロセスがあり学習は時間単位、 予測はデータポイント数(予測する値の数)に応じて課金されます。 学習(Training) トレーニング時間1時間分あたり、$21.25 予測(Prediction) 予測値1000個あたり、$0.20 (0-1M points) 予測値1000個あたり、$0.10 (1M-50M points) 予測値1000個あたり、$0.02 (>50M points) 引用:Vertex AI pricing,Vertex AI Forecast ケース:1000店舗の1週間後までの客数予測モデル  具体的なケースで費用を計算してみます。 たとえば1000店舗を運営しているレストランチェーン店のデータサイエンティストとして勤務していたとし、 店舗から仕込みや発注の都合で直近1週間の客数予測を毎週1回把握したいと要望があったとします。 またデータサイエンティストの事前の分析結果から、 客数予測モデルは毎月1回 (ここでは仮に)10時間分のコストをかけて再トレーニング させる必要があるとします。  この場合の費用は以下のとおり、$218.1/月と見積もれます。 学習(Training)費用 $21.25/時間 * 10時間 * 1回/月 = $212.5/月 予測(Prediction)費用 $0.2/1000 * 1000店舗 * 7日/週 * 4週/月 = $5.6/月 トレーニング時間の課題  上記のレストランチェーン店のケースでは、 トレーニング時間を仮に10時間分と設定しましたが、実際はどのように決めればよいのでしょうか? 使用するモデルが既に決定している場合は、学習用データと検証用データの損失関数を参照することでトレーニングが十分であるかどうかを確認できます。 しかし、Vertex Forecastでは損失関数を確認できません。 他のVertex Forecastユーザーもこの点について言及されていたので、学習の進捗がわからない点はユーザーならば認識している課題のようです。 ( ML: Vertex AI Forecast AutoML ではじめる需要予測 )  そのため、トレーニング時間決定にノウハウが必要となります。 トレーニング時間の決定方法 トレーニング時間の目安  まずトレーニング時間の参考値として、公式ドキュメントの表を紹介します。 この表では、行数、特徴量数、予測ホライズン(予測期間の長さ)によってトレーニング時間の目安が記載されています。 留意点として、この表の値はあくまで目安であり、コンテキストウィンドウ(入力期間の長さ)や特徴量の内容によっても必要なトレーニング時間は変わってきます。  コンテキストウィンドウ(入力期間の長さ)は、ユーザーが学習時に設定する値です。 大きいほど、モデルの精度が向上しますが、トレーニング時間も増加します。 ではコンテキストウィンドウは、どのように設定すればよいのでしょうか? 行数 特徴量の数 予測ホライズン(予測期間の長さ) トレーニング時間 1,200 万 10 6 3~6 時間 2,000 万 50 13 6~12 時間 1,600 万 30 365 24~48 時間 引用:Train a forecast model 予測ホライズン、コンテキストウィンドウとは 予測ホライズンとは、モデルがどれくらい先まで予測するかを設定する値です。日ごとの時系列データで1週間先まで予測する場合は7となります。 コンテキストウィンドウとは、モデルがどれくらいの期間を遡ってデータを参照して予測するかを設定する値です。予測に直近4週間の値を入力する場合は、28となります。 コンテキストウィンドウの目安  次に、コンテキストウィンドウの決定方法についてまとめます。 公式ドキュメントに記載された手順をフローチャートにまとめました。 ざっくりとしたプロセスですが、精度に満足するまでコンテキストウィンドウを増やしていくというものです。 このとき、コンテキストウィンドウの増加とともにトレーニング時間も比例的に増やす必要があります。 コンテキストウィンドウの目安 私見  ここまで公式ドキュメントで紹介されているトレーニング時間とコンテキストウィンドウの決定方法について説明しました。 私自身の経験と所感、結論をまとめます。 経験  以前、以下のケースで時系列データ予測をVertex Forecastで検証しました。 特徴量:4個(タイムスタンプ列(日付):1個、カテゴリ変数列2個、ターゲット変数列1個) タイムスタンプ列とターゲット変数列以外の特徴量が2件しか無いのは、トレーニング時間を抑えるため最低限の特徴量だけを特に前処理せずに入れたためです。 コンテキストウィンドウ:50 予測ホライズン:10 行数:約100万行(時系列識別子1000件、データポイント1000件)  このケースでは、12時間のトレーニング時間まで精度が向上しました。 公式ドキュメントのトレーニング時間の目安と比べて、これはやや長めの時間を必要としました。 標準的なトレーニング時間よりも多くの時間を必要とした要因としては、 特徴量のうち2個は数10のカテゴリ数を持つカテゴリ変数だったことや、 今回のデータが特定の日や曜日でイベントを持つデータだったため日付列から作成できる特徴が多かったことなどが、 考えられます。 所感  AutoMLサービスというと、手元のデータをアップロードするだけで簡単にモデルが構築できるというイメージがありました。 実際に使ってみたところ、私のケースでは簡単に精度の高いモデルが作成できました。 一方で、使えそうなデータをやみくもにトレーニングさせるのは、コスト面で現実的ではありません。 精度に寄与しない特徴量を削除するなど、工夫は必要となります。  欲張って特徴量を増やしすぎず、また学習を一度で完結させようとするのではなく適切な課金を確保することが、AutoMLをうまく利用する上でのポイントだと感じました。 結論  最後に推奨方法と私見をあわせて、結論をまとめます。 課金額に余裕があるとき。 公式ドキュメントのベストプラクティスに沿って、コンテキストウィンドウと予測ホライズンは同じ値にして、トレーニング時間6時間から始め適切なコンテキストウィンドウを探す。 適切なコンテキストウィンドウが見つかったら、時間を増減させて、トレーニング時間を調整する。 課金額に余裕がないとき(ちょっと触ってみたいとき) 特徴量を減らす。(計算量を減らすため) コンテキストウィンドウと予測ホライズンは同じ値にする。(計算量を減らすため) トレーニング時間1時間と2時間でトレーニングさせる。( 重要 :節約のため最小単位の1時間分($21.25)だけ試してみたいところですが、2時間分も動かしておいて、精度の伸びしろを確認しておくことは重要だと考えています。)
アバター
こんにちは。InsightEdgeのDataScientistのSugaです。以前からテレワークをしていますが、最近は自宅の仕事場環境を改善すべくスタンディングデスクやモニターアームを導入してすごく快適になりました。 今回は昨年に経済産業省が主催しているデジタル推進人材育成プログラムである、「マナビDX Quest」に参加したときの記事を書いたので、お時間がある方は読んでもらえれば幸いです。 目次 プログラムへの参加 マナビDX Questとは? 前身はAI Quest 初心者でも参加OK プログラム参加へのきっかけ お知らせが届く 参加動機 応募するときのポイント スキルアセスメント 時間の確保と参加する周辺環境整備 志望動機の推敲 プログラムキックオフ プログラム概要 キックオフセッション 受講手続き オンボーディング コミニュケーション 第1タームPBL(Project Based Learning) 店舗を運営する企業の収益改善 教材の内容 参加者との交流 交流セッション開催 Slackチャンネル 学び合う文化 第2タームPBL(Project Based Learning) 製造業の工数予測 プレゼン課題 地域企業協働プログラムへの参加 チーム組成と準備期間 チーム募集 開始前準備 企業とのマッチング 地域企業協働プログラムの取り組み ワークショップ開催 提案書作成 現地視察 報告書 まとめ 所感 関係人口の大切さ 今年も開催 プログラムへの参加 マナビDX Questとは? マナビDX Quest は 経済産業省が主催するデジタル推進人材育成プログラム です。ぱっと見ると、 「マイナビ?!」 と読めるのですが、毎日コミュニケーションズとは無関係のようです。 「学び」をカタカナにしたようですね。 DXもデジタルトランスフォーメーション(Digital Transformation)の略だと思っていたら、デラックスのDXみたいですね。てっきりデジタルトランスフォーメーションだと思っていました(笑) 前身はAI Quest 前身のプログラムはAI Questという名前で2019年から開始していますが、2022年からはマナビDX Questとして、AI(人工知能)の分野だけでなく、デジタル技術全般に関わるものとしてより範囲を広げて開始されました。詳細については本家のWebページを参照してもらればと思います。 初心者でも参加OK 以下に詳細の抜粋を紹介します。 このプログラムは特別なデジタルスキルを必要とせず、基本的なリテラシーと学ぶ意欲があれば誰でも参加できます。受講生は実際のDXプロジェクトを体験しながら、デジタル技術とビジネス要素(課題の発見、ゴール設定、コミュニケーション力など)を学びます。さらに、データの活用やビジネス変革といったスキルを習得し、データサイエンスプロフェッショナルやビジネスアーキテクトなどの役割を目指すことが出来るというものです。 世の中にはたくさん教育プログラムがありますが、調べてみると面白いものがたくさんあるんですね。 プログラム参加へのきっかけ 以前にプログラミングや機械学習の講師をやっている時期があり、そのときの生徒さんの一人に、カリキュラムを早々と終わらせてしまって、自分で技術書やBlogを読んで自主的に勉強している方がいました。 あるときに、AI Questというプログラムを見つけたので これに参加してみたいという相談 がありました。勉強になりそうだったので、参加してみたら良いのではという話をしました。 自分「どんな内容のプログラムなんですか?」 生徒「画像での不良品検知をやっているんですが、受講者同士でコンペをやって精度を競うんです」 生徒「その他に、実際の案件みたいにやるのでとてもリアルですよ」 生徒「参加者も初心者の人から、ガチな人までいて幅広いですよ」 自分「なかなか面白い試みですね、普通の研修とは少し違う感じですね」 自分「でも、こういう研修って参加費が高くて、なかなか一般の人は受講できないよね」 生徒「書類選考はありますが、通過したら無料で受講できますよ」 自分「え!?、無料なんだ、それは良いですね」 その時は面白い取り組みをしている程度という感じだったのですが、プログラム内容もしっかりしていて、次にあるときには参加しても良いかなと思っていました。 お知らせが届く その後、すっかりそのことは忘れていました。2022年7月になってから、 データサイエンティスト協会 のメーリングリストやコンペティションサイトである SIGNATE からの案内があり、新たにマナビDX Questとしてプログラム参加を募集するということでした。プログラムの内容を確認すると、6ヶ月に渡る長丁場だったので少し不安な部分もありましたが、名前が変わって内容も刷新されるということで 面白そうだったので参加する ことにしました。 参加動機 参加動機をまとめると、 どんな教育プログラムをするのかが気になる 参加者同士の交流が出来て、学習者にどんなニーズがあるのかが気になる 普段はデータ分析や予測モデル実装をする部分が多いのでコンサルティングもたまにはやりたい 新入社員教育など教育のコンテンツを作っていくときの参考にする ということがありました。 応募するときのポイント スキルアセスメント 応募するときにはスキルアセスメントがあるのですが、事前の心構えが必要になります。 いきなりテストが開始されるのでびっくりしないことが重要です 。もし、Jupiter Notebookを使いたい人は事前に用意しておくと良いと思います。データ集計の課題もありますが、データ量はそれほど多くないのでExcelでも対応できると思います。制限時間があるのでなるべく素早く解答する必要があります。 時間の確保と参加する周辺環境整備 それから、基本的には働きながら参加することになるので、 事前に職場へ報告して同意を得ておくとスムーズ です。ただ、仕事終わりや休日などのプライベートの時間で参加ができるので人によっては必要ないかもしれないです。 志望動機の推敲 それから、全員参加出来るわけではなく、選抜があるのですが、スキルアセスメントの結果よりも 志望動機のほうが重要視される と感じました。ですので、志望動機の内容はよく推敲して投稿するほうが良いと思いました。ただ、選考基準は公開されていないのであくまでそういう印象があるということです。 まとめると以下のようになります。 スキルアセスメントへの心構えとデータ分析課題への準備 時間の確保と参加する周辺環境整備 志望動機の推敲 プログラムキックオフ プログラム概要 詳細なプログラムについては本家のサイトを参照してもらうとして、主に以下のようなプログラムがあります。 * ケーススタディ教育プログラム * 地域企業協働プログラム ケーススタディ教育プログラムは「課題解決のためのAI実装プロジェクト」を擬似的に体験するものです。教材を自分で選択して取り組むことになりますが、教材によって課題整理/問題解決/コンサルティング/ロードマップ策定に重きが置かれているテーマもあれば、実際のAIモデル開発に重きが置かれているものもあります。 サイトにも掲載がありますが、 需要予測・在庫最適化 不良箇所検出 店舗を運営する企業の収益改善 業務最適化 などのテーマがありました。 ケーススタディ教育プログラムはPBL(ProjectBasedLearning)と呼ばれていて、 8月から10月に実施される第1ターム 12月末から2月まで実施される第2ターム に分かれています。 地域企業協働プログラムは受講生がチームを作り、実際の地域の中小企業の課題解決に取り組むものです。約2ヶ月間をかけて具体的な課題に対して解決策を提案して報告していく内容になっています。 キックオフセッション 受講手続き 応募後に受講が決定するとメールで受講案内が送られてきて、手続きをするこになります。PBLでは教材配布やモデル開発をするための インフラとしてSIGNATE を利用することになるのでその登録などを行います。受講期間中は オンラインの教材が使用可能 なのでこれから学び始める人にとってはとても良い環境だと思いました。 オンボーディング 受講者向けのガイダンスがオンラインで開催されるので、オンボーディングも丁寧に行われていると感じました。受講者は1800人の規模なので、説明会をするにしても工夫が必要で主催者側はスタートするまでの準備が大変そうという印象でした。また、 参加できない人向けにZoomの録画も提供されている のでそのあたりも親切でした。 コミニュケーション コンセプトとして受講者同士の学び合いを推奨しているので、その仕組をどのように設計するかも重要なポイントだと思いました。Slackチャンネルが用意されていたり、 コミニュケーションツールを活用したりと受講者同士が学び合う仕組みを準備 していました。開会式後、プログラムがスタートするのでそれまでに準備を進めていきます。 第1タームPBL(Project Based Learning) 店舗を運営する企業の収益改善 参加した Project Based Learning (PBL) では、店舗を運営する企業の収益改善のテーマを選択しました。このテーマは 過去案件として実際にあった現場研修プログラム をもとにして作られたものらしく、実際のビジネスシーンに近いリアルな内容でした。 教材は段階的に進行し、毎週新しい教材が公開されていきます。 まずはヒアリング内容から課題を抽出するところからスタートしました。その後、 実際のデータが提供され、そのデータ分析から課題をさらに深掘りし、デジタルを活用した解決策を探求していきます 。このプロセスは実際のDXプロジェクトでよくあるシナリオを再現しており、現実の問題解決をしていく過程を忠実に模擬していると思いました。 途中の提出物はPPTでの提案資料となり、 他の参加者と相互に評価をする課題 があります。点数の高かった人が成績優秀者に選ばれるという、競争要素も含んだ内容になっていました。この評価プロセスは自分自身の成果を他者と比較し、自分のアウトプットに対してどの程度の価値があるのかを知る良い機会となりました。 プロジェクトの自由度は非常に高く、店舗を運営する企業の収益改善の目的に沿っていれば、どんな課題設定にしてもよいです。ですので、 自分なりに課題をどう解決するかの仮説を考えて、解決策のアイディアを考える 良い時間になりました。 例えば、 * 需要予測 * 在庫最適化 * ダイナミックプライシング * デジタルマーケティング など、さまざまなアプローチを考えました。問題解決という観点ではデジタル技術を使わない方法(業務効率化や業務プロセス改善)もあり、 自由な発想によって多くの方法を出せる ということも感じました。一方で、初めての経験する方や初心者の人は、示されていたガイドラインに従う形で進めることも出来ます。 教材の内容 全体として、PBLは自分の考えを具現化し、それを他者と共有し評価するという、 実践的なビジネススキルを身につけるためのとても有効なプログラム だと感じました。また、店舗を運営する企業の収益改善という具体的なテーマを通して、データ分析から解決策提案までの一連のフローを経験でき、そのプロセスを通じて多くの学びを得ることができる教材だと思いました。 このとき、同じ課題をやっている受講者のSlackチャンネル中で活発に議論がなされていました。 各自が理解したことや提案したいアイディアを共有するための定期的な勉強会が主体的に開催されていて そこでの議論もとても有用なものでした。アイディアを共有してフィードバックを受けることで、より良い解決策になっていく受講者もいて、積極的に参加していく姿勢は素晴らしいと感じました。 参加者との交流 交流セッション開催 プログラム開始後は交流セッションが頻繁に開催されていました。そこでは、 Zoomのブレイクアウトセッションを通じて他の参加者と直接会話を交わす機会 が多く設けられていました。他の参加者の背景や参加理由を聞くだけもとても面白かったです。何か話すきっかけが出来たときはSlackでお礼コメントをするととても丁寧で良いと思いました。 ただ、通常の仕事も一緒だと思いますが、 顔が見えない分とても丁寧なコミニュケーションの必要性 を感じました。事務局からも 「丁寧なコミニュケーションをしてください」 と案内があり、やはり一定の配慮は意識した方が良いと思いました。 また、事務局主催の交流セッションの他にも、有志による交流セッションも多く開催されており、自発的な活動が行われていました。Zoomの有料アカウントを持っている人は良いのですが、持っていない人もいるので コミニュケーションツールが提供されて、常時交流できる環境 が整備されていました。 Slackチャンネル Slackチャンネルが設けられており、かなり多くのチャンネルが作られていました。これらのチャンネルでは、 特定のテーマや分野に関する議論の場として機能し、参加者間の交流の場 になっていました。そもそも、1800人規模のSlackはかなり規模が大きいので一定の運用ルールを作っていかないと収拾がつかなくなるので、運用面でも工夫が必要だと感じました。 プログラムの後半の地域企業協働プログラムではチームを組む必要があり、そのための準備として プログラムの早い段階では参加者同士で交流をしている人 が多かったです。チーム組成の話はこの後でしたいと思います。 学び合う文化 特に良いと思ったのは、 包括的なサポート体制と学び合う文化 です。過去に参加した経験のある人がメンターとして有志でサポートするしくみを作っていて、初心者の方々へのサポートが非常に充実していました。本来であれば、講師を採用して有償でサポートする体制を整えますが、 受講者同士が学び合うことでコストダウン にもなります。 さらに、わからないところは経験者によってすぐにアドバイスを提供するという風土が醸成されます。加えて、 サポートに対するコミュニティ貢献賞や成績優秀賞など表彰 も用意されていて様々な形でモチベーションを与えていることも良い点だと感じました。 第2タームPBL(Project Based Learning) 製造業の工数予測 第2タームに開催されるPBLは任意参加なので、プログラム途中でアンケートが実施されて、希望者が受講することになります。また、地域企業協働プログラムと同時期に行われるので、 企業協働プログラムに集中したい人は受講していない 人もいました。 自分はせっかくの機会なので受講することにして、 製造業の工数予測 のテーマを選択しました。基本的な流れは第1タームで経験しているので、全体のプロセスは同じなのですが、提案資料を作るだけでなく、実際に予測モデルを開発するという点が第1タームと異なるポイントでした。SIGNATEを使用してプライベートなコンペティションが開催されて 参加者で予測精度を競っていく ことになります。精度の良かった上位者には発表の機会が与えて、他の受講者にやった工夫を共有することになります。基本的にはテーブルデータの回帰問題を扱うので、特徴量エンジニアリングをどれだけ出来たかの勝負になっていました。データは実際に地域企業協働プログラムに参加した企業のものをベースに作られていると思っていて、かなり リアルな教材の作り になっていました。 プレゼン課題 教材の最後には意思決定者向けのプレゼンを作る課題もあり、受講者が作った資料もとても参考になりました。成績優秀者で非常にきれいなデータ分析のグラフを作っている方がいて、ぱっと見るとBIツールを使ったようにしか見えないのですが、発表後に聞いてみるとExcelで作っていることがわかり、とてもびっくりしました。 多様な背景を持つ受講者がたくさんいるので、まだまだ 知らない視点 がたくさんあると感じられました。その他、モデリング時のデータに対する見方もたくさんあり、 相互で学び合うことでのメリット があると思いました。 地域企業協働プログラムへの参加 チーム組成と準備期間 チーム募集 地域企業協働プログラムは2022年12月中旬にはじまりました。その前にチーム組成をする必要があり、チーム組成のイベントもたくさんありました。チーム人数は固定で決まっているので、多くなったり少なくなったりすることは出来なかったです。slackでの募集もあり、自分の場合はslackのチーム募集のチャンネルを使ってチームを作りました。募集後に顔合わせの打ち合わせをやって、自己紹介をしたり、どんなことができるかの共有をしてチームを組めるかを決めて行きました。 違うメンバーで顔合わせの打ち合わせは何回かやって、最終的に気が合いそうな人で組むことにしました。プログラムに参加している時点でやる気がある人なのでそこは問題ないのですが、条件をつけて探している人もいました。学生で参加している人もいましたが、社会人で参加している人も多く、時間の都合が合いやすい人でチームを作っている人もいました。 開始前準備 プロジェクトがうまくいくかどうかは良いチームを作れたかどうかにかかっている ので、チーム組成はとても重要だと思いました。営業職、コンサルティングをやっている人からエンジニア、データ分析を仕事にしている人や初学者、学生まで幅広い参加者がいます。チームとしては全体のバランスが大切で、出来ればいろんな多様性をもった人で組む方がうまくいくと思いました。同業者でも良いとは思うのですが、解決策の幅が狭くなってしまう傾向があるように感じました。 また、チームを組んだら、チームの目標と価値観をしっかり決めておくことや顔合わせをしっかりとやってお互いのことを知っておくなど準備をしたほうが良いです。仕事や学業など忙しい中で参加している人が多いので、忙しい時間帯を知ったりして、しっかりコミニュケーションできる関係を事前に作っておくことが大切です。自分が参加したチームも事前に顔合わせをしたり、 自分達のチームのロゴを作ったり 自己紹介資料を準備したりと事前準備をしっかりやりました。 企業とのマッチング チームとしてやりたいジャンルをあらかじめ登録して、プログラム参加企業とのマッチングが行われます。注意点として、必ずしもすべてのチームとのマッチングがされるわけではないので、希望に添えないこともあるということは事前に知っておく必要があります。 マッチングされなかったチームは分析コンペティションに参加する など、自主的に課題に取り組んでいるところもありました。 自分達のチームは四国にある企業とマッチングしました。課題のテーマとしては、 地域活性化とデジタルマーケティング でした。あらかじめ地域企業やりたいテーマを資料でもらって、そこから初回ミーティングをZoomで実施してどんなことがやりたいかをヒアリングしていくことになりました。プロジェクトを進める上でのポイントとして、企業側との技術的なキャップや期待値のギャップはとてもあるので、そのキャップを意識しながら話を進めていくことになります。技術をつかえばどんなことでも出来ると思われているととても大変なので、そのあたりを解消することも大切です。また、企業側のやりたいことが不明確である場合も多く、どんなことがやりたいかを明確にしていくことからスタートして行きました。 企業側はDX推進をやりはじめたばかりなので、 ロードマップ策定をやって今後の方向性を決めることが出来れば ある程度はうまくいったと言えます。企業側とのコミニュケーションをはじめるにあたってはなるべく信頼関係を作れるようにすることを意識しました。各チームメンバーと企業側の担当者の方の自己紹介をお互いにやって、スムーズにやりとり出来るよう心がけました。 地域企業協働プログラムの取り組み ワークショップ開催 企業側との打ち合わせは毎週土曜日に設定して打ち合わせを重ねて行きました。チームで話し合って、 アイディアを広げるワークショップを自主的にやろう ということになり、プロジェクトに参加する全員でアイディア出しをしました。特に、ワークショップはチームから提案してやることにしました。その結果として、企業側と打ち解けることも出来てやって良かったです。ワークショップをやることは、実際の解決につながるかどうかは不明確なところもありますが、シンプルにアイディアをワイワイと話すのは楽しいので仲良くなる目的として成功したと思いました。 その後はより具体的に地域活性化のアイディアを考えていくために、リサーチをしたり、ヒアリングをして行きました。 地域のことは知らないことも多く、観光や産業や歴史など幅広く調査をしました 。また、ドメイン知識は企業側に聞くと早いことがあり、分からないことは素直に聞くことでたくさんの発見がありました。 提案書作成 チーム内の打ち合わせも平日夜に集まって提案内容を作って行きました。Google Slidesを共有してみんなで編集しながらオンラインで会話しながらやっていました。 チームメンバーは地方に住んでいる人もいたので、基本はオンラインでやりとり しながら進めていました。 企業側は年度初めから新しいサービスを提供することになっていて、その サービス提供に合わせて施策が出来るようなスケジュール を組んで検討して行きました。 現地視察 ある程度、提案内容が固まった段階でやはり 実際に現場を見に行かなとわからない ということもあり、2022年12月にチームメンバーと一緒に四国へ行くことにしました。現地に行ってみると気づくことも多くとても良い経験になりました。さらに、地元の市役所の地域振興担当にもヒアリングを行って、地域の課題もヒアリングしました。最終的にはプログラムの最終発表のためにメンバー全員で四国に行って発表もしました。まとめた内容は企業側からの評判も良かったです。 写真は四国に行ったときの風景です。 報告書 最終的な報告書が経済産業省から公開されているので、 プログラムの詳細についてはそちらを参照 してもらえればと思います。かなりの分量があり各地で受講者が奮闘していた軌跡を知ることが出来ます。 令和4年度 地域デジタル人材育成・確保推進事業 2022年度「マナビDX Quest」現場研修プログラム事例集 まとめ 所感 応募当初はプログラム参加に少し迷いもありましたが、最終的にはプログラムに参加してよかったと思っています。平日夜や土日を使うので少し忙しくはなりますが、その分得ることも多かったです。地域企業協働プログラムに参加したチームメンバーはその後も情報交換をしたりしていて、 プログラム参加したことで新しい交流も生まれた と思いました。また、きっかけがなければは四国に行くタイミングもなかったので、新しく地域とつながるきっかけにもなりました。 関係人口の大切さ 市役所の地域振興担当が言っていたことがとても印象的で、 地域活性は関係人口(実際に住んでいる人ではなく、仕事や観光などで地域を訪れる人)が大切 ということでした。プログラムに取り組んだ自分達のチームはまさに関係人口となって地域を訪れたのでそのことを実感しました。地域企業協働プログラムに参加した企業は報告書を見ると、88社もあったので、プログラムに参加したそれぞれのチームごとの経験があったと思います。 今年も開催 今年度(2023年度)も「マナビDX Quest」は開催することが決まっていて7月中旬頃まで募集しているので 興味をもった方はチャレンジしてみる と普段とは違った体験が出来ると思います。 ※ ここに書かれているのは、あくまでも2022年度のプログラムに参加したときの個人の感想なので、人によっては違う経験をしたり、プログラム内容について 多少の差異や勘違いがあることはご了承ください 。また、教材内容や地域企業協働プログラムについては公開されている情報にもとづいて記事を作成しています。
アバター
こんにちは!Insight Edgeの小林まさみつです。 以前からChatGPTが様々なところで話題に上がっていて、とても盛り上がっていますね。 弊社でもChatGPTを活用してどのように価値を生み出すことができるかを日々考えており、業務の10%の時間を使って行なっている勉強会の1つのテーマとなっています。 その勉強会の中で「私の代わりにChatGPTがSlackのメッセージを送信する」アプリを作成しましたのでご紹介いたします。 ※本プログラムでは、実行される処理の内容がChatGPTの回答に依存するため、意図しない処理を実行する可能性があります。ご利用の際は自己責任でお願いいたします 目次 1. 概要 2. 構成 2.1. 構成要素 2.2. 処理の流れ 3. 環境 4. 実装 5. 実行結果 5.1. コンソールとSlack 5.2. 実際に処理されたシェルスクリプト 6. まとめ・今後の展望 1. 概要 現在、ChatGPTを活用した文章生成アプリケーションが様々に存在しますが、その大部分は人との対話やチャット用途に焦点を当てています。 一方で、ChatGPTの能力を活かし、生成されたプログラムを実際に動作させるアプリは前述の用途に対するアプリに比べてあまり探求されていない印象です。 そこで今回は、ChatGPTの潜在能力を最大限引き出す新たな試みに取り組みました。具体的には、ChatGTPに送信された文章の回答だけでなく、その回答をSlackに投稿するプログラムも生成させるようにし、文章の送信からそのプログラムの実行までを一括で行うアプリを開発しました。 アプリの動作イメージ 本アプリでは以下のような動作をイメージして作成していきます。 コンソールに、SlackのチャネルIDと投稿したい内容を生成する文章を入力する 投稿したいチャネルIDを入力してください:D03TDUPPQMP 投稿したい内容を入力してください:食事に誘って Slackにメッセージが投稿される 2. 構成 アプリの構成は以下の通りです。 2.1. 構成要素 登場する要素は以下の通りです。 コンソール:今回はコンソール上でアプリを動作させます。 GPTアプリ:コンソールから受け取った文章を元に、OpenAI APIへリクエストを送信し、ChatGPTにより生成されたプログラムを実行します。 OpenAI API: OpenAI社 が提供しているAPIです。今回は LangChain を用いてAPIを呼び出します。 Dockerコンテナ:自身の環境を汚さずに実行したいため、Dockerを用います。 Slack API: Slack のAPIです。メッセージを送信するために用います。 2.2. 処理の流れ 処理の流れとしては以下の通りです。 コンソールでSlackへ投稿したいメッセージの内容をGPTアプリへ入力する。 OpenAI APIへ以下の2つのリクエストを送信する。 コンソールに入力された内容を元に、投稿するメッセージを生成する。 Slackにメッセージを投稿するプログラムを生成する。 OpenAI APIから先ほどの2つの回答を受け取る。 受け取った内容を元に、Dockerコンテナを起動する。 DockerからSlack APIへメッセージ投稿のリクエストを送信する。 Dockerコンテナを削除し、自身の環境を元に戻す。 3. 環境 本システムの環境は以下の通りです。 前述の通り、OpenAI APIを利用するために、LangChainを用います。 MacOS 13.3.1 Python 3.11.1 pip 22.3.1 openai 0.27.7 langchain 0.0.184 Docker 20.10.20 各種APIキーは以下から作成できます。 OpenAI API: https://platform.openai.com/account/api-keys Slack API: https://api.slack.com/tutorials/tracks/getting-a-token ※Slack APIは User Token を作成し、 chat:write をスコープに加えます。 4. 実装 OpenAIは、APIリクエストの内容を保存しない(学習に用いない)としていますが、念の為SlackのAPIキーは送信しません。そのため、環境変数に格納しておき、その環境変数を用いてプログラムを作成するようにしています。 また、プログラムをシェルスクリプトとして生成してもらうことで、Pythonのsubprocessモジュールで直接実行するようにしました。 import subprocess from langchain.chat_models import ChatOpenAI from langchain.schema import ( HumanMessage, SystemMessage ) from langchain import LLMChain from langchain.prompts.chat import ( ChatPromptTemplate, HumanMessagePromptTemplate ) import os import re os.environ[ "OPENAI_API_KEY" ] = "**********" os.environ[ "SLACK_API_KEY" ] = "xoxp-**********" # Slackに投稿するテキスト生成用のLLMChain def create_slack_message (question): chat = ChatOpenAI(temperature= 0 ) human_message_prompt = HumanMessagePromptTemplate.from_template( """相手に対して次の内容を送信してください。 例 Q:今日の挨拶をして おはよう!元気? では、以下の内容でお願いします。 {text}""" ) question_prompt = ChatPromptTemplate.from_messages([human_message_prompt]) question_chain = LLMChain(llm=chat, prompt=question_prompt) answer = question_chain.run(text=question) return answer # Dockerfileを生成し、実行するコード生成用のLLMChain def create_docker_code (): chat = ChatOpenAI(temperature= 0 ) messages = [ SystemMessage(content= "あなたはシェルスクリプト、Docker、Slack APIにとても詳しく親切な人です" ), HumanMessage( content= """ 以下の内容を実行するシェルスクリプトを作成してください。 1. Slack APIを用いて他者にチャットを送るために必要な記述をしたDockerfileをカレントディレクトリに作成してください。 2. また、そのDockerfileを利用してコンテナを起動してください。 3. 2で作成したコンテナを削除してください。 以下の条件を満たしてください。 ・SlackAPIキー:$SLACK_API_KEY(環境変数に設定済み) ・送信先のチャネルID:$CHANNEL_ID(環境変数に設定済み) ・メッセージの内容:$SLACK_MESSAGE(環境変数に設定済み) ・SlackAPIキーはリクエストヘッダに、チャネルIDはリクエストボディに含めてください 回答は、以下の例のように記述してください。 特に、コメントや説明が無くスクリプトのみ記載されていることに気をつけてください。 また、改行コードはエスケープしてください。 ```sh cat << EOF > Dockerfile \\ nFROM alpine:latest \\ nRUN apk add --no-cache curl \\ nCMD curl -X GET -d '{"text":"$QUESTION","channel":"$CHANNEL_ID"}' "https://google.com" \\ nEOF docker build -t google-app . docker run -d -p 80:80 google-app docker rm -f google-app docker rmi google-app ``` """ ), ] return chat(messages).content if __name__ == "__main__" : # Slackに投稿するチャネルIDを環境変数に設定 os.environ[ "CHANNEL_ID" ] = input ( "投稿したいチャネルIDを入力してください:" ) # Slackに投稿するテキストを生成し、環境変数に格納 message_request = input ( "投稿したい内容を入力してください:" ) slack_message = create_slack_message(message_request).replace( " \n " , " \\ n" ) os.environ[ "SLACK_MESSAGE" ] = slack_message # Slackに投稿するためのスクリプトを生成し、その中のコードのみを抽出する ans = create_docker_code() code_block = re.findall( r'```[^\n]*\n(.*)```' , ans, re.DOTALL)[ 0 ] codes = code_block.split( " \n\n " ) # subprocessを用いてコードを1行ずつ実行する for shtxt in codes: subprocess.run(shtxt, shell= True ) ※本アプリはプログラムの生成がOpenAI APIに依存するため、エンジンが更新されたタイミングなどで動かなくなる可能性があります。受け取る回答のフォーマットに左右されないように改善していく必要があります。 5. 実行結果 実行結果は以下の通りです。 Dockerが起動し、実際にSlackへメッセージが投稿されていることを確認できました。 5.1. コンソールとSlack % python gpt.py 投稿したいチャネルIDを入力してください:D03TDUPPQMP 投稿したい内容を入力してください:食事に誘って [+] Building 3.2s (6/6) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 434B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/alpine:latest 3.1s => [1/2] FROM docker.io/library/alpine:latest@sha256:02bb6f428431fbc2809c5d1b41eab5a68350194fb508869a33cb1af4444c9b11 0.0s => CACHED [2/2] RUN apk add --no-cache curl 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:71d44499df5f6bea3c9bf89a84b59e0a3ceba1042f0dce52b63f4667749cacee 0.0s => => naming to docker.io/library/slack-app 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them 15e9ef691c891cffe18016ba92c106288cc7e0abc7f61b670cbfa4fd71275c23 15e9ef691c89 Untagged: slack-app:latest Deleted: sha256:71d44499df5f6bea3c9bf89a84b59e0a3ceba1042f0dce52b63f4667749cacee 5.2. 実際に処理されたシェルスクリプト Slackへメッセージを投稿するためのスクリプトです。 catコマンドでDockerfileを生成し、それを元に起動・削除しています。 cat << EOF > Dockerfile FROM alpine:latest RUN apk add --no-cache curl CMD curl -X POST -H "Authorization: Bearer $SLACK_API_KEY " -H "Content-type: application/json" -d \' {"channel":" $CHANNEL_ID ","text":" $SLACK_MESSAGE "} \' "https://slack.com/api/chat.postMessage" EOF docker build -t slack-app . docker run -d slack-app docker rm -f $( docker ps -aqf " ancestor=slack-app " ) docker rmi slack-app 6. まとめ・今後の展望 今回はChatGPTにSlackのメッセージを送信してもらうアプリを紹介しました。本アプリの作成を通してChatGPTの可能性をより実感できました。今後の展望としては、SlackのChannel IDを指定するのではなく、人名やチャネル名などを元に送信先を決定できるようしたいと考えています。そうすることでより使いやすくなりそうです。具体的には、Alexaアプリにすることでより簡単にメッセージを送信できるようになります。他にも、相手のメッセージに対して自動で返信してくれるようにするのも面白そうです。 本アプリではSlackのメッセージ送信を対象としましたが、他にも様々なコードを実行させることができるので色々試してみたいと思います。
アバター