ONNX версия модели
Привет, будут ли выпущены ONNX версии модели? например O3, O4?
Да это возможно, возьмем в проработку. Спасибо,что пользуетесь нашим решением.
А GGUF не планируете сделать ? при попытке прогнать через gguf-my-repo ругается на отсутствие токенайзера:
INFO:hf-to-gguf:Set model tokenizer
Traceback (most recent call last):
File "/home/user/app/./llama.cpp/convert_hf_to_gguf.py", line 5140, in
main()
File "/home/user/app/./llama.cpp/convert_hf_to_gguf.py", line 5134, in main
model_instance.write()
File "/home/user/app/./llama.cpp/convert_hf_to_gguf.py", line 440, in write
self.prepare_metadata(vocab_only=False)
File "/home/user/app/./llama.cpp/convert_hf_to_gguf.py", line 433, in prepare_metadata
self.set_vocab()
File "/home/user/app/./llama.cpp/convert_hf_to_gguf.py", line 4316, in set_vocab
raise FileNotFoundError(f"File not found: {tokenizer_path}")
FileNotFoundError: File not found: downloads/tmpbc6nm1xl/FRIDA/spiece.model
поддерживаю насчёт gguf
ни конвертнуть, ни в ollama не запустить
@hiauiarau , @ai-forever , модель, в целом, и так конвертируется в onnx.
- Конвертация:
import torch
from transformers import T5EncoderModel, AutoTokenizer
from pathlib import Path
MODEL_SOURCE_PATH = "ai-forever_frida" # Директория, в которой содержится модель
MODEL_TARGET_PATH = Path("ai-forever_frida-onnx")
if not MODEL_TARGET_PATH.exists():
MODEL_TARGET_PATH.mkdir()
tokenizer = AutoTokenizer.from_pretrained(MODEL_SOURCE_PATH)
model = T5EncoderModel.from_pretrained(MODEL_SOURCE_PATH)
model.eval()
dummy_input = tokenizer(
"Инпут для конвертации", max_length=512, padding=True, truncation=True, return_tensors="pt"
)["input_ids"]
torch.onnx.export(
model,
dummy_input,
(MODEL_TARGET_PATH / "t5_encoder.onnx").as_posix(),
input_names=["input_ids"],
output_names=["hidden_states"],
dynamic_axes={
"input_ids": {0: "batch_size", 1: "sequence_length"},
"hidden_states": {0: "batch_size", 1: "sequence_length"},
}
)
tokenizer.save_pretrained(MODEL_TARGET_PATH)
- Инференс:
import numpy as np
import onnxruntime as ort
from transformers import AutoTokenizer
from pathlib import Path
MODEL_PATH = Path("ai-forever_frida-onnx/t5_encoder.onnx")
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH.parent.as_posix())
model = ort.InferenceSession(MODEL_PATH)
my_input = tokenizer(
"search_query: Проверяем, работает ли onnx.", max_length=512, padding=True, truncation=True, return_tensors="np"
)["input_ids"]
outputs = model.run(None, {"input_ids": my_input})[0][:, 0][0]
embeddings = outputs / np.linalg.norm(outputs)
print(embeddings)
Косинусое расстояние между полученными векторами на 130 семплах (Клиент SentenceTransformers и ONNX) в среднем 0.99624.
Главное учитывать передачу в энкодер prompt_name.
@aveitsme
ваш код не воспроизводится. В папке не создается файл model.onnx.data а создается множество мелких файлов каждого слоя, всего 224 файла. Удачный экспорт происходит при указании dynamo=True. Но, тогда ошибки инференса 1. модель ждет ждет входной тензор в формате int64 2. модель ждет входной тензор формой [1, '8']
torch 2.6.0, onnx 1.16.1.
update: окей, такая версия все равно работает.
@hiauiarau , @ai-forever , модель, в целом, и так конвертируется в onnx.
- Конвертация:
import torch from transformers import T5EncoderModel, AutoTokenizer from pathlib import Path MODEL_SOURCE_PATH = "ai-forever_frida" # Директория, в которой содержится модель MODEL_TARGET_PATH = Path("ai-forever_frida-onnx") if not MODEL_TARGET_PATH.exists(): MODEL_TARGET_PATH.mkdir() tokenizer = AutoTokenizer.from_pretrained(MODEL_SOURCE_PATH) model = T5EncoderModel.from_pretrained(MODEL_SOURCE_PATH) model.eval() dummy_input = tokenizer( "Инпут для конвертации", max_length=512, padding=True, truncation=True, return_tensors="pt" )["input_ids"] torch.onnx.export( model, dummy_input, (MODEL_TARGET_PATH / "t5_encoder.onnx").as_posix(), input_names=["input_ids"], output_names=["hidden_states"], dynamic_axes={ "input_ids": {0: "batch_size", 1: "sequence_length"}, "hidden_states": {0: "batch_size", 1: "sequence_length"}, } ) tokenizer.save_pretrained(MODEL_TARGET_PATH)
- Инференс:
import numpy as np import onnxruntime as ort from transformers import AutoTokenizer from pathlib import Path MODEL_PATH = Path("ai-forever_frida-onnx/t5_encoder.onnx") tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH.parent.as_posix()) model = ort.InferenceSession(MODEL_PATH) my_input = tokenizer( "search_query: Проверяем, работает ли onnx.", max_length=512, padding=True, truncation=True, return_tensors="np" )["input_ids"] outputs = model.run(None, {"input_ids": my_input})[0][:, 0][0] embeddings = outputs / np.linalg.norm(outputs) print(embeddings)
Косинусое расстояние между полученными векторами на 130 семплах (Клиент SentenceTransformers и ONNX) в среднем 0.99624.
Главное учитывать передачу в энкодер prompt_name.
Подскажите почему используете только "input_ids" без "attention_mask" или инференс где нужно передавать два входа избыточен для FRIDA?
Вот моя реализация с примером для тестирования:
import torch
from transformers import T5EncoderModel, AutoTokenizer
from pathlib import Path
import onnxruntime as ort
import numpy as np
MODEL_SOURCE_ID = "ai-forever/FRIDA"
MODEL_TARGET_PATH = Path("onnx/frida-onnx")
ONNX_FILE_NAME = "FRIDA.onnx"
print("="*50)
print(f"Подготовка директории: {MODEL_TARGET_PATH}")
MODEL_TARGET_PATH.mkdir(parents=True, exist_ok=True)
# 1. Загружаем модель и токенизатор
print(f"Загрузка модели и токенизатора из '{MODEL_SOURCE_ID}'...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_SOURCE_ID)
model = T5EncoderModel.from_pretrained(MODEL_SOURCE_ID)
model.eval()
# 2. Создаем тестовые входы
print("Создание тестовых входных данных...")
test_texts = [
"paraphrase: В Ярославской области разрешили работу бань, но без посетителей",
"search_query: Сколько программистов нужно, чтобы вкрутить лампочку?",
"categorize_entailment: Женщину доставили в больницу, за ее жизнь сейчас борются врачи."
]
dummy_inputs = tokenizer(
test_texts[0],
max_length=512,
padding="max_length",
truncation=True,
return_tensors="pt"
)
# 3. Экспорт с двумя входами
onnx_model_path = MODEL_TARGET_PATH / ONNX_FILE_NAME
print(f"Экспорт модели в ONNX формат: {onnx_model_path}")
torch.onnx.export(
model,
(dummy_inputs["input_ids"], dummy_inputs["attention_mask"]),
onnx_model_path.as_posix(),
input_names=["input_ids", "attention_mask"],
output_names=["last_hidden_state"],
opset_version=14,
dynamic_axes={
"input_ids": {0: "batch_size", 1: "sequence_length"},
"attention_mask": {0: "batch_size", 1: "sequence_length"},
"last_hidden_state": {0: "batch_size", 1: "sequence_length"}
},
verbose=False
)
# 4. Сохраняем токенизатор
print(f"Сохранение токенизатора в '{MODEL_TARGET_PATH}'...")
tokenizer.save_pretrained(MODEL_TARGET_PATH)
print("Конвертация завершена успешно!")
# 5. Тестирование и сравнение результатов
print("\n" + "="*50)
print("ТЕСТИРОВАНИЕ РЕЗУЛЬТАТОВ")
def cls_pooling(hidden_state, attention_mask):
"""CLS pooling для получения эмбеддингов"""
return hidden_state[:, 0]
def normalize_embeddings(embeddings):
"""Нормализация эмбеддингов"""
return embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
# Тест с оригинальной моделью
print("Тестирование оригинальной модели...")
with torch.no_grad():
original_inputs = tokenizer(
test_texts,
max_length=512,
padding=True,
truncation=True,
return_tensors="pt"
)
original_outputs = model(**original_inputs)
original_embeddings = cls_pooling(
original_outputs.last_hidden_state,
original_inputs["attention_mask"]
)
original_embeddings = torch.nn.functional.normalize(original_embeddings, p=2, dim=1)
# Тест с ONNX моделью
print("Тестирование ONNX модели...")
onnx_session = ort.InferenceSession(onnx_model_path.as_posix())
onnx_inputs = tokenizer(
test_texts,
max_length=512,
padding=True,
truncation=True,
return_tensors="np"
)
onnx_inputs_int64 = {
"input_ids": onnx_inputs["input_ids"].astype(np.int64),
"attention_mask": onnx_inputs["attention_mask"].astype(np.int64)
}
onnx_outputs = onnx_session.run(None, onnx_inputs_int64)[0]
onnx_embeddings = onnx_outputs[:, 0]
onnx_embeddings = normalize_embeddings(onnx_embeddings)
cosine_similarity = np.sum(original_embeddings.numpy() * onnx_embeddings, axis=1)
print(f"\nCosine similarity между оригинальной и ONNX моделью:")
for i, sim in enumerate(cosine_similarity):
print(f" Текст {i+1}: {sim:.6f}")
print(f"Средняя схожесть: {np.mean(cosine_similarity):.6f}")
print("\n" + "="*50)
print("ГОТОВО! Модель успешно конвертирована и протестирована.")
print(f"Путь к модели: {MODEL_TARGET_PATH.resolve()}")