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
14 changes: 14 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ jobs:
forgelm --config "/tmp/qs-$tpl.yaml" --dry-run
done

- name: Ingestion + audit smoke test (Phase 11)
run: |
# Minimal end-to-end: TXT in → JSONL out → audit report out.
# Plain TXT path doesn't need the [ingestion] extra; the audit
# module is pure stdlib. Catches CLI wiring drift without paying
# for pypdf / langdetect installs.
mkdir -p /tmp/p11
echo "Article 10 governs data quality." > /tmp/p11/sample.txt
echo "Section two: representativeness, traceability, bias review." > /tmp/p11/sample2.txt
forgelm ingest /tmp/p11/ --recursive --output /tmp/p11/out.jsonl
test -s /tmp/p11/out.jsonl
forgelm --data-audit /tmp/p11/out.jsonl --output /tmp/p11/audit/
test -s /tmp/p11/audit/data_audit_report.json

wheel-install-smoke:
# ------------------------------------------------------------------
# This is the only test that catches package_data globs being broken
Expand Down
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@ All notable changes to ForgeLM are documented here.

## [Unreleased]

### Added

**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.

- **`forgelm/ingestion.py`** + **`forgelm ingest`** subcommand:
- Multi-format extractors: PDF (`pypdf`), DOCX (`python-docx`), EPUB (`ebooklib` + `beautifulsoup4`), TXT, Markdown.
- Two chunking strategies: `paragraph` (default; greedy, never splits a paragraph) and `sliding` (fixed window with `--overlap`). `semantic` raises `NotImplementedError` and is reserved for a follow-up phase.
- Output is `{"text": "..."}` JSONL — recognized as pre-formatted SFT input by `forgelm/data.py` without further preprocessing.
- `--recursive` walks directory trees; unsupported extensions are skipped silently, supported files with no extractable text skip with a warning.
- `--pii-mask` redacts detected PII spans before chunks land in the JSONL (shared regex set with the audit module).
- OCR is intentionally out of scope; scanned PDFs without a text layer warn and produce zero chunks.

- **`forgelm/data_audit.py`** + **`forgelm --data-audit`** top-level flag:
- Per-split metrics: sample count, column schema, text length distribution (`min/max/mean/p50/p95`), null/empty rate, top-3 language detection (best-effort via `langdetect`).
- 64-bit simhash near-duplicate detection within each split; Hamming-distance threshold 3 ≈ 95% similarity (canonical web-page-dedup setting).
- Cross-split overlap report — guards against silent train-test leakage that destroys benchmark fidelity.
- PII regex set (`email`, `phone`, `credit_card` Luhn-validated, `iban`, `tr_id` checksum-validated, `de_id`, `fr_ssn`, `us_ssn`); per-split + aggregate counts.
- Layout: single `.jsonl` file → treated as `train`; directory containing `train.jsonl` / `validation.jsonl` / `test.jsonl` (any subset) auto-discovered.
- Writes `data_audit_report.json` under `--output` (default `./audit/`); `--output-format json` mirrors the report on stdout for CI/CD pipelines.
- CPU-only; no GPU, no network.

- **EU AI Act Article 10 integration** — `generate_data_governance_report` now inlines `data_audit_report.json` under the `data_audit` key when present in the trainer's `output_dir`. Compliance bundle becomes a single self-contained document instead of a pointer.

- **`pyproject.toml` `[ingestion]` extra** — `pypdf`, `python-docx`, `ebooklib`, `beautifulsoup4`, `langdetect`. Cross-platform, no native compilation.

- **Tests** — `tests/test_ingestion.py` (TXT path + chunking strategies; PDF round-trip skips when `pypdf` missing) and `tests/test_data_audit.py` (PII regex + Luhn / TC Kimlik validators, simhash properties, end-to-end audit on file + split-keyed directory layouts, governance integration). All GPU/network-free.

- **Documentation** — new guides at `docs/guides/ingestion.md` and `docs/guides/data_audit.md`; README feature section, CLI epilog, install matrix, and roadmap status updated.

---

## [0.4.5] — 2026-04-26

### Added
Expand Down Expand Up @@ -71,7 +102,7 @@ All notable changes to ForgeLM are documented here.

---

## [0.4.0] — 2026-04-25
## [0.4.0] — 2026-04-26

### Added

Expand Down
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# ForgeLM

[![PyPI](https://img.shields.io/pypi/v/forgelm.svg)](https://pypi.org/project/forgelm/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![CI](https://github.com/cemililik/ForgeLM/actions/workflows/ci.yml/badge.svg)](https://github.com/cemililik/ForgeLM/actions/workflows/ci.yml)
Expand All @@ -26,6 +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)
- **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).
- **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.

### 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.
- **Conservative Defaults**: Every template ships QLoRA 4-bit, rank=8, batch=1, gradient checkpointing on — designed to run on a single 12 GB GPU.
Expand Down Expand Up @@ -63,6 +70,11 @@ 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+)
pip install -e ".[ingestion]"
forgelm ingest ./policies/ --recursive --output data/policies.jsonl
forgelm --data-audit data/policies.jsonl --output ./audit/

# Or generate config interactively
forgelm --wizard

Expand Down Expand Up @@ -90,6 +102,8 @@ See the [Quick Start Guide](docs/guides/quickstart.md) for a complete walkthroug
| Guide | Description |
|-------|-------------|
| [Quick Start](docs/guides/quickstart.md) | First fine-tuned model in 5 minutes |
| [Document Ingestion](docs/guides/ingestion.md) ([Türkçe](docs/guides/ingestion-tr.md)) | Raw PDF/DOCX/EPUB → SFT-ready JSONL |
| [Dataset Audit](docs/guides/data_audit.md) ([Türkçe](docs/guides/data_audit-tr.md)) | Length, language, dedup, cross-split leakage, PII |
| [Alignment (DPO/SimPO/KTO/GRPO)](docs/guides/alignment.md) | Complete post-training stack |
| [CI/CD Pipeline Integration](docs/guides/cicd_pipeline.md) | GitHub Actions, GitLab CI, Docker |
| [Enterprise Deployment](docs/guides/enterprise_deployment.md) | Docker, air-gapped, multi-GPU |
Expand All @@ -108,11 +122,24 @@ See the [Quick Start Guide](docs/guides/quickstart.md) for a complete walkthroug

## Notebooks

Each notebook is runnable in Colab with a free T4 GPU.

**Getting started**
- [Quick Start — SFT Fine-Tuning](notebooks/quickstart_sft.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/quickstart_sft.ipynb)

**Alignment methods** (post-SFT preference / RL)
- [DPO Preference Alignment](notebooks/dpo_alignment.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/dpo_alignment.ipynb)
- [KTO Binary Feedback](notebooks/kto_binary_feedback.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/kto_binary_feedback.ipynb)
- [GRPO Reasoning RL](notebooks/grpo_reasoning.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/grpo_reasoning.ipynb)
- [Multi-Dataset Training](notebooks/multi_dataset.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/multi_dataset.ipynb)

**Advanced training**
- [Multi-Dataset Training](notebooks/multi_dataset.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/multi_dataset.ipynb) — mix multiple datasets with configurable ratios.
- [GaLore Memory Optimization](notebooks/galore_memory_optimization.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/galore_memory_optimization.ipynb) — full-parameter training via gradient low-rank projection (LoRA alternative).
- [Synthetic Data Pipeline](notebooks/synthetic_data_training.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/synthetic_data_training.ipynb) — teacher-to-student distillation (API / local / pre-generated backends).

**Post-training & safety**
- [Post-Training Workflow](notebooks/post_training_workflow.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/post_training_workflow.ipynb) — end-to-end Phase 10 toolchain: `--fit-check` → `chat` → `export` (GGUF) → `deploy`.
- [Safety Evaluation & Red-Teaming](notebooks/safety_evaluation.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cemililik/ForgeLM/blob/main/notebooks/safety_evaluation.ipynb) — 140 adversarial prompts × 6 categories (Llama Guard).

---

Expand All @@ -137,6 +164,9 @@ pip install -e ".[eval]" # lm-evaluation-harness benchmarks
pip install -e ".[tracking]" # W&B experiment tracking
pip install -e ".[distributed]" # DeepSpeed multi-GPU
pip install -e ".[merging]" # mergekit model merging
pip install -e ".[ingestion]" # PDF/DOCX/EPUB → JSONL + langdetect
pip install -e ".[export]" # GGUF export via llama-cpp-python
pip install -e ".[chat]" # Rich terminal rendering for `forgelm chat`
pip install -e ".[dev]" # pytest, ruff (development)
```

Expand Down Expand Up @@ -208,7 +238,7 @@ forgelm/

configs/deepspeed/ # ZeRO-2, ZeRO-3, ZeRO-3+Offload presets
notebooks/ # Colab-ready Jupyter notebooks
tests/ # 430 passed (+34 skipped) across 30 test files
tests/ # pytest suite spanning every module (run with `pytest tests/`)
docs/guides/ # Quickstart, alignment, CI/CD, enterprise, safety guides
```

Expand Down
218 changes: 218 additions & 0 deletions docs/guides/data_audit-tr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Veri Seti Denetimi Rehberi

`forgelm --data-audit` 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.

---

## Çalıştırma

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

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

`--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`
geçince stdout'a **özet** JSON zarfı (üst seviye metrikler + rapor yolu
+ notlar) düşer — tam rapor yine `--output` altında diskte kalır. CI/CD
tüketicileri her detayı istediğinde stdout özetini parse etmek yerine
dosyayı `report_path`'tan slurp etmeli.

GPU gerekmiyor. Ağ çağrısı yok. CPU-only.

---

## Ne elde edersin

### Split başına metrikler

```json
{
"splits": {
"train": {
"sample_count": 1240,
"columns": ["text"],
"text_length": {"min": 32, "max": 4096, "mean": 1834.2, "p50": 1900, "p95": 3580},
"null_or_empty_count": 3,
"null_or_empty_rate": 0.0024,
"languages_top3": [
{"code": "tr", "count": 950},
{"code": "en", "count": 240},
{"code": "de", "count": 50}
],
"simhash_distinct": 1180,
"near_duplicate_pairs": 60,
"pii_counts": {"email": 18, "phone": 4}
}
}
}
```

### Cross-split örtüşmesi

```json
{
"cross_split_overlap": {
"hamming_threshold": 3,
"pairs": {
"train__test": {
"leaked_rows_in_train": 7,
"leak_rate_train": 0.0056,
"leaked_rows_in_test": 7,
"leak_rate_test": 0.7
}
}
}
}
```

Audit leak rate'i **her iki yönde** de raporlar çünkü birbirinden farklı
hikâyeler anlatırlar. 1240 train + 10 test satırında 7'sinin sızdığı bir
durumda `leak_rate_train = 7/1240 = %0.56` önemsiz görünür ama
`leak_rate_test = 7/10 = %70` benchmark güvenirliğini fiilen yok eden
metriktir. Her zaman küçük tarafın oranını okuyun — test bütünlüğünün
sessiz katili odur.

### PII özeti

```json
{
"pii_summary": {
"email": 18,
"phone": 4,
"credit_card": 1,
"tr_id": 2
}
}
```

Her satırın metin payload'ı regex ile taranır; kredi kartları Luhn
doğrulaması, TR Kimlik No'ları TC Kimlik checksum'ından geçirilir.
Diğer kategoriler regex şekli üzerinden yüzeylenir — false positive'ler
kasıtlıdır. Veri setini paylaşmadan önce `forgelm ingest --pii-mask`
ile (veya kendi ön işlemenizde) maskeleyin.

**Pattern önceliği belgeli.** `_PII_PATTERNS` iter sırası hem tespit
önceliğini hem maskeleme önceliğini yönetir — en spesifik pattern'lar
(`email`, `iban`, `credit_card`, ulusal kimlikler) önce taranır,
ardından gürültülü `phone` pattern'i. Bir span iki kategoriyle
eşleşebileceğinde, ilk / dar olan kazanır ve span sonraki pattern
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.

### Near-duplicate tespiti

Case-fold edilmiş kelime token'ları üzerinde 64-bit simhash, Hamming
mesafe ≤ 3 ile (simhash makalesinin canonical web-page-dedup
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ışı.

---

## Layout gereksinimleri

| Girdi şekli | Ne elde edersin |
|---|---|
| `*.jsonl` dosyası | `train` adlı tek split |
| `train.jsonl`, `validation.jsonl`, `test.jsonl`'in herhangi birini içeren `dir/` | Her mevcut dosya kendi split'i olur |
| Yaygın alias'ları (`dev`, `val`, `valid`, `eval`, `holdout`) içeren `dir/` | Canonical split adlarına katlanır — `dev.jsonl` → `validation`, `eval.jsonl` → `test`, vb. |
| Yalnızca canonical olmayan `*.jsonl` içeren `dir/` | Pseudo-split fallback: her `*.jsonl` kendi split'i olur VE cross-split leakage analizi gerçek bir partition olmadan anlamsızdır uyarısı yayılır |

Auditor şu öncelik sırasıyla bulduğu ilk metin-taşıyan sütunu okur:
`text` → `content` → `completion` → `prompt`. `messages` formatlı chat
verisinde rol etiketli içerikler birleştirilir.

**Şema kaymaları yüzeye çıkarılır.** Heterojen JSONL (opsiyonel
alanları olan satırlar) izinlidir — sütun şeması satırlar arası
anahtarların union'ı olarak hesaplanır; satır 0'dan sonra ortaya çıkan
herhangi bir sütun `schema_drift_columns` altında raporlanır, böylece
operatörler kaymanın kasıtlı olup olmadığına karar verebilir.

---

## Madde 10 governance entegrasyonu

`data_audit_report.json` trainer'ın `training.output_dir`'ünde eğitim
zamanında mevcut olduğunda,
[`generate_data_governance_report`](../../forgelm/compliance.py)
bulguları governance artifact'ının `data_audit` anahtarı altında
otomatik olarak inline eder. Compliance bundle'ınız ayrı dosyaya
işaret eden bir pointer yerine tek başına okunabilir bir doküman olur.

Önerilen iş akışı:

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

# Eğit (governance artifact denetimi inline edecek)
forgelm --config configs/policy-run.yaml
```

---

## CLI referansı

```text
forgelm --data-audit PATH \
[--output DIR] \
[--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.

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

> **Not:** Bu davranış kılavuzun başındaki özetle eşleşir:
> `--output-format json` stdout'a küçük bir zarf (success flag, üst
> seviye metrikler, rapor yolu) yazar. Tam `data_audit_report.json`
> her zaman `--output` altına yazılır. Her detayı istiyorsanız
> diskten okuyun.

---

## Sorun giderme

| Belirti | Sebep | Çözüm |
|---|---|---|
| `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 |

---

## Programmatic API

```python
from dataclasses import asdict
from forgelm.data_audit import audit_dataset

report = audit_dataset("data/sft.jsonl", output_dir="./audit/")
print(report.total_samples, report.pii_summary)

# Veya manuel serileştir:
import json
json.dump(asdict(report), open("custom_path.json", "w"), indent=2)
```

`AuditReport` düz bir dataclass'tır — `dataclasses.asdict()` size
JSON-hazır bir dict verir. PII regex helper'ları (`detect_pii`,
`mask_pii`) ve simhash fonksiyonu (`compute_simhash`) da public
API'nin parçası.
Loading
Loading