В этой реализации кодирования мы создадим регрессионную языковую модель (Regression Language Model, RLM) — модель, которая прогнозирует непрерывные числовые значения непосредственно из текстовых последовательностей. Вместо классификации или генерации текста мы сосредоточимся на обучении архитектуры на основе трансформера, которая изучает количественные отношения, скрытые в описаниях на естественном языке.
Этапы работы
1. Генерация синтетических данных:
— Создаём синтетический набор данных, который объединяет предложения на естественном языке с соответствующими числовыми значениями.
— Используем различные шаблоны, такие как температуры, рейтинги и проценты, чтобы модель изучила разнообразные отношения между текстом и числами.
2. Токенизация:
— Разрабатываем простой токенизатор для преобразования необработанного текста в числовые токены, которые модель может обрабатывать.
— Токенизатор строит словарь из всех уникальных слов и сопоставляет каждое слово с индексом, автоматически обрабатывая неизвестные слова и дополняя их.
3. Создание набора данных:
— Упаковываем пары текст–число в набор данных PyTorch, где каждое предложение токенизируется и возвращается в виде тензоров, готовых для пакетной обработки.
4. Обучение модели:
— Строим модель RLM на основе трансформера: токены и позиционные вложения проходят через многослойный кодировщик, а затем результат подаётся в небольшой MLP-слой для регрессии.
— Обучаем модель с помощью Adam и MSE-потери на GPU, если он доступен.
5. Тестирование:
— Генерируем несколько примеров на естественном языке и проверяем предсказания модели.
Код
«`python
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import matplotlib.pyplot as plt
from collections import Counter
import re
torch.manual_seed(42)
np.random.seed(42)
print(» Regression Language Model (RLM) Tutorial»)
print(«=» * 60)
Генерация синтетических данных
def generatesyntheticdata(n_samples=2000):
«»»Generate synthetic text-to-number regression data»»»
templates = [
(«The temperature is {} degrees», lambda x: x),
(«I rate this {} out of ten», lambda x: x),
(«The price is {} dollars», lambda x: x),
(«Confidence level: {}», lambda x: x / 100),
(«Speed of {} kilometers per hour», lambda x: x / 10),
(«{} percent complete», lambda x: x / 100),
(«Scored {} points in the game», lambda x: x / 10),
(«The distance is {} meters», lambda x: x),
]
data = []
for in range(nsamples):
template, transform = templates[np.random.randint(len(templates))]
value = np.random.uniform(0, 100)
text = template.format(round(value, 1))
target = transform(value)
data.append((text, target))
return data
Токенизатор
class SimpleTokenizer:
def init(self):
self.word2idx = {«
self.idx2word = {0: «
self.vocab_size = 2
def fit(self, texts):
«»»Build vocabulary from texts»»»
words = []
for text in texts:
words.extend(re.findall(r’\w+|[^\w\s]’, text.lower()))
word_counts = Counter(words)
for word, in wordcounts.most_common():
if word not in self.word2idx:
self.word2idx[word] = self.vocab_size
self.idx2word[self.vocab_size] = word
self.vocab_size += 1
def encode(self, text, max_len=20):
«»»Convert text to token indices»»»
words = re.findall(r’\w+|[^\w\s]’, text.lower())
indices = [self.word2idx.get(w, 1) for w in words]
if len(indices) < max_len:
indices += [0] * (max_len — len(indices))
else:
indices = indices[:max_len]
return indices
Набор данных
class RLMDataset(Dataset):
def init(self, data, tokenizer, max_len=20):
self.data = data
self.tokenizer = tokenizer
self.maxlen = maxlen
def len(self):
return len(self.data)
def getitem(self, idx):
text, target = self.data[idx]
tokens = self.tokenizer.encode(text, self.max_len)
return torch.tensor(tokens), torch.tensor([target], dtype=torch.float32)
Регрессионная языковая модель
class RegressionLanguageModel(nn.Module):
def init(self, vocabsize, embeddim=128, numheads=4, numlayers=2,
dropout=0.1, max_len=20):
super().init()
self.tokenembedding = nn.Embedding(vocabsize, embeddim, paddingidx=0)
self.positionembedding = nn.Embedding(maxlen, embed_dim)
encoder_layer = nn.TransformerEncoderLayer(
dmodel=embeddim,
nhead=num_heads,
dimfeedforward=embeddim * 4,
dropout=dropout,
batch_first=True
)
self.transformer = nn.TransformerEncoder(encoderlayer, numlayers=num_layers)
self.fc1 = nn.Linear(embed_dim, 64)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(dropout)
self.fc2 = nn.Linear(64, 1)
self.maxlen = maxlen
def forward(self, x):
batchsize, seqlen = x.shape
positions = torch.arange(0, seqlen, device=x.device).unsqueeze(0).expand(batchsize, -1)
tokenembed = self.tokenembedding(x)
posembed = self.positionembedding(positions)
embeddings = tokenembed + posembed
padding_mask = (x == 0)
encoded = self.transformer(embeddings, srckeypaddingmask=paddingmask)
maskexpanded = (~paddingmask).unsqueeze(-1).float()
summed = (encoded * mask_expanded).sum(dim=1)
pooled = summed / mask_expanded.sum(dim=1)
x = self.fc1(pooled)
x = self.relu(x)
x = self.dropout(x)
output = self.fc2(x)
return output
Обучение модели
def trainrlm(model, trainloader, val_loader, epochs=15, lr=0.001):
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=lr)
trainlosses, vallosses = [], []
print(f»\n Training on {device}»)
print(«-» * 60)
for epoch in range(epochs):
model.train()
train_loss = 0
for tokens, targets in train_loader:
tokens, targets = tokens.to(device), targets.to(device)
optimizer.zero_grad()
outputs = model(tokens)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
train_loss += loss.item()
trainloss /= len(trainloader)
trainlosses.append(trainloss)
model.eval()
val_loss = 0
with torch.no_grad():
for tokens, targets in val_loader:
tokens, targets = tokens.to(device), targets.to(device)
outputs = model(tokens)
loss = criterion(outputs, targets)
val_loss += loss.item()
valloss /= len(valloader)
vallosses.append(valloss)
print(f»Epoch {epoch+1:2d}/{epochs} | Train Loss: {trainloss:.4f} | Val Loss: {valloss:.4f}»)
return trainlosses, vallosses
Генерация синтетических данных
data = generatesyntheticdata(2000)
split_idx = int(0.8 * len(data))
traindata, valdata = data[:splitidx], data[splitidx:]
print(f»Train samples: {len(traindata)}, Val samples: {len(valdata)}»)
Создание токенизатора
tokenizer = SimpleTokenizer()
tokenizer.fit([text for text, in traindata])
print(f»Vocabulary size: {tokenizer.vocab_size}»)
Создание набора данных
traindataset = RLMDataset(traindata, tokenizer)
valdataset = RLMDataset(valdata, tokenizer)
trainloader = DataLoader(traindataset, batch_size=32, shuffle=True)
valloader = DataLoader(valdataset, batch_size=32)
Создание регрессионной языковой модели
model = RegressionLanguageModel(vocabsize=tokenizer.vocabsize)
print(f»Model parameters: {sum(p.numel() for p in model.parameters()):,}»)
Обучение модели
trainlosses, vallosses = trainrlm(model, trainloader, val_loader)
Визуализация прогресса обучения
plt.figure(figsize=(10, 4))
plt.plot(train_losses, label=’Train Loss’, linewidth=2)
plt.plot(val_losses, label=’Val Loss’, linewidth=2)
plt.xlabel(‘Epoch’)
plt.ylabel(‘Loss (MSE)’)
plt.title(‘RLM Training Progress’)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
Тестирование предсказаний
print(«\n Testing Predictions:»)
print(«-» * 60)
test_examples = [
«The temperature is 25.5 degrees»,
«I rate this 8.0 out of ten»,
«The price is 45.0 dollars»,
«75.0 percent complete»
]
with torch.no_grad():
for text in test_examples:
tokens = torch.tensor([tokenizer.encode(text)]).to(device)
prediction = model(tokens).item()
print(f»Input: {text}»)
print(f»Predicted value: {prediction:.4f}\n»)
print(» RLM Tutorial Complete!»)
«`
Мы успешно разработали, обучили и оценили регрессионную языковую модель, способную прогнозировать непрерывные значения на основе текстовых входных данных. Мы наблюдаем, как объединение позиционных вложений, трансформерных кодировщиков и простого регрессионного слоя позволяет модели улавливать числовую семантику, заложенную в языке.
1. Какие этапы включает в себя процесс создания регрессионной языковой модели на основе трансформера для прогнозирования непрерывных значений из текста?
Процесс включает в себя:
* генерацию синтетических данных;
* токенизацию;
* создание набора данных;
* обучение модели;
* тестирование.
2. Какие шаблоны используются для создания синтетических данных в этом проекте?
Для создания синтетических данных используются следующие шаблоны:
* «The temperature is {} degrees»;
* «I rate this {} out of ten»;
* «The price is {} dollars»;
* «Confidence level: {}»;
* «Speed of {} kilometers per hour»;
* «{} percent complete»;
* «Scored {} points in the game»;
* «The distance is {} meters».
3. Какие параметры используются для создания регрессионной языковой модели?
Для создания регрессионной языковой модели используются следующие параметры:
* размер словаря (vocab_size);
* размерность вложений (embed_dim);
* количество голов (num_heads);
* количество слоёв (num_layers);
* вероятность выпадения (dropout);
* максимальная длина последовательности (max_len).
4. Какие функции используются для обучения модели?
Для обучения модели используются следующие функции:
* generatesyntheticdata — для генерации синтетических данных;
* SimpleTokenizer — для токенизации текста;
* RLMDataset — для создания набора данных;
* RegressionLanguageModel — для создания регрессионной языковой модели;
* train_rlm — для обучения модели.
5. Какие инструменты и библиотеки используются в этом проекте?
В этом проекте используются следующие инструменты и библиотеки:
* Python;
* NumPy;
* PyTorch;
* Matplotlib;
* torch.nn;
* torch.optim;
* torch.utils.data.