尽管脚本可能是有效的 JavaScript,没有逻辑错误,并且代表服务器的一组有效指令,但在并行化和执行计算时,生成的对象可能太大、太多或计算时间太长。在这种情况下,您将收到一条错误消息,表明该算法无法缩放。这些错误通常是最难诊断和解决的。此类错误的示例包括:
- 计算超时
- 并发聚合过多
- 超出用户内存限制
- 发生了一个内部的错误
警告:存在配额限制以确保整个 Earth Engine 社区的计算资源的可用性。试图通过使用多个 Google 帐户来规避配额限制是违反 地球引擎服务条款的行为。
改进代码的可扩展性将使您更快地获得结果,并提高所有用户的计算资源的可用性。下面将讨论每种类型的错误,然后简要介绍一下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);
这个错误的目的是问你是否真的要减少 80300348117(也就是 800亿)像素。如果不是,则相应地增加scale
(以米为单位的像素大小),或设置bestEffort
为 true,以自动重新计算更大的比例。我们可以通过增大scale或者 maxPixels设置以besteffort来进行避免错误,除此之外我们也可以通过分块进行计算和统计。
计算超时
假设您在计算中需要所有这些像素。如果是这样,您可以增加 maxPixels
参数以允许计算成功。然而,地球引擎需要一些时间来完成计算。因此,可能会抛出“计算超时”错误:
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);
这个错误意味着地球引擎在停止计算之前等待了大约五分钟。导出允许 Earth Engine 在具有更长允许运行时间(但不是更多内存)的环境中执行计算。由于 from 的返回值reduceRegion()
是一个字典,您可以使用字典来设置具有空几何的特征的属性:
这里明确告诉大家有时候不要用print,而是直接通过后台导出,这样可以减少不必要的麻烦,通过导出后再次查看结果会好很多、
代码语言:javascript复制Export.table.toDrive({
collection: ee.FeatureCollection([
ee.Feature(null, ridiculousComputation)
]),
description: 'ridiculousComputation',
fileFormat: 'CSV'
});
并发聚合过多
此错误的“聚合”部分是指分布在多台机器上的操作(例如跨越多个图块的缩减)。Earth Engine 设置了一些限制,以防止同时运行过多的此类聚合。在这个例子中,“Too many concurrent aggregations”错误是由 map 中的 reduce 触发的:
代码语言:javascript复制var collection = ee.ImageCollection('LANDSAT/LT05/C01/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);
假设此代码的目的是获取每个图像的图像统计信息,一种可能的解决方案是Export
结果。例如,使用 ImageCollection
,FeatureCollection
与图像关联的元数据可以导出为表:
Export.table.toDrive({
collection: terribleAggregations,
description: 'terribleAggregations',
fileFormat: 'CSV'
});
总之以上要解决的首要原则就是打印可能出错的环节,我们选择用导出的方式进行查看,这样可以交给后台处理,而不是一致在你的界面等待出错。
超出用户内存限制
在 Earth Engine 中并行化您的算法的一种方法是将输入拆分为小块,在每个小块上分别运行相同的计算,然后组合结果。因此,计算输出图块所需的所有输入都必须适合内存。例如,当输入是具有许多波段的图像时,如果在计算中使用了所有波段,则最终可能会占用大量内存。为了演示,此示例通过强制(不必要地)将整个图像集合放入图块中来使用过多的内存:
这个非常糟糕的代码展示了一个不使用数组的原因,除非您真的需要(。当该集合转换为一个巨大的数组时,该数组必须一次全部加载到内存中。因为它是一个长时间的图像序列,所以数组很大并且不适合内存。
一种可能的解决方案是将tileScale
参数设置为更高的值。较高的 tileScale 值会导致图块缩小 1 倍 tileScale^2
。例如,以下允许计算成功:
var smallerHog = ee.ImageCollection('LANDSAT/LT05/C01/T1')
.toArray()
.arrayReduce(ee.Reducer.mean(), [0])
.arrayProject([1])
.arrayFlatten([['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'QA']])
.reduceRegion({
reducer: 'mean',
geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
scale: 1,
bestEffort: true,
tileScale: 16
});
print(smallerHog);
但是,更好的解决方案是不必要地使用数组,因此根本不需要摆弄tileScale
:也能解决问题:切记最好不要加入数组在统计过程中。
var okMemory = ee.ImageCollection('LANDSAT/LT05/C01/T1')
.mean()
.reduceRegion({
reducer: 'mean',
geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000),
scale: 1,
bestEffort: true,
});
print(okMemory);