|
|
--- |
|
|
license: gpl-3.0 |
|
|
datasets: |
|
|
- wikimedia/wikipedia |
|
|
--- |
|
|
|
|
|
# FractalGPT/EmbedderDecoder |
|
|
|
|
|
* **Оригинальная модель** |
|
|
[[ai-forever/rugpt3small_based_on_gpt2](https://huggingface.co/ai-forever/rugpt3small_based_on_gpt2)] |
|
|
|
|
|
* **Код генерации взят частично отсюда** |
|
|
[[vector2text](https://github.com/Koziev/vector2text)] |
|
|
|
|
|
* Заменен эмбеддер |
|
|
* Вместо нулей вектор дополняется квадратами чисел (далее можно кубами и т.д.) |
|
|
* Создан класс для генератора |
|
|
* Добавлен ранжировщик |
|
|
* Заменена модель вместо large — small |
|
|
* Убран top_p |
|
|
|
|
|
* **Пример использования** |
|
|
|
|
|
|
|
|
```python |
|
|
import torch |
|
|
import numpy as np |
|
|
from torch.nn import functional as F |
|
|
from transformers import GPT2Tokenizer, GPT2LMHeadModel |
|
|
|
|
|
def top_filtering(logits, top_k): |
|
|
""" |
|
|
Фильтрация top-k, в фильтрации top-p в этой задаче особо смысла нет |
|
|
""" |
|
|
assert logits.dim() == 1 |
|
|
top_k = min(top_k, logits.size(-1)) |
|
|
if top_k > 0: |
|
|
indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None] |
|
|
logits[indices_to_remove] = -float('Inf') |
|
|
|
|
|
return logits |
|
|
|
|
|
|
|
|
class TextEmbdGenerator: |
|
|
def __init__(self, name_or_path, sbert, device = None): |
|
|
""" |
|
|
Инициализация генератора текста с моделью и токенизатором. |
|
|
name_or_path: путь до модели токенизатора или ее имя для загрузки из Hugging Face. |
|
|
sbert: модель для ранжирования (такая же что и создает эбеддинги) |
|
|
""" |
|
|
self.device = device |
|
|
|
|
|
if self.device == None: |
|
|
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
|
|
|
|
|
|
self.tokenizer = GPT2Tokenizer.from_pretrained(name_or_path) |
|
|
self.model = GPT2LMHeadModel.from_pretrained(name_or_path).to(self.device) |
|
|
self.sbert = sbert |
|
|
|
|
|
|
|
|
def generate_embedding(self, embd, prompt = '', temperature=0.26, top_k=4, max_len=100): |
|
|
""" |
|
|
Генерация текста на основе начального эмбеддинга и заданного начального текста. |
|
|
""" |
|
|
vector = np.concatenate([embd,embd**2]) |
|
|
current_output_ids = self.tokenizer.encode(prompt) |
|
|
|
|
|
embedding = torch.FloatTensor([list(vector)]).to(self.device) |
|
|
|
|
|
while len(current_output_ids) < max_len: |
|
|
with torch.no_grad(): |
|
|
token_embeddings = self.model.base_model.wte(torch.LongTensor(current_output_ids).to(self.device)) |
|
|
input_vectors = torch.vstack((embedding, token_embeddings)).unsqueeze(dim=0) |
|
|
output_model = self.model(inputs_embeds=input_vectors) |
|
|
|
|
|
logits = output_model.logits |
|
|
if isinstance(logits, tuple): |
|
|
logits = logits[0] |
|
|
logits = logits[0, -1, :] |
|
|
logits /= temperature |
|
|
logits = top_filtering(logits, top_k) |
|
|
probs = F.softmax(logits, dim=-1) |
|
|
|
|
|
prev = torch.multinomial(probs, 1) |
|
|
if prev.item() == self.tokenizer.eos_token_id: |
|
|
break |
|
|
current_output_ids.append(prev.item()) |
|
|
|
|
|
output_text = self.tokenizer.decode(current_output_ids) |
|
|
return output_text.split('\n')[0] |
|
|
|
|
|
|
|
|
def cosine_similarity(self, x, y): |
|
|
"""Вычисление косинусного сходства.""" |
|
|
return np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y)) |
|
|
|
|
|
def generate_with_ranker(self, embd, prompt = '', seq=10, temperature=0.6, top_k=10, max_len=100): |
|
|
"""Генерация и ранжирование текста. Поумолчанию создаются 10 текстов""" |
|
|
sequences = [self.generate_embedding(embd, prompt, temperature, top_k, max_len) for _ in range(seq)] |
|
|
sequences = list(set(sequences)) # Удаление дубликатов |
|
|
|
|
|
# Ранжирование |
|
|
embeddings = self.sbert.encode(sequences) |
|
|
similarities = [self.cosine_similarity(embd, emb) for emb in embeddings] |
|
|
best_index = np.argmax(similarities) |
|
|
|
|
|
return sequences[best_index] |
|
|
``` |
|
|
|
|
|
--- |
|
|
|
|
|
```bash |
|
|
pip install sentence-transformers -q |
|
|
``` |
|
|
|
|
|
```python |
|
|
from sentence_transformers import SentenceTransformer |
|
|
|
|
|
sbert = SentenceTransformer('FractalGPT/SbertDistil') |
|
|
generator = TextEmbdGenerator('FractalGPT/EmbedderDecoder', sbert) |
|
|
``` |
|
|
|
|
|
```python |
|
|
embd = sbert.encode('там живут англичане') |
|
|
generator.generate_with_ranker(embd, prompt = 'он всегда был в') |
|
|
``` |
|
|
```bash |
|
|
>>> он всегда был в Англии. |
|
|
``` |
|
|
|
|
|
|
|
|
```python |
|
|
embd = sbert.encode('там живут немцы') |
|
|
generator.generate_with_ranker(embd, prompt = 'он всегда был в') |
|
|
``` |
|
|
```bash |
|
|
>>> он всегда был в Германии |
|
|
``` |
|
|
|
|
|
```python |
|
|
embd = sbert.encode('он сделает вывод на основе анализа ситуации') |
|
|
generator.generate_with_ranker(embd) |
|
|
``` |
|
|
```bash |
|
|
>>> в процессе анализа ситуации необходимо выяснить: |
|
|
``` |
|
|
|
|
|
|
|
|
```python |
|
|
embd = sbert.encode('интересный фильм смотрел, фильм понравился') |
|
|
generator.generate_with_ranker(embd, seq=5) |
|
|
``` |
|
|
```bash |
|
|
>>> фильм был снят по мотивам произведений |
|
|
``` |