سلسلة الذكاء الاصطناعي والاستشعار عن بعد – الجزء الثاني

الخميس 03 ذو القعدة 1446ھ الخميس 1 مايو 2025م
فيسبوك
إكس
واتساب
تيليجرام
لينكدإن

2٬080 كلمة

27 دقيقة

المحتوى

الذكاء الاصطناعي والاستشعار عن بعد

شهد مجال الاستشعار عن بُعد تطورًا ملحوظًا بفضل دمج تقنيات الذكاء الاصطناعي الحديثة، لا سيما خوارزميات التعلم العميق مثل الشبكات العصبية الالتفافية (CNN) والشبكات التكرارية (RNN)، التي أثبتت فعاليتها في تحليل الصور الفضائية واستخلاص المعلومات منها بدقة عالية.

تُستخدم هذه التقنيات في تطبيقات متعددة مثل تصنيف استخدامات الأراضي، واكتشاف التغيرات البيئية، ورصد الكوارث الطبيعية كحرائق الغابات والفيضانات. ومن الأمثلة البارزة على الاستخدامات الحديثة، تقنيات تحسين دقة الصور (Super-Resolution) المعتمدة على الذكاء الاصطناعي، والتي تُستخدم لرفع جودة الصور منخفضة الدقة الملتقطة من الأقمار الصناعية، مما يُمكّن من الحصول على تفاصيل أدق دون الحاجة إلى أجهزة تصوير أعلى تكلفة.

كما بدأت نماذج مثل Vision Transformers (ViTs) وGenerative Adversarial Networks (GANs) تُستخدم لتحسين نتائج التصنيف، وتوليد بيانات اصطناعية للتدريب، وتسهيل عملية التفسير الآلي للصور. هذه الأساليب تُسهم في تعزيز دقة المراقبة البيئية، ودعم اتخاذ القرار في مجالات مثل الزراعة الذكية، وإدارة الموارد الطبيعية، والتخطيط الحضري.

AI and Remote Sensing Series Part2 A scaled

بيانات الاستشعار عن بعد

تعتمد تقنيات الذكاء الاصطناعي في مجال الاستشعار عن بُعد بشكل كبير على توفر مجموعات بيانات عالية الجودة ومتنوعة. من أبرز هذه المجموعات UC-Merced، التي تُعد مرجعًا شهيرًا لتصنيف الصور الجوية بدقة مكانية تبلغ 0.3 متر، وتغطي 21 فئة مختلفة.

هناك أيضًا مجموعة OPTIMAL-31، التي تحتوي على صور عالية الجودة لتقييم النماذج في سياقات معقدة. من المجموعات الأخرى المهمة: EuroSAT، والتي تستند إلى صور القمر الصناعي Sentinel-2 وتغطي 10 فئات استخدام أراضٍ أوروبية، وBigEarthNet، وهي من أكبر مجموعات البيانات متعددة الأطياف وتعتمد أيضًا على Sentinel-2، وتُستخدم في تصنيف الصور والتعلم متعدد التسمية.

كذلك تُعد NWPU-RESISC45 من أكثر المجموعات شيوعًا، حيث تضم 31,500 صورة تغطي 45 فئة مختلفة بدقة 0.2 إلى 0.3 متر.

AI and Remote Sensing Series Part2 B

بالنسبة لمصادر الصور الفضائية، هناك تنوع واسع في أنظمة الاستشعار. يوفر Sentinel-1 بيانات رادارية (SAR) بدقة مكانية تتراوح بين 5 إلى 20 مترًا حسب النطاق والمنتج، ويُستخدم لرصد التغيرات الأرضية والتضاريس في جميع الظروف الجوية والليلية. أما Sentinel-2، فيوفر صورًا متعددة الأطياف بدقة مكانية تصل إلى 10 أمتار في بعض الحزم، ويُستخدم بكثرة في تطبيقات الزراعة، واكتشاف الغطاء النباتي، والتغيرات البيئية.

من الأقمار الصناعية التجارية المتقدمة، هناك WorldView-3، الذي يوفر صورًا بدقة مكانية تصل إلى 30 سنتيمترًا (بانكروماتيكية)، ويشمل نطاقات متعددة الطيف وفائقة الطيف، مما يجعله مناسبًا للتطبيقات الدقيقة مثل مراقبة البنية التحتية وتحليل المناطق الحضرية. كما يوجد أقمار صناعية أخرى مثل Pleiades (بدقة تصل إلى 50 سم)، وPlanetScope التابع لشركة Planet Labs، والذي يوفر صورًا يومية بدقة 3-5 أمتار، مما يجعله مناسبًا للمراقبة المستمرة وتطبيقات الزراعة الدقيقة.

AI and Remote Sensing Series Part2 C

توفر هذه المجموعات والأنظمة البيئية المتكاملة بيئة مثالية لتطوير وتدريب نماذج الذكاء الاصطناعي على مجموعة واسعة من المهام، من تصنيف الغطاء الأرضي إلى اكتشاف التغيرات والتنبؤ بالكوارث.

تقنيات حديثة

في السنوات الأخيرة، شهد مجال الاستشعار عن بُعد تطورات ملحوظة بفضل دمج تقنيات الذكاء الاصطناعي المتقدمة، مما أدى إلى تحسين دقة وكفاءة تحليل الصور الفضائية. أحد هذه التطورات يتمثل في استخدام نماذج المحولات (Transformers) لمعالجة المهام المعقدة مثل تصنيف المشاهد الطبيعية، حيث تم تطوير نموذج يجمع بين المحولات وتقنيات التعلم العميق لتحقيق دقة تصنيف عالية عبر مجموعات بيانات متعددة.

AI and Remote Sensing Series Part2 D scaled
AI and Remote Sensing Series Part2 E

في مجال تحسين دقة الصور (Super-Resolution)، تم تقديم نموذج EDiffSR الذي يعتمد على نموذج الانتشار الاحتمالي (Diffusion Probabilistic Model) لتحسين جودة الصور الفضائية منخفضة الدقة. يتميز هذا النموذج بقدرته على إنتاج صور ذات جودة بصرية عالية مع تقليل التعقيد الحسابي.

AI and Remote Sensing Series Part2 F

علاوة على ذلك، تم تطوير نموذج MA-GAN (شبكة توليدية تنافسية متعددة الانتباه) لتحسين دقة الصور في الاستشعار عن بُعد. يستخدم هذا النموذج كتلتي بناء رئيسيتين: كتلة التلافيف الهرمية في الكتلة الكثيفة المتبقية (PCRDB)، وكتلة الترقية المعتمدة على الانتباه (AUP). تعمل هاتان الكتلتان معًا لتحسين جودة الصور المنتجة، وقد أظهر النموذج تفوقًا على عدة طرق حديثة في مجموعة بيانات مشاهد الاستشعار عن بُعد.

AI and Remote Sensing Series Part2 G

هذه الابتكارات تسلط الضوء على الاتجاه المتزايد نحو استخدام تقنيات الذكاء الاصطناعي المتقدمة، مثل المحولات والشبكات التوليدية التنافسية، لتعزيز قدرات الاستشعار عن بُعد، مما يفتح آفاقًا جديدة لتحليل أكثر دقة وفعالية للبيانات الفضائية.

التطبيق العملي الأول

سنتعرف على كيفية بناء نموذج ذكاء اصطناعي بسيط يقوم بعمل تقسيم الصور باستخدام صور ملتقطة من طائرة درون لمناطق تعرضت للفيضانات.

سنستخدم مكتبة المبنية على PyTorch لتنفيذ هذا المشروع.

البيانات المستخدمة

البيانات المستخدمة مأخوذة من مجموعة بيانات ، والتي تحتوي على صور وفيه التوصيف (Masks) لها. يمكنك تحميل البيانات المستخدمة في هذا الدرس من خلال الزر أدناه

ويمكنك تجربة الكود البرمجي على منصة Google Colab بشكل مجاني، مرفق بنهاية الدرس ملف معد مسبقاً فيه جميع الشفرات.

ما هي مهمة التقسيم (Segmentation) في الرؤية الحاسوبية؟

في عالم الرؤية الحاسوبية، واحدة من أهم المهام هي تقسيم الصور ، إذ تهدف هذه المهمة إلى تحديد كل بكسل في الصورة إلى أي فئة ينتمي. بخلاف تصنيف الصور (Image Classification) الذي يعطي فئة واحدة للصورة ككل، أو حتى الكشف عن الأجسام (Object Detection) الذي يرسم مربعات حول الأجسام، فإن التقسيم يُعطي مستوى تفصيليًا لكل كائن في الصورة.

كيف يعمل التقسيم عمليًا؟

عند إدخال صورة إلى نموذج تقسيم، يقوم النموذج بإنتاج صورة جديدة (تُسمى: mask أو التوصيف). هذه الصورة الجديدة تحتوي على أرقام تمثل فئات مختلفة (مثلاً: ماء = 5، مبنى = 1، شجرة = 6...). بهذا الشكل، يصبح لدينا لكل بكسل في الصورة الأصلية توصيف دقيق لهويته.

علاقة التقسيم بالاستشعار عن بُعد

في سياق الاستشعار عن بُعد ، تكون الصور عادة مأخوذة من الأقمار الصناعية أو الطائرات بدون طيار (درون). وتكمن القوة في استخدام التقسيم هنا في القدرة على تحليل الأوضاع على الأرض بشكل دقيق:

هل هذا المبنى غمره الماء؟

هل الطريق سالك أم مغمور؟

هل هذه المنطقة مغطاة بالعشب أم بالماء؟

وهكذا.

ماذا سنفعل في هذا الدرس؟

في هذا الدليل التطبيقي، نستخدم نموذج ذكاء اصطناعي مبني على معمارية لتطبيق مهمة تقسيم متعددة الفئات على مجموعة بيانات حقيقية تُسمى . هذه البيانات تم جمعها من طائرة درون فوق مناطق تعرضت للفيضانات، وتشمل فئات متعددة مثل:

مباني مغمورة وغير مغمورة

طرق مغمورة وغير مغمورة

ماء، شجر، عشب، برك، مركبات، وغيرها ...

سنقوم بــــــــــ

تجهيز البيانات وتوصيفها.

تدريب نموذج ذكاء اصطناعي لفهم هذه الفئات.

تقييم النموذج وعرض نتائجه بصريًا.

لماذا هذا مهم؟

مهمة مثل هذه يمكن أن تُستخدم في حالات الطوارئ لإرسال فرق إنقاذ إلى الأماكن المتضررة، أو تقييم الأضرار بعد الكوارث الطبيعية، أو حتى التخطيط العمراني الذكي.

المتطلبات الأساسية

قبل أن نبدأ، تأكد من تثبيت المكتبة التالية:

				
					# Prerequisites / requirements:
!pip install segmentation-models-pytorch

				
			

استيراد المكتبات اللازمة:

				
					#import needed libraries:
import torch
import torchvision
from PIL import Image
import torchvision.transforms as transforms
from torch.utils.data import Dataset, DataLoader
import numpy as np
import matplotlib.pyplot as plt
import segmentation_models_pytorch as smp
import os
from matplotlib.colors import ListedColormap

				
			

التأكد من الجهاز المستخدم (GPU أو CPU):

				
					#Check mounted device type:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

				
			

إذا كنت تستخدم Google Colab ولديك GPU مفعّل، يمكنك فحصه باستخدام الأمر التالي:

				
					#Check GPU details if found:
!nvidia-smi

				
			

تحميل بيانات FloodNet

أولاً، نحتاج إلى وظيفة تساعدنا في جمع كافة الملفات داخل مجلد معين:

				
					#Function to extract list of dataset files from location in storage mounted in Colab/GDrive:
def list_files_in_directory(directory):
    file_paths = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            file_paths.append(os.path.join(root, file))
    return file_paths
				
			

تحديد مسارات البيانات للتدريب والاختبار:

				
					#Define paths to dataset location (train & test):
train_image_path = "/content/drive/MyDrive/datasets/FloodNet-Supervised_v1.0/train/train-org-img"
train_label_path = "/content/drive/MyDrive/datasets/FloodNet-Supervised_v1.0/train/train-label-img"
test_image_path = "/content/drive/MyDrive/datasets/FloodNet-Supervised_v1.0/test/test-org-img"
test_label_path = "/content/drive/MyDrive/datasets/FloodNet-Supervised_v1.0/test/test-label-img"

#extract list of images and masks from defined paths:
train_image_list = list_files_in_directory(train_image_path)
train_label_list = list_files_in_directory(train_label_path)
test_image_list = list_files_in_directory(test_image_path)
test_label_list = list_files_in_directory(test_label_path)

				
			

تعريف كلاس Dataset مخصص

الآن سنقوم بإنشاء كائن Dataset مخصص لـــ FloodNet:

				
					# Custom defined PyTorch ImageFolder dataset
class FloodNetDataset(Dataset):
    """FloodNet dataset."""

    def __init__(self, objects_list, labels_list, transform=None):
        """
        Args:
            objects_list (list): list of image paths to be used with the dataloader.
            labels_list (list): list of segmentation image labels paths to be used with the dataloader.
            transform (callable, optional): Optional transform to be applied
                on a sample.
        """
        self.objects_list = objects_list
        self.labels_list = labels_list
        self.transform = transform

    def __len__(self):
        return len(self.objects_list)

    def __getitem__(self, idx):
        image = Image.open(self.objects_list[idx])
        label = Image.open(self.labels_list[idx])

        if self.transform:
            image = self.transform(image)
            label = self.transform(label)

        return image, label

				
			

تجهيز البيانات وتحميلها في PyTorch

التحويلات (Transforms)

نحتاج إلى تحويل الصور لتكون مناسبة للتدريب. سنقوم بتحويل الصور من PIL إلى Tensor، ثم نعيد تحجيمها إلى أبعاد موحدة (64×64).

				
					# Transform:
transform = transforms.Compose([
    transforms.PILToTensor(),
    transforms.Resize((64, 64))
])

				
			

تعريف مجموعات البيانات

الآن نستخدم الكلاس FloodNetDataset الذي أنشأناه سابقًا لقراءة الصور وملفات التوصيف من المسارات:

				
					# Define datasets:
train_dataset = FloodNetDataset(objects_list=train_image_list, labels_list=train_label_list, transform=transform)
test_dataset = FloodNetDataset(objects_list=test_image_list, labels_list=test_label_list, transform=transform)

				
			

تحميل البيانات باستخدام DataLoader

DataLoader يسهل علينا التعامل مع البيانات أثناء التدريب، مثل تقسيمها إلى دفعات (Batches):

				
					# Define Dataloader:
batch_size = 16

floodnet_dataloader_train = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
floodnet_dataloader_test = DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=0)

				
			

إعداد الألوان والتسميات للفئات (للعرض)

لكي نستطيع عرض التوصيفات (Masks) بشكل مرئي ومفهوم، نحتاج إلى تعيين لون لكل فئة (class) من الفئات الموجودة في FloodNet. يتم ذلك باستخدام قائمة ألوان hex وقائمة بأسماء الفئات.

				
					# QoL Setup:
# Specify colors for each class using hex codes
class_colors = [
    "#000000",  # Background
    "#ff001e",  # Building-Flooded
    "#ff8f9c",  # Building-Non-Flooded
    "#56a100",  # Road-Flooded
    "#b3b3b3",  # Road-non-Flooded
    "#3bfcff",  # Water
    "#0004ff",  # Tree
    "#ff00ff",  # Vehicle
    "#f2ff00",  # Pool
    "#00ff1e"   # Grass
]

class_names = [
    "Background", "Building-Flooded", "Building-Non-Flooded", "Road-Flooded",
    "Road-non-Flooded", "Water", "Tree", "Vechile",
    "Pool", "Grass"
]

colormap = ListedColormap(class_colors)

				
			

عرض عينة من البيانات

قبل ما نبدأ التدريب، خلينا نعرض صورة وحدة مع توصيفها لنتأكد من تنسيق البيانات:

				
					#Show sample of dataset:
sample = next(iter(floodnet_dataloader_train))

plt.figure(figsize=(20, 5))
plt.subplot(1,2,1)
plt.imshow(sample[0][0].permute(1, 2, 0)) # for visualization we have to transpose back to HWC
plt.subplot(1,2,2)
plt.imshow(sample[1][0].permute(1, 2, 0), cmap=colormap)  # for visualization we have to remove 3rd dimension of mask

cbar = plt.colorbar(ticks=range(10), format='%1i', cmap=colormap)
cbar.ax.set_yticklabels(class_names)

plt.show()

				
			

تدريب نموذج UNet لتقسيم الصور

تعريف دالة الدقة (Accuracy)

نستخدم دالة بسيطة لحساب دقة النموذج من خلال مقارنة التوقعات بالملصقات الحقيقية (Masks):

				
					#Define Accuracy metric:
def acc(label, predicted):
    seg_acc = (label.cpu() == torch.argmax(predicted, axis=1).cpu()).sum() / torch.numel(label.cpu())
    return seg_acc

				
			

إعداد نموذج UNet من مكتبة segmentation_models_pytorch

				
					N_EPOCHS = 3

model = smp.Unet(
    encoder_name="resnet34",        # choose encoder, e.g. mobilenet_v2 or efficientnet-b7
    encoder_weights="imagenet",     # use `imagenet` pre-trained weights for encoder initialization
    in_channels=3,                  # model input channels (1 for gray-scale images, 3 for RGB, etc.)
    classes=10,                     # model output channels (number of classes in your dataset)
)

if str(device) == 'cuda':
        print("model is cuda")
        model = model.cuda()

				
			

تهيئة دالة الخسارة، المحسن، وجدولة معدل التعلم

				
					optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = smp.losses.DiceLoss('multiclass', from_logits=True)

lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.5)
min_loss = torch.tensor(float('inf'))

os.makedirs('./saved_models', exist_ok=True)

				
			

تدريب وتقييم النموذج

نبدأ الآن بحلقة التدريب على عدة عصور (Epochs):

				
					import copy

plot_losses = []
scheduler_counter = 0
best_model = None

for epoch in range(N_EPOCHS):
  # training
  model.train()
  loss_list = []
  acc_list = []
  for batch_i, (x, y) in enumerate(floodnet_dataloader_train):
      pred_mask = model(x.to(device).float())
      loss = criterion(pred_mask, y.to(device).type(torch.int64))

      optimizer.zero_grad()
      loss.backward()
      optimizer.step()
      loss_list.append(loss.cpu().detach().numpy())
      acc_list.append(acc(y,pred_mask).numpy())

      print(
          "\r[Epoch %d/%d] [Batch %d/%d] [Loss: %f (%f)]"
          % (
              epoch,
              N_EPOCHS,
              batch_i,
              len(floodnet_dataloader_train),
              loss.cpu().detach().numpy(),
              np.mean(loss_list),
          )
      )
  scheduler_counter += 1

  # testing
  model.eval()
  val_loss_list = []
  val_acc_list = []
  for batch_i, (x, y) in enumerate(floodnet_dataloader_test):
      with torch.no_grad():
          pred_mask = model(x.to(device).float())
      val_loss = criterion(pred_mask, y.to(device).type(torch.int64))
      val_loss_list.append(val_loss.cpu().detach().numpy())
      val_acc_list.append(acc(y,pred_mask).numpy())

  print(' epoch {} - loss : {:.5f} - acc : {:.2f} - val loss : {:.5f} - val acc : {:.2f}'.format(epoch,
                                                                                                  np.mean(loss_list),
                                                                                                  np.mean(acc_list),
                                                                                                  np.mean(val_loss_list),
                                                                                                  np.mean(val_acc_list)))
  plot_losses.append([epoch, np.mean(loss_list), np.mean(val_loss_list)])

  compare_loss = np.mean(val_loss_list)
  is_best = compare_loss < min_loss
  if is_best == True:
    scheduler_counter = 0
    min_loss = min(compare_loss, min_loss)
    torch.save(model.state_dict(), './saved_models/unet_epoch_{}_{:.5f}.pt'.format(epoch,np.mean(val_loss_list)))
    best_model = copy.deepcopy(model)

  if scheduler_counter > 5:
      lr_scheduler.step()
      print(f"lowering learning rate to {optimizer.param_groups[0]['lr']}")
      scheduler_counter = 0

				
			

رسم منحنى الخسارة:

				
					# plot loss
plot_losses = np.array(plot_losses)
plt.figure(figsize=(12,8))
plt.plot(plot_losses[:,0], plot_losses[:,1], color='b', linewidth=4)
plt.plot(plot_losses[:,0], plot_losses[:,2], color='r', linewidth=4)
plt.title("Crossentropy", fontsize=20)
plt.xlabel('epoch',fontsize=20)
plt.ylabel('loss',fontsize=20)
plt.grid()
plt.legend(['training', 'validation']) # using a named size
plt.savefig('loss_plots.png')

				
			

عرض عينات من نتائج النموذج

عرض صور من بيانات الاختبار مع نتائج النموذج:

				
					# lets look at some samples
floodnet_dataloader_sample = DataLoader(test_dataset, batch_size=1, shuffle=True, num_workers=0)
num_samples = 5

# Specify colors for each class using hex codes
class_colors = [
    "#000000", "#ff001e", "#ff8f9c", "#56a100",
    "#b3b3b3", "#3bfcff", "#0004ff", "#ff00ff",
    "#f2ff00", "#00ff1e"
]

class_names = [
    'Background', 'Building-Flooded', 'Building-Non-Flooded', 'Road-Flooded',
    'Road-non-Flooded', 'Water', 'Tree', 'Vechile',
    'Pool', 'Grass'
]

# Create a colormap with the given colors
colormap = ListedColormap(class_colors)
for i in range(num_samples):
    plt.figure(figsize=(20, 5))
    sample = next(iter(floodnet_dataloader_sample))
    model.eval()
    output = model(sample[0].float().to(device)).detach().type(torch.int64)
    plt.subplot(1,3,1)
    plt.title("Input Image")
    plt.imshow(sample[0][0].permute(1, 2, 0)) # for visualization we have to transpose back to HWC
    plt.subplot(1,3,2)
    plt.title("Mask Ground Truth")
    plt.imshow(sample[1].squeeze(), cmap=colormap)  # for visualization we have to remove 3rd dimension of mask
    plt.subplot(1,3,3)
    plt.title("Model's mask")
    plt.imshow(output.argmax(dim=1).squeeze().cpu(), cmap=colormap)  # for visualization we have to remove 3rd dimension of mask
    cbar = plt.colorbar(ticks=range(10), format='%1i', cmap=colormap)
    cbar.ax.set_yticklabels(class_names)

    plt.show()

				
			
JupyterLogo
تجدون في الرابط التالي ملف Jupyter Notebook مكتمل، جاهز للتطبيق مباشرة على منصات مثل Google Colab

🎉 ختامًا

في هذا الدرس، تعلمنا:

  • كيفية التعامل مع بيانات الاستشعار عن بعد المصنفة مثل FloodNet.
  • تجهيز بيانات الصور والتوصيفات وتحميلها في PyTorch.
  • استخدام نموذج UNet من مكتبة segmentation_models_pytorch.
  • تدريب النموذج، حساب الخسارة والدقة، وحفظ أفضل نسخة منه.
  • عرض نتائج النموذج بصريًا على صور حقيقية من بيانات الاختبار.
نشرة فهم البريدية
لتبقى على اطلاع دائم على كل ما هو جديد مما تقدمه منصة فهم، انضم لنشرتنا البريدية.
خريج دراسات عليا في هندسة الحاسب، اختصاص الذكاء الاصطناعي والاستشعار عن بعد من كلية الحاسب بجامعة الملك سعود، شغوف بتطبيقات الذكاء الاصطناعي بجميع أطيافه من تعلم الآلة، والتعلم العميق، ورؤية الحاسب. أقدّر رواد الأعمال أصحاب الفكر الهندسي مثل إيلون ماسك.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *