科研项目中实验记录工具
Project description
FineCache
科研项目中实验记录工具。
在科研项目(尤其是在深度学习项目)中代码运行的时间都比较长,有复杂的数据预处理步骤和诸多配置。我发现自己经常出现实验运行完成后,都忘记自己改了哪些东西。
本项目旨在保存一些项目的基本修改信息,以供分析和复现。
按照预期的方式使用本项目将为每次实验生成单独的文件夹,文件夹中将包含:
information.json
: 必要的信息。文件至少包含以下字段,也能存储添加的其它信息。commit
: HEAD的commit IDproject_root
: git项目的根目录patch_time
: 记录patch的时间main_start
: main开始的时间main_end
: main结束的时间tracking_records
: 额外记录的文件名列表(相对于项目根目录的路径)。
console.log
: 记录的被装饰函数的输出。changes.patch
: 与HEAD的差距patch。- 其它
FineCache.tracking_files
中记录的文件。 - 以pickle存储的中间结果文件。
安装
pip install FineCache
依赖 git。
详细说明
FineCache(self, base_path=None, template: str = "exp{id}", **kwargs)
-
base_path
。基础目录,默认为当前目录。在初始化时,将在base_path
下创建以template
命名自增的实验文件夹,后续在该文件夹下保存内容。可用
self.dir
获取创建的实验文件夹。 -
template
。文件夹命名模板字符串。其中{id}
为自增的序号,可以以str.format的语法插入其它变量,并通过**kwargs
传入具体的参数。
fc = FineCache('.exp_log', "exp{id}-{name}", name="DeepLearningModel")
# 运行一次将产生 `./.exp_log/exp1-DeepLearningModel/`
由于需要正则表达式匹配
{id}
以自增,所以应该尽量避免在{id}
的周围没有间隔符地放入太多其他变量。
FineCache.information
这个变量是一个Dict,并在 FineCache.record_main
结束时保存到文件夹中。
在 FineCache
初始化时,就已经存储了以下变量:
commit
: HEAD的commit ID。project_root
: git项目的根目录。
在其它函数的使用中,也会向此字典存储相应的变量。
FineCache.tracking_files
这个变量是一个List,其元素为需要保存的配置文件或任何其它文件。 可以使用正则表达式匹配直接的相对路径(不含./
开头)。
FineCache.save_changes(self, filename='changes.patch', in_dir=True)
一般认为应该在类初始化后立即调用。保存当前代码到HEAD的所有改动到对应的文件,并向 information
中写入时间。
filename
为保存文件名。in_dir
。默认为True
。即保存是否保存到FineCache对象的dir文件夹下。如果设置为False
,则保存到仅由filename
指定的路径中。
恢复时,首先恢复到 commit ID 对应的提交代码,再使用
git apply <patch_file>
命令应用补丁文件。
FineCache.record(self)
可同时作为装饰器或上下文管理器使用。
# fc = FineCache()
@fc.record()
def main():
pass
# 或
with fc.record():
pass
一般放在程序的主流程中,记录流程的运行开始时间和结束时间,并在主流程结束后调用 information
和 tracking_files
对应的内容写入目录。
FineCache.cache(self, filename_hash: Callable = None, in_dir=True)
这个装饰器能缓存函数的运行结果和参数。每次调用时,检查是否存在已缓存结果,如果存在则直接给出缓存结果。
缓存结果默认以pickle文件形式存储在 dir 文件夹下。
-
filename_hash
接受一个函数,控制如何产生的缓存文件名。当设置in_dir
时,指定缓存文件的完整路径。默认方法是对参数计算md5值,并以
f"{func_name}({str_args};{str_kwargs}).pk"
的方式组装,应该足以应对大多数的情况。需要注意的是,类的方法的首个参数是self,即类的对象。下面是一个使用
args_hash
的示例。 -
in_dir
。默认为True
。即保存是否保存到FineCache对象的dir文件夹下。如果设置为False
,则保存到仅由filename_hash
指定的路径中。
# fc = FineCache()
class DataLoader:
@fc.cache(filename_hash=lambda f, *a, **kw: f"{a[0].__class__.__name__}.{f.__name__}.pk")
def load(self):
pass
# 将产生缓存文件 "DataLoader.load.pk"
DataLoader().load()
Note: 所使用的缓存格式,目前仅支持用Pickle的形式进行存储。对于不支持 pickle 的函数参数,将会跳过存储;对于不支持 pickle 的函数运行结果,将会报错。
cache后的函数可以动态修改其中的参数;其可修改的参数定义如下:
filename_hash
和in_dir
。等同于cache的参数。agent
。默认为PickleAgent。具体请查看FineCache/CachedCall.py
中的定义。fine_cache
。是对FineCache对象的映射。
其它函数
FineCache.save_console(_self, filename: str = "console.log", in_dir=True)
也可以同时作为装饰器或上下文管理器使用。
在不影响代码段中向stdout的输出的同时,将输出的内容保存到对应的文件。
filename
为保存文件名。in_dir
。默认为True
。即保存是否保存到FineCache对象的dir文件夹下。如果设置为False
,则保存到仅由filename
指定的路径中。
示例
参见 examples/
。