Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,37 @@ All notable changes to ForgeLM are documented here.

## [Unreleased]

### Added
### Added — Phase 11.5 (Ingestion / Audit Polish, targeting v0.5.1)

Operational polish on top of `v0.5.0`'s ingestion + audit surface — no new training capabilities, but materially better handling for large corpora and a cleaner CLI shape. All 12 follow-ups carved out of Phase 11's review backlog.

- **`forgelm audit PATH` subcommand** — Promotes the `--data-audit` top-level flag to a first-class subcommand with `--verbose`, `--near-dup-threshold`, and its own `--output` default (`./audit/`). The legacy `forgelm --data-audit PATH` flag keeps working as a deprecation alias and logs a one-line notice; existing CI pipelines need no changes. Removal targeted no earlier than `v0.7.0`.
- **LSH-banded near-duplicate detection** (`find_near_duplicates`, `_count_leaked_rows`) — Pigeonhole-banded LSH (default `bands = threshold + 1`) drops within-split + cross-split scans from `O(n²)` to ~`O(n × k)`. Recall stays exact at the default Hamming threshold; brute-force fallback remains for edge thresholds where bands shrink below 4 bits. Unblocks audits on 100K+ row corpora.
- **Streaming `_read_jsonl_split`** — The audit's JSONL reader is now a generator yielding `(row, parse_err, decode_err)`; `_audit_split` consumes it row-by-row via a `_StreamingAggregator` so RAM stays bounded on multi-million-row splits. Per-line tolerance semantics (parse errors, decode errors, non-dict rows) preserved.
- **Token-aware ingestion** (`--chunk-tokens`, `--tokenizer`, `--overlap-tokens`) — Optional flags on `forgelm ingest` size chunks against an HF `AutoTokenizer.encode` instead of raw character counts, so chunks line up with `model.max_length` exactly. `--tokenizer` is required with `--chunk-tokens` (we refuse to default to a hidden vocab because the chunk count would silently differ per-model). `trust_remote_code=False` is hard-pinned for safety.
- **PDF page-level header / footer dedup** (`_strip_repeating_page_lines`) — Lines that recur as the first or last non-empty line on ≥ 70 % of a PDF's pages (company watermarks, page numbers, copyright lines) are stripped automatically before chunking. Reduces audit `near_duplicate_pairs` noise on long policy / book PDFs. Skipped on documents shorter than 3 pages.
- **PII severity tiers** — Audit JSON now carries a `pii_severity` block (`total`, `by_tier`, `by_type`, `worst_tier`) alongside the flat `pii_summary`. Tiers map regulatory weighting: `credit_card` / `iban` → critical (PCI-DSS), national IDs → high (GDPR Art. 9), `email` → medium, `phone` → low. The aggregate notes line leads with the worst tier (`WORST tier: CRITICAL`) so reviewers cannot miss it.
- **`summarize_report` truncation policy** — Default `verbose=False` folds zero-finding splits into a single tail line so multi-split summaries stay short; `--verbose` on the new `audit` subcommand reverses this for full output. Has no effect on the on-disk JSON report.
- **Structured ingestion notes** — `IngestionResult.extra_notes` keeps the human-readable list; new `notes_structured: {key: value}` (and an explicit `pdf_header_footer_lines_stripped` field) carries machine-readable counts for CI/CD consumers. JSON output exposes both.
- **Wizard "ingest first" entry point** — `_offer_ingest_for_directory` + `_prompt_dataset_path_with_ingest_offer`: BYOD quickstart and the full 8-step wizard now offer to run `forgelm ingest` inline when the typed dataset path is a directory of raw documents, then feed the produced JSONL straight back into the BYOD path. Closes the onboarding loop end-to-end.
- **xxhash backend for simhash + token-level memo** — Optional `xxhash.xxh3_64` digest path (added to `forgelm[ingestion]`); BLAKE2b stays as the fallback. The Python-level speedup is modest (~1.3× raw, ~1.05× end-to-end after the cache below absorbs Zipfian repeats — xxhash's "4-10×" figure refers to C-level pure-hash microbenchmarks, not the Python wrapping path). The bigger wall-clock win is the new module-scope `lru_cache(maxsize=10_000)` that memoises the per-token digest — most corpora's token traffic is dominated by a few thousand frequent tokens, so the cache hit rate is very high.
- **Atomic audit-report write** — `data_audit_report.json` is now written via `tempfile.NamedTemporaryFile` + `os.replace` so a crashed audit can never leave a half-written report on disk. `newline="\n"` pinned for byte-exact reproducibility across Windows / Linux / macOS.

### Tests

- `tests/test_data_audit.py` — `TestLshBandedNearDuplicates` (LSH parity vs. brute force + high-threshold fallback), `TestPiiSeverity` (critical-tier verdict + neutral case), `TestSummarizeVerbosePolicy` (clean splits folded vs. expanded), `TestAtomicWrite` (no `.tmp` leftovers), `TestStreamingReader` (per-line tuple yields), `TestTokenCachePerformance` (cross-text cache hits).
- `tests/test_ingestion.py` — `TestPdfHeaderFooterDedup` (multi-page header/footer collapse, short-doc skip, no-repeats pass-through), `TestStructuredIngestionNotes`, `TestTokenAwareCli` (validates the `--chunk-tokens` requires `--tokenizer` rule).
- `tests/test_cli_subcommands.py` — `TestAuditSubcommand` (subcommand happy path, JSON envelope, legacy `--data-audit` alias).
- `tests/test_wizard_byod.py` — refreshed for the new ingest-first wording (empty directory rejection, decline-the-ingest-offer path).

### Changed — Phase 11 (no behavioural delta unless noted)

- `AuditReport` gains a `pii_severity: Dict[str, Any]` field. JSON consumers reading only `pii_summary` continue to work; the new field is additive.
- `find_near_duplicates(fingerprints, *, threshold, bits=64)` accepts a `bits` keyword for adaptive banding (default 64 matches `compute_simhash`).
- `_read_jsonl_split` is now a generator. The legacy buffered tuple return is gone — callers that were materialising rows can wrap with `list(...)`.
- `_audit_split(split_name, path, ...)` now takes a path instead of an in-memory list; `_process_split` calls it directly. Returns `(info, fingerprints, pii_split, parse_errors, decode_errors)` so OSError handling stays in the orchestrator.

### Previously added — Phase 11

**Document Ingestion & Data Audit (Phase 11)** — bridges raw enterprise corpora (legal, medical, policy manuals) to ForgeLM's training data format and surfaces governance signals before training starts.

Expand Down Expand Up @@ -97,7 +127,7 @@ All notable changes to ForgeLM are documented here.
### Documentation

- New "Option 0: One-Command Quickstart Template" section at the top of `docs/guides/quickstart.md`.
- `docs/roadmap.md`, `docs/roadmap-tr.md`, `docs/roadmap/phase-12-quickstart.md`, `docs/roadmap/releases.md` updated to mark Phase 10.5 as Done.
- `docs/roadmap.md`, `docs/roadmap-tr.md`, `docs/roadmap/phase-10-5-quickstart.md`, `docs/roadmap/releases.md` updated to mark Phase 10.5 as Done.
- `README.md` quickstart section updated to lead with `forgelm quickstart`.

---
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
- **LLM-as-Judge**: API-based (OpenAI) or local model scoring for quality assessment
- **Auto-Revert**: Automatically discard models that fail loss, benchmark, or safety thresholds

### Document Ingestion & Data Audit (v0.5.0)
### Document Ingestion & Data Audit (v0.5.0 — polished in v0.5.1)
- **Multi-Format Ingestion**: `forgelm ingest ./policies/ --recursive --output data/policies.jsonl` — turns raw PDF / DOCX / EPUB / TXT / Markdown into the SFT-ready JSONL the trainer accepts. Optional dep: `pip install forgelm[ingestion]`.
- **Chunking Strategies**: `paragraph` (default; preserves boundaries) or `sliding` (fixed window with overlap).
- **Chunking Strategies**: `paragraph` (default; preserves boundaries) or `sliding` (fixed window with overlap). Token-aware mode in v0.5.1: `--chunk-tokens 1024 --tokenizer Qwen/Qwen2.5-7B-Instruct` sizes chunks against your model's actual vocabulary.
- **PII Masking on Ingest**: `--pii-mask` redacts emails, phones, credit cards (Luhn-validated), IBAN, and national IDs (TR / DE / FR / US-SSN) before chunks land in the JSONL.
- **Dataset Audit**: `forgelm --data-audit data/sft.jsonl --output ./audit/` — produces `data_audit_report.json` with sample count, length distribution, top-3 language detection, simhash near-duplicate rate, cross-split leakage check, null/empty rate, and PII flag counts. CPU-only; feeds EU AI Act Article 10 governance artifact automatically when present at training time.
- **PDF Page Header/Footer Dedup (v0.5.1)**: Lines that recur on ≥ 70 % of PDF pages (watermarks, page numbers, copyright lines) are stripped automatically — the audit's near-duplicate counts stop misfiring on long policy / book PDFs.
- **Dataset Audit**: `forgelm audit data/sft.jsonl --output ./audit/` — produces `data_audit_report.json` with sample count, length distribution, top-3 language detection, LSH-banded near-duplicate rate (`O(n × k)` typical case, exact recall at the default Hamming threshold), cross-split leakage check, null/empty rate, and PII flag counts with **severity tiers** (critical / high / medium / low + worst-tier verdict). CPU-only; streaming JSONL reader keeps memory bounded on multi-million-row splits; feeds EU AI Act Article 10 governance artifact automatically when present at training time. Legacy `--data-audit` flag still works as a deprecation alias.

### Quickstart Layer (v0.4.5)
- **One-Command Templates**: `forgelm quickstart customer-support` — bundled templates for SFT, code, BYOD domain expert, Turkish medical Q&A, and GRPO math reasoning. Auto-downsizes models on small GPUs.
Expand Down Expand Up @@ -70,10 +71,10 @@ forgelm quickstart customer-support # render config + train + chat
forgelm quickstart code-assistant --dry-run # render config only
forgelm quickstart medical-qa-tr --model your-org/your-model # override

# Have raw docs? Ingest them first (v0.5.0+)
# Have raw docs? Ingest them first (v0.5.0+; v0.5.1 added token-aware sizing)
pip install -e ".[ingestion]"
forgelm ingest ./policies/ --recursive --output data/policies.jsonl
forgelm --data-audit data/policies.jsonl --output ./audit/
forgelm audit data/policies.jsonl --output ./audit/ # `forgelm --data-audit ...` still works as legacy alias

# Or generate config interactively
forgelm --wizard
Expand Down
96 changes: 83 additions & 13 deletions docs/guides/data_audit-tr.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
# Veri Seti Denetimi Rehberi

`forgelm --data-audit` bir JSONL veri setini analiz eder ve kalite,
`forgelm audit PATH` bir JSONL veri setini analiz eder ve kalite,
governance ile PII sinyallerini kapsayan bir `data_audit_report.json`
üretir. Faz 11; `v0.5.0`'da tanıtıldı. Trainer'ın `output_dir`'ünde
mevcutsa, rapor EU AI Act Madde 10 veri governance artifact'ına
otomatik olarak beslenir.
üretir. Faz 11 (`v0.5.0`'da tanıtıldı) altyapıyı, Faz 11.5 (`v0.5.1`)
ise top-level flag'i first-class subcommand'a yükseltti, LSH-banded
near-duplicate tespitini, streaming JSONL okuyucusunu, PII şiddet
katmanlarını, atomik disk yazımı ve verbose-by-default kısaltma
politikasını ekledi.

Trainer'ın `output_dir`'ünde mevcutsa, rapor EU AI Act Madde 10 veri
governance artifact'ına otomatik olarak beslenir.

---

## Çalıştırma

```bash
# Tek split (`train` olarak değerlendirilir)
forgelm --data-audit data/sft.jsonl --output ./audit/
forgelm audit data/sft.jsonl --output ./audit/

# Çoklu split: train.jsonl / validation.jsonl / test.jsonl içeren dizin
forgelm --data-audit data/ --output ./audit/
forgelm audit data/ --output ./audit/

# Bulgu olmayan split'leri de göster
forgelm audit data/ --verbose

# Daha geniş / dar near-duplicate eşiği
forgelm audit data/ --near-dup-threshold 5
```

> **Eski alias:** `forgelm --data-audit PATH` deprecation alias'ı
> olarak korunuyor; çalışmaya devam ediyor ama bir uyarı log'lanıyor.
> Yeni script'lerde `audit` subcommand'ını kullanın.

`--output` varsayılan olarak `./audit/`'tir. Dizin yoksa oluşturulur;
**tam** `data_audit_report.json` her zaman oraya yazılır. Stdout
varsayılan olarak insan-okunabilir özet gösterir; `--output-format json`
Expand Down Expand Up @@ -109,6 +124,34 @@ görmeden değiştirilir. Phone, bare digit run'ları (timestamp, log line
numarası, ISO tarih) flag'lemesin diye kasıtlı olarak `+CC` veya
`(area)` formatına anchored.

### PII şiddet katmanları (Faz 11.5)

Düz `pii_summary` haritası bir compliance reviewer'a *bulgu ne kadar
kötü?* sorusunda sıfır rehberlik veriyor. Faz 11.5 yanına bir
`pii_severity` bloğu ekliyor:

```json
{
"pii_severity": {
"total": 25,
"by_tier": {"critical": 1, "high": 2, "medium": 18, "low": 4},
"by_type": {
"credit_card": {"count": 1, "tier": "critical"},
"tr_id": {"count": 2, "tier": "high"},
"email": {"count": 18, "tier": "medium"},
"phone": {"count": 4, "tier": "low"}
},
"worst_tier": "critical"
}
}
```

Tier tablosu konsensüs regülatif ağırlıklandırmadır (finansal
kimlikler için PCI-DSS; devlet kimlikleri için GDPR Md. 9 + ENISA).
PII şiddetine kapılayan pipeline'lar `pii_severity.worst_tier`'i
okumalı ve `critical` / `high`'ta açık bir review olmadan yayınlamayı
reddetmeli.

### Near-duplicate tespiti

Case-fold edilmiş kelime token'ları üzerinde 64-bit simhash, Hamming
Expand All @@ -117,9 +160,27 @@ kurulumunda kullandığı eşik, bu genişlikte ≈%95 benzerlik). Hem
**split-içi** çiftleri (`near_duplicate_pairs` per split) hem de
yukarıdaki **cross-split** sızıntıyı ortaya çıkarır.

Satır sayısında karesel; ~50K satıra kadar olan veri setlerinde
audit-zamanı kullanım için uygun. Daha büyük külliyatlar için LSH band
indeksi gerekecek — `v0.5.0` kapsamı dışı.
Faz 11.5 alttaki taramayı **LSH banding**'e geçirdi: pigeonhole
prensibi `bands = threshold + 1` seçiyor, aday çiftler herhangi bir
band-bucket'ında çakışan satırlardan ibaret oluyor ve Hamming kontrolü
yalnızca adaylar üzerinde çalışıyor. Recall varsayılan eşikte tam
korunuyor; maliyet `O(n²)`'den ~`O(n × k)`'ye düşüyor (cross-split
`_count_leaked_rows` helper'ı da aynı banded şekli kullanıyor).
Brute-force yolu, eşik bantları 4 bitin altına düşürecek kadar yüksek
olduğunda fallback olarak kalıyor — `find_near_duplicates` her iki
yolda da aynı sonucu döndürüyor.

Faz 11.5 simhash backend'ini de değiştirilebilir hale getirdi:

- **xxhash.xxh3_64** opsiyonel `xxhash` bağımlılığı (artık
`forgelm[ingestion]`'ın parçası) yüklüyse per-token digest'i bu
sürüyor; kısa anahtarlarda BLAKE2b'ye göre Python katmanında ~%30
hızlandırma sağlıyor (lru_cache devreye girince end-to-end kazanç
daha az; backend swap'i öncelikle ileriye dönük güvence).
- **BLAKE2b** bare install için fallback olarak kalıyor.
- Modül seviyesinde `lru_cache(maxsize=10_000)` digest'i token
seviyesinde memoize ediyor — Zipfian token frekansı sayesinde küçük
bir cache bile bir corpus'un trafiğinin çoğunu kapsıyor.

---

Expand Down Expand Up @@ -157,7 +218,7 @@ işaret eden bir pointer yerine tek başına okunabilir bir doküman olur.

```bash
# Önce denetim — uzun bir eğitim koşusuna girmeden sorunları yüzeye çıkar
forgelm --data-audit data/policies.jsonl --output ./checkpoints/policy-run/
forgelm audit data/policies.jsonl --output ./checkpoints/policy-run/

# Eğit (governance artifact denetimi inline edecek)
forgelm --config configs/policy-run.yaml
Expand All @@ -168,14 +229,23 @@ forgelm --config configs/policy-run.yaml
## CLI referansı

```text
forgelm --data-audit PATH \
forgelm audit PATH \
[--output DIR] \
[--verbose] \
[--near-dup-threshold N] \
[--output-format {text,json}] \
[--quiet | --log-level {DEBUG,INFO,WARNING,ERROR}]
```

`PATH` bir `.jsonl` dosyası veya bir dizin olabilir. `--output`
varsayılan olarak `./audit/`'tir.
varsayılan olarak `./audit/`'tir. `--verbose`, insan-okunabilir özette
bulgu olmayan split'leri de gösterir (varsayılan, çoklu-split
denetimlerini kısa tutmak için tüm temiz split'leri tek bir kuyruk
satırına katlar — diskteki JSON raporu etkilenmez). `--near-dup-threshold`
varsayılan Hamming eşiğini (3, ≈%95 benzerlik) ezer.

Eski `forgelm --data-audit PATH` flag'i deprecation alias olarak
korunuyor; davranış aynı, sadece ek bir uyarı log'lanıyor.

Üst düzey flag'tir (subcommand değil) — trainer'a dokunmadan çıkar.

Expand All @@ -194,7 +264,7 @@ varsayılan olarak `./audit/`'tir.
| `Audit failed: ... not found or empty` | Yol mevcut değil veya `.jsonl` yok | Yolu doğrulayın; dosya veya `train.jsonl` dizin layout'u verin |
| Dil istatistiklerinde `"unknown (install forgelm[ingestion])"` | `langdetect` yüklü değil | `pip install 'forgelm[ingestion]'` |
| Cross-split leakage tüm satırların %100'ünü flag'liyor | Tüm split'ler aynı içeriği barındırıyor | Yeniden karıştırın; muhtemelen aynı JSONL'i her split'e kopyaladınız |
| Büyük veri setinde `near_duplicate_pairs` çok büyük | Simhash karesel on-binlerce satırda koştu | Önce örnekleyin; LSH index desteği takip edecek |
| Gerçek bir corpus'ta `near_duplicate_pairs` çok büyük | Gerçekten yüksek near-duplicate oranı (boilerplate / tekrarlayan başlıklar / veri seti kalite sorunu) — Faz 11.5 LSH banding eski O(n²) taramayı O(n × k) ile değiştirdi, dolayısıyla büyük çift sayısı algoritmik gürültü değil sinyaldir | `--near-dup-threshold 1` veya 0 ile yalnızca çok-yakın eşleşmeleri tutun; PDF'lerde header/footer dedup otomatik çalışır (ingestion rehberine bakın); birkaç işaretli çift inceleyip dedupe veya kabul kararı verin |

---

Expand Down
Loading
Loading