Hướng dẫn gỡ lỗi

Các thuật toán bạn tạo trong Earth Engine chạy trong đám mây của Google, được phân phối trên nhiều máy tính. Việc gỡ lỗi có thể gặp nhiều thách thức vì lỗi có thể xảy ra trong mã phía máy khách hoặc quá trình thực thi phía máy chủ của các lệnh được mã hoá, đồng thời là kết quả của các vấn đề về quy mô cũng như lỗi cú pháp hoặc logic. Bạn không thể kiểm tra các bit của chương trình đang chạy ở đâu đó trên đám mây, trừ phi bạn yêu cầu. Tài liệu này trình bày các chiến lược, công cụ và giải pháp gỡ lỗi để giúp bạn giải quyết các lỗi thường gặp và gỡ lỗi tập lệnh Earth Engine.

Lỗi cú pháp

Lỗi cú pháp xảy ra khi mã của bạn vi phạm quy tắc của ngôn ngữ lập trình (JavaScript hoặc Python trong Earth Engine). Các lỗi này ngăn mã của bạn chạy và thường được phát hiện trước khi thực thi. Nếu bạn gặp lỗi cú pháp, hãy xem xét kỹ dòng được làm nổi bật hoặc thông báo lỗi và tham khảo các tài nguyên như Tài liệu tham khảo ngôn ngữ Python hoặc Hướng dẫn về kiểu JavaScript của Google. Trình tìm lỗi mã nguồn cũng có thể giúp xác định và khắc phục các vấn đề này.

Lỗi phía máy khách

Mặc dù mã có cú pháp chính xác, nhưng có thể vẫn có lỗi liên quan đến tính nhất quán hoặc logic của tập lệnh. Các ví dụ sau đây minh hoạ lỗi khi sử dụng một biến và phương thức không tồn tại.

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

// Load a Sentinel-2 image.
var image = ee.Image('USGS/SRTMGL1_003');

// Error: "bandNames" is not defined in this scope.
var display = image.visualize({bands: bandNames, min: 0, max: 9000});

// Error: image.selfAnalyze is not a function
var silly = image.selfAnalyze();

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

# Load a Sentinel-2 image.
image = ee.Image('USGS/SRTMGL1_003')

# NameError: name 'band_names' is not defined.
display = image.visualize(bands=band_names, min=0, max=9000)

# AttributeError: 'Image' object has no attribute 'selfAnalyze'.
silly = image.selfAnalyze()

Lỗi đầu tiên cho bạn biết rằng biến bandNames không được xác định trong phạm vi được tham chiếu. Để giải quyết vấn đề này, hãy đặt biến hoặc cung cấp đối số danh sách cho tham số bands. Lỗi thứ hai minh hoạ điều gì xảy ra khi hàm selfAnalyze() không tồn tại được gọi. Vì đó không phải là một phương thức thực trên hình ảnh, nên lỗi này cho bạn biết rằng đó không phải là một hàm. Trong cả hai trường hợp, lỗi đều mô tả vấn đề.

Truyền kiểu đối tượng không xác định

Lỗi "...is not a function" có thể là do Earth Engine không biết loại biến. Vấn đề này thường xuất hiện do:

  • Làm gì đó với đối tượng do first() trả về (không xác định được loại phần tử trong một tập hợp).
  • Thực hiện một thao tác nào đó đối với đối tượng do get() trả về (không xác định được loại phần tử được lưu trữ trong thuộc tính).
  • Thực hiện một thao tác nào đó đối với đối số hàm (trong hàm) khi không xác định được loại đối số.

Ví dụ về trường hợp trước:

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017');

// Error: collection.first(...).area is not a function
var area = collection.first().area();

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')

# AttributeError: 'Element' object has no attribute 'area'.
area = collection.first().area()

Giải pháp trong mọi trường hợp là truyền đối tượng thuộc loại không xác định bằng hàm khởi tạo thuộc loại đã biết. Tiếp tục ví dụ trước, giải pháp là truyền vào ee.Feature:

Giải pháp — sử dụng một dàn diễn viên!

Trình soạn thảo mã (JavaScript)

var area = ee.Feature(collection.first()).area();

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

area = ee.Feature(collection.first()).area()

(Xin lưu ý rằng bạn có thể gọi bất kỳ phương thức nào trên Element ở đây một cách an toàn vì đó là những gì Earth Engine cho là phương thức).

Tránh kết hợp các hàm máy khách và máy chủ

Ví dụ sau đây ít rõ ràng hơn:

Lỗi – mã này không thực hiện được việc bạn muốn

Trình soạn thảo mã (JavaScript)

// Don't mix EE objects and JavaScript objects.
var image = ee.Image('USGS/SRTMGL1_003');
var nonsense = image + 2;

// You can print this, but it's not what you were hoping for.
print(nonsense);

// Error: g.eeObject.name is not a function
Map.addLayer(nonsense);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

# Don't mix EE objects and Python objects.
image = ee.Image('USGS/SRTMGL1_003')
nonsense = image + 2

# TypeError: unsupported operand type(s) for +: 'Image' and 'int'.
display(nonsense)

# TypeError: unsupported operand type(s) for +: 'Image' and 'int'.
m = geemap.Map()
m.add_layer(nonsense)
m

Giả sử tác giả của mã này muốn thêm 2 vào mọi pixel trong hình ảnh, thì đây không phải là cách phù hợp để thực hiện việc này. Cụ thể, mã này kết hợp nhầm đối tượng phía máy chủ (image) với toán tử phía máy khách (+). Kết quả có thể gây ngạc nhiên. Trong trường hợp đầu tiên, việc in nonsense trong Trình soạn thảo mã JavaScript sẽ thực hiện thao tác được yêu cầu (+) bằng cách chuyển đổi cả image2 thành chuỗi, sau đó nối các chuỗi đó. Chuỗi kết quả là ngoài ý muốn (trong Python, một TypeError sẽ được gửi). Trong trường hợp thứ hai, khi thêm nonsense vào bản đồ, lỗi g.eeObject.name is not a function khó hiểu sẽ xuất hiện trong Trình chỉnh sửa mã JavaScript vì đối tượng đang được thêm vào bản đồ, nonsense, là một chuỗi, chứ không phải là đối tượng EE (trong Python, một TypeError sẽ được gửi). Để tránh kết quả có thể không mong muốn và lỗi không cung cấp thông tin, đừng kết hợp các đối tượng và hàm máy chủ với các đối tượng, hàm gốc hoặc hàm của máy khách. Giải pháp cho ví dụ này là sử dụng hàm máy chủ.

Giải pháp — sử dụng hàm máy chủ!

Trình soạn thảo mã (JavaScript)

Map.addLayer(image.add(2));

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

m = geemap.Map()
m.add_layer(image.add(2))
m

Hãy xem trang Máy khách so với máy chủ để biết thêm chi tiết.

Khoá trình duyệt của Trình soạn thảo mã JavaScript

Trình duyệt có thể bị treo hoặc khoá khi JavaScript chạy trong ứng dụng khách mất quá nhiều thời gian hoặc khi chờ một nội dung nào đó từ Earth Engine. Hai nguồn thường gặp gây ra lỗi này là vòng lặp for và/hoặc getInfo() trong mã của Trình soạn thảo mã JavaScript, với trường hợp xấu nhất là getInfo() bên trong vòng lặp for. Vòng lặp For có thể khiến trình duyệt bị khoá vì mã chạy trên máy của bạn. Mặt khác, getInfo() yêu cầu đồng bộ kết quả của một phép tính từ Earth Engine, chặn cho đến khi nhận được kết quả. Nếu quá trình tính toán mất nhiều thời gian, thì việc chặn có thể khiến trình duyệt của bạn bị khoá. Tránh cả vòng lặp for và getInfo() khi làm việc trong Trình soạn thảo mã. Hãy xem trang Máy khách so với máy chủ để biết thêm chi tiết.

Lỗi phía máy chủ

Mặc dù có tính nhất quán về logic trong mã ứng dụng, nhưng có thể có các lỗi chỉ xuất hiện rõ ràng tại thời điểm chạy trên máy chủ. Ví dụ sau đây minh hoạ những gì sẽ xảy ra khi cố gắng lấy một dải tần không tồn tại.

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

// Load a Sentinel-2 image.
var s2image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR');

// Error: Image.select: Pattern 'nonBand' did not match any bands.
print(s2image.select(['nonBand']));

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

# Load a Sentinel-2 image.
s2image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'
)

# EEException: Image.select: Band pattern 'non_band' did not match any bands.
print(s2image.select(['non_band']).getInfo())

Trong ví dụ này, lỗi sẽ thông báo cho bạn rằng không có dải nào có tên là nonBand. Giải pháp có thể dễ thấy là chỉ định tên ban nhạc tồn tại. Bạn có thể khám phá tên ban nhạc bằng cách in hình ảnh và kiểm tra hình ảnh đó trong bảng điều khiển hoặc bằng cách in danh sách tên ban nhạc do image.bandNames() trả về.

Tính bất biến

Các đối tượng phía máy chủ mà bạn tạo trong Earth Engine là immutable. (Mọi ee.Object đều là Object phía máy chủ). Điều đó có nghĩa là nếu muốn thay đổi đối tượng, bạn phải lưu trạng thái đã thay đổi vào một biến mới. Ví dụ: bạn không thể đặt thuộc tính trên hình ảnh Sentinel-2 bằng cách này:

Lỗi – mã này không làm được việc bạn muốn!

Trình soạn thảo mã (JavaScript)

var s2image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR');
s2image.set('myProperty', 'This image is not assigned to a variable');

// This will not result in an error, but will not find 'myProperty'.
print(s2image.get('myProperty')); // null

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

s2image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'
)
s2image.set('my_property', 'This image is not assigned to a variable')

# This will not result in an error, but will not find 'my_property'.
display(s2image.get('my_property'))  # None

Trong ví dụ này, s2image.set() trả về một bản sao của hình ảnh có thuộc tính mới, nhưng hình ảnh được lưu trữ trong biến s2image không thay đổi. Bạn cần lưu hình ảnh do s2image.set() trả về trong một biến mới. Ví dụ:

Giải pháp – ghi lại kết quả trong một biến!

Trình soạn thảo mã (JavaScript)

s2image = s2image.set('myProperty', 'OK');
print(s2image.get('myProperty')); // OK

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

s2image = s2image.set('my_property', 'OK')
display(s2image.get('my_property'))  # OK

Hàm được liên kết

Một ngữ cảnh khác mà các hàm máy khách và máy chủ không kết hợp là trong các hàm được ánh xạ. Cụ thể, các thao tác do hàm được liên kết chỉ định sẽ chạy trên đám mây, vì vậy, các hàm ứng dụng như getInfoExport (cũng như print và phương thức trên MapChart trong Trình soạn thảo mã JavaScript) sẽ không hoạt động trong các hàm được liên kết. Ví dụ:

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var collection = ee.ImageCollection('MODIS/006/MOD44B');

// Error: A mapped function's arguments cannot be used in client-side operations
var badMap3 = collection.map(function(image) {
  print(image);
  return image;
});

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.ImageCollection('MODIS/006/MOD44B')

# Error: A mapped function's arguments cannot be used in client-side operations.
bad_map_3 = collection.map(lambda image: print(image.getInfo()))

Lỗi hơi khó hiểu này là do quy trình mà Earth Engine sử dụng để biến mã này thành một tập hợp hướng dẫn có thể chạy trên máy chủ của Google. Không thể sử dụng các hàm phía máy khách và cấu trúc điều khiển để thao tác trên hình ảnh đối số được truyền đến hàm được ánh xạ. Để tránh lỗi này, hãy tránh sử dụng các hàm phía máy khách trong các hàm được liên kết. Hãy xem trang Máy khách so với máy chủ để tìm hiểu thêm về sự khác biệt giữa các hàm máy khách và máy chủ.

Hàm được liên kết có các yêu cầu bổ sung. Ví dụ: các hàm được liên kết phải trả về một giá trị nào đó:

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var collection = ee.ImageCollection('MODIS/006/MOD44B');

// Error: User-defined methods must return a value.
var badMap1 = collection.map(function(image) {
  // Do nothing.
});

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.ImageCollection('MODIS/006/MOD44B')

# Error: User-defined methods must return a value.
bad_map_1 = collection.map(lambda image: None)

Giải pháp có thể rõ ràng là trả về một giá trị nào đó. Tuy nhiên, hàm này không thể trả về bất kỳ loại đối tượng nào. Cụ thể, các hàm được liên kết trên ImageCollection hoặc FeatureCollection phải trả về Image hoặc Feature. Ví dụ: bạn không thể trả về ngày từ một hàm được liên kết trên ImageCollection:

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var collection = ee.ImageCollection('MODIS/006/MOD44B');

var badMap2 = collection.map(function(image) {
  return image.date();
});

// Error: Collection.map: A mapped algorithm must return a Feature or Image.
print(badMap2);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.ImageCollection('MODIS/006/MOD44B')

bad_map_2 = collection.map(lambda image: image.date())

# EEException: Collection.map:
# A mapped algorithm must return a Feature or Image.
print(bad_map_2.getInfo())

Để tránh điều này, hãy trả về hình ảnh đầu vào bằng một tập hợp thuộc tính mới. Sau đó, nếu cần danh sách ngày của hình ảnh trong bộ sưu tập, bạn có thể sử dụng aggregate_array():

Giải pháp — hãy đặt một thuộc tính!

Trình soạn thảo mã (JavaScript)

var collection = ee.ImageCollection('MODIS/006/MOD44B');

var okMap2 = collection.map(function(image) {
  return image.set('date', image.date());
});
print(okMap2);

// Get a list of the dates.
var datesList = okMap2.aggregate_array('date');
print(datesList);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.ImageCollection('MODIS/006/MOD44B')

ok_map_2 = collection.map(lambda image: image.set('date', image.date()))
print(ok_map_2.getInfo())

# Get a list of the dates.
dates_list = ok_map_2.aggregate_array('date')
print(dates_list.getInfo())

Lỗi quy trình

Mẫu được áp dụng cho một Hình ảnh không có dải

Lỗi "Pattern 'my_band' was applied to an Image with no bands" có nghĩa là có lệnh gọi ee.Image.select() cho một Hình ảnh có danh sách băng tần trống. Sau đây là những việc bạn có thể làm để giải quyết vấn đề này:

  • Nếu hình ảnh được tạo từ ImageCollection có một trình giảm hoặc sử dụng lệnh gọi first() hoặc toBands(), hãy đảm bảo rằng bộ sưu tập nguồn không trống.
  • Nếu hình ảnh được tạo từ một từ điển bằng cách sử dụng ee.Dictionary().toImage(), hãy đảm bảo từ điển không trống.
  • Nếu hình ảnh độc lập, hãy đảm bảo hình ảnh đó có dữ liệu (chứ không chỉ là ee.Image(0)).

Lỗi điều chỉnh theo tỷ lệ

Mặc dù một tập lệnh có thể chính xác về mặt cú pháp, không có lỗi logic và đại diện cho một tập lệnh hợp lệ cho máy chủ, nhưng trong quá trình song song hoá và thực thi phép tính, các đối tượng thu được có thể quá lớn, quá nhiều hoặc mất quá nhiều thời gian để tính toán. Trong trường hợp này, bạn sẽ gặp lỗi cho biết không thể mở rộng quy mô thuật toán. Đây thường là những lỗi khó chẩn đoán và giải quyết nhất. Sau đây là một số ví dụ về loại lỗi này:

  • Đã hết thời gian tính toán
  • Quá nhiều phép tổng hợp đồng thời
  • Đã vượt quá giới hạn bộ nhớ của người dùng
  • Đã xảy ra lỗi nội bộ

Việc cải thiện khả năng mở rộng mã sẽ giúp bạn nhận được kết quả nhanh hơn, đồng thời cải thiện khả năng sử dụng tài nguyên điện toán cho tất cả người dùng. Mỗi loại lỗi được thảo luận trong các phần sau, sau một phần ngắn về reduceRegion(), một hàm thường dùng và nổi tiếng là có thể gây ra mọi loại lỗi tỷ lệ.

reduceRegion()

Mặc dù reduceRegion() tham lam tiêu thụ đủ pixel để kích hoạt nhiều lỗi thú vị, nhưng cũng có các tham số dùng để kiểm soát quá trình tính toán để bạn có thể khắc phục các lỗi đó. Ví dụ: hãy xem xét việc giảm không nên dùng sau:

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var absurdComputation = ee.Image(1).reduceRegion({
  reducer: 'count',
  geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false),
  scale: 100,
});

// Error: Image.reduceRegion: Too many pixels in the region.
//        Found 80300348117, but only 10000000 allowed.
print(absurdComputation);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

absurd_computation = ee.Image(1).reduceRegion(
    reducer='count',
    geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False),
    scale=100,
)

# EEException: Image.reduceRegion: Too many pixels in the region.
#        Found 80300348117, but only 10000000 allowed.
print(absurd_computation.getInfo())

Ví dụ ngớ ngẩn này chỉ để minh hoạ. Mục đích của lỗi này là hỏi xem bạn thực sự muốn giảm 80300348117 (tức là 80 tỷ) pixel hay không. Nếu không, hãy tăng scale (kích thước pixel tính bằng mét) cho phù hợp hoặc đặt bestEffort thành true để tự động tính toán lại tỷ lệ lớn hơn. Hãy xem trang reduceRegion() để biết thêm thông tin chi tiết về các tham số này.

Đã hết thời gian tính toán

Giả sử bạn cần tất cả các pixel đó trong quá trình tính toán. Nếu có, bạn có thể tăng tham số maxPixels để cho phép quá trình tính toán thành công. Tuy nhiên, Earth Engine sẽ mất một khoảng thời gian để hoàn tất quá trình tính toán. Do đó, lỗi "computation timed out" ("hết thời gian tính toán") có thể xảy ra:

Không tốt — đừng làm như vậy!

Trình soạn thảo mã (JavaScript)

var ridiculousComputation = ee.Image(1).reduceRegion({
  reducer: 'count',
  geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false),
  scale: 100,
  maxPixels: 1e11
});

// Error: Computation timed out.
print(ridiculousComputation);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

ridiculous_computation = ee.Image(1).reduceRegion(
    reducer='count',
    geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False),
    scale=100,
    maxPixels=int(1e11),
)

# Error: Computation timed out.
print(ridiculous_computation.getInfo())

Lỗi này có nghĩa là Earth Engine đã chờ khoảng 5 phút trước khi dừng quá trình tính toán. Tính năng xuất cho phép Earth Engine thực hiện phép tính trong một môi trường có thời gian chạy được cho phép dài hơn (nhưng không có nhiều bộ nhớ hơn). Vì giá trị trả về từ reduceRegion() là một từ điển, nên bạn có thể sử dụng từ điển này để đặt các thuộc tính của một đối tượng có hình học rỗng:

Tốt — hãy sử dụng Export!

Trình soạn thảo mã (JavaScript)

Export.table.toDrive({
  collection: ee.FeatureCollection([
    ee.Feature(null, ridiculousComputation)
  ]),
  description: 'ridiculousComputation',
  fileFormat: 'CSV'
});

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

task = ee.batch.Export.table.toDrive(
    collection=ee.FeatureCollection([ee.Feature(None, ridiculous_computation)]),
    description='ridiculous_computation',
    fileFormat='CSV',
)
# task.start()

Quá nhiều phép tổng hợp đồng thời

Phần "aggregations" (tổng hợp) của lỗi này đề cập đến các thao tác được phân bổ trên nhiều máy (chẳng hạn như các thao tác giảm trên nhiều thẻ thông tin). Earth Engine có các giới hạn để ngăn việc chạy đồng thời quá nhiều phép tổng hợp như vậy. Trong ví dụ này, lỗi "Quá nhiều phép tổng hợp đồng thời" được kích hoạt do việc giảm trong một bản đồ:

Không tốt — đừng làm như vậy!

Trình soạn thảo mã (JavaScript)

var collection = ee.ImageCollection('LANDSAT/LT05/C02/T1')
    .filterBounds(ee.Geometry.Point([-123, 43]));

var terribleAggregations = collection.map(function(image) {
  return image.set(image.reduceRegion({
    reducer: 'mean',
    geometry: image.geometry(),
    scale: 30,
    maxPixels: 1e9
  }));
});

// Error: Quota exceeded: Too many concurrent aggregations.
print(terribleAggregations);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

collection = ee.ImageCollection('LANDSAT/LT05/C02/T1').filterBounds(
    ee.Geometry.Point([-123, 43])
)


def apply_mean_aggregation(image):
  return image.set(
      image.reduceRegion(
          reducer='mean',
          geometry=image.geometry(),
          scale=30,
          maxPixels=int(1e9),
      )
  )


terrible_aggregations = collection.map(apply_mean_aggregation)

# EEException: Computation timed out.
print(terrible_aggregations.getInfo())

Giả sử mục đích của mã này là lấy số liệu thống kê hình ảnh cho mỗi hình ảnh, một giải pháp có thể là Export kết quả. Ví dụ: sử dụng thực tế rằng ImageCollection cũng là FeatureCollection, siêu dữ liệu liên kết với hình ảnh có thể được xuất dưới dạng bảng:

Tốt — hãy sử dụng Export!

Trình soạn thảo mã (JavaScript)

Export.table.toDrive({
  collection: terribleAggregations,
  description: 'terribleAggregations',
  fileFormat: 'CSV'
});

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

task = ee.batch.Export.table.toDrive(
    collection=terrible_aggregations,
    description='terrible_aggregations',
    fileFormat='CSV',
)
# task.start()

Đã vượt quá giới hạn bộ nhớ của người dùng

Một cách để các thuật toán của bạn được chạy song song trong Earth Engine là chia dữ liệu đầu vào thành các ô, chạy riêng cùng một phép tính trên mỗi ô, sau đó kết hợp các kết quả. Do đó, tất cả dữ liệu đầu vào cần thiết để tính toán một thẻ thông tin đầu ra đều phải vừa với bộ nhớ. Ví dụ: khi dữ liệu đầu vào là một hình ảnh có nhiều dải tần, thì việc này có thể tốn nhiều bộ nhớ nếu tất cả các dải tần đều được sử dụng trong quá trình tính toán. Để minh hoạ, ví dụ này sử dụng quá nhiều bộ nhớ bằng cách buộc (không cần thiết) toàn bộ bộ sưu tập hình ảnh vào một thẻ thông tin:

Không tốt — đừng làm như vậy!

Trình soạn thảo mã (JavaScript)

var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
var memoryHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands)
  .toArray()
  .arrayReduce(ee.Reducer.mean(), [0])
  .arrayProject([1])
  .arrayFlatten([bands])
  .reduceRegion({
    reducer: 'mean',
    geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
    scale: 1,
    bestEffort: true,
  });

// Error: User memory limit exceeded.
print(memoryHog);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']
memory_hog = (
    ee.ImageCollection('LANDSAT/LT05/C02/T1')
    .select(bands)
    .toArray()
    .arrayReduce(ee.Reducer.mean(), [0])
    .arrayProject([1])
    .arrayFlatten([bands])
    .reduceRegion(
        reducer=ee.Reducer.mean(),
        geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
        scale=1,
        bestEffort=True,
    )
)

# EEException: User memory limit exceeded.
print(memory_hog.getInfo())

Mã rất tệ này minh hoạ một lý do không nên sử dụng mảng trừ phi bạn thực sự cần (xem thêm phần "Tránh chuyển đổi loại không cần thiết"). Khi bộ sưu tập đó được chuyển đổi thành một mảng khổng lồ, mảng này phải được tải vào bộ nhớ cùng một lúc. Vì là một chuỗi hình ảnh trong thời gian dài, nên mảng này có kích thước lớn và sẽ không vừa với bộ nhớ.

Một giải pháp có thể là đặt tham số tileScale thành giá trị cao hơn. Giá trị cao hơn của tileScale sẽ làm cho thẻ thông tin nhỏ hơn theo hệ số tileScale^2. Ví dụ: nội dung sau đây cho phép phép tính thành công:

Trình soạn thảo mã (JavaScript)

var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
var smallerHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands)
  .toArray()
  .arrayReduce(ee.Reducer.mean(), [0])
  .arrayProject([1])
  .arrayFlatten([bands])
  .reduceRegion({
    reducer: 'mean',
    geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
    scale: 1,
    bestEffort: true,
    tileScale: 16
  });

print(smallerHog);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']
smaller_hog = (
    ee.ImageCollection('LANDSAT/LT05/C02/T1')
    .select(bands)
    .toArray()
    .arrayReduce(ee.Reducer.mean(), [0])
    .arrayProject([1])
    .arrayFlatten([bands])
    .reduceRegion(
        reducer=ee.Reducer.mean(),
        geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
        scale=1,
        bestEffort=True,
        tileScale=16,
    )
)

print(smaller_hog.getInfo())

Tuy nhiên, giải pháp được ưu tiên hơn là không sử dụng mảng khi không cần thiết, vì vậy, bạn không cần phải xử lý tileScale:

Tốt – tránh sử dụng Mảng!

Trình soạn thảo mã (JavaScript)

var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
var okMemory = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands)
  .mean()
  .reduceRegion({
    reducer: 'mean',
    geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
    scale: 1,
    bestEffort: true,
  });

print(okMemory);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']
ok_memory = (
    ee.ImageCollection('LANDSAT/LT05/C02/T1')
    .select(bands)
    .mean()
    .reduceRegion(
        reducer=ee.Reducer.mean(),
        geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
        scale=1,
        bestEffort=True,
    )
)

print(ok_memory.getInfo())

Trừ khi cần thiết để giải quyết lỗi bộ nhớ, bạn không nên đặt tileScale vì các thẻ thông tin nhỏ hơn cũng dẫn đến mức hao tổn song song lớn hơn.

Lỗi nội bộ

Bạn có thể gặp lỗi như sau:

Nếu bạn gặp lỗi này, hãy nhấp vào đường liên kết "Báo lỗi" xuất hiện trong bảng điều khiển của Trình soạn thảo mã JavaScript. Bạn cũng có thể Gửi ý kiến phản hồi qua nút Trợ giúp. Lỗi này có thể là do lỗi logic trong tập lệnh của bạn chỉ xuất hiện rõ ràng trong thời gian chạy hoặc do sự cố với hoạt động bên trong của Earth Engine. Trong cả hai trường hợp, lỗi này không cung cấp thông tin và bạn nên báo cáo để khắc phục.

Lỗi nội bộ bao gồm mã request, như sau:

Các chuỗi này đóng vai trò là giá trị nhận dạng duy nhất để giúp nhóm Earth Engine xác định các vấn đề cụ thể. Thêm chuỗi này vào báo cáo lỗi.

Phương thức gỡ lỗi

Bạn đã lập trình phân tích, chạy phân tích và gặp lỗi. Bây giờ bạn phải làm gì? Phần này mô tả các kỹ thuật gỡ lỗi chung để tách riêng vấn đề và khắc phục vấn đề.

Kiểm tra biến và lớp bản đồ

Giả sử bạn có một dữ liệu phân tích rất phức tạp và dữ liệu đó tạo ra lỗi. Nếu không rõ nguồn gốc của lỗi, thì chiến lược ban đầu phù hợp là in hoặc trực quan hoá các đối tượng trung gian và kiểm tra các đối tượng đó để đảm bảo cấu trúc của đối tượng nhất quán với logic trong tập lệnh. Cụ thể, bạn có thể kiểm tra các giá trị pixel của các lớp được thêm vào bản đồ bằng Trình chỉnh sửa mã hoặc các công cụ kiểm tra geemap. Nếu bạn in nội dung nào đó, hãy nhớ mở rộng thuộc tính của nội dung đó bằng các tệp zip (▶). Một số điều cần kiểm tra bao gồm:

  • Tên ban nhạc. Tên ban nhạc trong hình ảnh có khớp với mã của bạn không?
  • Giá trị pixel. Dữ liệu của bạn có phạm vi phù hợp không? Thông tin này có được che giấu đúng cách không?
  • Rỗng. Có giá trị rỗng nào không nên có không?
  • Kích thước. Kích thước có bằng 0 khi không nên không?

aside()

Bạn có thể gặp khó khăn khi đặt mọi bước trung gian trong một quy trình phân tích vào một biến để có thể in và kiểm tra biến đó. Để in các giá trị trung gian từ một chuỗi dài các lệnh gọi hàm, bạn có thể sử dụng phương thức aside(). Ví dụ:

Trình soạn thảo mã (JavaScript)

var image = ee.Image(ee.ImageCollection('COPERNICUS/S2')
    .filterBounds(ee.Geometry.Point([-12.29, 168.83]))
    .aside(print)
    .filterDate('2011-01-01', '2016-12-31')
    .first());

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

image = ee.Image(
    ee.ImageCollection('COPERNICUS/S2_HARMONIZED')
    .filterBounds(ee.Geometry.Point([-12.29, 168.83]))
    .aside(display)
    .filterDate('2011-01-01', '2016-12-31')
    .first()
)

Chỉ cần nhớ rằng aside(print) (Trình soạn thảo mã JavaScript) và aside(display) (Python geemap) đang gọi các hàm phía máy khách và hàm này vẫn sẽ không thành công trong các hàm được liên kết. Bạn cũng có thể sử dụng aside với các hàm do người dùng xác định. Ví dụ:

Trình soạn thảo mã (JavaScript)

var composite = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
    .filterBounds(ee.Geometry.Point([106.91, 47.91]))
    .map(function(image) {
      return image.addBands(image.normalizedDifference(['B5', 'B4']));
    })
    .aside(Map.addLayer, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'collection')
    .qualityMosaic('nd');

Map.setCenter(106.91, 47.91, 11);
Map.addLayer(composite, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'composite');

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

m = geemap.Map()
m.set_center(106.91, 47.91, 11)

composite = (
    ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
    .filterBounds(ee.Geometry.Point([106.91, 47.91]))
    .map(lambda image: image.addBands(image.normalizedDifference(['B5', 'B4'])))
    .aside(m.add_layer, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'collection')
    .qualityMosaic('nd')
)

m.add_layer(composite, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'composite')
m

Chạy một hàm trên first()

Việc in và trực quan hoá rất hữu ích cho việc gỡ lỗi khi có thể, nhưng khi gỡ lỗi một hàm được liên kết trên một tập hợp, bạn không thể in trong hàm đó như mô tả trong phần hàm được liên kết. Trong trường hợp này, bạn nên tách riêng các phần tử có vấn đề trong tập hợp và kiểm thử hàm được ánh xạ trên một phần tử riêng lẻ. Khi kiểm thử hàm mà không liên kết hàm đó, bạn có thể sử dụng câu lệnh in để tìm hiểu vấn đề. Hãy xem ví dụ sau đây.

Lỗi – mã này không hoạt động!

Trình soạn thảo mã (JavaScript)

var image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU');

var someFeatures = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-2.02, 48.43])),
  ee.Feature(ee.Geometry.Point([-2.80, 48.37])),
  ee.Feature(ee.Geometry.Point([-1.22, 48.29])),
  ee.Feature(ee.Geometry.Point([-1.73, 48.65])),
]);

var problem = someFeatures.map(function(feature) {

  var dictionary = image.reduceRegion({
    reducer: 'first',
    geometry: feature.geometry(),
    scale: 10,
  });

  return feature.set({
    result: ee.Number(dictionary.get('B5'))
                .divide(dictionary.get('B4'))
  });
});

// Error in map(ID=2):
//  Number.divide: Parameter 'left' is required.
print(problem);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

image = ee.Image(
    'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU'
)

some_features = ee.FeatureCollection([
    ee.Feature(ee.Geometry.Point([-2.02, 48.43])),
    ee.Feature(ee.Geometry.Point([-2.80, 48.37])),
    ee.Feature(ee.Geometry.Point([-1.22, 48.29])),
    ee.Feature(ee.Geometry.Point([-1.73, 48.65])),
])


# Define a function to be mapped over the collection.
def function_to_map(feature):
  dictionary = image.reduceRegion(
      reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10
  )

  return feature.set(
      {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))}
  )


problem = some_features.map(function_to_map)

# EEException: Error in map(ID=2):
#  Number.divide: Parameter 'left' is required.
print(problem.getInfo())

Để gỡ lỗi này, bạn nên kiểm tra lỗi. May mắn thay, lỗi hữu ích này sẽ thông báo cho bạn rằng có vấn đề với tính năng ID=2. Để tìm hiểu thêm, bạn nên tái cấu trúc mã một chút. Cụ thể, bạn không thể có câu lệnh in trong hàm khi hàm đó được ánh xạ trên một bộ sưu tập, như mô tả trong phần này. Mục tiêu gỡ lỗi là tách riêng tính năng có vấn đề và chạy hàm với một số câu lệnh in trong đó. Với cùng một hình ảnh và các tính năng đã sử dụng trước đó:

Trình soạn thảo mã (JavaScript)

// Define a function to be mapped over the collection.
var functionToMap = function(feature) {

  var dictionary = image.reduceRegion({
    reducer: 'first',
    geometry: feature.geometry(),
    scale: 10,
  });

  // Debug:
  print(dictionary);

  return feature.set({
    result: ee.Number(dictionary.get('B5'))
                .divide(dictionary.get('B4'))
  });
};

// Isolate the feature that's creating problems.
var badFeature = ee.Feature(someFeatures
    .filter(ee.Filter.eq('system:index', '2'))
    .first());

// Test the function with print statements added.
functionToMap(badFeature);

// Inspect the bad feature in relation to the image.
Map.centerObject(badFeature, 11);
Map.addLayer(badFeature, {}, 'bad feature');
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 3000}, 'image');

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

# Define a function to be mapped over the collection.
def function_to_map(feature):
  dictionary = image.reduceRegion(
      reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10
  )

  # Debug:
  display(dictionary)

  return feature.set(
      {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))}
  )


# Isolate the feature that's creating problems.
bad_feature = ee.Feature(
    some_features.filter(ee.Filter.eq('system:index', '2')).first()
)

# Test the function with print statements added.
function_to_map(bad_feature)

# Inspect the bad feature in relation to the image.
m = geemap.Map()
m.center_object(bad_feature, 11)
m.add_layer(bad_feature, {}, 'bad feature')
m.add_layer(image, {'bands': ['B4', 'B3', 'B2'], 'max': 3000}, 'image')
m

Bây giờ, vì hàm này chỉ chạy trên một đối tượng, nên bạn có thể đặt lệnh gọi in (`display` cho Python geemap) vào bên trong. Kiểm tra đối tượng đã in để khám phá (aha!) rằng đối tượng do reduceRegion() trả về có giá trị rỗng cho mọi dải tần. Điều đó giải thích lý do phép chia không thành công: vì bạn không thể chia giá trị rỗng cho giá trị rỗng. Tại sao giá trị này lại rỗng? Để điều tra, hãy thêm hình ảnh đầu vào và đối tượng không hợp lệ vào bản đồ, đồng thời căn giữa đối tượng không hợp lệ. Khi làm như vậy, bạn sẽ phát hiện ra vấn đề là do điểm nằm ngoài giới hạn của hình ảnh. Dựa trên thông tin khám phá này, mã được gỡ lỗi là:

Trình soạn thảo mã (JavaScript)

var functionToMap = function(feature) {
  var dictionary = image.reduceRegion({
    reducer: 'first',
    geometry: feature.geometry(),
    scale: 10,
  });
  return feature.set({
    result: ee.Number(dictionary.get('B5'))
                .divide(dictionary.get('B4'))
  });
};

var noProblem = someFeatures
    .filterBounds(image.geometry())
    .map(functionToMap);

print(noProblem);

Thiết lập Python

Hãy xem trang Môi trường Python để biết thông tin về API Python và cách sử dụng geemap để phát triển tương tác.

import ee
import geemap.core as geemap

Colab (Python)

def function_to_map(feature):
  dictionary = image.reduceRegion(
      reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10
  )

  return feature.set(
      {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))}
  )


no_problem = some_features.filterBounds(image.geometry()).map(function_to_map)

display(no_problem)

Profiler

Trình phân tích tài nguyên cung cấp thông tin về thời gian EECU và mức sử dụng bộ nhớ (theo thuật toán và tài sản) do quá trình tính toán được thực hiện khi bật. Tìm các mục ở đầu trình phân tích tài nguyên để biết thông tin về các thao tác tốn nhiều tài nguyên nhất. Đối với các tập lệnh chạy trong thời gian dài hoặc không hiệu quả, các mục ở đầu trình phân tích tài nguyên sẽ cung cấp gợi ý về nơi cần tập trung nỗ lực để tối ưu hoá tập lệnh. Lưu ý quan trọng: chính trình phân tích tài nguyên sẽ ảnh hưởng đến hiệu suất của tập lệnh, vì vậy, bạn chỉ nên chạy trình phân tích tài nguyên khi cần.