ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kaggle Notebook 自定义模块:Dataset上传与版本更新

Kaggle Notebook 自定义模块:Dataset上传与版本更新 Kaggle 的 Notebook 用起来很爽免费 GPU、开箱即用的环境、无需自己配 CUDA但真正天天在上面跑项目的人很快会撞到一堵墙——你没法自然地管理自己的代码模块和文件。写个工具函数复制一次可以复制到第三个 Notebook 的时候就开始烦了想抽成一个utils.py上传上去又 import 不到改了一版代码重新传结果跑起来还是旧逻辑。这些事在本地开发里是基本功在 Kaggle 上却需要一套专门的处理方法。这篇文章想解决的就是这套方法在 Kaggle 上如何添加自己的模块和文件、如何修改已经上传的版本、以及怎么让这套流程不至于每天都在重复劳动。我按过来人的经验把它整理成从文件系统认知、到打包上传、到版本修改、到排错避坑的完整链路。不管你是刚注册 Kaggle 打第一场竞赛的新手还是已经在上面搭小型实验框架的老手都能从里面挑到自己用得上的部分。内容里提到的路径、命令和代码都可以直接抄去改。1. Kaggle Notebook 的文件系统到底长什么样1.1 三个绕不开的目录input、working 和系统盘刚上手 Kaggle 的人最容易犯的错是把本地开发的经验直接往平台搬——在某个路径下新建文件夹、写文件、下次打开还以为在里面。Kaggle 的容器其实是临时的它只给你两个有名字的目录需要记住。/kaggle/input是只读挂载区。你在项目右侧 Data 面板里加进来的每一个 Dataset 或 Competition 数据都会被挂载成/kaggle/input/数据集slug这样的一个子目录。这个目录的特点是权限只读你能读、能 import、能当成路径参数传但写不进去。这一点非常关键因为很多人第一反应是把自定义模块放到 input 里顺手改会发现报Read-only file system。/kaggle/working是可写工作区。它是 Notebook 的默认当前目录你!touch test.txt、%%writefile、或者用 Python 的open(x.txt,w)写文件默认都落在这一层。它的特殊性在于当你执行 Save Version或者用 Save Run All 提交一次运行之后/kaggle/working里的内容会被打包成这个 Notebook 的输出版本保存下来之后可以被其他 Notebook 挂载当成数据用。如果你只是开着 Interactive Session 跑跑就关掉这部分内容是不保证留下来的。第三类是系统盘比如/root、/usr/lib/python3.11/site-packages、/tmp。这些目录你能写在 session 存活期间但它们和/kaggle/working一样在 session 结束后清零。区别在于/kaggle/working有机会被 Save Version 固化下来系统盘基本没这个待遇。所以如果你依赖pip install装到 site-packages 里的东西session 一关就全没了这也是为什么 Kaggle 自定义模块推荐走 Dataset 而不是 pip 的原因。提示Interactive Session 有闲置超时机制超时后整个容器销毁/kaggle/working内未提交的内容会丢失。写重要代码一定要养成随手 Save Version 的习惯或者用 Dataset 版本固化。1.2 为什么你写的代码第二天就消失了几乎每个在 Kaggle 上认真写过几段代码的人都经历过一次我昨天写的工具函数去哪了。背后的原因不复杂Kaggle 的 Notebook 执行环境是一个一次性容器每次你打开、重新运行、Save Run All本质上都是启动一个干净的新容器只是把上次保存的 output 版本重新挂回来。这就带来两个后果。第一你临时写在/kaggle/working但没有提交保存的.py文件下次新 session 里看不到。第二即使你提交保存了那个文件是躺在某个版本快照里能不能被当前 Notebook 读到取决于你是否把那个版本或者后代版本作为输入挂进来。默认情况下Notebook 自己不会自动读取自己历史版本的 output。理解这一点之后添加自己的模块这件事的目标就很清楚了把代码变成一个稳定、只读、每次都能被挂在/kaggle/input下的资产。而 Kaggle 平台里最符合这个描述的载体就是 Dataset。把自建模块做成 Dataset是后面所有方案的核心不管你是通过网页上传、API 上传还是从 Notebook 输出转过来最后都汇聚到这一步。1.3 掌握目录边界后的文件放置原则理解上面两个目录之后我总结出一条给自己团队用的简单原则也分享给正在踩坑的你内容类型建议放置位置原因自建 Python 模块、工具函数库打包成 Dataset挂到/kaggle/input只读、可版本化、跨 Notebook 复用训练产出的模型权重、中间结果/kaggle/working需要频繁写且要随版本固化临时调试脚本、一次性实验代码/kaggle/working或%%writefile到当前目录用完即弃不需要复用第三方库尽量用 Kaggle 镜像自带的缺的用pip install临时装系统盘临时重启清空数据、配置 YAML视复用程度跨项目复用的配置放 Dataset和模块同理稳定是第一位这张表里最容易被忽略的是最后一行。很多人只把.py当模块把 YAML 配置文件、JSON schema、甚至小的参考词表当成随手写写藏在 Notebook cell 里。但只要它需要跨 Notebook 复用它就应该和模块一样走 Dataset。否则过两周你回来改又是一轮复制粘贴地狱。2. 把自己的模块打包成 Dataset 上传2.1 为什么选 Dataset 而不是写在 Notebook 里先说说为什么我不推荐把公用函数直接写在 Notebook 里。最直觉的理由是跨 Notebook 复用困难但更隐蔽的问题是测试和版本混乱。你的工具函数写在 cell 里改动了一个函数签名下游所有调用它的 Notebook 都不会报错提示只有你跑到那一步才发现参数不对。而在本地工程里这会被 IDE 用红色波浪线标出来在 Kaggle 里没人帮你盯。Dataset 方案的核心优势是把模块和使用模块的地方解耦。模块有自己独立的版本号改一次就产生一个新版本使用它的 Notebook 在 Data 面板里明确选择了某个版本改不改、什么时候改你自己控制。这种语义比复制粘贴清晰太多。另一个现实原因是共享。如果你想把工具函数给队友或者发布给竞赛社区Dataset 是 Kaggle 生态里天然的分发单元。一个 Dataset 链接甩过去别人挂载就能用不需要你把代码贴到 gist 再让人复制。2.2 本地目录组织与打包规范Dataset 就是一个目录。你上传什么结构挂载后就是什么结构。所以第一步是在本地把目录整理清楚。我给一个自己常用的最小模板my-kaggle-utils/ ├── kutils/ │ ├── __init__.py │ ├── io.py │ ├── metrics.py │ └── visualize.py ├── configs/ │ └── default.yaml ├── requirements.txt └── README.md这里有几个细节值得说清楚。第一把真正的模块代码放在一个同名子目录里比如kutils/并在里面放__init__.py。这样挂载后你可以from kutils import io而不是import io后者会和标准库冲突。子目录形式的包结构还能让你用相对导入from . import metrics组织大一点的代码更舒服。第二requirements.txt不一定要写 Kaggle 镜像已有的东西只写你额外依赖的。挂载后一句!pip install -q -r /kaggle/input/my-kaggle-utils/requirements.txt就能补齐环境。第三README.md不是摆设Kaggle 的 Dataset 页面会渲染它等于自带文档别人点进来一眼能看懂这是干什么的。打包的时候有两个选择直接把整个目录上传Kaggle 支持文件夹上传或者先压成 zip 再上传。我的经验是当文件数不多时直接上传目录更省事文件数多或者本地有隐藏文件时先 zip。因为 Kaggle 的文件夹上传对隐藏文件、某些编码文件名支持并不算完美zip 一步到位反而更稳。zip 上传后挂载路径是/kaggle/input/slug/xxx.zip需要自己在 Notebook 里解压这一点后面第 4 章会专门讲。2.3 网页端上传与版本控制上传流程本身不复杂但有几个容易踩的点。登录 Kaggle点左侧 Datasets → New Dataset会进入上传页面。这时候把刚才整理好的目录拖进去页面左侧会显示文件树。核对文件树是最重要的一步因为它决定了挂载后的路径结构。Kaggle 默认会把你的顶层目录名当成根但有时候会给你加一层同名嵌套看着挺迷惑。上传之前先看一眼不对劲就删掉重新拖。上传完成后在页面右侧填标题、slugURL 里那个唯一标识、描述然后点 Create。slug 最好自己起得短一点、语义化一点比如my-kaggle-utils因为后面在代码里写/kaggle/input/my-kaggle-utils全靠它起太长会天天打字。版本控制这件事值得专门讲。Dataset 只要改一次内容就要发一个新版本。上传页面右上角会有 New Version 入口进去后覆盖文件、或单独替换某个文件填一句 commit message点发布。Dataset 版本号会自增从 1 开始。挂载的时候Notebook 的 Data 面板默认用最新版本你也可以手动选某个旧版本。注意使用方 Notebook 挂载的永远是它所选的那个版本而不是最新版本。这意味着你发新版之后已经在跑的旧 Notebook 不会自动升级。这是个安全特性防止你上游一改、下游全崩但如果你确实想升级需要手动去 Data 面板切版本号很多人不知道这一点改了 Dataset 却发现 Notebook 里读取的还是老代码就在这儿卡住。2.4 在 Notebook 里挂载并 import挂载这一步在 Notebook 右侧的 Data 里搜索你刚上传的 Dataset 名字点加号即可。挂载完成后路径就出现在/kaggle/input/slug。然后 import# 挂载后路径固定建议写成常量避免到处硬编码 import sys UTILS_PATH /kaggle/input/my-kaggle-utils if UTILS_PATH not in sys.path: sys.path.append(UTILS_PATH) from kutils import io, metricssys.path.append这一句是必须的因为 Python 的 import 搜索路径默认不包含/kaggle/input下的任意目录。很多人 import 失败的第一反应是Dataset 没挂上其实大部分时候是路径没加。加路径的时候顺手做个if not in判断是为了防止你重复执行这个 cell 导致的重复条目虽然 Python 能容忍但会拖慢 import 检索。如果你走的是 zip 上传方案那这一层要多一步import zipfile, os ZIP /kaggle/input/my-kaggle-utils/my-kaggle-utils.zip DEST /kaggle/working/utils os.makedirs(DEST, exist_okTrue) with zipfile.ZipFile(ZIP) as z: z.extractall(DEST) sys.path.append(DEST)注意这里是解压到/kaggle/working而不是解压回/kaggle/input。因为 input 是只读的。这是 zip 方案和直接目录方案最大的区别也是新手最容易跟着教程写了半天、一看路径还是 read-only 报错的地方。3. 修改已上传模块的几种姿势3.1 通过网页重新发布新版本最省心模块写错了、想加新函数、修个 bug这是日常最高频的需求。最省心、最不容易出问题的做法就是回到 Dataset 页面走 New Version 流程。步骤和第一次上传差不多区别是页面会保留上一版的文件树你可以只替换改动的那几个文件而不是全量上传。填 commit message 的时候我建议写得具体一点比如 fix: metrics.f1 supports averageNone方便几个月后你翻版本历史时能一眼认出。发出版本后回到你的 Notebook记得手动把 Data 面板里的版本切到新号然后重新运行这里必须用 Restart Run All 或者至少重启内核只执行单个 cell 是不行的因为模块缓存在内存里第 3.4 节会详细解释。切版本这个动作很容易忘尤其版本号只差 1 的时候人在赶实验的时候经常以为自己切过了其实没切。这套流程的优点是稳、可回溯、对队友友好。缺点是步骤略多网页点来点去。如果你一天要改十次以上那就该上 API 了。3.2 用 Kaggle API 命令行更新Kaggle 提供了官方命令行工具kaggle可以自动化 Dataset 的版本发布。它不是 Python 包才叫这个名字的——pip install kaggle装下来的就是一个 CLI 加轻量库。基本配置是在本地生成一个~/.kaggle/kaggle.json里面放你的 API tokenKaggle 网站头像 → Settings → Create New API Token 就能下载。这个文件里包含账号信息注意不要提交到 Git。配置好之后更新一个 Dataset 版本就是kaggle datasets version -p ./my-kaggle-utils \ -m add metrics.auc with nan handling \ --dir-mode zip-p指定本地目录-m是 commit message--dir-mode zip表示把目录打成 zip 再上传不写这行会用默认模式。执行完会产生新版本号和网页操作等价。注意kaggle datasets version要求目录里已有一个符合 Dataset 元数据的结构或者是已在服务端存在的同一个 slug。如果你只想更新一个已有 Dataset本地目录名最好和 Kaggle 上的 slug 保持一致减少出错。第一次用建议拿一个小测试 Dataset 跑通整条链路再对生产模块动手。这套方式特别适合两类人一类是已经有本地开发习惯、把代码放在 Git 仓库里的一类是做 CI 自动发布的。配合 Git hook 或者简单的 Makefile你改完代码一条命令就能推 Kaggle 新版本全程不用开浏览器。我在做连续实验的时候用这套效率明显比网页上传高。3.3 在 Notebook 内直接改文件并验证还有一种临时改的姿势特别适合 debug直接在当前 Notebook 里把模块内容写到/kaggle/working用%%writefile或 Python 写文件的方式覆盖一份然后让 sys.path 指向这一份。比如%%writefile /kaggle/working/kutils_patch.py def add(a, b): return a b然后import sys sys.path.insert(0, /kaggle/working) import kutils_patch kutils_patch.add(1, 2)这种方式的好处是改完立即可测不用等 Dataset 版本发布坏处是它只活在当前 session重启就没了而且它和正式的 Dataset 版本会越走越远。所以我的经验是用它做临时验证不要用它做长期开发。验证成功之后再回到本地改文件、走第 3.1 或 3.2 的流程正式发布。否则过两天你会有一个谁也不知道以哪份为准的代码库。3.4 importlib.reload 与缓存陷阱这里要单独拎出来讲因为它是我明明改了啊系列故障里最常见的原因。Python 在第一次import X时会把X对象放进sys.modules缓存里。之后你再import XPython 直接返回缓存不会重新读磁盘。Kaggle 的 cell 执行是没有重新加载语义的即使你换了挂载 Dataset 的版本已经 import 过的模块对象还是老的。解决方式有三种按彻底程度排序第一种最彻底的方式是Restart Kernel Run All。内核重启后sys.modules清空所有模块重新从磁盘加载用的是当前挂载的版本。这是我改完模块后的首选代价是重跑整个 Notebook。第二种只想 reload 单个模块可以用import importlib, sys import kutils.metrics importlib.reload(kutils.metrics)但要注意reload只对顶层模块有效包下面嵌套的子模块要一个个 reload而且如果别的模块已经from kutils.metrics import f1把函数对象拿走了reload 之后那个已有引用不会变还是旧函数。第三种手动清缓存import sys for name in list(sys.modules): if name.startswith(kutils): del sys.modules[name]清完之后再import kutils就是新版本了。这个写法比 reload 更暴力但更可控我一般在调试时用。提示如果你在用%run或exec执行脚本情况会更复杂因为这些机制的执行缓存不在sys.modules里。一句话原则改模块就重启内核别和缓存斗智斗勇赢的永远不是你。4. 加载自定义文件的实操细节与坑4.1 sys.path 注入的正确写法与顺序问题sys.path是一个列表Python import 时会从前往后找。顺序很重要。如果你把自定义模块目录用append加到尾部而系统里恰好有个同名模块比如你起了个utils.py那么 Python 会先找到系统的那个你就会遇到我写的函数去哪了这种幽灵 bug。这种情况在 Kaggle 上并不罕见因为 Kaggle 镜像本身就装了一大堆库。所以推荐的做法是用insert(0, path)让自定义路径优先import sys UTILS /kaggle/input/my-kaggle-utils if UTILS not in sys.path: sys.path.insert(0, UTILS)配合命名规范进一步降低撞名概率。比如所有自定义模块都加统一前缀kutils_或者都放在kutils这个包里。别用utils、helpers、common这种通用词当顶层模块名因为它们撞车的概率真的很高。还有一个隐蔽点Kaggle 挂载的路径有时会带一层额外的目录。比如你上传的目录里再套一层同名目录结果就是/kaggle/input/my-kaggle-utils/my-kaggle-utils/kutils/。这时候你按/kaggle/input/my-kaggle-utils加路径就找不到包。所以在 Notebook 里第一次挂载新 Dataset 后我会习惯性地跑一句!ls /kaggle/input/my-kaggle-utils或者用 Python 的os.listdir看一眼确认层级之后再写路径。这一步花五秒钟能省掉半小时的抓耳挠腮。4.2 相对导入、包结构与init.py 的门道自定义模块一旦稍微成长起来就会想拆成多个文件。这时候包结构和相对导入就要处理好否则很容易撞上ImportError: attempted relative import with no known parent package。这个报错的原因很单纯你在顶层脚本里用了相对导入。比如你有一个kutils/__init__.py里写from . import metrics这是合法的因为kutils是一个包。但如果你把metrics.py单独拎出来执行它里面的from . import io就会炸因为它不知道自己属于哪个包。所以在设计上要遵守两条。第一包目录必须有__init__.py哪怕里面是空的。Kaggle 用的 Python 版本里虽然没有__init__.py的 namespace package 也能工作但显式声明更稳尤其是需要在__init__.py里做统一入口导出的时候。第二顶层入口和内部实现分离。比如你希望用户用from kutils import load_config那就在__init__.py里from .config import load_config内部实现藏在子模块里用户只用包名。# kutils/__init__.py from .io import load_csv, save_csv from .metrics import f1, auc __all__ [load_csv, save_csv, f1, auc]这样写的好处是用户不需要关心你内部怎么拆的改内部结构也不影响外部调用。对于要把模块分享给别人的场景这个 API 边界设计非常值。4.3 数据文件、配置文件的读取路径模块里如果带配置文件比如 YAML、JSON读取路径的写法需要绕一下。因为挂在/kaggle/input下的模块是只读的你不能像本地那样用相对路径open(configs/default.yaml)来打开——相对路径是相对于当前工作目录默认/kaggle/working不是相对于模块文件。这是初学时最容易搞混的点。正确做法是用__file__推导出模块自身所在目录# kutils/config.py from pathlib import Path import yaml CONFIG_DIR Path(__file__).resolve().parent.parent / configs def load_config(namedefault.yaml): with open(CONFIG_DIR / name, r, encodingutf-8) as f: return yaml.safe_load(f)Path(__file__).resolve().parent拿到的是当前模块文件所在目录parent.parent就是上一层这里指向包外的configs/。这样无论你在什么工作目录下运行都能找到配置文件。同一套逻辑也适用于加载模型权重、词表、小的参考数据。原则只有一个不要用 cwd 相对路径用__file__相对路径。在本地开发时这个规则也适用因为一旦你把代码挂成服务或者放到别的目录跑cwd 相对路径立刻失效而__file__相对路径稳稳的。4.4 常见报错速查表我把这几个章节里提到的报错整理成一张表方便你下次遇到直接对号入座。这些坑我基本每个都踩过至少一次。报错信息常见原因处理方式ModuleNotFoundError: No module named kutils没加sys.path或路径层级不对先!ls /kaggle/input/slug确认层级再sys.path.insert(0, ...)ImportError: attempted relative import with no known parent package在顶层脚本里用了from . import x改为绝对导入或把执行入口改成走包的方式OSError: [Errno 30] Read-only file system想往/kaggle/input里写改成写到/kaggle/working改了 Dataset 版本但行为没变内核缓存了旧模块Restart Kernel 后 Run All改了 Dataset 版本但读到旧内容Data 面板没切版本号手动切挂载版本FileNotFoundError: default.yaml用了 cwd 相对路径改成Path(__file__).parent推导模块和标准库/第三方库同名sys.path顺序 命名太通用用insert(0, ...)模块加前缀Session 重启后pip install的库消失装到系统盘了在 Notebook 开头重装或写入 requirements这张表里排前两行的报错几乎占了我在 Kaggle 上自定义模块问题的八成。剩下的两成里一半是缓存问题一半是版本没切。养成改模块 → 重启内核 → 确认版本三连能干掉绝大多数诡异现象。5. 让工作流顺手的几个工程化技巧5.1 用 %run 快速调试单文件如果你只是在调试某个脚本、还没打算把它固化成包%run会比 import 快很多%run /kaggle/input/my-kaggle-utils/scripts/quick_test.py%run会把脚本当成当前命名空间的一部分执行里面定义的变量和函数会直接出现在当前 Notebook 里方便你接着调。它的好处是不用管sys.path、不用处理包结构坏处是它不进入sys.modules不会触发缓存机制所以你改完再%run一次就是新代码这点对于快速迭代反而有利。但%run也有隐式坑它会污染当前 cell 的命名空间如果脚本里定义了一个和 Notebook 变量同名的东西会被悄悄覆盖。所以用%run做一次性调试可以用它当作正式的模块加载机制不建议。模块化还是老老实实走包和 import。5.2 一套可以直接抄的目录模板我把上面所有内容落到一个具体的目录结构你新建 Dataset 的时候可以照着来my-kaggle-utils/ ├── kutils/ │ ├── __init__.py # 统一 API 出口 │ ├── io.py # 读写、路径工具 │ ├── metrics.py # 指标 │ ├── viz.py # 绘图 │ └── _internal/ # 内部实现外部不直接 import │ └── __init__.py ├── configs/ │ └── default.yaml ├── scripts/ │ └── quick_test.py # 用来 %run 的调试脚本 ├── requirements.txt └── README.md外层kutils/是用户看到的部分_internal是内部实现用下划线前缀明确告诉别人别直接引用。configs和scripts放在包外面一方面能让配置文件加载逻辑更直观parent.parent / configs另一方面也避免包目录里塞太多非代码文件影响 import 扫描。在使用的 Notebook 里一个标准的开头 cell 大概长这样import sys, os UTILS /kaggle/input/my-kaggle-utils if UTILS not in sys.path: sys.path.insert(0, UTILS) # 若走 zip 上传额外解压 # import zipfile # with zipfile.ZipFile(f{UTILS}/my-kaggle-utils.zip) as z: # z.extractall(/kaggle/working/utils) # sys.path.insert(0, /kaggle/working/utils) from kutils import load_config, f1 cfg load_config() print(cfg)这段代码基本上每个新项目我都会开头粘贴一次改一下 slug 就能用。5.3 版本命名与回滚的实操建议Dataset 版本是自增数字1、2、3 一路下去短期够用但项目一长你会发现这个 v17 到底是哪一版。我在 commit message 上有个自己的小规范值得一试用type: short-desc前缀type 固定几个值比如feat、fix、refactor、docs。这样半年后你翻版本历史一眼能定位是哪一次引入回归 bug 的。回滚其实很方便因为旧版本都还在。如果新版出了问题把使用方 Notebook 的 Data 面板切回上一个版本号、重启内核就立刻恢复。不需要重新上传。这也正是把代码做成 Dataset 的核心价值每次改动都有记录任何一次改动都可以一键退回。这和本地一个git revert的意义是一样的。有个小坑要提前知道如果你在同一个 Dataset 上反复发版本旧版本占用的空间不会自动清Kaggle 对 Dataset 的容量和版本数是有限制的。定期把确实不再用的旧版本删掉或者干脆开一个新的 Dataset 承接大重构比一路堆到几十个版本要清爽。5.4 关于自动运行和长期维护的心得Kaggle 有一个 Save Run All提交运行的能力可以让 Notebook 离线跑完、产出固定版本。这个机制配合自定义模块使用时有一个容易忽略的细节提交运行的时候它读取的是挂载的 Dataset 版本且这个版本会被锁定在那个 commit 里。这意味着你在 Notebook 里切新版本后如果不重新提交一次下游依赖这个 Notebook 输出的人拿到的还是老模块跑出来的结果。所以我的经验是做长期项目的时候最好给模块更新和Notebook 重新提交这两件事绑定一个动作清单更新 Dataset 版本 → 打开使用方 Notebook → 切版本 → Restart Run All 验证 → Save Version。整个过程走一遍才算一次完整的模块升级。省的中间某一步跳过下游全乱。另外一点如果用 Dataset 承接模块记得给 Dataset 本身写一个清楚的说明包括每个版本改了什么、兼容性有没有破坏。这在你一个人玩的时候显得多余一旦团队协作或者你隔几个月回来接手这份说明就是救命稻草。6. 实操中的经验与坑前面讲了完整的流程这里再补几个分散的经验点都是我在实际使用中踩过或者被问过很多次的问题单独拎出来会更有参考价值。第一个是关于命名空间冲突。Kaggle 镜像里预装了海量的库utils、common、data这类名字特别容易撞。有一次我给一个模块起名io表面上没报错但实际 import 到的是 Kaggle 环境里某个别的模块函数签名完全对不上。后来我把所有自定义模块统一加kutils_前缀问题彻底消失。这个改名成本很低收益很高建议一开始就做。第二个是关于挂载多个 Dataset 的路径管理。实际项目里你可能同时挂好几个 Dataset一个放代码、一个放数据、一个放参考词表。它们的路径都在/kaggle/input下混在一起写会很难维护。我的做法是在 Notebook 开头统一定义一个字典PATHS { utils: /kaggle/input/my-kaggle-utils, data: /kaggle/input/my-competition-data, dict: /kaggle/input/my-dictionary, }后面任何地方引用路径都从PATHS里取改路径只改这一处。这比在 Notebook 里到处散落硬编码路径要清晰太多尤其是当你的 slug 改过名或者中间加了一层目录的时候。第三个是关于 requirements 和镜像版本的博弈。Kaggle 镜像的库版本会不定期更新你今天pip install的某个库明天可能和镜像里的某个库冲突。我的经验是尽量不装镜像已有的东西只在确实缺库时才装并且把版本 pin 在 requirements 里。如果发现自己要 pip 装一堆东西就要反思是不是应该把这些依赖固化到自定义模块的阶段或者干脆换个镜像。频繁 pip 安装还会拉长 Notebook 启动时间在竞赛抢时间的时候很吃亏。第四点是关于大文件的处理。有朋友把几百兆的模型权重也塞进代码 Dataset 里结果版本一多上传和挂载都变慢。正确做法是代码和数据分开管理轻量的代码、配置、词表放一个 Dataset模型权重、中间结果这类大文件放在 Notebook 的 output 里或者单独开一个 Dataset 放数据。这样代码 Dataset 的版本迭代很快数据 Dataset 稳定不动各自独立演进互不干扰。第五点聊一个比较少被提到但很实际的问题如何在多人协作时避免撞版本。如果几个人共用一个 Dataset 发版本很容易出现我刚准备上传发现版本号被别人推进了 3 个。我的做法是核心代码尽量由一个人维护上游其他人 fork 出自己的 Dataset 或者以只读方式引用。上游改动谨慎、缓慢下游按需切版本。这种上游稳、下游灵活的分工比所有人都往一个 Dataset 里推要清晰得多。最后聊一个操作习惯。我现在的做法是在本地开一个 Git 仓库开发模块提交测试通过后用 Kaggle API 一条命令推到 Dataset 新版本。这个链路把本地开发的便利性和 Kaggle 上的复用性打通了本地可以用 IDE 补全、跑单元测试Kaggle 上只是把稳定的代码当成依赖来引用。写过几次之后你会发现自定义模块这件事一旦走上正轨反而是整个 Kaggle 工作流里最让人省心的部分比起每次打开 Notebook 都要重新复制一遍工具函数体验完全不是一个量级。
返回列表