GENZITSU / UsefulMaterials

34 stars 0 forks source link

almost weekly useful materials - 02/08 - #126

Open GENZITSU opened 1 year ago

GENZITSU commented 1 year ago

Juman++ V2のインストール手順

表題の通り

コメント

sudoなしで実行できるのが嬉しいが、Juman++はそのほかのtokenzierと比べて実行速度がなぁ...

出典

Juman++ V2のインストール手順

GENZITSU commented 1 year ago

VSCodeにChatGPTの拡張機能を入れてコードレビューやバグを発見してもらう

範囲選択箇所のコードレビューやリファクタリング、コードの説明などをしてくれる拡張機能の利用方法を解説している記事

コメント

無料分のクレジットが付与されるとはいえ、優良ではあるので使用感はわからず。 OpenAPI側に入力が送られるので利用には慎重にならないと行けなさそう。

出典

VSCodeにChatGPTの拡張機能を入れてコードレビューやバグを発見してもらう

GENZITSU commented 1 year ago

Pythonで文字列の類似度を120倍高速に計算するRapidFuzzを勧めたい

編集距離計算でよく用いられるlevenshteinよりも高速なライブラリRapidFuzzの紹介

スクリーンショット 2023-02-02 14 48 45

RapidFuzzでは文字列の配列同士での距離比較や文字列比較前に実行する前処理のカスタマイズなどが可能でN:Nの他にも1:N, 1:1の比較も可能となっている。

以下カバーされている距離関数

デフォルトの前処理関数も用意されていて、reよりも高速とのこと

rapidfuzz.utils.default_processという前処理関数が提供されています。文字列を入力すると

  • 英数字のみを抽出(記号を除去)
  • 先頭と末尾のスペースを削除
  • 小文字化
  • を行います。 re.sub()より5倍以上も高速 です。

コメント

とても便利そう

出典

Pythonで文字列の類似度を120倍高速に計算するRapidFuzzを勧めたい

GENZITSU commented 1 year ago

数千万ユーザーのビッグデータに機械学習モデルを適用するには(広告配信ソリューション実現の工夫紹介)

非常に大量のサンプルに対するMLソリューションの実装・運用におけるtipsを紹介している記事

学習時のメモリ節約方法や推論時間の高速化、作成したモデルの管理方法など勉強になることが多い

ソリューション概要

予測ファネルでは、ユーザーの行動ログ、興味関心、属性などのデータから、ユーザーごとにCVする可能性を予測したスコアを活用して配信します。 スコア化した結果をマーケティングファネルに落とし込むことでCV見込みユーザーのボリュームを可視化し、高スコアユーザーに広告配信することでより多くのCVを獲得することが可能になります。 また、ミドルスコアユーザーに広告配信することで商材に関する興味関心の意識を醸成し、将来的にCVするユーザーを育成することも可能に

スクリーンショット 2023-02-02 15 52 31

学習時のメモリ節約方法

特徴量として用いる行動ログデータのlibsvm形式への変換 libsvm形式へ変換するためにAWS上で、もともと横持ちのデータとしてS3に格納しているデータをlibsvm形式に変換する前処理を実施しています。

スクリーンショット 2023-02-02 15 54 56

sklearnでも利用可能なのがえらい

scikit-learnライブラリのload_svmlight_filesを使用してlibsvm形式のファイルを読み込めば、以降は通常のscikit-learnに搭載されたモデルを学習するのと同様の手順でモデル作成が可能です。

大体1/3くらいになるっぽい

libsvm形式にすることでファイル容量をlibsvm形式変換前の3分の1以下に抑え、モデルの学習時に必要なメモリリソースも大幅に抑制することができました。

分析アーキテクチャー

学習用のlibsvm形式と推論用のデータ形式の二つを随時作成する日次バッチ処理が組まれていて、モデル作成リクエストに従って該当のデータを取得し、モデルを作るという構成

スクリーンショット 2023-02-02 15 56 40

推論速度の高速化

ロジスティック回帰モデルを採用し、かつ推論をAthena上でSQL処理させることで高速推論を実現 推論に時間のかかる決定木モデルなどは使わず、推論の速いロジスティック回帰を採用し、さらにAthena上で推論をSQL処理することで高速な推論を可能にしました

メリットはかなり大きく

C推論時間をおよそ1分に短縮することができました(1分は5000万ユーザーに推論した場合の時間)。同じユーザー数に対しするPython上でscikit-learnのRandom Forestモデルを用いて推論する場合は2時間以上

SQLで推論できるため、データを保持することなく推論することが可能になり、データのIOを簡素化

コメント

CVのスコアを活用する方法としてもとても勉強になった ロジスティック回帰でも商用に耐えるようにするための特徴量設計が以外と大変そうだが、SQL処理できると言うメリットはこの規模だととても大きそう 1つのモデルの運用であればバッチ処理でよいが、複数ユーザーから複数モデルの作成・予測が求められるケースだとこっちの方に軍配が上がるか

出典

数千万ユーザーのビッグデータに機械学習モデルを適用するには(広告配信ソリューション実現の工夫紹介)

GENZITSU commented 1 year ago

leondgarse / keras_cv_attention_models

tf2kerasで画像認識モデルの実装と学習済みモデルの配布がされているOSS

スクリーンショット 2023-02-03 16 56 37

スクリーンショット 2023-02-03 16 56 28

コメント

実装されているモデルはtimmとあまり差がないが、tfで実装されているのでtflie形式にできたりTPUを使いやすいのが利点だろうか

出典

leondgarse / keras_cv_attention_models

GENZITSU commented 1 year ago

Parquet+Petastormを使って画像分類モデルをSparkで学習させてみました!

databricks上で画像系DNNモデルを分散学習する際に必要となる前準備とDataLoaderの書き方をコードとともに紹介している記事

具体的には画像をsparkdfで読み取る際にラベルとバイナリの形式でデータを読み一度parquetに変換し、parquet形式を読み込めるようにSparkDatasetConverterのmake_torch_dataloader()メソッドを利用するとのこと

コメント

databricks上で学習すると言うのはなかなかレアそうだが、参考になる。

出典

Parquet+Petastormを使って画像分類モデルをSparkで学習させてみました!

GENZITSU commented 1 year ago

mmediting

inpatingやmatting, super resolution などの画像編集処理を行う各種モデルが実装されているOSS

スクリーンショット 2023-02-06 17 14 13

スクリーンショット 2023-02-06 17 14 52

スクリーンショット 2023-02-06 17 14 59

コメント

open-mmlabがカバーしている範囲が意外と広いことに驚くばかり

その他で気になったレポジトリ

出典

mmediting

GENZITSU commented 1 year ago

Demystify RAM Usage in Multi-Process Data Loaders

pytorchのデータローダをmulti worker, multi gpuで利用した際にメモリが大量に消費されてしまう事象の原因と対処法を解説しているブログ

原因

Linuxがサブプロセスを生成する際にCopy-on-writeが走り、親プロセスが保持しているメモリ領域を子プロセスがまるごとコピーしてしまうため。

解決方法

processがspwanされる際にメモリーをコピーせずに親プロセスの領域を3章できるように、プロセス間で共有したいデータはtorch.Tensor形式でシリアライズしておく

# from https://github.com/ppwwyyxx/RAM-multiprocess-dataloader/blob/200f5f2a209c2ce624b35e54746e07fbdb04ebda/serialize.py#L40

class TorchSerializedList(NumpySerializedList):
    def __init__(self, lst: list):
        super().__init__(lst)
        self._addr = torch.from_numpy(self._addr)
        self._lst = torch.from_numpy(self._lst)

    def __getitem__(self, idx):
        start_addr = 0 if idx == 0 else self._addr[idx - 1].item()
        end_addr = self._addr[idx].item()
        bytes = memoryview(self._lst[start_addr:end_addr].numpy())
        return pickle.loads(bytes)

以下のようにメモリ使用量を削減できる

スクリーンショット 2023-02-07 16 08 45

スクリーンショット 2023-02-07 16 07 37

ここからさらにプロセスごとのtorchのimport分を削減したい場合は以下のようなテクニックがある

multiprocessing.set_forkserver_preload(["torch"])

さらにmulti gpu x multi workerに対応させるためには以下のように、GPU番号に応じた処理を追加する必要ががある。

# from https://github.com/ppwwyyxx/RAM-multiprocess-dataloader/blob/200f5f2a209c2ce624b35e54746e07fbdb04ebda/serialize.py#L55

# NOTE: https://github.com/facebookresearch/mobile-vision/pull/120
# has another implementation that does not use tensors.
class TorchShmSerializedList(TorchSerializedList):
    def __init__(self, lst: list):
        from detectron2.utils import comm

        if comm.get_local_rank() == 0:
            super().__init__(lst)
        if comm.get_local_size() == 1:
            # Just one GPU on this machine. Do nothing.
            return
        if comm.get_local_rank() == 0:
            # Move to shared memory, obtain a handle.
            serialized = bytes(mp.reduction.ForkingPickler.dumps(
                (self._addr, self._lst)))
            # Broadcast the handle of shared memory to other GPU workers.
            comm.all_gather(serialized)
        else:
            serialized = comm.all_gather(None)[comm.get_rank() - comm.get_local_rank()]
            # Materialize a tensor from shared memory.
            self._addr, self._lst = mp.reduction.ForkingPickler.loads(serialized)
            print(f"Worker {comm.get_rank()} obtains a dataset of length="
                  f"{len(self)} from its local leader.")

コメント

worker数を増やした際にべらぼうにメモリを消費してしまう事象に悩まされていたが、これで解決しそう

出典

GENZITSU commented 1 year ago

iterative-stratification

MultilabelStratifiedKFoldの実装をしてくれているOSS

# from https://github.com/trent-b/iterative-stratification

from iterstrat.ml_stratifiers import MultilabelStratifiedKFold
import numpy as np

X = np.array([[1,2], [3,4], [1,2], [3,4], [1,2], [3,4], [1,2], [3,4]])
y = np.array([[0,0], [0,0], [0,1], [0,1], [1,1], [1,1], [1,0], [1,0]])

mskf = MultilabelStratifiedKFold(n_splits=2, shuffle=True, random_state=0)

for train_index, test_index in mskf.split(X, y):
   print("TRAIN:", train_index, "TEST:", test_index)
   X_train, X_test = X[train_index], X[test_index]
   y_train, y_test = y[train_index], y[test_index]

コメント

メモ

出典

iterative-stratification

GENZITSU commented 1 year ago

Stratified Group k-Fold Cross-Validation

GroupedMultilabelStratifiedKFoldの実装

# from https://www.kaggle.com/code/jakubwasikowski/stratified-group-k-fold-cross-validation/notebook

def stratified_group_k_fold(X, y, groups, k, seed=None):
    labels_num = np.max(y) + 1
    y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))
    y_distr = Counter()
    for label, g in zip(y, groups):
        y_counts_per_group[g][label] += 1
        y_distr[label] += 1

    y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))
    groups_per_fold = defaultdict(set)

    def eval_y_counts_per_fold(y_counts, fold):
        y_counts_per_fold[fold] += y_counts
        std_per_label = []
        for label in range(labels_num):
            label_std = np.std([y_counts_per_fold[i][label] / y_distr[label] for i in range(k)])
            std_per_label.append(label_std)
        y_counts_per_fold[fold] -= y_counts
        return np.mean(std_per_label)

    groups_and_y_counts = list(y_counts_per_group.items())
    random.Random(seed).shuffle(groups_and_y_counts)

    for g, y_counts in sorted(groups_and_y_counts, key=lambda x: -np.std(x[1])):
        best_fold = None
        min_eval = None
        for i in range(k):
            fold_eval = eval_y_counts_per_fold(y_counts, i)
            if min_eval is None or fold_eval < min_eval:
                min_eval = fold_eval
                best_fold = i
        y_counts_per_fold[best_fold] += y_counts
        groups_per_fold[best_fold].add(g)

    all_groups = set(groups)
    for i in range(k):
        train_groups = all_groups - groups_per_fold[i]
        test_groups = groups_per_fold[i]

        train_indices = [i for i, g in enumerate(groups) if g in train_groups]
        test_indices = [i for i, g in enumerate(groups) if g in test_groups]

        yield train_indices, test_indices

コメント

メモ

出典

Stratified Group k-Fold Cross-Validation