Введение
В эпоху быстрой обработки текстов и естественного языка токенизация играет важнейшую роль. Токенизация позволяет разделить текст на более мелкие части (токены), что является первым шагом во многих процессах обработки текста, таких как обучение моделей машинного обучения. В этой статье мы рассмотрим, как создать GUI-приложение для создания кастомных токенизаторов с использованием PyQt6 и библиотеки tokenizers от Hugging Face.
Обзор проекта
Скрипт реализует простое графическое приложение на PyQt6, которое позволяет пользователю выбрать текстовый файл для обучения токенизатора и указать директорию для сохранения созданных файлов токенизатора. Приложение использует библиотеку tokenizers, чтобы создать и сохранить токенизатор на основе модели BPE (Byte-Pair Encoding).
Описание основных компонентов
- Интерфейс приложенияПриложение имеет простой и понятный интерфейс, который содержит:Поле для выбора файла данных (например, текстовый файл для обучения).
Поле для указания папки, в которую будут сохранены файлы токенизатора.
Кнопку для запуска процесса создания токенизатора. - Функционал приложенияПриложение предоставляет следующие функции:Выбор файла данных: Пользователь может выбрать файл с текстовыми данными, на которых будет обучен токенизатор.
Выбор директории для сохранения: После создания токенизатора, все необходимые файлы сохраняются в указанной пользователем директории.
Создание токенизатора: При нажатии на кнопку "Создать токенизатор" запускается процесс тренировки модели BPE на выбранных данных. - Процесс создания токенизатораПри создании токенизатора выполняются следующие шаги:Тренировка модели: Используя модель BPE, обучаем токенизатор на выбранном текстовом файле.
Сохранение результатов: Результаты обучения, включая tokenizer.json, vocab.json, merges.txt и другие файлы конфигурации, сохраняются в указанной папке.
Как работает скрипт?
- Импорт библиотек и создание основного окна
Скрипт начинается с импорта необходимых библиотек: sys, os, json, PyQt6.QtWidgets, а также классов из библиотеки tokenizers. Основной класс приложения TokenizerApp наследует QMainWindow и отвечает за создание интерфейса и обработку событий. - Инициализация интерфейса
В методе initUI создаются виджеты интерфейса: поля для ввода пути к файлу и директории, кнопки для выбора файла и папки, а также кнопка для запуска процесса токенизации. - Выбор файла и директории
Методы select_data_file и select_output_dir позволяют пользователю выбрать нужный файл и папку через стандартные диалоговые окна PyQt6. - Создание токенизатора
Метод create_tokenizer проверяет, указаны ли файл и папка, а затем вызывает метод generate_tokenizer, который и занимается основной работой по созданию токенизатора. В случае успеха выводится сообщение об успешном создании токенизатора, в случае ошибки – сообщение об ошибке. - Сохранение данных токенизатора
Метод generate_tokenizer не только обучает модель BPE на заданных данных, но и сохраняет все ключевые файлы конфигурации и данные токенизатора, такие как vocab.json, merges.txt, special_tokens_map.json и tokenizer_config.json.
Заключение
Этот скрипт является отличным примером того, как можно использовать PyQt6 для создания удобных графических интерфейсов и интеграции их с мощными библиотеками для обработки текста, такими как tokenizers. Приложение позволяет легко и быстро создавать кастомные токенизаторы для различных задач обработки естественного языка, что может быть полезно как разработчикам, так и исследователям в области NLP
Сам скрипт:
import sys
import os
import json
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QLabel, QFormLayout, QStatusBar
)
from tokenizers import Tokenizer, models, trainers, pre_tokenizers, decoders
class TokenizerApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Tokenizer Creator")
self.setGeometry(100, 100, 600, 400)
self.initUI()
def initUI(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# File selection
self.data_file_line_edit = QLineEdit()
self.data_file_button = QPushButton("Выбрать файл данных")
self.data_file_button.clicked.connect(self.select_data_file)
# Directory selection
self.output_dir_line_edit = QLineEdit()
self.output_dir_button = QPushButton("Выбрать папку для сохранения")
self.output_dir_button.clicked.connect(self.select_output_dir)
# Start button
self.start_button = QPushButton("Создать токенизатор")
self.start_button.clicked.connect(self.create_tokenizer)
# Layout setup
form_layout = QFormLayout()
form_layout.addRow(QLabel("Файл данных:"), self.data_file_line_edit)
form_layout.addRow(self.data_file_button)
form_layout.addRow(QLabel("Папка для сохранения:"), self.output_dir_line_edit)
form_layout.addRow(self.output_dir_button)
layout.addLayout(form_layout)
layout.addWidget(self.start_button)
# Status bar
self.status_bar = QStatusBar()
self.setStatusBar(self.status_bar)
def select_data_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "Выберите файл данных", "", "Text Files (*.txt);;All Files (*)")
if file_path:
self.data_file_line_edit.setText(file_path)
def select_output_dir(self):
dir_path = QFileDialog.getExistingDirectory(self, "Выберите папку для сохранения")
if dir_path:
self.output_dir_line_edit.setText(dir_path)
def create_tokenizer(self):
data_file = self.data_file_line_edit.text()
output_dir = self.output_dir_line_edit.text()
if not data_file or not output_dir:
self.status_bar.showMessage("Необходимо выбрать и файл данных, и папку для сохранения.")
return
self.status_bar.showMessage("Создание токенизатора. Пожалуйста, подождите...")
try:
self.generate_tokenizer(data_file, output_dir)
self.status_bar.showMessage("Токенизатор успешно создан!")
except Exception as e:
self.status_bar.showMessage(f"Ошибка: {str(e)}")
def generate_tokenizer(self, data_file, output_dir):
tokenizer = Tokenizer(models.BPE())
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=True)
tokenizer.decoder = decoders.ByteLevel()
# Настройка тренера для BPE
trainer = trainers.BpeTrainer(
vocab_size=200000, # Настройте размер словаря
special_tokens=["<unk>", "<s>", "</s>", "<pad>", "<mask>", ".", ",", "=", "+", "-", "/", "*", "(", ")", " "],
show_progress=True
)
# Обучение токенизатора на ваших данных
tokenizer.train([data_file], trainer)
# Сохранение токенизатора
tokenizer_json_path = os.path.join(output_dir, "tokenizer.json")
tokenizer.save(tokenizer_json_path)
# Сохранение vocab.json
vocab = tokenizer.get_vocab()
with open(os.path.join(output_dir, "vocab.json"), 'w', encoding='utf-8') as f:
json.dump(vocab, f, ensure_ascii=False, indent=4)
# Сохранение merges.txt, извлекая информацию из tokenizer.json
with open(tokenizer_json_path, 'r', encoding='utf-8') as f:
tokenizer_data = json.load(f)
merges = tokenizer_data['model']['merges']
with open(os.path.join(output_dir, "merges.txt"), 'w', encoding='utf-8') as merges_file:
for merge in merges:
merges_file.write(f"{merge}\n")
# Сохранение special_tokens_map.json
special_tokens = {
"unk_token": "<unk>",
"bos_token": "<s>",
"eos_token": "</s>",
"pad_token": "<pad>",
"mask_token": "<mask>"
}
with open(os.path.join(output_dir, "special_tokens_map.json"), 'w', encoding='utf-8') as f:
json.dump(special_tokens, f, ensure_ascii=False, indent=4)
# Сохранение tokenizer_config.json
with open(os.path.join(output_dir, "tokenizer_config.json"), 'w', encoding='utf-8') as f:
json.dump({
"max_len": 512,
"do_lower_case": False
}, f, ensure_ascii=False, indent=4)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TokenizerApp()
window.show()
sys.exit(app.exec())