Google Earth Engine(GEE)——缩放错误(计算超时、聚合过多、内存溢出)

2024-02-02 08:36:08 浏览数 (1)

尽管脚本可能是有效的 JavaScript,没有逻辑错误,并且代表服务器的一组有效指令,但在并行化和执行计算时,生成的对象可能太大、太多或计算时间太长。在这种情况下,您将收到一条错误消息,表明该算法无法缩放。这些错误通常是最难诊断和解决的。此类错误的示例包括:

  • 计算超时
  • 并发聚合过多
  • 超出用户内存限制
  • 发生了一个内部的错误

警告:存在配额限制以确保整个 Earth Engine 社区的计算资源的可用性。试图通过使用多个 Google 帐户来规避配额限制是违反 地球引擎服务条款的行为。

改进代码的可扩展性将使您更快地获得结果,并提高所有用户的计算资源的可用性。下面将讨论每种类型的错误,然后简要介绍一下reduceRegion(),这是一个因能够导致每种类型的缩放错误而臭名昭著的常用函数。

reduceRegion()

尽管reduceRegion()贪婪地消耗了足够多的像素来触发各种令人咆哮的错误,但也有一些旨在控制计算的参数,因此您可以克服错误。例如,考虑以下不明智的减少:

代码语言: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);

这个错误的目的是问你是否真的要减少 80300348117(也就是 800亿)像素。如果不是,则相应地增加scale(以米为单位的像素大小),或设置bestEffort为 true,以自动重新计算更大的比例。我们可以通过增大scale或者 maxPixels设置以besteffort来进行避免错误,除此之外我们也可以通过分块进行计算和统计。

计算超时

假设您在计算中需要所有这些像素。如果是这样,您可以增加 maxPixels参数以允许计算成功。然而,地球引擎需要一些时间来完成计算。因此,可能会抛出“计算超时”错误:

代码语言: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);

这个错误意味着地球引擎在停止计算之前等待了大约五分钟。导出允许 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结果。例如,使用 ImageCollectionFeatureCollection与图像关联的元数据可以导出为表:

代码语言:javascript复制
Export.table.toDrive({
  collection: terribleAggregations,
  description: 'terribleAggregations',
  fileFormat: 'CSV'
});

总之以上要解决的首要原则就是打印可能出错的环节,我们选择用导出的方式进行查看,这样可以交给后台处理,而不是一致在你的界面等待出错。

超出用户内存限制

在 Earth Engine 中并行化您的算法的一种方法是将输入拆分为小块,在每个小块上分别运行相同的计算,然后组合结果。因此,计算输出图块所需的所有输入都必须适合内存。例如,当输入是具有许多波段的图像时,如果在计算中使用了所有波段,则最终可能会占用大量内存。为了演示,此示例通过强制(不必要地)将整个图像集合放入图块中来使用过多的内存:

这个非常糟糕的代码展示了一个不使用数组的原因,除非您真的需要(。当该集合转换为一个巨大的数组时,该数组必须一次全部加载到内存中。因为它是一个长时间的图像序列,所以数组很大并且不适合内存。

一种可能的解决方案是将tileScale参数设置为更高的值。较高的 tileScale 值会导致图块缩小 1 倍 tileScale^2。例如,以下允许计算成功:

代码语言:javascript复制
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:也能解决问题:切记最好不要加入数组在统计过程中。

代码语言:javascript复制
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);

0 人点赞