mirror of
https://git.victorphan.net/basketballcantho/CSIROBoeingPhase5-Vietnam.git
synced 2026-08-06 22:13:11 +07:00
train CNN thành công
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "72723821",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Prepare Data on Server - Load Raw Data Only\n",
|
||||
"Chuẩn bị dữ liệu trên server: **Chỉ tải dữ liệu thô từ S3, không xử lý**\n",
|
||||
"\n",
|
||||
"**Workflow:**\n",
|
||||
"1. Server: Tải S2 (red, nir, scl) + S1 (VH, VV) thô → Lưu NetCDF\n",
|
||||
"2. Local: Tải xuống → Tính NDVI → Cloud mask → Fill NaN → Aggregation → Train model\n",
|
||||
"\n",
|
||||
"**Sau khi chạy xong, tải các file data xuống máy cá nhân để xử lý + train model**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f502b085",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"%matplotlib inline\n",
|
||||
"\n",
|
||||
"import importlib\n",
|
||||
"import new_import_ODC \n",
|
||||
"\n",
|
||||
"importlib.reload(new_import_ODC)\n",
|
||||
"\n",
|
||||
"from new_import_ODC import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "379dd847",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Cấu hình Daskgateway\n",
|
||||
"cluster, client = notebook_utils.initialize_dask(use_gateway=True, workers=(1, 10))\n",
|
||||
"# Khai báo 1 Datacube là dc\n",
|
||||
"dc = datacube.Datacube()\n",
|
||||
"\n",
|
||||
"# Cấu hình truy cập dịch vụ S3\n",
|
||||
"configure_s3_access(aws_unsigned=False, requester_pays=True, client=client)\n",
|
||||
"\n",
|
||||
"client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "da3e2180",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Cấu hình thời gian lấy ảnh và tọa độ\n",
|
||||
"date_range = (\"2022-09-01\", \"2023-10-01\")\n",
|
||||
"longtitude_range = (105.5, 106.4)\n",
|
||||
"latitude_range = (9.2, 10.0)\n",
|
||||
"\n",
|
||||
"coordinates = (longtitude_range, latitude_range)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f521c79",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## DEBUG: Inspect what datacube wants to load\n",
|
||||
"print(\"🔍 DIAGNOSTIC: Checking datacube metadata...\\n\")\n",
|
||||
"\n",
|
||||
"# Check available products\n",
|
||||
"available_products = dc.list_products()\n",
|
||||
"s2_products = available_products[available_products['name'].str.contains('s2', case=False)]\n",
|
||||
"print(f\"Available S2 products:\\n{s2_products[['name', 'description']].to_string()}\\n\")\n",
|
||||
"\n",
|
||||
"# Query to check what would be loaded\n",
|
||||
"test_query = {\n",
|
||||
" 'product': 's2_l2a',\n",
|
||||
" 'x': longtitude_range,\n",
|
||||
" 'y': latitude_range,\n",
|
||||
" 'time': (\"2023-01-01\", \"2023-02-01\"), # Just 1 month for testing\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"print(f\"Test query: {test_query}\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # This queries metadata only, doesn't load data\n",
|
||||
" test_datasets = dc.find_datasets(**test_query)\n",
|
||||
" print(f\"\\n📊 Metadata check for Jan 2023:\")\n",
|
||||
" print(f\" Found {len(test_datasets)} scenes\")\n",
|
||||
" if test_datasets:\n",
|
||||
" first_ds = test_datasets[0]\n",
|
||||
" print(f\" First scene: {first_ds.center_time}\")\n",
|
||||
" print(f\" Bounds: {first_ds.bounds}\")\n",
|
||||
" print(f\" CRS: {first_ds.crs}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"❌ Error: {e}\")\n",
|
||||
"\n",
|
||||
"print(\"\\n\" + \"=\"*60 + \"\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8cf560b0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## SENTINEL-2 LOADING: Monthly chunks to prevent OOM\n",
|
||||
"print(\"📡 Tải dữ liệu Sentinel-2 L2A từ S3...\")\n",
|
||||
"print(f\" AOI: {longtitude_range}, {latitude_range}\")\n",
|
||||
"print(f\" Time range: {date_range}\\n\")\n",
|
||||
"\n",
|
||||
"data = None\n",
|
||||
"\n",
|
||||
"# Strategy: Load 13 monthly chunks instead of 396 scenes at once\n",
|
||||
"# This keeps memory usage manageable (~5-15 GB per month)\n",
|
||||
"\n",
|
||||
"date_ranges = [\n",
|
||||
" (\"2022-09-01\", \"2022-10-01\"),\n",
|
||||
" (\"2022-10-01\", \"2022-11-01\"),\n",
|
||||
" (\"2022-11-01\", \"2022-12-01\"),\n",
|
||||
" (\"2022-12-01\", \"2023-01-01\"),\n",
|
||||
" (\"2023-01-01\", \"2023-02-01\"),\n",
|
||||
" (\"2023-02-01\", \"2023-03-01\"),\n",
|
||||
" (\"2023-03-01\", \"2023-04-01\"),\n",
|
||||
" (\"2023-04-01\", \"2023-05-01\"),\n",
|
||||
" (\"2023-05-01\", \"2023-06-01\"),\n",
|
||||
" (\"2023-06-01\", \"2023-07-01\"),\n",
|
||||
" (\"2023-07-01\", \"2023-08-01\"),\n",
|
||||
" (\"2023-08-01\", \"2023-09-01\"),\n",
|
||||
" (\"2023-09-01\", \"2023-10-01\"),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"product = 's2_l2a'\n",
|
||||
"measurements = ['red', 'nir', 'scl']\n",
|
||||
"\n",
|
||||
"# Get native CRS once\n",
|
||||
"try:\n",
|
||||
" query_crs = {\n",
|
||||
" 'product': product,\n",
|
||||
" 'x': longtitude_range,\n",
|
||||
" 'y': latitude_range,\n",
|
||||
" 'time': date_range,\n",
|
||||
" }\n",
|
||||
" native_crs = notebook_utils.mostcommon_crs(dc, query_crs)\n",
|
||||
" print(f\"✅ Native CRS: {native_crs}\\n\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"⚠️ Could not determine CRS: {e}\")\n",
|
||||
" native_crs = 'EPSG:32648' # Fallback for UTM Zone 48N\n",
|
||||
"\n",
|
||||
"data_list = []\n",
|
||||
"\n",
|
||||
"for i, (start_date, end_date) in enumerate(date_ranges):\n",
|
||||
" print(f\"[{i+1:2d}/13] {start_date} → {end_date} \", end=\"\", flush=True)\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" monthly_query = {\n",
|
||||
" 'product': product,\n",
|
||||
" 'x': longtitude_range,\n",
|
||||
" 'y': latitude_range,\n",
|
||||
" 'time': (start_date, end_date),\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" load_params = {\n",
|
||||
" 'measurements': measurements,\n",
|
||||
" 'output_crs': native_crs,\n",
|
||||
" 'resolution': (-10, 10),\n",
|
||||
" 'group_by': 'solar_day',\n",
|
||||
" 'dask_chunks': {'x': 512, 'y': 512, 'time': 1},\n",
|
||||
" 'skip_broken_datasets': True,\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" monthly_data = load_s2l2a_with_offset(dc, monthly_query | load_params)\n",
|
||||
" \n",
|
||||
" n_scenes = monthly_data.sizes['time']\n",
|
||||
" if n_scenes > 0:\n",
|
||||
" data_list.append(monthly_data)\n",
|
||||
" print(f\"✓ {n_scenes} scenes\")\n",
|
||||
" else:\n",
|
||||
" print(\"⚠️ 0 scenes\")\n",
|
||||
" \n",
|
||||
" except MemoryError as e:\n",
|
||||
" print(f\"❌ OOM: {str(e)[:60]}\")\n",
|
||||
" break\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"❌ {str(e)[:60]}\")\n",
|
||||
" continue\n",
|
||||
"\n",
|
||||
"# Combine all monthly chunks\n",
|
||||
"if data_list:\n",
|
||||
" print(f\"\\n🔗 Combining {len(data_list)} monthly chunks...\")\n",
|
||||
" data = xr.concat(data_list, dim='time')\n",
|
||||
" print(f\"✅ Success! Shape: {dict(data.dims)}\")\n",
|
||||
" print(f\" Memory: {notebook_utils.xarray_object_size(data)}\")\n",
|
||||
" display(data)\n",
|
||||
"else:\n",
|
||||
" print(\"\\n❌ Failed to load any scenes\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cef198a0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Tải dữ liệu Sentinel-1 (VH, VV) - Raw data, không xử lý\n",
|
||||
"print(\"📡 Tải dữ liệu Sentinel-1 từ S3...\")\n",
|
||||
"try:\n",
|
||||
" dsvh, dsvv = load_data_sen1(dc, date_range, coordinates)\n",
|
||||
" print(f\"✅ VH shape: {dsvh.shape}\")\n",
|
||||
" print(f\"✅ VV shape: {dsvv.shape}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"⚠️ Error loading S1: {e}\")\n",
|
||||
" dsvh = None\n",
|
||||
" dsvv = None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5ba52958",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Lưu dữ liệu RAW thành file NetCDF (chưa xử lý)\n",
|
||||
"Dữ liệu này sẽ được tải xuống máy local để tiếp tục xử lý và training"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "06bf3f40",
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Close Dask client FIRST to avoid permission issues\n",
|
||||
"print(\"🔌 Closing Dask client to free resources...\")\n",
|
||||
"client.close()\n",
|
||||
"cluster.close()\n",
|
||||
"print(\"✅ Dask closed\\n\")\n",
|
||||
"\n",
|
||||
"# Now save data locally without Dask interference\n",
|
||||
"data_dir = \"data_for_training\"\n",
|
||||
"if not os.path.exists(data_dir):\n",
|
||||
" os.makedirs(data_dir)\n",
|
||||
" print(f\"✅ Tạo thư mục {data_dir}\\n\")\n",
|
||||
"\n",
|
||||
"print(\"💾 Lưu dữ liệu RAW từ S2 (red, nir, scl)...\")\n",
|
||||
"\n",
|
||||
"# FIX: Loại bỏ metadata problematic trước khi save\n",
|
||||
"data_clean = data.copy()\n",
|
||||
"\n",
|
||||
"# 1. Loại bỏ dict attributes từ variables\n",
|
||||
"for var_name in data_clean.data_vars:\n",
|
||||
" attrs_to_remove = []\n",
|
||||
" for attr_name, attr_value in data_clean[var_name].attrs.items():\n",
|
||||
" if isinstance(attr_value, dict):\n",
|
||||
" attrs_to_remove.append(attr_name)\n",
|
||||
" \n",
|
||||
" for attr_name in attrs_to_remove:\n",
|
||||
" print(f\" ⚠️ Removing problematic attr: {var_name}.{attr_name}\")\n",
|
||||
" del data_clean[var_name].attrs[attr_name]\n",
|
||||
"\n",
|
||||
"# 2. Xóa attrs từ coordinates\n",
|
||||
"for coord_name in data_clean.coords:\n",
|
||||
" attrs_to_remove = []\n",
|
||||
" for attr_name, attr_value in data_clean[coord_name].attrs.items():\n",
|
||||
" if attr_name in ['units', 'calendar', 'long_name', 'standard_name']:\n",
|
||||
" attrs_to_remove.append(attr_name)\n",
|
||||
" elif isinstance(attr_value, dict):\n",
|
||||
" attrs_to_remove.append(attr_name)\n",
|
||||
" \n",
|
||||
" for attr_name in attrs_to_remove:\n",
|
||||
" print(f\" ⚠️ Removing coord attr: {coord_name}.{attr_name}\")\n",
|
||||
" del data_clean[coord_name].attrs[attr_name]\n",
|
||||
"\n",
|
||||
"# Compute to memory BEFORE closing Dask\n",
|
||||
"print(\"\\n ⏳ Loading data into memory...\")\n",
|
||||
"try:\n",
|
||||
" data_computed = data_clean.compute()\n",
|
||||
" print(\" ✅ Data loaded to memory\\n\")\n",
|
||||
" \n",
|
||||
" # Save from memory (no Dask involved)\n",
|
||||
" s2_path = os.path.join(data_dir, \"sentinel2_raw.nc\")\n",
|
||||
" print(f\" - Saving to {s2_path}...\")\n",
|
||||
" data_computed.to_netcdf(s2_path, engine='netcdf4')\n",
|
||||
" s2_size = os.path.getsize(s2_path) / 1024**3\n",
|
||||
" print(f\" ✅ Sentinel-2 saved ({s2_size:.2f} GB)\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\" ❌ Error: {e}\")\n",
|
||||
" print(f\" ⚠️ Data may still be in memory, proceed to next step\")\n",
|
||||
"\n",
|
||||
"# Lưu raw Sentinel-1 (nếu thành công)\n",
|
||||
"if dsvh is not None and dsvv is not None:\n",
|
||||
" print(f\"\\n💾 Lưu dữ liệu RAW từ S1 (VH, VV)...\")\n",
|
||||
" \n",
|
||||
" # Remove problematic attrs từ S1 data\n",
|
||||
" if hasattr(dsvh, 'attrs'):\n",
|
||||
" for attr in list(dsvh.attrs.keys()):\n",
|
||||
" if attr in ['units', 'calendar'] or isinstance(dsvh.attrs[attr], dict):\n",
|
||||
" del dsvh.attrs[attr]\n",
|
||||
" \n",
|
||||
" if hasattr(dsvv, 'attrs'):\n",
|
||||
" for attr in list(dsvv.attrs.keys()):\n",
|
||||
" if attr in ['units', 'calendar'] or isinstance(dsvv.attrs[attr], dict):\n",
|
||||
" del dsvv.attrs[attr]\n",
|
||||
" \n",
|
||||
" s1_data = xr.Dataset({\n",
|
||||
" 'VH': dsvh,\n",
|
||||
" 'VV': dsvv,\n",
|
||||
" })\n",
|
||||
" \n",
|
||||
" s1_path = os.path.join(data_dir, \"sentinel1_raw.nc\")\n",
|
||||
" print(f\" - Saving to {s1_path}...\")\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" s1_data.to_netcdf(s1_path, engine='netcdf4')\n",
|
||||
" s1_size = os.path.getsize(s1_path) / 1024**3\n",
|
||||
" print(f\" ✅ Sentinel-1 saved ({s1_size:.2f} GB)\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\" ❌ Error saving S1: {e}\")\n",
|
||||
"else:\n",
|
||||
" print(\"⚠️ Sentinel-1 not saved\")\n",
|
||||
"\n",
|
||||
"print(f\"\\n✅ Data ready in '{data_dir}'\")\n",
|
||||
"print(f\"\\n📥 **Download to local machine using rsync:**\")\n",
|
||||
"print(f\" rsync -avz --progress user@server:~/CSIROBoeingPhase5-Vietnam/{data_dir}/ ./{data_dir}/\")\n",
|
||||
"print(f\"\\n🔧 Next: Process data locally (NDVI, cloud mask, aggregation, training)\")\n",
|
||||
"\n",
|
||||
"# Hiển thị tổng kích thước\n",
|
||||
"import subprocess\n",
|
||||
"try:\n",
|
||||
" result = subprocess.run(['du', '-sh', data_dir], capture_output=True, text=True)\n",
|
||||
" print(f\"\\n📊 Data size on server: {result.stdout.strip()}\")\n",
|
||||
"except:\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "93df03e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Lưu training data\n",
|
||||
"train_path = \"train/ST_training data_updated_1130points_new.shp\"\n",
|
||||
"import shutil\n",
|
||||
"\n",
|
||||
"print(f\"📋 Copy training data...\")\n",
|
||||
"# Copy toàn bộ các file liên quan đến shapefile\n",
|
||||
"train_dir = \"train\"\n",
|
||||
"train_output = os.path.join(data_dir, \"train_data\")\n",
|
||||
"if not os.path.exists(train_output):\n",
|
||||
" os.makedirs(train_output)\n",
|
||||
"\n",
|
||||
"for file in os.listdir(train_dir):\n",
|
||||
" if \"1130points_new\" in file:\n",
|
||||
" src = os.path.join(train_dir, file)\n",
|
||||
" dst = os.path.join(train_output, file)\n",
|
||||
" shutil.copy2(src, dst)\n",
|
||||
" print(f\"✅ {file}\")\n",
|
||||
"\n",
|
||||
"print(f\"\\n✅ Training data đã copy vào '{train_output}'\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8bb935d9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Đóng client, cluster\n",
|
||||
"print(\"\\n🔌 Đóng kết nối...\")\n",
|
||||
"client.close()\n",
|
||||
"cluster.close()\n",
|
||||
"print(\"✅ Xong!\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,405 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "912ed572-1658-406b-976c-cd6de2d4e89e",
|
||||
"metadata": {
|
||||
"editable": true,
|
||||
"slideshow": {
|
||||
"slide_type": ""
|
||||
},
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"%matplotlib inline\n",
|
||||
"\n",
|
||||
"import importlib\n",
|
||||
"import new_import_ODC \n",
|
||||
"\n",
|
||||
"importlib.reload(new_import_ODC)\n",
|
||||
"\n",
|
||||
"from new_import_ODC import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d824dc4f-994b-4d1c-8d24-ce6674da141c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Cấu hình Daskgateway\n",
|
||||
"cluster, client = notebook_utils.initialize_dask(use_gateway=True, workers=(1, 10))\n",
|
||||
"# Khai báo 1 Datacube là dc\n",
|
||||
"dc = datacube.Datacube()\n",
|
||||
"\n",
|
||||
"# Cấu hình truy cập dịch vụ S3\n",
|
||||
"configure_s3_access(aws_unsigned=False, requester_pays=True, client=client)\n",
|
||||
"\n",
|
||||
"client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fbed4c80-bbf8-4ea8-aa45-2460b2ba04c7",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## cấu hình thời gian lấy ảnh và tọa độ\n",
|
||||
"date_range = (\"2022-09-01\", \"2023-10-01\")\n",
|
||||
"longtitude_range = (105.5, 106.4)\n",
|
||||
"latitude_range = (9.2, 10.0)\n",
|
||||
"\n",
|
||||
"coordinates = (longtitude_range, latitude_range)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6b90c49b-0665-4478-a23b-d111ef88eb79",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## truy vấn ảnh vệ tinh sen2\n",
|
||||
"data = load_data(dc, date_range, longtitude_range, latitude_range)\n",
|
||||
"notebook_utils.heading(notebook_utils.xarray_object_size(data))\n",
|
||||
"display(data)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2f6938b6-82e2-4916-bc1d-719c169e25e4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Tiến hành loại bỏ các vị trí bị mây ảnh hưởng\n",
|
||||
"result = mask_clean(data)\n",
|
||||
"progress(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "435f9f78-a9a4-4226-86ca-d4bec42d454e",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tiến hành tính toán NDVI\n",
|
||||
"ds1 = calculate_indices(result, index=\"NDVI\", satellite_mission=\"s2\")\n",
|
||||
"ndvi = ds1[\"NDVI\"]\n",
|
||||
"display(ndvi)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "84992d28-8e3f-468e-be08-ded511f2c662",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Hiển thị ảnh NDVI chưa điền các giá trị mây (chưa fill nan)\n",
|
||||
"plt.imshow(ndvi.isel(time=6))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "72318b60-532a-4f08-a5f7-94762d08a42c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Thiết lập giá trị trung bình mùa vụ để xử lý các điểm ảnh bị mây dựa vào sự thay đổi theo mùa\n",
|
||||
"time_split = [\n",
|
||||
" slice(\"2022-09-01\", \"2023-01-01\"),\n",
|
||||
" slice(\"2023-01-01\", \"2023-05-01\"),\n",
|
||||
" slice(\"2023-05-01\", \"2023-07-01\"),\n",
|
||||
" slice(\"2023-07-01\", \"2023-10-01\"),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Điền mây ở các vị trí mang giá trị nan (fill nan)\n",
|
||||
"fill_nan_ndvi = fill_nan(ndvi, time_split)\n",
|
||||
"\n",
|
||||
"# In kết quả ảnh NDVI đã điền mây (đã fill nan)\n",
|
||||
"plt.imshow(fill_nan_ndvi.isel(time=6))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "375b1cfb-37f5-49fe-8061-ea32eb47f9f6",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"## tính ndvi theo tháng\n",
|
||||
"average_ndvi = fill_nan_ndvi.resample(time=\"1M\").mean().persist()\n",
|
||||
"progress(average_ndvi)\n",
|
||||
"\n",
|
||||
"# compute average_ndvi\n",
|
||||
"average_ndvi = average_ndvi.compute()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "187cc640-aef9-476b-91fc-b63f4d3ff2e3",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#Load dữ liệu ảnh Sentinel 1\n",
|
||||
"dsvh, dsvv = load_data_sen1(dc, date_range, coordinates)\n",
|
||||
"average_vv = calculate_average(dsvv, time_pattern='1M')\n",
|
||||
"average_vh = calculate_average(dsvh, time_pattern='1M')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d2585562-88aa-4c7d-bf70-1f6affcf65d4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## cấu hình bộ dữ liệu điểm huấn luyện mô hình (train file)\n",
|
||||
"train_path = \"train/ST_training data_updated_1130points_new.shp\" # đường dẫn shp file train\n",
|
||||
"\n",
|
||||
"## load dữ liệu điểm huấn luyện mô hình (train file)\n",
|
||||
"train = load_train_data(train_path)\n",
|
||||
"train.head()\n",
|
||||
"\n",
|
||||
"# cấu hình nhãn dữ liệu \n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": \"0\",\n",
|
||||
" \"Lua\": \"1\",\n",
|
||||
" \"CHN\": \"2\",\n",
|
||||
" \"CLN\": \"3\",\n",
|
||||
" \"TS\": \"4\",\n",
|
||||
" \"Song\": \"5\",\n",
|
||||
" \"Dat xay dung\": \"6\",\n",
|
||||
" \"Rung\": \"7\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# xây dựng tập dữ liệu (dataset) chứa dữ liệu VH, VV, NDVI\n",
|
||||
"datasets = get_data_sen1_and_sen2(train, average_ndvi, average_vh, average_vv)\n",
|
||||
"\n",
|
||||
"# chia tập dữ liệu thành các phần theo tỉ lệ 80(80-20)-20 tương ứng với tập train, validate, test\n",
|
||||
"X_train, X_val, X_test, y_train, y_val, y_test = split_train_data(\n",
|
||||
" train, label_mapping, datasets\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2e955884-d4af-422d-a8e6-d436199540e0",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Import XGBoost\n",
|
||||
"import xgboost as xgb\n",
|
||||
"from sklearn.metrics import accuracy_score\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Convert to numpy arrays\n",
|
||||
"X_train_np = np.asarray(X_train, dtype=np.float32)\n",
|
||||
"X_val_np = np.asarray(X_val, dtype=np.float32)\n",
|
||||
"y_train_np = np.asarray(y_train, dtype=np.int32)\n",
|
||||
"y_val_np = np.asarray(y_val, dtype=np.int32)\n",
|
||||
"\n",
|
||||
"print(\"🚀 Training XGBoost model...\")\n",
|
||||
"print(f\" Train samples: {len(X_train_np)}\")\n",
|
||||
"print(f\" Val samples: {len(X_val_np)}\")\n",
|
||||
"print(f\" Features: {X_train_np.shape[1]}\")\n",
|
||||
"print(f\" Classes: 8\\n\")\n",
|
||||
"\n",
|
||||
"# XGBoost parameters\n",
|
||||
"params = {\n",
|
||||
" 'objective': 'multi:softmax', # Multi-class classification\n",
|
||||
" 'num_class': 8, # 8 land use classes\n",
|
||||
" 'max_depth': 6, # Maximum tree depth\n",
|
||||
" 'learning_rate': 0.1, # Learning rate\n",
|
||||
" 'n_estimators': 200, # Number of trees\n",
|
||||
" 'subsample': 0.8, # Subsample ratio\n",
|
||||
" 'colsample_bytree': 0.8, # Feature sampling ratio\n",
|
||||
" 'random_state': 42,\n",
|
||||
" 'n_jobs': -1, # Use all CPU cores\n",
|
||||
" 'eval_metric': 'mlogloss' # Multi-class log loss\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# Train XGBoost model\n",
|
||||
"model = xgb.XGBClassifier(**params)\n",
|
||||
"\n",
|
||||
"model.fit(\n",
|
||||
" X_train_np, y_train_np,\n",
|
||||
" eval_set=[(X_train_np, y_train_np), (X_val_np, y_val_np)],\n",
|
||||
" verbose=True\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Validation accuracy\n",
|
||||
"y_val_pred = model.predict(X_val_np)\n",
|
||||
"val_accuracy = accuracy_score(y_val_np, y_val_pred)\n",
|
||||
"print(f\"\\n✅ Training completed!\")\n",
|
||||
"print(f\" Validation Accuracy: {val_accuracy:.4f} ({val_accuracy*100:.2f}%)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b2a1e42c-cf1b-4d82-a6af-b06e3496918f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Evaluate on test set\n",
|
||||
"X_test_np = np.asarray(X_test, dtype=np.float32)\n",
|
||||
"y_test_np = np.asarray(y_test, dtype=np.int32)\n",
|
||||
"\n",
|
||||
"print(\"📊 Evaluating XGBoost model on test set...\\n\")\n",
|
||||
"\n",
|
||||
"# Predictions\n",
|
||||
"y_pred_test = model.predict(X_test_np)\n",
|
||||
"\n",
|
||||
"# Metrics\n",
|
||||
"from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\n",
|
||||
"\n",
|
||||
"test_accuracy = accuracy_score(y_test_np, y_pred_test)\n",
|
||||
"precision = precision_score(y_test_np, y_pred_test, average='weighted', zero_division=0)\n",
|
||||
"recall = recall_score(y_test_np, y_pred_test, average='weighted', zero_division=0)\n",
|
||||
"f1 = f1_score(y_test_np, y_pred_test, average='weighted', zero_division=0)\n",
|
||||
"\n",
|
||||
"print(f\"📈 Test Results:\")\n",
|
||||
"print(f\" Accuracy: {test_accuracy:.4f} ({test_accuracy*100:.2f}%)\")\n",
|
||||
"print(f\" Precision: {precision:.4f}\")\n",
|
||||
"print(f\" Recall: {recall:.4f}\")\n",
|
||||
"print(f\" F1-Score: {f1:.4f}\\n\")\n",
|
||||
"\n",
|
||||
"# Confusion Matrix\n",
|
||||
"from sklearn.metrics import ConfusionMatrixDisplay\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"# Create figure first\n",
|
||||
"fig, ax = plt.subplots(figsize=(10, 8))\n",
|
||||
"\n",
|
||||
"class_names = list(label_mapping.keys())\n",
|
||||
"cm = confusion_matrix(y_test_np, y_pred_test)\n",
|
||||
"disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_names)\n",
|
||||
"disp.plot(cmap='Blues', ax=ax)\n",
|
||||
"plt.xticks(rotation=45, ha='right')\n",
|
||||
"plt.title('XGBoost Confusion Matrix')\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f1a14379-ed6e-4897-9ca4-2669743fab40",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Lưu mô hình huấn luyện\n",
|
||||
"import json\n",
|
||||
"import joblib\n",
|
||||
"\n",
|
||||
"# Save XGBoost model\n",
|
||||
"model_path = \"model_xgboost.joblib\"\n",
|
||||
"joblib.dump(model, model_path)\n",
|
||||
"print(f\"✅ Model saved to {model_path}\")\n",
|
||||
"\n",
|
||||
"# Save model info\n",
|
||||
"info = {\n",
|
||||
" \"model_type\": \"XGBoost\",\n",
|
||||
" \"num_classes\": 8,\n",
|
||||
" \"classes\": list(label_mapping.keys()),\n",
|
||||
" \"num_features\": X_train_np.shape[1],\n",
|
||||
" \"params\": params,\n",
|
||||
" \"accuracy\": float(test_accuracy),\n",
|
||||
" \"precision\": float(precision),\n",
|
||||
" \"recall\": float(recall),\n",
|
||||
" \"f1_score\": float(f1),\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"with open(\"model_xgboost_info.json\", \"w\") as f:\n",
|
||||
" json.dump(info, f, indent=2)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Model info saved to model_xgboost_info.json\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "33dd516d-9824-499e-96b9-5cd9224c194c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# đóng client, cluster\n",
|
||||
"client.close()\n",
|
||||
"cluster.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ee0ecd6a-733b-4655-8864-bc037a539ce2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,571 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a58466bf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Train CNN Model on Local Machine\n",
|
||||
"Huấn luyện mô hình CNN với PyTorch trên máy cá nhân\n",
|
||||
"\n",
|
||||
"**Yêu cầu**: Đã tải dữ liệu từ server vào thư mục `data_for_training/`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0e5a5a39",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import numpy as np\n",
|
||||
"import xarray as xr\n",
|
||||
"import torch\n",
|
||||
"import torch.nn as nn\n",
|
||||
"import torch.optim as optim\n",
|
||||
"from torch.utils.data import DataLoader, TensorDataset\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from sklearn.preprocessing import LabelEncoder\n",
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"import geopandas as gpd\n",
|
||||
"import joblib\n",
|
||||
"from utils import load_data_geo\n",
|
||||
"\n",
|
||||
"print(f\"PyTorch version: {torch.__version__}\")\n",
|
||||
"print(f\"GPU available: {torch.cuda.is_available()}\")\n",
|
||||
"if torch.cuda.is_available():\n",
|
||||
" print(f\"GPU device: {torch.cuda.get_device_name(0)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ff3f92e3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Load dữ liệu từ server"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "880dba25",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Đường dẫn dữ liệu\n",
|
||||
"data_dir = \"data_for_training\"\n",
|
||||
"\n",
|
||||
"print(\"📂 Kiểm tra các file dữ liệu...\")\n",
|
||||
"if not os.path.exists(data_dir):\n",
|
||||
" raise FileNotFoundError(f\"❌ Thư mục '{data_dir}' không tồn tại. Hãy tải dữ liệu từ server trước.\")\n",
|
||||
"\n",
|
||||
"# Load dữ liệu\n",
|
||||
"print(\"\\n📥 Load dữ liệu...\")\n",
|
||||
"average_ndvi = xr.open_dataarray(os.path.join(data_dir, \"average_ndvi.nc\"))\n",
|
||||
"average_vv = xr.open_dataarray(os.path.join(data_dir, \"average_vv.nc\"))\n",
|
||||
"average_vh = xr.open_dataarray(os.path.join(data_dir, \"average_vh.nc\"))\n",
|
||||
"\n",
|
||||
"print(f\"✅ NDVI shape: {average_ndvi.shape}\")\n",
|
||||
"print(f\"✅ VV shape: {average_vv.shape}\")\n",
|
||||
"print(f\"✅ VH shape: {average_vh.shape}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2236b22d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load training data\n",
|
||||
"train_data_path = os.path.join(data_dir, \"train_data\", \"ST_training data_updated_1130points_new.shp\")\n",
|
||||
"print(f\"\\n📋 Load training points...\")\n",
|
||||
"train = load_data_geo(train_data_path)\n",
|
||||
"print(f\"✅ Training points: {len(train)}\")\n",
|
||||
"print(f\"✅ Columns: {train.columns.tolist()}\")\n",
|
||||
"train.head()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8b1800e2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Chuẩn bị dữ liệu huấn luyện"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "128d1492",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Cấu hình nhãn dữ liệu\n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": 0,\n",
|
||||
" \"Lua\": 1,\n",
|
||||
" \"CHN\": 2,\n",
|
||||
" \"CLN\": 3,\n",
|
||||
" \"TS\": 4,\n",
|
||||
" \"Song\": 5,\n",
|
||||
" \"Dat xay dung\": 6,\n",
|
||||
" \"Rung\": 7,\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"num_classes = len(label_mapping)\n",
|
||||
"print(f\"🏷️ Số lớp: {num_classes}\")\n",
|
||||
"for label, idx in label_mapping.items():\n",
|
||||
" print(f\" {idx}: {label}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ec87566f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Trích xuất dữ liệu từ các điểm training\n",
|
||||
"print(\"\\n🔧 Trích xuất dữ liệu từ các điểm...\")\n",
|
||||
"X = []\n",
|
||||
"y = []\n",
|
||||
"\n",
|
||||
"for idx, point in train.iterrows():\n",
|
||||
" try:\n",
|
||||
" # Lấy tọa độ\n",
|
||||
" x_coord = point.geometry.x\n",
|
||||
" y_coord = point.geometry.y\n",
|
||||
" \n",
|
||||
" # Trích xuất giá trị từ mỗi band\n",
|
||||
" ndvi_data = average_ndvi.sel(x=x_coord, y=y_coord, method='nearest').values\n",
|
||||
" vv_data = average_vv.sel(x=x_coord, y=y_coord, method='nearest').values\n",
|
||||
" vh_data = average_vh.sel(x=x_coord, y=y_coord, method='nearest').values\n",
|
||||
" \n",
|
||||
" # Concatenate các band\n",
|
||||
" data_point = np.concatenate((ndvi_data, vv_data, vh_data))\n",
|
||||
" X.append(data_point)\n",
|
||||
" \n",
|
||||
" # Lấy nhãn\n",
|
||||
" label_text = point.Hientrang\n",
|
||||
" label_idx = label_mapping[label_text]\n",
|
||||
" y.append(label_idx)\n",
|
||||
" \n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\" ⚠️ Point {idx}: {e}\")\n",
|
||||
"\n",
|
||||
"X = np.array(X)\n",
|
||||
"y = np.array(y)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Dữ liệu trích xuất: {X.shape}\")\n",
|
||||
"print(f\"✅ Nhãn: {y.shape}\")\n",
|
||||
"print(f\"✅ Phân phối nhãn: {np.bincount(y)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2587a67c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Chia dữ liệu\n",
|
||||
"print(\"\\n📊 Chia dữ liệu (train/val/test = 60/20/20)...\")\n",
|
||||
"X_train, X_temp, y_train, y_temp = train_test_split(\n",
|
||||
" X, y, test_size=0.4, random_state=42, stratify=y\n",
|
||||
")\n",
|
||||
"X_val, X_test, y_val, y_test = train_test_split(\n",
|
||||
" X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"✅ Train: {X_train.shape}\")\n",
|
||||
"print(f\"✅ Val: {X_val.shape}\")\n",
|
||||
"print(f\"✅ Test: {X_test.shape}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "359761e4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Normalize dữ liệu\n",
|
||||
"print(\"\\n🔧 Normalize dữ liệu...\")\n",
|
||||
"mean = X_train.mean()\n",
|
||||
"std = X_train.std()\n",
|
||||
"X_train = (X_train - mean) / (std + 1e-8)\n",
|
||||
"X_val = (X_val - mean) / (std + 1e-8)\n",
|
||||
"X_test = (X_test - mean) / (std + 1e-8)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Mean: {mean:.4f}\")\n",
|
||||
"print(f\"✅ Std: {std:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0667150b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Convert to PyTorch tensors\n",
|
||||
"print(\"\\n🔧 Convert sang PyTorch tensors...\")\n",
|
||||
"X_train_tensor = torch.FloatTensor(X_train).unsqueeze(1) # (N, 1, features)\n",
|
||||
"X_val_tensor = torch.FloatTensor(X_val).unsqueeze(1)\n",
|
||||
"X_test_tensor = torch.FloatTensor(X_test).unsqueeze(1)\n",
|
||||
"\n",
|
||||
"y_train_tensor = torch.LongTensor(y_train)\n",
|
||||
"y_val_tensor = torch.LongTensor(y_val)\n",
|
||||
"y_test_tensor = torch.LongTensor(y_test)\n",
|
||||
"\n",
|
||||
"print(f\"✅ X_train shape: {X_train_tensor.shape}\")\n",
|
||||
"print(f\"✅ y_train shape: {y_train_tensor.shape}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "be2a4179",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tạo DataLoaders\n",
|
||||
"print(\"\\n🔧 Tạo DataLoaders...\")\n",
|
||||
"batch_size = 32\n",
|
||||
"\n",
|
||||
"train_dataset = TensorDataset(X_train_tensor, y_train_tensor)\n",
|
||||
"train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
|
||||
"\n",
|
||||
"val_dataset = TensorDataset(X_val_tensor, y_val_tensor)\n",
|
||||
"val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n",
|
||||
"\n",
|
||||
"test_dataset = TensorDataset(X_test_tensor, y_test_tensor)\n",
|
||||
"test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Train batches: {len(train_loader)}\")\n",
|
||||
"print(f\"✅ Val batches: {len(val_loader)}\")\n",
|
||||
"print(f\"✅ Test batches: {len(test_loader)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5231acf3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Xây dựng CNN Model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b279fe09",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Định nghĩa CNN model\n",
|
||||
"class CNNClassifier(nn.Module):\n",
|
||||
" def __init__(self, input_size, num_classes=8):\n",
|
||||
" super(CNNClassifier, self).__init__()\n",
|
||||
" \n",
|
||||
" # Conv blocks\n",
|
||||
" self.conv1 = nn.Conv1d(1, 64, kernel_size=3, padding=1)\n",
|
||||
" self.bn1 = nn.BatchNorm1d(64)\n",
|
||||
" self.conv2 = nn.Conv1d(64, 64, kernel_size=3, padding=1)\n",
|
||||
" self.bn2 = nn.BatchNorm1d(64)\n",
|
||||
" self.pool1 = nn.MaxPool1d(2)\n",
|
||||
" self.drop1 = nn.Dropout(0.25)\n",
|
||||
" \n",
|
||||
" self.conv3 = nn.Conv1d(64, 128, kernel_size=3, padding=1)\n",
|
||||
" self.bn3 = nn.BatchNorm1d(128)\n",
|
||||
" self.conv4 = nn.Conv1d(128, 128, kernel_size=3, padding=1)\n",
|
||||
" self.bn4 = nn.BatchNorm1d(128)\n",
|
||||
" self.pool2 = nn.MaxPool1d(2)\n",
|
||||
" self.drop2 = nn.Dropout(0.25)\n",
|
||||
" \n",
|
||||
" self.conv5 = nn.Conv1d(128, 256, kernel_size=3, padding=1)\n",
|
||||
" self.bn5 = nn.BatchNorm1d(256)\n",
|
||||
" self.conv6 = nn.Conv1d(256, 256, kernel_size=3, padding=1)\n",
|
||||
" self.bn6 = nn.BatchNorm1d(256)\n",
|
||||
" self.global_avg_pool = nn.AdaptiveAvgPool1d(1)\n",
|
||||
" self.drop3 = nn.Dropout(0.25)\n",
|
||||
" \n",
|
||||
" # FC layers\n",
|
||||
" self.fc1 = nn.Linear(256, 128)\n",
|
||||
" self.bn_fc1 = nn.BatchNorm1d(128)\n",
|
||||
" self.drop_fc1 = nn.Dropout(0.5)\n",
|
||||
" \n",
|
||||
" self.fc2 = nn.Linear(128, 64)\n",
|
||||
" self.bn_fc2 = nn.BatchNorm1d(64)\n",
|
||||
" self.drop_fc2 = nn.Dropout(0.5)\n",
|
||||
" \n",
|
||||
" self.fc3 = nn.Linear(64, num_classes)\n",
|
||||
" \n",
|
||||
" self.relu = nn.ReLU()\n",
|
||||
" \n",
|
||||
" def forward(self, x):\n",
|
||||
" # Block 1\n",
|
||||
" x = self.relu(self.bn1(self.conv1(x)))\n",
|
||||
" x = self.relu(self.bn2(self.conv2(x)))\n",
|
||||
" x = self.pool1(x)\n",
|
||||
" x = self.drop1(x)\n",
|
||||
" \n",
|
||||
" # Block 2\n",
|
||||
" x = self.relu(self.bn3(self.conv3(x)))\n",
|
||||
" x = self.relu(self.bn4(self.conv4(x)))\n",
|
||||
" x = self.pool2(x)\n",
|
||||
" x = self.drop2(x)\n",
|
||||
" \n",
|
||||
" # Block 3\n",
|
||||
" x = self.relu(self.bn5(self.conv5(x)))\n",
|
||||
" x = self.relu(self.bn6(self.conv6(x)))\n",
|
||||
" x = self.global_avg_pool(x)\n",
|
||||
" x = x.squeeze(-1)\n",
|
||||
" x = self.drop3(x)\n",
|
||||
" \n",
|
||||
" # FC layers\n",
|
||||
" x = self.relu(self.bn_fc1(self.fc1(x)))\n",
|
||||
" x = self.drop_fc1(x)\n",
|
||||
" x = self.relu(self.bn_fc2(self.fc2(x)))\n",
|
||||
" x = self.drop_fc2(x)\n",
|
||||
" x = self.fc3(x)\n",
|
||||
" \n",
|
||||
" return x\n",
|
||||
"\n",
|
||||
"# Khởi tạo model\n",
|
||||
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
|
||||
"model = CNNClassifier(input_size=X_train.shape[1], num_classes=num_classes)\n",
|
||||
"model = model.to(device)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Model created\")\n",
|
||||
"print(f\"📍 Device: {device}\")\n",
|
||||
"print(f\"\\n📋 Model architecture:\")\n",
|
||||
"print(model)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ff42829a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Huấn luyện Model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "de90a544",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Loss function và optimizer\n",
|
||||
"criterion = nn.CrossEntropyLoss()\n",
|
||||
"optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
|
||||
"scheduler = optim.lr_scheduler.ReduceLROnPlateau(\n",
|
||||
" optimizer, mode='min', factor=0.5, patience=5, verbose=True\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"epochs = 100\n",
|
||||
"early_stop_patience = 15\n",
|
||||
"best_val_loss = float('inf')\n",
|
||||
"early_stop_counter = 0\n",
|
||||
"\n",
|
||||
"train_losses = []\n",
|
||||
"val_losses = []\n",
|
||||
"train_accs = []\n",
|
||||
"val_accs = []\n",
|
||||
"\n",
|
||||
"print(\"🚀 Bắt đầu huấn luyện...\\n\")\n",
|
||||
"\n",
|
||||
"for epoch in range(epochs):\n",
|
||||
" # Training\n",
|
||||
" model.train()\n",
|
||||
" train_loss = 0\n",
|
||||
" train_correct = 0\n",
|
||||
" train_total = 0\n",
|
||||
" \n",
|
||||
" for X_batch, y_batch in train_loader:\n",
|
||||
" X_batch = X_batch.to(device)\n",
|
||||
" y_batch = y_batch.to(device)\n",
|
||||
" \n",
|
||||
" optimizer.zero_grad()\n",
|
||||
" outputs = model(X_batch)\n",
|
||||
" loss = criterion(outputs, y_batch)\n",
|
||||
" loss.backward()\n",
|
||||
" optimizer.step()\n",
|
||||
" \n",
|
||||
" train_loss += loss.item()\n",
|
||||
" _, predicted = torch.max(outputs.data, 1)\n",
|
||||
" train_correct += (predicted == y_batch).sum().item()\n",
|
||||
" train_total += y_batch.size(0)\n",
|
||||
" \n",
|
||||
" train_loss /= len(train_loader)\n",
|
||||
" train_acc = 100 * train_correct / train_total\n",
|
||||
" train_losses.append(train_loss)\n",
|
||||
" train_accs.append(train_acc)\n",
|
||||
" \n",
|
||||
" # Validation\n",
|
||||
" model.eval()\n",
|
||||
" val_loss = 0\n",
|
||||
" val_correct = 0\n",
|
||||
" val_total = 0\n",
|
||||
" \n",
|
||||
" with torch.no_grad():\n",
|
||||
" for X_batch, y_batch in val_loader:\n",
|
||||
" X_batch = X_batch.to(device)\n",
|
||||
" y_batch = y_batch.to(device)\n",
|
||||
" \n",
|
||||
" outputs = model(X_batch)\n",
|
||||
" loss = criterion(outputs, y_batch)\n",
|
||||
" val_loss += loss.item()\n",
|
||||
" _, predicted = torch.max(outputs.data, 1)\n",
|
||||
" val_correct += (predicted == y_batch).sum().item()\n",
|
||||
" val_total += y_batch.size(0)\n",
|
||||
" \n",
|
||||
" val_loss /= len(val_loader)\n",
|
||||
" val_acc = 100 * val_correct / val_total\n",
|
||||
" val_losses.append(val_loss)\n",
|
||||
" val_accs.append(val_acc)\n",
|
||||
" \n",
|
||||
" # Print progress\n",
|
||||
" if (epoch + 1) % 10 == 0:\n",
|
||||
" print(f'Epoch [{epoch+1}/{epochs}]')\n",
|
||||
" print(f' Train Loss: {train_loss:.4f}, Acc: {train_acc:.2f}%')\n",
|
||||
" print(f' Val Loss: {val_loss:.4f}, Acc: {val_acc:.2f}%')\n",
|
||||
" \n",
|
||||
" # Early stopping\n",
|
||||
" scheduler.step(val_loss)\n",
|
||||
" \n",
|
||||
" if val_loss < best_val_loss:\n",
|
||||
" best_val_loss = val_loss\n",
|
||||
" early_stop_counter = 0\n",
|
||||
" # Lưu best model\n",
|
||||
" torch.save(model.state_dict(), 'model_cnn_pytorch_best.pt')\n",
|
||||
" else:\n",
|
||||
" early_stop_counter += 1\n",
|
||||
" if early_stop_counter >= early_stop_patience:\n",
|
||||
" print(f'\\n⛔ Early stopping at epoch {epoch+1}')\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"print(f'\\n✅ Huấn luyện hoàn thành!')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0868ab12",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load best model\n",
|
||||
"model.load_state_dict(torch.load('model_cnn_pytorch_best.pt'))\n",
|
||||
"\n",
|
||||
"# Evaluate on test set\n",
|
||||
"model.eval()\n",
|
||||
"test_correct = 0\n",
|
||||
"test_total = 0\n",
|
||||
"test_loss = 0\n",
|
||||
"\n",
|
||||
"with torch.no_grad():\n",
|
||||
" for X_batch, y_batch in test_loader:\n",
|
||||
" X_batch = X_batch.to(device)\n",
|
||||
" y_batch = y_batch.to(device)\n",
|
||||
" \n",
|
||||
" outputs = model(X_batch)\n",
|
||||
" loss = criterion(outputs, y_batch)\n",
|
||||
" test_loss += loss.item()\n",
|
||||
" _, predicted = torch.max(outputs.data, 1)\n",
|
||||
" test_correct += (predicted == y_batch).sum().item()\n",
|
||||
" test_total += y_batch.size(0)\n",
|
||||
"\n",
|
||||
"test_loss /= len(test_loader)\n",
|
||||
"test_acc = 100 * test_correct / test_total\n",
|
||||
"\n",
|
||||
"print(f\"📊 Test Results:\")\n",
|
||||
"print(f\" Test Loss: {test_loss:.4f}\")\n",
|
||||
"print(f\" Test Accuracy: {test_acc:.2f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c2067227",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Vẽ đồ thị huấn luyện\n",
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(15, 5))\n",
|
||||
"\n",
|
||||
"# Loss\n",
|
||||
"axes[0].plot(train_losses, label='Train Loss')\n",
|
||||
"axes[0].plot(val_losses, label='Val Loss')\n",
|
||||
"axes[0].set_xlabel('Epoch')\n",
|
||||
"axes[0].set_ylabel('Loss')\n",
|
||||
"axes[0].set_title('Model Loss')\n",
|
||||
"axes[0].legend()\n",
|
||||
"axes[0].grid(True)\n",
|
||||
"\n",
|
||||
"# Accuracy\n",
|
||||
"axes[1].plot(train_accs, label='Train Accuracy')\n",
|
||||
"axes[1].plot(val_accs, label='Val Accuracy')\n",
|
||||
"axes[1].set_xlabel('Epoch')\n",
|
||||
"axes[1].set_ylabel('Accuracy (%)')\n",
|
||||
"axes[1].set_title('Model Accuracy')\n",
|
||||
"axes[1].legend()\n",
|
||||
"axes[1].grid(True)\n",
|
||||
"\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.savefig('training_history.png', dpi=150, bbox_inches='tight')\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"print(\"✅ Đồ thị đã lưu vào 'training_history.png'\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d8402a21",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Lưu Model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c12de183",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Lưu model state dict\n",
|
||||
"print(\"💾 Lưu model...\")\n",
|
||||
"torch.save(model.state_dict(), 'model_cnn_pytorch.pt')\n",
|
||||
"print(f\"✅ Model state dict đã lưu: model_cnn_pytorch.pt\")\n",
|
||||
"\n",
|
||||
"# Lưu thông tin model\n",
|
||||
"model_info = {\n",
|
||||
" 'state_dict': model.state_dict(),\n",
|
||||
" 'num_classes': num_classes,\n",
|
||||
" 'input_size': X_train.shape[1],\n",
|
||||
" 'label_mapping': label_mapping,\n",
|
||||
" 'mean': mean,\n",
|
||||
" 'std': std,\n",
|
||||
" 'test_accuracy': test_acc,\n",
|
||||
" 'test_loss': test_loss\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"torch.save(model_info, 'model_cnn_pytorch_full.pt')\n",
|
||||
"print(f\"✅ Full model info đã lưu: model_cnn_pytorch_full.pt\")\n",
|
||||
"\n",
|
||||
"print(f\"\\n✅ Model ready for prediction!\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d2134b50",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Training CNN Model with PyTorch for Land Use Classification\n",
|
||||
"Huấn luyện mô hình CNN với PyTorch cho phân loại sử dụng đất từ dữ liệu Sentinel-1 và Sentinel-2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5b9ca134",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"%matplotlib inline\n",
|
||||
"\n",
|
||||
"import importlib\n",
|
||||
"import new_import_ODC \n",
|
||||
"\n",
|
||||
"importlib.reload(new_import_ODC)\n",
|
||||
"\n",
|
||||
"from new_import_ODC import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "709c2518",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Kiểm tra GPU availability\n",
|
||||
"print(f\"PyTorch version: {torch.__version__}\")\n",
|
||||
"print(f\"CUDA available: {torch.cuda.is_available()}\")\n",
|
||||
"if torch.cuda.is_available():\n",
|
||||
" print(f\"CUDA device: {torch.cuda.get_device_name(0)}\")\n",
|
||||
" device = 'cuda'\n",
|
||||
"else:\n",
|
||||
" print(\"Using CPU for training\")\n",
|
||||
" device = 'cpu'\n",
|
||||
"\n",
|
||||
"print(f\"\\nDevice sẽ dùng: {device}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "15f073ca",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Cấu hình Daskgateway\n",
|
||||
"cluster, client = notebook_utils.initialize_dask(use_gateway=True, workers=(1, 10))\n",
|
||||
"# Khai báo 1 Datacube là dc\n",
|
||||
"dc = datacube.Datacube()\n",
|
||||
"\n",
|
||||
"# Cấu hình truy cập dịch vụ S3\n",
|
||||
"configure_s3_access(aws_unsigned=False, requester_pays=True, client=client)\n",
|
||||
"\n",
|
||||
"client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "74a229f6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## cấu hình thời gian lấy ảnh và tọa độ\n",
|
||||
"date_range = (\"2022-09-01\", \"2023-10-01\")\n",
|
||||
"longtitude_range = (105.5, 106.4)\n",
|
||||
"latitude_range = (9.2, 10.0)\n",
|
||||
"\n",
|
||||
"coordinates = (longtitude_range, latitude_range)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1ebdade4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## truy vấn ảnh vệ tinh sen2\n",
|
||||
"data = load_data(dc, date_range, longtitude_range, latitude_range)\n",
|
||||
"notebook_utils.heading(notebook_utils.xarray_object_size(data))\n",
|
||||
"display(data)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c444f3cc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Tiến hành loại bỏ các vị trí bị mây ảnh hưởng\n",
|
||||
"result = mask_clean(data)\n",
|
||||
"progress(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f0df6581",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tiến hành tính toán NDVI\n",
|
||||
"ds1 = calculate_indices(result, index=\"NDVI\", satellite_mission=\"s2\")\n",
|
||||
"ndvi = ds1[\"NDVI\"]\n",
|
||||
"display(ndvi)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "430302e3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Hiển thị ảnh NDVI chưa điền các giá trị mây (chưa fill nan)\n",
|
||||
"plt.imshow(ndvi.isel(time=6))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6798b0d2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Thiết lập giá trị trung bình mùa vụ để xử lý các điểm ảnh bị mây dựa vào sự thay đổi theo mùa\n",
|
||||
"time_split = [\n",
|
||||
" slice(\"2022-09-01\", \"2023-01-01\"),\n",
|
||||
" slice(\"2023-01-01\", \"2023-05-01\"),\n",
|
||||
" slice(\"2023-05-01\", \"2023-07-01\"),\n",
|
||||
" slice(\"2023-07-01\", \"2023-10-01\"),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Điền mây ở các vị trí mang giá trị nan (fill nan)\n",
|
||||
"fill_nan_ndvi = fill_nan(ndvi, time_split)\n",
|
||||
"\n",
|
||||
"# In kết quả ảnh NDVI đã điền mây (đã fill nan)\n",
|
||||
"plt.imshow(fill_nan_ndvi.isel(time=6))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0e10d6e6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"## tính ndvi theo tháng\n",
|
||||
"average_ndvi = fill_nan_ndvi.resample(time=\"1M\").mean().persist()\n",
|
||||
"progress(average_ndvi)\n",
|
||||
"\n",
|
||||
"# compute average_ndvi\n",
|
||||
"average_ndvi = average_ndvi.compute()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7b3b7086",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#Load dữ liệu ảnh Sentinel 1\n",
|
||||
"dsvh, dsvv = load_data_sen1(dc, date_range, coordinates)\n",
|
||||
"average_vv = calculate_average(dsvv, time_pattern='1M')\n",
|
||||
"average_vh = calculate_average(dsvh, time_pattern='1M')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6d3f9ab1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## cấu hình bộ dữ liệu điểm huấn luyện mô hình (train file)\n",
|
||||
"train_path = \"train/ST_training data_updated_1130points_new.shp\" # đường dẫn shp file train\n",
|
||||
"\n",
|
||||
"## load dữ liệu điểm huấn luyện mô hình (train file)\n",
|
||||
"train = load_train_data(train_path)\n",
|
||||
"train.head()\n",
|
||||
"\n",
|
||||
"# cấu hình nhãn dữ liệu \n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": \"0\",\n",
|
||||
" \"Lua\": \"1\",\n",
|
||||
" \"CHN\": \"2\",\n",
|
||||
" \"CLN\": \"3\",\n",
|
||||
" \"TS\": \"4\",\n",
|
||||
" \"Song\": \"5\",\n",
|
||||
" \"Dat xay dung\": \"6\",\n",
|
||||
" \"Rung\": \"7\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# xây dựng tập dữ liệu (dataset) chứa dữ liệu VH, VV, NDVI\n",
|
||||
"datasets = get_data_sen1_and_sen2(train, average_ndvi, average_vh, average_vv)\n",
|
||||
"\n",
|
||||
"# chia tập dữ liệu thành các phần theo tỉ lệ 80(80-20)-20 tương ứng với tập train, validate, test\n",
|
||||
"X_train, X_val, X_test, y_train, y_val, y_test = split_train_data(\n",
|
||||
" train, label_mapping, datasets\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c0188e1b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Huấn luyện mô hình CNN với PyTorch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ba38ce6a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Huấn luyện mô hình CNN với PyTorch\n",
|
||||
"print(\"🔷 Bắt đầu huấn luyện CNN model với PyTorch...\\n\")\n",
|
||||
"\n",
|
||||
"cnn_model, history, scaler = train_cnn_pytorch(\n",
|
||||
" X_train, X_val, X_test, \n",
|
||||
" y_train, y_val, y_test,\n",
|
||||
" num_classes=8,\n",
|
||||
" epochs=100,\n",
|
||||
" batch_size=32,\n",
|
||||
" learning_rate=1e-3,\n",
|
||||
" device=device,\n",
|
||||
" verbose=True\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fd19df06",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Vẽ đồ thị huấn luyện\n",
|
||||
"plot_pytorch_training_history(history)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e16d8c20",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Lưu mô hình CNN PyTorch\n",
|
||||
"save_pytorch_model(cnn_model, scaler, model_name=\"model_cnn_pytorch.pth\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "adb17862",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Hiển thị model architecture\n",
|
||||
"print(\"\\n📐 Model Architecture:\")\n",
|
||||
"print(cnn_model)\n",
|
||||
"\n",
|
||||
"# Đếm số parameters\n",
|
||||
"total_params = sum(p.numel() for p in cnn_model.parameters())\n",
|
||||
"trainable_params = sum(p.numel() for p in cnn_model.parameters() if p.requires_grad)\n",
|
||||
"print(f\"\\n📊 Model Parameters:\")\n",
|
||||
"print(f\" Total parameters: {total_params:,}\")\n",
|
||||
"print(f\" Trainable parameters: {trainable_params:,}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b4963d6f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# đóng client, cluster\n",
|
||||
"client.close()\n",
|
||||
"cluster.close()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "ac069784-fbb6-48c8-a547-11b96cade97b",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"jupyter": {
|
||||
"outputs_hidden": true,
|
||||
"source_hidden": true
|
||||
},
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/tmp/ipykernel_218/1243805045.py:22: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n",
|
||||
" df = pd.read_sql(sql, conn)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" product_name total_images\n",
|
||||
"0 s2_l2a 2074896\n",
|
||||
"1 sentinel_2_c1_l2a 1137446\n",
|
||||
"2 landsat7_c2l2_sr 169065\n",
|
||||
"3 landsat7_c2l2_st 168410\n",
|
||||
"4 landsat8_c2l2_sr 122846\n",
|
||||
"5 landsat8_c2l2_st 120778\n",
|
||||
"6 landsat5_c2l2_sr 118583\n",
|
||||
"7 landsat5_c2l2_st 118406\n",
|
||||
"8 landsat8_c2l1 111513\n",
|
||||
"9 nasa_aqua_l2_oc 37232\n",
|
||||
"10 landsat9_c2l2_sr 30214\n",
|
||||
"11 landsat9_c2l2_st 29709\n",
|
||||
"12 landsat9_c2l1 18875\n",
|
||||
"13 nasa_aqua_l2_sst 12070\n",
|
||||
"14 ga_ls_mangrove_cover_cyear_3 5580\n",
|
||||
"15 sentinel1_grd_gamma0_10m_unsmooth 5488\n",
|
||||
"16 sentinel1_grd_gamma0_20m 4260\n",
|
||||
"17 copernicus_dem_30 1334\n",
|
||||
"18 global_mangrove_soc_2020_30m 784\n",
|
||||
"19 global_mangrove_soc_2000_30m 781\n",
|
||||
"20 global_mangrove_canopy_height_2015_12m 761\n",
|
||||
"21 sentinel1_grd_gamma0_10m 291\n",
|
||||
"22 lpdaac_nasadem 264\n",
|
||||
"23 cci_biomass_annual_v51 248\n",
|
||||
"24 esa_worldcover_2020 184\n",
|
||||
"25 esa_worldcover_2021 184\n",
|
||||
"26 global_tidal_marsh_soc_30m 41\n",
|
||||
"27 global_tidal_marsh_distribution_2020_10m 35\n",
|
||||
"28 copernicus_dem_fiji 26\n",
|
||||
"29 lpdaac_mod11a1v061_lste 2\n",
|
||||
"30 global_mangrove_soc_2000_100m 1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import psycopg2\n",
|
||||
"import os\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"# Kết nối (như cũ)\n",
|
||||
"conn = psycopg2.connect(\n",
|
||||
" host=os.environ.get('DB_HOSTNAME'),\n",
|
||||
" user=os.environ.get('DB_USERNAME'),\n",
|
||||
" password=os.environ.get('DB_PASSWORD'),\n",
|
||||
" dbname=os.environ.get('DB_DATABASE')\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Đếm số lượng ảnh theo từng loại sản phẩm\n",
|
||||
"sql = \"\"\"\n",
|
||||
"SELECT t.name as product_name, count(*) as total_images\n",
|
||||
"FROM agdc.dataset d\n",
|
||||
"JOIN agdc.dataset_type t ON d.dataset_type_ref = t.id\n",
|
||||
"GROUP BY t.name\n",
|
||||
"ORDER BY total_images DESC;\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"df = pd.read_sql(sql, conn)\n",
|
||||
"print(df)\n",
|
||||
"conn.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a0ae4051-3bfd-49fd-83fe-4c31c74338e2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import psycopg2\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# 1. Lấy thông tin kết nối\n",
|
||||
"db_host = os.environ.get('DB_HOSTNAME')\n",
|
||||
"db_user = os.environ.get('DB_USERNAME')\n",
|
||||
"db_pass = os.environ.get('DB_PASSWORD')\n",
|
||||
"db_name = os.environ.get('DB_DATABASE')\n",
|
||||
"\n",
|
||||
"# 2. Danh sách các bảng cần lấy\n",
|
||||
"tables = [\n",
|
||||
" 'agdc.metadata_type',\n",
|
||||
" 'agdc.dataset_type',\n",
|
||||
" 'agdc.dataset_location',\n",
|
||||
" 'agdc.dataset'\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"print(\"Đang kết nối trực tiếp tới PostgreSQL...\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Kết nối trực tiếp (Bỏ qua Pandas/SQLAlchemy)\n",
|
||||
" conn = psycopg2.connect(\n",
|
||||
" host=db_host,\n",
|
||||
" user=db_user,\n",
|
||||
" password=db_pass,\n",
|
||||
" dbname=db_name\n",
|
||||
" )\n",
|
||||
" cur = conn.cursor()\n",
|
||||
" print(\"Kết nối thành công!\\n\")\n",
|
||||
"\n",
|
||||
" for table_name in tables:\n",
|
||||
" print(f\"--> Đang xuất bảng: {table_name}\")\n",
|
||||
" \n",
|
||||
" # Tên file CSV đầu ra\n",
|
||||
" file_name = table_name.split('.')[1] + \".csv\"\n",
|
||||
" \n",
|
||||
" # Sử dụng lệnh COPY chuyên dụng của Postgres (Cực nhanh và chuẩn)\n",
|
||||
" # SQL: COPY (SELECT * FROM table) TO STDOUT WITH CSV HEADER\n",
|
||||
" sql = f\"COPY (SELECT * FROM {table_name}) TO STDOUT WITH CSV HEADER\"\n",
|
||||
" \n",
|
||||
" with open(file_name, 'w') as f:\n",
|
||||
" cur.copy_expert(sql, f)\n",
|
||||
" \n",
|
||||
" print(f\" Đã lưu xong: {file_name}\")\n",
|
||||
"\n",
|
||||
" cur.close()\n",
|
||||
" conn.close()\n",
|
||||
" print(\"\\nHOÀN TẤT! Bạn hãy tải 4 file CSV về máy.\")\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"\\nCÓ LỖI XẢY RA: {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d139879e-c350-4986-a2e6-0d59099eb770",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"jupyter": {
|
||||
"outputs_hidden": true,
|
||||
"source_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Đang kết nối...\n",
|
||||
"Kết nối thành công! Đang ước lượng nhanh...\n",
|
||||
"\n",
|
||||
"--- BẢNG DỰ TÍNH DUNG LƯỢNG (ƯỚC LƯỢNG) ---\n",
|
||||
"NĂM | SỐ ẢNH (ƯỚC TÍNH) | SIZE (CSV) \n",
|
||||
"------------------------------------------------------------\n",
|
||||
"2020 | ~ 21,448 | ~ 83.78 MB\n",
|
||||
"2021 | ~ 21,448 | ~ 83.78 MB\n",
|
||||
"2022 | ~ 21,448 | ~ 83.78 MB\n",
|
||||
"2023 | ~ 21,448 | ~ 83.78 MB\n",
|
||||
"2024 | ~ 21,448 | ~ 83.78 MB\n",
|
||||
"------------------------------------------------------------\n",
|
||||
"TỔNG CỘNG : ~ 107,240 ảnh (Khoảng 418.91 MB)\n",
|
||||
"------------------------------------------------------------\n",
|
||||
"(Lưu ý: Số liệu này là ước tính của Database, độ chính xác khoảng 80-90%)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdin",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"Bạn có muốn bắt đầu tải không? (y/n): y\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
">>> Đang tải bảng định nghĩa...\n",
|
||||
"\n",
|
||||
">>> Đang tải dữ liệu chính...\n",
|
||||
"--> Năm 2020...\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import psycopg2\n",
|
||||
"import os\n",
|
||||
"import re # Thư viện xử lý chuỗi để lấy số liệu\n",
|
||||
"\n",
|
||||
"# --- CẤU HÌNH ---\n",
|
||||
"YEARS = [2020, 2021, 2022, 2023, 2024]\n",
|
||||
"AVG_ROW_SIZE_KB = 4 \n",
|
||||
"\n",
|
||||
"db_host = os.environ.get('DB_HOSTNAME')\n",
|
||||
"db_user = os.environ.get('DB_USERNAME')\n",
|
||||
"db_pass = os.environ.get('DB_PASSWORD')\n",
|
||||
"db_name = os.environ.get('DB_DATABASE')\n",
|
||||
"\n",
|
||||
"print(\"Đang kết nối...\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" conn = psycopg2.connect(\n",
|
||||
" host=db_host, user=db_user, password=db_pass, dbname=db_name\n",
|
||||
" )\n",
|
||||
" cur = conn.cursor()\n",
|
||||
" print(\"Kết nối thành công! Đang ước lượng nhanh...\\n\")\n",
|
||||
"\n",
|
||||
" # ==========================================\n",
|
||||
" # BƯỚC 1: ƯỚC LƯỢNG SIÊU TỐC (INSTANT ESTIMATE)\n",
|
||||
" # ==========================================\n",
|
||||
" print(\"--- BẢNG DỰ TÍNH DUNG LƯỢNG (ƯỚC LƯỢNG) ---\")\n",
|
||||
" print(f\"{'NĂM':<10} | {'SỐ ẢNH (ƯỚC TÍNH)':<20} | {'SIZE (CSV)':<20}\")\n",
|
||||
" print(\"-\" * 60)\n",
|
||||
"\n",
|
||||
" total_est_rows = 0\n",
|
||||
"\n",
|
||||
" for year in YEARS:\n",
|
||||
" # Mẹo: Dùng EXPLAIN để lấy số liệu ước tính từ Query Planner\n",
|
||||
" # Nó sẽ trả về chuỗi kiểu: \"Seq Scan on dataset ... (rows=12345 ...)\"\n",
|
||||
" sql_estimate = f\"\"\"\n",
|
||||
" EXPLAIN SELECT 1 FROM agdc.dataset\n",
|
||||
" WHERE (metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01'\n",
|
||||
" AND (metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
|
||||
" \"\"\"\n",
|
||||
" cur.execute(sql_estimate)\n",
|
||||
" explain_result = cur.fetchone()[0] # Lấy dòng đầu tiên của kết quả EXPLAIN\n",
|
||||
" \n",
|
||||
" # Dùng Regex để bắt lấy con số sau chữ \"rows=\"\n",
|
||||
" match = re.search(r\"rows=(\\d+)\", explain_result)\n",
|
||||
" if match:\n",
|
||||
" count = int(match.group(1))\n",
|
||||
" else:\n",
|
||||
" count = 0 # Không bắt được số\n",
|
||||
" \n",
|
||||
" total_est_rows += count\n",
|
||||
" est_size_mb = (count * AVG_ROW_SIZE_KB) / 1024\n",
|
||||
" \n",
|
||||
" print(f\"{year:<10} | ~ {count:<18,} | ~ {est_size_mb:.2f} MB\")\n",
|
||||
"\n",
|
||||
" print(\"-\" * 60)\n",
|
||||
" print(f\"TỔNG CỘNG : ~ {total_est_rows:,} ảnh (Khoảng {(total_est_rows * AVG_ROW_SIZE_KB)/1024:.2f} MB)\")\n",
|
||||
" print(\"-\" * 60)\n",
|
||||
" print(\"(Lưu ý: Số liệu này là ước tính của Database, độ chính xác khoảng 80-90%)\")\n",
|
||||
"\n",
|
||||
" # ==========================================\n",
|
||||
" # QUYẾT ĐỊNH TẢI\n",
|
||||
" # ==========================================\n",
|
||||
" check = input(\"\\nBạn có muốn bắt đầu tải không? (y/n): \")\n",
|
||||
" if check.lower() != 'y':\n",
|
||||
" print(\"Đã hủy.\")\n",
|
||||
" exit()\n",
|
||||
"\n",
|
||||
" # ==========================================\n",
|
||||
" # BƯỚC 2 & 3: TẢI DỮ LIỆU (Giữ nguyên logic cũ)\n",
|
||||
" # ==========================================\n",
|
||||
" # ... (Phần code tải small_tables và tải dữ liệu chính giữ nguyên như cũ) ...\n",
|
||||
" # Để code gọn, mình viết tiếp phần tải ở dưới đây:\n",
|
||||
" \n",
|
||||
" # 2. Tải bảng nhỏ\n",
|
||||
" print(\"\\n>>> Đang tải bảng định nghĩa...\")\n",
|
||||
" for tb in ['agdc.metadata_type', 'agdc.dataset_type']:\n",
|
||||
" f_name = tb.split('.')[1] + \".csv\"\n",
|
||||
" with open(f_name, 'w') as f:\n",
|
||||
" cur.copy_expert(f\"COPY (SELECT * FROM {tb}) TO STDOUT WITH CSV HEADER\", f)\n",
|
||||
" \n",
|
||||
" # 3. Tải dữ liệu chính\n",
|
||||
" print(\"\\n>>> Đang tải dữ liệu chính...\")\n",
|
||||
" for year in YEARS:\n",
|
||||
" print(f\"--> Năm {year}...\")\n",
|
||||
" \n",
|
||||
" # Dataset\n",
|
||||
" f_ds = f\"dataset_{year}.csv\"\n",
|
||||
" sql_ds = f\"\"\"\n",
|
||||
" COPY (SELECT * FROM agdc.dataset \n",
|
||||
" WHERE (metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01' \n",
|
||||
" AND (metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
|
||||
" ) TO STDOUT WITH CSV HEADER\"\"\"\n",
|
||||
" with open(f_ds, 'w') as f: cur.copy_expert(sql_ds, f)\n",
|
||||
" \n",
|
||||
" # Location\n",
|
||||
" f_loc = f\"dataset_location_{year}.csv\"\n",
|
||||
" sql_loc = f\"\"\"\n",
|
||||
" COPY (SELECT l.* FROM agdc.dataset_location l JOIN agdc.dataset d ON l.dataset_ref = d.id\n",
|
||||
" WHERE (d.metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01' \n",
|
||||
" AND (d.metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
|
||||
" ) TO STDOUT WITH CSV HEADER\"\"\"\n",
|
||||
" with open(f_loc, 'w') as f: cur.copy_expert(sql_loc, f)\n",
|
||||
" \n",
|
||||
" print(\"\\nHOÀN TẤT TOÀN BỘ!\")\n",
|
||||
" cur.close()\n",
|
||||
" conn.close()\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"\\nCÓ LỖI: {e}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"cells": [],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user