0-8

12年お世話になった BrainPad から Ubie へ行きます

11月30日をもって新卒入社から約12年勤めた BrainPad を辞め、新たに Ubie で働き始めることとしました!12年も勤めた会社を辞めるのはやっぱり個人的には大きな決断だったので、後で思い出せるよう、転職にあたって考えたことをつらつら書いておこうと思います。

Ubieの入社ブログは他の方々がたくさん書いていて、Ubieがどんな会社で、皆どんなところに惹かれたのかがわかるので面白いです。ただ、やっぱり僕は新卒から12年も働かせてもらった BrainPad にも思い入れがあって、 BrainPad のことも含めて書いておきたいので、なんとなく正式に転職する前の今1、この記事を書いています。疲れてやめたとかではなく、僕にとっては BrainPad も Ubie もどちらも良い会社で、とはいえ、いろいろ考えた末に Ubie を選んだ、というお話です。

医療版Googleを目指す

Ubie への転職のきっかけは今年の7月、代表の阿部さんと話す機会をいただいたことです。現役の医師ということもあって、阿部さんの話は具体的で、熱意に溢れていました。「医療版Googleを目指す」という話を聞いて、僕は厨二病だなぁと思ったと同時に一緒に働くならこういう人と働きたいと思ったのを覚えています。

ちなみにそのとき聞いた話は、人を適切な医療に導くことがいかに重要かという話で、この話はその後 Note でも書かれています。

note.com

僕はもともと薬があまり好きではなく、40度近くの熱が出ても「水を2L以上飲んで寝とけば治るっしょ」と思ってる人間だったので、病院に行く機会もほとんどないし、医療とはほとんど縁がなかったのですが、数年前に結婚して子供ができてからは病院に通う回数も増え、医療にも関心を持つようになりました。

まだ0歳だった息子を抱いていた時に、手を滑らせて落としてしまったことがあります。泣き喚く息子に、僕は何をどうしたら良いかわからず慌ててましたが、妻に言われて医療相談サービスに電話してみると、簡単なヒアリングの上で救急車の可否も教えてくれて、本当に感謝しかなかったです。形は少し違うけれど、 Ubie が今提供しているのは、まさにそういったサービスだと思います。

ちなみに最近 Twitter の広告で 「19番目のカルテ 徳重晃の問診 - 富士屋カツヒト/川下剛史 | ゼノン編集部 (comic-zenon.com)」という漫画を知りました。専門医ではなく総合診療医をテーマとした漫画で、「問診をして適切な専門医に患者を送り届ける」ことでいろんな患者さんを救ってくれます。

f:id:ohtaman:20211130171640p:plain
「19番目のカルテ 徳重晃の問診 第1話 なんでも治せるお医者さん 」より

まさにこういったことができるといいなと思っています。漫画なので、出てくる医師がありえないくらいスーパーだったりして、そのままその通りとはいきませんが、総合診療医にいつでも相談できるとしたらどれだけ心強いだろうか、それに近いサービスが提供できたら、と思うわけです。そんな感じで Ubie のミッションへの共感が、転職のきっかけとなりました。

データ活用の浸透を目指す BrainPad と Ubie

もちろん僕は Ubie のミッションだけではなくて、 BrainPad のミッション2にも共感しています。だからこそ 12年間も在籍しました。BrainPad を受けた当時、データ活用を主軸にしている会社はほとんどなかったし、データ分析なんて言葉が話題になることもありませんでした。そんな中、データ活用をミッションに据えて上場準備をしている小さい会社が BrainPad で、一次面接だと油断していたら代表の草野が登場し、目を輝かせながらデータ活用の重要性を語っていたのを今でも覚えています。

当時データ活用はとてもニッチな分野だったけれど、その後のビッグデータブームやAIブームのおかげで、データの重要性は広く認知され、データ活用はニッチな分野ではなくなりました。BrainPad は今でも(そしておそらく今後も)あまり業界を絞らずに活動していますが、業界を絞ってより狭い領域を狙う企業やサービスもたくさん生まれました。その一例として医療業界を考えると、データ活用を推し進めたその先に Ubie の目指す未来があるように僕には思えました。Ubie に移ったとしても、自分の目指す方向は BrainPad と同じです。

少し余談ですが、その生い立ちだけではなく、BrainPad は数年先を見通す力がすごいな、と思うことが何度かありました。最近だと例えば2016年頃。当時、深層学習がブームとなってAIベンチャーがいくつも生まれ、機械学習エンジニアやデータサイエンティストの争奪戦となっていました(今もですが)。その頃 BrainPad は、実はコンサルの出身者も積極的に採用していました。機械学習そのものを提供するのではなく、それをビジネスで活用してもらうには、分析結果から様々なアクションを起こせる必要があります。それにはクライアント先に入り込むことが必要があるという話で、結果として今の DX を推進する体制につながっています。

www.brainpad.co.jp

お互いに考え方が結構違うので初めの頃は大変そうでしたが、最近は良いバランスがとれるようになってきているようです。今考えてみると、数年先が見えていたからこその戦略だったように思いますが、当時僕は「気持ちはわかるけど、BrainPad がコンサルぽくなるのやだなぁ」くらいに思っていました。ごめんなさい。

人材の大切さ

さて、僕がUbie に惹かれたもう1つの理由が人材の濃さでした。スキル面も魅力的ですが、個人的にはみんながみんな高い視座を持っていて、同じ方向に向かって好き勝手やっている感じにとても惹かれました。なかなかこんなメンバーを集められない、というか、採用をこだわり抜いたらこうなるのか、と。

Ubie は明確に人に投資しています。スタートアップなので、今後想定し得ないことが起こったりもすると思います。BrainPadも紆余曲折ありました。ただ、そう言った局面でこそ、きちんと人に投資していることが強さにつながるだろうと考えています。

一部上場企業の CxO をやめて一人の機械学習エンジニアに

BrainPad では CDTO (最高データ技術責任者)という役職で自分の思う通りに働かせてもらっていたのですが、なんとなく地に足がついていない感じがしていました。現場に入る時間が減ったことや依頼される講演内容の変化など、色々あると思いますが、とにかく少し違和感がありました。また、すこしコンフォートゾーンに浸りすぎているという感触もありました。

そんなことを考えていた時に、Ubieの人たちと話す機会があり、一歩踏み出して、この異色な環境に飛び込んでみようと思いました。Ubieでは、一人の機械学習エンジニアとして手を動かしますが、ホラクラシーという組織のため、自分の役割を自分で決められるというのも魅力的でした。

Ubie はスタートアップなので、当然失敗するリスクはかなりあります。ただ、もし失敗して BrainPad に出戻ったとしても、今のまま BrainPad に居続けるよりも、高い価値を提供できる自分になっているに違いないと考えました。なんとなくのイメージしたのは、目の前に精神と時の部屋があったらどうしますか、という話で、それは飛び込まない理由はないだろうと。

f:id:ohtaman:20211201020850p:plain
精神と時の部屋

そんなことを考えていたので、BrainPadの人たちが、戻ってきてね、と言ってくれた時はとても嬉しかったです。

最後に

本当はもっと色々考えることがあったのですが、色々な観点で比較して、一歩踏み出すことにしました。 僕は初めて転職を経験しましたが、やはり中の人と話して中のことを知るのは大事だなと感じました。なので、Ubie に興味のある方は一度カジュアル面談で中の人と話してみるのが個人的にはおすすめです。どの会社も綺麗な話だけではないですから。

以下のリンクから進むと、Ubie の中の人との面談を設定できます。

meety.net

もちろん直接面接に申し込んでいただくのもOKです。

ubie.life

BrainPad に興味のある方は、社員の知り合いがいたら声をかけると良いです。いない場合は、人事のカジュアル面談にいくとよしなにしてくれると思います。ちなみに BrainPad は社長の草野と話せる機会を定期的に提供しているので、興味のある方は人事に聞いてみてください。

hrmos.co

最後に、転職には興味ないけど、(企業色の一切ない)僕個人と雑談してもいいという奇特な方がもしいたら、雑談しましょう!技術的な話でもコミュニティ運営の話でも、子育ての話でも、なんでもOKです。以下のリンクから

meety.net

ではでは。


  1. そう思って11/30に書き始めたのに、結局12/1になりました。

  2. 「データ活用の促進を通じて持続可能な未来をつくる」

「問題解決力を鍛える! アルゴリズムとデータ構造」を読んだ

問題解決力を鍛える! アルゴリズムとデータ構造」を読んだので、そのメモです。章末問題は気になった問題しかやっていないので、時間を見つけてもう一度取り組みたい。

www.amazon.co.jp

全体を通して感じたこと

本書を一言でいうと「丁寧」に尽きると思う。どこまで丁寧なんだ、というくらい丁寧。

まず解説が丁寧で用語もきちんと、できるだけ噛み砕いて説明してあります。図もたくさんあって、イメージをつけながら理解できます。その上コードもしっかり乗っていて、解説でわからなかったところは読んで理解できる。

解説が丁寧で他書やネットに頼らなくても読み進められるので、途中で思考が中断されないのがよかった。自分の場合は、子供を寝かしつけた後、深夜まで集中して一気に読み進められた。個人的には理論的な話と実装が別れているほうが好きなんだけど、わからないときにさっと実装を眺められるのは確かに嬉しいなと思った。

個人的に面白かった箇所

競技プログラミング向けの書籍はきちんと読んだことがなかったので、知らないことも多かった。ネットで拾った断片的な情報はいろいろ知っていたけど、この本を読んで断片的な知識がいろいろつながったのはとても良かった。

以下は面白いなと思ったところ

  1. 判定問題と最適化問題
    二分探索の応用例として、最適化問題を判定問題に帰着させて解く方法が紹介されていた。読んでみれば、たしかにそうだよね、という内容だけど、いままで気づかなかったので面白かった。

  2. Union Find
    あまり知らなかったんですが、有名なのかも。Union Find はグループ分けを効率的に管理するデータ構造のこと。

    • issame(x, y): x と y が同じグループに所属するかどうかを返す
    • unite(x, y): x と y を含むグループを併合する

    という演算が高速にできるのがポイント。最小全域木を求めるクラスカル法の効率的な実装などに利用できる。

  3. トポロジカルソート
    与えられた有向グラフに対し、各頂点を辺の向きに沿うように順序つけて並び替えることで、makeとかでうまいこと依存関係を解決するの使われている。実は深さ優先探索における再帰関数の抜けた順がそのままソート順になっているんだというのが面白いなと思った。

  4. フォード・ファルカーソン法と残余グラフ
    特に理屈があるわけではないんだけど、16章のネットワークフローの話は、やっぱり面白い。小学校のときに電気回路の話を水の流れで説明されたときに面白い、と思ったのを引きずっているだけかもしれない。

まとめ

やっぱり競技プログラミング楽しそう(参画するとはいっていない)。10年前に買ってちゃんと読んでいなかった蟻本、もう一回開いてみよう。

Model Building in Mathematical Programming: 9.5 Special kinds of integer programming

Optimization NightH. Paul Williams, Model Building in Mathematical Programming, 5th Edition, Wiley, 2013. の輪読会をしているので、そのメモです。

Chapter 9 Building Integer programming model I

9.5 Special kinds of integer programming models

ここでは、MIPとしてよく知られている問題と定式化方法を紹介している

  1. 集合被覆問題: Set covering problems
    • 部分集合の組が与えらえられたときに、最小の数ですべての要素をカバーしなさい、という問題
    • 各部分集合を使うか否かを表す変数 $\delta _ i $ を使って、各要素がいずれかに含まれていなさい、という制約を課す
    • 応用例には航空スタッフのスケジューリングなど
    • 基本的にときやすい問題で、難易度はその構造ではなく問題サイズに依存する
  2. 集合パッキング問題: Set packing problems
    • 部分集合の組が与えられたときに、要素の重複を許さず、どれだけ多くの部分集合を詰め込めるか、という問題
    • 各部分集合を使うか否かを表す変数 $\delta _ i $ を使って、各要素の重複を許さない、という制約を課す
    • 線形緩和問題の双対がちょうど集合被覆の緩和問題になる
    • 応用例にはマッチング問題など
  3. 集合分割問題
    • 部分集合の組が与えられたときに、要素の重複を許さず、すべての部分集合をカバーする、という問題
    • 応用例としては、一票の重みの差を最小にして選挙区の設定など
    • slack変数を使って表現した集合パッキングと同じ
  4. ナップサック問題
    • ナップサックにどれだけ多く荷物を積み込めるか
    • 応用例にはプロジェクト選択問題などもあるが、別の問題の部分問題(列生成法の子問題?)として現れることが多い
  5. 巡回セールスマン問題
    • すべての都市を1回ずつ巡回するときに最短経路を求める問題
    • 都市 $i$ から都市 $j$ へ(直接)進むかどうかを表す変数 $\delta _ {ij} $ を使って表現する
    • 部分巡回路の除去が重要
      • シンプルなのは、一度部分巡回路制約なしで解いてしまって、最適解に部分巡回路が含まれていたら、その部分巡回路を明示的に除去する制約を追加する(これを繰り返す)方法。他にもいろいろある
  6. 配送計画問題
    • 巡回セールスマン問題の拡張。容量制約のある車両が複数台で顧客を回る
    • 定式化できるが、現実的なサイズの問題は難しい。列生成法を使う方法もある
  7. 2次割当問題
    • 2つの集合 $S$ と $T$ が与えられたときに、 $S$ の要素と $T$ の要素を1対1対応させながらコストを最小化する問題で、コストは組合せで決まる($i$ と$j$ が対応して、かつ $k$ と $l$ が対応した場合にコスト $C_{ijkl}$ かかる)ような問題
    • 例えば2点間の距離を最小化するような問題は、2次割当問題として定式化できるし、巡回セールスマン問題もこの形で定式化できる
    • 目的関数が2次なので、一次式に変換してから解く必要がある

MathJax を導入した

今まで数式ははてな記法 [tex: hogehoge] で書いてきたが、VSCodeとかでプレビューできないし、結構ストレスがたまっていた。そこで MathJax を導入した。といっても、管理画面から script タグを追加するだけ*1

これで以下の様に $ を使って記述できるようになった。

コード 表示
$\frac{1}{2}$ $\frac{1}{2}$
$$\frac{1}{2}$$ $$\frac{1}{2}$$
$x\_{i} + x\_{j}$ $x_{i} + x_{j}$

align環境も使える。

$$
\begin{align}
a & = b, \\\\
b & = c.
\end{align}
$$

$$ \begin{align} a & = b, \\ b & = c. \end{align} $$

注意点として、\^_エスケープしておく必要がある。

cocodrips.hateblo.jp

*1:具体的には こちらの記事 の通りにすれば良い

Model Building in Mathematical Programming: 9.3 〜 9.4

Optimization NightH. Paul Williams, Model Building in Mathematical Programming, 5th Edition, Wiley, 2013. の輪読会をしているので、そのメモです。

9.3 Special ordered sets of variables

ここでは、special ordered sets type 1 (SOS1) と special oredered sets type 2 (SOS2) という特殊な変数の組について解説している。SOS

  1. SOS1
    • ちょうど1つだけ非ゼロとなるような変数の組
  2. SOS2
    • たかだか2つの変数だけが非ゼロで、その2つの変数は隣り合っていなければいけない

SOS2 は、まさに区分線形近似ででてきたもの。つまり、MIPの範囲まで広げれば、非凸な関数も区分線形近似できる。

SOSの使用例としては、施設配置問題(候補のうち1つだけが値を持つ)、Capacity Extension (容量拡張? ある量を超えると追加のコストがかかるような場合に、追加コストの状況を選択する)、非線形関数(区分線形近似)などがある。ちなみに区分線形近似は、非連続な関数に対しても使える。

9.4 Extra conditions applied to linear programming models

LPに追加の条件が課せられた場合に、MIPとして定式化できることがある。ここでは、いくつかの例を紹介している

  1. Disjunctive constraints
    • いわゆる or 条件。前述の通り、 indicator variables によって、複雑な論理条件を記述できる
  2. Non-convex regions
    • or を表現できるので、下図のような非凸な領域も表現できる。
      f:id:ohtaman:20201012153722p:plain
      非凸な例
  3. Limitting the number of variables in a solution
    • 以下のような制約を課せば、正となる変数の個数に制限をつけられる
      \displaystyle \delta _ 1 + \delta _ 2 + \dots + \delta _ n \leq k.
  4. Sequentially dependent decisions
    • 前期の状態によって今期の判断に制限がかかるような条件は、前期の状態を表す変数と今期の判断を表す変数の組合せで表現できる
  5. Economies of scale
    • コストが上にサチるような状況では、(コストを下げたいという意味で)目的関数が非凸だが、MIPであれば区分線形近似できる
  6. Discrete capacity extensions
    • 容量が段階的に増えるような条件も、indicator variable をつかって表現できる
  7. Maximax objectives
    • minimax と違い、 maximax はLPでは表現できないが、MIPであればor条件を使って表現できる。

Model Building in Mathematical Programming: 9.2

Optimization NightH. Paul Williams, Model Building in Mathematical Programming, 5th Edition, Wiley, 2013. の輪読会をしているので、そのメモです。

9.2 Logical conditions and 0–1 variables

9.1 で、 0-1変数を使って 'if - then' を表せることがわかった。本章では、それを組み合わせてより複雑な論理式を記述できることが示されている。具体的には、まず各条件に対応する indicator variable をつくっておき、それらの間に制約を入れる。具体的には以下の様になる。

論理式 indicator variables による表現
 X _ 1 \vee X _ 2  \delta _ 1 + \delta _ 2 \geq 1
 X _ 1 \cdot X _ 2  \delta _ 1 = 1,\ \delta _ 2 = 1
 \sim X _ 1  \delta _ 1 = 0
 X _ 1 \to X _ 2  \delta _ 1 - \delta _ 2 \leq 0
 X _ 1 \leftrightarrow X _ 2  \delta _ 1 - \delta _ 2 = 0

ここで、それぞれの記号の意味は、

記号 意味
 \vee or (A or B or both)
 \cdot and
 \sim not
 \to implies (if ... then)
 \leftrightarrow if and only if

こういうのはパズルっぽいので好きなんだけど、プログラムで自動化できそうな気がするし、条件式を記述しているだけだよと solver に伝えてあげたほうが、解きやすそう(計算量を落とせそう)な気がなんとなくする。他人が indicator variable を使って記述した複雑な論理式を読み解くなんて絶対にやりたくない。論理式をそのまま取り扱ってくれる solver ってあるんだろうか。気になる。

宿題: 12.12 Logical design

NORゲート(NOR は NOT OR ですね)を用いて論理回路を設計する問題。入力と出力が与えられて、それを満たす回路を出力する。 まさに論理式を記述してみよう、という問題。パズルみたいで面白かった。本当に頭の体操という感じ。

colab.research.google.com

Model Building in Mathematical Programming: 9.1

Optimization NightH. Paul Williams, Model Building in Mathematical Programming, 5th Edition, Wiley, 2013. の輪読会をしているので、そのメモです。

そのまま進めると Chapter 8 ですが、どうやらお話章のようなので、そこは割愛して Chapter 9 へ。

宿題: 12.21 Agricultural pricing

政府が乳製品の価格を調整する問題。 生乳の生産量が決まっている中で、ミルク(加工乳?)やチーズ、バターにどういう価格付けをするとよいか、というお話。 これまでの問題と違って、内容はとてもシンプルだが、目的関数が非線形になる。各製品の単価を  x _ i 、需要(消費量)を  d _ i とおくと、収益は  \sum _ i d _ i x _ i となるので。

そこで、 Chapter 7 で学んだように、目的関数を区分線形な形に変形して解く。区分線形な形にするには、分離可能(separable)な形式、つまり、目的関数が単変数関数の和になるように書き直しておかなければいけない。 逆に分離可能になっていれば、分割する点を指定して区分線形な形には機械的に書き直すことができる。今回は↓みたいな感じで実装した。

ただ、分割する点をどうやって決めるか、あるいは変数の上限と下限をどう設定するかについてはなにか指針が必要そうだ。 実際の案件では、例えば現在の値の1.5倍までにしましょう、みたいに適当に決められそうな気がするが、教科書の問題を解くときは、他の制約式等から得られる論理的な上限を指定する必要がありそうなんだけど、論理的な上限は本当に大きくなってしまう可能性があるので、ちょっと怖い。

def linearize(
    single_variable_func: callable,
    points: List[Number],
    prefix: str='',
    x: Union[pulp.LpVariable, str]='x',
    y: Union[pulp.LpVariable, str]='y'
) -> Tuple[pulp.LpVariable, pulp.LpVariable, pulp.LpVariable, List[pulp.LpConstraint]]:
    '''
    非線形な単変数関数を区分線形近似する

    Arguments:
        single_variable_func (callable): 近似対象の単変数関数
        points (List[Number]): 分割する点
        prefix (str): 新規に作られる変数のプレフィックス
        x Union[pulp.LpVariable, str]: 変数 x(関数の入力)。文字列が与えられた場合は新たに生成する。
        y Union[pulp.LpVariable, str]: 変数 y(関数の出力)。文字列が与えられた場合は新たに生成する。

 Returns:
      x, y, weights, constraints (Tuple[pulp.LpVariable, pulp.LpVariable, pulp.LpVariable, List[pulp.LpConstraint]]): 変数x, 変数y, 各分割点の重み, 追加すべき制約式
    '''

    values = [single_variable_func(p) for p in points]
    # 分割点から最大値と最小値を求める
    min_x, max_x = min(points), max(points)
    min_y, max_y = min(values), max(values)

    if isinstance(x, str):
        x = pulp.LpVariable(f'{prefix}-x', min_x, max_x)
    if isinstance(y, str):
        y = pulp.LpVariable(f'{prefix}-y', min_y, max_y)

    # 各分割点の重み
    weights = pulp.LpVariable.matrix(f'{prefix}-w', points, 0, 1)
    constraints = [
        x == pulp.lpSum(p*w for p, w in zip(points, weights)),  # x と weights の関係
        y == pulp.lpSum(v*w for v, w in zip(values, weights)),  # y と weights の関係
        pulp.lpSum(weights) == 1  # weights の正規化 (総和が1)
    ]

    return x, y, weights, constraints

回答の Colab は以下の通り。未完成...、というかバグっていて動かない。時間見つけてデバグしないと。。

colab.research.google.com

Chapter 9 Building integer programming models I

これまではあくまで連続変数の線型計画法を扱っていたが、ここでようやく整数計画問題に入る。

9.1 The uses of discrete variables

整数変数の利用用途には主に3つある。

  1. indivisible (discrete) quantities: そもそも整数の値が出てくるような場合に使う
  2. decision variables: 決定変数。何らかの施策をするかしないか決めるような場合に使う
  3. indicator variables: if-then のような条件式を表現するのに使う

例えば、  x \geq 0 を連続変数、  \delta を 0-1 変数とした時、 M x の上限として、

 x > 0 \to \delta = 1

という条件式は、

 x - M\delta \leq 0

と書き直せる。

この章では、特に 3. indicator variables について大きく取り上げている。というのも、 indicator variables を使いこなせるか否かが、複雑な条件を定式化できるかを決めるからだと思う。

この論理式の書き換えは非常に混乱しやすいので、以下にまとめてみる(多分あっているはず...)。前提として、 m,\ M はそれぞれ  x の下限値と上限値。

(下限値と右辺値が曖昧になっていたため、テーブルを書き直しました。 10/12)

if-then formulation
1  x > 0 \to \delta = 1  x - M\delta \leq 0
2  x \geq 0 \to \delta = 1  x + \epsilon - M\delta \leq 0
3  x\ \lt \ 0 \to \delta = 1  x - m\delta  \geq 0
4  x \leq 0 \to \delta = 1  x + \epsilon - m\delta  \geq 0
5  \delta = 1 \to x \geq 0  x - m(1 - \delta) \geq 0
6  \delta = 1 \to x > 0  x + \epsilon - m(1 - \delta) \geq 0
7  \delta = 1 \to x \leq 0   x - M(\delta - 1) \leq 0
8  \delta = 1 \to x\ \lt \ 0  x + \epsilon - M(\delta - 1) \geq 0

ここで  \epsilon は十分小さい数で、制約式では等号なしの不等号を使えないために必要になる。また、上の表は、  x の代わりに  \sum_{i}a _ {i}x _ {i} のような数式であっても成り立つ。

どうでもいいんだけど、上の式の < は全角の < を使ってる。はてなブログTeX の < ってどうやって書くのが正解なんだろ。エスケープできればいいだけなんだけどわからん。

TODO

  • 12.21 の Colab をきれいに書き直して最後まで解く
  • 宿題: 12.12 Logical design