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();
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();
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();
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);
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ả image
và 2
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));
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']));
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 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
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
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ư getInfo
và Export
(cũng như print
và phương thức trên Map
và Chart
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; });
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. });
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);
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);
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ặctoBands()
, 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);
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);
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' });
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);
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' });
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);
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);
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);
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());
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');
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);
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');
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);
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.