有名テック企業の技術ブログを、ひとつのフィードで。
フィード
32件
長女と2人ポケパーク、世代を超えて愛されるものを作れるってすごいよね はじめに こんにちは、エムスリー株式会社 業務執行役員 VPoE 兼 基盤チーム チームリーダーの河合(@vaaaaanquish)です。 この記事は「基盤開発チーム ブログリレー3日目」の記事です。 先日、基盤チームで「うちもブログリレーやろう!」と盛り上がりまして、「いいね!私も書こうかな!」と気軽に思っていたのですが、何故か1日目と2日目の記事がOCamlの記事になっており「それをやられたらビッグウェーブに乗るしかないが…?」ということで私もOCamlで機械学習をやりました。 つまり本記事は、気合いと根性のやってみた記事になります。 はじめに LightGBMとは ということで出来ました 技術的に面白いなと思ったところ ctypes-foreign float32/float64問題 メモリ解放問題 char**のマーシャリング 動かしてみる おわりに We are hiring !! エンジニア採用ページはこちら カジュアル面談もお気軽にどうぞ インターンも常時募集しています LightGBMとは LightGBMは、勾配ブースティングというアルゴリズムを実装したフレームワークです。 2016年8月にMicrosoftが公開して以来、汎化性能の高さやライブラリとしての扱いやすさから人気を伸ばし、今尚Kaggleの表形式コンペでは「最も定番のフレームワーク」と言っても差し支えないほど使われています。 github.com 本家の中身はC++で、OpenMPでゴリゴリに並列化しつつメモリ書き込みの競合を避けるためにスレッドローカルなメモリ領域を確保したりと、面白い工夫がいくつも実装されている強いライブラリです。 私はLightGBMのRust版のBindingを作った経験があり、LightGBMにcommitする程度にはC APIを概ね把握しているため、OCamlでもFFIさえ掴めれば出来るはずです*1。 github.com 一方OCamlは初心者。一体、どうなっちゃうのー!? ということで出来ました 出来ました。 github.com なんとかなったので、実際の挙動はRepositoryを見てもらうとして、ここからは技術的に面白かった部分の話を書いていこうと思います。 技術的に面白いなと思ったところ ctypes-foreign 調べるとOCamlでC関数を呼ぶ方法はいくつか見つかりました。 今回は ctypes-foreign を使いました。 github.com ctypes-foreignは、libffiを利用した動的FFIを扱うライブラリで、OCaml側だけでC関数のバインディングを記述できそうだったので「これなら簡単じゃん…!」という事で進めました。 当然痛い目に遭いました。 具体的にはポインタ周りです。 ctypes-foreignでは、C関数名と型シグネチャを渡す書き方をします。 @-> 演算子で引数の型を連鎖させ、returning で戻り値の型を指定する、以下のようなコードです。 open Ctypes open Foreign let lgbm_dataset_create_from_mat = foreign "LGBM_DatasetCreateFromMat" (ptr void @-> int @-> int32_t @-> int32_t @-> int @-> string @-> ptr void @-> ptr (ptr void) @-> returning int) LightGBMは機械学習のライブラリなので行列演算が主たる操作になります。 つまり、ポインタのポインタのポインタを多く扱うライブラリでして、頭の中で「今@->@->@->@->だから次は@->@->で……つまり今俺は@->@->@->を触っている……?」という、AIもやってくれないパズルをすることになりました。 ctypes-foreignは、書き手にCのスタブコードを書かせないという意味で凄いライブラリで、型レベル DSLや動的libffiの実装は他のFFIバインディングでも使えるなというアイデアが詰まっています。一方普遍的な事実として、プログラミングにおいて初見の簡単さは実際の簡単さに比例しないという当たり前の事を思い出す、そんな令和の春になりました。 もうぶっちゃけほとんどこのパズルに時間使ったので、ここからはオマケと言っても過言ではないです。 float32/float64問題 LightGBMのC APIでは、機械学習において、入力となる行列(特徴量)がfloat32/float64、回答を表す行列(ラベル)がfloat32です。 Rustではf64とf32が別の型として存在するので自然に区別できますが、OCamlのfloatは常に64bitのdoubleです。 ここでctypesのCArrayを活用しています。 (* 特徴量: OCaml float → C double(自然な変換) *) let flat = CArray.make double (nrow * ncol) in Array.iteri (fun i row -> Array.iteri (fun j v -> CArray.set flat (i * ncol + j) v) row ) data; (* ラベル: OCaml float → C float(暗黙の精度切り捨て) *) let c_label = CArray.make float label_len in Array.iteri (fun i v -> CArray.set c_label i v) label; CArray.make doubleとCArray.make float でCの型を指定して、ctypesに適切なメモリレイアウトのバッファを確保させています。 ctypesのランタイム型記述子で作った事で、64bit→32bitの精度切り捨ても自動で行えて、個人的にニヤニヤしたお気に入りの実装です。 メモリ解放問題 C APIで確保したリソースは明示的に解放が必要になるのは当然のことです。 リソース解放においては、OCamlでは Gc.finalise という機能があります。 実装を始めた当初は決定論的に呼ばれるものかという意識をせず「Rustで言う所のDropトレイトみたいなもんかな」という安易な考えで組み込みました。 let from_mat ~data ~label = (* ... C APIでハンドルを取得 ... *) let t = { handle } in Gc.finalise free t; (* GCがtを回収する時にfreeが呼ばれる *) t ここでRustのDropにはない制約としてGc.finalise の「ファイナライザ内での例外処理」に当たりました。 A finalisation function may raise an exception; in this case the exception will interrupt whatever the program was doing when the function was called. 上記の公式ドキュメントの記載によると、ファイナライザは例外を投げると、その例外はGCのタイミングに依存した無関係なアロケーションポイントで再raise されるため、GCが発生した時点で実行中だった無関係なコードが中断されるみたいです。 そのため free関数でC APIの戻り値を無視するような実装になっています。 let free t = ignore (Lightgbm_raw.lgbm_dataset_free t.handle<span cl
こんにちは。エンジニアリンググループのAI・機械学習チームに所属している鴨田 です。弊チームでは毎週1時間の技術共有会を実施しており、各自が担当するプロダクトの技術や、最近読んだ論文を紹介しています。今週はICLR2026が開催されていることもあり、同学会の論文読み会となりました。1セッションにつき1名が担当し、各自が選定した論文の詳細について解説しました。本ブログではその一部として、セッションごとの「推し論文」を紹介します。 まだ読んでいない方は前回のAAAI2026の輪読会ブログも是非ご覧になってください www.m3tech.blog ICLR 2026からトップページバナーを引用 Is it Thinking or Cheating? Detecting Implicit Reward Hacking by Measuring Reasoning Effort 推しポイント はじめに 報酬のハッキング 暗黙のハッキング 論文の提案 感想 AnyUp: Universal Feature Upsampling 推しポイント 課題 感想 Neon: Negative Extrapolation From Self-Training Improves Image Generation 推しポイント RealPDEBench: A Benchmark for Complex Physical Systems with Real-World Data 推しポイント マスク学習によるダイナミクスの獲得 U-Netの有用性とコストパフォーマンス 実データ収集における計測規模 Invisible Safety Threat: Malicious Finetuning via Steganography 推しポイント ステガノグラフィによる攻撃 ステガノグラフィでの学習、推論の工夫 感想 We are hiring !! エンジニア採用ページはこちら カジュアル面談もお気軽にどうぞ インターンも常時募集しています Is it Thinking or Cheating? Detecting Implicit Reward Hacking by Measuring Reasoning Effort セッション: Oral Session 2D LLMs and Evaluation 著者: Xinpeng Wang, Nitish Joshi, Barbara Plank, Rico Angell, He He 論文リンク:https://openreview.net/forum?id=Gk7gLAtVDO 紹介者: 髙橋 論文中Figure 2から引用 推しポイント はじめに ある評価指標が目標に設定されると、その評価指標はもはや良い評価指標ではなくなる これはよく知られた格言でKPIデザインなどでよく言及されますが、LLMにも当てはまります。 最近のコーディングエージェントなどのLLMは、多ステップの推論を経て複雑な問題を解きます。こうした推論能力の最適化には主に強化学習が用いられ、最終的な正解や、そこに至る正しい推論ステップ(過程)に対して報酬を与えることでモデルの学習が進められます。 報酬のハッキング この学習の過程でモデルは設計者の期待から逸脱した行動によって報酬を「ハック」しようとすることがあります。 例えば、ユニットテストの通過のみを報酬として設定すると、モデルは要件から想定される実装の代わりに、テストの入出力をそのままハードコードして無理やりパスさせようとするケースがあります。 このような「明示的なハッキング」であれば、モデルの推論過程(CoT:Chain-of-Thought)を監視することで比較的容易に検知できます。なぜなら、モデルが抜け道を使おうとするプロセスや意図自体が、CoTのテキスト上にそのまま出力されてしまうためです。 暗黙のハッキング 今回の論文が問題提起しているのは、明示的なハッキングより巧妙な「暗黙のハッキング(Implicit Hacking)」と呼ばれる現象です。 暗黙のハッキングとは、モデルが実際には早期に抜け道を利用して答えを出しているにもかかわらず、CoT上では「いかにも正当な推論を順序立てて行っているかのような」もっともらしいテキストを生成して隠蔽している状態を指します。 暗黙のハッキングが行われていると、出力されたテキストを監視する従来の手法では見抜くことができなくなってしまいます。 Claude Codeを利用していても、実際には実行していないコマンドをあたかも実行したかのように報告することがあります。 論文の提案 論文中の実験ではタスクの中に意図的にLoophole(容易に報酬が得られる抜け道)が存在する環境を構築し、強化学習を通じてモデルがどのように振る舞うかを観察しています。 引用図のように特定の条件(問題のid番号や負の数を返せば報酬が得られる)を満たせば本来の推論をスキップして正答できる抜け道を与えた結果、モデルはその抜け道を利用して容易に正解を導き出しながらも、出力上はもっともらしく長い推論過程を生成し続けるという「暗黙のハッキング」を学習するモデルが実際に作られました。 論文ではこうした暗黙のハッキングを検出するための手法として、Truncated Reasoning AUC Evaluation (TRACE)を提案しています。 考え方としては、「ハッキングを利用していると推論のステップ数が少ない段階で本来解けないはずの問題を正解できてしまう」、という性質を逆に利用します。 具体的には、推論ステップの生成を10%、30%、50%といった任意の割合で強制的に打ち切り、その時点での文脈のみから最終解答を出力させます。 各打ち切り時点の推論ステップと正答率をグラフにプロットし、その曲線の下の面積(AUC: Area Under the Curve)を計算します。 暗黙のハッキングを行っているモデルは、推論の初期段階で打ち切られても高い正答率を保つため、AUCの値が大きくなる一方でハッキングを利用していないモデルでは、推論ステップ数に伴って正答率が向上するためAUCの値は比較して小さくとどまります。 この指標を用いることで、生成されたテキストのもっともらしさに騙されることなく、モデルの内部的な推論の早期終了を定量的に検知できる、と論文では主張されています。 感想 LLMの発展は常に目覚ましいもので、どうしてもモデルの規模に目が奪われがちですが、モデル能力の向上は評価側の発展に支えられているのだなと改めて感じさせてくれる論文でした。 AnyUp: Universal Feature Upsampling セッション: Oral Session 5E Learning in computer vision 著者: Thomas Wimmer, Prune Truong, Marie-Julie Rakotosaona, Michael Oechsle, Federico Tombari, Bernt Schiele, Jan Eric Lenssen 論文リンク:https://arxiv.org/pdf/2510.12764 紹介者: 鴨田 論文中Figure 3から引用 視覚基盤モデル(VFM)の発展により、画像全体の高度な意味理解が可能になりましたが、構造上出力される特徴量マップの空間解像度が劇的に低下してしまうため、ピクセル単位の精緻な予測(セグメンテーションや深度推定など)が難しいという根本的な課題があります。 この課題を解決し、低下した解像度を復元するアプローチとして特徴量アップサンプリングの研究がこれまでも盛んに行われてきました。しかし、既存の学習ベースの手法には、DINOやCLIPなどバックボーンとなるモデルを変更するたびに、アップサンプラー全体をゼロから再学習しなければならないという実用上の大きな壁がありました。 この論文の面白いところは、特定のモデルアーキテクチャに依存しない「特徴量非依存(Feature-Agnostic)」なアップサンプリングを推論時に実現している点です。 従来のように特定の特徴量に依存するのではなく、入力段に独自の「特徴量非依存レイヤー」を設け、画像のどこにエッジやテクスチャの境界があるかといったパターンを抽出するアプローチをとっています。これにより、未知の次元数や表現空間を持つ特徴量であっても、一度学習するだけで任意の解像度へ柔軟に拡張できるようになりました。 推しポイント 個人的に一番の推しなのは、「画像の解像度を復元(アップサンプリング)するには、わざわざ画像全体の特徴を計算しなくても、局所的(Local)な特徴を見るだけで十分ではないか」というアプローチです。 従来の手法は画像全体のクロスアテンションを計算しがちでしたが、AnyUpは局所的な構造変化さえ捉えられればよいと割り切り、ローカルなウィンドウアテンションを採用しています。さらに、複数の異なるモデル(DINOv2とSigLIPなど)でマルチバックボーン学習させることで、未知のモデルに対するゼロショット汎化性能を底上げしており、この直感的な設計と普遍性の組み合わせが見事です 。 課題 ただし、ウィンドウアテンションの副作用として、オブジェクトの境界分離能力(空間的識別性)が甘く、特徴量マップ全体が滑らかに一様化しやすい傾向があったり、アテンション計算の性質上、解像度が大きくなると計算コストとメモリ消費が二次関数的に爆発してしまうという構造的な弱点も抱えています。 このような課題が解決されていないので、計算の線形化を目指す「UPLiFT」や、学習効率と高倍率へのスケーリングに特化した「DiveUp」という論文が続々と登場しています。 感想 とはいえ、テーマ自体が「普遍的アップサンプリング」として面白いので後続の論文がたくさん出ている点と、この論文自体シンプルなアプローチで読みやすい点を考慮して推し論文としました! 後続の論文も読みやすいので合わせて読んでみてください! Neon: Negative Extrapolation From Self-Training Improves Image Generation セッション: Oral Session 1B Generative models I 著者: Sina Alemohammad, Zhangyang Wang, Richard Baraniuk 論文リンク:https://openreview.net/pdf?id=kpLRYtPGt3 紹介者: 中村 伊吹 論文中Figure 1から引用 推しポイント 生成AIの性能向上には大量のデータが必要ですが、高品質な実データは今後ますます貴重になります。そこで期待されるのが、モデル自身が生成した「合成データ」を使った自己学習です。ただし、合成データだけでFine-Tuningすると、品質や多様性が急速に崩れる「モデル崩壊」が起きやすい、という難しさがあります。 論文では、合成データによる崩壊の原因を、モデルがもともと出しやすい画像をさらに出しやすくしてしまう mode seeking にあると説明しています。つまり、自己生成データにはどうしても偏りがあり、その偏りでさらに学習すると、よく出るパターンばかりが強化され、生成の多様性が失われていく、という見方です。 この論文の面白いところは、そのモデル崩壊を「避けるべき失敗」として扱うのではなく、あえて利用する発想にあります。合成データで少しだけ自己学習したときの更新方向を、「モデルが崩壊していく方向」だとみなし、その逆向きにモデルを動かすことで性能改善を狙います。タイトルの Negative Extrapolation という名前も、
こんにちは。AI・機械学習チームの田中(@yusuke14tanaka)です。 この記事はAI・機械学習チームブログリレーの13日目の記事です。12日目は鴨田さんによる「SAM3とマトリックス・コードで作る"cat matrix"」でした。 www.m3tech.blog 2026年1月にエムスリーに入社し、気がつけば3か月が経ちました。前職では、視覚障がい者向け歩行支援デバイス「あしらせ」を開発する株式会社Ashiraseで共同創業者兼取締役CTOを務めていました。 前職あしらせのTシャツを着た筆者 今回は、スタートアップのCTOから、エムスリーのAI・機械学習チームに転職した自分が、入社前に感じていた不安と、3か月経った今の正直な感想をお伝えしたいと思います。 同じような境遇で転職を迷っている方、特にCTO経験者の方に届けば嬉しいです。 前職でやっていたこと なぜエムスリーにしたのか 入社前に感じていた5つの不安 1. 歯車になるのでは? 2. 裁量がなくなるのでは? 3. 我流のスキルでついていけるか? 4. 畑違いの領域でやっていけるか? 5. 東証プライム上場企業は堅いのでは? 3か月経って、実際どうだったか 歯車感 → ほとんど感じていない 裁量 → 全く困っていない 我流スキル → 「わからない」への耐性が活きた 畑違い → 意外なところで繋がった プライム上場企業の堅さ → 想像よりずっと柔らかい Claude Codeという最強のキャッチアップ相棒 エムスリーの学びの文化 CTO経験が活きていること CTOはあくまで「役割」の一つ CTO経験者の方へ We are hiring! エンジニア採用ページはこちら カジュアル面談もお気軽にどうぞ インターンも常時募集しています 前職でやっていたこと 「あしらせ」は、靴に装着する振動デバイスとスマートフォンアプリを組み合わせた、視覚障がい者向けの歩行支援サービスです。共同創業者兼取締役CTOとして、組み込みFW(C / FreeRTOS)・iOSアプリ(Swift)・バックエンドシステム(Python / Flask)の開発を一貫してリードしていました。 あしらせデバイス(出典: ashirase.com) ゼロからプロダクトを立ち上げ、大手家電量販店をはじめとする代理店での販売まで漕ぎ着けることができました。CES 2023 Innovation Awardや、東京都ベンチャー技術大賞 優秀賞、J-Startup 2023 認定もいただいています。 技術的には組み込みFW開発がメインで、あしらせデバイスの姿勢推定アルゴリズムや、BLE(Bluetooth Low Energy)を使ったOTA(Over the Air)によるFWアップデートの仕組みなどをゼロから作っていました。カルマンフィルタや粒子フィルタを用いた歩行者デッドレコニング(推測航法)にも取り組んでおり、この制御工学の経験が、後述するエムスリーでの仕事に意外な形で繋がることになります。 なお、本記事の執筆や画像の掲載について、Ashirase代表に相談したところ快くOKをいただきました。 なぜエムスリーにしたのか 共同創業者兼取締役CTOとして5年半走り続ける中で、持病もあり働き方を見直す必要が出てきました。次のキャリアを考えたとき、エムスリーのAI・機械学習チームでは、ソフトウェア開発だけでなく、機械学習モデルの構築にも携われると聞いたのが決め手でした。 また、優秀なエンジニアが多い環境で、自分の技術力を伸ばしたかったというのもあります。1人目のエンジニアとしてゼロから開発を始め、我流で進めてきた部分がどうしても多かった。コーチのような存在もいない。メガベンチャーのエンジニアのレベルを肌で感じながら、自分の技術力をもっと高めていきたいと思っていました。 入社前に感じていた5つの不安 CTO経験者がメガベンチャーに転職するとき、特有の不安があります。自分の場合は、こんなことを考えていました。 1. 歯車になるのでは? スタートアップのCTOは、プロダクトの全体像を見渡しながら仕事をします。メガベンチャーに入ったら、大きな組織の一部品として、狭い領域だけを任されるのではないか。そんな不安がありました。 2. 裁量がなくなるのでは? 技術選定も設計判断も、自分で決めて動けるのがスタートアップの醍醐味です。メガベンチャーでは、承認フローや会議を経ないと何も進まないのではないか、と思っていました。 3. 我流のスキルでついていけるか? 正直に言うと、これが一番大きな不安でした。スタートアップでは体系的にスキルを学ぶ機会が少なく、常に我流で模索しながら開発していました。メガベンチャーの優秀なエンジニアの中でちゃんと成果を出せるのか、かなり不安でした。 4. 畑違いの領域でやっていけるか? 組み込み・モバイル畑からWeb・MLの世界へ。Python、Go、GCP、Kubernetes、BigQuery——技術スタックが根本的に違う領域への転身です。キャッチアップできるのか、戦力になれるのか、という不安がありました。 5. 東証プライム上場企業は堅いのでは? スタートアップはカジュアルな文化が一般的です。プライム上場企業に入って、堅い雰囲気に馴染めるのだろうか、という漠然とした不安もありました。 3か月経って、実際どうだったか 歯車感 → ほとんど感じていない AI・機械学習チームでは、プロジェクトをほぼ丸ごと任される文化があります。自分でプロジェクトの全体像を把握しながら動けるので、歯車感はほとんど感じていません。 むしろ、チームを越えた動きもしやすい環境です。BigQueryにどういったデータがあるかが探しにくい状態だったので、Claude Codeのプラグインや独自ツールを活用して、全社的にBigQueryのデータを検索しやすくする仕組みを他チームに提案しに行ったりもしました。こうした動きがしやすい関係性があるのは、とてもありがたいです。 裁量 → 全く困っていない 裁量がなくて困った、という経験は3か月間で一度もありません。現場での意思決定が尊重される文化があり、メンバーであっても自分の判断で動ける幅が広いと感じています。 我流スキル → 「わからない」への耐性が活きた 最初はかなり苦労しました。打ち合わせ中に何を言っているのか理解できないことも正直多かったです。BigQueryも、GCPも、Goも、触ったことがない。組み込み系ではWindowsがメインだったので、MacがメインPCになったこと自体が初めてで、そもそもパソコンの使い方みたいなところからつまずいたりもしていました。新人時代に戻ったような感覚でした。 ただ、スタートアップで5年半やってきたおかげで、「わからない」ことに対する耐性はかなりついていました。CTOをやっていたら、知らないことに出会うのなんて日常茶飯事です。そこでへこたれている暇はなかったし、その感覚が今も活きています。 畑違い → 意外なところで繋がった これが一番伝えたい話です。 現在、コンテンツレコメンドの最適化を担当しているのですが、既存のコンテンツ表示の抑制ロジックがステップ関数のような離散的な制御になっていました。ここを連続的な制御に変える改善を行い、全ユーザーに展開できました。 具体的には、コンテンツごとの興味持続時間を考慮するモデルへと改善し、医師の皆様により"今の興味"に近い情報を届けられるようになりました。入社3か月で手応えのある成果を出せたのは、自分にとっても大きな自信になりました。 この改善のアイデアは、あしらせ時代にカルマンフィルタや制御モデルを扱っていた経験から、ごく自然に出てきたものです。離散的な制御は現実に即さないことが多く、制御工学的には避けられる手法です。その感覚があったからこそ、改善の方向性がすぐに見えました。 また、banditアルゴリズムの理解にも、前職の知識が役立ちました。banditの内部でもベイズ更新が使われていますが、カルマンフィルタで散々ベイズ更新と格闘していたおかげで、内部状態が逐次的に更新されていく感覚がすんなり理解できました。「基礎からわかる時系列分析」という書籍も併せて読み、制御工学と機械学習の接点をより深く理解できました。 畑違いの経験は、無駄にならない。 むしろ、異なる領域の知識があるからこそ出せる価値がある。これは3か月で得た一番大きな実感です。 プライム上場企業の堅さ → 想像よりずっと柔らかい これは一番ギャップが大きかったかもしれません。想像していたよりもずっと柔らかい。エンジニアリングチームは良い意味で柔らかく、コミュニケーションも取りやすいです。 特にエンジニア気質というか、ちょっとコミュニケーションが難しい人——いわゆる「聞きづらい人」が全くいない。これは本当に驚きました。チーム内はもちろん、チーム間でもとても協力的で、質問もしやすく、キャッチアップもしやすい。 Claude Codeという最強のキャッチアップ相棒 キャッチアップの話をもう少し掘り下げます。 エムスリーではClaude Codeが使い放題です。これが、畑違いの領域からのキャッチアップに本当に助かりました。 具体的には次のような使い方をしていました。 BigQueryのクエリを書くときに聞く Go言語の書き方を教えてもらう 論文を読むときに要約・解説させる M3内で開発・管理しているOSSパッケージgokartの使い方や実装を聞く さらに、AI・機械学習チームのメンバーが作成したClaude Codeのスキルやナレッジが蓄積されており、チームの暗黙知にもアクセスしやすい環境が整っていました。 さらに、次のテックブログ記事にもあるように、 www.m3tech.blog エムスリーではほぼ全員のエンジニアがClaude Codeを日常的に使っており、AIレビューやスキルの共有がチーム横断で進んでいます。こういったナマの知識が社内に蓄積されていて、それを吸収できるのも大きいです。 おかげさまで、すっかりClaude Codeのヘビーユーザーです。CTOをやっていた頃は、わからないことがあっても自分で調べるしかなかった。今は、Claudeに聞けるし、チームメンバーにも聞ける。この差は本当に大きいです。 エムスリーの学びの文化 もう一つ、入社して驚いたのが学びの文化です。 Googleのデータベースに関する輪読会 論文輪読会 技術書の輪読会 自分の技術を発表するテックトーク これらが毎週のように開催されています。しかも形骸化しておらず、ちゃんと身になっている。 自分の場合、Googleのデータベース輪読会に参加したとき、最初は正直何を言っているのか全然わからなかった。ですが、自分で復習し、2か月後には自分でも発表しました。まだ完全に理解できているとは言えませんが、BigQueryやデータベースに対する感覚値をつかむことができたのは、この輪読会のおかげです。 こういった場で否定する人が一切いないのも特徴です。本当に心地よく発表を聞けるし、発表することができる。スタートアップでは、こうした組織的な学びの場を作る余裕がなかったので、これはエムスリーならではの価値だと思います。 CTO経験が活きていること CTOをやっていた頃は、とにかく会社の成長が最も大切だと考えていましたし、そのために必要な仕事をレバレッジが効く順に実施していました。最もやばいところに常に自分が入り込む。 この考え方は、メガベンチャーであっても変わりません。 自分にとって都合が良いことではなく、会社全体にとってベストなことを選ぶ。 この判断軸はCTOをやる中で身についたものですし、エムスリーの「しゃ(社長意識)」とも重なる部分が大きいです。 CTO経験者であれば、この社風は自然にフィットするのではないかと思います。 CTOはあくまで「役割」の一つ 転職を考えたとき、「CTOからメンバーに戻ることに抵抗はないのか」と聞かれることがあります。 正直に言うと、全くありません。 CTOはあくまで役割の一つでしかない。プライドとかそういう話ではなくて、その役割が必要な場面で、自分がその役割を担う。それだけのことです。エムスリーではグループ会社でCTOを務める道もありますし、役職に固執する必要は全くないと思っています。 むしろ、CTO経験があるからこそメンバーとしても強い。全体を俯瞰する力、ステークホルダー全体の最適化を考える癖、未知の領域に飛び込むキャッチアップ力。これらは役職に関係なく活きるスキルです。 CTO経験者の方へ 最後に、スタートアップでCTOをやっていて、メガベンチャーへの転職を迷っている方へ。 エムスリーは、CTO経験者にとって良い環境だと思います。理由を3つ挙げます。 ビジネスを重要視するカルチャー。会社全体のメリット・デメリットを考えて動いてきた経営者やCTOからすると、すごく馴染みやすい環境です。 技術力が高く、学び続ける文化がある。テックトークや論文輪読会が当たり前にある。技術に対して熱心な人が多く、自分もまだまだ成長できると感じられる環境です。 現場の決定権が大きい。CTOの裁量からメンバーになっても、裁量がなくなったとは感じていません。自分の判断で動ける幅が広いです。 不安に感じている方がいれば、それは杞憂だとお伝
AI・機械学習チームの鴨田です。この記事はAI・機械学習チームブログリレーの12日目の記事です。11日目は池嶋さんによる「Agentic MLOpsで加速する機械学習開発」でした。 娘の影響でYoutubeで「シナぷしゅ」を見ることが多くなったのですが、毎月更新される月歌(その月のテーマソング)とそれと共に投稿されるパパ・ママ向け解説動画が楽しみになりました。プロデューサーが直接こだわりを解説していて内容が濃くおすすめです。 nanobananaに「マトリックス・コードで猫の黒いシルエットが表現されている画像」で作成した画像 記事要約 Facebook/Meta AIの画像セグメンテーションモデル「SAM3」を使って猫の画像からMaskを抽出 抽出したMaskをマトリックス・コードのアニメーションと組み合わせて動く猫のシルエットを表現 記事要約 きっかけ SAM3とは SAM3の主な特徴 実装:SAM3でMaskを抽出 環境セットアップ 静止画からのMask抽出 動画からのMask抽出 MaskをASCII artに変換 実装:マトリックス・コードと組み合わせ OSSの選定と改修 実施結果 コード 余談:Google Colabのメモリ不足 まとめ We are hiring! エンジニア採用ページはこちら カジュアル面談もお気軽にどうぞ インターンも常時募集しています きっかけ YouTube*1を見ていたら、マトリックス・コードで猫のシルエットが表現されているTシャツを着ている人を発見しました。 「これ、手元で実現できないかな?」と考えていたところ、ちょうど以前申請していたFacebook/Meta AIのSAM3(Segment Anything Model 3)のモデル利用許可メールが届きました。 そこで、次のアプローチで実現しました。 SAM3を使って猫の画像から猫のMaskを抽出 マトリックス・コード生成ツールを改修してMask領域を描画しないようにする 猫のシルエットが浮かび上がるマトリックス・コードアニメーションを完成させる SAM3とは SAM3(Segment Anything Model 3)は、Meta AI Researchが2025年にリリースした最新の画像・動画セグメンテーションモデルです。主な特徴は次の通りです。 SAM3の主な特徴 1. Promptable Concept Segmentation SAM3の最大の特徴は、テキストプロンプトによるセグメンテーションです。従来のSAMでは点やボックスを指定する必要がありましたが、SAM3では「cat」のようなテキストを与えるだけで、画像内の該当するオブジェクトを自動でセグメンテーションします。 「cat」と指示すると、猫の範囲全体をMaskします。「ear」と指示すると生き物の耳をちゃんと認識して、インスタンスごとにMaskが生成されます。 左:プロンプトで「cat」と指示した結果。右:プロンプトで「ear」と指示した結果。 2. 画像と動画の両対応 SAM3は静止画だけでなく、動画のセグメンテーションにも対応しています。動画内のオブジェクトを追跡しながらフレームごとにMaskを生成できるため、今回のような動的なアニメーション作成にも活用できます。 3. ゼロショット学習 事前学習済みモデルを使うだけで、特定のドメインに対するファインチューニングなしで高精度なセグメンテーションができます。 詳細はHugging Faceのモデルページを参照してください。 huggingface.co 実装:SAM3でMaskを抽出 環境セットアップ まず、必要なライブラリをインストールします。 !pip install -U transformers !pip install -U av SAM3は利用申請が必要なモデル(gated model)のため、Hugging Faceでモデルページにアクセスしてライセンスに同意する必要があります。その後、トークンを使ってログインします。 from huggingface_hub import login login(token="YOUR_HF_TOKEN") 静止画からのMask抽出 次のコードで猫のMaskを抽出します。プロンプトには「cat」を使用します。 from transformers import Sam3Processor, Sam3Model import torch from PIL import Image device = "cuda" if torch.cuda.is_available() else "cpu" # モデルとプロセッサの読み込み model = Sam3Model.from_pretrained("facebook/sam3").to(device) processor = Sam3Processor.from_pretrained("facebook/sam3") # 画像の読み込み image = Image.open("cat_image.jpg").convert("RGB") # テキストプロンプトでセグメンテーション inputs = processor(images=image, text="cat", return_tensors="pt").to(device) with torch.no_grad(): outputs = model(**inputs) # 後処理 results = processor.post_process_instance_segmentation( outputs, threshold=0.5, mask_threshold=0.5, target_sizes=inputs.get("original_sizes").tolist() )[0] print(f"Found {len(results['masks'])} objects") 動画からのMask抽出 動画の場合は、SAM3VideoModelを使用します。 from transformers import Sam3VideoModel, Sam3VideoProcessor from transformers.video_utils import load_video model = Sam3VideoModel.from_pretrained("facebook/sam3").to(device, dtype=torch.bfloat16) processor = Sam3VideoProcessor.from_pretrained("facebook/sam3") # 動画の読み込み video_frames, _ = load_video("cat_video.mp4") # セッションの初期化 inference_session = processor.init_video_session( video=video_frames, inference_device=device, processing_device="cpu", video_storage_device="cpu", dtype=torch.bfloat16, ) # テキストプロンプトの追加 inference_session = processor.add_text_prompt( inference_session=inference_session, text="cat", ) # 全フレームを処理 outputs_per_frame = {} for model_outputs in model.propagate_in_video_iterator( inference_session=inference_session, max_frame_num_to_track=130 ): processed_outputs = processor.postprocess_outputs(inference_session, model_outputs) outputs_per_frame[model_outputs.frame_idx] = processed_outputs これで、各フレームごとに猫のMaskが取得できます。 MaskをASCII artに変換 抽出したMaskをマトリックス・コード生成ツールで使えるよう、ASCII artに変換します。 import numpy as np from PIL import Image def generate_mask_ascii_art(masks, scale_factor=0.5, fill_char="#", bg_char=" "): """ Mask領域をASCII artとして出力 """ if hasattr(masks, 'cpu'): masks = masks.cpu().numpy() # 複数Maskを結合 if masks.ndim == 3: combined_mask = np.any(masks > 0, axis=0).astype(np.uint8) * 255 else: combined_mask = (masks > 0).astype(np.uint8) * 255 # リサイズ mask_img = Image.fromarray(combined_mask) orig_w, orig_h = mask_img.size aspect_correction = 0.5 <s
こんにちは、AI・機械学習チームの池嶋大樹です。 LLMエージェントがモデルの性能グラフを見ながら、YAMLの設定を自律的にチューニングしていく――そんなAgentic MLOpsを私たちのチームでは実践しています。 私たちのチームでは6年前から、YAMLで機械学習モデルの設定を管理し、設定を差し替えるだけで実験を回せるconfig-drivenな機械学習を実践してきました。 もともと実験管理やコードと設定の分離といったメリットがありましたが、LLMエージェントがYAMLの設定を自律的にチューニングできるようになったことで、開発がさらに加速しています。 本記事では機械学習におけるconfig-drivenのメリットと、Agentic MLOpsによってさらに生産性が向上した話を紹介します。 YAMLによるconfig-driven機械学習とは YAMLによるconfig-driven機械学習のメリット コードと設定の分離 実験管理で有利 LLMを使ったAgentic MLOpsへ まとめ We are hiring! YAMLによるconfig-driven機械学習とは m3.comでは、あるテーマに興味が高いユーザーに絞ってコンテンツを届けたい、という施策が頻繁に発生します。 例えば、ある疾患に興味がありそうなユーザーにだけ特集ページを案内する、といったケースです。 私たちのチームでは、こうした「XXXに興味が高いユーザー」をピックアップするための機械学習モデルを開発・運用しています。 対象となるテーマはさまざまな疾患や薬剤から、生活に関する情報まで多岐にわたり、テーマごとに教師データや最適化ロジックが異なります。 モデルもGBDTやNNなど複数を組み合わせたアンサンブルで構成されているため、テーマごとの設定に加え、モデルごとのハイパーパラメータや特徴量も必要になり、全体の設定項目はかなり多くなります。 そこで、これらの設定をすべてYAMLファイルに切り出し、コードを変えずに設定ファイルだけ差し替えて実験を回せるよう、config-driven機械学習を実践してきました。 例えば、次のようなYAMLファイルでモデルの構成を記述します。 # モデル設定YAMLの超抜粋(設定項目が多いと、実際には500行以上になることもある) project_config: project_name: recommend_toppage_A train_data_path: gs://bucket/train_data.csv loading_model_names: - model_a_pv_and_meta_nn - model_a_pv_and_meta_optuna_lgb - ... ensemble_config: - ensemble_name: ens_group_1 group_name: group_1 minimum_allowed_model_auc: 0.75 ensemble_max_model_counts: 15 auto_model_selection: true actual_label_columns: - actual_label_1 - ensemble_name: ens_group_2 group_name: group_2 minimum_allowed_model_auc: 0.77 ensemble_max_model_counts: 15 auto_model_selection: true actual_label_columns: - actual_label_1 segmentation_config: - group_name: group_1 single_segment_config: - ensemble_name: ens_group_1 should_extract_higher: true score_threshold: 0.3 assigned_segment: 1 - ensemble_name: ens_group_1 should_extract_higher: false score_threshold: 0.3 assigned_segment: 0 このYAMLファイルでは、project_configでプロジェクト名や学習データのパス、読み込むモデルの一覧を定義し、ensemble_configでグループごとのアンサンブル条件(どの教師ラベルで最適化するか、アンサンブルに使うモデルの最低AUC、最大モデル数など)を指定しています。 segmentation_configでは、アンサンブルモデルの予測スコアをもとにユーザーをセグメントに分割するルールを定義しています。 最終的にユーザーを「興味が高い/低い」といったセグメントに分け、興味が高いユーザーにだけ施策を配信します。 このYAMLを入力として、モデルの学習・推論・アンサンブル・セグメンテーションまでを自動実行するPythonのパイプラインスクリプトを整えているため、プロジェクトのたびにコードを触る必要はなく、YAMLを編集するだけで別プロジェクト用のモデル作成が可能になっています。 YAMLによるconfig-driven機械学習のメリット コードと設定の分離 設定をYAMLに切り出しているため、ハイパーパラメータや特徴量を変えたいときにコードを触る必要がありません。 同じコードベースのまま、YAMLを差し替えるだけで複数のプロジェクトや実験構成を管理できるようになりました。 レビューの負担も軽くなります。 コード側はテスト済みの安全なものをそのまま使うため、レビューでは設定ファイルの内容が適切かどうかだけを確認すれば済みます。 実験管理で有利 実験条件がYAMLファイルとしてそのまま残るため、再現性が高く保てます。 「あの施策/実験の設定なんだっけ?」と振り返りたいときも、YAMLを見るだけで分かります。 YAMLをGitで管理すれば、「前回の実験から何を変えたか」が差分で一目瞭然です。 実験ごとにYAMLファイルを残しておけば、それ自体が実験ログとして機能します。 LLMを使ったAgentic MLOpsへ ここまでのメリットは以前からあったものですが、課題もありました。 実際のYAMLは学習・モデルアンサンブル・ユーザーセグメンテーションのハイパーパラメータを細かく設定しています。 さらに、ユーザーを属性ごとに分けたグループごとにこれらを設定するため、完成版のYAMLは数百行に及びます。 グループごとに設定を分けることで推計結果の偏りを防げていましたが、設定項目が多い分、新しいメンバーにとっては慣れるまでに時間がかかる面もありました。 LLMエージェントがYAMLの設定を自律的に編集・チューニングできるようになり、この課題が大きく解消されました。 「モデルにAUCの閾値をXXXに上げて」「新しいグループを追加して」と自然言語で指示するだけで、LLMがYAMLの該当箇所を正しい書き方で修正してくれます。 設定YAMLの書き方ドキュメントを完全には理解しなくても、LLMが設定の構造を解釈した上で生成・修正してくれるため、慣れていないメンバーの学習コストが大幅に下がりました。 さらに、Claude CodeのSkillsを活用して、チューニング作業自体の自動化にも取り組んでいます。 例えば、ユーザーセグメンテーションのパラメータチューニング手順を次のようにSkillとして定義しています。 # セグメンテーション閾値チューニング スキル ## 核心原則: inference推論分布とprecisionのバランス チューニングでは以下の2つを同時に満たすことを目指す: 1. inferenceの各セグメント人数比率が、教師データの人数比率に近いこと 2. 各セグメントのprecision(positive rate)が良好であること ## Step 1: ベースライン実行 `segmentation_config` で全員を同一セグメントに割り当てて実行し、モデル性能を確認する。 ## Step 2: グラフからの閾値決定 `grouped_performance_rank_1.png` のビン境界値をもとに閾値を決定する。 ## Step 3: YAMLの編集と再実行 閾値を高い順に設定する。セグメント数は3〜4が現実的。 ## Step 4: 評価と反復 inference推論分布とprecisionの両方を確認し、必要に応じて閾値を調整する。 ... 実際のSkillはより詳細ですが、LLMがこのSkillに従い、YAMLの閾値を編集 → パイプラインを実行 → 結果を評価 → 再調整、というサイクルを自動で回してくれます。 LLMが実際にモデルの性能グラフを見て、precisionやセグメント割合を分析しながら閾値を調整していく様子は、見ていても面白いものです。 LLMの操作対象がYAMLに限定されており、モデル実行はテスト済みの既存Pythonスクリプトなので、安心して任せられます。 現状では局所解にハマることもあり、教師データの作り方を変えるといった判断にはまだ人間が必要です。 しかし、チューニングのサイクルをLLMが高速で回してくれるおかげで、最適な閾値を見つけるまでの効率は大幅に向上しました。 まとめ YAMLによるconfig-driven機械学習は、コードと設定の分離や実験管理といった従来のメリットがあります。 そしてAgentic MLOpsの時代になり、自然言語での設定編集やSkillsによる自動チューニングなど、YAMLの扱いやすさがさらに活きるようになりました。 設定ファイルの複雑さという課題も、LLMエージェントが正しい書き方で生成・修正してくれることで解消されつつあります。 config-drivenで設計しておくと、エージェントの操作対象をYAMLに限定できるため安全に自動化しやすい、というのも大きな学びでした。 機械学習の設定管理にお悩みの方は、config-driven機械学習 × Agentic MLOpsをぜひ試してみてはいかがでしょうか。 We are hiring! エムスリーでは、AI・機械学習を活用したプロダクト開発を一緒に進めてくれるエンジニアを募集しています。 興味のある方は、ぜひ次のリンクからご応募ください。 jobs.m3.com