File size: 8,699 Bytes
6592886 aca5916 bc628f9 6592886 bc628f9 aca5916 bc628f9 4105808 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 bc628f9 aca5916 b46980a aca5916 b46980a aca5916 b46980a aca5916 b46980a aca5916 bc628f9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
---
license: apache-2.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
* Добавлен расчет среднего эмбеддинга (для ранжировщика в случае работы с массивом)
* Добавлена работа с матрицами эмбеддингов
* Добавлены 2 новых способа смеси эмбеддингов:
* Эмбеддинги в первой степени из одного текста, а квадраты из другого(в эмбеддинги и их квадраты также можно включать разную по структуре информацию)
* Передавать массив эмбеддингов и их квадратов
* **Пример использования**
```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 в этой задаче особо смысла нет
код с top-p: https://github.com/ictnlp/DSTC8-AVSD/blob/master/generate.py
"""
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 __get_embds(self, embds, sqr_embds):
'''Работает с матрицей эмбеддингов'''
list_emb = []
sq = embds if sqr_embds == None else sqr_embds
for i, embd in enumerate(embds):
vector = np.concatenate([embd,sq[i]**2])
list_emb.append(list(vector))
return torch.FloatTensor(list_emb).to(self.device)
def __det_mean(self, embds):
'''Получение среднего'''
m = np.zeros((384))
for embd in embds:
m += embd
m /= len(embds)
return m
def generate_embedding(self, embds, prompt = '', sqr_embds = None, temperature=0.26, top_k=4, max_len=100):
"""
Генерация текста на основе начального эмбеддинга и заданного начального текста.
"""
current_output_ids = self.tokenizer.encode(prompt) # Промпт
embedding = self.__get_embds(embds, sqr_embds) # Матрица входа
word_tokens = self.model.base_model.wte # Словарь токенов
while len(current_output_ids) < max_len:
with torch.no_grad():
outp_ids_tensor = torch.LongTensor(current_output_ids).to(self.device) # Выходы
token_embeddings = word_tokens(outp_ids_tensor) # эмбеддинги
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, embds, prompt = '', sqr_embds = None, seq=10, temperature=0.6, top_k=10, max_len=100):
"""Генерация и ранжирование текста. Поумолчанию создаются 10 текстов"""
sequences = [self.generate_embedding(embds, prompt, sqr_embds, temperature, top_k, max_len) for _ in range(seq)]
sequences = list(set(sequences)) # Удаление дубликатов
# Ранжирование
embd = self.__det_mean(embds)
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])
```
```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('машина') - sbert.encode('колеса') + sbert.encode('крылья')
generator.generate_with_ranker([embd], 'это')
```
```bash
>>> этот самолёт
```
```python
embd = sbert.encode('полицейский - главный герой') + sbert.encode('Произошло ужасное событие в фильме')
embd /= 2
generator.generate_with_ranker([embd], 'Собеседование на')
```
```bash
>>> Собеседование на роль главного героя фильма — молодого лейтенанта полиции — происходит в доме
```
**После дообучения**
```python
embd_1 = sbert.encode('полицейский - главный герой')
embd_2 = sbert.encode('Произошло событие в фильме')
generator.generate_with_ranker([embd_1, embd_2], 'В ')
```
```bash
>>> В этом фильме главный герой - полицейский.
```
```python
embd_1 = sbert.encode('полицейский - главный герой')
embd_2 = sbert.encode('Произошло событие в фильме')
generator.generate_with_ranker([embd_1], 'Это', [embd_2])
```
```bash
>>> Это полицейский, который в полицейском участке снимается в фильме.
```
```python
embd = sbert.encode('радиоприемник')
ans = vector_answer(embd, 'Как это устроено?')
print(ans)
```
```bash
>>> Радиоволны распространяются в воздухе, создавая электромагнитное поле, которое может быть использовано для передачи информации.
``` |