Kiến trúc Transformer đã chứng tỏ khả năng vượt trội trong xử lý ngôn ngữ tự nhiên và gần đây đã mở rộng thành công sang lĩnh vực học đa phương thức, mang lại những bước tiến đột phá. Trong bối cảnh đa phương thức, Transformer cần xử lý dữ liệu không đồng nhất từ nhiều kênh khác nhau (thị giác, ngôn ngữ, âm thanh, v.v.), điều này đặt ra cả thách thức và cơ hội mới trong thiết kế kiến trúc.
Thích nghi kiến trúc Transformer cho Học Đa Phương Thức
Để thích nghi với môi trường đa phương thức, kiến trúc Transformer đã phát triển thành một số mô hình thiết kế chính:
Các Mô Hình Kiến Trúc Transformer Đa Phương Thức Cơ Bản
1. Kiến trúc Hợp nhất Sớm (Early Fusion)
Kiến trúc hợp nhất sớm tích hợp thông tin từ các phương thức khác nhau ngay tại lớp đầu vào, sử dụng chung một bộ mã hóa Transformer. Các ví dụ điển hình bao gồm VisualBERT và Unicoder-VL:
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
# Giả định các lớp mã hóa cơ bản
class ImageFeatureExtractor(nn.Module):
def __init__(self, output_dim=512):
super().__init__()
self.conv = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)
self.fc = nn.Linear(32 * 4 * 4, output_dim) # Kích thước giả định sau conv
def forward(self, img_batch):
x = F.relu(self.conv(img_batch))
x = x.view(x.size(0), -1) # Flatten
return self.fc(x).unsqueeze(1) # Thêm chiều sequence
class TextEmbeddingLayer(nn.Module):
def __init__(self, vocab_size, embed_dim=512):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
def forward(self, text_tokens):
return self.embedding(text_tokens)
# Giả định một khối Transformer cơ bản
class BaseTransformerBlock(nn.Module):
def __init__(self, embed_dim, num_heads, feedforward_dim, dropout=0.1):
super().__init__()
self.attn = nn.MultiheadAttention(embed_dim, num_heads, dropout=dropout, batch_first=True)
self.norm1 = nn.LayerNorm(embed_dim)
self.feed_forward = nn.Sequential(
nn.Linear(embed_dim, feedforward_dim),
nn.ReLU(),
nn.Linear(feedforward_dim, embed_dim)
)
self.norm2 = nn.LayerNorm(embed_dim)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
def forward(self, x):
attn_output, _ = self.attn(x, x, x)
x = self.norm1(x + self.dropout1(attn_output))
ff_output = self.feed_forward(x)
x = self.norm2(x + self.dropout2(ff_output))
return x
class UnifiedMultimodalModel(nn.Module):
def __init__(self, config):
super().__init__()
self.image_embedder = ImageFeatureExtractor(output_dim=config['embed_dim'])
self.text_embedder = TextEmbeddingLayer(vocab_size=config['vocab_size'], embed_dim=config['embed_dim'])
self.main_transformer = nn.Sequential(*[
BaseTransformerBlock(config['embed_dim'], config['num_heads'], config['feedforward_dim'])
for _ in range(config['num_layers'])
])
def forward(self, images, text_ids):
# Mã hóa riêng biệt đặc trưng thị giác và văn bản
visual_representations = self.image_embedder(images)
text_representations = self.text_embedder(text_ids)
# Nối các đầu vào đa phương thức
# Thêm một token [CLS] giả định hoặc một cách để phân biệt các phương thức
multimodal_combined_input = torch.cat([visual_representations, text_representations], dim=1)
# Xử lý bằng Transformer thống nhất
output_features = self.main_transformer(multimodal_combined_input)
return output_features
# Ví dụ cấu hình
# config_early = {'embed_dim': 512, 'num_heads': 8, 'feedforward_dim': 2048, 'num_layers': 6, 'vocab_size': 10000}
# model_early_fusion = UnifiedMultimodalModel(config_early)
2. Kiến trúc Hợp nhất Muộn (Late Fusion)
Kiến trúc hợp nhất muộn duy trì các bộ mã hóa Transformer độc lập cho mỗi phương thức, thực hiện việc hợp nhất đặc trưng ở các lớp cao hơn:
# Giả định các khối Transformer độc lập cho thị giác và văn bản
class VisionTransformer(nn.Module):
def __init__(self, config):
super().__init__()
self.feature_extractor = ImageFeatureExtractor(output_dim=config['embed_dim'])
self.encoder_blocks = nn.Sequential(*[
BaseTransformerBlock(config['embed_dim'], config['num_heads'], config['feedforward_dim'])
for _ in range(config['num_layers'])
])
def forward(self, img_input):
features = self.feature_extractor(img_input)
return self.encoder_blocks(features)
class LanguageTransformer(nn.Module):
def __init__(self, config):
super().__init__()
self.embedding_layer = TextEmbeddingLayer(vocab_size=config['vocab_size'], embed_dim=config['embed_dim'])
self.encoder_blocks = nn.Sequential(*[
BaseTransformerBlock(config['embed_dim'], config['num_heads'], config['feedforward_dim'])
for _ in range(config['num_layers'])
])
def forward(self, text_input_ids):
embeddings = self.embedding_layer(text_input_ids)
return self.encoder_blocks(embeddings)
class FeatureCombiner(nn.Module):
def __init__(self, input_dim, output_dim):
super().__init__()
self.linear_combine = nn.Linear(input_dim * 2, output_dim) # Giả định 2 phương thức
def forward(self, visual_reps, text_reps):
# Có thể dùng pooling trước khi nối nếu sequence lengths khác nhau
# Ví dụ: lấy [CLS] token hoặc global average pooling
visual_pooled = visual_reps.mean(dim=1)
text_pooled = text_reps.mean(dim=1)
combined = torch.cat([visual_pooled, text_pooled], dim=-1)
return self.linear_combine(combined)
class SeparateEncoderFusion(nn.Module):
def __init__(self, config):
super().__init__()
self.vision_net = VisionTransformer(config)
self.language_net = LanguageTransformer(config)
self.combiner_module = FeatureCombiner(config['embed_dim'], config['final_output_dim'])
def forward(self, image_data, text_data):
# Mã hóa độc lập từng phương thức
vision_encodings = self.vision_net(image_data)
language_encodings = self.language_net(text_data)
# Hợp nhất đặc trưng ở lớp cao
fused_representations = self.combiner_module(vision_encodings, language_encodings)
return fused_representations
# Ví dụ cấu hình
# config_late = {'embed_dim': 512, 'num_heads': 8, 'feedforward_dim': 2048, 'num_layers': 6, 'vocab_size': 10000, 'final_output_dim': 256}
# model_late_fusion = SeparateEncoderFusion(config_late)
3. Kiến trúc Chú ý Chéo (Cross-Attention)
Kiến trúc chú ý chéo cho phép tương tác sâu giữa các phương thức thông qua cơ chế chú ý chéo, với các mô hình tiêu biểu như ViLBERT và LXMERT:
(Mã ví dụ cho kiến trúc chú ý chéo sẽ được trình bày chi tiết hơn trong phần thảo luận về ViLBERT và LXMERT.)
Những Thách thức Kỹ thuật Chủ yếu và Giải pháp
Vấn đề Đồng bộ Phương thức (Modality Alignment)
Dữ liệu đa phương thức thường không đồng bộ về mặt thời gian hoặc không gian. Cơ chế tự chú ý của Transformer vốn dĩ có khả năng xử lý việc đồng bộ theo chuỗi:
class InterModalAttention(nn.Module):
def __init__(self, feature_dim):
super().__init__()
self.query_mapper = nn.Linear(feature_dim, feature_dim)
self.key_mapper = nn.Linear(feature_dim, feature_dim)
self.value_mapper = nn.Linear(feature_dim, feature_dim)
def forward(self, source_sequence, target_sequence):
# source_sequence (ví dụ: thị giác) đóng vai trò Query
# target_sequence (ví dụ: văn bản) đóng vai trò Key và Value
queries = self.query_mapper(source_sequence)
keys = self.key_mapper(target_sequence)
values = self.value_mapper(target_sequence)
# Tính trọng số chú ý chéo phương thức
attention_scores = torch.matmul(queries, keys.transpose(-2, -1)) / math.sqrt(queries.size(-1))
attention_weights = F.softmax(attention_scores, dim=-1)
# Áp dụng chú ý
aligned_representations = torch.matmul(attention_weights, values)
return aligned_representations
# Ví dụ sử dụng:
# visual_tokens = torch.randn(1, 10, 512) # batch, seq_len, dim
# text_tokens = torch.randn(1, 15, 512)
# cross_attn_layer = InterModalAttention(512)
# output = cross_attn_layer(visual_tokens, text_tokens)
Xử lý Tính không đồng nhất của Phương thức (Modality Heterogeneity)
Các phương thức khác nhau có đặc tính thống kê và mức độ chi tiết ngữ nghĩa khác nhau, đòi hỏi chiến lược tiền xử lý và trích xuất đặc trưng chuyên biệt:
| Loại Phương thức | Phương pháp Trích xuất Đặc trưng | Chiến lược Chuỗi hóa | Xử lý Đặc biệt |
|---|---|---|---|
| Hình ảnh | CNN/ViT | Đặc trưng lưới/patch | Mã hóa vị trí |
| Văn bản | Word Embedding/Byte-Pair Encoding | Chuỗi token | Mã hóa đoạn văn |
| Âm thanh | Phổ tần (Spectrogram) | Khung thời gian | Mã hóa tần số |
| Video | 3D CNN/Transformer | Khối không gian-thời gian | Mã hóa thời gian |
Tối ưu hóa Hiệu quả Tính toán
Transformer đa phương thức đối mặt với thách thức về độ phức tạp tính toán, yêu cầu các cơ chế chú ý hiệu quả:
class OptimizedMultimodalAttention(nn.Module):
def __init__(self, embed_dim, num_heads):
super().__init__()
self.embed_dim = embed_dim
self.num_heads = num_heads
self.head_dim = embed_dim // num_heads
# Projections for queries, keys, values for both modalities
self.query_proj_v = nn.Linear(embed_dim, embed_dim)
self.key_proj_v = nn.Linear(embed_dim, embed_dim)
self.value_proj_v = nn.Linear(embed_dim, embed_dim)
self.query_proj_t = nn.Linear(embed_dim, embed_dim)
self.key_proj_t = nn.Linear(embed_dim, embed_dim)
self.value_proj_t = nn.Linear(embed_dim, embed_dim)
self.output_proj = nn.Linear(embed_dim * 2, embed_dim) # Output combination
def _split_heads(self, x):
batch_size, seq_len, _ = x.size()
return x.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
def _combine_heads(self, x):
batch_size, num_heads, seq_len, head_dim = x.size()
return x.transpose(1, 2).contiguous().view(batch_size, seq_len, num_heads * head_dim)
def _compute_attention(self, q, k, v):
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.head_dim)
weights = F.softmax(scores, dim=-1)
return torch.matmul(weights, v)
def forward(self, visual_seq, text_seq):
batch_size = visual_seq.size(0)
# Apply projections and split into heads for visual modality
q_v = self._split_heads(self.query_proj_v(visual_seq))
k_v = self._split_heads(self.key_proj_v(visual_seq))
v_v = self._split_heads(self.value_proj_v(visual_seq))
# Apply projections and split into heads for text modality
q_t = self._split_heads(self.query_proj_t(text_seq))
k_t = self._split_heads(self.key_proj_t(text_seq))
v_t = self._split_heads(self.value_proj_t(text_seq))
# Cross-attention: visual queries attend to text keys/values
visual_attended_to_text = self._compute_attention(q_v, k_t, v_t)
# Cross-attention: text queries attend to visual keys/values
text_attended_to_visual = self._compute_attention(q_t, k_v, v_v)
# Combine heads back
visual_attended = self._combine_heads(visual_attended_to_text)
text_attended = self._combine_heads(text_attended_to_visual)
# Concatenate and project for final multimodal representation
combined_output = torch.cat([visual_attended, text_attended], dim=-1)
final_representation = self.output_proj(combined_output)
return final_representation
# Ví dụ sử dụng:
# visual_data = torch.randn(2, 50, 768) # Batch, Visual Tokens, Dim
# text_data = torch.randn(2, 30, 768) # Batch, Text Tokens, Dim
# efficient_attn = OptimizedMultimodalAttention(embed_dim=768, num_heads=12)
# output = efficient_attn(visual_data, text_data)
So sánh các Kiến trúc Transformer Đa Phương Thức Tiêu biểu
Bảng dưới đây tổng hợp các đặc điểm và kịch bản ứng dụng của các kiến trúc Transformer đa phương thức chính:
| Tên Mô hình | Chiến lược Hợp nhất | Phương pháp Tiền huấn luyện | Ưu điểm Chính | Nhiệm vụ Phù hợp |
|---|---|---|---|---|
| ViLBERT | Chú ý chéo hai luồng | Học đa phương thức bị che | Tương tác sâu giữa các phương thức | VQA, Truy xuất |
| LXMERT | Bộ mã hóa ba luồng | Tiền huấn luyện đa nhiệm vụ | Khả năng tổng quát hóa cao | Hiểu biết đa phương thức |
| VisualBERT | Hợp nhất sớm một luồng | Tiền huấn luyện end-to-end | Đơn giản, hiệu quả | Suy luận thị giác |
| UNITER | Bộ mã hóa thống nhất một luồng | Tiền huấn luyện quy mô lớn | Hiệu suất vượt trội | Học đa nhiệm vụ |
| CLIP | Học tương phản | Cặp hình ảnh-văn bản | Khả năng zero-shot | Phân loại, Truy xuất |
Các Yếu tố Thiết kế Kiến trúc trong Ứng dụng Thực tế
Khi triển khai Transformer đa phương thức, cần xem xét các yếu tố thiết kế kiến trúc sau:
1. Thiết kế Bộ mã hóa Đặc thù Phương thức
# Cấu hình bộ mã hóa cho từng phương thức
encoder_settings_by_modality = {
'vision_encoder': {
'model_type': 'ViT-Base',
'patch_dim': 16,
'embedding_dim': 768,
'num_blocks': 12
},
'text_encoder': {
'model_type': 'BERT-Base',
'vocabulary_size': 30522,
'embedding_dim': 768,
'num_blocks': 12
},
'audio_encoder': {
'model_type': 'AudioSpectrogramNet',
'sample_rate': 16000,
'embedding_dim': 512,
'num_blocks': 6
}
}
2. Hợp nhất Đặc trưng Đa tỷ lệ
Để tận dụng thông tin ở các mức độ chi tiết khác nhau, việc hợp nhất đặc trưng đa tỷ lệ là rất quan trọng. Điều này có thể đạt được bằng cách trích xuất đặc trưng từ nhiều lớp của bộ mã hóa từng phương thức và kết hợp chúng thông qua các cơ chế hợp nhất chuyên biệt (ví dụ: concatenating, summing, hoặc gated fusion).
3. Cơ chế Định tuyến Động
Thiết kế cơ chế định tuyến động để tự động lựa chọn đường dẫn hợp nhất tối ưu cho các mẫu đầu vào khác nhau:
class AdaptiveFusionSelector(nn.Module):
def __init__(self, num_modalities, num_fusion_experts, embedding_size):
super().__init__()
# Mạng lưới chọn lựa chuyên gia dựa trên sự kết hợp của các đặc trưng phương thức
self.selector_network = nn.Linear(num_modalities * embedding_size, num_fusion_experts)
def forward(self, list_of_modality_features):
# Nối các đặc trưng của tất cả các phương thức
# Giả định mỗi đặc trưng phương thức đã được pooled thành vector 1D (batch_size, embedding_size)
combined_modal_vector = torch.cat(list_of_modality_features, dim=-1)
# Tính điểm cho từng "chuyên gia" hợp nhất tiềm năng
modality_scores = self.selector_network(combined_modal_vector)
selection_probabilities = F.softmax(modality_scores, dim=-1)
# Chọn chuyên gia với xác suất cao nhất (hoặc lấy trung bình có trọng số)
selected_expert_index = torch.argmax(selection_probabilities, dim=-1)
return selected_expert_index
# Ví dụ:
# expert_router = AdaptiveFusionSelector(num_modalities=2, num_fusion_experts=3, embedding_size=768)
# visual_feat = torch.randn(1, 768) # Giả định đã pooled
# text_feat = torch.randn(1, 768)
# selected_expert = expert_router([visual_feat, text_feat])
Kỹ thuật Tối ưu hóa Hiệu suất
1. Chiến lược Cân bằng Gradient
Trong huấn luyện đa phương thức, thường xảy ra vấn đề mất cân bằng gradient giữa các phương thức. Các chiến lược cân bằng gradient có thể giúp điều chỉnh đóng góp của mỗi phương thức vào tổng lỗi:
def weighted_gradient_descent(loss_components_dict):
total_weighted_loss = 0.0
module_gradients = {}
for modality_name, loss_value in loss_components_dict.items():
# Tính toán một hệ số trọng số cân bằng cho mỗi phần mất mát
# Hàm calculate_weight_for_modality cần được định nghĩa tùy chỉnh
# dựa trên độ lớn mất mát, sự đóng góp hoặc các heuristic khác.
scaling_factor = calculate_weight_for_modality(modality_name, loss_value)
weighted_loss_part = loss_value * scaling_factor
weighted_loss_part.backward(retain_graph=True) # retain_graph để các loss khác cũng có thể gọi .backward()
# Thu thập gradient từ các module liên quan đến phương thức này
module_gradients[modality_name] = gather_module_gradients(modality_name)
total_weighted_loss += weighted_loss_part.item()
# Hàm giả định để tính trọng số (cần triển khai cụ thể)
def calculate_weight_for_modality(mod_name, current_loss):
# Ví dụ đơn giản: trọng số đảo nghịch với độ lớn loss hoặc hằng số
return 1.0 # Hoặc 1.0 / (current_loss.item() + 1e-6)
# Hàm giả định để thu thập gradient (cần triển khai cụ thể)
def gather_module_gradients(mod_name):
# Lấy gradient từ các tham số của các module liên quan
return {p.name: p.grad for p in some_model_params_for_modality if p.grad is not None} # Placeholder
return total_weighted_loss, module_gradients
# Ví dụ sử dụng:
# loss_img = torch.tensor(0.5, requires_grad=True)
# loss_txt = torch.tensor(0.1, requires_grad=True)
# losses = {'image': loss_img, 'text': loss_txt}
# total_loss, grads = weighted_gradient_descent(losses)
2. Tối ưu hóa Hiệu quả Bộ nhớ
Transformer đa phương thức tiêu tốn nhiều bộ nhớ. Các kỹ thuật như chú ý theo khối (chunked attention) có thể giảm đáng kể yêu cầu về bộ nhớ:
class ChunkedAttentionBlock(nn.Module):
def __init__(self, dimension, chunk_length=256):
super().__init__()
self.dimension = dimension
self.chunk_length = chunk_length
# Giả định một multi-head attention layer bên trong
self.attention_layer = nn.MultiheadAttention(dimension, num_heads=8, batch_first=True)
def forward(self, queries, keys, values):
batch_size, sequence_length, _ = queries.size()
output_result = torch.zeros_like(queries)
# Xử lý theo từng khối để giảm sử dụng bộ nhớ
for start_idx in range(0, sequence_length, self.chunk_length):
end_idx = min(start_idx + self.chunk_length, sequence_length)
queries_chunk = queries[:, start_idx:end_idx, :]
# Tính toán chú ý cho khối hiện tại
# Trong một MultiheadAttention thực tế, cần cung cấp Q, K, V cho attention_layer
# Nhưng ở đây, để minh họa, chúng ta giả định nó xử lý đầu vào trong một lượt
# (thường các thư viện đã tối ưu hóa điều này nội bộ hoặc cần triển khai thủ công)
# Đối với mục đích minh họa đơn giản:
# chunk_output, _ = self.attention_layer(queries_chunk, keys, values)
# Để đơn giản hóa logic, giả định tính toán chú ý trực tiếp
# Q_chunk, K, V
# Trong thực tế, bạn sẽ tính toán attention scores cho từng Q_chunk với toàn bộ K, V
# Ví dụ về cách tính attention cho một khối Q với toàn bộ K, V:
query_proj = nn.Linear(self.dimension, self.dimension, bias=False)(queries_chunk)
key_proj = nn.Linear(self.dimension, self.dimension, bias=False)(keys)
value_proj = nn.Linear(self.dimension, self.dimension, bias=False)(values)
# Chia heads cho query_proj, key_proj, value_proj...
# ... (cần thêm logic chia head và tính attention)
# Để giữ ví dụ ngắn gọn, chúng ta giả định đây là một hàm attention đã được tối ưu hóa.
# Trong một triển khai thực tế, bạn sẽ cần logic để tính toán attention cho từng khối query
# với toàn bộ key và value hoặc sử dụng các kỹ thuật sparse/linear attention.
# Giả sử một hàm tính toán chú ý cho khối đã có
scores = torch.matmul(query_proj, key_proj.transpose(-2, -1)) / math.sqrt(self.dimension)
weights = F.softmax(scores, dim=-1)
chunk_output = torch.matmul(weights, value_proj)
output_result[:, start_idx:end_idx, :] = chunk_output
return output_result
# Ví dụ:
# Q_tensor = torch.randn(1, 1024, 768)
# K_tensor = torch.randn(1, 1024, 768)
# V_tensor = torch.randn(1, 1024, 768)
# chunked_attn = ChunkedAttentionBlock(dimension=768, chunk_length=128)
# output_mem_efficient = chunked_attn(Q_tensor, K_tensor, V_tensor)
Việc thích nghi kiến trúc Transformer cho học đa phương thức là một lĩnh vực nghiên cứu đầy thử thách nhưng mang lại nhiều giá trị. Thông qua các chiến lược hợp nhất được thiết kế cẩn thận, cơ chế chú ý hiệu quả và kỹ thuật tối ưu hóa thông minh, kiến trúc Transformer có thể phát huy tối đa tiềm năng trong học đa phương thức, cung cấp cho các hệ thống AI khả năng nhận thức và hiểu biết mạnh mẽ hơn.
Các Mô hình Kinh điển: ViLBERT và LXMERT
Trong lịch sử phát triển của học đa phương thức, ViLBERT và LXMERT, được giới thiệu vào năm 2019, là hai mô hình cột mốc quan trọng, đặt nền tảng vững chắc cho các nhiệm vụ hiểu biết thị giác-ngôn ngữ. Những mô hình này đã mở rộng thành công khả năng học biểu diễn mạnh mẽ của Transformer sang lĩnh vực đa phương thức thông qua thiết kế kiến trúc và chiến lược tiền huấn luyện đổi mới.
ViLBERT: BERT Song Luồng cho Thị giác và Ngôn ngữ
ViLBERT (Vision-and-Language BERT) là một trong những mô hình đầu tiên mở rộng kiến trúc BERT thành công sang lĩnh vực đa phương thức. Đổi mới cốt lõi của nó nằm ở việc áp dụng kiến trúc song luồng, xử lý riêng biệt đầu vào thị giác và văn bản, sau đó thực hiện tương tác chéo phương thức thông qua cơ chế đồng chú ý (co-attention).
Thiết kế Kiến trúc
ViLBERT sử dụng hai luồng xử lý độc lập:
- Luồng Thị giác: Xử lý đặc trưng hình ảnh.
- Luồng Văn bản: Xử lý nhúng từ (word embeddings) và nhúng vị trí (positional embeddings) của văn bản.
Luồng thị giác của ViLBERT sử dụng bộ phát hiện vật thể Faster R-CNN để trích xuất đặc trưng vùng từ hình ảnh, mỗi vùng được biểu diễn dưới dạng một vector đặc trưng 2048 chiều. Luồng văn bản sử dụng bộ mã hóa và lớp nhúng BERT tiêu chuẩn để xử lý đầu vào văn bản.
Cơ chế Đồng chú ý (Co-attention)
Lớp đồng chú ý là đổi mới cốt lõi của ViLBERT, cho phép trao đổi thông tin hai chiều giữa hai phương thức:
class MutualAttentionUnit(nn.Module):
def __init__(self, representation_dim, head_count):
super().__init__()
# Chú ý từ thị giác đến văn bản (Query: Visual, Key/Value: Text)
self.image_to_text_attention = nn.MultiheadAttention(representation_dim, head_count, batch_first=True)
# Chú ý từ văn bản đến thị giác (Query: Text, Key/Value: Visual)
self.text_to_image_attention = nn.MultiheadAttention(representation_dim, head_count, batch_first=True)
def forward(self, img_reps, text_reps):
# Đặc trưng hình ảnh được chú ý dựa trên ngữ cảnh văn bản
visual_contextualized, _ = self.image_to_text_attention(
img_reps, text_reps, text_reps
)
# Đặc trưng văn bản được chú ý dựa trên ngữ cảnh hình ảnh
text_contextualized, _ = self.text_to_image_attention(
text_reps, img_reps, img_reps
)
return visual_contextualized, text_contextualized
# Ví dụ:
# img_features = torch.randn(1, 36, 768) # Batch, num_regions, dim
# text_features = torch.randn(1, 20, 768) # Batch, num_tokens, dim
# co_attn_block = MutualAttentionUnit(768, 12)
# attended_img, attended_text = co_attn_block(img_features, text_features)
Nhiệm vụ Tiền huấn luyện
ViLBERT sử dụng hai nhiệm vụ tiền huấn luyện chính:
- Mô hình hóa Đa phương thức Bị che (Masked Multimodal Modeling): Che ngẫu nhiên các token văn bản hoặc vùng thị giác, mô hình phải dự đoán chúng dựa trên ngữ cảnh.
- Dự đoán Đồng bộ Đa phương thức (Multimodal Alignment Prediction): Dự đoán xem cặp hình ảnh-văn bản có khớp với nhau hay không.
LXMERT: Học Biểu diễn Bộ mã hóa Chéo Phương thức
LXMERT (Learning Cross-Modality Encoder Representations from Transformers) áp dụng kiến trúc ba bộ mã hóa, được thiết kế đặc biệt để học các mối quan hệ đồng bộ sâu sắc giữa thị giác và ngôn ngữ.
Kiến trúc Ba Bộ mã hóa
LXMERT bao gồm ba thành phần cốt lõi:
- Bộ mã hóa Vật thể (Object-Relationship Encoder): Xử lý thông tin thị giác, bao gồm cả mối quan hệ giữa các vật thể.
- Bộ mã hóa Ngôn ngữ (Language Encoder): Xử lý đầu vào văn bản.
- Bộ mã hóa Chéo Phương thức (Cross-Modality Encoder): Tích hợp thông tin từ hai bộ mã hóa trên thông qua chú ý chéo.
Chiến lược Tiền huấn luyện
LXMERT sử dụng năm nhiệm vụ tiền huấn luyện đa dạng:
| Nhiệm vụ Tiền huấn luyện | Mô tả | Mục tiêu |
|---|---|---|
| Mô hình hóa Ngôn ngữ Bị che | Che token văn bản và dự đoán | Hiểu biết ngôn ngữ |
| Dự đoán Vật thể Bị che | Che vùng thị giác và dự đoán | Hiểu biết thị giác |
| Đối sánh Chéo Phương thức | Xác định cặp hình ảnh-văn bản khớp | Đồng bộ chéo phương thức |
| Trả lời câu hỏi dựa trên Hình ảnh | Trả lời câu hỏi văn bản về hình ảnh | Khả năng suy luận |
| Phát hiện Mối quan hệ Thị giác | Xác định mối quan hệ giữa các vật thể | Hiểu biết không gian |
Chi tiết Triển khai Kỹ thuật
Bộ mã hóa chéo phương thức của LXMERT sử dụng cấu trúc Transformer đa lớp:
class IntermodalFusionLayer(nn.Module):
def __init__(self, embed_dim, num_heads):
super().__init__()
# Chú ý tự thân cho mỗi phương thức
self.vision_self_attn = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)
self.text_self_attn = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)
# Chú ý chéo: thị giác query văn bản
self.vision_to_text_attn = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)
# Chú ý chéo: văn bản query thị giác
self.text_to_vision_attn = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)
self.feed_forward = nn.Sequential(
nn.Linear(embed_dim, embed_dim * 4),
nn.ReLU(),
nn.Linear(embed_dim * 4, embed_dim)
)
self.norm1 = nn.LayerNorm(embed_dim)
self.norm2 = nn.LayerNorm(embed_dim)
self.norm3 = nn.LayerNorm(embed_dim)
self.norm4 = nn.LayerNorm(embed_dim)
self.dropout = nn.Dropout(0.1)
def forward(self, vis_input, text_input):
# 1. Self-attention cho từng phương thức
vis_attn_out, _ = self.vision_self_attn(vis_input, vis_input, vis_input)
vis_input = self.norm1(vis_input + self.dropout(vis_attn_out))
text_attn_out, _ = self.text_self_attn(text_input, text_input, text_input)
text_input = self.norm2(text_input + self.dropout(text_attn_out))
# 2. Cross-attention giữa các phương thức
# Thị giác hỏi văn bản
vis_cross_attn_out, _ = self.vision_to_text_attn(vis_input, text_input, text_input)
vis_output = self.norm3(vis_input + self.dropout(vis_cross_attn_out))
# Văn bản hỏi thị giác
text_cross_attn_out, _ = self.text_to_vision_attn(text_input, vis_input, vis_input)
text_output = self.norm4(text_input + self.dropout(text_cross_attn_out))
# 3. Feed-forward layer (thường áp dụng sau mỗi lớp Transformer)
vis_output = vis_output + self.dropout(self.feed_forward(vis_output))
text_output = text_output + self.dropout(self.feed_forward(text_output))
return vis_output, text_output
class CrossDomainTransformerBlock(nn.Module):
def __init__(self, feature_dim, num_layers, num_heads):
super().__init__()
self.layers = nn.ModuleList([
IntermodalFusionLayer(feature_dim, num_heads)
for _ in range(num_layers)
])
def forward(self, vision_features, language_features):
for layer_block in self.layers:
vision_features, language_features = layer_block(
vision_features, language_features
)
return vision_features, language_features
# Ví dụ:
# vision_embeds = torch.randn(1, 36, 768)
# lang_embeds = torch.randn(1, 20, 768)
# lxmert_cross_encoder = CrossDomainTransformerBlock(feature_dim=768, num_layers=9, num_heads=12)
# final_vision_embeds, final_lang_embeds = lxmert_cross_encoder(vision_embeds, lang_embeds)
So sánh Hiệu suất Mô hình
ViLBERT và LXMERT đã thể hiện hiệu suất xuất sắc trên nhiều bộ dữ liệu tiêu chuẩn:
| Mô hình | VQA v2.0 | GQA | NLVR2 | Số tham số |
|---|---|---|---|---|
| ViLBERT | 70.55% | - | - | 220M |
| LXMERT | 72.42% | 60.00% | 76.18% | 183M |
| VisualBERT | 70.80% | - | - | 110M |
| VL-BERT | 71.16% | - | - | 108M |
Đóng góp Đổi mới và Tác động
Những đóng góp chính của ViLBERT
- Tiền huấn luyện độc lập nhiệm vụ: Lần đầu tiên chứng minh rằng các biểu diễn thị giác-ngôn ngữ có thể được tiền huấn luyện và chuyển giao sang nhiều nhiệm vụ hạ nguồn khác nhau.
- Kiến trúc song luồng: Duy trì tính đặc thù của phương thức trong khi vẫn cho phép tương tác chéo phương thức hiệu quả.
- Tiền huấn luyện quy mô lớn: Sử dụng tập dữ liệu Conceptual Captions để tiền huấn luyện.
Những đổi mới cốt lõi của LXMERT
- Thiết kế ba bộ mã hóa: Bộ mã hóa quan hệ vật thể, bộ mã hóa ngôn ngữ và bộ mã hóa chéo phương thức chuyên biệt.
- Nhiệm vụ tiền huấn luyện đa dạng: Năm mục tiêu tiền huấn luyện bổ sung bao quát toàn diện nhu cầu hiểu biết đa phương thức.
- Khả năng tổng quát hóa mạnh mẽ: Đạt được mức cải thiện tuyệt đối 22% trong các nhiệm vụ suy luận thị giác.
Ví dụ Ứng dụng Thực tế
Dưới đây là một ví dụ mã sử dụng LXMERT cho nhiệm vụ hỏi đáp thị giác:
import torch
from transformers import LxmertForQuestionAnswering, LxmertTokenizer
from PIL import Image
# Tải mô hình và bộ token hóa đã được tiền huấn luyện
qa_processor = LxmertForQuestionAnswering.from_pretrained("unc-nlp/lxmert-base-qa-uncased")
lxmert_token_encoder = LxmertTokenizer.from_pretrained("unc-nlp/lxmert-base-qa-uncased")
# Chuẩn bị đầu vào
# Thay đổi đường dẫn đến một tệp ảnh thực tế trên hệ thống của bạn
sample_image_path = "example.jpg"
try:
input_image = Image.open(sample_image_path).convert("RGB")
except FileNotFoundError:
print(f"Error: Image file not found at {sample_image_path}. Please provide a valid path.")
exit()
query_question = "What color is the car in the image?"
# Xử lý đầu vào bằng bộ token hóa
processed_inputs = lxmert_token_encoder(
question=query_question,
# LxMERT cũng cần các đặc trưng hình ảnh, thường được trích xuất bởi Faster R-CNN.
# Đối với ví dụ này, chúng ta sẽ bỏ qua bước trích xuất đặc trưng hình ảnh phức tạp
# và giả định mô hình có thể xử lý chỉ từ câu hỏi.
# Trong ứng dụng thực tế, bạn sẽ cần:
# visual_features = get_image_features(input_image)
# visual_boxes = get_image_boxes(input_image)
# ... và truyền chúng vào mô hình cùng với encoded_inputs.
# Hiện tại, chỉ xử lý phần văn bản.
return_tensors="pt",
padding="max_length",
max_length=20,
truncation=True
)
# Để ví dụ này chạy được mà không cần các đặc trưng thị giác phức tạp,
# chúng ta cần tạo các tensor giả cho visual_feats và visual_bboxes.
# Trong một triển khai thực tế, chúng sẽ đến từ một mô hình trích xuất đặc trưng thị giác.
batch_size = processed_inputs['input_ids'].shape[0]
dummy_visual_feats = torch.randn(batch_size, 36, 2048) # Giả định 36 vùng, dim 2048
dummy_visual_bboxes = torch.randn(batch_size, 36, 4) # Giả định 36 bounding boxes
# Thực hiện dự đoán
with torch.no_grad():
prediction_results = qa_processor(
input_ids=processed_inputs['input_ids'],
attention_mask=processed_inputs['attention_mask'],
token_type_ids=processed_inputs['token_type_ids'],
visual_feats=dummy_visual_feats,
visual_pos=dummy_visual_bboxes # Hoặc visual_pos, tùy theo yêu cầu của model
)
# Lấy câu trả lời được dự đoán
predicted_answer_idx = torch.argmax(prediction_results.question_answering_score, dim=-1)
decoded_answer = lxmert_token_encoder.decode(predicted_answer_idx)
print(f"Câu hỏi: {query_question}")
print(f"Câu trả lời dự đoán: {decoded_answer}")
Thách thức Kỹ thuật và Giải pháp
Vấn đề Đồng bộ Phương thức
ViLBERT và LXMERT giải quyết thách thức đồng bộ phương thức thông qua các cách sau:
- Đồng bộ phân cấp: Thiết lập kết nối chéo phương thức ở các cấp độ trừu tượng khác nhau.
- Cơ chế chú ý: Sử dụng cơ chế tự chú ý và chú ý chéo để học các mối quan hệ đồng bộ.
- Tiền huấn luyện đa nhiệm vụ: Buộc mô hình học các biểu diễn đồng bộ thông qua các nhiệm vụ đa dạng.
Tối ưu hóa Hiệu quả Tính toán
| Chiến lược Tối ưu hóa | ViLBERT | LXMERT |
|---|---|---|
| Chia sẻ tham số | Chia sẻ một phần | Các bộ mã hóa độc lập |
| Cơ chế chú ý | Đồng chú ý | Chú ý chéo |
| Hiệu quả tiền huấn luyện | Trung bình | Khá cao |
Ảnh hưởng Phát triển và Các công trình Tiếp theo
Thành công của ViLBERT và LXMERT đã đặt nền tảng cho các mô hình Transformer đa phương thức tiếp theo:
- Mô hình kiến trúc: Xác lập mô hình hai luồng hoặc ba luồng với tương tác chú ý chéo là một phương pháp tiêu chuẩn.
- Chiến lược tiền huấn luyện: Khẳng định hiệu quả của tiền huấn luyện trên các cặp dữ liệu đa phương thức quy mô lớn.