REMOTE SENSING

Earth Engine & Geemap: 로컬에서 훈련된 머신러닝 모델(scikit-learn) 사용법 소개

유병혁 2023. 8. 6. 06:54

안녕하세요? 이번 글은 Google Earth Engine geemap에서 로컬에서 훈련된 머신러닝 모델(scikit-learn) 사용법을 정리해 보겠습니다. 태안해안국립공원 지역의 Landsat 8호 위성영상을 대상으로 토지피복 분류를 다뤄보는 내용입니다. 해당 내용은 geemap 북 내용을 일부 수정, 보완한 것입니다.

 

6. Analyzing Geospatial Data — Geospatial Data Science with Earth Engine and Geemap

next 7. Exporting Earth Engine Data

book.geemap.org

일단, ee와 geemap과 함께 필요한 모듈을 가져오고, Earth Engine을 초기화하는 작업을 수행합니다.

import pandas as pd
from geemap import ml
from sklearn import ensemble

import ee
import geemap​
# Earth Engine 초기화
ee.Initialize()

scikit-learn을 사용하여 로컬에서 모델 훈련

특성(feature) 데이터와 레이블(label) 데이터를 지정하고 scikit-learn을 사용하여 로컬에서 랜덤 포레스트 분류기(RandomForestClassifier)를 훈련합니다. n_trees는 랜덤 포레스트 분류기에서 사용할 트리의 개수를 나타냅니다.

url = "https://raw.githubusercontent.com/gee-community/geemap/master/examples/data/rf_example.csv"
df = pd.read_csv(url)

# 데이터프레임을 CSV 파일로 저장
output_file = "rf_example.csv"
df.to_csv(output_file, index=False)

df

feature_names = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7']
label = "landcover"
X = df[feature_names]
y = df[label]
n_trees = 10

# scikit-learn을 사용하여 로컬에서 모델 훈련
rf = ensemble.RandomForestClassifier(n_trees).fit(X, y)

scikit-learn 분류기 객체를 문자열 리스트로 변환

scikit-learn 분류기 객체를 문자열 리스트로 변환한 후, 다시 해당 분류기를 GEE 분류기로 변환해 줍니다. 이러한 과정을 통해 로컬에서 훈련된 머신러닝 모델을 Google Earth Engine에서 사용할 수 있습니다.

# scikit-learn 분류기 객체를 문자열 리스트로 변환
trees = ml.rf_to_strings(rf, feature_names)
print(len(trees))
10
print(trees[0])
1) root 62 9999 9999 (1.163265306122449)
  2) B7 <= 0.019053 20 0.0000 2 *
  3) B7 > 0.019053 62 0.6633 0
    6) B2 <= 0.117214 21 0.0000 1 *
    7) B2 > 0.117214 21 0.0000 0 *
# sk-learn 분류기를 GEE 분류기로 변환
ee_classifier = ml.strings_to_classifier(trees)
ee_classifier.getInfo()
{'type': 'Classifier.decisionTreeEnsemble',
 'treeStrings': ['1) root 62 9999 9999 (1.163265306122449)\n  2) B7 <= 0.019053 20 0.0000 2 *\n  3) B7 > 0.019053 62 0.6633 0\n    6) B2 <= 0.117214 21 0.0000 1 *\n    7) B2 > 0.117214 21 0.0000 0 *\n',
  '1) root 61 9999 9999 (2.1215051779528844)\n  2) B6 <= 0.047678 21 0.0000 2 *\n  3) B6 > 0.047678 61 0.6645 0\n    6) B5 <= 0.204988 40 0.4956 0\n      12) B2 <= 0.110891 5 0.0000 1 *\n      13) B2 > 0.110891 15 0.0000 0 *\n    7) B5 > 0.204988 40 0.4956 0\n      14) B6 <= 0.255315 20 0.4043 1\n        28) B4 <= 0.109414 13 0.0000 1 *\n        29) B4 > 0.109414 3 0.0000 0 *\n      15) B6 > 0.255315 4 0.0000 0 *\n',
  '1) root 65 9999 9999 (2.931862729101076)\n  2) B2 <= 0.124305 65 0.6562 2\n    4) B4 <= 0.057878 44 0.5199 2\n      8) B3 <= 0.070845 4 0.0000 1 *\n      9) B3 > 0.070845 26 0.3200 2\n        18) B7 <= 0.037645 19 0.0000 2 *\n        19) B7 > 0.037645 3 0.0000 1 *\n    5) B4 > 0.057878 44 0.5199 2\n      10) B7 <= 0.030050 4 0.0000 2 *\n      11) B7 > 0.030050 18 0.5240 1\n        22) B4 <= 0.102578 9 0.0000 1 *\n        23) B4 > 0.102578 14 0.2550 1\n          46) B4 <= 0.121925 2 0.0000 0 *\n          47) B4 > 0.121925 3 0.0000 1 *\n  3) B2 > 0.124305 21 0.0000 0 *\n',
  '1) root 61 9999 9999 (1.7184977605963625)\n  2) B5 <= 0.071009 22 0.0000 2 *\n  3) B5 > 0.071009 61 0.6633 1\n    6) B3 <= 0.100830 18 0.0000 1 *\n    7) B3 > 0.100830 39 0.4938 1\n      14) B5 <= 0.311796 21 0.1748 0\n        28) B6 <= 0.263031 16 0.0000 0 *\n        29) B6 > 0.263031 20 0.0666 0\n          58) B4 <= 0.180226 1 0.0000 1 *\n          59) B4 > 0.180226 3 0.0000 0 *\n      15) B5 > 0.311796 1 0.0000 1 *\n',
  '1) root 67 9999 9999 (1.2142789660099749)\n  2) B5 <= 0.070122 26 0.0000 2 *\n  3) B5 > 0.070122 67 0.6591 2\n    6) B2 <= 0.116317 20 0.0000 1 *\n    7) B2 > 0.116317 41 0.4964 0\n      14) B6 <= 0.306811 20 0.0000 0 *\n      15) B6 > 0.306811 1 0.0000 1 *\n',
  '1) root 61 9999 9999 (1.535938124581055)\n  2) B5 <= 0.084699 24 0.0000 2 *\n  3) B5 > 0.084699 61 0.6516 2\n    6) B2 <= 0.128682 37 0.4875 0\n      12) B7 <= 0.118544 14 0.0000 1 *\n      13) B7 > 0.118544 18 0.0768 1\n        26) B6 <= 0.181488 1 0.0000 0 *\n        27) B6 > 0.181488 3 0.0000 1 *\n    7) B2 > 0.128682 19 0.0000 0 *\n',
  '1) root 70 9999 9999 (2.0373260123038595)\n  2) B6 <= 0.040969 26 0.0000 2 *\n  3) B6 > 0.040969 70 0.6574 1\n    6) B7 <= 0.116309 44 0.4813 1\n      12) B2 <= 0.115374 18 0.0000 1 *\n      13) B2 > 0.115374 5 0.0000 0 *\n    7) B7 > 0.116309 44 0.4813 1\n      14) B2 <= 0.128682 21 0.4170 0\n        28) B6 <= 0.186668 1 0.0000 0 *\n        29) B6 > 0.186668 6 0.0000 1 *\n      15) B2 > 0.128682 14 0.0000 0 *\n',
  '1) root 61 9999 9999 (1.4084234736818741)\n  2) B6 <= 0.038694 21 0.0000 2 *\n  3) B6 > 0.038694 61 0.6641 0\n    6) B2 <= 0.116759 19 0.0000 1 *\n    7) B2 > 0.116759 40 0.4942 0\n      14) B7 <= 0.188192 16 0.0000 0 *\n      15) B7 > 0.188192 21 0.0526 0\n        30) B2 <= 0.162857 1 0.0000 1 *\n        31) B2 > 0.162857 4 0.0000 0 *\n',
  '1) root 59 9999 9999 (1.1393393937099212)\n  2) B5 <= 0.071009 22 0.0000 2 *\n  3) B5 > 0.071009 59 0.6474 2\n    6) B2 <= 0.115278 18 0.0000 1 *\n    7) B2 > 0.115278 19 0.0000 0 *\n',
  '1) root 66 9999 9999 (1.1378508954602249)\n  2) B5 <= 0.064203 22 0.0000 2 *\n  3) B5 > 0.064203 66 0.6579 0\n    6) B2 <= 0.116759 21 0.0000 1 *\n    7) B2 > 0.116759 23 0.0000 0 *\n']}

Google Earth Engine(GEE) 분류기를 사용한 이미지 분류

 

Landsat 8 Datasets in Earth Engine  |  Earth Engine Data Catalog  |  Google for Developers

Landsat, a joint program of the USGS and NASA, has been observing the Earth continuously from 1972 through the present day. Today the Landsat satellites image the entire Earth's surface at a 30-meter resolution about once every two weeks, including multisp

developers.google.com

# GEE 분류기를 사용한 이미지 분류

# USGS Landsat 8 Collection 2 Tier 1 Raw Scenes
# https://developers.google.com/earth-engine/datasets/catalog/landsat-8
l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1')

ee.Algorithms.Landsat.simpleComposite는 GEE의 내장 함수로, 원시 Landsat 영상 컬렉션으로부터 Landsat TOA (Top of Atmosphere) 합성을 계산합니다.

 

표준 TOA 보정을 적용한 후, SimpleLandsatCloudScore 알고리즘을 사용하여 각 픽셀에 대해 구름 점수를 할당합니다. 각 지점에서 가능한 가장 낮은 범위(기본값: 10)의 구름 점수를 선택하고, 허용된 픽셀로부터 밴드별 백분위수 값(기본값: 50, 즉 중간값)을 계산합니다. 이 함수는 LandsatPathRowLimit 알고리즘을 사용하여 maxDepth(기본값: 40) 입력 씬보다 많은 지역에서는 가장 구름이 적은 씬만 선택합니다.

 

ee.Algorithms.Landsat.simpleComposite  |  Google Earth Engine  |  Google for Developers

projects.locations.filmstripThumbnails

developers.google.com

# cloud-free Landsat 8 TOA composite 생성
# https://developers.google.com/earth-engine/apidocs/ee-algorithms-landsat-simplecomposite
image = ee.Algorithms.Landsat.simpleComposite(
    collection=l8.filterDate('2022-01-01', '2022-12-31'), asFloat=True
)
Map = geemap.Map()

point = ee.Geometry.Point([126.2256, 36.6125])
Map.centerObject(point, 9)
Map.addLayer(
    image,
    {"bands": ['B7', 'B5', 'B3'], "min": 0.05, "max": 0.55, "gamma": 1.5},
    'image',
)
Map

Landsat TOA 합성 이미지(image)에서 특성 값(feature_names)에 해당하는 밴드들을 GEE 분류기(ee_classifier)를 사용하여 분류하고, 그 결과를 classified 변수에 저장합니다. 

classified = image.select(feature_names).classify(ee_classifier)
Map.addLayer(
    classified,
    {"min": 0, "max": 2, "palette": ['red', 'green', 'blue']},
    'classification',
)
Map

로컬 환경에 트리 모델 저장

scikit-learn 분류기를 문자열 리스트로 변환한 trees는 로컬에 저장 가능합니다. 필요시 GEE 분류기로 변환하여 재사용하시면 되겠습니다. 같은 방식으로 환경부 토지피복지도(https://egis.me.go.kr/intro/land.do)를 학습 데이터 생성 시 참고해 보시면 좋겠습니다. 

# trees를 로컬에 저장
out_csv = "trees.csv"
ml.trees_to_csv(trees, out_csv)
another_classifier = ml.csv_to_classifier(out_csv)
classified = image.select(feature_names).classify(another_classifier)

1913_geemap_로컬에서 훈련된 머신러닝 모델(scikit-learn) 사용법 소개.ipynb
0.02MB