الگوریتمهایی که در Earth Engine ایجاد میکنید در ابر Google اجرا میشوند و روی بسیاری از رایانهها توزیع شدهاند. اشکال زدایی می تواند چالش برانگیز باشد زیرا خطاها می توانند در کد سمت سرویس گیرنده یا اجرای دستورالعمل های کدگذاری شده در سمت سرور رخ دهند و ناشی از مشکلات مقیاس بندی و همچنین خطاهای نحوی یا منطقی باشند. بیتهای برنامه که در جایی در فضای ابری اجرا میشوند، برای بازرسی در دسترس نیستند، مگر اینکه آنها را بخواهید. این سند استراتژیها، ابزارها و راهحلهای اشکالزدایی را ارائه میکند تا به شما در حل خطاهای رایج و اشکالزدایی اسکریپتهای Earth Engine کمک کند.
خطاهای نحوی
خطاهای نحوی زمانی اتفاق می افتد که کد شما قوانین زبان برنامه نویسی (جاوا اسکریپت یا پایتون در Earth Engine) را زیر پا می گذارد. این خطاها مانع از اجرای کد شما می شوند و معمولاً قبل از اجرا ضبط می شوند. اگر با یک خطای نحوی مواجه شدید، خط هایلایت شده یا پیام خطا را به دقت بررسی کنید و از منابعی مانند مرجع زبان پایتون یا راهنمای سبک جاوا اسکریپت گوگل استفاده کنید. یک خط کد نیز می تواند به شناسایی و رفع این مشکلات کمک کند.
خطاهای سمت مشتری
با وجود کد صحیح نحوی، ممکن است خطاهایی مرتبط با سازگاری یا منطق اسکریپت وجود داشته باشد. مثالهای زیر خطاهای استفاده از یک متغیر و روشی را نشان میدهند که وجود ندارد.
خطا - این کد کار نمی کند!
ویرایشگر کد (جاوا اسکریپت)
// 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
کولب (پایتون)
# 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()
اولین خطا به شما اطلاع می دهد که متغیر 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
کولب (پایتون)
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
کولب (پایتون)
area = ee.Feature(collection.first()).area()
(شایان ذکر است که می توانید با خیال راحت هر روشی را در Element
در اینجا فراخوانی کنید، زیرا Earth Engine فکر می کند که چنین است).
از مخلوط کردن عملکردهای سرویس گیرنده و سرور خودداری کنید
مثال زیر کمتر واضح است:
خطا - این کد کاری را که شما می خواهید انجام نمی دهد
ویرایشگر کد (جاوا اسکریپت)
// 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
کولب (پایتون)
# 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
فرض کنید نویسنده این کد قصد دارد به هر پیکسل در تصویر 2
اضافه کند، این روش درستی نیست. به طور خاص، این کد به اشتباه یک شی سمت سرور ( image
) را با یک اپراتور سمت سرویس گیرنده ( +
) مخلوط می کند. نتایج ممکن است تعجب آور باشد. در حالت اول، چاپ nonsense
در ویرایشگر کد جاوا اسکریپت، با تبدیل هر دو image
و 2
به رشته، و سپس به هم پیوستن آنها، عملیات درخواستی ( +
) را انجام می دهد. رشته حاصل ناخواسته است (در پایتون TypeError پرتاب می شود). در حالت دوم، با اضافه کردن nonsense
به نقشه، خطای رمزی g.eeObject.name is not a function
در ویرایشگر کد جاوا اسکریپت نمایش داده میشود، زیرا شیء اضافه شده به نقشه، nonsense
، یک رشته است، نه یک شی EE (در پایتون TypeError پرتاب میشود). برای جلوگیری از نتایج احتمالی ناخواسته و خطاهای غیر اطلاعاتی، اشیاء و توابع سرور را با اشیاء، توابع اولیه یا کلاینت ترکیب نکنید. راه حل این مثال استفاده از تابع سرور است.
راه حل - از یک تابع سرور استفاده کنید!
ویرایشگر کد (جاوا اسکریپت)
Map.addLayer(image.add(2));
import ee import geemap.core as geemap
کولب (پایتون)
m = geemap.Map() m.add_layer(image.add(2)) m
برای جزئیات بیشتر به صفحه Client vs Server مراجعه کنید.
قفل مرورگر ویرایشگر کد جاوا اسکریپت
زمانی که جاوا اسکریپت در کلاینت اجرا می شود، یا زمانی که منتظر چیزی از Earth Engine هستید، مسدود یا قفل شدن مرورگر ممکن است رخ دهد. دو منبع رایج این خطا، حلقههای for-loop و/یا getInfo()
در کد ویرایشگر کد جاوا اسکریپت، با بدترین سناریوی getInfo()
در داخل یک حلقه for هستند. حلقههای For میتوانند باعث قفل شدن مرورگر شوند زیرا کد روی دستگاه شما اجرا میشود. از طرف دیگر، getInfo()
به طور همزمان نتیجه یک محاسبات را از Earth Engine درخواست می کند و تا زمانی که نتیجه دریافت شود مسدود می شود. اگر محاسبه زمان زیادی ببرد، مسدود شدن می تواند باعث قفل شدن مرورگر شما شود. هنگام کار در ویرایشگر کد، از هر دو حلقه for-loop و getInfo()
اجتناب کنید. برای جزئیات بیشتر به صفحه Client vs Server مراجعه کنید.
خطاهای سمت سرور
با وجود سازگاری منطقی در کد مشتری، ممکن است اشکالاتی وجود داشته باشد که فقط در زمان اجرا روی سرور آشکار می شوند. مثال زیر نشان میدهد که چه اتفاقی میافتد هنگام تلاش برای بدست آوردن گروهی که وجود ندارد.
خطا - این کد کار نمی کند!
ویرایشگر کد (جاوا اسکریپت)
// 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
کولب (پایتون)
# 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
کولب (پایتون)
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
کولب (پایتون)
s2image = s2image.set('my_property', 'OK') display(s2image.get('my_property')) # OK
توابع نگاشت شده
زمینه دیگری که در آن توابع سرویس گیرنده و سرور با هم ترکیب نمی شوند، توابع نقشه برداری شده است. به طور خاص، عملیات مشخص شده توسط تابع نقشهبرداری شده در فضای ابری اجرا میشود، بنابراین توابع مشتری مانند getInfo
و Export
(و همچنین print
و روش روی Map
و Chart
در ویرایشگر کد جاوا اسکریپت) در توابع نقشهبرداری شده کار نمیکنند. به عنوان مثال:
خطا - این کد کار نمی کند!
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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()))
این خطای تا حدی مرموز ناشی از فرآیندی است که Earth Engine برای تبدیل این کد به مجموعهای از دستورالعملهایی که میتوانند در سرورهای Google اجرا شوند، استفاده میکند. توابع سمت کلاینت و ساختارهای کنترلی را نمی توان برای کار بر روی تصویر آرگومان ارسال شده به تابع نگاشت شده استفاده کرد. برای جلوگیری از این خطا، از استفاده از توابع سمت سرویس گیرنده در توابع نقشه برداری شده خودداری کنید. برای کسب اطلاعات بیشتر در مورد تمایز بین عملکردهای سرویس گیرنده و سرور، به صفحه Client vs Server مراجعه کنید.
توابع نقشهبرداری شده نیازمندیهای اضافی هستند. برای مثال، توابع نگاشت شده باید چیزی را برگردانند:
خطا - این کد کار نمی کند!
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
collection = ee.ImageCollection('MODIS/006/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/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
کولب (پایتون)
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())
برای جلوگیری از این امر، تصویر ورودی را با یک مجموعه ویژگی جدید برگردانید. سپس، اگر به لیستی از تاریخ های تصاویر در مجموعه نیاز دارید، می توانید از aggregate_array()
استفاده کنید:
راه حل - یک ویژگی تنظیم کنید!
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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())
اشتباهات رویه ای
الگو بر روی یک تصویر بدون باند اعمال شد
خطای "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
کولب (پایتون)
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())
این مثال احمقانه فقط برای نمایش است. هدف از این خطا این است که از شما بپرسد که آیا واقعاً می خواهید 80300348117 (یعنی 80 میلیارد ) پیکسل را کاهش دهید. در غیر این صورت، scale
افزایش دهید (اندازه پیکسل بر حسب متر) یا bestEffort
روی true تنظیم کنید تا مقیاس بزرگتر به صورت خودکار دوباره محاسبه شود. برای جزئیات بیشتر در مورد این پارامترها به صفحه reduceRegion()
مراجعه کنید.
زمان محاسبه تمام شد
فرض کنید به تمام آن پیکسل ها در محاسبات خود نیاز دارید. اگر چنین است، می توانید پارامتر maxPixels
را افزایش دهید تا محاسبات موفق شود. با این حال، موتور Earth مدتی طول می کشد تا محاسبات را تمام کند. در نتیجه، ممکن است یک خطای "مدت زمان پایان محاسبات" ایجاد شود:
بد - این کار را نکنید!
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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
کولب (پایتون)
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
کولب (پایتون)
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
کولب (پایتون)
task = ee.batch.Export.table.toDrive( collection=terrible_aggregations, description='terrible_aggregations', fileFormat='CSV', ) # task.start()
از محدودیت حافظه کاربر فراتر رفت
یکی از راههایی که الگوریتمهای شما در Earth Engine موازی میشوند این است که ورودیها را به کاشیها تقسیم میکنیم، محاسبات یکسانی را به طور جداگانه روی هر کاشی اجرا میکنیم و سپس نتایج را با هم ترکیب میکنیم. در نتیجه، تمام ورودیهای لازم برای محاسبه یک کاشی خروجی باید در حافظه قرار گیرند. به عنوان مثال، هنگامی که ورودی تصویری با باندهای زیاد است، اگر از همه باندها در محاسبات استفاده شود، می تواند حافظه زیادی را به خود اختصاص دهد. برای نشان دادن، این مثال با مجبور کردن (غیر ضروری) کل مجموعه تصویر در یک کاشی، از حافظه بسیار زیادی استفاده می کند:
بد - این کار را نکنید!
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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
کولب (پایتون)
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
کولب (پایتون)
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 برای شناسایی مسائل خاص کمک کنند. این رشته را در گزارش های اشکال وارد کنید.
روش های اشکال زدایی
تحلیل خود را کدگذاری کردید، آن را اجرا کردید و با خطا مواجه شدید. حالا چی؟ این بخش تکنیک های کلی اشکال زدایی را برای جداسازی مشکل و رفع آن شرح می دهد.
متغیرها و لایه های نقشه را بررسی کنید
فرض کنید یک تحلیل بسیار پیچیده دارید که خطا ایجاد می کند. اگر مشخص نیست که خطا از کجا منشأ می گیرد، یک استراتژی اولیه خوب این است که اشیاء میانی را چاپ یا تجسم کنید و آنها را بررسی کنید تا مطمئن شوید ساختار شی با منطق موجود در اسکریپت شما مطابقت دارد. به طور خاص، میتوانید مقادیر پیکسل لایههای اضافه شده به نقشه را با ابزار ویرایشگر کد یا بازرس geemap بررسی کنید. اگر چیزی را چاپ می کنید، مطمئن شوید که ویژگی های آن را با زیپی (▶) گسترش دهید. برخی از مواردی که باید بررسی شوند عبارتند از:
- نام گروه ها آیا نام باندهای تصویر با کد شما مطابقت دارد؟
- مقادیر پیکسل آیا داده های شما محدوده مناسبی دارند؟ آیا ماسک مناسبی دارد؟
- پوچ آیا چیزی پوچ است که نباید باشد؟
- اندازه ها آیا اندازه صفر است در حالی که نباید باشد؟
aside()
قرار دادن هر مرحله میانی در تجزیه و تحلیل در یک متغیر به طوری که بتوان آن را چاپ و بازرسی کرد، می تواند دشوار باشد. برای چاپ مقادیر میانی از یک زنجیره طولانی از فراخوانی تابع، می توانید از متد aside()
استفاده کنید. به عنوان مثال:
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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)
(geemap پایتون) در حال فراخوانی توابع سمت کلاینت هستند و همچنان در توابع نقشهبرداری شده با شکست مواجه میشوند. شما همچنین می توانید از کنار با توابع تعریف شده توسط کاربر استفاده کنید. به عنوان مثال:
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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
کولب (پایتون)
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
کولب (پایتون)
# 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
اکنون، چون این تابع فقط روی یک ویژگی اجرا میشود، میتوانید یک فراخوان چاپی («نمایش» برای geemap پایتون) در داخل آن قرار دهید. شیء چاپ شده را بررسی کنید تا متوجه شوید (آه ها!) که شیء برگردانده شده توسط reduceRegion()
دارای تهی برای هر باند است. این توضیح می دهد که چرا تقسیم شکست می خورد: زیرا شما نمی توانید null را به null تقسیم کنید. چرا در وهله اول باطل است؟ برای بررسی، تصویر ورودی و ویژگی بد را به نقشه اضافه کنید و روی ویژگی بد تمرکز کنید. با انجام این کار، متوجه می شوید که مشکل به دلیل خارج از محدوده تصویر است. بر اساس این کشف، کد اشکال زدایی شده به صورت زیر است:
ویرایشگر کد (جاوا اسکریپت)
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
کولب (پایتون)
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 و میزان مصرف حافظه (به ازای هر الگوریتم و دارایی) حاصل از محاسبات انجام شده در زمانی که فعال است، ارائه می دهد. برای اطلاعاتی در مورد عملیات فشرده ترین منابع، ورودی های بالای نمایه ساز را جستجو کنید. برای اسکریپتهای طولانیمدت یا ناکارآمد، ورودیهای بالای نمایهساز سرنخهایی درباره مکان تمرکز تلاشها برای بهینهسازی اسکریپت ارائه میدهند. نکته مهم: خود پروفایل بر عملکرد اسکریپت تأثیر می گذارد، بنابراین فقط در صورت لزوم باید آن را اجرا کنید.