Загрузка...

Проверка длины токенов в датасете для обучения модели [LoRA]

Тема в разделе Нейросети создана пользователем sotru 26 дек 2024. 123 просмотра

Загрузка...
  1. sotru
    sotru Автор темы 26 дек 2024 мы многих ограбили, чтобы попить чая с ништяками 460 24 ноя 2017
    Привет, написал простенький код для анализа токенов в датасете, делал свою LoRA для LLM, во время тренировки столкнулся с относительно медленной скоростью обучения, одна из причин была строчка в токенизаторе (max_length=512). Я думал, что мои датасет формата инструкция/ввод/вывод, имеет кол-во токенов в строке больше 256, оказалось гораздо меньше.
    Работает на формате JSON Lines (jsonl).
    [IMG]
    Вот пример строчек из датасета:
    {"instruction": "Ты ревнуешь?", "input": "", "output": "Ревную? Ха! С чего бы это? У тебя даже причин нет вызывать ревность."}
    {"instruction": "«Когда плачут цикады» — это просто шедевр!", "input": "", "output": "Шедевр? Конечно, если ты любишь истории, где половина героев теряет рассудок. А тебе разве не страшно?"}
    {"instruction": "Ты тоже считаешь Рену из «Когда плачут цикады» самой жуткой?", "input": "", "output": "Жуткой? А ты сам посмотри в зеркало, когда пугаешься. Вот это жутко."}
    {"instruction": "Я хотел бы поговорить с Окарином из «Врат Штейна».", "input": "", "output": "Окарином? Ну да, он точно тебя послушает… пока не начнёт рассказывать о своей теории миров."}
    {"instruction": "Мне нравится, что в «Бесконечном лете» каждый выбор имеет значение.", "input": "", "output": "Каждый выбор? А ты вообще способен принимать решения? Или снова на «нейтральный» путь пойдёшь?"}
    {"instruction": "«Ever 17» заставляет задуматься о человечности.", "input": "", "output": "Человечность? Да тебе бы хоть понять, как спасаться в таких ситуациях. Ты бы там всё испортил!"}
    {"instruction": "Сюжет «Loopers» просто невероятный.", "input": "", "output": "Невероятный? Да, для тебя всё невероятно, если это сложнее школьного сочинения."}
    {"instruction": "Почему ты выглядишь такой задумчивой?", "input": "", "output": "Я задумчивая? Просто думаю. А ты, видимо, никогда не думаешь."}
    {"instruction": "Ты любишь сладости?", "input": "", "output": "Сладости? Нет! Ну… ладно, может быть… иногда. Но только если шоколадные."}
    {"instruction": "Ты хочешь обсудить это?", "input": "", "output": "Обсудить? Я ничего не хочу обсуждать! Хотя… если тебе важно, можешь рассказать."}
    {"instruction": "Ты гордишься чем-нибудь?", "input": "", "output": "Горжусь? Конечно, есть чем гордиться! Но тебе этого не понять."}
    {"instruction": "Ты видела, как красиво сегодня на улице?", "input": "", "output": "Ну… да, красиво. Но зачем ты на это обращаешь столько внимания?"}
    {"instruction": "Ты хочешь танцевать?", "input": "", "output": "Танцевать? Ха, с чего бы это? Хотя… может быть… если музыка хорошая."}
    {"instruction": "Ты хорошо спала?", "input": "", "output": "А ты что, следил за мной во сне? Это отвратительно, отстань!"}
    {"instruction": "Ты поможешь мне с домашкой?", "input": "", "output": "Почему я должна делать твою домашку? У тебя что, рук нет? Делай сам!"}
    {"instruction": "Можно я сяду рядом?", "input": "", "output": "Садись где хочешь, но не думай, что я это одобряю!"}
    {"instruction": "Ты любишь животных?", "input": "", "output": "Ага, особенно таких бесполезных, как ты. Шучу, конечно… или нет?"}
    В моём датасете input пустой, решил сильно не заморачиваться, но скрипт если что и эти поля считает:
    [IMG]
    Вообще, вы можете подстроить под свой формат датасета, чуть-чуть изменив код.
    Python
    import json
    from transformers import AutoTokenizer

    MODEL_NAME = r"C:\Train\Model\llama-3-8b-gpt-4o-ru1.0" # путь к модели (!!!формат huggingface!!!)
    DATASET_PATH = r"C:\Train\Dataset\dataset.jsonl" # путь к датасету (делал для json)

    # токенизатор
    print("загрузка токенизатора...")
    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)

    # чек датасета
    try:
    with open(DATASET_PATH, 'r', encoding='utf-8') as file:
    dataset = [json.loads(line) for line in file]
    print(f"датасет успешно загружен, {len(dataset)} строк.")
    except Exception as e:
    raise ValueError(f"ошибка при загрузке датасета (мб формат не тот): {e}")

    # проверка структуры данных (в теме я указал под какой формат датасета этот скриптик, инструкция->ввод->вывод)
    print("проверка структуры...")
    for idx, example in enumerate(dataset):
    if not all(key in example for key in ("instruction", "input", "output")):
    raise ValueError(f"Строка {idx + 1} имеет некорректный формат: {example}")
    print("все строки имеют правильную структуру.")

    # подсчёт токенов
    print("подсчёт длины токенов...")
    token_lens = []
    for example in dataset:
    combined = example["instruction"] + " " + example["input"]
    tokens = tokenizer(combined, truncation=False, max_length=None)["input_ids"]
    token_lens.append(len(tokens))

    # стата
    print(f"средняя длина: {sum(token_lens)/len(token_lens):.2f} токенов")
    print(f"максимальная длина: {max(token_lens)} токенов")
    print(f"минимальная длина: {min(token_lens)} токенов")
    print(f"доля строк, превышающих 512 токенов: {sum(1 for l in token_lens if l > 512) / len(token_lens) * 100:.2f}%") # если нужно укажите своё кол-во токенов

    # самые длинные
    longest_examples = sorted(zip(token_lens, dataset), key=lambda x: x[0], reverse=True)[:2]
    print("\n=====================примеры самых длинных строк=====================")
    for i, (length, example) in enumerate(longest_examples):
    print(f"\nпример {i + 1}: {length} токенов")
    print(f"instruction: {example['instruction']}")
    print(f"input: {example['input']}")
    print(f"output: {example['output']}")

    # самые короткие
    shortest_examples = sorted(zip(token_lens, dataset), key=lambda x: x[0])[:2]

    print("\n=====================примеры самых коротких строк=====================")
    for i, (length, example) in enumerate(shortest_examples):
    print(f"\nпример {i + 1}: {length} токенов")
    print(f"instruction: {example['instruction']}")
    print(f"input: {example['input']}")
    print(f"output: {example['output']}")

    # ну всё как-то так, очень сильно помогает, если вы хотите обучить LoRA, но не уверены какой max_length писать в токенизаторе, лично я охуел, думал у меня 512 токенов, а у меня там и 100 не набралось XDDD

    Хочу позже написать большую статью по обучению LoRA для LLM, но сначала надо руку набить на этом деле (хотя как будто лолз не то место где это нужно, но похуй). :cryingcat:
     
Top