← Назад к вопросам

В чем разница между энкодером и декодером?

1.7 Middle🔥 81 комментариев
#Глубокое обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между энкодером и декодером

Энкодер и декодер - это два компонента архитектуры нейронных сетей, которые работают вместе в моделях типа "Encoder-Decoder" и Transformer.

Энкодер (Encoder)

Назначение: обработка входных данных и создание представления

  • Берет исходные данные (текст, изображение, звук)
  • Извлекает признаки и семантику
  • Создает плотное представление (embedding/latent space)
  • Направлен внутрь (от входа к внутреннему представлению)
import torch
import torch.nn as nn

class SimpleEncoder(nn.Module):
    def __init__(self, input_size, hidden_size, latent_size):
        super().__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, latent_size)
    
    def forward(self, x):
        # x shape: (batch_size, input_size)
        h = torch.relu(self.fc1(x))
        z = self.fc2(h)  # latent representation
        return z

# Пример: энкодер берет текст, выдает эмбеддинг
encoder = SimpleEncoder(input_size=768, hidden_size=256, latent_size=128)
text_embedding = encoder(input_text)  # (batch_size, 128)

Декодер (Decoder)

Назначение: восстановление или генерация данных из представления

  • Берет плотное представление (embedding)
  • Восстанавливает исходный формат
  • Генерирует выходные данные
  • Направлен наружу (от внутреннего представления к выходу)
class SimpleDecoder(nn.Module):
    def __init__(self, latent_size, hidden_size, output_size):
        super().__init__()
        self.fc1 = nn.Linear(latent_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)
    
    def forward(self, z):
        # z shape: (batch_size, latent_size)
        h = torch.relu(self.fc1(z))
        x_reconstructed = self.fc2(h)  # восстановленные данные
        return x_reconstructed

# Пример: декодер берет эмбеддинг, выдает текст
decoder = SimpleDecoder(latent_size=128, hidden_size=256, output_size=768)
reconstructed_text = decoder(text_embedding)  # (batch_size, 768)

Полная архитектура Autoencoder

class Autoencoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = SimpleEncoder(768, 256, 128)
        self.decoder = SimpleDecoder(128, 256, 768)
    
    def forward(self, x):
        z = self.encoder(x)  # Энкодер
        x_reconstructed = self.decoder(z)  # Декодер
        return x_reconstructed, z

# Использование
autoencoder = Autoencoder()
output, latent = autoencoder(input_data)

# Loss function - насколько хорошо восстановили данные
loss = nn.MSELoss()(output, input_data)

Architektura Encoder-Decoder (Seq2Seq)

Энкодер и декодер разделены и могут быть разными:

Вход: "Hello"    Выход: "Привет"
  |
  v
[ЭНКОДЕР]  -> скрытый вектор состояния -> [ДЕКОДЕР]
     |
     v
  context
     ^
     |
  используется декодером
import torch
import torch.nn as nn

class Seq2SeqEncoder(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.gru = nn.GRU(embedding_dim, hidden_dim, batch_first=True)
    
    def forward(self, input_ids):
        # input_ids: (batch_size, seq_len)
        embedded = self.embedding(input_ids)  # (batch_size, seq_len, embedding_dim)
        _, hidden = self.gru(embedded)  # hidden: (1, batch_size, hidden_dim)
        return hidden

class Seq2SeqDecoder(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.gru = nn.GRU(embedding_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, vocab_size)
    
    def forward(self, input_ids, hidden):
        # input_ids: (batch_size, 1)
        # hidden: (1, batch_size, hidden_dim) из энкодера
        embedded = self.embedding(input_ids)  # (batch_size, 1, embedding_dim)
        output, hidden = self.gru(embedded, hidden)
        logits = self.fc(output)  # (batch_size, 1, vocab_size)
        return logits, hidden

# Использование
encoder = Seq2SeqEncoder(vocab_size=5000, embedding_dim=256, hidden_dim=512)
decoder = Seq2SeqDecoder(vocab_size=5000, embedding_dim=256, hidden_dim=512)

input_ids = torch.tensor([[1, 2, 3, 4]])  # "Hello"
encoder_hidden = encoder(input_ids)  # Context от энкодера

# Декодер генерирует ответ
output_logits, _ = decoder(torch.tensor([[1]]), encoder_hidden)

Encoder-Decoder в Transformers

BERT - только энкодер:

from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")  # Только encoder

inputs = tokenizer("Hello world", return_tensors="pt")
outputs = model(**inputs)
embeddings = outputs.last_hidden_state  # (1, seq_len, 768)

T5 - энкодер + декодер:

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")  # Encoder + Decoder

inputs = tokenizer("translate English to French: Hello", return_tensors="pt")
outputs = model(**inputs)
# Encoder обработает "Hello"
# Decoder сгенерирует перевод

Практический пример: Автоматическое сжатие текста

import torch
import torch.nn as nn

class TextAutoencoder(nn.Module):
    def __init__(self, vocab_size, embedding_dim, latent_dim):
        super().__init__()
        
        # Энкодер: текст -> сжатое представление
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.encoder_lstm = nn.LSTM(embedding_dim, 256, batch_first=True)
        self.fc_latent = nn.Linear(256, latent_dim)
        
        # Декодер: сжатое представление -> текст
        self.fc_decode = nn.Linear(latent_dim, 256)
        self.decoder_lstm = nn.LSTM(256, 256, batch_first=True)
        self.fc_out = nn.Linear(256, vocab_size)
    
    def encode(self, input_ids):
        # Энкодер
        x = self.embedding(input_ids)
        _, (h, c) = self.encoder_lstm(x)
        latent = self.fc_latent(h[0])
        return latent
    
    def decode(self, latent, seq_len):
        # Декодер
        x = self.fc_decode(latent).unsqueeze(1)
        output, _ = self.decoder_lstm(x.expand(-1, seq_len, -1))
        logits = self.fc_out(output)
        return logits
    
    def forward(self, input_ids):
        latent = self.encode(input_ids)
        seq_len = input_ids.size(1)
        output = self.decode(latent, seq_len)
        return output, latent

# Использование
model = TextAutoencoder(vocab_size=5000, embedding_dim=128, latent_dim=64)
input_text = torch.randint(0, 5000, (2, 50))  # batch_size=2, seq_len=50

reconstructed, compressed = model(input_text)
print(f"Входные данные: {input_text.shape}")
print(f"Сжатое представление: {compressed.shape}")  # Намного меньше!
print(f"Восстановленные данные: {reconstructed.shape}")

Таблица сравнения

АспектЭнкодерДекодер
НаправлениеВход → ВнутренностьВнутренность → Выход
ЗадачаИзвлечение признаковГенерация/восстановление
ВходИсходные данныеПредставление (embedding)
ВыходКомпактное представлениеДанные в исходном формате
Примертекст → векторвектор → текст

Применение в разных задачах

1. Классификация (только энкодер)

embedding = encoder(text)
logits = classifier(embedding)

2. Перевод (энкодер + декодер)

latent = encoder(text_en)
text_ru = decoder(latent)

3. Автоматическое сжатие (энкодер + декодер)

compressed = encoder(image)  # Малый размер
restored = decoder(compressed)  # Восстановленное

4. Генерация (только декодер)

latent = random_vector()
generated = decoder(latent)

Вывод: Энкодер сжимает информацию, декодер её распаковывает. Вместе они создают мощные архитектуры для трансформации данных.