본문 바로가기

개발하자

나중을 위해 주피터(IPython) 노트북 세션을 절이거나 저장하는 방법

반응형

나중을 위해 주피터(IPython) 노트북 세션을 절이거나 저장하는 방법

많은 시간이 소요되는 계산을 수행하면서 주피터/아이피톤 노트북에서 더 큰 데이터 분석을 수행하고 있다고 가정해 보겠습니다. 그렇다면 어떤 이유에서인지 주피터 로컬 서버 I를 종료해야 하지만, 시간이 많이 걸리는 모든 계산을 다시 할 필요 없이 나중에 분석 작업으로 돌아가고 싶습니다.


제가 하고 싶은 일은 주피터 세션 전체(모든 팬더 데이터 프레임, np.array, 변수 등)를 저장하거나 저장하여 이전과 동일한 상태로 세션으로 돌아갈 수 있다는 것을 알고 안전하게 서버를 종료할 수 있도록 하는 것입니다.

기술적으로 가능하기는 하나요? 제가 간과한 내장 기능이 있습니까?


답변에 따라 어떤 것이 "경량 피클"이어야 하는지가 있다. 그러나 다음과 같이 변수를 수동으로 저장해야 합니다:

# 기분 전환을 위해 r

내가 원하는 것에 꽤 가깝지만 수동으로 해야 하고 다른 세션을 구별할 수 없기 때문에 유용성이 떨어진다.




(이것을 실제 답으로 제시하기보다는 코멘트를 하고 싶지만, 코멘트를 하기 위해서는 평판이 더 필요합니다.)

대부분의 데이터 유사 변수를 체계적인 방법으로 저장할 수 있습니다. 내가 주로 하는 일은 모든 데이터 프레임, 배열 등을 저장하는 것이다. 노트의 처음에, 선언한다

backup = pd.HDFStore('backup.h5')

생성할 때 새 변수를 저장합니다

backup['var1'] = var1

마지막에, 아마 할 수 있는 좋은 생각일거야

backup.close()

서버를 끄기 전에. 다음에 노트북을 계속 사용하려면:

backup = pd.HDFStore('backup.h5')
var1 = backup['var1']

솔직히 말해서, 나는 ipython 노트북에도 내장된 기능을 선호한다. 이런 식으로 모든 것을 저장할 수는 없고(예를 들어, 오브젝트, 연결), 그렇게 많은 보일러 플레이트 코드로 노트북을 정리하는 것은 어렵다.




이 질문은 다음과 관련이 있습니다:

개별 세포의 결과를 저장하기 위해 는 유용하다.

%%cache longcalc.pkl var1 var2 var3
var1 = longcalculation()
....

노트북을 다시 실행하면 이 셀의 내용이 캐시에서 로드됩니다.

이것은 당신의 질문에 정확하게 대답하는 것은 아니지만, 모든 긴 계산의 결과가 빠르게 복구될 때 충분할 것이다. 이것은 노트북 위에 있는 실행 버튼을 누르는 것의 조합으로 나에게 실행 가능한 해결책이다.

캐시 마법은 전체 노트북의 상태를 저장할 수 없다. 내가 알기로는 아직 "노트북"을 재개할 수 있는 다른 시스템은 없다. 이것은 파이썬 커널의 모든 이력을 저장하는 것을 요구한다. 노트북을 로드하고 커널에 연결한 후 이 정보를 로드해야 합니다.




나는 ()가 너의 질문에 대답을 잘 한다고 생각한다.

노트북 세션을 저장하는 데 사용:

import dill
dill.dump_session('notebook_env.db')

노트북 세션을 복원하는 데 사용:

import dill
dill.load_session('notebook_env.db')

()




절일 수 없는 물체에 대해 실패하고 그러한 물체를 단순히 무시하도록 구성할 수 없기 때문에, 나는 뉴로모픽 엔지니어링 주피터 노트북 클래스 칩 연습에 사용되는 정적 함수 한 쌍을 작성했다.

이 접근 방식은 유용한 게시물을 기반으로 합니다

사용 예:

from ne1 import savevars,loadvars
a=1
b=[2,3]
c='string'
o=(i for i in []) # make generator that cannot be pickled

savevars('testvars')
del a,b,c
loadvars('testvars')
print(a)
print(b)
print(c)

출력:

[INFO]: 2023-10-02 08:28:32,878 - NE1 - saved to testvars.dill variables [ a b c ] (File "/home/ne1/CoACH-labs/ne1.py", line 132, in savevars)
[WARNING]: 2023-10-02 08:28:32,879 - NE1 - could not pickle: ['o'] (File "/home/ne1/CoACH-labs/ne1.py", line 134, in savevars)
[INFO]: 2023-10-02 08:28:32,881 - NE1 - from testvars.dill loaded variables ['a', 'b', 'c'] (File "/home/ne1/CoACH-labs/ne1.py", line 158, in loadvars)
1
[2, 3]
string

아래의 코드를 사용하기 위한 완성도를 위해 로깅 메시지를 포맷하는 커스텀 로거도 넣었습니다. 이 로깅 출력을 원하지 않을 경우 다음으로 대체합니다

기능:

def savevars(filename):
    """
    saves all local variables to a file with dill
    
    :param filename: the name of the file. The suffix .dill is added if there is not a suffix already.
    """
    if filename is None:
        log.error('you must supply a filename')
        return
    from pathlib import Path
    p=Path(filename)
    if p.suffix=='': # if suffix is missing add .dill
        p = p.parent / (p.name + _DILL)

    import inspect,dill
    locals=None
    frame = inspect.currentframe().f_back
    try:
        locals = frame.f_locals
    finally:
        del frame
    if locals is None: return

    data={}
    could_not_pickle=[]

    from types import ModuleType
    s=f'saved to {p} variables [ '
    for k,v in locals.items():
        # don't try to pickle any pyplane objects
        if k.startswith('_') or k=='tmp' or k=='In' or k=='Out' or hasattr(v, '__call__') \
            or isinstance(v,ModuleType) or isinstance(v,logging.Logger): 
            continue
        try:
            if not dill.pickles(v):
                could_not_pickle.append(k)
                continue
        except:
            could_not_pickle.append(k)
            continue
        s=s+k+' '
        data[k]=v
    s=s+']'
    try:
       with open(p,'wb') as f:
            try:
                dill.dump(data,f)
                log.info(f'{s}')
                if len(could_not_pickle)>0:
                    log.warning(f'could not pickle: {could_not_pickle}')
            except TypeError as e:
                log.error(f'\n Error: {e}')
    except Exception as e:
        log.error(f'could not save data to {p}')

그 기능을

def loadvars(filename):
    """ Loads variables from file into the current workspace
    
    :param filename: the dill file to load from, e.g. lab1. The suffix .dill is added automatically unless there is already a suffix.

    This function loads the variables found in filename into the parent workspace.
    """
    import dill
    from pathlib import Path
    p=Path(filename)
    if p.suffix=='': # if suffix is missing add .dill
        p = p.parent / (p.name + _DILL)
    if not p.exists:
        log.error(f'{p} does not exist')
        return
    try:
        with open(p,'rb') as f:
            data=dill.load(f)
            log.info(f'from {p} loaded variables {list(data.keys())}')
            import inspect
            try:
                frame = inspect.currentframe().f_back # get the workspace frame (jupyter workspace frame)
                locals = frame.f_locals # get its local variable dict
                for k in data:
                    try:
                        locals[k] = data[k] # set a value in it
                    except Exception as e:
                        log.error(f'could not set variable {k}')
            finally:
                del frame
    except Exception as e:
        log.error(f'could not load; got {e}')

pycharm에서 작동하는 포맷 및 코드라인 하이퍼링크를 사용하는 사용자 지정 Logger:

import logging
# general logger. Produces nice output format with live hyperlinks for pycharm users
# to use it, just call log=get_logger() at the top of your python file
# all these loggers share the same logger name 'Control_Toolkit'

_LOGGING_LEVEL = logging.DEBUG # usually INFO is good

class CustomFormatter(logging.Formatter):
    """Logging Formatter to add colors and count warning / errors"""
    # see https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output/7995762#7995762

    # \x1b[ (ESC[) is the CSI introductory sequence for ANSI https://en.wikipedia.org/wiki/ANSI_escape_code
    # The control sequence CSI n m, named Select Graphic Rendition (SGR), sets display attributes.
    grey = "\x1b[2;37m" # 2 faint, 37 gray
    yellow = "\x1b[33;21m"
    cyan = "\x1b[0;36m" # 0 normal 36 cyan
    green = "\x1b[31;21m" # dark green
    red = "\x1b[31;21m" # bold red
    bold_red = "\x1b[31;1m"
    light_blue = "\x1b[1;36m"
    blue = "\x1b[1;34m"
    reset = "\x1b[0m"
    # File "{file}", line {max(line, 1)}'.replace("\\", "/")
    format = '[%(levelname)s]: %(asctime)s - %(name)s - %(message)s (File "%(pathname)s", line %(lineno)d, in %(funcName)s)'

    FORMATS = {
        logging.DEBUG: grey + format + reset,
        logging.INFO: cyan + format + reset,
        logging.WARNING: red + format + reset,
        logging.ERROR: bold_red + format + reset,
        logging.CRITICAL: bold_red + format + reset
    }

    def format(self, record):
        log_fmt = self.FORMATS.get(record.levelno)
        formatter = logging.Formatter(log_fmt)
        return formatter.format(record).replace("\\", "/") #replace \ with / for pycharm links


def get_logger():
    """ Use get_logger to define a logger with useful color output and info and warning turned on according to the global LOGGING_LEVEL.

    :returns: the logger.
    """
    # logging.basicConfig(stream=sys.stdout, level=logging.INFO)
    logger = logging.getLogger('NE1') # tobi changed so all have same name so we can uniformly affect all of them
    logger.setLevel(_LOGGING_LEVEL)
    # create console handler if this logger does not have handler yet
    if len(logger.handlers)==0:
        ch = logging.StreamHandler()
        ch.setFormatter(CustomFormatter())
        logger.addHandler(ch)
    return logger

log=get_logger()

반응형