Best way to convert long Korean novel TXT files into a Hugging Face dataset for causal LM fine-tuning? A Stack Exchange user asked for the best way to convert long Korean novel TXT files into a Hugging Face dataset for causal LM fine-tuning, and the answer recommends separating corpus storage from sequence construction. The practical default is to store by book or chapter and later chunk into fixed-token blocks using the exact model tokenizer, with no overlap initially and optional metadata like book_id. The answer suggests using the Hugging Face 'text' loader with sample_by='document' or building explicit records, and advises checking token counts and decoded sequences before training. Some parts seem fairly well established, while others seem less settled: For continued pretraining / causal-LM training on novel text, I would separate how you store the corpus from how you construct the fixed-length sequences that the model actually trains on . So, for your specific questions, my default answers would be: | Question | Practical default | | Paragraph, scene, chapter, or fixed tokens per Dataset row? | Book or chapter for storage; fixed tokens later for training. They do not need to be the same unit. | | Tokenizer-aware 1024/2048-token chunking? | Yes. Construct training blocks from token IDs produced by the exact model tokenizer. | | Overlap? | No overlap initially. Consecutive blocks are the simplest baseline. | | Artificial line breaks? | Repair verified formatting artifacts, but preserve real paragraph/dialogue structure. | | Is {"text": "..."} enough? | Yes. book id , chapter id , etc. are optional but very useful metadata. | | Are 20,000+ character rows a problem? | Not by themselves. A long storage row does not mean feeding the whole row to the model at once. | | Preserve chapter/scene boundaries? | Preserve them in the canonical corpus. Training block boundaries do not necessarily have to match them. | In other words, I would not make the irreversible dataset representation itself a collection of 2048-token fragments. I would keep a clean, reconstructable corpus first, and derive model-specific training blocks from it. A reasonable first pipeline would be: original TXT files ↓ conservative cleanup ↓ canonical book/chapter records + metadata ↓ train/validation split at an appropriate source boundary ↓ Qwen tokenizer ↓ explicit document-boundary token where appropriate ↓ 1024/2048/etc. fixed-token blocks ↓ causal-LM labels That keeps the original book/chapter structure available if you later change tokenizer, block size, model, packing strategy, or evaluation setup. The Hugging Face text loader actually supports this distinction directly: it normally samples TXT files line-by-line, but it can also sample by paragraph or by entire document using sample by . See Loading text data with Datasets https://huggingface.co/docs/datasets/main/nlp load . For example, if one TXT file is one book: python from datasets import load dataset from pathlib import Path files = str p for p in sorted Path "novels" .glob " .txt" ds = load dataset "text", data files=files, split="train", sample by="document", If you want reliable book/chapter IDs, provenance, ordering information, etc., I would probably build the records explicitly instead: python from datasets import Dataset from pathlib import Path records = for path in sorted Path "novels" .glob " .txt" : text = path.read text encoding="utf-8" Only conservative, corpus-verified cleanup here. text = text.replace "\r\n", "\n" .replace "\r", "\n" records.append { "book id": path.stem, "text": text, } ds = Dataset.from list records text is all the language-model objective needs. The extra fields are mainly useful for splitting, inspection, debugging, and rebuilding the tokenized dataset later. Before doing a long training run, I would check only a few inexpensive things: - token counts per book/chapter using the exact Qwen tokenizer ; - a few before/after excerpts from the line-break cleanup; - whether the intended train/validation source units are actually disjoint; - a few decoded packed sequences around book boundaries; - where the document-boundary tokens ended up; - labels at document-boundary and padding positions; - how many tokens the final packing procedure drops or pads. Those checks tend to reveal preprocessing mistakes much more cheaply than discovering them after training. Why “Dataset row”, “document”, “training block”, and “attention boundary” are different There are really four boundaries here, and they can be chosen independently. This is mainly an organizational boundary. For example: row 0 = Book A row 1 = Book B or: row 0 = Book A / Chapter 1 row 1 = Book A / Chapter 2 row 2 = Book A / Chapter 3 row 3 = Book B / Chapter 1 ... Both are reasonable Dataset representations. The chapter version can be convenient because you can inspect, filter, reorder, or split chapters easily. The book version is simpler and preserves the original source with less preprocessing. This means: where should the model be told that one independent document ended and another begins? That does not have to equal the Dataset row boundary. For example, you can store chapters separately: row: Book A, Chapter 1 row: Book A, Chapter 2 row: Book A, Chapter 3 while treating them as one continuous semantic document: Chapter 1 Chapter 2 Chapter 3