در این آموزش، ما یک رویکرد جدید یادگیری عمیق را بررسی میکنیم که توجه پنهان چند-سر را با تقسیمبندی تخصصی دقیق ترکیب میکند. با استفاده از قدرت توجه پنهان، مدل مجموعهای از ویژگیهای تخصصی پالایششده را یاد میگیرد که زمینه سطح بالا و جزئیات فضایی را ضبط میکند و در نهایت تقسیمبندی دقیق در سطح پیکسل را ممکن میسازد. در طول این پیادهسازی، ما شما را از طریق یک پیادهسازی سرتاسری با استفاده از PyTorch در Google Colab راهنمایی میکنیم و بلوکهای اصلی کلیدی، از یک رمزگذار کانولوشن ساده تا مکانیسمهای توجه که ویژگیهای حیاتی را برای تقسیمبندی جمع میکنند، نشان میدهیم. این راهنمای عملی برای کمک به شما در درک و آزمایش تکنیکهای پیشرفته تقسیمبندی با استفاده از دادههای مصنوعی به عنوان نقطه شروع طراحی شده است.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدimport torch
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
import numpy as np
torch.manual_seed(42)
ما کتابخانههای ضروری مانند PyTorch را برای یادگیری عمیق، numpy را برای محاسبات عددی و matplotlib را برای تجسم وارد میکنیم و یک محیط قوی برای ساخت شبکههای عصبی راهاندازی میکنیم. همچنین، torch.manual_seed(42) با ثابت کردن seed تصادفی برای همه مولدهای اعداد تصادفی مبتنی بر torch، نتایج قابل تکرار را تضمین میکند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدclass SimpleEncoder(nn.Module):
"""
A basic CNN encoder that extracts feature maps from an input image.
Two convolutional layers with ReLU activations and max-pooling are used
to reduce spatial dimensions.
"""
def __init__(self, in_channels=3, feature_dim=64):
super(). __init__()
self.conv1 = nn.Conv2d(in_channels, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, feature_dim, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.pool(x)
x = F.relu(self.conv2(x))
x = self.pool(x)
return x
کلاس SimpleEncoder یک شبکه عصبی کانولوشن (CNN) اساسی را پیادهسازی میکند که نقشههای ویژگی را از یک تصویر ورودی استخراج میکند. از دو لایه کانولوشن همراه با فعالسازیهای ReLU و max-pooling برای کاهش تدریجی ابعاد فضایی استفاده میکند و در نتیجه نمایش تصویر را برای پردازش بعدی ساده میکند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدclass LatentAttention(nn.Module):
"""
This module learns a set of latent vectors (the experts) and refines them
using multi-head attention on the input features.
Input:
x: A flattened feature tensor of shape [B, N, feature_dim],
where N is the number of spatial tokens.
Output:
latent_output: The refined latent expert representations of shape [B, num_latents, latent_dim].
"""
def __init__(self, feature_dim, latent_dim, num_latents, num_heads):
super().__init__()
self.num_latents = num_latents
self.latent_dim = latent_dim
self.latents = nn.Parameter(torch.randn(num_latents, latent_dim))
self.key_proj = nn.Linear(feature_dim, latent_dim)
self.value_proj = nn.Linear(feature_dim, latent_dim)
self.query_proj = nn.Linear(latent_dim, latent_dim)
self.attention = nn.MultiheadAttention(embed_dim=latent_dim, num_heads=num_heads, batch_first=True)
def forward(self, x):
B, N, _ = x.shape
keys = self.key_proj(x)
values = self.value_proj(x)
queries = self.latents.unsqueeze(0).expand(B, -1, -1)
queries = self.query_proj(queries)
latent_output, _ = self.attention(query=queries, key=keys, value=values)
return latent_output
ماژول LatentAttention یک مکانیزم توجه پنهان را پیادهسازی میکند که در آن مجموعهای ثابت از بردارهای تخصصی پنهان از طریق توجه چند-سر با استفاده از ویژگیهای ورودی پیشبینی شده به عنوان کلیدها و مقادیر پالایش میشوند. در گذر رو به جلو (forward pass)، این بردارهای پنهان (پرس و جوها) به ورودی تبدیل شده توجه میکنند و در نتیجه نمایشهای تخصصی پالایششدهای ایجاد میکنند که وابستگیهای ویژگی زیربنایی را ثبت میکنند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدclass ExpertSegmentation(nn.Module):
"""
For fine-grained segmentation, each pixel (or patch) feature first projects into the latent space.
Then, it attends over the latent experts (the output of the LatentAttention module) to obtain a refined representation.
Finally, a segmentation head projects the attended features to per-pixel class logits.
Input:
x: Flattened pixel features from the encoder [B, N, feature_dim]
latent_experts: Latent representations from the attention module [B, num_latents, latent_dim]
Output:
logits: Segmentation logits [B, N, num_classes]
"""
def __init__(self, feature_dim, latent_dim, num_heads, num_classes):
super().__init__()
self.pixel_proj = nn.Linear(feature_dim, latent_dim)
self.attention = nn.MultiheadAttention(embed_dim=latent_dim, num_heads=num_heads, batch_first=True)
self.segmentation_head = nn.Linear(latent_dim, num_classes)
def forward(self, x, latent_experts):
queries = self.pixel_proj(x)
attn_output, _ = self.attention(query=queries, key=latent_experts, value=latent_experts)
logits = self.segmentation_head(attn_output)
return logits
ماژول ExpertSegmentation ویژگیهای سطح پیکسل را برای تقسیمبندی با پیشبینی ابتدا آنها به فضای پنهان و سپس اعمال توجه چند-سر با استفاده از نمایشهای تخصصی پنهان، پالایش میکند. در نهایت، این ویژگیهای پالایششده را از طریق یک سر تقسیمبندی برای تولید logits کلاس در هر پیکسل نگاشت میکند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدclass SegmentationModel(nn.Module):
"""
The final model that ties together the encoder, latent attention module,
and the expert segmentation head into one end-to-end trainable architecture.
"""
def __init__(self, in_channels=3, feature_dim=64, latent_dim=64, num_latents=16, num_heads=4, num_classes=2):
super().__init__()
self.encoder = SimpleEncoder(in_channels, feature_dim)
self.latent_attn = LatentAttention(feature_dim=feature_dim, latent_dim=latent_dim,
num_latents=num_latents, num_heads=num_heads)
self.expert_seg = ExpertSegmentation(feature_dim=feature_dim, latent_dim=latent_dim,
num_heads=num_heads, num_classes=num_classes)
def forward(self, x):
features = self.encoder(x)
B, F, H, W = features.shape
features_flat = features.view(B, F, H * W).permute(0, 2, 1)
latent_experts = self.latent_attn(features_flat)
logits_flat = self.expert_seg(features_flat, latent_experts)
logits = logits_flat.permute(0, 2, 1).view(B, -1, H, W)
return logits
کلاس SegmentationModel رمزگذار CNN، ماژول توجه پنهان و سر تقسیمبندی تخصصی را در یک شبکه یکپارچه و قابل آموزش سرتاسری ادغام میکند. در طول گذر رو به جلو، مدل تصویر ورودی را به نقشههای ویژگی رمزگذاری میکند، این ویژگیها را برای پردازش توجه پنهان مسطح و تبدیل میکند و در نهایت از تقسیمبندی تخصصی برای تولید logits کلاس در هر پیکسل استفاده میکند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدmodel = SegmentationModel()
x_dummy = torch.randn(2, 3, 128, 128)
output = model(x_dummy)
print("Output shape:", output.shape)
ما مدل تقسیمبندی را نمونهسازی میکنیم و یک دستهای از تصاویر RGB با ابعاد 128×128 را از آن عبور میدهیم. شکل خروجی چاپ شده تأیید میکند که مدل ورودی را به درستی پردازش میکند و نقشههای تقسیمبندی را با ابعاد مورد انتظار تولید میکند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدdef generate_synthetic_data(batch_size, channels, height, width, num_classes):
"""
Generates a batch of synthetic images and corresponding segmentation targets.
The segmentation targets have lower resolution reflecting the encoder’s output size.
"""
x = torch.randn(batch_size, channels, height, width)
target_h, target_w = height // 4, width // 4
y = torch.randint(0, num_classes, (batch_size, target_h, target_w))
return x, y
batch_size = 4
channels = 3
height = 128
width = 128
num_classes = 2
model = SegmentationModel(in_channels=channels, num_classes=num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
num_iterations = 100
model.train()
for iteration in range(num_iterations):
x_batch, y_batch = generate_synthetic_data(batch_size, channels, height, width, num_classes)
optimizer.zero_grad()
logits = model(x_batch) # logits shape: [B, num_classes, H/4, W/4]
loss = criterion(logits, y_batch)
loss.backward()
optimizer.step()
if iteration % 10 == 0:
print(f"Iteration {iteration}: Loss = {loss.item():.4f}")
ما یک مولد داده مصنوعی تعریف میکنیم که تصاویر تصادفی و اهداف تقسیمبندی با وضوح پایین مربوطه را برای مطابقت با وضوح خروجی رمزگذار تولید میکند. سپس، مدل تقسیمبندی را برای 100 تکرار با استفاده از تابع زیان cross-entropy و بهینهساز Adam تنظیم و آموزش میدهیم. مقادیر زیان هر 10 تکرار چاپ میشوند تا پیشرفت آموزش را نظارت کنند.
کپی کد کپی شد از مرورگر دیگری استفاده کنیدmodel.eval()
x_vis, y_vis = generate_synthetic_data(1, channels, height, width, num_classes)
with torch.no_grad():
logits_vis = model(x_vis)
pred = torch.argmax(logits_vis, dim=1) # shape: [1, H/4, W/4]
img_np = x_vis[0].permute(1, 2, 0).numpy()
gt_np = y_vis[0].numpy()
pred_np = pred[0].numpy()
fig, axs = plt.subplots(1, 3, figsize=(12, 4))
axs[0].imshow((img_np - img_np.min()) / (img_np.max()-img_np.min()))
axs[0].set_title("Input Image")
axs[1].imshow(gt_np, cmap='jet')
axs[1].set_title("Ground Truth")
axs[2].imshow(pred_np, cmap='jet')
axs[2].set_title("Predicted Segmentation")
for ax in axs:
ax.axis('off')
plt.tight_layout()
plt.show()
در حالت ارزیابی، ما یک نمونه مصنوعی تولید میکنیم، پیشبینی تقسیمبندی مدل را با استفاده از torch.no_grad() محاسبه میکنیم و سپس تانسورها را به آرایههای numpy تبدیل میکنیم. در نهایت، تصویر ورودی، ground truth و نقشههای تقسیمبندی پیشبینی شده را در کنار هم با استفاده از matplotlib تجسم میکند.
در پایان، ما نگاهی عمیق به پیادهسازی توجه پنهان چند-سر در کنار تقسیمبندی تخصصی دقیق ارائه دادیم و نشان دادیم که چگونه این اجزا میتوانند با هم کار کنند تا عملکرد تقسیمبندی را بهبود بخشند. با شروع از ساخت یک رمزگذار CNN اساسی، ما از طریق ادغام مکانیسمهای توجه پنهان حرکت کردیم و نقش آنها را در پالایش نمایشهای ویژگی برای طبقهبندی سطح پیکسل نشان دادیم. ما شما را تشویق میکنیم که بر این پایه بنا کنید، مدل را بر روی مجموعهدادههای دنیای واقعی آزمایش کنید و پتانسیل رویکردهای مبتنی بر توجه را در یادگیری عمیق برای وظایف تقسیمبندی بیشتر بررسی کنید.
اینجا دفترچه کولب قرار دارد. همچنین، فراموش نکنید که ما را در توییتر دنبال کنید و به کانال تلگرام و گروه لینکدین ما بپیوندید. فراموش نکنید که به سابردیت ML با بیش از ۸۵ هزار عضو ما بپیوندید.