> ## Documentation Index
> Fetch the complete documentation index at: https://starforge.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 管理数据集

> 本地预处理 → 版本化上传 → 作业自动分发到共享缓存

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
sf dataset prepare gsm8k-zh                     # 本地预处理
sf dataset push gsm8k-zh v2 ./out/gsm8k-zh      # 作为版本 v2 上传
sf submit my-grpo --train-dataset alice/gsm8k-zh@v2 --train-data train.parquet
```

平台数据集一次解决三件事：**版本化**，让训练指向一个确切的版本，而不是磁盘上碰巧存在的那份；
**分发**，作业启动时自己拉进集群共享缓存，而不用有人挨个节点 scp；
**权限**，谁能用它是数据集自己的属性，而不是文件系统的属性。

## 三步走

<Steps>
  <Step title="本地预处理">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    sf dataset prepare              # 列出可用的预处理脚本
    sf dataset prepare gsm8k-zh     # 跑 common/data/prepare_gsm8k_zh.py
    ```

    预处理脚本按约定放在 `common/data/prepare_*.py`，产出本地目录（parquet / jsonl）。
  </Step>

  <Step title="版本化上传">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    sf dataset push gsm8k-zh v1 ./out/gsm8k-zh        # 私有（默认）
    sf dataset push gsm8k-zh v1 ./out/gsm8k-zh --public   # 公开给全平台引用
    ```

    上传到对象存储（MinIO / S3），流式分片 + SHA256 校验 + 断点续传（中断后重跑跳过已传文件）。版本**不可变**——同名版本不能覆盖。
  </Step>

  <Step title="训练中引用">
    推荐写进实验 config：

    ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    data:
      train:
        dataset: alice/gsm8k-zh@v2      # <owner>/<name>[@version]，省略版本取最新
        file: train.parquet
    ```

    或提交时临时覆盖：

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    sf submit my-exp --train-dataset alice/gsm8k-zh@v2 --train-data train.parquet
    ```

    作业启动时平台把数据集拉到**集群共享缓存**（带完整性校验，损坏自动重拉）并注入 `<NAME>_DATA_DIR` 环境变量；`--train-data` 写数据集内的相对文件名即可。
  </Step>
</Steps>

## 写说明（数据集卡片）

一个只有名字的数据集，对上传者之外的所有人都是黑盒 —— 而拿错数据的代价是几百 GPU 小时。
把说明写进数据目录的 `README.md`，`sf dataset push` 会连同数据一起发上来：

```markdown theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# gsm8k-zh

从 GSM8K 改写的中文数学题，已按题干去重。

## 字段

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `question` | string | 题干 |
| `answer` | string | 含推理过程的参考解 |

## 怎么来的

`common/data/prepare_gsm8k_zh.py`，翻译后人工抽检 200 条。
```

事后单独改说明不用重推数据：

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
sf dataset card alice/gsm8k-zh -f README.md
```

首段会被摘成一句话，显示在列表每一行上；正文在控制台的**说明**页签里渲染。

## 管理

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
sf dataset ls                                  # 可见数据集（公开的 + 自己的）
sf dataset visibility gsm8k-zh --public        # 改可见性（owner 或 admin）
```

控制台 **数据 → 数据集**（`/data`）每行直接给出说明、最新版本、文件数、体积、格式与
更新时间 —— 挑数据集不用一个个点开试。点进去是四个页签：

| 页签 | 回答的问题                                      |
| -- | ------------------------------------------ |
| 说明 | 这份数据是什么、字段有哪些、怎么来的                         |
| 文件 | 这一版装了什么、多大、校验和是多少                          |
| 预览 | 字段是什么类型、空值多不多、文本大概多长（判断 `max_seq_len` 够不够） |
| 使用 | 被多少个作业引用过 —— 也就是「能不能换版本 / 清理」              |

### parquet

parquet 是平台上最常见的训练数据格式，预览开箱可用（`pyarrow` 随控制台一起装，
不是可选依赖）。它比 jsonl / csv 多给两件事：

* **总行数**。写在文件尾部的 footer 里，读几 KB 就有。jsonl / csv 要全扫才知道，
  所以那两种格式这里显示「—」，不猜一个数。
* **字段的声明类型**（`int64` / `string` / `timestamp[us]` …）。它比按前几行样本猜出来的
  准：一列样本恰好全是整数不代表它是整数列，一列样本全是 null 也不代表它没有类型。

平台只读 footer + 第一个 row group，总流量有上限。**行组特别大的文件（写入时常配成
64–128 MB 一组）读不到样例行**，这时字段与行数照常显示，样例行位置给一句说明 ——
那两样只花 footer 的几 KB，不该跟样例行一起丢掉。

<Note>
  预览里的**字段长度取自截断之前的原始值**。样例单元格下发到浏览器时会截到 160 字符，
  照样例算出来的「平均长度」永远等于截断上限，那个数没法用来判断 `max_seq_len`。

  「被 N 个作业引用」是全平台口径；下面的作业名单仍然只列你本来就看得到的那些。
</Note>

<Note>
  数据集清单（含预签名 URL）在**提交时**生成并写进作业包——作业侧不需要对象存储凭据，也不需要能访问 console，少一个运行期依赖就少一处失败点。
</Note>

## 敏感数据扫描

数据集发布后，对账任务会扫描它一次，结果显示在数据集详情页。

**产出的是报告，从不改写你上传的数据。** 这条线业内一致——Cloud DLP 的 `inspect` 和
`deidentify` 是你分别调用的两个操作，Macie 只报告不碰对象。在这里理由更硬一层：回流缓冲区
是平台自己产生的，改写它是平台的事；**训练集是你的材料**，静默改写它会改变模型学到什么、
不可逆、而且事后没人解释得清一个结果为什么是那样。

要清洗，用 **Processing Run**：读原材料、跑你自己的处理、发布成新版本——你的代码，
在平台里跑，带全程血缘。

### 它抽样，并且如实说抽了多少

一份一百 GB 的数据集不可能在提交路径上读完。扫描读若干个有界窗口，**并报告读了多少行**。
抽样扫描永远不能说"干净"，只能说"我读到的部分里没发现"——一份不写抽样量的报告，
迟早会被人当成证据引用。

窗口是**分散在文件里**取的，不是从头部取。一个有问题的导出通常是追加在后面的，
而测试样例往往在最前面——只读头部会系统性地漏掉最该抓到的那种情况。

### 置信度，不是布尔

每条规则带置信度。`api_key`、`private_key`、过了校验位的身份证号是 `high`；
邮箱、电话是 `medium`；**通用长 token 规则是 `low`——它会打中代码语料里的每一段 base64
和每个 git SHA**。

所以拦截策略（`FORGE_DATA_SCAN_POLICY=block`）**只对 high 生效**。一个对低置信命中开火的
门禁，一周之内就会被关掉，连带把有用的那一半也关掉。

### 自定义词表

`FORGE_DATA_SCAN_DENY_TERMS` 加本部署自己的敏感词（客户号、案件号），
`FORGE_DATA_SCAN_ALLOW_TERMS` 压掉已知误报。

**只能填词，不能填正则。** 在设置框里粘一段正则，就等于让一次配置改动把后台任务挂死——
Python 的 `re` 没有超时。平台自己转义编译。Presidio 的 deny list 是同样的设计。

## 空间（不是 train/val）

作业要读、但不拿来训练的资料——内部文档、参考 PDF、任何脚本该看见的东西——放在
**空间**里：在控制台建一个目录，把文件拖进去。它没有版本，当前内容就是它的内容。

```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
data:
  volumes:
    - alice/legal-docs
```

每个空间以只读方式出现在容器的 `$VOLUMES_DIR/<name>`。未经 owner 开启，任何人都
不能下载里面的文件，且在任何设置下都没有预览。详见控制台的空间页面。

## 与 HuggingFace 数据集的关系

config 里直接写 HF dataset id（如 `nvidia/OpenMathInstruct-2`）也可以：提交时平台做 HF 预检（gated 数据集校验你的授权）。平台数据集适合**内部数据**与**预处理后的衍生数据**——不用推 HF、权限留在内网。
