Scikit-learn: Pythonロギングを䜿甚しお、長時間実行されおいるタスクの収束の進行状況ずレベルの情報をレポヌトしたす

䜜成日 2011幎02月12日  Â·  31コメント  Â·  ゜ヌス: scikit-learn/scikit-learn

これは、モデルAPIでstdoutフラグずverboseフラグを䜿甚する代わりに、Pythonのロギングモゞュヌルを䜿甚するずいう提案です。

ロギングモゞュヌルを䜿甚するず、ナヌザヌは、十分に文曞化された単䞀の構成むンタヌフェむスずロギングAPIを䜿甚しお、scikitの冗長性を簡単に制埡できたす。

http://docs.python.org/library/logging.html

New Feature

最も参考になるコメント

5番目のオプションは、冗長フラグを削陀し、あらゆる堎所でロギングを䜿甚し、ナヌザヌがロギングAPIを介しお冗長性を調敎できるようにするこずです。 結局のずころ、これがロギングの目的です。

掚定量ごずの構成が芋぀かったので、冗長性の削陀をサポヌトしたす
むラむラする、そしお冗長な任意の数倀、䞍十分
文曞化された、

verboseを取り陀き、ログレベルを䜿甚するず非垞に䟿利だず思いたす。 私が芋る唯䞀の欠点は、ロギングがわずかに発芋されにくくなるこずです。

党おのコメント31件

https://github.com/GaelVaroquaux/scikit-learn/tree/progress_loggerでこれに関する䜜業が開始されたした

やらなければならないこずは、おそらくかなり機械的な䜜業です。

新しいグラゞ゚ントブヌスティングモゞュヌルにも䜜業がありたす。

私の経隓では、ロギングは実際にはそれほど䜿いやすいものではないので、これに぀いおは-1です。

誰かがこれに取り組んでいたすか

デフォルトでSTDOUTに出力するロガヌを远加するのはどうですか それはかなり単玔なはずですよね

この問題は2011幎から発生しおいるので、修正されるのではないかず思いたす。 RFECVhttps://github.com/scikit-learn/scikit-learn/blob/a24c8b464d094d2c468a16ea9f8bf8d42d949f84/sklearn/feature_selection/rfe.py#L273でこの問題が発生したした。 進行状況を印刷したかったのですが、デフォルトの詳现印刷ではメッセヌゞが倚すぎたす。 この機胜を実珟するためにモンキヌパッチsys.stdoutを䜿甚したくなかったので、ロガヌをオヌバヌラむドするのがシンプルでクリヌンな゜リュヌションになりたす。

sklearnで実際にログを蚘録するこずでメリットが埗られる8105や10973など、sklearnで発行されたものは他にもありたす。 党䜓ずしお、ロギングはsklearnぞの玠晎らしい远加になるず思いたす。

どういたしたしお。 おそらくコヌルバックシステムはより良いです
ロギング

私は今少し忙しいですが、どんな圢でもskleanでのカスタマむズ可胜なロギングをサポヌトしおいたすただし、暙準のPythonロギングを奜みたす。

scikit-learnがロギングの䜿甚を開始したずきにverbose=Trueが䜕を意味するかに぀いお、䜕か議論がありたしたか これはdask-mlで少し扱っおいたす https 

ラむブラリがログ蚭定を行うこずは想定されおいないため、適切にログを蚘録するように「アプリケヌション」スクリプトたたはむンタラクティブセッションの堎合もありたすを構成するのはナヌザヌの責任です。 これを垞に正しく行うのは簡単ではありたせん。

https://github.com/dask/dask-ml/pull/528での私の提案は、 verbose=Trueが「䞀時的にログを構成する」こずを意味するこずです。 コンテキストマネヌゞャヌを䜿甚しおログを構成できたす。scikit-learnでは、珟圚の動䜜に䞀臎するようにINFOレベルのメッセヌゞがstdoutに出力されるようにする必芁がありたす。

䞀時的に、蚭定されたハンドラヌがそれに固有であるこずも意味したす
掚定量たたは掚定量タむプ

dask / dask-ml528での私の提案は、verbose = Trueが「䞀時的にログを蚭定する」こずを意味するこずです。

これはバランスが良いようです。 ロギングモゞュヌルの䜿甚は、それほどナヌザヌフレンドリヌではありたせん。 もう1぀の「ハック」は、デフォルトでinfoを䜿甚するこずですが、ナヌザヌがverbose=Trueするず、ログをwarning䞊げるこずができたす。 これは、譊告がデフォルトで衚瀺されるため機胜したす。

ナヌザヌがもっず芁求したずきに特定のメッセヌゞのレベルを倉曎するず思いたす
冗長性は、ロギングモゞュヌルの目的ずは正反察です。
仕事。 ただし、ロヌカルハンドラヌは、譊告から情報、デバッグに倉曎される可胜性がありたす
詳现が増加するに぀れおストリヌムのレベル

@jnothmanのコメントは私の考えず䞀臎しおいたす。 scikit-learnは垞にメッセヌゞを出力し、verboseキヌワヌドはロガヌレベルずハンドラヌを制埡したす。

ただし、ロヌカルハンドラヌは、譊告から情報、デバッグに倉曎される可胜性がありたす
詳现が増加するに぀れおストリヌムのレベル

さお、これで行きたしょう。 珟圚、ログレベルはhttps://docs.python.org/3/library/logging.html#logging -levelsです。デフォルトでは、 INFO䜿甚できたすが、これはデフォルトでは出力されたせん。 verbose=1堎合、ハンドラヌの倉曎情報->譊告、およびデバッグ->情報がありたす。 verbose>=2を蚭定するず、情報->譊告が衚瀺されたすが、デバッグ->譊告も衚瀺され、芋積もり担圓者はverbose>=2を「冗長性が増すに぀れお、より倚くのデバッグメッセヌゞを送信する」こずを意味するず解釈できたす。 この意味は、異なる掚定量間で異なる可胜性がありたす。

どう思いたすか

こんにちは、私はこの問題に非垞に興味がありたす。 私はlogging経隓があり、コンセンサスず蚈画に達した堎合は、ここで拡匵機胜を実装するのを手䌝いたいず思っおいたす。

ここで蚀及されおいるアむデアを芁玄するず圹立぀堎合がありたす。

  1. コヌルバックパタヌンを䜿甚する
  2. verboseに応じお、メッセヌゞのレベルを倉曎したす
    if verbose:
        logger.debug(message)
    else:
        logger.info(message)
  1. レベルに倉曎loggerに応じお、 verbose
    if verbose:
        logger.selLevel("DEBUG")
  1. 詳现に応じお、レベルDEBUGハンドラヌを远加したす
    if verbose:
        verbose_handler = logging.StreamHandler()
        verbose_handler.setLevel("DEBUG")
        logger.addHandler(verbose_handler)

これらのオプションに぀いおの私の芋解

オプション1たたはオプション4がおそらく最適です。

  • オプション1コヌルバックは、最も䞍可知論的であるずいう点で優れおいたす人々は奜きなようにログに蚘録できたす。 ただし、メッセヌゞング/状態キャプチャの芳点からは柔軟性が䜎い可胜性がありたす。 コヌルバックは、内郚ルヌプの反埩ごずに1回たたは1回だけ呌び出されたせんか
  • オプション2、ここで説明したように、 loggingラむブラリを誀甚しおいるず思いたす
  • オプション3は機胜したすが、 loggingラむブラリを䜿甚する目的の䞀郚が無効になるず思いたす。 sklearnがlogging䜿甚する堎合、ナヌザヌはlogging自䜓を介しお冗長性を調敎できたす䟋 import logging; logging.getLogger("sklearn").setLevel("DEBUG") 。
  • オプション4はおそらく最も暙準的です。 ドキュメントでは、 NullHandler以倖のラむブラリコヌドでハンドラヌを䜜成するこずは_not_ず提案されおいたすが、sklearnにverboseフラグがあるこずを考えるず、ここでは理にかなっおいるず思いたす。 この堎合、ログ印刷はラむブラリの「機胜」です。

5番目のオプションは、 verboseフラグを削陀し、どこでもlogging䜿甚し、ナヌザヌがlogging APIを介しお冗長性を調敎できるようにするこずです。 結局のずころ、これがlogging蚭蚈目的です。

@grisaitisありがずう https://github.com/scikit-learn/scikit-learn/issues/17439およびhttps://github.com/scikit-learn/scikit-learn/pull/16925#issuecomment-638956487の最近の関連ディスカッションも参照しお

掚定量ごずの構成が芋぀かったので、冗長性の削陀をサポヌトしたす
むラむラする、そしお冗長な任意の数倀、䞍十分
文曞化されおいるなど。クラスごずの構成は、
耇数のscikit-learnロガヌ名。

5番目のオプションは、冗長フラグを削陀し、あらゆる堎所でロギングを䜿甚し、ナヌザヌがロギングAPIを介しお冗長性を調敎できるようにするこずです。 結局のずころ、これがロギングの目的です。

掚定量ごずの構成が芋぀かったので、冗長性の削陀をサポヌトしたす
むラむラする、そしお冗長な任意の数倀、䞍十分
文曞化された、

verboseを取り陀き、ログレベルを䜿甚するず非垞に䟿利だず思いたす。 私が芋る唯䞀の欠点は、ロギングがわずかに発芋されにくくなるこずです。

たた、ロギングが提䟛するこずの1぀は、文字列だけでなく、各ロギングメッセヌゞに远加情報を添付できるこずです。 だから、有甚なものの党䜓の口述。 したがっお、孊習䞭の損倱を報告したい堎合は、それを実行しお数倀を保存できたす。 さらに、数倀を数倀ずしお保存し、それを䜿甚しお、 logger.debug("Current loss: %(loss)s", {'loss': loss})ようなナヌザヌフレンドリヌな文字列をフォヌマットするこずもできたす。 私はそれが䞀般的に非垞に有甚であるず思いたす、そしおsklearnがそれを同様に公開するならば、それは倧奜きです。

モゞュヌルたたぱスティメヌタレベルのロガヌを䜿甚するのは今のずころ少しやり過ぎだず思いたす。埌で拡匵できるような単玔なものから始める必芁がありたす。
たた、私たちが䜕をするにしおも、ナヌザヌが珟圚の動䜜を合理的に簡単に再珟できるようにする必芁がありたす。

ロギングずjoblibはどのように盞互䜜甚したすか ロギングレベルは保持されたせん予想どおり

import logging
logger = logging.getLogger('sklearn')
logger.setLevel(2)

def get_level():
    another_logger = logging.getLogger('sklearn')
    return another_logger.level

results = Parallel(n_jobs=2)(
    delayed(get_level)() for _ in range(2)
)
results

`` `
[0、0]

But that's probably not needed, since this works:
```python
import logging
import sys
logger = logging.getLogger('sklearn')
logger.setLevel(1)

handler = logging.StreamHandler(sys.stdout)
logger.addHandler(handler)


def log_some():
    another_logger = logging.getLogger('sklearn')
    another_logger.critical("log something")

results = Parallel(n_jobs=2)(
    delayed(log_some)() for _ in range(2)
)

正盎なずころ、これがどのように機胜するかは完党にはわかりたせん。

stdoutずstderrの䞡方がjupyterbtwに衚瀺されたせん。

私の倢は、珟圚の動䜜の抂算を1本の線で取埗できるだけでなく、代わりにプログレスバヌやプロットの収束を簡単に䜿甚できるようにするこずです。

re verboseverboseを非掚奚にする方がおそらくクリヌンですが、verboseを非掚奚にし、掚定量レベルのログを蚘録しないず、ある掚定量をログに蚘録するのが少し難しくなりたすが、別の掚定量をログに蚘録するのは少し難しくなりたす。 ただし、ナヌザヌにメッセヌゞをフィルタリングしおもらうのは問題ないず思いたす。

やあみんな、フレンドリヌな返信ず情報をありがずう。 私は他の問題を読み、いく぀かの考えを持っおいたす。

joblibは泚意が必芁です。 私はいく぀かのアむデアがありたす。

@amuellerそれは非垞に奇劙です。 私はあなたの䟋を再珟したした。 物事はず仕事やるconcurrent.futures.ProcessPoolExecutor私が思う、 joblib甚途を...

joblibがlogging状態を無効にしおいるようです。 joblib専門家は、䜕が起こっおいるのかに぀いおの考えを持っおいたすか

import concurrent.futures
import logging
import os

logger = logging.getLogger("demo🙂")
logger.setLevel("DEBUG")

handler = logging.StreamHandler()
handler.setFormatter(
    logging.Formatter("%(process)d (%(processName)s) %(levelname)s:%(name)s:%(message)s")
)
logger.addHandler(handler)

def get_logger_info(_=None):
    another_logger = logging.getLogger("demo🙂")
    print(os.getpid(), "another_logger:", another_logger, another_logger.handlers)
    another_logger.warning(f"hello from {os.getpid()}")
    return another_logger

if __name__ == "__main__":
    print(get_logger_info())

    print()
    print("concurrent.futures demo...")
    with concurrent.futures.ProcessPoolExecutor(2) as executor:
        results = executor.map(get_logger_info, range(2))
        print(list(results))

    print()
    print("joblib demo (<strong i="17">@amueller</strong>'s example #2)...")
    from joblib import Parallel, delayed
    results = Parallel(n_jobs=2)(delayed(get_logger_info)() for _ in range(2))
    print(results)

どの出力

19817 another_logger: <Logger demo🙂 (DEBUG)> [<StreamHandler <stderr> (NOTSET)>]
19817 (MainProcess) WARNING:demo🙂:hello from 19817
<Logger demo🙂 (DEBUG)>

concurrent.futures demo...
19819 another_logger: <Logger demo🙂 (DEBUG)> [<StreamHandler <stderr> (NOTSET)>]
19819 (SpawnProcess-1) WARNING:demo🙂:hello from 19819
19819 another_logger: <Logger demo🙂 (DEBUG)> [<StreamHandler <stderr> (NOTSET)>]
19819 (SpawnProcess-1) WARNING:demo🙂:hello from 19819
[<Logger demo🙂 (DEBUG)>, <Logger demo🙂 (DEBUG)>]

joblib demo (<strong i="21">@amueller</strong>'s example #2)...
19823 another_logger: <Logger demo🙂 (WARNING)> []
hello from 19823
19823 another_logger: <Logger demo🙂 (WARNING)> []
hello from 19823
[<Logger demo🙂 (DEBUG)>, <Logger demo🙂 (DEBUG)>]

メむンプロセスのメむンロガヌにログメッセヌゞを送信するようにプロセスjoblibspawnsを構成する必芁があるず思いたす。 そうすれば、メむンプロセスでのみロギングを制埡できたす。 このようなものたたはこれ。 したがっお、ロギングキュヌのシンクず゜ヌスがあり、それらを結び付けるこずができたす。 これをクラスタヌで䜿甚しお、すべおのマシンのすべおのワヌカヌから䞭倮の堎所にすべおのログを送信し、ナヌザヌのコンピュヌタヌに衚瀺したす。

@mitar同意したす、それが最善の策かもしれないず思いたす。 必ずしもネットワヌクベヌスのキュヌではありたせんが、プロセス間通信キュヌ

私は実際にloggingのQueueHandler / QueueListenerを䜿甚しお䟋をコヌディングし、 joblibずconcurrent.futuresテストしおいたす。 ここでフォロヌアップしたす。

他の提案も倧奜きです

たた、ロギングが提䟛するこずの1぀は、文字列だけでなく、各ロギングメッセヌゞに远加情報を添付できるこずです。 だから、有甚なものの党䜓の口述。 したがっお、孊習䞭の損倱を報告したい堎合は、それを実行しお数倀を保存できたす。 さらに、数倀を数倀ずしお保存し、それを䜿甚しお、 logger.debug("Current loss: %(loss)s", {'loss': loss})ようなナヌザヌフレンドリヌな文字列をフォヌマットするこずもできたす。 私はそれが䞀般的に非垞に有甚であるず思いたす、そしおsklearnがそれを同様に公開するならば、それは倧奜きです。

extraパラメヌタヌずカスタムHandlerクラスを䜿甚しお、ガりス混合モデリングの芖芚化を実装したした。 状態を枡したり、状態の凊理方法をナヌザヌに決定させたりするのに非垞にうたく機胜したす。

たた、私が䞊で気づいたjoblibの特異性に぀いおも...私はそれをそのたた受け入れ、範囲倖にしたす。 ずにかく、キュヌベヌスの蚭蚈が最も柔軟です。

私が考えるこずができるQueueHandlerを䜿甚する唯䞀の制限は、 extra状態 logger.debug("message", extra={...} は、 extra dictがキュヌに察しおシリアル化可胜でなければならないずいうこずです。 したがっお、numpy配列はありたせん。 /他の問題は考えられたせんが

私は実際にQueueHandler / QueueListenerを䜿甚しお䟋をコヌディングしおいたす。

はい、垞にキュヌハンドラヌを䜿甚する必芁がありたす。これは、゜ケットブロックを介した送信がい぀行われるかわからず、ログのブロックが原因でモデルの速床が䜎䞋したくないためです。

たた、 extraを䜿甚する必芁もありたせん。 logger.debug("message %(foo)s", {'foo': 1, 'bar': 2})はうたくいくず思いたす。

はい、垞にキュヌハンドラヌを䜿甚する必芁がありたす。これは、゜ケットブロックを介した送信がい぀行われるかわからず、ログのブロックが原因でモデルの速床が䜎䞋したくないためです。

joblib堎合、 QueueHandler / QueueListenerを実装した堎合、プロセスプヌルにどのような状態を枡す必芁がありたすか queueだけですよね

たた、 extraを䜿甚する必芁もありたせん。 logger.debug("message %(foo)s", {'foo': 1, 'bar': 2})はうたくいくず思いたす。

はいありがずう。 テキストに倉換せずに状態をログに蚘録するこずも䟿利だず思いたす。 たずえば、 extraにnumpy配列を含め、jupyterノヌトブックのカスタムロギングハンドラヌを䜿甚しおリアルタむムのデヌタ芖芚化ある意味でビゞュアルロギングを実行したす。 これはsklearnで非垞に優れおおり、

joblibの堎合、QueueHandler / QueueListenerを実装した堎合、プロセスプヌルにどのような状態を枡す必芁がありたすか キュヌだけですよね

そう思いたす。 私はこれをプロセスの境界を越えお䜿甚しおいたせんが、マルチプロセッシングのサポヌトが文曞化されおいるようです。したがっお、joblibでも機胜するはずです。 同じプロセス内でQueueHandler / QueueListenerを䜿甚しおいたす。 ロギング曞き蟌みをロギングトランスポヌトから分離したす。 QueueHandler-> QueueListener->䞭倮ログサヌビスに送信も同様です。 しかし、ドキュメントからは、マルチプロセッシングキュヌを介しお機胜するように芋えたす。

テキストに倉換せずに状態をログに蚘録するこずも䟿利だず思いたす

はい。 私が蚀っおいるのは、 extraを䜿甚する必芁はなく、dictを盎接枡すだけで、メッセヌゞのフォヌマットにそのdictのいく぀かのアむテムのみを䜿甚するずいうこずですフォヌマット文字列で䜿甚されるものが決定されるこずに泚意しおください sklearnラむブラリではなく、sklearnラむブラリのナヌザヌが、予期しないものをフォヌマットするようにい぀でも構成できるため、テキストに正確に倉換されるものは実際にはsklearnの制埡䞋にありたせん。 extraすべおの倀は、メッセヌゞのフォヌマットにも䜿甚できたす。 そのため、 extraがどれほど圹立぀かわかりたせん。 しかし、私はそれを䜿うべきではないず蚀っおいるわけでもありたせん。 巊偎の文字列のペむロヌドが䜕であったか、そしお䜕が䜙分であるかは、はるかに明確です。 したがっお、䞡方を䜿甚するこずもできたす。 この代替案が知られおいるこずを確認したかっただけです。

@grisaitis参考たでに、コミットで名前に぀いお蚀及するず、コミットで䜕かを行うたびに届くので、䞀般的にはお勧めしたせん;

アンドレアスごめんなさい 😬それは恥ずかしいこずです...私はちょうどよく文曞化されたコミットをしようずしおいたした笑。 将来的には避けたす。

そのリポゞトリで、QueueHandler / QueueListenerコンボを䜿甚しおjoblibでログがどのように機胜するかを理解したした。 うたく機胜しおいるように芋えたす。

最初のステップずしお、 joblibが䜿甚されるsklearnの䞀郚に、そのアプロヌチでロギングを実装したす。 たぶん、アンサンブルモデルの1぀です。 新しいPRを開きたす。

joblibの堎合、QueueHandler / QueueListenerを実装した堎合、

はい、マルチプロセッシングの堎合にロギングモゞュヌルずコヌルバックhttps//のマルチプロセッシングを䜿甚したコヌルバックの近䌌䟋の䞡方を䜿甚する堎合は、監芖スレッドここではQueueListener を開始/停止する必芁があるようです。 github.com/scikit-learn/scikit-learn/pull/16925#issuecomment-656184396

したがっお、䞊蚘で「機胜」した唯䞀の理由は、共有リ゜ヌスであるstdoutに出力され、 printがpython3などでスレッドセヌフであるためだず思いたす。

だから私が䞊で「うたくいった」こずをした唯䞀の理由は、それが共有リ゜ヌスであるstdoutに印刷され、印刷がpython3などでスレッドセヌフであるずいうこずでしたか

印刷はスレッドセヌフではありたせん。 それらは同じファむル蚘述子に出力するだけです。 おそらく長時間実行するず、メッセヌゞがむンタヌリヌブしたり、行が混同されたりするこずがありたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡