цепи маркова и трансформеры..
---
## Общая идея
1. Предобработка текста:
- Считать текст из файла `.txt`.
- Токенизировать текст на слова.
- Провести лемматизацию (получить корни слов) с помощью библиотек, например, для русского — pymorphy2, для английского — spaCy.
- Получить две последовательности: слов и их корней.
2. Модель цепей Маркова:
- Построить модель цепей Маркова на основе последовательности слов и/или корней.
- Можно сделать отдельные цепи для слов и для корней, либо объединить их (например, пары (слово, корень)).
3. Модель трансформера:
- Создать упрощённый трансформер, который принимает на вход эмбеддинги слов и корней.
- Для этого можно объединить эмбеддинги слова и его корня (например, конкатенацией или суммой).
- Обучить трансформер предсказывать следующий токен (слово или корень).
4. Комбинация результатов:
- При генерации текста можно комбинировать вероятности из цепей Маркова и трансформера.
- Например, усреднить вероятности или использовать веса, чтобы получить итоговое распределение для выбора следующего слова.
**
```python
import pymorphy2
from collections import defaultdict, Counter
import numpy as np
# Предобработка
morph = pymorphy2.MorphAnalyzer()
def tokenize(text):
return text.lower().split() # простой токенизатор, лучше использовать nltk/spacy
def lemmatize(words):
return [morph.parse(w)[0].normal_form for w in words]
# Цепи Маркова
class MarkovChain:
def __init__(self):
self.transitions = defaultdict(Counter)
def train(self, tokens):
for i in range(len(tokens) - 1):
self.transitions[tokens[i]][tokens[i+1]] += 1
def next_word_probs(self, current):
total = sum(self.transitions[current].values())
return {word: count/total for word, count in self.transitions[current].items()}
# Упрощённый трансформер (просто эмбеддинги и матричные операции)
class SimpleTransformer:
def __init__(self, vocab):
self.vocab = vocab
self.vocab_size = len(vocab)
self.embed_dim = 64
self.embeddings = np.random.randn(self.vocab_size, self.embed_dim) * 0.01
# Здесь можно добавить self-attention и другие слои
def embed(self, token):
idx = self.vocab.get(token, None)
if idx is None:
idx = self.vocab.get('<unk>')
return self.embeddings[idx]
def predict_next(self, context_tokens):
# усредняем эмбеддинги контекста и считаем скалярные произведения с эмбеддингами всех слов
context_embeds = np.mean([self.embed(t) for t in context_tokens], axis=0)
scores = self.embeddings @ context_embeds
probs = np.exp(scores) / np.sum(np.exp(scores))
return {word: probs[idx] for word, idx in self.vocab.items()}
# Комбинирование
def combine_probs(probs1, probs2, alpha=0.5):
combined = {}
keys = set(probs1.keys()) | set(probs2.keys())
for k in keys:
p1 = probs1.get(k, 0)
p2 = probs2.get(k, 0)
combined[k] = alpha * p1 + (1 - alpha) * p2
# Нормализуем
s = sum(combined.values())
for k in combined:
combined[k] /= s
return combined
# --- Использование
text = open('input.txt', encoding='utf-8').read()
words = tokenize(text)
lemmas = lemmatize(words)
# Создаём словарь для трансформера (слова + корни)
unique_tokens = list(set(words + lemmas + ['<unk>']))
vocab = {w: i for i, w in enumerate(unique_tokens)}
# Обучаем цепь Маркова на словах
markov_words = MarkovChain()
markov_words.train(words)
# Обучаем цепь Маркова на корнях
markov_lemmas = MarkovChain()
markov_lemmas.train(lemmas)
# Инициализируем трансформер
transformer = SimpleTransformer(vocab)
# Генерация следующего слова на основе текущего контекста
context = words[-3:] # последние 3 слова
probs_markov = markov_words.next_word_probs(context[-1])
probs_transformer = transformer.predict_next(context)
# Комбинируем вероятности
final_probs = combine_probs(probs_markov, probs_transformer, alpha=0.6)
# Выбираем слово с максимальной вероятностью
next_word = max(final_probs, key=final_probs.get)
print("Следующее слово:", next_word)
```
# Что можно улучшить и расширить
- Использовать полноценный токенизатор и лемматизатор
(например, spaCy для английского, pymorphy2 для русского).
- Реализовать полноценный трансформер с self-attention
(например, на PyTorch или TensorFlow).
- Обучать трансформер на большом корпусе.
- Использовать более сложные методы объединения информации из слов и корней (например, отдельные эмбеддинги + attention).
- При генерации применять сэмплирование (топ-k, топ-p), чтобы получать разнообразный текст.
**
import random
def generate_text(length, start_word, markov_chain_words, transformer_model, vocab, alpha=0.5):
generated = [start_word]
for _ in range(length - 1):
current_word = generated[-1]
# Получаем вероятности от цепи Маркова
probs_markov = markov_chain_words.next_word_probs(current_word)
if not probs_markov:
# Если нет переходов, случайно выбираем слово из словаря
probs_markov = {w: 1/len(vocab) for w in vocab}
# Получаем вероятности от трансформера по контексту последних 3 слов
context = generated[-3:] if len(generated) >= 3 else generated
probs_transformer = transformer_model.predict_next(context)
# Комбинируем вероятности
combined_probs = combine_probs(probs_markov, probs_transformer, alpha=alpha)
# Выбираем следующее слово случайно по распределению
words = list(combined_probs.keys())
probabilities = list(combined_probs.values())
next_word = random.choices(words, probabilities)[0]
generated.append(next_word)
return generated
# Пример использования:
start = words[0] # или любой начальный токен
generated_words = generate_text(200, start, markov_words, transformer, vocab, alpha=0.6)
print(' '.join(generated_words))
Свидетельство о публикации №125062208039