Liss Codebase
Liss Codebase
├── assets/
├── data/
│ ├── processed/
│ │ ├── patches_clear/
│ │ ├── patches_cloudy/
│ │ └── sentinel/
│ │ └── train/
│ │ ├── input/
│ │ └── target/
│ └── raw/
│ ├── cloud_free/
│ ├── cloudy/
│ └── sentinel/
├── docs/
├── final_outputs/
├── inference_results/
├── inference_sentinel_results/
├── inferencepics/
├── liss4_env/
│ ├── Include/
│ ├── Lib/
│ ├── Scripts/
│ ├── share/
│ └── [Link]
├── models/
├── sentinel_gan_samples/
├── sentinel_samples/
├── src/
│ ├── __pycache__/
│ ├── __init__.py
│ ├── [Link]
│ └── [Link]
├── create_patches.py
├── download_sentinel.py
├── evaluate_metrics.py
├── final_cloud_free_map.png
├── folder_stack.py
├── folder_stack_clear.py
├── generate_full_map.py
├── [Link]
├── inference_result1.[Link]
├── inference_sentinel.py
├── inspect_data.py
├── live_demo.py
├── live_generation_result.png
├── [Link]
├── prepare_sentinel_data.py
├── [Link]
├── reconstructed_full_map.[Link]
├── reconstructed_full_map11.tif
├── stack_bands.py
├── stack_bands_ncl.py
├── stitch_results.py
├── [Link]
├── train_sentinel.py
└── train_sentinel_gan.py
[Link] ->
import os
import torch
from [Link] import Dataset
import numpy as np
from PIL import Image
from torchvision import transforms
# ==========================================
# TOOL 1: The Original LISS-4 Dataset Loader
# ==========================================
class SatellitePatchDataset(Dataset):
def __init__(self, cloudy_dir, clear_dir):
self.cloudy_dir = cloudy_dir
self.clear_dir = clear_dir
self.image_filenames = [Link](cloudy_dir)
[Link] = [Link]([
[Link](),
[Link]((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
def __len__(self):
return len(self.image_filenames)
cloudy_img = [Link](cloudy_path).convert("RGB")
clear_img = [Link](clear_path).convert("RGB")
cloudy_tensor = [Link](cloudy_img)
clear_tensor = [Link](clear_img)
# ==========================================
# TOOL 2: The New Sentinel-1 & 2 Dataset Loader
# ==========================================
class SentinelDataset(Dataset):
def __init__(self, data_dir, transform=None):
self.input_dir = [Link](data_dir, "input")
self.target_dir = [Link](data_dir, "target")
self.patch_files = sorted([f for f in [Link](self.input_dir)
if [Link](".npy")])
[Link] = transform
def __len__(self):
return len(self.patch_files)
input_tensor = torch.from_numpy(input_np).float()
target_tensor = torch.from_numpy(target_np).float()
for c in range(target_tensor.shape[0]):
min_val = target_tensor[c].min()
max_val = target_tensor[c].max()
if max_val > min_val:
target_tensor[c] = (target_tensor[c] - min_val) / (max_val
- min_val)
# ==========================================
# 1. GENERATOR COMPONENTS (V2 ARCHITECTURE)
# ==========================================
class UNetDown([Link]):
def __init__(self, in_size, out_size, normalize=True, dropout=0.0):
super(UNetDown, self).__init__()
layers = [nn.Conv2d(in_size, out_size, kernel_size=4, stride=2,
padding=1, bias=False)]
if normalize:
[Link](nn.BatchNorm2d(out_size))
[Link]([Link](0.2))
if dropout:
[Link]([Link](dropout))
[Link] = [Link](*layers)
class UNetUp([Link]):
def __init__(self, in_size, out_size, dropout=0.0):
super(UNetUp, self).__init__()
class GeneratorUNet([Link]):
def __init__(self, in_channels=5, out_channels=3):
super(GeneratorUNet, self).__init__()
# Encoder (Downsampling)
self.down1 = UNetDown(in_channels, 64, normalize=False)
self.down2 = UNetDown(64, 128)
self.down3 = UNetDown(128, 256)
self.down4 = UNetDown(256, 512, dropout=0.5)
self.down5 = UNetDown(512, 512, dropout=0.5)
self.down6 = UNetDown(512, 512, dropout=0.5)
self.down7 = UNetDown(512, 512, dropout=0.5)
self.down8 = UNetDown(512, 512, normalize=False, dropout=0.5)
u1 = self.up1(d8, d7)
u2 = self.up2(u1, d6)
u3 = self.up3(u2, d5)
u4 = self.up4(u3, d4)
u5 = self.up5(u4, d3)
u6 = self.up6(u5, d2)
u7 = self.up7(u6, d1)
return [Link](u7)
# ==========================================
# 2. DISCRIMINATOR COMPONENT
# ==========================================
class Discriminator([Link]):
def __init__(self, in_channels=5, target_channels=3):
super(Discriminator, self).__init__()
if len(stacked_files) == 0:
print(f"No stacked .tif files found in {stacked_dir}")
return
total_patches += 1
print(f"Finished slicing: {file_name}")
if __name__ == "__main__":
# --- Cloudy Data ---
# Points to the output folder made by folder_stack.py
cloudy_stacked = r"data\raw\cloudy\stacked_output"
cloudy_patches = r"data\processed\patches_cloudy"
def download_sentinel_triplet():
print("Initializing Microsoft Planetary Computer API...")
# ==========================================
# STEP A: GET THE "ANSWER KEY" (Clear Season)
# ==========================================
print("--- Searching for Clear Target Image (Jan - May) ---")
clear_search = [Link](
collections=["sentinel-2-l2a"],
bbox=bbox,
datetime="2023-01-01/2023-05-30",
query={"eo:cloud_cover": {"lt": 5}} # Less than 5% clouds
)
clear_items = list(clear_search.items())
best_clear = clear_items[0]
print(f"[+] Found Clear S2 Image from: {best_clear.datetime}")
# ==========================================
# STEP B: GET THE "PROBLEM" (Monsoon Season)
# ==========================================
print("\n--- Searching for Cloudy Input Image (Jun - Aug) ---")
cloudy_search = [Link](
collections=["sentinel-2-l2a"],
bbox=bbox,
datetime="2023-06-01/2023-08-30",
query={"eo:cloud_cover": {"gt": 40, "lt": 80}} # 40% to 80% cloudy
)
cloudy_items = list(cloudy_search.items())
best_cloudy = cloudy_items[0]
cloudy_date_str = best_cloudy.[Link]("%Y-%m-%d")
print(f"[+] Found Cloudy S2 Image from: {best_cloudy.datetime}")
# ==========================================
# STEP C: GET THE "X-RAY" (Radar on the exact Cloudy Day)
# ==========================================
print(f"\n--- Searching for Radar Image near {cloudy_date_str} ---")
cloudy_date = best_cloudy.datetime
start_date = (cloudy_date -
[Link](days=2)).strftime("%Y-%m-%d")
end_date = (cloudy_date +
[Link](days=2)).strftime("%Y-%m-%d")
radar_time_window = f"{start_date}/{end_date}"
radar_search = [Link](
collections=["sentinel-1-rtc"],
bbox=bbox,
datetime=radar_time_window
)
radar_items = list(radar_search.items())
best_radar = radar_items[0]
print(f"[+] Found matching S1 Radar Image from:
{best_radar.datetime}\n")
# ==========================================
# STEP D: DOWNLOAD PIXELS TO HARD DRIVE
# ==========================================
print("--- Starting Direct Cloud-to-Disk Download ---")
if __name__ == "__main__":
download_sentinel_triplet()
Evaluate_metrics.py ->
import os
import torch
import numpy as np
from [Link] import peak_signal_noise_ratio as compute_psnr
from [Link] import structural_similarity as compute_ssim
from [Link] import GeneratorUNet
def evaluate():
print("[*] Starting V2 Model Evaluation...")
device = [Link]("cuda" if [Link].is_available() else "cpu")
if not [Link](checkpoint_path):
print(f"[!] Error: No trained model found at {checkpoint_path}!")
return
total_psnr = 0.0
total_ssim = 0.0
# 2. Evaluation Loop
with torch.no_grad():
for idx, file_name in enumerate(files):
in_arr = [Link]([Link](input_dir,
file_name)).astype(np.float32)
tar_arr = [Link]([Link](target_dir,
file_name)).astype(np.float32)
in_tensor = in_tensor.unsqueeze(0).to(device)
in_tensor = torch.nan_to_num(in_tensor, nan=0.0)
# Generate AI Prediction
ai_prediction = generator(in_tensor, dataset_type="sentinel")
ai_img = (ai_prediction.cpu().squeeze().numpy() + 1) / 2.0
ai_img = [Link]([Link](ai_img, (1, 2, 0)), 0, 1)
# 3. Calculate Math Metrics
patch_psnr = compute_psnr(tar_arr, ai_img, data_range=1.0)
patch_ssim = compute_ssim(tar_arr, ai_img, data_range=1.0,
channel_axis=2)
total_psnr += patch_psnr
total_ssim += patch_ssim
# 4. Averages
avg_psnr = total_psnr / len(files)
avg_ssim = total_ssim / len(files)
print("\n========================================")
print(" 🏆 FINAL V2 MODEL METRICS 🏆")
print("========================================")
print(f"Average PSNR: {avg_psnr:.2f} dB")
print(f"Average SSIM: {avg_ssim:.4f}")
print("========================================")
if __name__ == "__main__":
evaluate()
folder_stack_ [Link] ->
import os
import rasterio
# Make sure it's a directory and skip the output folder itself
if [Link](folder_path) and folder_name != "stacked_output":
output_path = [Link](output_stacked_dir,
f"stacked_{folder_name}.tif")
success_count += 1
else:
print(f"[Skipped] Clear folder '{folder_name}' is missing
band files.")
print(f"\nOperation Complete! Successfully stacked {success_count}
clear scenes.")
if __name__ == "__main__":
# Target paths set specifically for cloud_free data
clear_folders = r"data\raw\cloud_free"
output_directory = r"data\raw\cloud_free\stacked_output"
stack_clear_folders(clear_folders, output_directory)
Folder_stack.py ->
import os
import rasterio
# Make sure it's actually a folder, and skip our output folder
if [Link](folder_path) and folder_name != "stacked_output":
output_path = [Link](output_stacked_dir,
f"stacked_{folder_name}.tif")
success_count += 1
else:
print(f"[Skipped] Folder '{folder_name}' is missing one or
more band files.")
if __name__ == "__main__":
# Point this to the directory containing all your extracted scene
folders
cloudy_folders = r"data\raw\cloudy"
output_directory = r"data\raw\cloudy\stacked_output"
stack_from_folders(cloudy_folders, output_directory)
Generate_full_map.py ->
import os
import torch
import numpy as np
from PIL import Image
from [Link] import GeneratorUNet
import math
import re
def generate_full_map(city_name="cherrapunji"):
print(f"[*] Initializing Full Map Reconstruction for
{city_name.upper()}...")
device = [Link]("cuda" if [Link].is_available() else "cpu")
if not [Link](checkpoint_path):
print(f"[!] Error: No trained model found at {checkpoint_path}!")
return
in_tensor = torch.from_numpy(in_arr_norm).permute(2, 0,
1).unsqueeze(0).to(device)
in_tensor = torch.nan_to_num(in_tensor, nan=0.0)
# AI Prediction
with torch.no_grad():
ai_prediction = generator(in_tensor, dataset_type="sentinel")
full_clear_map.save(clear_path)
full_cloudy_map.save(cloudy_path)
if __name__ == "__main__":
cities = ["cherrapunji", "mumbai", "bengaluru"]
Inference_sentinel.py ->
import os
import torch
import numpy as np
import [Link] as plt
from [Link] import GeneratorUNet
import random
def run_inference():
print("[*] Initializing Hackathon Inference Engine...")
device = [Link]("cuda" if [Link].is_available() else "cpu")
if not [Link](checkpoint_path):
print(f"[!] Error: No trained model found at {checkpoint_path}!")
return
in_tensor = torch.from_numpy(in_arr).permute(2, 0,
1).unsqueeze(0).to(device)
in_tensor = torch.nan_to_num(in_tensor, nan=0.0)
[Link](figsize=(15, 5))
[Link](1, 3, 1)
[Link]("1. Input (Cloudy Optical + SAR)")
[Link](cloudy_rgb)
[Link]('off')
[Link](1, 3, 2)
[Link]("2. Ground Truth (Clear Optical)")
[Link](tar_img)
[Link]('off')
[Link](1, 3, 3)
[Link]("3. AI Generation (V1 Output)")
[Link](ai_img)
[Link]('off')
output_path = f"inference_sentinel_results/{test_file.replace('.npy',
'.png')}"
plt.tight_layout()
[Link](output_path, dpi=300, bbox_inches='tight')
print(f"\n[+] SUCCESS! Check the folder for: {output_path}")
if __name__ == "__main__":
run_inference()
[Link]->
import os
import torch
import rasterio
import numpy as np
from [Link] import save_image
def test_ai_model():
device = [Link]("cuda" if [Link].is_available() else "cpu")
print(f"Preparing AI on: {device}")
# Initialize model
generator = GeneratorUNet().to(device)
# ==========================================
# 1. LOAD THE BRAIN (UNPACKING CHECKPOINT)
# ==========================================
weights_path = [Link]("models", "checkpoint_latest.pth")
if [Link](weights_path):
# Load the master checkpoint dictionary
checkpoint = [Link](weights_path, map_location=device)
[Link]()
# ==========================================
# 2. SETUP DIRECTORIES
# ==========================================
input_dir = [Link]("data", "processed", "patches_cloudy")
output_dir = "inference_results"
[Link](output_dir, exist_ok=True)
# ==========================================
# 3. RUN INFERENCE USING RASTERIO
# ==========================================
with torch.no_grad():
for img_name in test_batch:
img_path = [Link](input_dir, img_name)
try:
with [Link](img_path) as src:
img_array = [Link]()
if img_array.shape[0] >= 3:
img_array = img_array[:3, :, :]
output_path = [Link](output_dir,
f"clear_{img_name.replace('.tif', '.png')}")
save_image(fake_clear, output_path, normalize=True)
print(f"Saved: {output_path}")
except Exception as e:
print(f"[!] Skipping {img_name} due to error: {e}")
if __name__ == "__main__":
test_ai_model()
Inspect_data.py ->
import rasterio
import numpy as np
import os
def inspect_satellite_image(image_path):
"""
Opens a LISS-IV GeoTIFF file, reads its metadata,
and verifies its shape and spectral integrity.
"""
if not [Link](image_path):
raise FileNotFoundError(f"Target image not found at:
{image_path}")
bands_data = []
for i in range(1, band_count + 1):
band = [Link](i)
bands_data.append(band)
if __name__ == "__main__":
# Placeholder path for execution
sample_path = r"data\raw\cloudy\sample_liss4.tif"
try:
matrix, metadata = inspect_satellite_image(sample_path)
except FileNotFoundError as e:
print(f"\n[Setup Status]: Setup complete. Waiting for raw data
input. Error caught successfully: {e}")
Live_demo.py ->
import torch
import numpy as np
from PIL import Image
from [Link] import GeneratorUNet
# 2. Grab a raw cloudy/radar data patch (Change this filename to any patch
you want)
patch_path = "data/processed/sentinel/train/input/mumbai_patch_10.npy"
in_arr = [Link](patch_path).astype(np.float32)
Prepare_sentinel_data.py ->
import os
import numpy as np
import rasterio
from [Link] import Resampling
from [Link] import Window
def process_sentinel_dataset():
raw_dir = [Link]("data", "raw", "sentinel")
processed_dir = [Link]("data", "processed", "sentinel")
[Link]->
import os
import glob
from PIL import Image
def stitch_patches():
# Increase PIL's pixel limit for massive satellite images
Image.MAX_IMAGE_PIXELS = None
input_dir = "inference_results"
output_file = "final_cloud_free_map.png"
patch_size = 256
if not images:
print("[!] No images found in inference_results folder.")
return
max_x = 0
max_y = 0
if __name__ == "__main__":
stitch_patches()
# Open all three files and write them into the new stacked file
with [Link](band_green_path) as src_g, \
[Link](band_red_path) as src_r, \
[Link](band_nir_path) as src_nir:
if __name__ == "__main__":
# --- UPDATE THESE PATHS TO MATCH YOUR DOWNLOADED FILES ---
# For example, if your folder is named 'cloudy_scene' and contains the
3 bands:
try:
stack_satellite_bands(green, red, nir, output_stacked)
except FileNotFoundError as e:
print(f"\n[Error]: Could not find one of the files. Please check
your file paths! Details: {e}")
stack_band->import rasterio
import os
# Open all three files and write them into the new stacked file
with [Link](band_green_path) as src_g, \
[Link](band_red_path) as src_r, \
[Link](band_nir_path) as src_nir:
if __name__ == "__main__":
# --- UPDATE THESE PATHS TO MATCH YOUR DOWNLOADED FILES ---
# For example, if your folder is named 'cloudy_scene' and contains the
3 bands:
try:
stack_satellite_bands(green, red, nir, output_stacked)
except FileNotFoundError as e:
print(f"\n[Error]: Could not find one of the files. Please check
your file paths! Details: {e}")
Stick_result ->
import os
import glob
from PIL import Image
def stitch_patches():
# Remove PIL pixel limit for large satellite imagery scale
Image.MAX_IMAGE_PIXELS = None
input_dir = "inference_results"
output_file = "final_cloud_free_map.png"
patch_size = 256
print("Scanning inference results...")
images = [Link]([Link](input_dir, "clear_*_patch_*.png"))
if not images:
print("[!] No images found in inference_results folder.")
return
max_x = 0
max_y = 0
if __name__ == "__main__":
stitch_patches()
Train_sentinel_gan.py ->
import os
import torch
import [Link] as nn
import [Link] as optim
from [Link] import Dataset, DataLoader
import numpy as np
from [Link] import save_image
import ee
# =====================================================================
# 1. DATA ACQUISITION BLOCK
# =====================================================================
GEE_PROJECT = "norse-quest-474800-i5"
try:
[Link](project=GEE_PROJECT)
except Exception:
[Link]()
[Link](project=GEE_PROJECT)
CITIES = {
"mumbai": [72.75, 18.85, 73.10, 19.25],
"cherrapunji": [91.60, 25.15, 91.90, 25.45],
"bengaluru": [77.45, 12.85, 77.75, 13.15]
}
INPUT_DIR = [Link]("data", "processed", "sentinel", "train",
"input")
TARGET_DIR = [Link]("data", "processed", "sentinel", "train",
"target")
[Link](INPUT_DIR, exist_ok=True)
[Link](TARGET_DIR, exist_ok=True)
PATCH_SIZE = 256
TILE_STEP = 0.04
patch_count = 0
for x_start in lon_steps:
for y_start in lat_steps:
x_end = min(x_start + TILE_STEP, bbox[2])
y_end = min(y_start + TILE_STEP, bbox[3])
tile_roi = [Link]([x_start, y_start, x_end,
y_end])
try:
s1 =
[Link]('COPERNICUS/S1_GRD').filterBounds(tile_roi).filterDate(
'2025-06-01', '2025-09-01').median().select(['VV', 'VH'])
s2_cloudy =
[Link]('COPERNICUS/S2_SR_HARMONIZED').filterBounds(tile_roi).f
ilterDate('2025-06-01',
'2025-09-01').filter([Link]('CLOUDY_PIXEL_PERCENTAGE',
50)).median().select(['B4', 'B3', 'B2'])
s2_clear =
[Link]('COPERNICUS/S2_SR_HARMONIZED').filterBounds(tile_roi).f
ilterDate('2025-11-01',
'2026-02-01').filter([Link]('CLOUDY_PIXEL_PERCENTAGE',
5)).median().select(['B4', 'B3', 'B2'])
input_stack = [Link]([s1,
s2_cloudy]).reproject(crs='EPSG:4326', scale=10)
target_stack = s2_clear.reproject(crs='EPSG:4326',
scale=10)
input_info =
input_stack.sampleRectangle(region=tile_roi, defaultValue=0).getInfo()
target_info =
target_stack.sampleRectangle(region=tile_roi, defaultValue=0).getInfo()
in_matrix =
[Link]([[Link](input_info['properties'][b]) for b in ['VV', 'VH',
'B4', 'B3', 'B2']], axis=-1)
tar_matrix =
[Link]([[Link](target_info['properties'][b]) for b in ['B4', 'B3',
'B2']], axis=-1)
h, w, _ = in_matrix.shape
for y in range(0, h - PATCH_SIZE, PATCH_SIZE):
for x in range(0, w - PATCH_SIZE, PATCH_SIZE):
in_patch = in_matrix[y:y+PATCH_SIZE,
x:x+PATCH_SIZE, :]
tar_patch = tar_matrix[y:y+PATCH_SIZE,
x:x+PATCH_SIZE, :]
if in_patch.shape == (PATCH_SIZE, PATCH_SIZE,
5) and tar_patch.shape == (PATCH_SIZE, PATCH_SIZE, 3):
patch_id =
f"{city_name}_patch_{patch_count}.npy"
[Link]([Link](INPUT_DIR, patch_id),
in_patch)
[Link]([Link](TARGET_DIR,
patch_id), tar_patch)
patch_count += 1
except Exception:
continue
else:
print(f"\n[+] Dataset found. Skipping GEE.")
# =====================================================================
# 2. DATASET DEFINITION
# =====================================================================
class SentinelDataset(Dataset):
def __init__(self, input_dir, target_dir):
self.input_dir = input_dir
self.target_dir = target_dir
self.file_names = [f for f in [Link](input_dir) if
[Link]('.npy')]
in_tensor = torch.from_numpy(in_arr)
tar_tensor = torch.from_numpy(tar_arr)
if in_tensor.shape[-1] == 5:
in_tensor = in_tensor.permute(2, 0, 1)
if tar_tensor.shape[-1] == 3:
tar_tensor = tar_tensor.permute(2, 0, 1)
# =====================================================================
# 3. GAN TRAINING PIPELINE
# =====================================================================
def train_gan():
device = [Link]("cuda" if [Link].is_available() else "cpu")
print(f"[*] Using device: {device}")
generator = GeneratorUNet().to(device)
discriminator = Discriminator().to(device)
criterion_GAN = [Link]()
criterion_L1 = nn.L1Loss()
[Link]("models", exist_ok=True)
checkpoint_path = "models/checkpoint_latest.pth"
start_epoch = 0
if [Link](checkpoint_path):
print("[*] Found existing checkpoint. Loading weights...")
checkpoint = [Link](checkpoint_path, map_location=device)
generator.load_state_dict([Link]('generator_state_dict',
checkpoint), strict=False)
if 'discriminator_state_dict' in checkpoint:
discriminator.load_state_dict(checkpoint['discriminator_state_dict'],
strict=False)
if 'optimizer_G_state_dict' in checkpoint:
optimizer_G.load_state_dict(checkpoint['optimizer_G_state_dict'])
optimizer_D.load_state_dict(checkpoint['optimizer_D_state_dict'])
else:
print("[!] Optimizers not found. Starting fresh optimizers.")
start_epoch = [Link]('epoch', -1) + 1
print(f"[*] Resuming from Epoch {start_epoch}")
[Link]("sentinel_gan_samples", exist_ok=True)
with torch.no_grad():
dummy = discriminator(imgs_tar, imgs_in)
valid = torch.ones_like(dummy, device=device)
fake = torch.zeros_like(dummy, device=device)
# ------------------
# Train Generator
# ------------------
optimizer_G.zero_grad()
gen_imgs = generator(imgs_in, dataset_type="sentinel")
loss_G = criterion_GAN(discriminator(gen_imgs, imgs_in),
valid) + lambda_pixel * criterion_L1(gen_imgs, imgs_tar)
loss_G.backward()
# ---------------------
# Train Discriminator
# ---------------------
optimizer_D.zero_grad()
loss_D = 0.5 * (criterion_GAN(discriminator(imgs_tar,
imgs_in), valid) +
criterion_GAN(discriminator(gen_imgs.detach(),
imgs_in), fake))
loss_D.backward()
optimizer_D.step()
if i % 20 == 0:
print(f"[Epoch {epoch}/500] [Batch {i}] [D loss:
{loss_D.item():.4f}] [G loss: {loss_G.item():.4f}]")
save_image((gen_imgs.data[:1] + 1) / 2.0,
f"sentinel_gan_samples/ep{epoch}_b{i}.png")
[Link]({
'epoch': epoch,
'generator_state_dict': generator.state_dict(),
'discriminator_state_dict': discriminator.state_dict(),
'optimizer_G_state_dict': optimizer_G.state_dict(),
'optimizer_D_state_dict': optimizer_D.state_dict()
}, checkpoint_path)
if __name__ == "__main__":
train_gan()
train_sentinel.py->
import os
import torch
import [Link] as nn
import [Link] as optim
from [Link] import Dataset, DataLoader
import numpy as np
from [Link] import save_image
# ==========================================
# 1. SENTINEL DATA LOADER
# ==========================================
class SentinelDataset(Dataset):
def __init__(self, input_dir, target_dir):
self.input_dir = input_dir
self.target_dir = target_dir
# Only load the .npy files
[Link] = [f for f in [Link](input_dir) if
[Link]('.npy')]
def __len__(self):
return len([Link])
# ==========================================
# THE FIX: NORMALIZATION (Signal Step-Down)
# ==========================================
# Safely scale the Input array to [-1, 1]
in_min, in_max = [Link](in_arr), [Link](in_arr)
if in_max - in_min > 0:
in_arr = (in_arr - in_min) / (in_max - in_min) # Scale to [0,
1]
in_arr = (in_arr - 0.5) / 0.5 # Scale to [-1,
1]
# ==========================================
# 2. MAIN TRAINING LOOP
# ==========================================
def train_sentinel():
device = [Link]("cuda" if [Link].is_available() else "cpu")
print(f"Preparing Sentinel Training on: {device}")
# Initialize Model
generator = GeneratorUNet().to(device)
[Link]("sentinel_samples", exist_ok=True)
optimizer_G.zero_grad()
if __name__ == "__main__":
train_sentinel()
[Link]->
import os
import time
import torch
import [Link] as nn
from [Link] import DataLoader
def train_gan():
# 1. Hyperparameters
epochs = 10
batch_size = 4
lr = 0.0002
lambda_pixel = 100.0
SAVE_INTERVAL_SECONDS = 300 # 300 seconds = 5 minutes
# 3. Initialize Models
generator = GeneratorUNet(in_channels=3, out_channels=3).to(device)
discriminator = Discriminator(in_channels=3).to(device)
# 5. Optimizers
optimizer_G = [Link]([Link](), lr=lr,
betas=(0.5, 0.999))
optimizer_D = [Link]([Link](), lr=lr,
betas=(0.5, 0.999))
if [Link](checkpoint_path):
print("\n[+] Found existing save file! Loading AI memories...")
checkpoint = [Link](checkpoint_path, map_location=device)
generator.load_state_dict(checkpoint['generator_state_dict'])
discriminator.load_state_dict(checkpoint['discriminator_state_dict'])
optimizer_G.load_state_dict(checkpoint['optimizer_G_state_dict'])
optimizer_D.load_state_dict(checkpoint['optimizer_D_state_dict'])
start_epoch = checkpoint['epoch']
try:
for epoch in range(start_epoch, epochs + 1):
for i, batch in enumerate(dataloader):
real_cloudy = batch["cloudy"].to(device)
real_clear = batch["clear"].to(device)
# ---------------------------
# Train Generator
# ---------------------------
optimizer_G.zero_grad()
fake_clear = generator(real_cloudy)
pred_fake = discriminator(real_cloudy, fake_clear)
valid_label = torch.ones_like(pred_fake).to(device)
fake_label = torch.zeros_like(pred_fake).to(device)
# ---------------------------
# Train Discriminator
# ---------------------------
optimizer_D.zero_grad()
# Print updates
print(f"[Epoch {epoch}/{epochs}] [Batch
{i}/{len(dataloader)}] [D loss: {loss_D.item():.4f}] [G loss:
{loss_G.item():.4f}]")
#
---------------------------------------------------------
# 5-MINUTE AUTOMATIC TIMER CHECK
#
---------------------------------------------------------
current_time = [Link]()
if (current_time - last_save_time) >=
SAVE_INTERVAL_SECONDS:
print(f"\n[~] 5 minutes elapsed. Running background
auto-save for Batch {i}...")
[Link]({
'epoch': epoch,
'batch': i,
'generator_state_dict': generator.state_dict(),
'discriminator_state_dict':
discriminator.state_dict(),
'optimizer_G_state_dict':
optimizer_G.state_dict(),
'optimizer_D_state_dict':
optimizer_D.state_dict(),
}, checkpoint_path)
last_save_time = current_time
print("[+] Auto-save complete. Resuming training
metrics smoothly...\n")
[Link]({
'epoch': current_save_epoch,
'batch': current_save_batch,
'generator_state_dict': generator.state_dict(),
'discriminator_state_dict': discriminator.state_dict(),
'optimizer_G_state_dict': optimizer_G.state_dict(),
'optimizer_D_state_dict': optimizer_D.state_dict(),
}, checkpoint_path)
print("[+] Emergency save complete. You can safely close your
terminal.")
return
if __name__ == "__main__":
train_gan()