Open GENZITSU opened 3 years ago
機械学習に関するtipsがまとめられているgithub。 項目はシェルの基本操作から、学習基盤(doker, )、アプリ開発、後処理前処理、各フレームワークなど内容がもりもり
個人的にためになったのはこれら
かなり濃密なまとめ集なので、定期的に覗きに行きたい。
データセットの最適な語彙数を決めるためのアルゴリズムVOLTをライブドアコーパスに適用した記事。
論文名: Vocabulary Learning via Optimal Transport for Neural Machine Translation
VOLTは入力としてサブワードで分割済みの学習コーパスと、語彙サイズの候補を受け取り、そこから適切な語彙を返します。 仕組みとしてはMUV(Marginal Utility of Vocabularization)と呼ばれる尺度を導入し、与えられた語彙サイズの候補の中からもっとも良いものを選択するアルゴリズムです。
語彙サイズは増やせば増やすほど、コーパスのエントロピーは減少します。 しかし、語彙サイズが増えていくと、学習時に使われない語彙が増えてしまったり、モデルのパラメーター数が大きくなってしまいます。 この語彙サイズとエントロピーの関係を、経済学の限界効用(語彙サイズがコストで、エントロピーが効用)になぞらえてMUVとして定義
具体例を挙げてVOLTアルゴリズムを解説します。 あらかじめある程度大きな語彙サイズ(たとえば30K)で学習コーパスをサブワード化します。 その後、語彙サイズ候補を S ={1K, 2K, …,29K, 30K}のように設定します。 するとVOLTは各語彙サイズごとに最適輸送を用いて語彙を決定し、その時のエントロピーが算出されます。 そして、語彙サイズが1Kの時と2Kの時のエントロピーの変化量、2Kの時と3Kの時のエントロピーの変化量などを比較していき、MUVが最大となる語彙サイズを決定しています。
著者たちはこのVOLTを利用することで、機械翻訳タスクにおいて従来の語彙サイズよりも小さいサイズで同等の精度が達成できることを示しました。
1K ~ 10Kまでを1Kずつグリッドサーチしていったとのこと。
最終的に到達している精度は変わらないが、VOLTの方が少ない語彙数なのでモデルのパラメータ数を節約できる。
また、VOLTを使わない場合は、それぞれの語彙数でモデルを学習させないといけないので、リソースを食う。
学習させるモデルがでかいと語彙サイズを変えてグリッドサーチするのが難しくなる点で有用そう。
VOLT自体の速度餓鬼になるところ。
rinna社が公開した日本語gpt-2を用いた条件付きタイトル生成の紹介。
以下のようにデータを整形することで条件付きの生成を可能にしている。
SPECIAL_TOKENS['bos_token']
+ ニュース記事のカテゴリー + SPECIAL_TOKEN['sep_token'] + ニュース記事の本文
+ SPECIAL_TOKEN['sep_token'] + ニュース記事のタイトル + SPECIAL_TOKEN['eos_token']
google colabでバッチサイズ1で学習をしていながら、ロスはちゃんと下がっている模様。 (学習は3時間ほどかかった模様)
生成された結果はこはこんな感じ。 ちゃんと指定したカテゴリごとに生成文を変えてくれるようだ。
peachyという若い女性向けニューズで条件付けすると、タイトルが少し可愛くなっていることがわかる。
promptプログラミングによって、条件付けを行うアイデアは自分にとっては新鮮だった。
そしてそれが存外うまくいっているのにびびる笑
ライブドアコーパス時代はそこまで大きいコーパスではないのに、なかなかやるなgpt2。
敵対的サンプルの現実での脅威の例がまとめられている。
A General Framework for Adversarial Examples with Objec-tivesと言う論文では敵対的サンプルで作成したメガネを着用することで、別人へのなりすましを可能にした。
不審者が社員になりすまして企業に侵入するといった物理セキュリティでの脅威が考えられます。
敵対的サンプルを利用して作成したシャツを用いて、人物検出を回避する例がいくつかの研究で示されている。
Making an Invisibility Cloak: Real World Adversarial Attacks on Object Detectorsと言う研究では静止画に対して人物検出を回避する例を発表
[Adversarial T-shirt! Evading Person Detectors in A Physical World]と言う研究では、動画へも対応する例を発表。
この研究では、物理世界で57パーセントの攻撃成功率と報告しています。これらの例が示すように、顔認証システムでのなりすましや物体検知モデルの検知を回避する敵対的サンプルは物理セキュリティの脅威となり得る
Optimization-Guided Binary Diversification to Mislead Neural Networks for Malware Detectionと言う研究ではマルウェアの攻撃性を保ちつつ、検知ソフトに引っかからないようにする例が発表されている。
「VirusTotal」というマルウェア検査を行うウェブサイト経由で68種類のマルウェア検知ソフトを用いて試したところ、平均して50パーセント程度の精度で回避できたという研究成果が出ています。
Audio Adversarial Examples: Targeted Attacks on Speech-to-Textと言う研究では、敵対的ノイズを入れることで元の音声とは別の音声に認識させる例が発表されている。
ここにサンプルが載っているが、
オリジナルの音声が「without the dataset the article is useless」の音声を「okay google browse to evil dot com」と誤認識させることに成功
攻撃者がターゲットのGoogleアシスタントを起動して強制的に悪意のあるサイトに誘導できる
マルウェア検知の回避、音声の敵対的サンプルが興味深かった。
ホワイトボックス攻撃か、グレーボックス、ブラックボックスかによって脅威性は変わってくるが、いずれにしても今後の動向に注目していきたい。
学習済みefficientnetを用いて、音声の異常検知を行う取り組み。
モデル:ゼロショット学習モデル(EfficientNetB4ベース) テストデータ:音声異常検知コンペデータ(DCASE Challenge2020 task2)
テストデータについて 機器の種類は6種類※。IDで3〜4個のデータに分けられている ※ 6種類:ToyCar, ToyConveyor, fan, pump, slide rail, valve IDが異なると音声取得状況が変わる(環境音や音の強さが異なる、詳細は[6]を参照)
物によってデータの種類によってはAutoEncoderのベースラインよりも高い精度になるものがある。
難しいデータに関しては、人間の目で見ても難しい。
記事の中ではデータ取得環境による違いや、ノイズに対する影響も調べられていた。
そのその中で、学習済みモデルのどのlayerを使うべきかが環境ごとに異なることに触れられている。
音のデータで学習していないのに、ある程度はできてしまうのが驚き。 音形で事前学習したものを使えばもっと精度が高いものができそうな感じがする。
BERTの推論速度を高速化させるためのさまざまな手法の検証記事
pruning(剪定): モデルの重みの一定割合で0にする手法
ここではL1ノルム基準で削る手法を用いました。
# from https://tech.jxpress.net/entry/2021/08/26/170000
import torch.nn.utils.prune as prune
PRUNE_RATE = 0.2
def prune_transform(model: nn.Module) -> nn.Module:
for name, module in model.named_modules():
if isinstance(module, torch.nn.Linear):
prune.l1_unstructured(module, name='weight', amount=PRUNE_RATE)
prune.remove(module, "weight")
return model
torchscript(Jit): PyTorchのコードからシリアライズ可能で最適化可能なモデルを作成する手法です。Python以外のC++等のランタイムで実行可能になります。
# from https://tech.jxpress.net/entry/2021/08/26/170000
def torchscript_transform(model):
model = torch.jit.trace(model, (SANPLE_INTPUT))
return model
- quantization(量子化)
- どちらのタスクにおいても殆ど精度を落とさずに推論時間を10~20%ほど削減することが可能です。 実装も容易であるため、高速化の際にはまず試してみたい手法です。
- distillation(蒸留)
- 精度面ではタスクによって大きく結果が異なることがわかります。
- 推論時間については約30%ほど削減できており、タスクによっては非常に有効な選択肢になり得ます。
- max_length
- どちらのタスクでも推論時間を40%~45%ほど削減できており、高速化において最も安定して寄与した
- ある程度速度が求められるシチュエーションの場合、まず初めにチューニングすべきパラメータ
- do_not_pad
- この手法はデータセットによって大きく効果が異なる結果となりました
- 精度は不変であるため、バッチ処理が不可能な状況下では積極的に利用すべき
- torchscript
- 精度を落とさずに、少しではありますが推論速度を向上させることができます。
- また、torchscriptはその他にも多くのメリットを有しており(Python以外のランタイムで実行可能、推論時にネットワークの定義が不要など)、プロダクションにデプロイする際はONNX等と並ぶ選択肢となります。
- Pruning
- 今回の実験ではかなり微妙な結果でした。
- twittterデータセットではpruning:0.4で10%ほどの推論時間削減を達成しましたが、その他の手法のトレードオフと比較するとコストパフォーマンスが低い印象です。その他の手法を全て適応した後、それでも高速化が必要ならば検討する、といったものになるでしょう。
- また、livedoorデータセットにおいてはまさかの低速化に寄与する結果となってしまいました。
こう言う検証記事はとてもありがたい。
ax.set_xlim([0,10])
ax.set_ylim([0,10])
ax.set_xlabel("lon")
...
みたいに冗長に書かずとも
ax.set(xlim=[0,10], ylim=[0,10], xlabel="lon", ...)
と一行で書ける
これでコードがスリムになる!
R社のAWS研修のCloudWatch版
CloudWatchの各種機能
サービス → メトリクス → 何らかのフィルター → 統計量 と言う順番で指標を作る
複数のメトリクスを用いて新たな指標を作ることも可能
ログはロググループ / ログストリーム / ログイベント などで構成される
ロググループに対してメトリクスを設定することでログの監視を行うことが可能
もともとはcloud watchの1サービスだったが、最近は独立したEvent Bridge。
特定のイベントの発火をトリガーにしたアクションを定義することが可能。
特定のイベントではなく、メトリクスの推移をトリガーにしたアクションも定義可能。
勉強になる。
メッセージのフィルタ処理 / アクセス制御 / メッセージのリトライ機能などを有している。
SNSではサブスクライバーのスペックを考慮せずに送ってしまうと言う問題がある。
SQSで手強している機能
その中で特に有用そうなものをピックアップ
dead letter queue: 失敗したメッセージののリトライ処理と、失敗したメッセージの個別補完機能
可視性タイムアウト: 処理されているメッセージを他から見えなくする。
各種タイマーの設定: メッセージを安全に処理できるようにするための準備時間を提供
メッセージの暗号化: 転送中も保管中も暗号化してくれる。
これまた勉強になりました。
API GateWayを用いたRequest Responseベース
S3やSNSを用いた非同期処理ベース
DynamoDBやkinesisのStreamに対するポーリング
SQSに対するポーリング
処理のリトライルールは、起動方法が異なる
Lambdaには同時実行数が存在
新規実行コンテナが立ち上がる際はオーバーヘッドが大きい
その他の注意点
lambdaは稀に複数回実行されることがあったりする。
エンジニアリング → 事業価値の関係を述べ、事業価値最大化のための方法論が述べられている。
機能やUIはリリースして初めて価値を生み出し、使われ続けることで価値を生み出し続けることが可能
企業価値の最大化のためには
技術的負債とは、現在の実装が将来のリードタイム遅延や価値積み上げの制約につながることを言う。
リソース効率を重視するか、リードタイム短縮を重視するかがある。
リソース効率高 & リードタイム小が理想だが、完璧は不可能。
一旦リードタイム小を目指すのが道としては良いとのこと。
感慨深い記事である。
エンジニアリングが生み出す積分値を向上させるためにはどうすれば良いかを日頃から考えておくのはとてもためになりそう。
リードタイム小を目指すのが理想的だが、現場の人はかなり疲れそうだなぁ。
近年では、モデルの規模や学習データの量の拡大に加えて、画像や動画への対応、会話や長文質問といった、難易度の高い言語理解への対応が進んでいます。
今年発表されたDALL-Eではテキストを入力として、画像を生成することが可能
対話可能チャットボット用のtransformerも発表されている模様。 事前に設定したシナリオを必要としなくなった反面、目的指向型の会話には使えない模様。
また、会話の理解を対象にしたユニークなトランスフォーマーも出てきました。2020年に発表された言語理解AI「Meena」は、膨大なSNS上での会話データを学習し、どんな話題に対しても気の利いた回答を返してくれます。
今年になって発表されたMeenaの強化版「LaMDA」では、Meenaができなかった「事実(Factuality)」の観点で適切な応答を返すことができます。これにより、フェイクニュースのような事実でない内容の応答を返してしまうという、GPT-3で見られた課題を解消しています。
現状のチャットボットはあらかじめ設定したシナリオに沿って会話を進める必要があり、少しでもシナリオから外れてしまうと会話が破綻してしまうという問題がありました。MeenaやLaMDAは、トランスフォーマーによって大量の会話データを学習することで、この問題を解決
ただし、雑談を楽しむためのチャットボットではなく、飛行機の予約や資産運用相談など、なにかしらの目的があって会話するチャットボットには使えません。
テキストに加えて、画像や動画も入力可能なtransformerも発表されている。
検索サービスを目的としたものとしては、長文質問検索を行うMUM(Multitask Unified Mode)が今年発表されました。これは通常であれば複数回の検索が必要になるような複雑な質問に対し、さまざまな角度から答えを返してくれるサービスです。注目すべきは、画像や動画の入力についても対応していることです。
このような潮流の他に、超大規模モデルという流れもある。
北京の人工知能研究所が発表したWuDao2.0はGPT-3の10倍のパラメータで、性能もめちゃくちゃ高い。
構造はswin transformerをベースにしているとのこと。
今年6月に発表された「Wu Dao(悟道)2.0」です。Wu Dao 2.0は北京智源人工知能研究院(BAAI)が開発したもので、1.75兆個のパラメーターというGPT-3の10倍の規模を誇ります。2.4TBのテキストデータ(中国語+英語)と、2.5TBの画像データで学習
画像やテキストそしてマルチモーダルの理解を対象とした9つのベンチマークにおいて、Google、OpenAI、Microsoftなどの並み居るAIを打ち負かし、トップの座を獲得しています。このことはBERTやGPT-3の登場時のようなインパクトを世間に与えている
追うのがむかしい、トランスフォーマーの最近の動向が知れてよかった。
入力の多様化とモデルサイズ(データサイズの)巨大化という2大潮流があるみたい。
どんどんでかくなる一方で、使用するための計算資源もバカデカくなっていくのはなんだかなぁ。
「マシン・アンラーニング」と呼ばれるコンピューターサイエンスの最新分野では、人工知能のプログラムに選択的健忘を起こさせる方法の研究が進められている。機械学習システムのパフォーマンスに影響を及ぼさずに、特定の人物やデータセットの痕跡をすべて消し去ることが目的だ。
モデルの再訓練を避けながら、特定のデータの影響をモデルから取り払う試みである。
ペンシルヴェニア大学教授でマシン・アンラーニングを研究するアーロン・ロスは語る。「データの削除を求められたとき、個人のデータの影響をすべて消し去ることはできるのでしょうか。しかも、ゼロから訓練をやり直すコストを避けながらです」
このような試みの背景には、GDPRなどに代表されるデータの主導権を企業ではなくユーザーに帰属させようという流れがある。
最近では不適切なデータで学習したモデルは、削除する必要性すら出ている。
最近になって米国と欧州の規制当局は、個人情報などを含む機密性の高いデータを用いて訓練されたAIシステムの所有者は、システム全体を削除しなければならないこともあるとの見解を示している。
実際にセキュリティ分野の研究では、アルゴリズムが訓練に使われた機密データを漏洩させてしまう場合があると示されている。 米連邦取引委員会(FTC)は今年に入って、顔認識システムを手がけるスタートアップのParavisionに、不適切な方法で取得した顔写真のデータセットとそれを使って訓練された機械学習のアルゴリズムを削除するよう命じている。
データセットをいくつかに分割して、再訓練のコストを下げる手法が提案されている。
こうしたなかトロント大学とウィスコンシン大学マディソン校の研究者たちは、訓練に使われるデータセットを複数の部分に分割し、最終的なアウトプットである機械学習システムに統合する前にそれぞれの部分を個別に処理する手法を19年に提示した。これなら、あとからデータの一部を削除する必要が生じた場合でも、再処理が必要になる部分は限られる。このやり方は実際に機能することを、研究者たちは100万枚以上の画像とネットショッピングの購入データを使った実験で確認している。
一方で、本当に忘れたかどうかを検証する方法も必要になっている。
カマスはまた、システムが削除されたはずのデータを本当に忘れたのか、企業や当局が検証する方法にも関心をもっている。
受託系の会社だと縁のない話だが、自社でサービスをもっていて一機能としてMLを提供している会社にとっては意識する必要がある話題になってくる。
とはいえ、学習データを作る際にはこれがどのユーザーからのどのデータであるまでは保持されていなさそうなので、
データ収集→モデル作成までのパイプラインがかなり高度になってからの話に思える。
iosアプリ上でのAIモデルの活用に関する事例紹介と活用にあたっての課題とその対応策がまとめられている。
Yahoo!知恵袋のiOSアプリではその軽量版モデルを持っており、リアルタイムで不適切判定を行っています。そして、サーバー側でマスクされる可能性がある投稿・コメントには、あらかじめアラートを表示させるということしています。
こちらの事例に関しては別の記事で詳細が述べられている。
アプリ内の文言を各ユーザーの端末上で直接検索でき、2021年8月現在では「ツール」のタブに導入されています。タブ内の検索アイコンをタップすると検索画面が表示され、ここで入力ワードに関連するサービスを探せます。
こちらも別記事で詳細が述べられている
アプリへの組み込み自体は簡単な一方で、エッジAIを用いた良いUXの構築にはいくつか課題がある。
現在のCore MLの周辺技術は充実していて、アプリへ学習済みモデルを組み込む事はとても簡単に実現できます。 一方でモデルを使ってよいUXを構築したり、モデルの運用まで考慮し始めると想像より大変になってきます。
機械学習モデルのサイズ
- アプリサイズはゲームを除くと大きいものでも100〜200MB程度であることを考えると、できれば10MB前後に抑えるのが理想
- サイズを落とすためにはモデル自体の性能を落とす必要があります。結果としてアプリが提供できる品質にどうしても制限がかかります。
- この問題に対応するためアプリの機能はあくまでもサーバーでやっていることの補完的なものという位置づけにしています。
- 軽量化にはKnowledge Distillationを使い 既に利用している大規模なモデルを使って投稿テキストに対するラベル+スコアを生成し、それを元に新しいモデルを作成するという方法で行っています。
モデルの互換性
- Core MLは他の機械学習フレームワークと完全に互換性があるわけではありません。
- 変換不可なオペレーターがある場合は、モデルを複数に分解してそのオペレーターの処理をSwiftで直接実装するといったことが必要
モデルの更新
- 再学習についてはCore ML自体にいくつかの選択肢が用意されています。ユーザーの入力情報をもとに再学習をする場合にはiOS 13以降で利用可能なMLUpdateTaskが使えます。
- Turi Createを使ってアップデート可能なモデルを作成し、モデル内の一部レイヤを再学習させるといったことができます。
- iOS 14ではCore ML Model Deploymentというサービスが使えるようになりました。Core MLモデルを管理・配信するのが主要な機能です。ユーザーはアプリ起動後にオンデマンドでモデルのダウンロードをするという仕組みとなっています。モデルのバージョン管理が可能なため、アプリの更新なしにサーバーで作成した新しいモデルへ差し替えられます。
テストとアプリ上での品質
- アプリの中に組み込んでみると、mlmodelを使った推論結果がサーバー側とアプリ側で微妙に違うということが起き得ます。
- 必ずアプリに組み込んで品質テストをしましょう。XCTestの中で.mlmodelを動かすことは可能なので、従来のユニットテストの延長としてモデルの品質テストを書くことが可能です。
- Core MLのモデルを使ったコードを書く場合には、最初にXCTestを使って結果が期待した範囲に収まるかのテストを書きます。
- モデルの品質をどこまで下げられるかは重要に問題です。その答えはアプリがどんなUXを提供したいかによって異なってきます。
- 作成するモデルの品質は仕様に依存しますし、仕様もモデルの品質に依存してきます。自ずと開発中に仕様変更が入りやすくなるため、UXの検討とモデルの開発は並行で進めることをおすすめします。
エッジAIに関するプロダクト理解がかなり上がる良記事だった。 とくに、モデルの品質に合わせて仕様を作る 、モデルの開発とUXの検討は同時並行で進めるべきというのは、とても参考になった。 そして、モデルサイズ~10MBという世界で戦う必要がるというのも驚き。 このサイズになると確かに精度に合わせてUXを変えるという方向が正義になるのも納得。
Pytorchにモデルのpruningが実装されたということで、性能を試してみた記事。
pruningにはモデルの構造を変えるものと、コネクションを切るだけという2種類があり、今回は後者を選択
ちなみに、後者の方法では、構造自体は変わらないので推論速度はあまり変わらないらしい。
- Structured Pruning(構造的Pruning) → ニューロンそのものを除去する。ネットワークの構造が変化する
- UnStructured Pruning(非構造的Pruning) → ニューロン間のコネクションを除去する。ネットワークの構造は変化しない
記事ではpytorch 1.9をもちいて、CIFAR10をVGGを用いて学習、30%の割合でpruningを行い精度劣化やモデルサイズの削減を確認している。
pruningには以下のようなコードを用いている。アルゴリズムとしては重みの絶対値ベースのprune.L1Unstructured
を選択
https://tech-blog.optim.co.jp/entry/2021/08/30/100000
import torch.nn.utils.prune as prune
# prune_amount
amount = 0.3
pruned_model = models.vgg16(pretrained=False, num_classes=10).to(device)
pruned_model.load_state_dict(torch.load('cifar10_vgg16.pth.tar'))
parameters_to_prune = (
(pruned_model.features[0], 'weight'),
(pruned_model.features[2], 'weight'),
(pruned_model.features[5], 'weight'),
(pruned_model.features[7], 'weight'),
(pruned_model.features[10], 'weight'),
(pruned_model.features[12], 'weight'),
(pruned_model.features[14], 'weight'),
(pruned_model.features[17], 'weight'),
(pruned_model.features[19], 'weight'),
(pruned_model.features[21], 'weight'),
(pruned_model.features[24], 'weight'),
(pruned_model.features[26], 'weight'),
(pruned_model.features[28], 'weight'),
(pruned_model.classifier[0], 'weight'),
(pruned_model.classifier[3], 'weight'),
(pruned_model.classifier[6], 'weight')
)
prune.global_unstructured(
parameters_to_prune,
pruning_method=prune.L1Unstructured,
amount=amount,
)
prune.remove(pruned_model.features[0], 'weight')
prune.remove(pruned_model.features[2], 'weight')
prune.remove(pruned_model.features[5], 'weight')
prune.remove(pruned_model.features[7], 'weight')
prune.remove(pruned_model.features[10], 'weight')
prune.remove(pruned_model.features[12], 'weight')
prune.remove(pruned_model.features[14], 'weight')
prune.remove(pruned_model.features[17], 'weight')
prune.remove(pruned_model.features[19], 'weight')
prune.remove(pruned_model.features[21], 'weight')
prune.remove(pruned_model.features[24], 'weight')
prune.remove(pruned_model.features[26], 'weight')
prune.remove(pruned_model.features[28], 'weight')
prune.remove(pruned_model.classifier[0], 'weight')
prune.remove(pruned_model.classifier[3], 'weight')
prune.remove(pruned_model.classifier[6], 'weight')
結果としては以下の表に集約される。
JX通信社の記事でも紹介されていたpruningがここでも紹介されており、流行を感じる。
JX社の記事ではpruningにより若干の速度向上が観測されたようだが、今回はあまり効果がなかったのだろうか?
(感覚的にはコネクションが切られているのであれば、速度が上がりそうだが、実際は重みを0にしてるだけだから変わらないのかな?)
とはいえ、モデルのサイズが減れば推論時のバッチサイズを上げることも可能なので、そっち側からの精度向上が期待できそう。
partial AUCとは何者か、そして何を狙った指標なのかが詳細に説明されている。
pAUC自体はPartial AUC Maximization via Nonlinear Scoring Functionsという論文で提案されたものらしい。
partial AUCとは以下の図のように、False Positive Rateが低いところのみでAUCを計算しましょうというもの。
コアな概念としては以下
こういう指標があることを知らなかった。
記事自体は2019年のものの割に、今まで聞いたことがなかった指標なのでマイナーな指標なのかもしれない。
軽量イメージとして名高いalpineだが、実はpythonを入れるには難儀な点があるとのこと
それぞれの理由としては
- Alpineのアプリが使うlibc(musl)のメモリ周りアロケートの実装が、性能よりもライブラリのサイズ重視のシンプルでPythonの使い方と合わなくて速度が出ないとのこと。これはアプリケーションの実装次第なのでjemallocを使っているRubyとかの人は関係ないでしょうし、PostgreSQLとかNginxはAlpine版でも速度は変わらないようです。
- 後者の速度の問題ですが、PyPIはLinux向けにはmanylinux1という形式でバイナリを提供しており、DebianでもRedHatでも高速にインストールできます。しかし、この形式はAlpineには対応していないため、C拡張を使うライブラリを使うと、Dockerイメージのビルド時間が伸びまくってしますわけです。
記事中では、以下のようにbuster系のイメージをつかったmulti stage buildが紹介されていた。
build用のコンテナは使用するライブラリによってslimにしても良いらしい。
使うライブラリがpure python、もしくはC拡張でもwheelによるバイナリ配布をしているパッケージのみであれば、ビルド用イメージも3.8-slim-busterにできます。slimを使っていても、もしライブラリを追加した瞬間にGCCが必要になっても、イメージを3.8-busterに変えるだけなので、このマルチステージビルドの構成は崩さない方が良いでしょう。
# from https://future-architect.github.io/articles/20200513/
# ここはビルド用のコンテナ
FROM python:3.8-buster as builder
WORKDIR /opt/app
COPY requirements.lock /opt/app
RUN pip3 install -r requirements.lock
# ここからは実行用コンテナの準備
FROM python:3.8-slim-buster as runner
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
COPY --from=builder /usr/local/bin/uwsgi /usr/local/bin/uwsgi
RUN apt update \
&& apt install -y libpq5 libxml2 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -r -s /bin/false uwsgiusr
RUN mkdir -p /opt/app/src/logs/app_logs
RUN touch /opt/app/src/logs/server.log
RUN chown -R uwsgiusr /opt/app/src/logs
COPY deploy/uwsgi.ini /opt/app
COPY mysite /opt/app/mysite
USER uwsgiusr
EXPOSE 8000
CMD ["uwsgi", "--ini", "/opt/app/uwsgi.ini"]
なぜ、よく見る/root/.cacheのコピーをしないかと言うと、以下のような無駄なレイヤーが出るかと書かれていた。
2020年時点の記事なので、もしかすると今はCOPYで作られるレイヤーも削除可能になっているかもしれない。
この方法であれば、uwsgiのような別の場所に入る実行ファイルも自動で処理されるのできれいにうまくいくのですが、最終的なイメージに/root/.cacheのレイヤーが残ってしまいます。RUNによるレイヤーなら&&を駆使して削除できるのですが、これはCOPYで作られるレイヤーなので、今のDockerだけだとこの無駄は削除できないのですよね。
alpine選ばれがちだけど、パフォーマンスが悪いことは知らなかった。
マルチステージビルドのやり方も参考になる。
日本音響学会 第22回サマーセミナー 深層学習に基づく音声変換
猿渡・小山研究室のメンバーからの発表
音声認識の主要なアプローチと役立つデータセット/ツールなどがまとめられていた。
コメント
データセットはさておき、有用なツールを探すのは結構しんどいのでありがたい。
出典
元記事