الگوریتمهایی که در Earth Engine ایجاد میکنید در Google Cloud اجرا میشوند و در رایانههای زیادی توزیع میشوند. اشکالزدایی میتواند چالشبرانگیز باشد زیرا خطاها میتوانند در کد سمت کارخواه یا اجرای سمت سرور دستورالعملهای کدگذاریشده رخ دهند و ناشی از مشکلات مقیاسبندی و همچنین خطاهای نحوی یا منطقی باشند. بخشهایی از برنامه که در جایی در فضای ابری اجرا میشوند برای بازرسی دردسترس نیستند، مگراینکه آنها را درخواست کنید. این سند راهبردها، ابزارها، و راهحلهای اشکالزدایی را ارائه میدهد تا به شما کمک کند خطاهای رایج را برطرف کنید و اسکریپتهای Earth Engine را اشکالزدایی کنید.
خطاهای نحو
خطاهای نحوی زمانی رخ میدهند که کد شما قوانین زبان برنامهنویسی را نقض کند (چه جاوا اسکریپت یا پایتون در Earth Engine). این خطاها مانع از اجرای کد شما میشوند و معمولاً قبلاز اجرا شناسایی میشوند. اگر با خطای نحوی مواجه شدید، خط برجستهشده یا پیام خطا را بهدقت بررسی کنید و به منابعی مانند مرجع زبان Python یا راهنمای سبک Google JavaScript مراجعه کنید. خطایاب نحوی کد نیز میتواند به شناسایی و رفع این مشکلات کمک کند.
خطاهای سمت کارخواه
باوجود کد صحیح ازنظر نحوی، ممکن است خطاهایی در ارتباط با سازگاری یا منطق دستورات وجود داشته باشد. مثالهای زیر خطاهای ناشی از استفاده از متغیر و روشی را نشان میدهند که وجود ندارند.
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
// Load a Sentinel-2 image. var image = ee.Image('NASA/NASADEM_HGT/001'); // 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('NASA/NASADEM_HGT/001') # 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()
اولین خطا به شما اطلاع میدهد که متغیر bandNames در دامنهای که به آن ارجاع داده شده است تعریف نشده است. بهعنوان راهحل، متغیر را تنظیم کنید یا
شناسه فهرست برای پارامتر bands ارائه دهید. خطای دوم نشان میدهد که وقتی تابع selfAnalyze() که وجود ندارد فراخوانی میشود چه اتفاقی میافتد. ازآنجاییکه
این روش واقعی برای تصاویر نیست، خطا به شما میگوید که این یک تابع نیست. در هر دو
مورد، خطا توصیفکننده مشکل است.
تبدیل نوع شیء ناشناخته
خطای «...is not a function» ممکن است ناشی از این باشد که Earth Engine
نوع متغیر را نمیداند. نمودهای رایج این مشکل ناشی از موارد زیر است:
- انجام کاری روی شیء برگرداندهشده توسط
first()(نوع عناصر در مجموعه ناشناخته است). - انجام کاری روی شیء برگرداندهشده توسط
get()(نوع عنصر ذخیرهشده در ویژگی ناشناخته است). - انجام کاری روی متغیر مستقل تابع (در تابع) وقتی نوع متغیر مستقل ناشناخته است.
برای مثال، در مورد اول:
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
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()
راهحل در همه موارد این است که شیء از نوع ناشناخته را با سازنده نوع شناختهشده قالببندی کنید. در ادامه مثال قبلی، راهحل این است که به
ee.Feature تبدیل شود:
راهحل — از گچگیری استفاده کنید!
ویرایشگر کد (جاوا اسکریپت)
var area = ee.Feature(collection.first()).area();
import ee import geemap.core as geemap
Colab (Python)
area = ee.Feature(collection.first()).area()
(شایان ذکر است که میتوانید با اطمینان هر روشی را در Element در اینجا فراخوانی کنید
زیرا Earth Engine فکر میکند این همان چیزی است که هست).
از ترکیب کردن توابع کلاینت و سرور خودداری کنید
مثال زیر کمتر واضح است:
خطا — این کد کاری را که میخواهید انجام نمیدهد
ویرایشگر کد (جاوا اسکریپت)
// Don't mix EE objects and JavaScript objects. var image = ee.Image('NASA/NASADEM_HGT/001'); 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('NASA/NASADEM_HGT/001') 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
با فرض اینکه نویسنده این کد قصد داشته 2 را به هر پیکسل در تصویر اضافه کند، این روش درستی برای انجام این کار نیست. بهطور خاص، این کد بهاشتباه یک شیء سمت سرور (image) را با یک عملگر سمت کارخواه (+) ترکیب میکند. نتایج ممکن است غافلگیرکننده باشد. در حالت اول، چاپ
nonsense در «ویرایشگر کد جاوا اسکریپت» عملیات درخواستی
(+) را با تبدیل کردن image و 2 به رشته
و سپس الحاق آنها انجام میدهد. رشته حاصل ناخواسته است (در Python، خطای TypeError ایجاد میشود).
در مورد دوم، با افزودن nonsense به نقشه، خطای مبهم g.eeObject.name is not a function در «ویرایشگر کد جاوا اسکریپت» نمایش داده میشود زیرا شیء اضافهشده به نقشه، nonsense، یک رشته است، نه یک شیء EE (در Python، خطای TypeError ایجاد میشود). برای جلوگیری از نتایج ناخواسته احتمالی و
خطاهای غیرآموزنده، اشیاء و توابع سرور را با اشیاء، اصول،
یا توابع کارخواه ترکیب نکنید. راه حل این مثال استفاده از تابع سرور است.
راهحل — از تابع سرور استفاده کنید!
ویرایشگر کد (جاوا اسکریپت)
Map.addLayer(image.add(2));
import ee import geemap.core as geemap
Colab (Python)
m = geemap.Map() m.add_layer(image.add(2)) m
برای جزئیات بیشتر، به صفحه مشتری دربرابر سرور مراجعه کنید.
قفل مرورگر ویرایشگر کد جاوا اسکریپت
وقتی جاوا اسکریپت درحال اجرا در کارخواه بیشازحد طول بکشد یا وقتی منتظر چیزی از Earth Engine باشد، ممکن است مرورگر متوقف یا قفل شود. دو منبع رایج این خطا عبارتند از
حلقههای for و/یا getInfo() در کد «ویرایشگر کد جاوا اسکریپت» شما، با
بدترین سناریو getInfo() در داخل یک حلقه for. حلقههای For میتوانند باعث قفل شدن مرورگر شوند زیرا کد در دستگاه شما اجرا میشود. ازسوی دیگر،
getInfo() بهطور همزمان نتیجه محاسبات را از Earth Engine درخواست میکند،
و تا زمانی که نتیجه دریافت نشود، مسدود میشود. اگر محاسبه زمان زیادی طول بکشد، مسدود کردن
میتواند باعث قفل شدن مرورگرتان شود. هنگام کار در «ویرایشگر کد»، از حلقههای for و getInfo() اجتناب کنید. برای جزئیات بیشتر، صفحه
مشتری درمقابل سرور را ببینید.
خطاهای سمت سرور
باوجود سازگاری منطقی در کد کارخواه، ممکن است اشکالاتی وجود داشته باشد که فقط در زمان اجرا در سرور آشکار میشوند. مثال زیر نشان میدهد که وقتی میخواهید باندی را که وجود ندارد دریافت کنید، چه اتفاقی میافتد.
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
// 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())
در این مثال، خطا به شما اطلاع میدهد که باندی بهنام
nonBand وجود ندارد. راهحل احتمالاً واضح این است که نام گروهی را مشخص کنید که
وجود دارد. میتوانید نام باندها را با چاپ تصویر و بررسی آن در کنسول، یا با چاپ فهرست نام باندهای برگرداندهشده توسط image.bandNames() پیدا کنید.
تغییرناپذیری
اشیاء سمت سروری که در Earth Engine ایجاد میکنید
تغییرناپذیر هستند. (هر
ee.Object یک Object سمت سرور است). یعنی اگر
بخواهید تغییری در شیء ایجاد کنید، باید حالت تغییریافته را در متغیر جدیدی
ذخیره کنید. برای مثال، این روش برای تنظیم ویژگی در تصویر Sentinel-2 کار نخواهد کرد:
خطا — این کد کاری را که میخواهید انجام نمیدهد!
ویرایشگر کد (جاوا اسکریپت)
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
در این مثال، s2image.set() نسخهای از تصویر را با ویژگی جدید برمیگرداند، اما تصویر ذخیرهشده در متغیر s2image بدون تغییر باقی میماند. باید
تصویر برگرداندهشده توسط s2image.set() را در متغیر جدیدی ذخیره کنید. برای مثال:
راهحل — نتیجه را در یک متغیر ضبط کنید!
ویرایشگر کد (جاوا اسکریپت)
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
توابع نگاشتهشده
زمینه دیگری که در آن توابع کارخواه و سرور باهم ترکیب نمیشوند در توابع
نگاشتشده است. بهطور مشخص، عملیات تعیینشده توسط تابع نگاشتشده در فضای ابری اجرا میشود،
بنابراین توابع کارخواه مانند getInfo و Export
(و همچنین print و روش در Map و Chart در
«ویرایشگر کد جاوا اسکریپت») در توابع نگاشتشده کار نخواهند کرد. برای مثال:
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
var collection = ee.ImageCollection('MODIS/061/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/061/MOD44B') # Error: A mapped function's arguments cannot be used in client-side operations. bad_map_3 = collection.map(lambda image: print(image.getInfo()))
این خطای تاحدودی مبهم ناشی از فرایندی است که Earth Engine برای تبدیل این کد به مجموعهای از دستورالعملها استفاده میکند که میتوانند در سرورهای Google اجرا شوند. از توابع سمت کارخواه و ساختارهای کنترلی نمیتوان برای اعمال روی تصویر متغیر مستقل ارسالشده به تابع نگاشتشده استفاده کرد. برای جلوگیری از این خطا، از توابع سمت کارخواه در توابع نگاشتشده استفاده نکنید. برای کسب اطلاعات بیشتر درباره تفاوت بین عملکردهای کارخواه و سرور، به صفحه کارخواه درمقابل سرور مراجعه کنید.
توابع نگاشتشده الزامات دیگری دارند. برای مثال، توابع نگاشتشده باید چیزی را برگردانند:
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
var collection = ee.ImageCollection('MODIS/061/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/061/MOD44B') # Error: User-defined methods must return a value. bad_map_1 = collection.map(lambda image: None)
راهحل احتمالاً واضح این است که چیزی را برگردانید. اما نمیتواند هر نوع چیزی را برگرداند. بهطور دقیقتر، توابع نگاشتشده روی ImageCollection یا
FeatureCollection باید Image یا
Feature برگردانند. برای مثال، نمیتوانید تاریخی را از تابعی که روی ImageCollection نگاشت شده است برگردانید:
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
var collection = ee.ImageCollection('MODIS/061/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/061/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())
برای جلوگیری از این مشکل، تصویر ورودی را با مجموعه دارایی جدیدی برگردانید. سپس، اگر به فهرستی از تاریخهای تصاویر موجود در مجموعه نیاز دارید، میتوانید از aggregate_array() استفاده کنید:
راهحل — یک خصوصیت تنظیم کنید!
ویرایشگر کد (جاوا اسکریپت)
var collection = ee.ImageCollection('MODIS/061/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/061/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())
خطاهای رویهای
الگو روی تصویری بدون باند اعمال شد
خطای "Pattern 'my_band' was applied to an Image with no bands"
به این معنی است که فراخوانی ee.Image.select() برای «تصویر»
با فهرست باند خالی وجود دارد. برای رسیدگی به این موضوع میتوانید این کارها را انجام دهید:
- اگر تصویر از ImageCollection با کاهنده یا بااستفاده از فراخوانیهای
first()یاtoBands()تولید شده است، مطمئن شوید که مجموعه منبع خالی نباشد. - اگر تصویر از واژهنامهای بااستفاده از
ee.Dictionary().toImage()تولید شده است، مطمئن شوید واژهنامه خالی نباشد. - اگر تصویر مستقل است، مطمئن شوید داده داشته باشد (و فقط
ee.Image(0)نباشد).
خطاهای مقیاسبندی
اگرچه ممکن است یک اسکریپت ازنظر نحوی صحیح باشد، بدون خطاهای منطقی باشد، و مجموعه معتبری از دستورالعملها را برای سرور نشان دهد، اما در موازیسازی و اجرای محاسبات، اشیای حاصل ممکن است خیلی بزرگ، خیلی زیاد، یا محاسبه آنها خیلی طولانی باشد. در این حالت، خطایی دریافت خواهید کرد که نشان میدهد الگوریتم نمیتواند مقیاسبندی شود. این خطاها معمولاً سختترین خطاها برای تشخیص و حلوفصل هستند. نمونههایی از این نوع خطا عبارتند از:
- مهلت زمانی محاسبه تمام شد
- تعداد تجمیعهای همزمان بسیار زیاد است
- از حد مجاز حافظه کاربر بیشتر است
- خطای داخلی روی داد
بهبود مقیاسبندی کدتان به شما امکان میدهد نتایج را سریعتر دریافت کنید و همچنین
دسترسی به منابع محاسباتی را برای همه کاربران بهبود میبخشد. هر نوع خطا در بخشهای زیر مورد بحث قرار میگیرد، بهدنبال یک توضیح مختصر درباره reduceRegion()، یک تابع پرکاربرد که بهدلیل توانایی ایجاد هر نوع خطای مقیاسبندی بدنام است.
reduceRegion()
اگرچه reduceRegion() با حرص پیکسلهای کافی را مصرف میکند تا تنوع هیجانانگیزی از خطاها را ایجاد کند، پارامترهایی نیز برای کنترل محاسبات وجود دارد تا بتوانید بر خطاها غلبه کنید. برای مثال، کاهش غیرقابلتوصیه زیر را درنظر بگیرید:
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
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())
این مثال ساده فقط برای نمایش است. هدف از این خطا این است که از شما بپرسد آیا واقعاً میخواهید ۸۰۳۰۰۳۴۸۱۱۷ (یعنی ۸۰ میلیارد) پیکسل را کاهش دهید. اگر نه، scale (اندازه پیکسل به متر) را بهطور مناسب افزایش دهید، یا
bestEffort را روی true تنظیم کنید تا مقیاس بزرگتری بهطور خودکار دوباره محاسبه شود. برای جزئیات بیشتر درباره این پارامترها،
صفحه reduceRegion() را
ببینید.
مهلت زمانی محاسبه تمام شد
فرض کنید به همه آن پیکسلها در محاسباتتان نیاز دارید. اگر اینطور است، میتوانید پارامتر
maxPixels را افزایش دهید تا محاسبه با موفقیت انجام شود. بااینحال،
مدتی طول میکشد تا Earth Engine محاسبات را تمام کند. درنتیجه، ممکن است خطای «مهلت زمانی محاسبه تمام شد» ایجاد شود:
بد — این کار را نکنید!
ویرایشگر کد (جاوا اسکریپت)
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())
این خطا به این معنی است که Earth Engine حدود پنج دقیقه قبلاز توقف محاسبات منتظر مانده است. صادر کردن به Earth Engine اجازه میدهد محاسبات را در محیطی با زمان اجرای مجاز طولانیتر (اما نه حافظه بیشتر) انجام دهد. ازآنجاییکه مقدار برگشتی
از reduceRegion() یک فرهنگ لغت است، میتوانید از فرهنگ لغت برای تنظیم
ویژگیهای یک عارضه با هندسه تهی استفاده کنید:
خوب — از Export استفاده کنید!
ویرایشگر کد (جاوا اسکریپت)
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()
تعداد تجمیعهای همزمان بسیار زیاد است
بخش «انبوهشها» در این خطا به عملیاتی اشاره دارد که در چندین ماشین توزیع شدهاند (مانند کاهشهایی که بیش از یک کاشی را دربرمیگیرند). Earth Engine محدودیتهایی دارد تا از اجرای همزمان تعداد زیادی از این تجمیعها جلوگیری کند. در این مثال، خطای «تعداد تجمیعهای همزمان بسیار زیاد است» با کاهش در نقشه راهاندازی میشود:
بد — این کار را نکنید!
ویرایشگر کد (جاوا اسکریپت)
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())
با فرض اینکه هدف این کد دریافت آمار تصویر برای هر تصویر است، یک
راهحل ممکن این است که نتیجه را Export کنید. برای مثال، بااستفاده از این واقعیت که ImageCollection FeatureCollection نیز هست، فرادادههای مرتبط با تصاویر را میتوان بهصورت جدول صادر کرد:
خوب — از Export استفاده کنید!
ویرایشگر کد (جاوا اسکریپت)
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()
از حد مجاز حافظه کاربر بیشتر است
یکی از روشهای موازیسازی الگوریتمها در Earth Engine تقسیم ورودیها به کاشی، اجرای جداگانه محاسبات یکسان روی هر کاشی، و سپس ترکیب نتایج است. As a consequence, all of the inputs necessary to compute an output tile have to fit into memory. برای مثال، وقتی ورودی تصویری با باندهای زیاد است، اگر از همه باندها در محاسبات استفاده شود، ممکن است حافظه زیادی مصرف شود. برای نمایش، این مثال با اجبار (غیرضروری) کل مجموعه تصویر به یک کاشی، از حافظه بسیار زیادی استفاده میکند:
بد — این کار را نکنید!
ویرایشگر کد (جاوا اسکریپت)
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())
این کد بسیار بد نشان میدهد که چرا نباید از آرایهها استفاده کنید، مگراینکه واقعاً نیاز داشته باشید (همچنین به بخش «از تبدیل غیرضروری نوع اجتناب کنید» مراجعه کنید). وقتی آن مجموعه به آرایهای عظیم تبدیل میشود، آرایه باید بهطور کامل و یکباره در حافظه بار شود. چون این سری زمانی تصاویر طولانی است، آرایه بزرگ است و در حافظه جا نمیشود.
یک راهحل ممکن این است که پارامتر tileScale را روی مقدار بالاتری تنظیم کنید. مقادیر بالاتر tileScale منجر به کاشیهای کوچکتر با ضریب
tileScale^2 میشود. برای مثال، مورد زیر به محاسبات اجازه میدهد
موفق شود:
ویرایشگر کد (جاوا اسکریپت)
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())
بااینحال، راهحل بسیار ترجیحی این است که از آرایهها بهطور غیرضروری استفاده نکنید، بنابراین اصلاً نیازی به دستکاری tileScale ندارید:
خوب — از آرایهها اجتناب کنید!
ویرایشگر کد (جاوا اسکریپت)
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())
مگر اینکه برای حل خطای حافظه لازم باشد، نباید tileScale را تنظیم کنید
چون کاشیهای کوچکتر نیز منجر به سربار موازیسازی بزرگتر میشوند.
خطاهای داخلی
ممکن است با خطایی مواجه شوید که شبیه این است:
اگر این خطا را دریافت کردید، روی پیوند «گزارش خطا» که در کنسول «ویرایشگر کد جاوا اسکریپت» ظاهر میشود کلیک کنید. همچنین میتوانید از دکمه راهنما، بازخورد ارسال کنید. این خطا میتواند ناشی از خطاهای منطقی در اسکریپت شما باشد که فقط در زمان اجرا آشکار میشوند یا مشکلی در عملکرد داخلی Earth Engine. در هر دو حالت، خطا غیرآموزنده است و باید گزارش شود تا بتوان آن را برطرف کرد.
خطاهای داخلی شامل شناسه request هستند، مانند موارد زیر:
این رشتهها بهعنوان شناسههای منحصربهفرد عمل میکنند تا به تیم Earth Engine کمک کنند مشکلات خاص را شناسایی کند. این رشته را در گزارشهای اشکال اضافه کنید.
روشهای اشکالزدایی
تحلیلتان را کدگذاری کردید، آن را اجرا کردید، و خطایی دریافت کردید. حالا چه؟ این بخش روشهای کلی اشکالزدایی را برای جداسازی مشکل و رفع آن شرح میدهد.
بررسی متغیرها و لایههای نقشه
فرض کنید تحلیل بسیار پیچیدهای دارید که خطایی ایجاد میکند. اگر مشخص نیست که خطا از کجا ناشی میشود، یک استراتژی اولیه خوب این است که اشیاء میانی را چاپ یا تجسم کنید و آنها را بررسی کنید تا مطمئن شوید که ساختار شیء با منطق موجود در اسکریپت شما سازگار است. بهطور خاص، میتوانید مقادیر پیکسل لایههای اضافهشده به نقشه را با Code Editor یا ابزارهای بازرس geemap بازرسی کنید. اگر چیزی را چاپ میکنید، حتماً ویژگیهای آن را با دکمههای بازشونده (▶) گسترش دهید. برخیاز مواردی که باید بررسی کنید عبارتند از:
- نام گروههای موسیقی. آیا نامهای باند تصویر با کد شما مطابقت دارد؟
- مقادیر پیکسل. آیا دادههایتان محدوده درستی دارد؟ آیا بهدرستی پنهان شده است؟
- تهی. آیا چیزی که نباید تهی باشد، تهی است؟
- اندازهها. آیا اندازه صفر است درحالیکه نباید باشد؟
aside()
قرار دادن هر مرحله میانی در یک تحلیل در یک متغیر میتواند دشوار باشد تا بتوان آن را چاپ و بررسی کرد. برای چاپ مقادیر میانی از زنجیره طولانی
فراخوانیهای تابع، میتوانید از روش aside() استفاده کنید. برای مثال:
ویرایشگر کد (جاوا اسکریپت)
var image = ee.Image(ee.ImageCollection('COPERNICUS/S2_HARMONIZED') .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() )
فقط بهخاطر داشته باشید که aside(print) (ویرایشگر کد جاوا اسکریپت) و
aside(display) (Python geemap) توابع سمت کارخواه را فراخوانی میکنند و همچنان
در توابع نگاشتشده ناموفق خواهند بود. همچنین میتوانید از aside
با توابع تعریفشده توسط کاربر استفاده کنید. برای مثال:
ویرایشگر کد (جاوا اسکریپت)
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
درحال اجرای تابع در first()
چاپ و تجسم برای اشکالزدایی درصورت دردسترس بودن مفید هستند، اما وقتی درحال اشکالزدایی تابعی هستید که روی مجموعهای نگاشت شده است، نمیتوانید در تابع چاپ کنید، همانطور که در بخش توابع نگاشتشده توضیح داده شده است. در این مورد، مفید است که عناصر مشکلساز را در مجموعه جدا کنید و تابع نگاشتشده را روی یک عنصر تکی آزمایش کنید. وقتی تابع را بدون نگاشت کردن آن آزمایش میکنید، میتوانید از عبارتهای چاپ برای درک مشکل استفاده کنید. مثال زیر را درنظر بگیرید.
خطا — این کد کار نمیکند!
ویرایشگر کد (جاوا اسکریپت)
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())
برای اشکالزدایی این مورد، بررسی خطا آموزنده است. خوشبختانه، این خطای مفید
به شما اطلاع میدهد که مشکلی در ویژگی با ID=2 وجود دارد. برای
بررسی بیشتر، بازسازی کردن کد میتواند مفید باشد. بهطور خاص، نمیتوانید
عبارتهای چاپ را در تابع داشته باشید وقتی که روی مجموعهای نگاشت شده است، همانطور که در
این بخش توضیح داده شده است. هدف از اشکالزدایی، جداسازی ویژگی مشکلساز و اجرای تابع با چند عبارت چاپی در آن است. با همان تصویر و ویژگیهایی که قبلاً استفاده شده است:
ویرایشگر کد (جاوا اسکریپت)
// 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
اکنون، چون تابع فقط روی یک عارضه اجرا میشود، میتوانید یک فراخوانی چاپ (`display` برای
Python geemap) در داخل آن قرار دهید. شیء چاپشده را بررسی کنید تا متوجه شوید (آها!) شیء
برگرداندهشده توسط reduceRegion() برای هر باند دارای مقادیر تهی است. این توضیح میدهد که چرا تقسیم ناموفق است: چون نمیتوانید تهی را بر تهی تقسیم کنید. چرا در وهله اول تهی است؟
برای بررسی، تصویر ورودی و عارضه بد را به نقشه اضافه کنید و عارضه بد را در مرکز قرار دهید. با انجام این کار، متوجه میشوید که مشکل بهدلیل قرار گرفتن نقطه در خارج از
مرزهای تصویر است. براساس این یافته، کد اشکالزداییشده عبارت است از:
ویرایشگر کد (جاوا اسکریپت)
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)
تحلیلگر
نمایهساز اطلاعاتی درباره زمان EECU و استفاده از حافظه (بهازای هر الگوریتم و دارایی) ارائه میدهد که از محاسبات انجامشده درحین فعال بودن آن حاصل میشود. برای اطلاعات درباره عملیاتهایی که بیشترین منابع را مصرف میکنند، ورودیهای بالای نمایهساز را بررسی کنید. برای اسکریپتهای طولانی یا ناکارآمد، ورودیهای بالای نمایهساز سرنخهایی درباره اینکه تلاشها برای بهینهسازی اسکریپت باید روی کجا متمرکز شود ارائه میدهند. نکته مهم: خود نمایهساز بر عملکرد اسکریپت تأثیر میگذارد، بنابراین فقط درصورت لزوم باید آن را اجرا کنید.