The framework measures how novel LLM-generated text is relative to pretraining data, using a three-stage pipeline: dense retrieval (FAISS + GIST embeddings), late-interaction reranking (ColBERTv2), and human baseline calibration.
Models studied: SmolLM and SmolLM2 (360M and 1.7B parameters, base and instruct variants).
thesis-repository/
│
├── download_data_code/ Download pretraining corpora + benchmarks
├── dolma/ HuggingFace dataset loader for Dolma
├── calc_chunks_and_embeddings_code/ Chunk corpora + compute GIST embeddings
├── create_FAISS_index_SmolLM.py/.sbatch Build FAISS HNSW index (SmolLM corpora)
├── create_FAISS_index_SmolLM2.py/.sbatch Build FAISS HNSW index (SmolLM2 corpora)
├── analyze_generations_novelty_code/ Core novelty analysis pipeline
├── effect_of_chunking_borders/ Chunking border analysis experiment
├── eval_benchmarks/ Model evaluation (lm-eval-harness + custom)
├── eval_benchmarks_lighteval/ GSM8K evaluation (lighteval)
├── results/generation_novelty/ Plotting + statistical analysis
├── sum_cpu_time.py Computational cost (Appendix A.5)
├── container.def Singularity/Apptainer container definition
└── requirements.txt Python dependencies
The full pipeline runs on an HPC cluster using SLURM and Singularity containers. Each stage has Python scripts and corresponding .sbatch job files.
download_data_code/ — Download pretraining corpora and benchmark datasets.
| Script | Description |
|---|---|
download_DCLM_dedup.py | DCLM corpus |
download_cosmopediav2.py | Cosmopedia v2 |
download_finemath.py | FineMath + InfiWebMath |
download_fineweb_edu_dedup.py | FineWeb-edu |
download_python_edu.py | Python-edu (from Software Heritage S3) |
download_stack_edu.py | Stack-edu (from Software Heritage S3) |
download_dolma.sh, download_dolma_second_step.py | Dolma human baseline |
download_instruct.py | Instruct-tuning data |
download_benchmarks_for_perplexity.py | Benchmark datasets |
concat_stack_edu_Java_parts.py | Post-processing: concatenate Stack-edu Java parts |
dolma/dolma.py — HuggingFace dataset loader for Dolma.
calc_chunks_and_embeddings_code/ — Split corpora into fixed-size token windows and compute GIST-large embeddings.
| Script pattern | Description |
|---|---|
calculate_chunks_*.py | Chunk each dataset into token windows |
calculate_embeddings_*.py | Compute GIST-large embeddings (GPU) |
utils.py | Shared text assembly utilities |
Datasets chunked: Cosmopedia v2, DCLM, FineMath, FineWeb-edu, InfiWebMath, Python-edu, Stack-edu, GSM8K, OpenRewrite, TruthfulQA, instruct data, OpenHermes-2.5.
| Script | Description |
|---|---|
create_FAISS_index_SmolLM.py | Build FAISS HNSW index from SmolLM corpus embeddings |
create_FAISS_index_SmolLM2.py | Build FAISS HNSW index from SmolLM2 corpus embeddings |
analyze_generations_novelty_code/ — Core novelty analysis pipeline.
| Script pattern | Description |
|---|---|
analyze_generations_*.py | Stage 1: FAISS retrieval for model generations (Dolma, GSM8K, TruthfulQA, OpenRewrite) |
rerank_top_100_with_granularity*.py | Stage 2: ColBERTv2 reranking at multiple chunk granularities |
combine_*.py | Combine batched SmolLM2 results |
analyze_ngram_vs_embed_toy_examples.py | Toy examples for Figure 1.1 |
analyze_ngram_vs_embed_toy_examples_post_hoc.py | Post-hoc toy example analysis |
build_compare_novelty_with_human_intuition.py | Human intuition comparison (Appendix A.6) |
get_token_lengths_*.py | Token length computation for normalization |
sum_faiss_times.py | FAISS timing aggregation |
utils.py | FAISS search, normalization, shared utilities |
eval_benchmarks/ — Model evaluation using lm-eval-harness and custom evaluations.
| Script | Description |
|---|---|
custom_eval_openrewrite_lm.py | Custom OpenRewriteEval evaluation |
SmolLM1/*.sbatch | SmolLM1 evaluation jobs (lm-eval + OpenRewrite) |
SmolLM2/*.sbatch | SmolLM2 evaluation jobs (lm-eval + OpenRewrite) |
eval_benchmarks_lighteval/ — GSM8K evaluation using lighteval.
| Script | Description |
|---|---|
tasks.py | Custom task definitions |
math_utils.py | Math answer parsing |
SmolLM1/*.sbatch, SmolLM2/*.sbatch | GSM8K evaluation jobs per model |
test_lighteval.sbatch | Test job |
effect_of_chunking_borders/ — Analyzes how chunking borders affect retrieval results (Figure A.2).
| Script | Description |
|---|---|
find_texts_for_analysis.py | Find test documents |
prepare_chunks.py | Prepare shifted-border chunks |
prepare_chunks_test.py | Unit test for chunking logic |
analyze_similarity.py | Compute similarity across borders |
plot_ranking.py | Produce Figure A.2 |
results/generation_novelty/ — All plotting and statistical testing scripts.
| Script | Produces |
|---|---|
create_simple_novelty_graph_relative_to_human.py | Figure 4.1 — Novelty profiles on Dolma |
create_simple_novelty_graph_relative_to_human_gen_benchmark.py | Figure 4.2 — Novelty profiles on domain-specific benchmarks |
create_simple_novelty_graph_relative_to_human_violin_plots.py | Figure A.3 — Violin plots (Dolma) |
create_simple_novelty_graph_relative_to_human_violin_plots_gen_benchmark.py | Figure A.4 — Violin plots (per-domain) |
create_simple_novelty_graph_relative_to_human_filter_incoherent.py | Figure A.5 — Coherence filtering |
create_simple_novelty_graph_relative_to_human_alt_answer.py | Figure A.6 — Alternative TruthfulQA answers |
reranking_ablation.py | Figure A.1 — FAISS-to-ColBERT reranking histogram |
calculate_wilcoxon_tests.py | Tables A.1–A.10 (benchmark p-values) |
calculate_wilcoxon_tests_dolma.py | Tables A.1–A.10 (Dolma p-values) |
calculate_wilcoxon_tests_dolma_context_comparison.py | Tables A.9–A.10 (prompted vs unprompted) |
generate_wilcoxon_tables.py | Format LaTeX p-value tables |
get_qualitative_examples_truthfulqa.py | Qualitative examples (Section 4.3) |
get_qualitative_examples_gsm8k.py | Qualitative examples (Section 4.3) |
utils.py | Shared plotting and data loading utilities |
| File | Description |
|---|---|
sum_cpu_time.py | Computational cost calculation (Appendix A.5) |
results/times.ttf | Font file used for plots |
The Singularity/Apptainer container is defined in container.def:
requirements.txtBuild with:
apptainer build container.sif container.def
All scripts are designed to run inside the container via SLURM. The general pattern:
singularity run \
--bind $(pwd):/mnt \
--bind $HF_HOME:/hf-cache \
container.sif \
bash -c "export HF_HOME=/hf-cache && python3 /mnt/script.py --job-num $SLURM_ARRAY_TASK_ID"
All scripts run inside a Singularity container with bind mounts:
| Host path | Container path | Contents |
|---|---|---|
data/ | /mnt/data/ | Pretraining corpora, benchmark datasets |
data/smollm2_corpus/ | /mnt/data/smollm2_corpus/ | SmolLM2-specific chunked data |
data/FAISS/ | /mnt/data/FAISS/ | FAISS indices (SmolLM) |
data/smollm2_corpus/FAISS/ | /mnt/data/smollm2_corpus/FAISS/ | FAISS indices (SmolLM2) |
results/ | /mnt/results/ | Novelty analysis results, plots |
$HF_HOME | /hf-cache | HuggingFace model/dataset cache |
| Variable | Purpose |
|---|---|
HF_TOKEN | HuggingFace Hub API token (for uploads) |
HF_HOME | HuggingFace cache directory |
SENTRY_DSN | Sentry error tracking DSN (optional) |
WANDB_API_KEY | Weights & Biases API key (for eval benchmarks) |
faiss-cpu): Dense retrieval with HNSW indicesen_core_web_sm, en_core_web_trf): Text processing| Figure/Table | Script |
|---|---|
| Figure 1.1(a) | Hand-designed, based on analyze_generations_novelty_code/analyze_ngram_vs_embed_toy_examples.py |
| Figure 1.1(b) | analyze_generations_novelty_code/analyze_ngram_vs_embed_toy_examples.py |
| Algorithm 1 | Pseudocode in LaTeX (no script) |
| Figure 4.1 | results/generation_novelty/create_simple_novelty_graph_relative_to_human.py |
| Figure 4.2 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_gen_benchmark.py |
| Table 4.1 | Inline LaTeX table (no script) |
| Figure A.1 | results/generation_novelty/reranking_ablation.py |
| Figure A.2 | effect_of_chunking_borders/plot_ranking.py |
| Figure A.3 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_violin_plots.py |
| Figure A.4 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_violin_plots_gen_benchmark.py |
| Figure A.5 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_filter_incoherent.py |
| Figure A.6 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_alt_answer.py |
| Tables A.1–A.10 | results/generation_novelty/calculate_wilcoxon_tests*.py, generate_wilcoxon_tables.py |
The framework measures how novel LLM-generated text is relative to pretraining data, using a three-stage pipeline: dense retrieval (FAISS + GIST embeddings), late-interaction reranking (ColBERTv2), and human baseline calibration.
Models studied: SmolLM and SmolLM2 (360M and 1.7B parameters, base and instruct variants).
thesis-repository/
│
├── download_data_code/ Download pretraining corpora + benchmarks
├── dolma/ HuggingFace dataset loader for Dolma
├── calc_chunks_and_embeddings_code/ Chunk corpora + compute GIST embeddings
├── create_FAISS_index_SmolLM.py/.sbatch Build FAISS HNSW index (SmolLM corpora)
├── create_FAISS_index_SmolLM2.py/.sbatch Build FAISS HNSW index (SmolLM2 corpora)
├── analyze_generations_novelty_code/ Core novelty analysis pipeline
├── effect_of_chunking_borders/ Chunking border analysis experiment
├── eval_benchmarks/ Model evaluation (lm-eval-harness + custom)
├── eval_benchmarks_lighteval/ GSM8K evaluation (lighteval)
├── results/generation_novelty/ Plotting + statistical analysis
├── sum_cpu_time.py Computational cost (Appendix A.5)
├── container.def Singularity/Apptainer container definition
└── requirements.txt Python dependencies
The full pipeline runs on an HPC cluster using SLURM and Singularity containers. Each stage has Python scripts and corresponding .sbatch job files.
download_data_code/ — Download pretraining corpora and benchmark datasets.
| Script | Description |
|---|---|
download_DCLM_dedup.py | DCLM corpus |
download_cosmopediav2.py | Cosmopedia v2 |
download_finemath.py | FineMath + InfiWebMath |
download_fineweb_edu_dedup.py | FineWeb-edu |
download_python_edu.py | Python-edu (from Software Heritage S3) |
download_stack_edu.py | Stack-edu (from Software Heritage S3) |
download_dolma.sh, download_dolma_second_step.py | Dolma human baseline |
download_instruct.py | Instruct-tuning data |
download_benchmarks_for_perplexity.py | Benchmark datasets |
concat_stack_edu_Java_parts.py | Post-processing: concatenate Stack-edu Java parts |
dolma/dolma.py — HuggingFace dataset loader for Dolma.
calc_chunks_and_embeddings_code/ — Split corpora into fixed-size token windows and compute GIST-large embeddings.
| Script pattern | Description |
|---|---|
calculate_chunks_*.py | Chunk each dataset into token windows |
calculate_embeddings_*.py | Compute GIST-large embeddings (GPU) |
utils.py | Shared text assembly utilities |
Datasets chunked: Cosmopedia v2, DCLM, FineMath, FineWeb-edu, InfiWebMath, Python-edu, Stack-edu, GSM8K, OpenRewrite, TruthfulQA, instruct data, OpenHermes-2.5.
| Script | Description |
|---|---|
create_FAISS_index_SmolLM.py | Build FAISS HNSW index from SmolLM corpus embeddings |
create_FAISS_index_SmolLM2.py | Build FAISS HNSW index from SmolLM2 corpus embeddings |
analyze_generations_novelty_code/ — Core novelty analysis pipeline.
| Script pattern | Description |
|---|---|
analyze_generations_*.py | Stage 1: FAISS retrieval for model generations (Dolma, GSM8K, TruthfulQA, OpenRewrite) |
rerank_top_100_with_granularity*.py | Stage 2: ColBERTv2 reranking at multiple chunk granularities |
combine_*.py | Combine batched SmolLM2 results |
analyze_ngram_vs_embed_toy_examples.py | Toy examples for Figure 1.1 |
analyze_ngram_vs_embed_toy_examples_post_hoc.py | Post-hoc toy example analysis |
build_compare_novelty_with_human_intuition.py | Human intuition comparison (Appendix A.6) |
get_token_lengths_*.py | Token length computation for normalization |
sum_faiss_times.py | FAISS timing aggregation |
utils.py | FAISS search, normalization, shared utilities |
eval_benchmarks/ — Model evaluation using lm-eval-harness and custom evaluations.
| Script | Description |
|---|---|
custom_eval_openrewrite_lm.py | Custom OpenRewriteEval evaluation |
SmolLM1/*.sbatch | SmolLM1 evaluation jobs (lm-eval + OpenRewrite) |
SmolLM2/*.sbatch | SmolLM2 evaluation jobs (lm-eval + OpenRewrite) |
eval_benchmarks_lighteval/ — GSM8K evaluation using lighteval.
| Script | Description |
|---|---|
tasks.py | Custom task definitions |
math_utils.py | Math answer parsing |
SmolLM1/*.sbatch, SmolLM2/*.sbatch | GSM8K evaluation jobs per model |
test_lighteval.sbatch | Test job |
effect_of_chunking_borders/ — Analyzes how chunking borders affect retrieval results (Figure A.2).
| Script | Description |
|---|---|
find_texts_for_analysis.py | Find test documents |
prepare_chunks.py | Prepare shifted-border chunks |
prepare_chunks_test.py | Unit test for chunking logic |
analyze_similarity.py | Compute similarity across borders |
plot_ranking.py | Produce Figure A.2 |
results/generation_novelty/ — All plotting and statistical testing scripts.
| Script | Produces |
|---|---|
create_simple_novelty_graph_relative_to_human.py | Figure 4.1 — Novelty profiles on Dolma |
create_simple_novelty_graph_relative_to_human_gen_benchmark.py | Figure 4.2 — Novelty profiles on domain-specific benchmarks |
create_simple_novelty_graph_relative_to_human_violin_plots.py | Figure A.3 — Violin plots (Dolma) |
create_simple_novelty_graph_relative_to_human_violin_plots_gen_benchmark.py | Figure A.4 — Violin plots (per-domain) |
create_simple_novelty_graph_relative_to_human_filter_incoherent.py | Figure A.5 — Coherence filtering |
create_simple_novelty_graph_relative_to_human_alt_answer.py | Figure A.6 — Alternative TruthfulQA answers |
reranking_ablation.py | Figure A.1 — FAISS-to-ColBERT reranking histogram |
calculate_wilcoxon_tests.py | Tables A.1–A.10 (benchmark p-values) |
calculate_wilcoxon_tests_dolma.py | Tables A.1–A.10 (Dolma p-values) |
calculate_wilcoxon_tests_dolma_context_comparison.py | Tables A.9–A.10 (prompted vs unprompted) |
generate_wilcoxon_tables.py | Format LaTeX p-value tables |
get_qualitative_examples_truthfulqa.py | Qualitative examples (Section 4.3) |
get_qualitative_examples_gsm8k.py | Qualitative examples (Section 4.3) |
utils.py | Shared plotting and data loading utilities |
| File | Description |
|---|---|
sum_cpu_time.py | Computational cost calculation (Appendix A.5) |
results/times.ttf | Font file used for plots |
The Singularity/Apptainer container is defined in container.def:
requirements.txtBuild with:
apptainer build container.sif container.def
All scripts are designed to run inside the container via SLURM. The general pattern:
singularity run \
--bind $(pwd):/mnt \
--bind $HF_HOME:/hf-cache \
container.sif \
bash -c "export HF_HOME=/hf-cache && python3 /mnt/script.py --job-num $SLURM_ARRAY_TASK_ID"
All scripts run inside a Singularity container with bind mounts:
| Host path | Container path | Contents |
|---|---|---|
data/ | /mnt/data/ | Pretraining corpora, benchmark datasets |
data/smollm2_corpus/ | /mnt/data/smollm2_corpus/ | SmolLM2-specific chunked data |
data/FAISS/ | /mnt/data/FAISS/ | FAISS indices (SmolLM) |
data/smollm2_corpus/FAISS/ | /mnt/data/smollm2_corpus/FAISS/ | FAISS indices (SmolLM2) |
results/ | /mnt/results/ | Novelty analysis results, plots |
$HF_HOME | /hf-cache | HuggingFace model/dataset cache |
| Variable | Purpose |
|---|---|
HF_TOKEN | HuggingFace Hub API token (for uploads) |
HF_HOME | HuggingFace cache directory |
SENTRY_DSN | Sentry error tracking DSN (optional) |
WANDB_API_KEY | Weights & Biases API key (for eval benchmarks) |
faiss-cpu): Dense retrieval with HNSW indicesen_core_web_sm, en_core_web_trf): Text processing| Figure/Table | Script |
|---|---|
| Figure 1.1(a) | Hand-designed, based on analyze_generations_novelty_code/analyze_ngram_vs_embed_toy_examples.py |
| Figure 1.1(b) | analyze_generations_novelty_code/analyze_ngram_vs_embed_toy_examples.py |
| Algorithm 1 | Pseudocode in LaTeX (no script) |
| Figure 4.1 | results/generation_novelty/create_simple_novelty_graph_relative_to_human.py |
| Figure 4.2 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_gen_benchmark.py |
| Table 4.1 | Inline LaTeX table (no script) |
| Figure A.1 | results/generation_novelty/reranking_ablation.py |
| Figure A.2 | effect_of_chunking_borders/plot_ranking.py |
| Figure A.3 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_violin_plots.py |
| Figure A.4 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_violin_plots_gen_benchmark.py |
| Figure A.5 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_filter_incoherent.py |
| Figure A.6 | results/generation_novelty/create_simple_novelty_graph_relative_to_human_alt_answer.py |
| Tables A.1–A.10 | results/generation_novelty/calculate_wilcoxon_tests*.py, generate_wilcoxon_tables.py |