LLM [2] Подготовка данных
- 01LLM [1] Данные, железо и выбор модели
- 02LLM [2] Подготовка данных
Чистим текст: шапки, язык, пустые строки, склейка через <|endoftext|>.
Открываем архив, который мы скачали в прошлой статье. Книги на которых мы будем учить модель находятся в папке: gutenberg/data/raw/PG*_raw.txt
- 51 667 файлов
- 20 ГБ
- Метаданные: metadata/metadata.csv
Код статьи: https://github.com/format37/gpt
В корень я кладу config.yaml. Пропишите в нём ваши пути. У меня такие:
prepare_dataset:
metadata_folder: /home/alex/projects/gutenberg/metadata/metadata.csv
data_dir: /home/alex/projects/gutenberg/data/raw
target_dir: /home/alex/projects/gutenberg/data/target
Откройте любой файл PG*_raw.txt.
The Project Gutenberg EBook of Journal des Goncourt (Deuxième série,
deuxième volume), by Edmond de Goncourt
This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever. You may copy it, give it away or
re-use it under the terms of the Project Gutenberg License included
with this eBook or online at www.gutenberg.org
Title: Journal des Goncourt (Deuxième série, deuxième volume)
Mémoires de la vie littéraire
Author: Edmond de Goncourt
Release Date: December 30, 2005 [EBook #17420]
Language: French
Character set encoding: UTF-8
*** START OF THIS PROJECT GUTENBERG EBOOK JOURNAL DES GONCOURT ***
Produced by Carlo Traverso, Mireille Harmelin and the
Online Distributed Proofreading Team of Europe. This file
was produced from images generously made available by the
Bibliothèque nationale de France (BnF/Gallica) at
http://gallica.bnf.fr.
JOURNAL DES GONCOURT
_Mémoires de la Vie Littéraire_
DEUXIÈME SÉRIE--DEUXIÈME VOLUME--TOME CINQUIÈME
1872-1877
PARIS, BIBLIOTHÈQUE-CHARPENTIER, 11, RUE DE GRENELLE.
1891
PRÉFACE
(_Réponse à Monsieur Renan_)
Monsieur Renan me faisait l'honneur de me dire, il y a des années, qu'une
lettre fausse avait été publiée par LE FIGARO, comme émanant de lui, et
que son dédain de l'imprimé était tel, qu'il n'avait pas réclamé.
Le monsieur Renan de l'année dernière, est vraiment bien changé.
A propos de vieilles conversations de 1870, rapportées dans mon Journal:
voici la lettre, que le _Petit Lannionnais_ publiait de l'auteur de la VIE
DE JÉSUS-CHRIST.
Paris, 26 novembre, 1890.
Ah! mon cher cousin, que je vous sais gré de vous indigner pour moi,
en ce temps de mensonge...
Один файл это одна книга. Шапка содержит лицензию. Потом идет заголовок и абзацы разделённые пустой строкой и тремя звездочками. Нам нужно чтобы текст выглядел так как он будет выглядеть в чате. Абзацы разделенные пустой строкой.
Отбираем подходящие файлы:
- Английские тексты
- Имеющиеся файлы
from tqdm import tqdm
import os
import yaml
import pandas as pd
from cleanup import strip_headers
def file_list(config):
target_dir = config["target_dir"]
if not os.path.exists(target_dir):
os.makedirs(target_dir)
# Select only english texts
df = pd.read_csv(config["metadata_folder"])
print('Initial size:', len(df))
df = df[(df.language=="['en']") & (df.type=='Text')]
print('English texts:', len(df))
# Only existing files
files = os.listdir(config["data_dir"])
downloaded = [file.split("_")[0] for file in files]
df = df[df.id.isin(downloaded)]
print('Existing:', len(df))
# Compose file path
pathes = []
for name in df.id:
path = os.path.join(config['data_dir'], f"{name}_raw.txt")
pathes.append(path)
return pathes
Для удаления лицензии нам понадобится cleanup.py - Убедитесь что он у вас в data/ Изначально он взят из c-w/gutenberg - я убрал там лимит в 100 строк на поиск маркера *** END OF, чтобы концовка срезалась и у коротких книг.
- Сжимаем серию пустых строк до одной пустой строки
def collapse_blank_lines(text):
result = []
for line in text.split("\n"):
if line.strip():
# Has text in a line
result.append(line)
elif result and result[-1] != "":
# First empty string after the text
result.append("")
# Skip other empty strings
return "\n".join(result)
- Склеиваем книги через токен <|endoftext|> чтобы модель понимала что документ кончился и следующий текст с ним не связан
- Пишем в файлы по 500 МБ, чтобы иметь возможность обучать по частям
def combine_files(files, config):
max_size_mb = 500
separator = "<|endoftext|>"
target_dir = config['target_dir']
if not os.path.exists(target_dir):
os.makedirs(target_dir)
current_content = []
current_size = 0
file_counter = 1
for file_path in tqdm(files):
try:
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
except UnicodeDecodeError:
# Not UTF-8 (UTF-16, cp1252): skip the book
tqdm.write(f"Skipping {file_path}: not UTF-8")
continue
# Remove extra \ufeff garbage
content = content.replace("\ufeff", "")
# Remove license
content = strip_headers(content)
# Collapse blank lines
content = collapse_blank_lines(content)
# Write each 500 mb
estimated_size = len(content.encode("utf-8"))
if current_size + estimated_size > max_size_mb * 1024 * 1024:
target_file_path = os.path.join(
target_dir,
f"combined_{file_counter}.txt"
)
with open(target_file_path, "w", encoding="utf-8") as target_file:
target_file.write(separator.join(current_content))
file_counter += 1
current_content = [content]
current_size = estimated_size
else:
current_content.append(content)
current_size += estimated_size
# Write tail file
if current_content:
target_file_path = os.path.join(target_dir, f"combined_{file_counter}.txt")
with open(target_file_path, "w", encoding="utf-8") as target_file:
target_file.write(separator.join(current_content))
print(f"{file_counter} file(s) saved in {target_dir}")
def main():
with open("config.yaml") as f:
config = yaml.safe_load(f)["prepare_dataset"]
files = file_list(config)
combine_files(files, config)
if __name__=='__main__':
main()
Запускаем:
python data/prepare_dataset.py
На моей машине выполнение заняло около 23 минут. Я намеренно не делал параллелизацию и дедупликацию чтобы не усложнять там где это не сыграет большой роли для финального качества GPT 2 small.
Дедупликация исключает похожие книги. Например одна и та же книга может быть выпущена разными изданиями и оба издания могут быть представлены в датасете. Строго говоря, посимвольно они отличаются но текст почти идентичен. Если считать по совпадению название + автор то дублей у нас в датасете около 0.5% - несколько пьес Шекспира модель увидит 4 раза вместо 2.
В процессе вы увидите около 66 сообщений вроде
Skipping /home/alex/projects/gutenberg/data/raw/PG10511_raw.txt: not UTF-8
Это нормально. Несколько книг будет отброшено, чтобы не иметь проблем с кодировкой.
Взглянем на результат:
The Magna Carta
Contents
The Text of Magna Carta
Magna Carta 1215
The text of THE MAGNA CARTA
A note from Michael Hart, preparer of the 0.1 version.
This file contains a number of versions of the Magna Carta, some of
which were a little mangled in transit. I am sure our volunteers will
find and correct errors I didn’t catch, and that version 0.2 - 1.0 will
have significant improvements, as well as at least one more version in
Latin.
Version 1.0 may contain a dozen different versions.
The Text of Magna Carta
JOHN, by the grace of God King of England, Lord of Ireland, Duke of
Normandy and Aquitaine, and Count of Anjou, to his archbishops,
bishops, abbots, earls, barons, justices, foresters, sheriffs,
stewards, servants, and to all his officials and loyal subjects,
Greeting.
KNOW THAT BEFORE GOD, for the health of our soul and those of our
ancestors and heirs, to the honour of God, the exaltation of the holy
Church, and the better ordering...
...on the fifteenth day of June,
in the seventeenth year of our reign.
<|endoftext|> SENECA
APOCOLOCYNTOSIS
WITH AN ENGLISH TRANSLATION BY
W.H.D. ROUSE, M.A. LITT. D.
MCMXX
INTRODUCTION
This piece is ascribed to Seneca by ancient
Обратите внимание что специальное слово <|endoftext|> разделяет книги.
Итог:
- 39250 книг
- 30 файлов до 500 МБ
- Общий объем 14.3 ГБ
Переходим к следующей части - Токенизатору.