del uneccessary file
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,768 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "17da4353",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"✅ Import thành công\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Import libraries\n",
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import xarray as xr\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# Element84 Earth Search STAC\n",
|
||||
"import pystac_client\n",
|
||||
"from odc.stac import load\n",
|
||||
"\n",
|
||||
"# Machine Learning\n",
|
||||
"import torch\n",
|
||||
"import torch.nn as nn\n",
|
||||
"import torch.optim as optim\n",
|
||||
"from torch.utils.data import TensorDataset, DataLoader\n",
|
||||
"from sklearn.metrics import classification_report, confusion_matrix, accuracy_score\n",
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"\n",
|
||||
"print(\"✅ Import thành công\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "9c063be3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"✅ Kết nối Element84 Earth Search thành công\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Kết nối Element84 Earth Search (AWS-hosted STAC API)\n",
|
||||
"catalog = pystac_client.Client.open(\n",
|
||||
" \"https://earth-search.aws.element84.com/v1\"\n",
|
||||
")\n",
|
||||
"print(\"✅ Kết nối Element84 Earth Search thành công\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "d87beed2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"✅ Đã đọc shapefile: 1130 points\n",
|
||||
" Columns: ['No', 'X', 'Y', 'LU2022', 'Hientrang', 'HT_code', 'geometry']\n",
|
||||
" CRS: EPSG:32648\n",
|
||||
"⚠️ Không tìm thấy column class, hiển thị 5 dòng đầu:\n",
|
||||
" No X Y LU2022 Hientrang HT_code \\\n",
|
||||
"0 1.0 603860.819 1081162.862 Pomelo CLN 3 \n",
|
||||
"1 2.0 601306.410 1082782.940 Pomelo CLN 3 \n",
|
||||
"2 3.0 601084.510 1081351.870 Pomelo CLN 3 \n",
|
||||
"3 4.0 602193.760 1079205.220 Pomelo CLN 3 \n",
|
||||
"4 5.0 602459.000 1080946.000 Pomelo CLN 3 \n",
|
||||
"\n",
|
||||
" geometry longitude latitude \n",
|
||||
"0 POINT (603860.819 1081162.862) 603860.819 1081162.862 \n",
|
||||
"1 POINT (601306.41 1082782.94) 601306.410 1082782.940 \n",
|
||||
"2 POINT (601084.51 1081351.87) 601084.510 1081351.870 \n",
|
||||
"3 POINT (602193.76 1079205.22) 602193.760 1079205.220 \n",
|
||||
"4 POINT (602459 1080946) 602459.000 1080946.000 \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Tạo file CSV training data từ shapefile\n",
|
||||
"import geopandas as gpd\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"# Đọc shapefile training data\n",
|
||||
"shapefile_path = \"/home/jovyan/remote-sensing/train/ST_training_data_updated_1130points_new.shp\"\n",
|
||||
"gdf = gpd.read_file(shapefile_path)\n",
|
||||
"\n",
|
||||
"print(f\"✅ Đã đọc shapefile: {len(gdf)} points\")\n",
|
||||
"print(f\" Columns: {list(gdf.columns)}\")\n",
|
||||
"print(f\" CRS: {gdf.crs}\")\n",
|
||||
"\n",
|
||||
"# Extract longitude, latitude từ geometry\n",
|
||||
"gdf['longitude'] = gdf.geometry.x\n",
|
||||
"gdf['latitude'] = gdf.geometry.y\n",
|
||||
"\n",
|
||||
"# Tìm column chứa class name (có thể là 'LULC', 'class', 'label', etc.)\n",
|
||||
"class_column = None\n",
|
||||
"for col in gdf.columns:\n",
|
||||
" if col.lower() in ['lulc', 'class', 'label', 'class_name', 'type', 'landuse']:\n",
|
||||
" class_column = col\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"if class_column is None:\n",
|
||||
" print(\"⚠️ Không tìm thấy column class, hiển thị 5 dòng đầu:\")\n",
|
||||
" print(gdf.head())\n",
|
||||
"else:\n",
|
||||
" # Tạo DataFrame với các cột cần thiết\n",
|
||||
" train_df = pd.DataFrame({\n",
|
||||
" 'longitude': gdf['longitude'],\n",
|
||||
" 'latitude': gdf['latitude'],\n",
|
||||
" 'class_name': gdf[class_column]\n",
|
||||
" })\n",
|
||||
" \n",
|
||||
" # Export ra CSV\n",
|
||||
" csv_path = \"/media/x79/2A7D-FAA0/remote-sensing/train_data.csv\"\n",
|
||||
" train_df.to_csv(csv_path, index=False)\n",
|
||||
" \n",
|
||||
" print(f\"\\n✅ Đã tạo file CSV: {csv_path}\")\n",
|
||||
" print(f\" Số lượng points: {len(train_df)}\")\n",
|
||||
" print(f\" Classes: {train_df['class_name'].unique()}\")\n",
|
||||
" print(f\" Class distribution:\")\n",
|
||||
" print(train_df['class_name'].value_counts())\n",
|
||||
" print(f\"\\n📋 Preview 5 dòng đầu:\")\n",
|
||||
" print(train_df.head())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "83784d01",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Tìm thấy 45 scenes Sentinel-2\n",
|
||||
"✅ Sentinel-2 raw: FrozenMappingWarningOnValuesAccess({'y': 8874, 'x': 9902, 'time': 28})\n",
|
||||
" Variables: ['red', 'green', 'blue', 'nir', 'swir16', 'swir22', 'scl']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Cấu hình vùng và thời gian\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",
|
||||
"bbox = (longtitude_range[0], latitude_range[0], longtitude_range[1], latitude_range[1])\n",
|
||||
"\n",
|
||||
"# Tìm kiếm Sentinel-2 L2A\n",
|
||||
"search = catalog.search(\n",
|
||||
" collections=[\"sentinel-2-l2a\"],\n",
|
||||
" bbox=bbox,\n",
|
||||
" datetime=f\"{date_range[0]}/{date_range[1]}\",\n",
|
||||
" query={\"eo:cloud_cover\": {\"lt\": 30}}\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"items = search.item_collection()\n",
|
||||
"print(f\" Tìm thấy {len(items)} scenes Sentinel-2\")\n",
|
||||
"\n",
|
||||
"if len(items) == 0:\n",
|
||||
" raise ValueError(\"Không tìm thấy dữ liệu Sentinel-2 cho vùng và thời gian này\")\n",
|
||||
"\n",
|
||||
"# Load data với odc-stac\n",
|
||||
"data_sen2 = load(\n",
|
||||
" items,\n",
|
||||
" bands=[\"red\", \"green\", \"blue\", \"nir\", \"swir16\", \"swir22\", \"scl\"],\n",
|
||||
" bbox=bbox,\n",
|
||||
" resolution=10,\n",
|
||||
" chunks={\"time\": 1, \"x\": 2048, \"y\": 2048},\n",
|
||||
" groupby=\"solar_day\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"✅ Sentinel-2 raw: {data_sen2.dims}\")\n",
|
||||
"print(f\" Variables: {list(data_sen2.data_vars)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c3faed92",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ValueError",
|
||||
"evalue": "dimension time on 0th function argument to apply_ufunc with dask='parallelized' consists of multiple chunks, but is also a core dimension. To fix, either rechunk into a single array chunk along this dimension, i.e., ``.chunk(dict(time=-1))``, or pass ``allow_rechunk=True`` in ``dask_gufunc_kwargs`` but beware that this may significantly increase memory usage.",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[6], line 33\u001b[0m\n\u001b[1;32m 31\u001b[0m data_clean \u001b[38;5;241m=\u001b[39m mask_clean(data_sen2)\n\u001b[1;32m 32\u001b[0m data_ndvi \u001b[38;5;241m=\u001b[39m calculate_indices(data_clean, index\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNDVI\u001b[39m\u001b[38;5;124m\"\u001b[39m, satellite_mission\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ms2\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m---> 33\u001b[0m data_fill \u001b[38;5;241m=\u001b[39m \u001b[43mfill_nan\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata_ndvi\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 34\u001b[0m data_sen2_monthly \u001b[38;5;241m=\u001b[39m data_fill\u001b[38;5;241m.\u001b[39mresample(time\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m1MS\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;241m.\u001b[39mmean()\u001b[38;5;241m.\u001b[39mcompute()\n\u001b[1;32m 36\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m✅ S2 monthly shape: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdata_sen2_monthly\u001b[38;5;241m.\u001b[39mdims\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
|
||||
"Cell \u001b[0;32mIn[6], line 28\u001b[0m, in \u001b[0;36mfill_nan\u001b[0;34m(ds)\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfill_nan\u001b[39m(ds):\n\u001b[1;32m 27\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Fill NaN bằng interpolation theo thời gian\"\"\"\u001b[39;00m\n\u001b[0;32m---> 28\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mds\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minterpolate_na\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtime\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mlinear\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfill_value\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mextrapolate\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/dataset.py:6773\u001b[0m, in \u001b[0;36mDataset.interpolate_na\u001b[0;34m(self, dim, method, limit, use_coordinate, max_gap, **kwargs)\u001b[0m\n\u001b[1;32m 6655\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Fill in NaNs by interpolating according to different methods.\u001b[39;00m\n\u001b[1;32m 6656\u001b[0m \n\u001b[1;32m 6657\u001b[0m \u001b[38;5;124;03mParameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 6769\u001b[0m \u001b[38;5;124;03m D (x) float64 40B 5.0 3.0 1.0 -1.0 4.0\u001b[39;00m\n\u001b[1;32m 6770\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 6771\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mxarray\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcore\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmissing\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _apply_over_vars_with_dim, interp_na\n\u001b[0;32m-> 6773\u001b[0m new \u001b[38;5;241m=\u001b[39m \u001b[43m_apply_over_vars_with_dim\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 6774\u001b[0m \u001b[43m \u001b[49m\u001b[43minterp_na\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6775\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6776\u001b[0m \u001b[43m \u001b[49m\u001b[43mdim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6777\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6778\u001b[0m \u001b[43m \u001b[49m\u001b[43mlimit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlimit\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6779\u001b[0m \u001b[43m \u001b[49m\u001b[43muse_coordinate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43muse_coordinate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6780\u001b[0m \u001b[43m \u001b[49m\u001b[43mmax_gap\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_gap\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6781\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 6782\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 6783\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m new\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/missing.py:222\u001b[0m, in \u001b[0;36m_apply_over_vars_with_dim\u001b[0;34m(func, self, dim, **kwargs)\u001b[0m\n\u001b[1;32m 220\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, var \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdata_vars\u001b[38;5;241m.\u001b[39mitems():\n\u001b[1;32m 221\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m dim \u001b[38;5;129;01min\u001b[39;00m var\u001b[38;5;241m.\u001b[39mdims:\n\u001b[0;32m--> 222\u001b[0m ds[name] \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvar\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdim\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 224\u001b[0m ds[name] \u001b[38;5;241m=\u001b[39m var\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/missing.py:367\u001b[0m, in \u001b[0;36minterp_na\u001b[0;34m(self, dim, use_coordinate, method, limit, max_gap, keep_attrs, **kwargs)\u001b[0m\n\u001b[1;32m 365\u001b[0m warnings\u001b[38;5;241m.\u001b[39mfilterwarnings(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moverflow\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;167;01mRuntimeWarning\u001b[39;00m)\n\u001b[1;32m 366\u001b[0m warnings\u001b[38;5;241m.\u001b[39mfilterwarnings(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minvalid value\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;167;01mRuntimeWarning\u001b[39;00m)\n\u001b[0;32m--> 367\u001b[0m arr \u001b[38;5;241m=\u001b[39m \u001b[43mapply_ufunc\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 368\u001b[0m \u001b[43m \u001b[49m\u001b[43minterpolator\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 369\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 370\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 371\u001b[0m \u001b[43m \u001b[49m\u001b[43minput_core_dims\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43m[\u001b[49m\u001b[43mdim\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mdim\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 372\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput_core_dims\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43m[\u001b[49m\u001b[43mdim\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 373\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput_dtypes\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 374\u001b[0m \u001b[43m \u001b[49m\u001b[43mdask\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mparallelized\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 375\u001b[0m \u001b[43m \u001b[49m\u001b[43mvectorize\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 376\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeep_attrs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeep_attrs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 377\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mtranspose(\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdims)\n\u001b[1;32m 379\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m limit \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 380\u001b[0m arr \u001b[38;5;241m=\u001b[39m arr\u001b[38;5;241m.\u001b[39mwhere(valids)\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/computation.py:1265\u001b[0m, in \u001b[0;36mapply_ufunc\u001b[0;34m(func, input_core_dims, output_core_dims, exclude_dims, vectorize, join, dataset_join, dataset_fill_value, keep_attrs, kwargs, dask, output_dtypes, output_sizes, meta, dask_gufunc_kwargs, on_missing_core_dim, *args)\u001b[0m\n\u001b[1;32m 1263\u001b[0m \u001b[38;5;66;03m# feed DataArray apply_variable_ufunc through apply_dataarray_vfunc\u001b[39;00m\n\u001b[1;32m 1264\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(a, DataArray) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args):\n\u001b[0;32m-> 1265\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mapply_dataarray_vfunc\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1266\u001b[0m \u001b[43m \u001b[49m\u001b[43mvariables_vfunc\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1267\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1268\u001b[0m \u001b[43m \u001b[49m\u001b[43msignature\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msignature\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1269\u001b[0m \u001b[43m \u001b[49m\u001b[43mjoin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjoin\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1270\u001b[0m \u001b[43m \u001b[49m\u001b[43mexclude_dims\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexclude_dims\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1271\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeep_attrs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeep_attrs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1272\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1273\u001b[0m \u001b[38;5;66;03m# feed Variables directly through apply_variable_ufunc\u001b[39;00m\n\u001b[1;32m 1274\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(a, Variable) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args):\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/computation.py:307\u001b[0m, in \u001b[0;36mapply_dataarray_vfunc\u001b[0;34m(func, signature, join, exclude_dims, keep_attrs, *args)\u001b[0m\n\u001b[1;32m 302\u001b[0m result_coords, result_indexes \u001b[38;5;241m=\u001b[39m build_output_coords_and_indexes(\n\u001b[1;32m 303\u001b[0m args, signature, exclude_dims, combine_attrs\u001b[38;5;241m=\u001b[39mkeep_attrs\n\u001b[1;32m 304\u001b[0m )\n\u001b[1;32m 306\u001b[0m data_vars \u001b[38;5;241m=\u001b[39m [\u001b[38;5;28mgetattr\u001b[39m(a, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mvariable\u001b[39m\u001b[38;5;124m\"\u001b[39m, a) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m args]\n\u001b[0;32m--> 307\u001b[0m result_var \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mdata_vars\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 309\u001b[0m out: \u001b[38;5;28mtuple\u001b[39m[DataArray, \u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m] \u001b[38;5;241m|\u001b[39m DataArray\n\u001b[1;32m 310\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m signature\u001b[38;5;241m.\u001b[39mnum_outputs \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n",
|
||||
"File \u001b[0;32m/env/lib/python3.12/site-packages/xarray/core/computation.py:764\u001b[0m, in \u001b[0;36mapply_variable_ufunc\u001b[0;34m(func, signature, exclude_dims, dask, output_dtypes, vectorize, keep_attrs, dask_gufunc_kwargs, *args)\u001b[0m\n\u001b[1;32m 762\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m axis, dim \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(core_dims, start\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m-\u001b[39m\u001b[38;5;28mlen\u001b[39m(core_dims)):\n\u001b[1;32m 763\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(data\u001b[38;5;241m.\u001b[39mchunks[axis]) \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m--> 764\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 765\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdimension \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdim\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mn\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124mth function argument to \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 766\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mapply_ufunc with dask=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mparallelized\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m consists of \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 767\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmultiple chunks, but is also a core dimension. To \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 768\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfix, either rechunk into a single array chunk along \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 769\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mthis dimension, i.e., ``.chunk(dict(\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdim\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m=-1))``, or \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 770\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpass ``allow_rechunk=True`` in ``dask_gufunc_kwargs`` \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 771\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbut beware that this may significantly increase memory usage.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 772\u001b[0m )\n\u001b[1;32m 773\u001b[0m dask_gufunc_kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mallow_rechunk\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 775\u001b[0m output_sizes \u001b[38;5;241m=\u001b[39m dask_gufunc_kwargs\u001b[38;5;241m.\u001b[39mpop(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moutput_sizes\u001b[39m\u001b[38;5;124m\"\u001b[39m, {})\n",
|
||||
"\u001b[0;31mValueError\u001b[0m: dimension time on 0th function argument to apply_ufunc with dask='parallelized' consists of multiple chunks, but is also a core dimension. To fix, either rechunk into a single array chunk along this dimension, i.e., ``.chunk(dict(time=-1))``, or pass ``allow_rechunk=True`` in ``dask_gufunc_kwargs`` but beware that this may significantly increase memory usage."
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Tiền xử lý Sentinel-2: cloud mask + NDVI + resampling\n",
|
||||
"\n",
|
||||
"def mask_clean(ds):\n",
|
||||
" \"\"\"Cloud masking sử dụng SCL band (Scene Classification Layer)\"\"\"\n",
|
||||
" if \"scl\" not in ds:\n",
|
||||
" print(\"⚠️ Không có SCL band, bỏ qua cloud masking\")\n",
|
||||
" return ds\n",
|
||||
" \n",
|
||||
" cloud_mask = (\n",
|
||||
" (ds[\"scl\"] == 3) | # cloud shadow\n",
|
||||
" (ds[\"scl\"] == 8) | # cloud medium probability\n",
|
||||
" (ds[\"scl\"] == 9) | # cloud high probability\n",
|
||||
" (ds[\"scl\"] == 10) # thin cirrus\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" ds_masked = ds.where(~cloud_mask)\n",
|
||||
" return ds_masked.drop_vars(\"scl\", errors=\"ignore\")\n",
|
||||
"\n",
|
||||
"def calculate_indices(ds, index=\"NDVI\", satellite_mission=\"s2\"):\n",
|
||||
" \"\"\"Tính chỉ số NDVI\"\"\"\n",
|
||||
" if index == \"NDVI\":\n",
|
||||
" ndvi = (ds[\"nir\"] - ds[\"red\"]) / (ds[\"nir\"] + ds[\"red\"] + 1e-8)\n",
|
||||
" ds[\"NDVI\"] = ndvi\n",
|
||||
" return ds\n",
|
||||
"\n",
|
||||
"def fill_nan(ds):\n",
|
||||
" \"\"\"Fill NaN bằng interpolation theo thời gian\"\"\"\n",
|
||||
" # Rechunk time dimension thành 1 chunk để tránh lỗi với interpolate_na\n",
|
||||
" ds_rechunked = ds.chunk({\"time\": -1})\n",
|
||||
" return ds_rechunked.interpolate_na(dim=\"time\", method=\"linear\", fill_value=\"extrapolate\")\n",
|
||||
"\n",
|
||||
"# Áp dụng tiền xử lý\n",
|
||||
"data_clean = mask_clean(data_sen2)\n",
|
||||
"data_ndvi = calculate_indices(data_clean, index=\"NDVI\", satellite_mission=\"s2\")\n",
|
||||
"data_fill = fill_nan(data_ndvi)\n",
|
||||
"data_sen2_monthly = data_fill.resample(time=\"1MS\").mean().compute()\n",
|
||||
"\n",
|
||||
"print(f\"✅ S2 monthly shape: {data_sen2_monthly.dims}\")\n",
|
||||
"print(f\" Variables: {list(data_sen2_monthly.data_vars)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "569bfebb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tải Sentinel-1 (SAR VV/VH) từ Element84\n",
|
||||
"\n",
|
||||
"search_s1 = catalog.search(\n",
|
||||
" collections=[\"sentinel-1-grd\"],\n",
|
||||
" bbox=bbox,\n",
|
||||
" datetime=f\"{date_range[0]}/{date_range[1]}\",\n",
|
||||
" query={\n",
|
||||
" \"sat:orbit_state\": {\"eq\": \"descending\"},\n",
|
||||
" \"sar:product_type\": {\"eq\": \"GRD\"}\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"items_s1 = search_s1.item_collection()\n",
|
||||
"print(f\" Tìm thấy {len(items_s1)} scenes Sentinel-1\")\n",
|
||||
"\n",
|
||||
"if len(items_s1) == 0:\n",
|
||||
" print(\"⚠️ Không tìm thấy Sentinel-1, tạo dummy data\")\n",
|
||||
" # Tạo dummy data với cùng kích thước như S2\n",
|
||||
" data_sen1_monthly = xr.Dataset({\n",
|
||||
" \"VV\": xr.DataArray(\n",
|
||||
" np.zeros_like(data_sen2_monthly[\"red\"].values),\n",
|
||||
" coords=data_sen2_monthly[\"red\"].coords,\n",
|
||||
" dims=data_sen2_monthly[\"red\"].dims\n",
|
||||
" ),\n",
|
||||
" \"VH\": xr.DataArray(\n",
|
||||
" np.zeros_like(data_sen2_monthly[\"red\"].values),\n",
|
||||
" coords=data_sen2_monthly[\"red\"].coords,\n",
|
||||
" dims=data_sen2_monthly[\"red\"].dims\n",
|
||||
" )\n",
|
||||
" })\n",
|
||||
"else:\n",
|
||||
" # Load Sentinel-1 data\n",
|
||||
" data_sen1 = load(\n",
|
||||
" items_s1,\n",
|
||||
" bands=[\"vv\", \"vh\"],\n",
|
||||
" bbox=bbox,\n",
|
||||
" resolution=10,\n",
|
||||
" chunks={\"time\": 1, \"x\": 2048, \"y\": 2048},\n",
|
||||
" groupby=\"solar_day\"\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # Rename bands to uppercase (VV, VH)\n",
|
||||
" data_sen1 = data_sen1.rename({\"vv\": \"VV\", \"vh\": \"VH\"})\n",
|
||||
" data_sen1_monthly = data_sen1.resample(time=\"1MS\").mean().compute()\n",
|
||||
"\n",
|
||||
"print(f\"✅ S1 monthly shape: {data_sen1_monthly.dims}\")\n",
|
||||
"print(f\" Variables: {list(data_sen1_monthly.data_vars)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ecc56c2f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Ánh xạ nhãn lớp đất\n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": \"0\", \"Lua\": \"1\", \"CHN\": \"2\", \"CLN\": \"3\",\n",
|
||||
" \"TS\": \"4\", \"Song\": \"5\", \"Dat xay dung\": \"6\", \"Rung\": \"7\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"def load_train_data(csv_path=\"/media/x79/2A7D-FAA0/remote-sensing/train_data.csv\", label_mapping=None):\n",
|
||||
" \"\"\"Load training points từ CSV\"\"\"\n",
|
||||
" df = pd.read_csv(csv_path)\n",
|
||||
" if label_mapping:\n",
|
||||
" df[\"label\"] = df[\"class_name\"].map(label_mapping).astype(str)\n",
|
||||
" return df\n",
|
||||
"\n",
|
||||
"def get_data_sen1_and_sen2(train_df, sen2_data, sen1_data):\n",
|
||||
" \"\"\"Extract features từ S2 và S1 tại các điểm training\"\"\"\n",
|
||||
" X_list = []\n",
|
||||
" y_list = []\n",
|
||||
" \n",
|
||||
" for idx, row in train_df.iterrows():\n",
|
||||
" try:\n",
|
||||
" lon, lat = float(row[\"longitude\"]), float(row[\"latitude\"])\n",
|
||||
" label = int(row[\"label\"])\n",
|
||||
" \n",
|
||||
" # Extract S2 features (mean, std, min, max theo time)\n",
|
||||
" s2_point = sen2_data.sel(x=lon, y=lat, method=\"nearest\")\n",
|
||||
" s2_features = []\n",
|
||||
" \n",
|
||||
" for var in [\"red\", \"green\", \"blue\", \"nir\", \"swir16\", \"swir22\", \"NDVI\"]:\n",
|
||||
" if var in s2_point:\n",
|
||||
" vals = s2_point[var].values\n",
|
||||
" if vals.size > 0:\n",
|
||||
" s2_features.extend([\n",
|
||||
" np.nanmean(vals), np.nanstd(vals),\n",
|
||||
" np.nanmin(vals), np.nanmax(vals)\n",
|
||||
" ])\n",
|
||||
" else:\n",
|
||||
" s2_features.extend([0, 0, 0, 0])\n",
|
||||
" \n",
|
||||
" # Extract S1 features\n",
|
||||
" s1_point = sen1_data.sel(x=lon, y=lat, method=\"nearest\")\n",
|
||||
" s1_features = []\n",
|
||||
" \n",
|
||||
" for var in [\"VV\", \"VH\"]:\n",
|
||||
" if var in s1_point:\n",
|
||||
" vals = s1_point[var].values\n",
|
||||
" if vals.size > 0:\n",
|
||||
" s1_features.extend([np.nanmean(vals), np.nanstd(vals)])\n",
|
||||
" else:\n",
|
||||
" s1_features.extend([0, 0])\n",
|
||||
" \n",
|
||||
" features = s2_features + s1_features\n",
|
||||
" \n",
|
||||
" # Bỏ qua nếu có NaN\n",
|
||||
" if not np.isnan(features).any() and not np.isinf(features).any():\n",
|
||||
" X_list.append(features)\n",
|
||||
" y_list.append(label)\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠️ Lỗi tại row {idx}: {e}\")\n",
|
||||
" continue\n",
|
||||
" \n",
|
||||
" return X_list, y_list\n",
|
||||
"\n",
|
||||
"def split_train_data(X, y, test_size=0.2, val_size=0.1, random_state=42):\n",
|
||||
" \"\"\"Split data thành train/val/test\"\"\"\n",
|
||||
" X = np.array(X, dtype=np.float32)\n",
|
||||
" y = np.array(y, dtype=np.int64)\n",
|
||||
" \n",
|
||||
" # Train + temp\n",
|
||||
" X_train, X_temp, y_train, y_temp = train_test_split(\n",
|
||||
" X, y, test_size=test_size + val_size, random_state=random_state, stratify=y\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # Val + test\n",
|
||||
" val_ratio = val_size / (test_size + val_size)\n",
|
||||
" X_val, X_test, y_val, y_test = train_test_split(\n",
|
||||
" X_temp, y_temp, test_size=(1 - val_ratio), random_state=random_state, stratify=y_temp\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" return X_train, X_val, X_test, y_train, y_val, y_test\n",
|
||||
"\n",
|
||||
"# Load và extract features\n",
|
||||
"train_data = load_train_data(label_mapping=label_mapping)\n",
|
||||
"X, y = get_data_sen1_and_sen2(train_data, data_sen2_monthly, data_sen1_monthly)\n",
|
||||
"X_train, X_val, X_test, y_train, y_val, y_test = split_train_data(X, y, test_size=0.2, val_size=0.1)\n",
|
||||
"\n",
|
||||
"X_train_np = np.array(X_train, dtype=np.float32)\n",
|
||||
"X_val_np = np.array(X_val, dtype=np.float32)\n",
|
||||
"X_test_np = np.array(X_test, dtype=np.float32)\n",
|
||||
"y_train_np = np.array(y_train, dtype=np.int64)\n",
|
||||
"y_val_np = np.array(y_val, dtype=np.int64)\n",
|
||||
"y_test_np = np.array(y_test, dtype=np.int64)\n",
|
||||
"\n",
|
||||
"n_features = X_train_np.shape[1]\n",
|
||||
"n_classes = len(np.unique(y_train_np))\n",
|
||||
"\n",
|
||||
"print(f\"✅ Train: {X_train_np.shape} Val: {X_val_np.shape} Test: {X_test_np.shape}\")\n",
|
||||
"print(f\" n_features={n_features} n_classes={n_classes}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5492528b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import torch\n",
|
||||
"import torch.nn as nn\n",
|
||||
"import torch.optim as optim\n",
|
||||
"from torch.utils.data import TensorDataset, DataLoader\n",
|
||||
"\n",
|
||||
"# ── MobileNetV3 + LR-ASPP classifier ──────────────────────────────────────────\n",
|
||||
"class MobileNetLRASPPClassifier(nn.Module):\n",
|
||||
" \"\"\"\n",
|
||||
" MobileNetV3-inspired backbone with LR-ASPP (Lite Reduced ASPP) head\n",
|
||||
" for land-use classification on flat feature vectors.\n",
|
||||
" \"\"\"\n",
|
||||
" def __init__(self, n_features, n_classes):\n",
|
||||
" super().__init__()\n",
|
||||
" # Feature extraction backbone\n",
|
||||
" self.feature_extractor = nn.Sequential(\n",
|
||||
" nn.Linear(n_features, 128), nn.BatchNorm1d(128), nn.ReLU(inplace=True), nn.Dropout(0.2),\n",
|
||||
" nn.Linear(128, 256), nn.BatchNorm1d(256), nn.ReLU(inplace=True), nn.Dropout(0.3),\n",
|
||||
" nn.Linear(256, 512), nn.BatchNorm1d(512), nn.ReLU(inplace=True), nn.Dropout(0.3),\n",
|
||||
" )\n",
|
||||
" # LR-ASPP Branch 1: global pooling → 128\n",
|
||||
" self.global_pool = nn.AdaptiveAvgPool1d(1)\n",
|
||||
" self.global_conv = nn.Sequential(nn.Linear(512, 128), nn.ReLU(inplace=True))\n",
|
||||
" # LR-ASPP Branch 2: direct 1×1 → 128\n",
|
||||
" self.branch_conv = nn.Sequential(nn.Linear(512, 128), nn.BatchNorm1d(128), nn.ReLU(inplace=True))\n",
|
||||
" # Fusion → n_classes\n",
|
||||
" self.classifier = nn.Sequential(\n",
|
||||
" nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(inplace=True), nn.Dropout(0.4),\n",
|
||||
" nn.Linear(128, n_classes),\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" def forward(self, x):\n",
|
||||
" feat = self.feature_extractor(x)\n",
|
||||
" global_feat = self.global_pool(feat.unsqueeze(-1)).squeeze(-1)\n",
|
||||
" global_feat = self.global_conv(global_feat)\n",
|
||||
" branch_feat = self.branch_conv(feat)\n",
|
||||
" fused = torch.cat([global_feat, branch_feat], dim=1)\n",
|
||||
" return self.classifier(fused)\n",
|
||||
"\n",
|
||||
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
|
||||
"print(f\"✅ Device: {device}\")\n",
|
||||
"model = MobileNetLRASPPClassifier(n_features, n_classes).to(device)\n",
|
||||
"print(model)\n",
|
||||
"total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
|
||||
"print(f\" Trainable params: {total_params:,}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9da40f5a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"# ── Hyper-parameters ───────────────────────────────────────────────────────────\n",
|
||||
"LEARNING_RATE = 1e-3\n",
|
||||
"BATCH_SIZE = 64\n",
|
||||
"N_EPOCHS = 60\n",
|
||||
"PATIENCE = 10\n",
|
||||
"CONV_THRESHOLD = 1e-4 # cải thiện val_loss < THRESHOLD → đánh dấu hội tụ\n",
|
||||
"CONV_WINDOW = 3 # cần CONV_WINDOW bước liên tiếp thỏa mãn\n",
|
||||
"\n",
|
||||
"# ── Tensors & DataLoaders ──────────────────────────────────────────────────────\n",
|
||||
"X_tr_t = torch.FloatTensor(X_train_np)\n",
|
||||
"y_tr_t = torch.LongTensor(y_train_np)\n",
|
||||
"X_va_t = torch.FloatTensor(X_val_np)\n",
|
||||
"y_va_t = torch.LongTensor(y_val_np)\n",
|
||||
"\n",
|
||||
"train_loader = DataLoader(TensorDataset(X_tr_t, y_tr_t), batch_size=BATCH_SIZE, shuffle=True)\n",
|
||||
"val_loader = DataLoader(TensorDataset(X_va_t, y_va_t), batch_size=BATCH_SIZE, shuffle=False)\n",
|
||||
"\n",
|
||||
"# ── Class-weighted loss ────────────────────────────────────────────────────────\n",
|
||||
"class_counts = np.bincount(y_train_np)\n",
|
||||
"class_weights = 1.0 / (class_counts + 1e-6)\n",
|
||||
"class_weights = class_weights / class_weights.sum() * n_classes\n",
|
||||
"criterion = nn.CrossEntropyLoss(weight=torch.FloatTensor(class_weights).to(device))\n",
|
||||
"\n",
|
||||
"optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=1e-4)\n",
|
||||
"scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode=\"min\", factor=0.5, patience=5)\n",
|
||||
"\n",
|
||||
"# ── Training loop ──────────────────────────────────────────────────────────────\n",
|
||||
"train_losses, val_losses, val_accs, lr_history = [], [], [], []\n",
|
||||
"best_val_loss = float(\"inf\")\n",
|
||||
"best_epoch = 1\n",
|
||||
"best_state_dict = None\n",
|
||||
"patience_counter = 0\n",
|
||||
"convergence_epoch = None # ← điểm hội tụ sẽ được ghi lại ở đây\n",
|
||||
"early_stop_epoch = None\n",
|
||||
"\n",
|
||||
"print(\"🚀 Training MobileNetV3 + LR-ASPP...\")\n",
|
||||
"print(f\" conv_threshold={CONV_THRESHOLD} conv_window={CONV_WINDOW} patience={PATIENCE}\")\n",
|
||||
"for epoch in range(1, N_EPOCHS + 1):\n",
|
||||
" # --- Train ---\n",
|
||||
" model.train()\n",
|
||||
" epoch_loss = 0.0\n",
|
||||
" for bx, by in train_loader:\n",
|
||||
" bx, by = bx.to(device), by.to(device)\n",
|
||||
" optimizer.zero_grad()\n",
|
||||
" loss = criterion(model(bx), by)\n",
|
||||
" loss.backward()\n",
|
||||
" torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n",
|
||||
" optimizer.step()\n",
|
||||
" epoch_loss += loss.item()\n",
|
||||
" avg_train_loss = epoch_loss / len(train_loader)\n",
|
||||
"\n",
|
||||
" # --- Validate ---\n",
|
||||
" model.eval()\n",
|
||||
" val_loss = 0.0; correct = 0; total = 0\n",
|
||||
" with torch.no_grad():\n",
|
||||
" for bx, by in val_loader:\n",
|
||||
" bx, by = bx.to(device), by.to(device)\n",
|
||||
" out = model(bx)\n",
|
||||
" val_loss += criterion(out, by).item()\n",
|
||||
" pred = out.argmax(1)\n",
|
||||
" correct += (pred == by).sum().item()\n",
|
||||
" total += by.size(0)\n",
|
||||
" avg_val_loss = val_loss / len(val_loader)\n",
|
||||
" val_acc = correct / total\n",
|
||||
"\n",
|
||||
" scheduler.step(avg_val_loss)\n",
|
||||
" lr = optimizer.param_groups[0][\"lr\"]\n",
|
||||
" lr_history.append(lr)\n",
|
||||
"\n",
|
||||
" train_losses.append(avg_train_loss)\n",
|
||||
" val_losses.append(avg_val_loss)\n",
|
||||
" val_accs.append(val_acc)\n",
|
||||
"\n",
|
||||
" # ── Phát hiện điểm hội tụ (sliding window trên val_loss) ──────────────\n",
|
||||
" if convergence_epoch is None and epoch >= CONV_WINDOW + 1:\n",
|
||||
" window = val_losses[-(CONV_WINDOW + 1):]\n",
|
||||
" improvements = [abs(window[i] - window[i - 1]) for i in range(1, len(window))]\n",
|
||||
" if all(imp < CONV_THRESHOLD for imp in improvements):\n",
|
||||
" convergence_epoch = epoch - CONV_WINDOW + 1\n",
|
||||
" print(f\" 📍 Hội tụ phát hiện tại epoch {convergence_epoch} \"\n",
|
||||
" f\"(val_loss={val_losses[convergence_epoch-1]:.4f})\")\n",
|
||||
"\n",
|
||||
" if epoch % 5 == 0 or epoch == 1:\n",
|
||||
" print(f\" Epoch {epoch:3d}/{N_EPOCHS} train={avg_train_loss:.4f} \"\n",
|
||||
" f\"val={avg_val_loss:.4f} acc={val_acc:.4f} lr={lr:.2e}\")\n",
|
||||
"\n",
|
||||
" # ── Early stopping ─────────────────────────────────────────────────────\n",
|
||||
" if avg_val_loss < best_val_loss:\n",
|
||||
" best_val_loss = avg_val_loss\n",
|
||||
" best_epoch = epoch\n",
|
||||
" best_state_dict = {k: v.clone() for k, v in model.state_dict().items()}\n",
|
||||
" patience_counter = 0\n",
|
||||
" else:\n",
|
||||
" patience_counter += 1\n",
|
||||
" if patience_counter >= PATIENCE:\n",
|
||||
" early_stop_epoch = epoch\n",
|
||||
" print(f\"⏹ Early stopping tại epoch {epoch} (patience={PATIENCE})\")\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"# Restore best weights\n",
|
||||
"model.load_state_dict(best_state_dict)\n",
|
||||
"total_epochs = len(train_losses)\n",
|
||||
"print(f\"\\n✅ Training hoàn tất! Best epoch={best_epoch} Best val_loss={best_val_loss:.4f}\")\n",
|
||||
"if convergence_epoch:\n",
|
||||
" print(f\" Điểm hội tụ : epoch {convergence_epoch}\")\n",
|
||||
"\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"# PHÂN TÍCH ĐIỂM HỘI TỤ — MobileNetV3 + LR-ASPP\n",
|
||||
"# EMA-smoothed curves + annotated convergence / best / early-stop markers\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"epochs_axis = list(range(1, total_epochs + 1))\n",
|
||||
"\n",
|
||||
"# Exponential Moving Average smoothing\n",
|
||||
"def ema(values, alpha=0.2):\n",
|
||||
" s = [values[0]]\n",
|
||||
" for v in values[1:]:\n",
|
||||
" s.append(alpha * v + (1 - alpha) * s[-1])\n",
|
||||
" return s\n",
|
||||
"\n",
|
||||
"val_losses_ema = ema(val_losses, alpha=0.3)\n",
|
||||
"train_losses_ema = ema(train_losses, alpha=0.3)\n",
|
||||
"val_accs_ema = ema(val_accs, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# ── Tính ΔVal-loss per epoch ──────────────────────────────────────────────────\n",
|
||||
"delta_val = [abs(val_losses_ema[i] - val_losses_ema[i-1])\n",
|
||||
" for i in range(1, len(val_losses_ema))]\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(2, 2, figsize=(16, 10))\n",
|
||||
"\n",
|
||||
"# --- Top-left: Loss curves ---\n",
|
||||
"ax = axes[0, 0]\n",
|
||||
"ax.plot(epochs_axis, train_losses, \"b-\", alpha=0.25, linewidth=0.8)\n",
|
||||
"ax.plot(epochs_axis, train_losses_ema, \"b-\", linewidth=2, label=\"Train loss (EMA)\")\n",
|
||||
"ax.plot(epochs_axis, val_losses, \"g-\", alpha=0.25, linewidth=0.8)\n",
|
||||
"ax.plot(epochs_axis, val_losses_ema, \"g-\", linewidth=2, label=\"Val loss (EMA)\")\n",
|
||||
"ax.axvline(x=best_epoch, color=\"red\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Best epoch={best_epoch}\")\n",
|
||||
"if convergence_epoch:\n",
|
||||
" ax.axvline(x=convergence_epoch, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"HỘI TỤ epoch={convergence_epoch}\")\n",
|
||||
"if early_stop_epoch:\n",
|
||||
" ax.axvline(x=early_stop_epoch, color=\"gray\", linestyle=\"-.\", linewidth=1.5,\n",
|
||||
" label=f\"Early stop epoch={early_stop_epoch}\")\n",
|
||||
"ax.set_xlabel(\"Epoch\")\n",
|
||||
"ax.set_ylabel(\"Loss\")\n",
|
||||
"ax.set_title(\"Loss Curves (raw + EMA)\")\n",
|
||||
"ax.legend(fontsize=8)\n",
|
||||
"ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Top-right: Val accuracy ---\n",
|
||||
"ax = axes[0, 1]\n",
|
||||
"ax.plot(epochs_axis, val_accs, \"g-\", alpha=0.3, linewidth=0.8)\n",
|
||||
"ax.plot(epochs_axis, val_accs_ema, \"g-\", linewidth=2, label=\"Val acc (EMA)\")\n",
|
||||
"ax.axvline(x=best_epoch, color=\"red\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Best epoch={best_epoch} ({val_accs[best_epoch-1]*100:.2f}%)\")\n",
|
||||
"if convergence_epoch:\n",
|
||||
" ax.axvline(x=convergence_epoch, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"HỘI TỤ epoch={convergence_epoch} ({val_accs[convergence_epoch-1]*100:.2f}%)\")\n",
|
||||
"if early_stop_epoch:\n",
|
||||
" ax.axvline(x=early_stop_epoch, color=\"gray\", linestyle=\"-.\", linewidth=1.5,\n",
|
||||
" label=f\"Early stop\")\n",
|
||||
"ax.set_xlabel(\"Epoch\")\n",
|
||||
"ax.set_ylabel(\"Accuracy\")\n",
|
||||
"ax.set_title(\"Val Accuracy Curve\")\n",
|
||||
"ax.legend(fontsize=8)\n",
|
||||
"ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Bottom-left: ΔVal-loss (marginal improvement) ---\n",
|
||||
"ax = axes[1, 0]\n",
|
||||
"ax.bar(epochs_axis[1:], delta_val,\n",
|
||||
" color=[\"green\" if d > CONV_THRESHOLD else \"salmon\" for d in delta_val],\n",
|
||||
" alpha=0.75)\n",
|
||||
"ax.axhline(y=CONV_THRESHOLD, color=\"red\", linestyle=\"--\",\n",
|
||||
" label=f\"Threshold = {CONV_THRESHOLD:.0e}\")\n",
|
||||
"if convergence_epoch:\n",
|
||||
" ax.axvline(x=convergence_epoch, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"HỘI TỤ epoch={convergence_epoch}\")\n",
|
||||
"ax.set_xlabel(\"Epoch\")\n",
|
||||
"ax.set_ylabel(\"|ΔVal Loss|\")\n",
|
||||
"ax.set_title(\"Marginal Val-Loss Improvement per Epoch\")\n",
|
||||
"ax.legend(fontsize=8)\n",
|
||||
"ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Bottom-right: Learning rate schedule ---\n",
|
||||
"ax = axes[1, 1]\n",
|
||||
"ax.semilogy(epochs_axis, lr_history, \"purple\", linewidth=2)\n",
|
||||
"if convergence_epoch:\n",
|
||||
" ax.axvline(x=convergence_epoch, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"HỘI TỤ epoch={convergence_epoch}\")\n",
|
||||
"ax.axvline(x=best_epoch, color=\"red\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Best epoch={best_epoch}\")\n",
|
||||
"ax.set_xlabel(\"Epoch\")\n",
|
||||
"ax.set_ylabel(\"Learning Rate (log)\")\n",
|
||||
"ax.set_title(\"Learning Rate Schedule (ReduceLROnPlateau)\")\n",
|
||||
"ax.legend(fontsize=8)\n",
|
||||
"ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"plt.suptitle(\"MobileNetV3 + LR-ASPP — Convergence Analysis\", fontsize=13, fontweight=\"bold\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"# ── Tổng kết ──────────────────────────────────────────────────────────────────\n",
|
||||
"print(f\"\\n{'═'*60}\")\n",
|
||||
"print(f\" Tổng số epoch : {total_epochs}\")\n",
|
||||
"print(f\" Best epoch : {best_epoch} (val_loss={best_val_loss:.4f})\")\n",
|
||||
"print(f\" Best val accuracy : {val_accs[best_epoch-1]*100:.4f}%\")\n",
|
||||
"if convergence_epoch:\n",
|
||||
" print(f\" Điểm HỘI TỤ : epoch {convergence_epoch} \"\n",
|
||||
" f\"(val_acc={val_accs[convergence_epoch-1]*100:.2f}%)\")\n",
|
||||
" wasted = total_epochs - convergence_epoch\n",
|
||||
" print(f\" Epochs sau hội tụ : {wasted} \"\n",
|
||||
" f\"(có thể giảm N_EPOCHS không ảnh hưởng nhiều đến kết quả)\")\n",
|
||||
"if early_stop_epoch:\n",
|
||||
" print(f\" Early stop tại epoch: {early_stop_epoch}\")\n",
|
||||
"print(f\"{'═'*60}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bc690b92",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import classification_report, confusion_matrix, accuracy_score\n",
|
||||
"import seaborn as sns\n",
|
||||
"\n",
|
||||
"# ── Đánh giá trên tập test ─────────────────────────────────────────────────────\n",
|
||||
"model.eval()\n",
|
||||
"with torch.no_grad():\n",
|
||||
" X_te_t = torch.FloatTensor(X_test_np).to(device)\n",
|
||||
" logits = model(X_te_t)\n",
|
||||
" y_pred = logits.argmax(1).cpu().numpy()\n",
|
||||
"\n",
|
||||
"acc = accuracy_score(y_test_np, y_pred)\n",
|
||||
"print(f\"Test Accuracy : {acc:.4f} ({acc*100:.2f}%)\\n\")\n",
|
||||
"print(classification_report(y_test_np, y_pred, digits=4))\n",
|
||||
"\n",
|
||||
"# ── Confusion matrix ────────────────────────────────────────────────────────────\n",
|
||||
"class_names = list(label_mapping.keys())\n",
|
||||
"cm = confusion_matrix(y_test_np, y_pred)\n",
|
||||
"plt.figure(figsize=(9, 7))\n",
|
||||
"sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Purples\",\n",
|
||||
" xticklabels=class_names, yticklabels=class_names)\n",
|
||||
"plt.xlabel(\"Predicted\")\n",
|
||||
"plt.ylabel(\"Actual\")\n",
|
||||
"plt.title(\"Confusion Matrix — MobileNetV3 + LR-ASPP\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d4805767-4f58-4464-930c-66fcbb341cc2",
|
||||
"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
|
||||
}
|
||||
@@ -1,353 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3ab233c4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"%matplotlib inline\n",
|
||||
"\n",
|
||||
"import importlib\n",
|
||||
"import new_import_ODC\n",
|
||||
"\n",
|
||||
"importlib.reload(new_import_ODC)\n",
|
||||
"from new_import_ODC import *\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0af1f969",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Cấu hình Dask + ODC + S3\n",
|
||||
"cluster, client = notebook_utils.initialize_dask(use_gateway=True, workers=(1, 10))\n",
|
||||
"dc = datacube.Datacube()\n",
|
||||
"configure_s3_access(aws_unsigned=False, requester_pays=True, client=client)\n",
|
||||
"client\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b0809939",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## cấu hình thời gian 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",
|
||||
"coordinates = (longtitude_range, latitude_range)\n",
|
||||
"\n",
|
||||
"## truy vấn ảnh Sentinel-2\n",
|
||||
"data = load_data(dc, date_range, longtitude_range, latitude_range)\n",
|
||||
"notebook_utils.heading(notebook_utils.xarray_object_size(data))\n",
|
||||
"display(data)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b74030e3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# Cloud masking + NDVI + fill nan + resample\n",
|
||||
"result = mask_clean(data)\n",
|
||||
"progress(result)\n",
|
||||
"\n",
|
||||
"ds1 = calculate_indices(result, index=\"NDVI\", satellite_mission=\"s2\")\n",
|
||||
"ndvi = ds1[\"NDVI\"]\n",
|
||||
"\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",
|
||||
"fill_nan_ndvi = fill_nan(ndvi, time_split)\n",
|
||||
"plt.imshow(fill_nan_ndvi.isel(time=6)); plt.title(\"NDVI (after fill)\"); plt.colorbar(); plt.show()\n",
|
||||
"\n",
|
||||
"average_ndvi = fill_nan_ndvi.resample(time=\"1M\").mean().persist()\n",
|
||||
"progress(average_ndvi)\n",
|
||||
"average_ndvi = average_ndvi.compute()\n",
|
||||
"print(f\"NDVI monthly: {average_ndvi.shape}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "df61871b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load Sentinel-1 (VH, VV)\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\")\n",
|
||||
"print(f\"VV: {average_vv.shape} VH: {average_vh.shape}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d0def6c0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## Chuẩn bị dữ liệu train\n",
|
||||
"train_path = \"train/ST_training_data_updated_1130points_new.shp\"\n",
|
||||
"train = load_train_data(train_path)\n",
|
||||
"train.head()\n",
|
||||
"\n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": \"0\", \"Lua\": \"1\", \"CHN\": \"2\", \"CLN\": \"3\",\n",
|
||||
" \"TS\": \"4\", \"Song\": \"5\", \"Dat xay dung\": \"6\", \"Rung\": \"7\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"datasets = get_data_sen1_and_sen2(train, average_ndvi, average_vh, average_vv)\n",
|
||||
"X_train, X_val, X_test, y_train, y_val, y_test = split_train_data(train, label_mapping, datasets)\n",
|
||||
"\n",
|
||||
"import numpy as np\n",
|
||||
"X_train_np = np.asarray(X_train, dtype=np.float32)\n",
|
||||
"X_val_np = np.asarray(X_val, dtype=np.float32)\n",
|
||||
"X_test_np = np.asarray(X_test, 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",
|
||||
"y_test_np = np.asarray(y_test, dtype=np.int32)\n",
|
||||
"\n",
|
||||
"# Gộp train + val để tận dụng toàn bộ dữ liệu train\n",
|
||||
"X_fit = np.concatenate([X_train_np, X_val_np], axis=0)\n",
|
||||
"y_fit = np.concatenate([y_train_np, y_val_np], axis=0)\n",
|
||||
"\n",
|
||||
"print(f\"Train (fit): {X_fit.shape} Test: {X_test_np.shape} Classes: {len(label_mapping)}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2dc75f84",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"from sklearn.ensemble import RandomForestClassifier\n",
|
||||
"\n",
|
||||
"# ── Xây dựng và train mô hình Random Forest ───────────────────────────────────\n",
|
||||
"model = RandomForestClassifier(\n",
|
||||
" n_estimators=200,\n",
|
||||
" max_depth=30,\n",
|
||||
" min_samples_leaf=2,\n",
|
||||
" n_jobs=-1,\n",
|
||||
" class_weight=\"balanced\", # xử lý mất cân bằng nhãn\n",
|
||||
" random_state=42,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"🚀 Training Random Forest...\")\n",
|
||||
"print(f\" n_estimators = {model.n_estimators}\")\n",
|
||||
"print(f\" max_depth = {model.max_depth}\")\n",
|
||||
"print(f\" Train samples: {len(X_fit)}\")\n",
|
||||
"\n",
|
||||
"model.fit(X_fit, y_fit)\n",
|
||||
"\n",
|
||||
"val_acc = model.score(X_val_np, y_val_np)\n",
|
||||
"print(f\"\\n✅ Training hoàn tất! Val accuracy: {val_acc:.4f} ({val_acc*100:.2f}%)\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "90588a5d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from sklearn.ensemble import RandomForestClassifier\n",
|
||||
"\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"# PHÂN TÍCH ĐIỂM HỘI TỤ — Random Forest\n",
|
||||
"# Phương pháp: tăng dần n_estimators (warm_start) và theo dõi val accuracy\n",
|
||||
"# Điểm hội tụ = lần đầu cải thiện val_acc < THRESHOLD trong WINDOW bước liên tiếp\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"N_RANGE = list(range(5, 205, 5)) # 5, 10, 15, ... 200\n",
|
||||
"THRESHOLD = 0.0005 # cải thiện < 0.05% → coi là hội tụ\n",
|
||||
"WINDOW = 3 # cần WINDOW bước liên tiếp dưới threshold\n",
|
||||
"\n",
|
||||
"conv_model = RandomForestClassifier(\n",
|
||||
" max_depth=30, min_samples_leaf=2, n_jobs=-1,\n",
|
||||
" class_weight=\"balanced\", random_state=42,\n",
|
||||
" warm_start=True, # ← cho phép thêm cây mà không retrain lại\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"train_accs_c, val_accs_c = [], []\n",
|
||||
"print(\"🔍 Phân tích hội tụ (warm_start)...\")\n",
|
||||
"for n in N_RANGE:\n",
|
||||
" conv_model.n_estimators = n\n",
|
||||
" conv_model.fit(X_fit, y_fit)\n",
|
||||
" train_accs_c.append(conv_model.score(X_fit, y_fit))\n",
|
||||
" val_accs_c.append(conv_model.score(X_val_np, y_val_np))\n",
|
||||
"\n",
|
||||
"val_accs_c = np.array(val_accs_c)\n",
|
||||
"train_accs_c = np.array(train_accs_c)\n",
|
||||
"\n",
|
||||
"# ── Tìm điểm hội tụ ───────────────────────────────────────────────────────────\n",
|
||||
"improvements = np.abs(np.diff(val_accs_c))\n",
|
||||
"convergence_idx = None\n",
|
||||
"for i in range(len(improvements) - WINDOW + 1):\n",
|
||||
" if all(improvements[i : i + WINDOW] < THRESHOLD):\n",
|
||||
" convergence_idx = i + 1 # chỉ số của điểm đầu tiên trong cửa sổ\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"best_idx = int(np.argmax(val_accs_c))\n",
|
||||
"best_n = N_RANGE[best_idx]\n",
|
||||
"conv_n = N_RANGE[convergence_idx] if convergence_idx is not None else None\n",
|
||||
"\n",
|
||||
"# ── Vẽ đồ thị ─────────────────────────────────────────────────────────────────\n",
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(15, 5))\n",
|
||||
"\n",
|
||||
"# --- Trái: accuracy curve ---\n",
|
||||
"axes[0].plot(N_RANGE, train_accs_c, \"b-o\", markersize=3, label=\"Train\")\n",
|
||||
"axes[0].plot(N_RANGE, val_accs_c, \"g-o\", markersize=3, label=\"Val\")\n",
|
||||
"axes[0].axvline(x=best_n, color=\"red\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Best val acc n={best_n} ({max(val_accs_c)*100:.2f}%)\")\n",
|
||||
"if conv_n:\n",
|
||||
" axes[0].axvline(x=conv_n, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"Hội tụ n={conv_n} ({val_accs_c[convergence_idx]*100:.2f}%)\")\n",
|
||||
"axes[0].set_xlabel(\"n_estimators\")\n",
|
||||
"axes[0].set_ylabel(\"Accuracy\")\n",
|
||||
"axes[0].set_title(\"Convergence — Val Accuracy vs n_estimators\")\n",
|
||||
"axes[0].legend(fontsize=8)\n",
|
||||
"axes[0].grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Phải: cải thiện biên (marginal improvement) ---\n",
|
||||
"axes[1].bar(N_RANGE[1:], improvements * 100, color=\"steelblue\", alpha=0.7)\n",
|
||||
"axes[1].axhline(y=THRESHOLD * 100, color=\"red\", linestyle=\"--\",\n",
|
||||
" label=f\"Threshold = {THRESHOLD*100:.3f}%\")\n",
|
||||
"if conv_n:\n",
|
||||
" axes[1].axvline(x=conv_n, color=\"orange\", linestyle=\":\", linewidth=1.5,\n",
|
||||
" label=f\"Hội tụ n={conv_n}\")\n",
|
||||
"axes[1].set_xlabel(\"n_estimators\")\n",
|
||||
"axes[1].set_ylabel(\"ΔVal Accuracy (%)\")\n",
|
||||
"axes[1].set_title(\"Marginal Improvement per Step\")\n",
|
||||
"axes[1].legend(fontsize=8)\n",
|
||||
"axes[1].grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"plt.suptitle(\"Random Forest — Convergence Analysis\", fontsize=13, fontweight=\"bold\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"# ── Tổng kết ──────────────────────────────────────────────────────────────────\n",
|
||||
"print(f\"\\n{'═'*55}\")\n",
|
||||
"print(f\" Best val accuracy : {max(val_accs_c)*100:.4f}% (n_estimators={best_n})\")\n",
|
||||
"if conv_n:\n",
|
||||
" print(f\" Điểm HỘI TỤ : n_estimators = {conv_n}\")\n",
|
||||
" print(f\" → Có thể dùng n_estimators={conv_n} thay vì 200 để tiết kiệm thời gian\")\n",
|
||||
" saved_pct = (1 - conv_n / 200) * 100\n",
|
||||
" print(f\" → Tiết kiệm ~{saved_pct:.0f}% thời gian train\")\n",
|
||||
"else:\n",
|
||||
" print(\" → Mô hình chưa hội tụ trong phạm vi [5, 200]. Thử tăng n_estimators.\")\n",
|
||||
"print(f\"{'═'*55}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bc57f244",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import classification_report, confusion_matrix, accuracy_score\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns\n",
|
||||
"\n",
|
||||
"# ── Đánh giá trên tập test ─────────────────────────────────────────────────────\n",
|
||||
"y_pred = model.predict(X_test_np)\n",
|
||||
"\n",
|
||||
"acc = accuracy_score(y_test_np, y_pred)\n",
|
||||
"print(f\"Test Accuracy : {acc:.4f} ({acc*100:.2f}%)\\n\")\n",
|
||||
"print(classification_report(y_test_np, y_pred, digits=4))\n",
|
||||
"\n",
|
||||
"# ── Feature importance ──────────────────────────────────────────────────────────\n",
|
||||
"feat_imp = model.feature_importances_\n",
|
||||
"idx = feat_imp.argsort()[::-1][:20]\n",
|
||||
"plt.figure(figsize=(12, 4))\n",
|
||||
"plt.bar(range(len(idx)), feat_imp[idx])\n",
|
||||
"plt.xticks(range(len(idx)), idx, rotation=45)\n",
|
||||
"plt.title(\"Top-20 Feature Importances\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"# ── Confusion matrix ────────────────────────────────────────────────────────────\n",
|
||||
"class_names = list(label_mapping.keys())\n",
|
||||
"cm = confusion_matrix(y_test_np, y_pred)\n",
|
||||
"plt.figure(figsize=(9, 7))\n",
|
||||
"sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\",\n",
|
||||
" xticklabels=class_names, yticklabels=class_names)\n",
|
||||
"plt.xlabel(\"Predicted\")\n",
|
||||
"plt.ylabel(\"Actual\")\n",
|
||||
"plt.title(\"Confusion Matrix — Random Forest\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "efc23f2c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import joblib, json, os\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# ── Lưu mô hình ────────────────────────────────────────────────────────────────\n",
|
||||
"model_path = \"model_random_forest_land_use.joblib\"\n",
|
||||
"joblib.dump(model, model_path)\n",
|
||||
"print(f\"✅ Model saved → {model_path}\")\n",
|
||||
"\n",
|
||||
"# ── Lưu thông tin mô hình ──────────────────────────────────────────────────────\n",
|
||||
"info = {\n",
|
||||
" \"model_type\": \"RandomForest\",\n",
|
||||
" \"n_estimators\": model.n_estimators,\n",
|
||||
" \"max_depth\": model.max_depth,\n",
|
||||
" \"min_samples_leaf\": model.min_samples_leaf,\n",
|
||||
" \"class_weight\": \"balanced\",\n",
|
||||
" \"n_features\": int(X_fit.shape[1]),\n",
|
||||
" \"label_mapping\": label_mapping,\n",
|
||||
" \"test_accuracy\": float(acc),\n",
|
||||
" \"train_samples\": int(len(X_fit)),\n",
|
||||
" \"test_samples\": int(len(X_test_np)),\n",
|
||||
" \"saved_at\": datetime.now().isoformat(),\n",
|
||||
"}\n",
|
||||
"info_path = \"model_random_forest_land_use_info.json\"\n",
|
||||
"with open(info_path, \"w\") as f:\n",
|
||||
" json.dump(info, f, indent=2, ensure_ascii=False)\n",
|
||||
"print(f\"✅ Info saved → {info_path}\")\n",
|
||||
"print(json.dumps(info, indent=2, ensure_ascii=False))\n",
|
||||
"\n",
|
||||
"# ── Đóng kết nối Dask ──────────────────────────────────────────────────────────\n",
|
||||
"try:\n",
|
||||
" client.close()\n",
|
||||
" cluster.close()\n",
|
||||
" print(\"✅ Dask cluster closed.\")\n",
|
||||
"except Exception:\n",
|
||||
" pass\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f8e59602",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import importlib\n",
|
||||
"import new_import_ODC as odc_tools\n",
|
||||
"importlib.reload(odc_tools)\n",
|
||||
"from new_import_ODC import *\n",
|
||||
"print(\"✅ Import thành công\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8101f17e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Khởi tạo Dask + Datacube + S3\n",
|
||||
"cluster, client = initialize_dask(use_gateway=True)\n",
|
||||
"dc = datacube.Datacube()\n",
|
||||
"configure_s3_access(aws_unsigned=True)\n",
|
||||
"print(\"✅ Dask + Datacube + S3 sẵn sàng\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cba4d661",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Cấu hình vùng và thời gian\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",
|
||||
"# Tải dữ liệu Sentinel-2\n",
|
||||
"data_sen2 = load_data(\n",
|
||||
" dc=dc,\n",
|
||||
" date_range=date_range,\n",
|
||||
" longtitude_range=longtitude_range,\n",
|
||||
" latitude_range=latitude_range,\n",
|
||||
")\n",
|
||||
"print(f\"✅ Sentinel-2 raw: {data_sen2.dims}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "28b9d92d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tiền xử lý Sentinel-2: cloud mask + NDVI + resampling\n",
|
||||
"data_clean = mask_clean(data_sen2)\n",
|
||||
"data_ndvi = calculate_indices(data_clean, index=\"NDVI\")\n",
|
||||
"data_fill = fill_nan(data_ndvi)\n",
|
||||
"data_sen2_monthly = data_fill.resample(time=\"1MS\").mean().compute()\n",
|
||||
"print(f\"✅ S2 monthly shape: {data_sen2_monthly.dims}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0e4efc29",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tải Sentinel-1 (SAR VV/VH)\n",
|
||||
"data_sen1 = load_data_sen1(\n",
|
||||
" dc=dc,\n",
|
||||
" date_range=date_range,\n",
|
||||
" longtitude_range=longtitude_range,\n",
|
||||
" latitude_range=latitude_range,\n",
|
||||
")\n",
|
||||
"data_sen1_monthly = calculate_average(data_sen1, [\"VV\", \"VH\"], resample=\"1MS\").compute()\n",
|
||||
"print(f\"✅ S1 monthly shape: {data_sen1_monthly.dims}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb119111",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Ánh xạ nhãn lớp đất\n",
|
||||
"label_mapping = {\n",
|
||||
" \"Lua tom\": \"0\", \"Lua\": \"1\", \"CHN\": \"2\", \"CLN\": \"3\",\n",
|
||||
" \"TS\": \"4\", \"Song\": \"5\", \"Dat xay dung\": \"6\", \"Rung\": \"7\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"train_data = load_train_data(label_mapping=label_mapping)\n",
|
||||
"X, y = get_data_sen1_and_sen2(train_data, data_sen2_monthly, data_sen1_monthly)\n",
|
||||
"\n",
|
||||
"X_train, X_val, X_test, y_train, y_val, y_test = split_train_data(X, y, test_size=0.2, val_size=0.1)\n",
|
||||
"\n",
|
||||
"X_train_np = np.array(X_train, dtype=np.float32)\n",
|
||||
"X_val_np = np.array(X_val, dtype=np.float32)\n",
|
||||
"X_test_np = np.array(X_test, dtype=np.float32)\n",
|
||||
"y_train_np = np.array(y_train, dtype=np.int64)\n",
|
||||
"y_val_np = np.array(y_val, dtype=np.int64)\n",
|
||||
"y_test_np = np.array(y_test, dtype=np.int64)\n",
|
||||
"\n",
|
||||
"X_fit = np.concatenate([X_train_np, X_val_np], axis=0)\n",
|
||||
"y_fit = np.concatenate([y_train_np, y_val_np], axis=0)\n",
|
||||
"\n",
|
||||
"print(f\"✅ X_fit: {X_fit.shape} | X_test: {X_test_np.shape}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "69492c1f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"from sklearn.svm import SVC\n",
|
||||
"from sklearn.preprocessing import StandardScaler\n",
|
||||
"\n",
|
||||
"# ── Chuẩn hoá đặc trưng (quan trọng với SVM) ──────────────────────────────────\n",
|
||||
"scaler = StandardScaler()\n",
|
||||
"X_fit_scaled = scaler.fit_transform(X_fit)\n",
|
||||
"X_test_scaled = scaler.transform(X_test_np)\n",
|
||||
"X_val_scaled = scaler.transform(X_val_np)\n",
|
||||
"\n",
|
||||
"# ── Xây dựng và train mô hình SVM ─────────────────────────────────────────────\n",
|
||||
"model = SVC(\n",
|
||||
" kernel=\"rbf\",\n",
|
||||
" C=10,\n",
|
||||
" gamma=\"scale\",\n",
|
||||
" probability=True,\n",
|
||||
" class_weight=\"balanced\",\n",
|
||||
" random_state=42,\n",
|
||||
" verbose=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"🚀 Training SVM (RBF kernel)...\")\n",
|
||||
"print(f\" Train samples: {len(X_fit_scaled)}\")\n",
|
||||
"model.fit(X_fit_scaled, y_fit)\n",
|
||||
"\n",
|
||||
"val_acc = model.score(X_val_scaled, y_val_np)\n",
|
||||
"print(f\"✅ Training hoàn tất! Val accuracy: {val_acc:.4f} ({val_acc*100:.2f}%)\")\n",
|
||||
"print(f\" n_support_vectors: {model.n_support_}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ac391274",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from sklearn.model_selection import learning_curve\n",
|
||||
"from sklearn.svm import SVC\n",
|
||||
"\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"# PHÂN TÍCH ĐIỂM HỘI TỤ — SVM\n",
|
||||
"# Phương pháp 1: Learning Curve (accuracy vs training set size)\n",
|
||||
"# Phương pháp 2: C-sensitivity (val accuracy vs regularization C)\n",
|
||||
"# Điểm hội tụ = training size tại đó cải thiện val_score < threshold\n",
|
||||
"# ═══════════════════════════════════════════════════════════════════════════════\n",
|
||||
"THRESHOLD = 0.002 # cải thiện val_score < 0.2% → hội tụ\n",
|
||||
"N_CV = 3 # số fold cho cross-validation (tăng để chính xác hơn)\n",
|
||||
"\n",
|
||||
"# ── 1. Learning Curve ──────────────────────────────────────────────────────────\n",
|
||||
"print(\"🔍 Phân tích learning curve (train size)... [có thể mất vài phút]\")\n",
|
||||
"svc_for_lc = SVC(kernel=\"rbf\", C=10, gamma=\"scale\",\n",
|
||||
" class_weight=\"balanced\", random_state=42)\n",
|
||||
"\n",
|
||||
"train_sizes_pct = np.linspace(0.1, 1.0, 10)\n",
|
||||
"train_sizes, train_scores, val_scores = learning_curve(\n",
|
||||
" svc_for_lc, X_fit_scaled, y_fit,\n",
|
||||
" train_sizes=train_sizes_pct,\n",
|
||||
" cv=N_CV, scoring=\"accuracy\", n_jobs=-1, verbose=0,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"train_mean = train_scores.mean(axis=1)\n",
|
||||
"train_std = train_scores.std(axis=1)\n",
|
||||
"val_mean = val_scores.mean(axis=1)\n",
|
||||
"val_std = val_scores.std(axis=1)\n",
|
||||
"\n",
|
||||
"# Tìm điểm hội tụ\n",
|
||||
"val_improvements = np.abs(np.diff(val_mean))\n",
|
||||
"convergence_size_idx = None\n",
|
||||
"for i in range(len(val_improvements) - 1):\n",
|
||||
" if val_improvements[i] < THRESHOLD and val_improvements[i + 1] < THRESHOLD:\n",
|
||||
" convergence_size_idx = i + 1\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"# ── 2. C-Sensitivity ──────────────────────────────────────────────────────────\n",
|
||||
"print(\"🔍 Phân tích C-sensitivity...\")\n",
|
||||
"C_range = [0.01, 0.1, 1, 5, 10, 50, 100, 500]\n",
|
||||
"val_accs_c = []\n",
|
||||
"for c_val in C_range:\n",
|
||||
" m = SVC(kernel=\"rbf\", C=c_val, gamma=\"scale\",\n",
|
||||
" class_weight=\"balanced\", random_state=42)\n",
|
||||
" m.fit(X_fit_scaled, y_fit)\n",
|
||||
" val_accs_c.append(m.score(X_val_scaled, y_val_np))\n",
|
||||
"\n",
|
||||
"val_accs_c = np.array(val_accs_c)\n",
|
||||
"best_C = C_range[int(np.argmax(val_accs_c))]\n",
|
||||
"\n",
|
||||
"# ── Vẽ đồ thị ─────────────────────────────────────────────────────────────────\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(18, 5))\n",
|
||||
"\n",
|
||||
"# --- Trái: Learning Curve ---\n",
|
||||
"axes[0].plot(train_sizes, train_mean, \"b-o\", markersize=4, label=\"Train\")\n",
|
||||
"axes[0].fill_between(train_sizes, train_mean - train_std, train_mean + train_std,\n",
|
||||
" alpha=0.2, color=\"blue\")\n",
|
||||
"axes[0].plot(train_sizes, val_mean, \"g-o\", markersize=4, label=\"Val (CV)\")\n",
|
||||
"axes[0].fill_between(train_sizes, val_mean - val_std, val_mean + val_std,\n",
|
||||
" alpha=0.2, color=\"green\")\n",
|
||||
"if convergence_size_idx is not None:\n",
|
||||
" csize = train_sizes[convergence_size_idx]\n",
|
||||
" axes[0].axvline(x=csize, color=\"orange\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Hội tụ ~{int(csize):,} mẫu\")\n",
|
||||
"axes[0].set_xlabel(\"Training samples\")\n",
|
||||
"axes[0].set_ylabel(\"Accuracy\")\n",
|
||||
"axes[0].set_title(\"Learning Curve — Score vs Train Size\")\n",
|
||||
"axes[0].legend(fontsize=8)\n",
|
||||
"axes[0].grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Giữa: Marginal improvement of val score ---\n",
|
||||
"axes[1].bar(range(len(val_improvements)), val_improvements * 100,\n",
|
||||
" color=[\"green\" if v > THRESHOLD else \"salmon\" for v in val_improvements],\n",
|
||||
" alpha=0.8)\n",
|
||||
"axes[1].axhline(y=THRESHOLD * 100, color=\"red\", linestyle=\"--\",\n",
|
||||
" label=f\"Threshold={THRESHOLD*100:.2f}%\")\n",
|
||||
"if convergence_size_idx is not None:\n",
|
||||
" axes[1].axvline(x=convergence_size_idx - 0.5, color=\"orange\", linestyle=\":\",\n",
|
||||
" linewidth=1.5, label=f\"Hội tụ tại step {convergence_size_idx}\")\n",
|
||||
"step_labels = [f\"{int(train_sizes[i])}\" for i in range(1, len(train_sizes))]\n",
|
||||
"axes[1].set_xticks(range(len(val_improvements)))\n",
|
||||
"axes[1].set_xticklabels(step_labels, rotation=45, fontsize=7)\n",
|
||||
"axes[1].set_xlabel(\"Training size step\")\n",
|
||||
"axes[1].set_ylabel(\"ΔVal Accuracy (%)\")\n",
|
||||
"axes[1].set_title(\"Marginal Val Improvement per Add. Samples\")\n",
|
||||
"axes[1].legend(fontsize=8)\n",
|
||||
"axes[1].grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"# --- Phải: C sensitivity ---\n",
|
||||
"axes[2].semilogx(C_range, val_accs_c * 100, \"m-o\", markersize=6)\n",
|
||||
"axes[2].axvline(x=best_C, color=\"red\", linestyle=\"--\", linewidth=1.5,\n",
|
||||
" label=f\"Best C={best_C} ({max(val_accs_c)*100:.2f}%)\")\n",
|
||||
"axes[2].set_xlabel(\"C (regularization)\")\n",
|
||||
"axes[2].set_ylabel(\"Val Accuracy (%)\")\n",
|
||||
"axes[2].set_title(\"C-Sensitivity (Regularization)\")\n",
|
||||
"axes[2].legend(fontsize=8)\n",
|
||||
"axes[2].grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"plt.suptitle(\"SVM — Convergence Analysis\", fontsize=13, fontweight=\"bold\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"# ── Tổng kết ──────────────────────────────────────────────────────────────────\n",
|
||||
"print(f\"\\n{'═'*60}\")\n",
|
||||
"if convergence_size_idx is not None:\n",
|
||||
" print(f\" Điểm HỘI TỤ (Δval < {THRESHOLD*100:.1f}%) : \"\n",
|
||||
" f\"~{int(train_sizes[convergence_size_idx]):,} mẫu \"\n",
|
||||
" f\"(val_acc={val_mean[convergence_size_idx]*100:.2f}%)\")\n",
|
||||
" pct_data = train_sizes[convergence_size_idx] / len(X_fit_scaled) * 100\n",
|
||||
" print(f\" → Chỉ cần ~{pct_data:.0f}% dữ liệu để mô hình hội tụ\")\n",
|
||||
"else:\n",
|
||||
" print(\" → Cần thêm dữ liệu: val score vẫn đang cải thiện ở toàn bộ tập train\")\n",
|
||||
"print(f\" C tối ưu : {best_C} (val_acc={max(val_accs_c)*100:.2f}%)\")\n",
|
||||
"print(f\" C hiện tại dùng : 10 {'✅' if best_C == 10 else '⚠️ Thử dùng C=' + str(best_C)}\")\n",
|
||||
"print(f\"{'═'*60}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "940f640d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import classification_report, confusion_matrix, accuracy_score\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns\n",
|
||||
"\n",
|
||||
"# ── Đánh giá trên tập test ─────────────────────────────────────────────────────\n",
|
||||
"y_pred = model.predict(X_test_scaled)\n",
|
||||
"\n",
|
||||
"acc = accuracy_score(y_test_np, y_pred)\n",
|
||||
"print(f\"Test Accuracy : {acc:.4f} ({acc*100:.2f}%)\\n\")\n",
|
||||
"print(classification_report(y_test_np, y_pred, digits=4))\n",
|
||||
"\n",
|
||||
"# ── Confusion matrix ────────────────────────────────────────────────────────────\n",
|
||||
"class_names = list(label_mapping.keys())\n",
|
||||
"cm = confusion_matrix(y_test_np, y_pred)\n",
|
||||
"plt.figure(figsize=(9, 7))\n",
|
||||
"sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Oranges\",\n",
|
||||
" xticklabels=class_names, yticklabels=class_names)\n",
|
||||
"plt.xlabel(\"Predicted\")\n",
|
||||
"plt.ylabel(\"Actual\")\n",
|
||||
"plt.title(\"Confusion Matrix — SVM (RBF)\")\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "182c64ab",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import joblib, json\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# ── Lưu scaler (cần thiết khi inference) ──────────────────────────────────────\n",
|
||||
"scaler_path = \"model_svm_land_use_scaler.joblib\"\n",
|
||||
"joblib.dump(scaler, scaler_path)\n",
|
||||
"print(f\"✅ Scaler saved → {scaler_path}\")\n",
|
||||
"\n",
|
||||
"# ── Lưu mô hình SVM ────────────────────────────────────────────────────────────\n",
|
||||
"model_path = \"model_svm_land_use.joblib\"\n",
|
||||
"joblib.dump(model, model_path)\n",
|
||||
"print(f\"✅ Model saved → {model_path}\")\n",
|
||||
"\n",
|
||||
"# ── Lưu thông tin mô hình ──────────────────────────────────────────────────────\n",
|
||||
"info = {\n",
|
||||
" \"model_type\": \"SVM\",\n",
|
||||
" \"kernel\": model.kernel,\n",
|
||||
" \"C\": model.C,\n",
|
||||
" \"gamma\": model.gamma,\n",
|
||||
" \"probability\": model.probability,\n",
|
||||
" \"class_weight\": \"balanced\",\n",
|
||||
" \"n_features\": int(X_fit.shape[1]),\n",
|
||||
" \"label_mapping\": label_mapping,\n",
|
||||
" \"scaler\": scaler_path,\n",
|
||||
" \"test_accuracy\": float(acc),\n",
|
||||
" \"train_samples\": int(len(X_fit_scaled)),\n",
|
||||
" \"test_samples\": int(len(X_test_scaled)),\n",
|
||||
" \"saved_at\": datetime.now().isoformat(),\n",
|
||||
"}\n",
|
||||
"info_path = \"model_svm_land_use_info.json\"\n",
|
||||
"with open(info_path, \"w\") as f:\n",
|
||||
" json.dump(info, f, indent=2, ensure_ascii=False)\n",
|
||||
"print(f\"✅ Info saved → {info_path}\")\n",
|
||||
"print(json.dumps(info, indent=2, ensure_ascii=False))\n",
|
||||
"\n",
|
||||
"# ── Đóng kết nối Dask ──────────────────────────────────────────────────────────\n",
|
||||
"try:\n",
|
||||
" client.close()\n",
|
||||
" cluster.close()\n",
|
||||
" print(\"✅ Dask cluster closed.\")\n",
|
||||
"except Exception:\n",
|
||||
" pass\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"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
File diff suppressed because one or more lines are too long
@@ -1,6 +0,0 @@
|
||||
export AWS_ACCESS_KEY_ID="ASIA4YF43ZWIXQ6HJIAY"
|
||||
export AWS_SECRET_ACCESS_KEY="3N8KoV2ZBqQcFqRUVxQXW8K9sm90CNDV9aHUkNw0"
|
||||
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEO7//////////wEaDmFwLXNvdXRoZWFzdC0xIkcwRQIgR/6jnB1QIlWdCryDauBSFI34+KF256iV4X1Lyz4bP6YCIQCKE6A1q3jrlX9RFZ2hrFSOhdHKq187xD6yCUjnXOBkACrgBAi3//////////8BEAAaDDg3NjU2OTQxNTA1NyIMWcHZX71GMI7BdhDIKrQED9cJwWh4/DI3QG+W0jXsvCgvKnFTb+Yd690xdVxIrZuYsrmA+ncbp9Xj0GQSSay28XTBpG6Wgx8b2RSh3+ClJWvRJmvgxvOHpRAZqzgDB+0SJTWS1syeyGK9dlvL6VjI0LMw2r37m3mJzcUKvrVD8Hsg6iUT3FpPp0FKCbjpaSO9rZDXgxIGBwN/QbTNnD6wBwndYB0SI5QGHIIr2uW7IznKgXXY6sCq4uMjQDRULn6OO+ADSDBBahI/ZyhiTbUzL6LNjgvv0i9+Lots3xVg3Mp3yo8iKK5ILIVhmd/2QAX2uRQoLd9QRlChSQ4fwBKXEWN+A1UaPUfHRV0zudVmICBu+fk4lF3EWMkD/TRrkDCDRSBtMMa85m9yyxE7O0bSE/9gErDd/1zNNV1d64MRNrVhG4KWa6VnoOvvcupmgxmDV17db5o0tfFxa1TxHpkHsaTuCY0U8Q+Ep0da/LNdRkbiSoAjPNoAOoE+K5c7Z8g06Q13tTbvYQlDVIH1Kl3KtLlSDa6JUgWg0AMAFLJJCEEgBtLOL0nBuBujDOETnSXoIQjEJQkOvgWaiFP1A74hvXmpR39yOUzWCLRYhwXGt4xQW2NOYuHVFUdhu0rZ7XqHwzV6rYoBSP2uAZPw9diEZXYItgp2hHTAVEc0xEJp5hmBL94pPkpaMEwgOONW3QpqOj+Wg6yv7VPMY8FEEVEexHL1W134htZTgi8SMvx6M4M0oiL7caMy2tPkKF4o87ei6b3OMKnyoM0GOoMCneMKuFPe1C2TkcJ2qQ878F7c4ov/MtFZB3MsCMFXxm9Bx2Nj+v+nB9wQIxEUPA4/aS/zwYMTaYpHdNWJlQrMQllCfEIM9AmjX6GtP46bCPzzcawPlWYa88rGzQNKEEty1qJLJFIk8dK9ulImwIoOJ0aoRbaENYGUzWYJo6YM/yewVp6fm0MuULvlaOR9+tMxXfSc4leiXN6gk90fAW8SDUuaSHkCVphiH0dLnBf0cuzFyxFBMb3i8qNCFM6Mrnj1xPISYp/2PeGnAzEY/n56Cbaq/anT5BjwehAyUV1wPXW5Sdvgg1fygPbluQwtS1h7GxYFt72+GcusVabuXEmu9ab+AQ=="
|
||||
|
||||
Cognito: eyJraWQiOiIzejR4V0txYmd5Mlo4NXR3TFVvRGFSNmp4WVNSZUdKNHdLeEM4K0phbUM0PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJiMmM2ZmU5Ny02MGQ5LTQ1YmMtYTRlNy02ZTk1MDkwMmZlYjMiLCJjb2duaXRvOmdyb3VwcyI6WyJkZWZhdWx0LWdyb3VwIiwiYWxsb2NhdGlvbjpSLTE5MjQ0OkNTSVJPIGFuZCBWaWV0bmFtIHBhcnRuZXJzIl0sImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMS5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMV9DNEdDYllhT2EiLCJjbGllbnRfaWQiOiI2YTczMzJyOXRybGhxNmkyZmZwbDVma3JnNSIsIm9yaWdpbl9qdGkiOiJmNjczYjFjOS01NGQ3LTQ5MzYtODg4Yi1mMjJjZDU1YTBkNDYiLCJldmVudF9pZCI6IjRlZTUwZGNjLWEzYWMtNGMxYy04MjFhLTU2MGIwOGI0ZGFlYyIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3NzI2MzIzNTgsImV4cCI6MTc3MjY2MTE1OCwiaWF0IjoxNzcyNjMyMzU5LCJqdGkiOiJhYWMxMzFmMS1jZTc3LTRlMmMtOGQ2Zi1hNDc3MWM0ZTY3ZjUiLCJ1c2VybmFtZSI6ImhpZW5tMjUyMzAwMSJ9.N15e6a0MWQtdZWBIHpDC3rKcwjn9ATEo-WY7oaB1SV4m2u1j17ld_AlnkiplAFWq52viKjWEO8ArY4Okb9xMUraK_nV-YxkAuTv15_hG32Q-qbFWsholcJzc4jObCKc3NXPVolx8zFZn0r9nQoakCqGaQWCfshT3_ZPAMdhIisOn7Jq6jDWyTfivMQlbmCPNCxSR3Yqt6_UTs2pvLdTuyP7hEGyuk8u4F_FyMxZcmGRKwPeKeepjJ22HoDkcvL9rpWIKoMZ-SQABLGqXPAFUEOPuvfCYh6bcivcztwaLszW70zHUbJzJZmyY8wi0PViplg-CK31yTkBej3-ARaC9Zg
|
||||
ID: eyJraWQiOiJOMmdRc1c0S3o1YUltR3hGZEVJVmUxOUIxTWpZSmJPcG5kYUxKQUpNakxJPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJiMmM2ZmU5Ny02MGQ5LTQ1YmMtYTRlNy02ZTk1MDkwMmZlYjMiLCJjb2duaXRvOmdyb3VwcyI6WyJkZWZhdWx0LWdyb3VwIiwiYWxsb2NhdGlvbjpSLTE5MjQ0OkNTSVJPIGFuZCBWaWV0bmFtIHBhcnRuZXJzIl0sImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuYXAtc291dGhlYXN0LTEuYW1hem9uYXdzLmNvbVwvYXAtc291dGhlYXN0LTFfQzRHQ2JZYU9hIiwiY29nbml0bzp1c2VybmFtZSI6ImhpZW5tMjUyMzAwMSIsIm9yaWdpbl9qdGkiOiJmNjczYjFjOS01NGQ3LTQ5MzYtODg4Yi1mMjJjZDU1YTBkNDYiLCJhdWQiOiI2YTczMzJyOXRybGhxNmkyZmZwbDVma3JnNSIsImV2ZW50X2lkIjoiNGVlNTBkY2MtYTNhYy00YzFjLTgyMWEtNTYwYjA4YjRkYWVjIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3NzI2MzIzNTgsIm5hbWUiOiJIaWVuIFBoYW4iLCJleHAiOjE3NzI2NjExNTgsImlhdCI6MTc3MjYzMjM1OSwianRpIjoiMGViODczOTItNWZhMS00OTAwLWFiZmUtNzFmMWEyYjI1YzdiIiwiZW1haWwiOiJoaWVubTI1MjMwMDFAZ3N0dWRlbnQuY3R1LmVkdS52biJ9.QEoa4uJmmSk0qpOBi_a3RrCoqRu-oASbAHc24tgIuSeM_wcQsyTbKNbYdDS9P0n6JZf-wCiCknpsHl6TKiGDL3xDVguesm8ZPdyYkdgpCvE7EnyrCOSa01hcubAL-Z3_TMyUVs0WyDrJ3HS0YT-0Gig7m2y17oL44zwtrWwXcrTJMW94QimW5OMsDKZMn1oQKKGkBhC18FB4lNcerAh9tLknGfJQEseH6_5rJAeLJSwzXJBCfZjM_Yt-4ZmmB1ruNfiHUXfT2QRbBFRDcWcpA0gYJoROrm16tByyivwGcaV2BIRIiSKqi1NSRPdTNqOWmmYh-yufWFG8CdumGpX5ow
|
||||
File diff suppressed because one or more lines are too long
@@ -1,155 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "30681e56",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 🧪 Test Planetary Computer Connection\n",
|
||||
"\n",
|
||||
"Notebook này test kết nối và load dữ liệu từ Microsoft Planetary Computer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e32c8eca",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, '/media/x79/2A7D-FAA0/remote-sensing')\n",
|
||||
"\n",
|
||||
"from load_data_no_odc import load_sentinel2_stac, load_sentinel1_stac\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"print(\"✅ Module imported successfully\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "501dd8ef",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Small test area (1 month, small bbox)\n",
|
||||
"bbox = (105.8, 9.5, 106.0, 9.7) # Small area in Mekong Delta\n",
|
||||
"date_range = (\"2023-01-01\", \"2023-01-31\") # 1 month only\n",
|
||||
"\n",
|
||||
"print(f\"Test parameters:\")\n",
|
||||
"print(f\" Bbox: {bbox}\")\n",
|
||||
"print(f\" Date: {date_range}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "187e2c1a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Test Sentinel-2\n",
|
||||
"print(\"\\n\" + \"=\" * 70)\n",
|
||||
"print(\"Testing Sentinel-2 L2A\")\n",
|
||||
"print(\"=\" * 70)\n",
|
||||
"\n",
|
||||
"data_s2 = load_sentinel2_stac(\n",
|
||||
" bbox=bbox,\n",
|
||||
" date_range=date_range,\n",
|
||||
" bands=['red', 'green', 'blue', 'nir08', 'SCL'],\n",
|
||||
" resolution=60 # Lower resolution for faster test\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if data_s2 is not None:\n",
|
||||
" print(f\"\\n✅ SUCCESS! Sentinel-2 loaded\")\n",
|
||||
" print(f\" Dims: {dict(data_s2.dims)}\")\n",
|
||||
" print(f\" Vars: {list(data_s2.data_vars)}\")\n",
|
||||
"else:\n",
|
||||
" print(\"\\n❌ Failed to load Sentinel-2\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e688f3b9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Test Sentinel-1\n",
|
||||
"print(\"\\n\" + \"=\" * 70)\n",
|
||||
"print(\"Testing Sentinel-1 RTC\")\n",
|
||||
"print(\"=\" * 70)\n",
|
||||
"\n",
|
||||
"data_s1 = load_sentinel1_stac(\n",
|
||||
" bbox=bbox,\n",
|
||||
" date_range=date_range,\n",
|
||||
" bands=['vv', 'vh'],\n",
|
||||
" resolution=60 # Lower resolution for faster test\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if data_s1 is not None:\n",
|
||||
" print(f\"\\n✅ SUCCESS! Sentinel-1 loaded\")\n",
|
||||
" print(f\" Dims: {dict(data_s1.dims)}\")\n",
|
||||
" print(f\" Vars: {list(data_s1.data_vars)}\")\n",
|
||||
"else:\n",
|
||||
" print(\"\\n❌ Failed to load Sentinel-1\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "211796a7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Visualize if data loaded successfully\n",
|
||||
"if data_s2 is not None:\n",
|
||||
" print(\"\\n📊 Visualizing Sentinel-2 RGB composite...\")\n",
|
||||
" \n",
|
||||
" # Select first timestep\n",
|
||||
" rgb = data_s2[['red', 'green', 'blue']].isel(time=0)\n",
|
||||
" \n",
|
||||
" # Plot\n",
|
||||
" fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n",
|
||||
" \n",
|
||||
" rgb['red'].plot(ax=axes[0], cmap='Reds')\n",
|
||||
" axes[0].set_title('Red band')\n",
|
||||
" \n",
|
||||
" rgb['green'].plot(ax=axes[1], cmap='Greens')\n",
|
||||
" axes[1].set_title('Green band')\n",
|
||||
" \n",
|
||||
" rgb['blue'].plot(ax=axes[2], cmap='Blues')\n",
|
||||
" axes[2].set_title('Blue band')\n",
|
||||
" \n",
|
||||
" plt.tight_layout()\n",
|
||||
" plt.show()\n",
|
||||
" \n",
|
||||
" print(\"✅ Visualization complete!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d4e29a09",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ✅ Results\n",
|
||||
"\n",
|
||||
"Nếu cả 2 tests đều pass:\n",
|
||||
"- ✅ Kết nối Planetary Computer OK\n",
|
||||
"- ✅ Load Sentinel-2 OK\n",
|
||||
"- ✅ Load Sentinel-1 OK\n",
|
||||
"- ✅ Sẵn sàng sử dụng cho training!\n",
|
||||
"\n",
|
||||
"Next step: Sử dụng `01.train_DecisionTree_PlanetaryComputer.ipynb` để train model"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user