μ΄κ²μ λͺ¨λΈ APIμμ stdout λ° verbose νλκ·Έλ₯Ό μ¬μ©νλ λμ pythonμ λ‘κΉ λͺ¨λμ μ¬μ©νλ μ μμ λλ€.
λ‘κΉ λͺ¨λμ μ¬μ©νλ©΄ μ λ¬Έμνλ λ¨μΌ κ΅¬μ± μΈν°νμ΄μ€μ λ‘κΉ APIλ₯Ό μ¬μ©νμ¬ μ¬μ©μκ° scikitμ μμΈν μ λλ₯Ό μ μ΄νκΈ°κ° λ μ¬μμ§λλ€.
https://github.com/GaelVaroquaux/scikit-learn/tree/progress_logger μμ μ΄μ λν μμ μ΄ μμλμμ΅λλ€.
λ¨μ μΌμ μλ§λ μλΉν κΈ°κ³μ μΈ μμ μΌ κ²μ λλ€.
μλ‘μ΄ Gradient Boosting λͺ¨λμλ μμ μ΄ μμ΅λλ€.
λ΄ κ²½νμ λ‘κΉ μ μ€μ λ‘ μ¬μ©νκΈ°κ° μ½μ§ μμΌλ―λ‘ -1μ λλ€.
μ΄ μμ μ νλ μ¬λμ΄ μμ΅λκΉ?
κΈ°λ³Έμ μΌλ‘ STDOUTμ μΈμνλ λ‘κ±°λ₯Ό μΆκ°νλ κ²μ μ΄λ»μ΅λκΉ? μλΉν κ°λ¨ν΄μΌ ν©λλ€. λ§μ£ ?
μ΄ λ¬Έμ λ 2011λ
λΆν° 곡κ°λ λ¬Έμ μΈλ° ν΄κ²°λ μ§ κΆκΈν©λλ€. RFECV(https://github.com/scikit-learn/scikit-learn/blob/a24c8b464d094d2c468a16ea9f8bf8d42d949f84/sklearn/feature_selection/rfe.py#L273)μμ μ΄ λ¬Έμ κ° λ°μνμ΅λλ€. μ§ν μν©μ μΈμνκ³ μΆμμ§λ§ κΈ°λ³Έ μμΈ μΈμλ λ무 λ§μ λ©μμ§λ₯Ό μΈμν©λλ€. μ΄ μμ
μ μννκΈ° μν΄ sys.stdout
λ₯Ό μμμ΄ ν¨μΉνκ³ μΆμ§ μμμΌλ©° λ‘κ±°λ₯Ό μ¬μ μνλ κ²μ΄ κ°λ¨νκ³ κΉ¨λν μ루μ
μ΄ λ κ²μ
λλ€.
#8105 λ° #10973κ³Ό κ°μ΄ sklearnμμ μ€μ λ‘κ·ΈμΈμ ν΅ν΄ ννμ λ³Ό μ μλ λ€λ₯Έ λ°νμ΄ μμ΅λλ€. μ λ°μ μΌλ‘ λ‘κΉ μ sklearnμ ν° λμμ΄ λ κ²μ΄λΌκ³ μκ°ν©λλ€.
λΉμ μ κ·Έκ²μ λν΄ μμ
μ νμν©λλ€. μλ§λ μ½λ°± μμ€ν
μ΄
λ²μ± λ°μΆ
λλ μ§κΈ μ½κ° λ°μμ§λ§ μ΄λ€ ννλ‘λ skleanμμ μ¬μ©μ μ μ κ°λ₯ν λ‘κΉ μ μ§μν©λλ€(λΉλ‘ νμ€ νμ΄μ¬ λ‘κΉ μ μ νΈνμ§λ§).
scikit-learnμ΄ λ‘κΉ
μ μ¬μ©νκΈ° μμν λ verbose=True
κ° λ¬΄μμ μλ―Ένλμ§μ λν λ
Όμκ° μμμ΅λκΉ? μ°λ¦¬λ μ΄κ²μ dask-mlμμ μ½κ° λ€λ£¨κ³ μμ΅λλ€: https://github.com/dask/dask-ml/pull/528.
λΌμ΄λΈλ¬λ¦¬κ° λ‘κΉ κ΅¬μ±μ μννμ§ μμμΌ νλ€λ μ μ κ°μν λ μ μ νκ² λ‘κΉ νλλ‘ "μμ© νλ‘κ·Έλ¨"(λ¨μ§ μ€ν¬λ¦½νΈ λλ λνμ μΈμ μΌ μ μμ)μ ꡬμ±νλ κ²μ μ¬μ©μμ λͺ«μ λλ€. μ΄κ²μ νμ μ¬λ°λ₯΄κ² μννλ κ²μ΄ μ½μ§ μμ΅λλ€.
https://github.com/dask/dask-ml/pull/528μ λ΄ μ μμ verbose=True
κ° "λλ₯Ό μν΄ μΌμμ μΌλ‘ λ‘κΉ
ꡬμ±"μ μλ―Ένλ κ²μ
λλ€. 컨ν
μ€νΈ κ΄λ¦¬μλ₯Ό μ¬μ©νμ¬ λ‘κΉ
μ κ΅¬μ± ν μ μμΌλ©° scikit-learnμ INFO
μμ€ λ©μμ§κ° νμ¬ λμκ³Ό μΌμΉνλλ‘ stdoutμ μΈμλλλ‘ ν©λλ€.
μΌμμ μΌλ‘ νΈλ€λ¬ μ€μ μ΄ ν΄λΉ μ€μ κ³Ό κ΄λ ¨λμ΄ μμμ μλ―Έν©λλ€.
μΆμ κΈ° λλ μΆμ κΈ° μ ν?
dask/dask-ml#528μμ λ΄ μ μμ verbose=Trueκ° "λλ₯Ό μν΄ μΌμμ μΌλ‘ λ‘κΉ κ΅¬μ±"μ μλ―Ένλ κ²μ λλ€.
μ΄κ²μ μ’μ κ· νμΈ κ² κ°μ΅λλ€. λ‘κΉ
λͺ¨λμ μ¬μ©νλ κ²μ κ·Έλ€μ§ μ¬μ©μ μΉνμ μ΄μ§ μμ΅λλ€. λ λ€λ₯Έ "ν΄νΉ"μ κΈ°λ³Έμ μΌλ‘ 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
λν μ½κ°μ κ²½νμ΄ μμΌλ©° μΌλΆ ν©μμ κ³νμ λλ¬νλ©΄ μ¬κΈ°μμ κ°μ μ¬νμ ꡬννλ λ° λμμ μ£Όκ³ μΆμ΅λλ€.
μ¬κΈ°μ μΈκΈλ μμ΄λμ΄λ₯Ό μμ½νλ λ° λμμ΄ λ μ μμ΅λλ€.
verbose
μ λ°λΌ λ©μμ§ μμ€ λ³κ²½ if verbose:
logger.debug(message)
else:
logger.info(message)
logger
μ λ°λΌ verbose
if verbose:
logger.selLevel("DEBUG")
DEBUG
μμ€μ νΈλ€λ¬ μΆκ° if verbose:
verbose_handler = logging.StreamHandler()
verbose_handler.setLevel("DEBUG")
logger.addHandler(verbose_handler)
μ΄ μ΅μ μ λν λμ 견ν΄:
μ΅μ 1 λλ μ΅μ 4κ° κ°μ₯ μ’μ΅λλ€.
logging
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μ©νκ³ μλ€κ³ μκ°ν©λλ€.logging
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ λͺ©μ μ μΌλΆλ₯Ό 무ν¨ννλ€κ³ μκ°ν©λλ€. sklearnμ΄ logging
λ₯Ό μ¬μ©νλ κ²½μ° μ¬μ©μλ logging
μ체λ₯Ό ν΅ν΄ μμΈν μ λλ₯Ό μ‘°μ ν μ μμ΅λλ€(μ: import logging; logging.getLogger("sklearn").setLevel("DEBUG")
.NullHandler
μ΄μΈμ λΌμ΄λΈλ¬λ¦¬ μ½λμμ νΈλ€λ¬λ₯Ό μμ±νμ§ _not_ μ μνμ§λ§ sklearnμ verbose
νλκ·Έκ° μλ€λ μ μ κ°μν λ μ¬κΈ°μμ μλ―Έκ° μλ€κ³ μκ°ν©λλ€. μ΄ κ²½μ° λ‘κ·Έ μΈμλ λΌμ΄λΈλ¬λ¦¬μ "κΈ°λ₯"μ
λλ€.λ€μ― λ²μ§Έ μ΅μ
μ 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 λ‘κ±° μ΄λ¦.
λ€μ― λ²μ§Έ μ΅μ μ μμΈν νλκ·Έλ₯Ό μ κ±°νκ³ λͺ¨λ κ³³μμ λ‘κΉ μ μ¬μ©νλ©° μ¬μ©μκ° λ‘κΉ APIλ₯Ό ν΅ν΄ μμΈν μ λλ₯Ό μ‘°μ ν μ μλλ‘ νλ κ²μ λλ€. μ΄κ²μ΄ λ°λ‘ λ‘κΉ μ΄ μ€κ³λ λͺ©μ μ λλ€.
μμ€ν°λ©μ΄ν°λ³ ꡬμ±μ μ°ΎμΌλ©΄ μμΈν μ 보 μ κ±°λ₯Ό μ§μνκ² μ΅λλ€.
μ€λ§μ€λ½κ³ μμμ μ₯ν©ν μ«μ κ°μ΄ μ’μ§ μμ΅λλ€.
λ¬Έμν,
verbose
μμ κ³ λ‘κΉ
μμ€μ μ¬μ©νλ κ²μ΄ λ§€μ° μ’μ κ²μ΄λΌκ³ μκ°ν©λλ€. λ΄κ° λ³Ό μμλ μ μΌν λ¨μ μ λ‘κΉ
μ μ½κ° λ κ²μνκ² λ§λ λ€λ κ²μ
λλ€.
λν λ‘κΉ
μ΄ μ 곡νλ ν κ°μ§λ λ¬Έμμ΄λΏλ§ μλλΌ κ° λ‘κΉ
λ©μμ§μ μΆκ° μ 보λ₯Ό 첨λΆν μ μλ€λ κ²μ
λλ€. κ·Έλμ μ μ©ν κ²λ€μ μ 체 λμ
λ리. λ°λΌμ νμ΅ μ€ μμ€μ λ³΄κ³ νλ €λ©΄ κ·Έλ κ² νκ³ μ«μ κ°μ μ μ₯ν μ μμ΅λλ€. λν μ«μ κ°μ μ«μλ‘ μ μ₯νκ³ μ΄λ₯Ό μ¬μ©νμ¬ 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μ λͺ¨λ jupyter btwμ νμλμ§ μμ΅λλ€.
λ΄ κΏ: ν μ€λ‘ νμ¬ λμμ κ·Όμ¬μΉλ₯Ό μ»μ μ μμ§λ§ λμ μ§νλ₯ νμμ€μ΄λ νλ‘― μλ ΄μ μ½κ² μ¬μ©ν μ μμ΅λλ€.
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)>]
λ©μΈ νλ‘μΈμ€μ λ©μΈ λ‘κ±°μ λ‘κΉ λ©μμ§λ₯Ό 보λ΄λλ‘ joblibκ° μμ±νλ νλ‘μΈμ€λ₯Ό ꡬμ±ν΄μΌ νλ€κ³ μκ°ν©λλ€. κ·Έλ¬λ©΄ λ©μΈ νλ‘μΈμ€μμλ§ λ‘κΉ μ μ μ΄ν μ μμ΅λλ€. μ΄κ² λλ μ΄κ² κ³Ό κ°μ κ² . λ°λΌμ λ‘κΉ ν μ±ν¬μ μμ€κ° μμΌλ©° ν¨κ» λ¬Άμ μ μμ΅λλ€. μ°λ¦¬λ ν΄λ¬μ€ν°μμ μ΄κ²μ μ¬μ©νμ¬ λͺ¨λ μ»΄ν¨ν°μ λͺ¨λ μμ μμ λͺ¨λ λ‘κΉ μ μ€μ μμΉλ‘ λ³΄λ΄ μ¬μ©μμ μ»΄ν¨ν°μ νμν©λλ€.
@mitar λμν©λλ€. κ·Έκ² μ΅μ μ μ νμΌ μ μλ€κ³ μκ°ν©λλ€. (λ°λμ λ€νΈμν¬ κΈ°λ° νλ μλμ§λ§ νλ‘μΈμ€ κ° ν΅μ ν)
μ λ μ€μ λ‘ logging
μ QueueHandler
/ QueueListener
λ₯Ό μ¬μ©νμ¬ μμ λ₯Ό μ½λ©νκ³ μμΌλ©° joblib
λ° concurrent.futures
λ‘ ν
μ€νΈν©λλ€. μ¬κΈ°μμ λ°λ₯Ό κ²μ
λλ€.
λ€λ₯Έ μ μλ μ’μν©λλ€.
λν λ‘κΉ μ΄ μ 곡νλ ν κ°μ§λ λ¬Έμμ΄λΏλ§ μλλΌ κ° λ‘κΉ λ©μμ§μ μΆκ° μ 보λ₯Ό 첨λΆν μ μλ€λ κ²μ λλ€. κ·Έλμ μ μ©ν κ²λ€μ μ 체 λμ λ리. λ°λΌμ νμ΅ μ€ μμ€μ λ³΄κ³ νλ €λ©΄ κ·Έλ κ² νκ³ μ«μ κ°μ μ μ₯ν μ μμ΅λλ€. λν μ«μ κ°μ μ«μλ‘ μ μ₯νκ³ μ΄λ₯Ό μ¬μ©νμ¬
logger.debug("Current loss: %(loss)s", {'loss': loss})
μ κ°μ μ¬μ©μ μΉνμ μΈ λ¬Έμμ΄ νμμ μ§μ ν μ μμ΅λλ€. λλ κ·Έκ²μ΄ μΌλ°μ μΌλ‘ λ§€μ° μ μ©νλ€λ κ²μ μμκ³ sklearnμ΄ κ·Έκ²μ 곡κ°νλ€λ©΄ μ’μν κ²μ λλ€.
extra
맀κ°λ³μμ μ¬μ©μ μ μ νΈλ€λ¬ ν΄λμ€λ₯Ό μ¬μ©νμ¬ κ°μ°μ€ νΌν© λͺ¨λΈλ§μ μκ°νλ₯Ό ꡬννμ΅λλ€. μνλ₯Ό μ λ¬νκ³ μ¬μ©μκ° μνλ₯Ό μ²λ¦¬νλ λ°©λ²μ κ²°μ νλλ‘ νλ λ° λ§€μ° νλ₯νκ² μλν©λλ€.
λν λ΄κ° μμμ μμμ°¨λ¦° 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μμ λ§€μ° νλ₯ν κ²μ΄λ©° @rth κ° μ½λ°±μΌλ‘ μ μ¬ν μμ
μ μνν κ²μ²λΌ 보μ
λλ€.
joblibμ κ²½μ° QueueHandler / QueueListenerλ₯Ό ꡬννλ€λ©΄ νλ‘μΈμ€ νμ μ΄λ€ μνλ₯Ό μ λ¬ν΄μΌ ν κΉμ? κ·Έλ₯ λκΈ°μ΄, κ·Έλ μ§?
λλ κ·Έλ κ² μκ°ν΄. νλ‘μΈμ€ κ²½κ³λ₯Ό ββλμ΄ μ΄κ²μ μ¬μ©νμ§ μμμ§λ§ λ€μ€ μ²λ¦¬μ λν λ¬Έμνλ μ§μμ΄ μλ κ² κ°μΌλ―λ‘ joblibμμλ μλν΄μΌ ν©λλ€. λμΌν νλ‘μΈμ€ λ΄μμ QueueHandler/QueueListenerλ₯Ό μ¬μ©νκ³ μμ΅λλ€. λ‘κΉ μ μ‘μμ λ‘κΉ μ°κΈ°λ₯Ό λΆλ¦¬ν©λλ€. QueueHandler -> QueueListener -> μ€μ λ‘κΉ μλΉμ€λ‘ 보λ΄κΈ°λ λ§μ°¬κ°μ§μ λλ€. κ·Έλ¬λ λ¬Έμμμ λ€μ€ μ²λ¦¬ λκΈ°μ΄μ ν΅ν΄ μλν μ μλ κ²μ²λΌ 보μ λλ€.
λλ κ·Έκ²μ ν μ€νΈλ‘ λ³ννμ§ μκ³ μνλ₯Ό κΈ°λ‘νλ κ²λ μ μ©νλ€λ κ²μ μμμ΅λλ€.
μ. λ΄κ° λ§νλ €λ κ²μ extra
λ₯Ό μ¬μ©ν νμκ° μμ§λ§ dictλ₯Ό μ§μ μ λ¬ν λ€μ λ©μμ§ νμνλ₯Ό μν΄ ν΄λΉ dictμ λͺ κ°μ§ νλͺ©λ§ μ¬μ©νλ€λ κ²μ
λλ€(νμ λ¬Έμμ΄μ μ¬μ©λλ νλͺ©μ΄ κ²°μ λλ€λ μ μ μ μνμμμ€. sklearn λΌμ΄λΈλ¬λ¦¬κ° μλ sklearn λΌμ΄λΈλ¬λ¦¬ μ¬μ©μμ μν΄ μμνμ§ λͺ»ν μμμ μ§μ νλλ‘ νμ ꡬμ±ν μ μμΌλ―λ‘ μ νν ν
μ€νΈλ‘ λ³νλλ λ΄μ©μ μ€μ λ‘ sklearn μ μ΄ νμ μμ§ μμ΅λλ€. extra
λͺ¨λ κ°μ λ©μμ§ νμμλ μ¬μ©ν μ μμ΅λλ€. κ·Έλμ extra
κ° μΌλ§λ μ μ©νμ§ μ λͺ¨λ₯΄κ² μ΅λλ€. κ·Έλ¬λ λλ λν μ°λ¦¬κ° κ·Έκ²μ μ¬μ©ν΄μλ μλλ€κ³ λ§νλ κ²μ΄ μλλλ€. μΌμͺ½μ μλ λ¬Έμμ΄μ νμ΄λ‘λμ μΆκ° μ¬νμ΄ ν¨μ¬ λ λͺ
νν©λλ€. κ·Έλμ μ°λ¦¬λ λ λ€ μ¬μ©ν μλ μμ΅λλ€. λλ λ¨μ§ μ΄ λμμ΄ μλ €μ Έ μλμ§ νμΈνκ³ μΆμμ΅λλ€.
@grisaitis μ°Έκ³ λ‘ μ»€λ°μμ μ΄λ¦μ μΈκΈνλ©΄ ββ컀λ°μΌλ‘ 무μμ΄λ ν λλ§λ€(μ: λ¦¬λ² μ΄μ€ λλ λ³ν© λλ νΈμ) κ·Έ μ¬λμ μ΄λ©μΌμ λ°κΈ° λλ¬Έμ μΌλ°μ μΌλ‘ κΆμ₯νμ§ μμ΅λλ€ ;)
μ£μ‘ν©λλ€ μλλ μμ€! π¬ μ°½νΌνλ€μ... κ·Έλ₯ λ¬Έμν μ λ 컀λ°μ νλ €κ³ νλ κ² λΏμ΄μμ γ γ γ γ μμΌλ‘λ νΌν κ²μ λλ€.
κ·Έ 리ν¬μ§ν 리μμ QueueHandler / QueueListener 콀보λ₯Ό μ¬μ©νμ¬ joblib
μμ λ‘κΉ
μ΄ μλνλ λ°©λ²μ μμλμ΅λλ€. μ μλνλ κ²μΌλ‘ 보μ
λλ€.
첫 λ²μ§Έ λ¨κ³λ‘ joblib
κ° μ¬μ©λλ sklearnμ μΌλΆμμ ν΄λΉ μ κ·Ό λ°©μμΌλ‘ λ‘κΉ
μ ꡬνν©λλ€. μλ§λ μμλΈ λͺ¨λΈ μ€ νλμΌ κ²μ
λλ€. μλ‘μ΄ PRμ μ½λλ€.
joblibμ κ²½μ° QueueHandler / QueueListenerλ₯Ό ꡬννλ©΄
μ, λ€μ€ μ²λ¦¬μ κ²½μ° λ‘κΉ
λͺ¨λκ³Ό μ½λ°±μ μ¬μ©νλ κ²½μ° λͺ¨λν°λ§ μ€λ λ(μ¬κΈ°μλ QueueListener
)λ₯Ό μμ/μ€μ§ν΄μΌ ν κ² κ°μ΅λλ€(https://μμ λ€μ€ μ²λ¦¬κ° μλ μ½λ°±μ λλ΅μ μΈ μ). github.com/scikit-learn/scikit-learn/pull/16925#issuecomment-656184396)
κ·Έλμ μμμ λ΄κ° "μλ"ν μ μΌν μ΄μ λ 곡μ 리μμ€ μΈ stdoutμ μΈμλμκ³ print
λ python3 λλ μ΄μ μ μ¬ν κ²μμ μ€λ λλ‘λΆν° μμ νλ€λ κ²μ
λλ€.
κ·Έλμ μμμ λ΄κ° "μλ"ν μ μΌν μ΄μ λ 곡μ 리μμ€ μΈ stdoutμ μΈμλμκ³ μΈμλ python3 λλ μ΄μ μ μ¬ν κ²μμ μ€λ λλ‘λΆν° μμ νλ€λ κ²μ λλ€.
μΈμλ μ€λ λλ‘λΆν° μμ νμ§ μμ΅λλ€. κ·Έλ€μ λ¨μ§ λμΌν νμΌ μ€λͺ μλ‘ μΈμν©λλ€. μλ§λ λ μ€λ μκ° λμ μ€ννλ©΄ λ©μμ§κ° λλλ‘ μΈν°λ¦¬λΈλκ³ νμ΄ νΌλλλ κ²μ λ³Ό μ μμ΅λλ€.
κ°μ₯ μ μ©ν λκΈ
verbose
μμ κ³ λ‘κΉ μμ€μ μ¬μ©νλ κ²μ΄ λ§€μ° μ’μ κ²μ΄λΌκ³ μκ°ν©λλ€. λ΄κ° λ³Ό μμλ μ μΌν λ¨μ μ λ‘κΉ μ μ½κ° λ κ²μνκ² λ§λ λ€λ κ²μ λλ€.