はじめに DELISH KITCHENでクライアントグループのマネージャーをやっている今井です。 クライアントチーム初のブログということで、DELISH KITCHENの Androidアプリの今の構成の話と、 アプリを作って4年が経とうとしてる中での変遷を紹介していきます。 なお、このブログは全体の構成の雰囲気を掴んでもらうことを目的にしておりますので、 細かい設計の話や採用技術の細かい特徴の紹介は割愛させていただきます。 それらはまた別の機会に紹介できればと思います。 現在の構成 ここでは現在のプロジェクトの構成とアプリで採用しているアーキテクチャの紹介をしていきます。 プロジェクトの構成 DELISH KITCHENのAndroidアプリではMultiModuleを採用しており、 大きく app core features の3種類のModuleに分かれています。 app いわゆるメインモジュールです。feature間をつなぐためのRouterの実装や、 ライブラリの初期化等を行っております。 歴史上の理由でここにもまだまだfeature要素が残ってしまっていますが、 徐々にfeatureモジュールに切り出しています。 core 各モジュールの共通で使う拡張関数やユーティリティクラスなどを入れています。 モジュール間の遷移に使ってるRouter等もここでInterfaceを定義しており、 実態はappモジュールで実装、DIで各モジュールに配布しています。 features 実際にfeaturesというモジュールがあるわけではなく、 機能ごとにfeatureモジュールとして分割しています。 各featureモジュールではcore以外のmoduleのimportを禁止しており、 強制的に参照不可にすることで依存をなるべく減らしています。 アーキテクチャ アーキテクチャとしてはMVVM+レイヤードアーキテクチャを採用しています。 図の通りですが、 Android Architecture Component (以下、AAC)を全面採用し、 MVVM+レイヤードアーキテクチャを構成しています。 ViewModelはそのままAACのViewModelを採用しており、 ViewModelからViewへのデータの公開はLiveData、 ViewからActionの受け付けはシンプルにメソッドコールにしています。 通信部分はKotlin Coroutineで繋いでいます。 この構成にいたるまでいろいろ変遷してきているので、 その一部を次で紹介します。 変遷 この4年間でKotlinがGoogleに正式にサポートされたり、AACやJetpackが登場したり Android界隈で大きくデファクトが変わってきました。 DELISH KITCHENのAndroidアプリではそれに対して比較的柔軟に採用技術を変更してきました。 その中で大きく変更があった3点を紹介します。 1. MonoModuleからMultiModuleへ コード量が増えてきてビルド時間が長くなってきたので検討し始めました。 副産物的な感じでしたが、参照をあえて出来なくすることで依存関係を意識せざるを得ない状況になり、チーム全体の依存に対する意識が向上しました。また、その事に頭を使わなくて良くなったのでとても良かったです。 分割し始めた当初はInstant AppやDynamic Feature Moduleも検討していました。 2. Android Architecture Componentの採用とRxの置き換え リリースから1年くらい経つと、機能が乗ってしまったいわゆるSuperActivity/Fragmentが出現し始めたので、 MVVMやFluxの導入を考えていたところAACが発表されたため即採用しました。 またAPI通信まわりは各レイヤーの繋ぎにとどまっていたRxをKotlinCoroutineとLiveDataに置き換えることで、 AACの恩恵をフルで受けれるような構成に変更しました。 3. Viewへのアクセス周りの変遷 ここが一番紆余曲折あったところです。 ざっくりと KotterKnife → Kotlin Android Extension → Databinding → ViewBinding と変更してきました。 初期はJavaの ButterKnife の流れで KotterKnife を採用してたものの、 型安全じゃないとかFragmentで使えないなどの理由から、Kotlin Android Extensionに移行しました。 その後すぐにnullableになってしまうのが辛くなったのと、xml上で値を設定できる便利さから DataBinding を採用しました。 DataBinding自体は全然問題なかったんですが、あまり双方向Bindingを生かす場面がなかったのと、 ロジックがxmlにも一部分散することでコードレビューが大変になったので、現在は ViewBinding を採用しています。 加えてViewBindingはDataBindingビルドが速かったり、型安全だったりと、しばらくはViewBindingで落ち着きそうです。 (おまけ) Dagger → Koin 人類にはDaggerは早かった(笑) っていうのもありますが、Daggerの機能をそんなに活かしきれていなかったのと、 誰でも比較的簡単にライブラリの挙動が理解できるように Koin に変更しました。 設計自体に影響が大きくあった訳ではないですが、コードの変更量が膨大で、 変更作業が一番辛かったのでおまけとして紹介させてください(笑)。 そんな中、今年出た DaggerHilt への変更を検討中だったりもします😇。 まとめ DELISH KITCHENのAndroidのアプリに関して少しでも知っていただけたら幸いです。 今回ご紹介した設計がベストだとは考えていませんし、まだまだ発展途上です。 アプリの規模にかかわらず、良いものであれば積極採用することはぶらさず、 開発してて楽しい環境を作りながら、より良いアプリをより早く提供できるように努めていければと思ってます。
はじめに はじめまして。2020年3月からエブリーでインターンをしている田村です。 私はデータエンジニア・データサイエンティストとしてインターンシップに参加し、データ関連部門に配属され、データ業務を担当しています。 今回は、エブリーにインターンとして入社し約4ヶ月間で感じたことをまとめていこうと思います。 目次 1.エブリーのインターンに参加した経緯 2.インターンを通して学んだこと 1.エブリーのインターンに参加した経緯 私は機械学習を主とする統計分野に興味があり大学院に進学したのですが、査読した論文を検証できるデータを保持するインターン先を探す中で、DELISH KITCHENを運営しているエブリーと出会いました。 面談の前にオフィスツアーをしたのですが、まず驚いたのは東京タワーの見える六本木グランドター38階のオフィスです。 食のメデイアを運営していることから、本格的なキッチンスタジオがあり、フードスタイリストの方が日々料理動画を撮影しています。 作業エリアは集中できる雰囲気なことや、CTOとのカジュアル面談時に大量のデータを扱うことが出来そうだと期待してインターンとして入社することに決めました。 2.インターンを通して学んだこと 私がデータエンジニアとしてインターンの業務を通じて学んだことを書いてみます。 ・DIKW まず、初日にデータチームのマネージャーに教えられたことはDIKWモデルというデータがどのように事業に貢献するかというモデルです。詳しい記事は こちら をご覧ください。 ・Arm Treasure Data / Databricks / Redashなどのデータプラットフォーム DELISH KITCHENのログデータの分析だけでも膨大な量で、これらのビッグデータを処理できる計算基盤が必須です。 所属しているデータ部門では、Databricksと呼ばれるApache Sparkをバックエンドとした分析プラットフォームを用いて、データクレンジングなどの前処理や機械学習の処理を実装しています。 また こちら の記事でもあるように、sql,scala,pythonなどの複数の言語を組み合わせて処理を書けるためこれらの言語の基本文法はマスターできました。学校ではPythonを利用した研究開発だけを実装しており、Python以外の言語に触れる機会が無かったのですが、SQLが特に重要だと教えられ、今では自分のやりたい事は大体実現できるようになりました。 インターン生でもエブリーの全てのデータに自由にアクセスでき、分析する基盤まであるのはとても良い環境だと思います。 ・他部門との連携 私の所属するデータ関連部門では、エブリーが運営している複数のメディアから発生するデータ分析依頼や要望を引き受けています。 「●●を知りたい」などの抽象的な課題を具体的な課題に落とし込んだ後、どんなデータを提供したら良いのか、どんな見せ方をしたらいいのかを考え、Redashのダッシュボードを提供したり統計的な手法で知見を伝えたりします。 他部門の業務を経験が浅いインターンが他部門の業務や課題を理解するのは難しいですが、エブリーではインターン生も他部門の議事録や組織図をconfleneceやカオナビで把握できます。 ・リモート環境 コロナの影響でエブリーでは3月からインターンも含めリモートワークを推奨しています。 私もリモートでのインターンは初めてで、移動時間がなくなったり服を選んだりする手間がなくなったりメリットが多いなと思いました。意思疎通が対面よりもスムーズにできないという問題がありますが、私のチームでは毎日30分程のミーティングを行い、課題の共有やコミニケーションを行うようにしています。 会議に参加できなくても録画しておけば後から見直せるので便利です。 最近では半年に1回の社員総会もリモートで行い こちら に詳しい記事があります。 最後に エブリーではデータ関連部門以外でもエンジニアのインターンを募集しています。 メディアの運営に携わってみたい、アプリの開発に携わってみたいという方は こちら をご覧ください。
はじめまして。2020年4月からエブリーに新卒で入社した伊藤です。 データエンジニア・データサイエンティストとしてデータ関連部門に所属し、日々データ業務に関わっています。 データ業務の1つである機械学習モデルの開発は、実験環境でモデルの精度を確認した上で本番環境に適用するプロセスを経ます。 今回は機械学習の実装で利用したMLflowとOptunaを組み合わせが、モデルの開発・運用・レビューで高いアジリティを提供できると分かり、導入事例として紹介できたらと思います。 取り組んだ問題 最近のデータ業務で、DELISH KITCHENユーザの過去の行動を分析し、ある特定のアクションが将来どの程度の確率で行われるかを機械学習で予測する、という問題に取り組みました。 ユーザがDELISH KITCHENをどのように使っているのか(レシピのお気に入り登録など)という情報は、集計された状態でデータウェアハウスに蓄積されています 1 。 まずはそれらを抽出し、予測を行うための特徴量データセットとして用意した後、パラメータの調整や特徴量の取り方などを試行錯誤しつつ、実験環境で機械学習モデルを構築しました。 大学の研究やデータコンペティションでは、多くの場合高い精度のモデルができたら一旦区切りとなりますが、企業で開発を行う場合にはこれを実際のビジネス施策でも使う必要があります。 そのためには、実験環境で行った「特徴量の抽出」→「モデルの学習」→「モデルの予測」→「最終結果の出力」という4つの段階が本番環境で1つのパイプラインとして自動化されており、かつ持続的に運用できる状態でなければなりません。 MLOps ここでMLOpsという概念を紹介したいと思います。 MLOpsとは機械学習のライフサイクルの管理やその環境を指す考え方で、機械学習(Machine Learning)と運用(Operations)を組み合わせた言葉です。 MLOpsの考え方に基づくと、上に挙げた4段階それぞれの品質を持続的に維持・改善しており、かつ全体としても1つのパイプラインとして運用できる環境の構築が重要になります 2 。 特に、ユーザ行動を使う今回のようなケースでは、予測したい行動データが日々更新され、実験では良い結果が出ていたモデルも時間が経つと「古い」モデルとなってしまうため、新しいデータを使ってモデルを定期的に更新していかなければなりません。 さらに、将来の研究でさらに良さそうなモデルが見つかった場合は過去のモデルと比較してより良いものをパイプラインに組み込めるような設計になっていると、より効果的な運用が可能になります。 このようなMLOps環境を実現するため、今回はMLflowとOptunaという2つのツールを組み合わせて活用しました。 MLflow MLflow 3 とはDatabricks社が開発した機械学習のライフサイクルを管理するためのプラットフォームです。 MLflowを使うと、学習結果の保存や過去の学習結果との比較が簡単に行えるようになります。 簡単な例としてロジスティック回帰によるアイリスデータセットの分類問題を考えると、実行環境によって設定は多少異なりますが、「ハイパーパラメータ」「予測精度」「学習モデル」の3つが対応した学習結果をおおよそ次のように登録できます。 from sklearn.linear_model import LogisticRegression import mlflow import mlflow.sklearn with mlflow.start_run(): lr_c = 0.1 model = LogisticRegression(C=lr_c).fit(x_train, y_train) score = model.score(x_test, y_test) mlflow.log_param( 'C' , lr_c) mlflow.log_metric( 'Mean Accuracy' , score) mlflow.sklearn.log_model( sk_model=model, artifact_path= 'mlflow_demo' , registered_model_name= 'lr_iris' ) 登録された学習モデルはMLflowを通してバージョン管理され、バージョンを指定したロードもできるため、新しいモデルと古いモデルとの性能比較を行ったり、時期や状況に応じたモデルの入れ替えも可能です。 それぞれのバージョンに対して、パラメータと予測精度が保存されています。 Optuna Optuna 4 は、Preferred Networks社が開発したハイパーパラメータチューニングのためのフレームワークです。 本来ハイパーパラメータチューニングは、パラメータの値を変更した学習結果を確認しながら最適値を見つける、非常に手間の掛かる作業です。 そのため、パラメータそれぞれに候補となる値を用意し、それらの組み合わせを全て試して最適なものを見つける、グリッドサーチと呼ばれる方法が主に使われていました。 しかし、グリッドサーチでチューニングの工程は自動化できるものの、パラメータの種類・候補が多いほど組み合わせが爆発的に増加するため探索に時間がかかってしまう、そもそも候補に含まれない値は探索できない、といった問題がありました。 Optunaでは、探索する値の候補を探索範囲として渡すことが可能です。 また、過去の探索結果に基づいて次に探索すべき範囲を判断するようなアルゴリズムが実装されているため、指定された範囲に含まれる値全てを試さずに、より確からしい最適解を導き出すことができます。 これにより、Optunaを使うとグリッドサーチよりも柔軟で効率的なハイパーパラメータチューニングが実現できます。 もう一度ロジスティック回帰によるアイリスデータセットの分類問題を考えます。 先ほどの例ではハイパーパラメータ C を決め打ちで設定していましたが、ここではOptunaを使い交差検証によるチューニングをしてみます。 from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score import optuna def objective (trial): lr_c = trial.suggest_loguniform( 'C' , 1e-4 , 1e2 ) model = LogisticRegression(C=lr_c) score = cross_val_score(model, x_train, y_train, cv= 3 ) accuracy = score.mean() return accuracy study = optuna.create_study(direction= 'maximize' ) study.optimize(objective, n_trials= 10 ) best_params = study.best_params 最適なパラメータは best_params として辞書形式で得られるので、その後は最適なパラメータでモデルを学習 → MLflowで結果を保存、という流れになります。 今回モデルの学習に用いるユーザ行動は時間的に変化するデータであるため、モデルの品質を持続させるには定期的に新しいデータで再学習する必要があります。 Optunaを使うとデータに応じて適切なハイパーパラメータを自動的に探索・決定できるようになり、 手動による介入を行わずに一定レベルの品質でモデルの再学習を行えます 5 。 MLOps環境の構築 それでは、MLOps環境をどのように構築したのかを紹介したいと思います。 エブリーではデータ分析基盤としてDatabricksを使っているため、Databricks notebookをベースに環境構築を行いました。 tech.every.tv まず、一連のパイプラインを「特徴量の抽出」「モデルの学習」「モデルの推論」「最終結果の出力」という4つのステップに分け、それぞれを順番に実行できるようなジョブを作成しました。 肝となるのが「モデルの学習」と「モデルの推論」のステップで、ここでMLflowとOptunaを活用します。 「モデルの学習」では、MLflowに登録されている最新の前処理モデルと予測モデルの2種類をロードし、検証用のデータを使ってこれらのモデル性能の検証を行います。 検証結果が良ければそのまま次のステップへ進みますが、もし検証結果が悪いようなら、再学習するためのタスクを呼び出してこれらのモデルをアップデートします。 モデルの再学習では、実験環境には存在しない本番環境の最新のデータを利用したハイパーパラメータチューニング、モデルの学習を行います。 チューニングするパラメータはOptunaに登録されており、探索はOptunaに実装されているアルゴリズムに従って行われるため、データに合わせた柔軟なチューニングが自動で行われます。 これにより、データが更新される度に必要となるハイパーパラメータの検証工程が減り、パイプラインの維持・改良をスムーズにできるようになります。 再学習後に得られたモデルはMLflowでバージョン管理し、必要に応じて過去のモデルとの比較もできるようにしました。 「モデルの推論」ではMLflowを通して最新のモデルをロードし、最新の行動データに対する予測を行います。 1つ前のステップでモデルの性能に関する検証を行っているため、ここで得られる予測は(完全ではないかもしれませんが)ある程度品質が保証されたものになります。 まとめ 以上、実験環境で機械学習モデルを作成するところからMLOps環境に昇華させるまでを、簡単に紹介させていただきました。 ここで紹介したパイプラインは現在バッチとして登録されており、定期的にモデルの更新とユーザ行動の予測が行われています。 現時点で運用を始めて数ヶ月が経ちましたが、現在も当初の予測精度付近で安定しており、構築した環境がモデルの品質維持に役立っているのでは、と考えています。 今回の業務を通して、MLflowとOptunaの有効性を改めて確認できたとともに、エブリーに入社するまではあまり経験してこなかった実運用環境の構築について新しく学べました。 今後は、MLOps環境を運用しつつ、新たなビジネス施策にも貢献できれば嬉しく思います。 ここまで読んでいただきありがとうございました。 https://speakerdeck.com/smdmts/databricks-and-spark-with-etl-and-visualization ↩ https://www.slideshare.net/databricks/mlflow-infrastructure-for-a-complete-machine-learning-life-cycle ↩ https://github.com/mlflow/mlflow/ ↩ https://github.com/optuna/optuna ↩ 時系列データを用いて交差検証を行う場合は、学習・予測データの分け方に注意する必要があります。 ↩
はじめに はじめまして。2020年4月にエブリーに新卒で入社した吉田です。 私はデータエンジニア・データサイエンティストとして入社し、データ関連部門に配属して日々データ業務に関わっています。 私達のチームでは、巨大なデータを集計・分析するための基盤としてDatabricks社の Databricks を使用しています。 今回の記事では、私達の業務におけるユースケースを交えながら、Databricksの利点や、活用方法を紹介できたらと思います。 Databricksとは DatabricksはApache Sparkベースの分析プラットフォームであり、データ分析の際に行う Data Sourceからデータを集約 分散処理によって高速にデータを整形 分析 可視化や集計したデータをData Lakeに保存 といった流れをDatabricks notebookを用いて記述し、Spark clusterを用いた高速な分散処理が可能です。 データ分析によく使われているツールであるJupyter notebookと同じような感覚でビックデータを扱え、インラインでの図表表示などにも対応しています。 またSpark clusterの設定やワークスペース、学習済み機械学習モデル、Jobの管理をWebUIを用いて行え、非常に扱いやすい分析プラットフォームです。 エブリーでDatabricksをどう使ってるか 私達のチームではデータ分析をする際に Arm Treasure DataやS3、BigQuery、Deltaからデータを抽出 データを加工し、Deltaに保存 Deltaから加工済みデータをTreasureDataに保存 TreasureDataをRedashから読み込み可視化 という流れを行っています。 この2の工程でDatabricksのnotebookを用いています。 SQLでは複雑なクエリになってしまう処理をDataFrameとして処理すると、コードを簡潔にでき可読性が上がります。 なぜDatabricksなのか Databricksを扱うにあたり便利な機能を紹介していきます。 豊富なData source DatabricksではS3上のcsvファイルやBigQuery、TreasureDataのデータ等をSparkを用いて高速に取り込めます。 特にDatabricks社が公開しているオープンソースのストレージレイヤーであるDelta Lakeを用いると、データへの信頼性とパフォーマンスが高まります。 Delta Lakeには ACIDトランザクションによりデータの整合性を確保 スキーマの適用によりデータの過不足や不正を検知 スナップショット作成によるロールバックや過去データの参照 Sparkの分散処理による高速な読みこみ といった機能が存在します。 これらの利点を、Spark Dataframeへの簡単なAPIによって使用できます。 // 書き込み sparkDataframe .write .format( "delta" ) .save( "delta/path" ) // 読み込み val sparkDataframe = spark.sql( """ select * from delta.`delta/path` """ ) ひとつのnotebook上でscala,python,sql等を混ぜて実行できる Databricksのnotebookではセルの先頭で %python や %scala といったマジックコマンドを記載すると、notebookに指定した言語とは別に、セル単位で使用する言語を選択できます。 pythonはデータを柔軟に扱え、データ分析において強力な言語ですが、型安全でない、scala等に比べて処理速度に劣るといった欠点が存在します。 そこでノートブック中で高速にしたい処理をscalaで処理し、分析部分をpythonで扱うといった運用が可能です。 履歴管理機能や同時編集機能が便利 Databricksにはnotebookの履歴を管理する機能や、複数人で同時に1つのnotebookを編集する機能が備えられています。 履歴の管理機能ですが、例えば notebookをリファクタリングしていたら重要なセルをまるごと消去してしまった データをいじくり回していたらnotebookがわけわからなくなった といった場合に、自動的に保存されている履歴から任意の履歴の復元が可能な機能です。 この機能はgitでの管理に関係なく履歴を保存してくれるため、わざわざgitで管理するほどでもない簡単な分析でも気軽に利用できるのが利点です。 次に複数人でのnotebook編集機能ですが、Databricksでは自分が見ているnotebookを他の人が閲覧している場合、閲覧しているユーザ名とそのユーザがどのセルを見ているかがセルに色がつき、わかるようになっています。 この機能を活用すると、複数人でnotebookを見ながら分析方法についての議論等が簡単に行なえます。 Gitによってバージョン管理が可能 DatabricksのnotebookではIpython notebookとは異なりセルの出力結果等がファイルに記載されないため、gitを用いたコードのバージョン管理が可能です。 これにより、一般的なコード開発と同じような コーディング P/Rを送る レビューしてもらう 修正 取り込み 運用 といった流れをデータ分析にも適用可能です。 そのため、クエリミスや不適切なデータ処理を可能な限りなくせ、また、より良い分析方法を協議できます。 それにより、信頼性の高いデータ分析を行えます。 また、gitホスティングサービスに連携したCircleCIを用いると、notebookのP/Rマージ時に本番環境への自動デプロイや、Job作成が行えます。 notebookをバッチスクリプトとして扱える Databricksで作成したnotebookはそのままDatabricks上でバッチJobとして登録できます。 使用するクラスタ構成や、実行するnotebook、スケジュールやリトライ回数等を簡単に設定できます。 notebookをバッチとして登録する利点として、 - 過去の実行結果がnotebookの出力としてセル単位で残る - セル単位で実行され結果が残るため修正が容易 というものがあります。 実行結果がセル単位で残るため、各セルごとの実行時間を比較してパフォーマンスが悪い処理を容易に特定可能で、パフォーマンス改善中の比較データとして過去の実装の結果を参照できます。 私達のチームでは、バッチのアラートをSlackに通知しており、アラート発生 -> セル単位の処理結果を見てエラー箇所を特定しリカバリという流れで安定したバッチ処理の管理を行えています。 まとめ 以上、エブリーでのDatabricksのユースケースと利点を簡単に紹介させていただきました。 Databricksを使用すると Spark clusterによるスケーラブルな計算基盤 Delta lakeによるデータの安全性 データ分析の信頼性 を確保できます。 こちらはあくまで一例ですが、Databricksの利点等を知っていただけたのであれば幸いです。
皆さん、こんにちは。株式会社エブリーは、『動画を通じてもっと楽しく、もっと充実した毎日に』をミッションに掲げた、『動画』『リアルデータ』『AI』のメディア企業です。 株式会社エブリーのエンジニア文化を紹介するために、技術ブログを発信していくことになりました。 はじめに 動画配信と言っても、動画編集サポートツール、動画エンコーディングインフラ、機械学習、ビッグデータ処理基盤、メディア運営をサポートする管理画面など、利用している技術は多岐に渡り『技術のるつぼ』と言っても過言ではありません。 採用技術 サーバサイド:Golang フロントエンド:Swift、Kotlin Webフロント:Nuxt、React、Angular データ基盤:Arm Treasure Data、BigQuery、Databricks インフラ:AWS、GCP プロジェクト管理:Asana、Confluence 対象ドメイン 料理、育児・子育て、ニュースエンタメ エブリーに在籍するエンジニア これまであまり外部に公開していなかったのですが、エブリーには個性的なキャリアを持つエンジニアが在籍しています。 AR黎明期にセカイカメラを作っていた人 金融系企業や教育系企業でCTOをやっていた人 ソーシャルゲーム企業の事業責任者をやっていた人 アドテク企業で爆速な配信サーバーを作っていた人 GAN(機械学習)でリンゴの画像生成をひたすら創っている人 エンジニアが『動画を通じてもっと楽しく、もっと充実した毎日に』を目指して、会社のミッションをどのように支えているか、紹介していきますのでぜひお楽しみに!