rslearn 0.0.21__py3-none-any.whl → 0.0.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,255 @@
1
+ """A partial data source implementation providing get_items using a STAC API."""
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ import shapely
7
+ from upath import UPath
8
+
9
+ from rslearn.config import QueryConfig
10
+ from rslearn.const import WGS84_PROJECTION
11
+ from rslearn.data_sources.data_source import Item, ItemLookupDataSource
12
+ from rslearn.data_sources.utils import match_candidate_items_to_window
13
+ from rslearn.log_utils import get_logger
14
+ from rslearn.utils.geometry import STGeometry
15
+ from rslearn.utils.stac import StacClient, StacItem
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class SourceItem(Item):
21
+ """An item in the StacDataSource data source."""
22
+
23
+ def __init__(
24
+ self,
25
+ name: str,
26
+ geometry: STGeometry,
27
+ asset_urls: dict[str, str],
28
+ properties: dict[str, str],
29
+ ):
30
+ """Creates a new SourceItem.
31
+
32
+ Args:
33
+ name: unique name of the item
34
+ geometry: the spatial and temporal extent of the item
35
+ asset_urls: map from asset key to the unsigned asset URL.
36
+ properties: properties requested by the data source implementation.
37
+ """
38
+ super().__init__(name, geometry)
39
+ self.asset_urls = asset_urls
40
+ self.properties = properties
41
+
42
+ def serialize(self) -> dict[str, Any]:
43
+ """Serializes the item to a JSON-encodable dictionary."""
44
+ d = super().serialize()
45
+ d["asset_urls"] = self.asset_urls
46
+ d["properties"] = self.properties
47
+ return d
48
+
49
+ @staticmethod
50
+ def deserialize(d: dict[str, Any]) -> "SourceItem":
51
+ """Deserializes an item from a JSON-decoded dictionary."""
52
+ item = super(SourceItem, SourceItem).deserialize(d)
53
+ return SourceItem(
54
+ name=item.name,
55
+ geometry=item.geometry,
56
+ asset_urls=d["asset_urls"],
57
+ properties=d["properties"],
58
+ )
59
+
60
+
61
+ class StacDataSource(ItemLookupDataSource[SourceItem]):
62
+ """A partial data source implementing get_items using a STAC API.
63
+
64
+ This is a helper class that full implementations can extend to not have to worry
65
+ about the get_items and get_item_by_name implementation.
66
+ """
67
+
68
+ def __init__(
69
+ self,
70
+ endpoint: str,
71
+ collection_name: str,
72
+ query: dict[str, Any] | None = None,
73
+ sort_by: str | None = None,
74
+ sort_ascending: bool = True,
75
+ required_assets: list[str] | None = None,
76
+ cache_dir: UPath | None = None,
77
+ limit: int = 100,
78
+ properties_to_record: list[str] = [],
79
+ ):
80
+ """Create a new StacDataSource.
81
+
82
+ Args:
83
+ endpoint: the STAC endpoint to use.
84
+ collection_name: the STAC collection name.
85
+ query: optional STAC query dict to include in searches, e.g. {"eo:cloud_cover": {"lt": 50}}.
86
+ sort_by: sort results by this STAC property.
87
+ sort_ascending: if sort_by is set, sort in ascending order (default).
88
+ Otherwise sort in descending order.
89
+ required_assets: if set, we ignore items that do not have all of these
90
+ asset keys.
91
+ cache_dir: optional cache directory to cache items. This is recommended if
92
+ allowing direct materialization from the data source, since it will
93
+ likely be necessary to make lots of get_item_by_name calls during
94
+ materialization. TODO: give direct materialization access to the Item
95
+ object.
96
+ limit: limit to pass to search queries.
97
+ properties_to_record: if these properties on the STAC item exist, they are
98
+ are retained in the SourceItem when we initialize it.
99
+ """
100
+ self.client = StacClient(endpoint)
101
+ self.collection_name = collection_name
102
+ self.query = query
103
+ self.sort_by = sort_by
104
+ self.sort_ascending = sort_ascending
105
+ self.required_assets = required_assets
106
+ self.cache_dir = cache_dir
107
+ self.limit = limit
108
+ self.properties_to_record = properties_to_record
109
+
110
+ def _stac_item_to_item(self, stac_item: StacItem) -> SourceItem:
111
+ # Make sure geometry, time range, and assets are set.
112
+ if stac_item.geometry is None:
113
+ raise ValueError("got unexpected item with no geometry")
114
+ if stac_item.time_range is None:
115
+ raise ValueError("got unexpected item with no time range")
116
+ if stac_item.assets is None:
117
+ raise ValueError("got unexpected item with no assets")
118
+
119
+ shp = shapely.geometry.shape(stac_item.geometry)
120
+ geom = STGeometry(WGS84_PROJECTION, shp, stac_item.time_range)
121
+ asset_urls = {
122
+ asset_key: asset_obj.href
123
+ for asset_key, asset_obj in stac_item.assets.items()
124
+ }
125
+
126
+ # Keep any properties requested by the data source implementation.
127
+ properties = {}
128
+ for prop_name in self.properties_to_record:
129
+ if prop_name not in stac_item.properties:
130
+ continue
131
+ properties[prop_name] = stac_item.properties[prop_name]
132
+
133
+ return SourceItem(stac_item.id, geom, asset_urls, properties)
134
+
135
+ def get_item_by_name(self, name: str) -> SourceItem:
136
+ """Gets an item by name.
137
+
138
+ Args:
139
+ name: the name of the item to get
140
+
141
+ Returns:
142
+ the item object
143
+ """
144
+ # If cache_dir is set, we cache the item. First here we check if it is already
145
+ # in the cache.
146
+ cache_fname: UPath | None = None
147
+ if self.cache_dir:
148
+ cache_fname = self.cache_dir / f"{name}.json"
149
+ if cache_fname is not None and cache_fname.exists():
150
+ with cache_fname.open() as f:
151
+ return SourceItem.deserialize(json.load(f))
152
+
153
+ # No cache or not in cache, so we need to make the STAC request.
154
+ logger.debug(f"Getting STAC item {name}")
155
+ stac_items = self.client.search(ids=[name], collections=[self.collection_name])
156
+
157
+ if len(stac_items) == 0:
158
+ raise ValueError(
159
+ f"Item {name} not found in collection {self.collection_name}"
160
+ )
161
+ if len(stac_items) > 1:
162
+ raise ValueError(
163
+ f"Multiple items found for ID {name} in collection {self.collection_name}"
164
+ )
165
+
166
+ stac_item = stac_items[0]
167
+ item = self._stac_item_to_item(stac_item)
168
+
169
+ # Finally we cache it if cache_dir is set.
170
+ if cache_fname is not None:
171
+ with cache_fname.open("w") as f:
172
+ json.dump(item.serialize(), f)
173
+
174
+ return item
175
+
176
+ def get_items(
177
+ self, geometries: list[STGeometry], query_config: QueryConfig
178
+ ) -> list[list[list[SourceItem]]]:
179
+ """Get a list of items in the data source intersecting the given geometries.
180
+
181
+ Args:
182
+ geometries: the spatiotemporal geometries
183
+ query_config: the query configuration
184
+
185
+ Returns:
186
+ List of groups of items that should be retrieved for each geometry.
187
+ """
188
+ groups = []
189
+ for geometry in geometries:
190
+ # Get potentially relevant items from the collection by performing one search
191
+ # for each requested geometry.
192
+ wgs84_geometry = geometry.to_projection(WGS84_PROJECTION)
193
+ logger.debug("performing STAC search for geometry %s", wgs84_geometry)
194
+ stac_items = self.client.search(
195
+ collections=[self.collection_name],
196
+ intersects=json.loads(shapely.to_geojson(wgs84_geometry.shp)),
197
+ date_time=wgs84_geometry.time_range,
198
+ query=self.query,
199
+ limit=self.limit,
200
+ )
201
+ logger.debug("STAC search yielded %d items", len(stac_items))
202
+
203
+ if self.required_assets is not None:
204
+ # Filter out items that are missing any of the assets in self.asset_bands.
205
+ good_stac_items = []
206
+ for stac_item in stac_items:
207
+ if stac_item.assets is None:
208
+ raise ValueError(f"got STAC item {stac_item.id} with no assets")
209
+
210
+ good = True
211
+ for asset_key in self.required_assets:
212
+ if asset_key in stac_item.assets:
213
+ continue
214
+ good = False
215
+ break
216
+ if good:
217
+ good_stac_items.append(stac_item)
218
+ logger.debug(
219
+ "required_assets filter from %d to %d items",
220
+ len(stac_items),
221
+ len(good_stac_items),
222
+ )
223
+ stac_items = good_stac_items
224
+
225
+ if self.sort_by is not None:
226
+ sort_by = self.sort_by
227
+ stac_items.sort(
228
+ key=lambda stac_item: stac_item.properties[sort_by],
229
+ reverse=not self.sort_ascending,
230
+ )
231
+
232
+ candidate_items = [
233
+ self._stac_item_to_item(stac_item) for stac_item in stac_items
234
+ ]
235
+
236
+ # Since we made the STAC request, might as well save these to the cache.
237
+ if self.cache_dir is not None:
238
+ for item in candidate_items:
239
+ cache_fname = self.cache_dir / f"{item.name}.json"
240
+ if cache_fname.exists():
241
+ continue
242
+ with cache_fname.open("w") as f:
243
+ json.dump(item.serialize(), f)
244
+
245
+ cur_groups = match_candidate_items_to_window(
246
+ geometry, candidate_items, query_config
247
+ )
248
+ groups.append(cur_groups)
249
+
250
+ return groups
251
+
252
+ def deserialize_item(self, serialized_item: Any) -> SourceItem:
253
+ """Deserializes an item from JSON-decoded data."""
254
+ assert isinstance(serialized_item, dict)
255
+ return SourceItem.deserialize(serialized_item)
@@ -150,8 +150,11 @@ class AttentionPool(IntermediateComponent):
150
150
  D // self.num_heads
151
151
  )
152
152
  attn_weights = F.softmax(attn_scores, dim=-1)
153
- x = torch.matmul(attn_weights, v) # [B, head, 1, D_head]
154
- return x.reshape(B, D, H, W)
153
+ x = torch.matmul(attn_weights, v) # [B*H*W, num_heads, 1, D_head]
154
+ x = x.squeeze(-2) # [B*H*W, num_heads, D_head]
155
+ return rearrange(
156
+ x, "(b h w) nh dh -> b (nh dh) h w", b=B, h=H, w=W
157
+ ) # [B, D, H, W]
155
158
 
156
159
  def forward(self, intermediates: Any, context: ModelContext) -> FeatureMaps:
157
160
  """Forward pass for attention pooling linear probe.
@@ -345,14 +345,14 @@ class RslearnLightningModule(L.LightningModule):
345
345
  )
346
346
 
347
347
  if self.visualize_dir:
348
- for idx, (inp, target, output, metadata) in enumerate(
349
- zip(inputs, targets, outputs, metadatas)
348
+ for inp, target, output, metadata in zip(
349
+ inputs, targets, outputs, metadatas
350
350
  ):
351
351
  images = self.task.visualize(inp, target, output)
352
352
  for image_suffix, image in images.items():
353
353
  out_fname = os.path.join(
354
354
  self.visualize_dir,
355
- f"{metadata['window_name']}_{metadata['bounds'][0]}_{metadata['bounds'][1]}_{image_suffix}.png",
355
+ f"{metadata.window_name}_{metadata.patch_bounds[0]}_{metadata.patch_bounds[1]}_{image_suffix}.png",
356
356
  )
357
357
  Image.fromarray(image).save(out_fname)
358
358
 
@@ -6,7 +6,7 @@ import numpy.typing as npt
6
6
  import torch
7
7
  from torchmetrics import MetricCollection
8
8
 
9
- from rslearn.models.component import FeatureMaps
9
+ from rslearn.models.component import FeatureMaps, Predictor
10
10
  from rslearn.train.model_context import ModelContext, ModelOutput, SampleMetadata
11
11
  from rslearn.utils import Feature
12
12
 
@@ -83,7 +83,7 @@ class EmbeddingTask(Task):
83
83
  return MetricCollection({})
84
84
 
85
85
 
86
- class EmbeddingHead:
86
+ class EmbeddingHead(Predictor):
87
87
  """Head for embedding task.
88
88
 
89
89
  It just adds a dummy loss to act as a Predictor.
@@ -108,8 +108,10 @@ class BasicTask(Task):
108
108
  Returns:
109
109
  a dictionary mapping image name to visualization image
110
110
  """
111
- image = input_dict["image"].cpu()
112
- image = image[self.image_bands, :, :]
111
+ raster_image = input_dict["image"]
112
+ assert isinstance(raster_image, RasterImage)
113
+ # We don't really handle time series here, just use the first timestep.
114
+ image = raster_image.image.cpu()[self.image_bands, 0, :, :]
113
115
  if self.remap_values:
114
116
  factor = (self.remap_values[1][1] - self.remap_values[1][0]) / (
115
117
  self.remap_values[0][1] - self.remap_values[0][0]
rslearn/utils/geometry.py CHANGED
@@ -153,8 +153,8 @@ class ResolutionFactor:
153
153
  else:
154
154
  return Projection(
155
155
  projection.crs,
156
- projection.x_resolution // self.numerator,
157
- projection.y_resolution // self.numerator,
156
+ projection.x_resolution / self.numerator,
157
+ projection.y_resolution / self.numerator,
158
158
  )
159
159
 
160
160
  def multiply_bounds(self, bounds: PixelBounds) -> PixelBounds:
rslearn/utils/stac.py ADDED
@@ -0,0 +1,173 @@
1
+ """STAC API client."""
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+ from datetime import datetime
6
+ from typing import Any
7
+
8
+ import requests
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ Bbox = tuple[float, float, float, float]
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class StacAsset:
17
+ """A STAC asset."""
18
+
19
+ href: str
20
+ title: str | None
21
+ type: str | None
22
+ roles: list[str] | None
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class StacItem:
27
+ """A STAC item."""
28
+
29
+ id: str
30
+ properties: dict[str, Any]
31
+ collection: str | None
32
+ bbox: Bbox | None
33
+ geometry: dict[str, Any] | None
34
+ assets: dict[str, StacAsset] | None
35
+ time_range: tuple[datetime, datetime] | None
36
+
37
+ @classmethod
38
+ def from_dict(cls, item: dict[str, Any]) -> "StacItem":
39
+ """Create a STAC item from the item dict returned from API."""
40
+ properties = item.get("properties", {})
41
+
42
+ # Parse bbox.
43
+ bbox: Bbox | None = None
44
+ if "bbox" in item:
45
+ if len(item["bbox"]) != 4:
46
+ raise NotImplementedError(
47
+ f"got bbox with {len(item['bbox'])} coordinates but only 4 coordinates is implemented"
48
+ )
49
+ bbox = tuple(item["bbox"])
50
+
51
+ # Parse assets.
52
+ assets: dict[str, StacAsset] = {}
53
+ for name, asset in item.get("assets", {}).items():
54
+ assets[name] = StacAsset(
55
+ href=asset["href"],
56
+ title=asset.get("title"),
57
+ type=asset.get("type"),
58
+ roles=asset.get("roles"),
59
+ )
60
+
61
+ # Parse time range.
62
+ time_range: tuple[datetime, datetime] | None = None
63
+ if "start_datetime" in properties and "end_datetime" in properties:
64
+ time_range = (
65
+ datetime.fromisoformat(properties["start_datetime"]),
66
+ datetime.fromisoformat(properties["end_datetime"]),
67
+ )
68
+ elif "datetime" in properties:
69
+ ts = datetime.fromisoformat(properties["datetime"])
70
+ time_range = (ts, ts)
71
+
72
+ return cls(
73
+ id=item["id"],
74
+ properties=properties,
75
+ collection=item.get("collection"),
76
+ bbox=bbox,
77
+ geometry=item.get("geometry"),
78
+ assets=assets,
79
+ time_range=time_range,
80
+ )
81
+
82
+
83
+ class StacClient:
84
+ """Limited functionality client for STAC APIs."""
85
+
86
+ def __init__(self, endpoint: str):
87
+ """Create a new StacClient.
88
+
89
+ Args:
90
+ endpoint: the STAC endpoint (base URL)
91
+ """
92
+ self.endpoint = endpoint
93
+ self.session = requests.Session()
94
+
95
+ def search(
96
+ self,
97
+ collections: list[str] | None = None,
98
+ bbox: Bbox | None = None,
99
+ intersects: dict[str, Any] | None = None,
100
+ date_time: datetime | tuple[datetime, datetime] | None = None,
101
+ ids: list[str] | None = None,
102
+ limit: int | None = None,
103
+ query: dict[str, Any] | None = None,
104
+ ) -> list[StacItem]:
105
+ """Execute a STAC item search.
106
+
107
+ We use the JSON POST API. Pagination is handled so the returned items are
108
+ concatenated across all available pages.
109
+
110
+ Args:
111
+ collections: only search within the provided collection(s).
112
+ bbox: only return features intersecting the provided bounding box.
113
+ intersects: only return features intersecting this GeoJSON geometry.
114
+ date_time: only return features that have a temporal property intersecting
115
+ the provided time range or timestamp.
116
+ ids: only return the provided item IDs.
117
+ limit: number of items per page. We will read all the pages.
118
+ query: query dict, if STAC query extension is supported by this API. See
119
+ https://github.com/stac-api-extensions/query.
120
+
121
+ Returns:
122
+ list of matching STAC items.
123
+ """
124
+ # Build JSON request data.
125
+ request_data: dict[str, Any] = {}
126
+ if collections is not None:
127
+ request_data["collections"] = collections
128
+ if bbox is not None:
129
+ request_data["bbox"] = bbox
130
+ if intersects is not None:
131
+ request_data["intersects"] = intersects
132
+ if date_time is not None:
133
+ if isinstance(date_time, tuple):
134
+ start_time = date_time[0].isoformat().replace("+00:00", "Z")
135
+ end_time = date_time[1].isoformat().replace("+00:00", "Z")
136
+ request_data["datetime"] = f"{start_time}/{end_time}"
137
+ else:
138
+ request_data["datetime"] = date_time.isoformat().replace("+00:00", "Z")
139
+ if ids is not None:
140
+ request_data["ids"] = ids
141
+ if limit is not None:
142
+ request_data["limit"] = limit
143
+ if query is not None:
144
+ request_data["query"] = query
145
+
146
+ # Handle pagination.
147
+ cur_url = self.endpoint + "/search"
148
+ items: list[StacItem] = []
149
+ while True:
150
+ logger.debug("Reading STAC items from %s", cur_url)
151
+ response = self.session.post(url=cur_url, json=request_data)
152
+ response.raise_for_status()
153
+ data = response.json()
154
+ for item_dict in data["features"]:
155
+ items.append(StacItem.from_dict(item_dict))
156
+
157
+ next_link = None
158
+ next_request_data: dict[str, Any] = {}
159
+ for link in data.get("links", []):
160
+ if "rel" not in link or link["rel"] != "next":
161
+ continue
162
+ assert link["method"] == "POST"
163
+ next_link = link["href"]
164
+ next_request_data = link["body"]
165
+ break
166
+
167
+ if next_link is None:
168
+ break
169
+
170
+ cur_url = next_link
171
+ request_data = next_request_data
172
+
173
+ return items
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rslearn
3
- Version: 0.0.21
3
+ Version: 0.0.22
4
4
  Summary: A library for developing remote sensing datasets and models
5
5
  Author: OlmoEarth Team
6
6
  License: Apache License
@@ -218,11 +218,13 @@ Requires-Dist: fsspec>=2025.10.0
218
218
  Requires-Dist: jsonargparse>=4.35.0
219
219
  Requires-Dist: lightning>=2.5.1.post0
220
220
  Requires-Dist: Pillow>=11.3
221
+ Requires-Dist: pydantic>=2
221
222
  Requires-Dist: pyproj>=3.7
222
223
  Requires-Dist: python-dateutil>=2.9
223
224
  Requires-Dist: pytimeparse>=1.1
224
225
  Requires-Dist: rasterio>=1.4
225
226
  Requires-Dist: shapely>=2.1
227
+ Requires-Dist: soilgrids>=0.1.4
226
228
  Requires-Dist: torch>=2.7.0
227
229
  Requires-Dist: torchvision>=0.22.0
228
230
  Requires-Dist: tqdm>=4.67
@@ -317,6 +319,7 @@ for how to setup these data sources.
317
319
  - Xyz (Slippy) Tiles (e.g., Mapbox tiles)
318
320
  - Planet Labs (PlanetScope, SkySat)
319
321
  - ESA WorldCover 2021
322
+ - ISRIC SoilGrids (WCS)
320
323
 
321
324
  rslearn can also be used to easily mosaic, crop, and re-project any sets of local
322
325
  raster and vector files you may have.
@@ -10,21 +10,24 @@ rslearn/config/__init__.py,sha256=n1qpZ0ImshTtLYl5mC73BORYyUcjPJyHiyZkqUY1hiY,47
10
10
  rslearn/config/dataset.py,sha256=AJlS-41B70E2Y4ST545J2P3Kz83jrFCRdkZecKZ7sQY,23255
11
11
  rslearn/data_sources/__init__.py,sha256=zzuZUxrlEIw84YpD2I0HJvCoLDB29LbmnKTXiJykzGU,660
12
12
  rslearn/data_sources/aws_landsat.py,sha256=0ZQtmd2NCnvLy4vFSB1AlmoguJbiQB_e_T4eS1tnW9Q,20443
13
- rslearn/data_sources/aws_open_data.py,sha256=lrHnMJTH3NAaRdNjxwCIxSq8rq90IvV4ho-qAG6Hdgc,29348
13
+ rslearn/data_sources/aws_open_data.py,sha256=rDE9VZXXA669fD9jfOizxpN41lmvvJc-skZz3LettJU,29197
14
14
  rslearn/data_sources/aws_sentinel1.py,sha256=knBg2ZdwzGRIibUPAqnhYR-DbHqFL4tLsuRVrucTWU4,4745
15
+ rslearn/data_sources/aws_sentinel2_element84.py,sha256=VkIAjCqzqi_m6StSQ-aY_AMtesFhkYYgwiUNkpBe7AA,13984
15
16
  rslearn/data_sources/climate_data_store.py,sha256=gwlbugwAT0YoOINOKNVlZuzpxUO5G0tfzwy4XVlURFg,18360
16
17
  rslearn/data_sources/copernicus.py,sha256=DLyXwnkFo2LzbxfLKHkOvHyZcNYFg5w-yXQPeBL67_w,35049
17
18
  rslearn/data_sources/data_source.py,sha256=lxdcxefETX5ui5uUdZn-ACSBhy6YVo4XDfk368EMD40,4862
18
19
  rslearn/data_sources/earthdaily.py,sha256=BNP7BK_vb9yQw6LaIaJ80vjCfBZ9TeALGkjHYIet_W0,18205
19
20
  rslearn/data_sources/earthdata_srtm.py,sha256=bwo8e_y9fFPliZ411tTWOiAUlEcb3AWBkeZxnkFY5SI,10633
20
21
  rslearn/data_sources/eurocrops.py,sha256=FQqdBcNl43fArq6rd_-iffVJyliIDbB0lIHvNdmtQBU,8663
21
- rslearn/data_sources/gcp_public_data.py,sha256=E3BhJqOgHMqwcfaxg7D47KNmfAwJDiDjH8-OdqNdjuI,36524
22
+ rslearn/data_sources/gcp_public_data.py,sha256=qXWFQ4y0cCVBla68H4bpolG0FKW9_vLyTlA-0mJc1Y0,37349
22
23
  rslearn/data_sources/google_earth_engine.py,sha256=xdoSDjSVp6lPVPMv4UJZ6BRUozUA2hFbSTl1707TBoM,23523
23
24
  rslearn/data_sources/local_files.py,sha256=mo5W_BxBl89EPTIHNDEpXM6qBjrP225KK0PcmNgvJZQ,19090
24
25
  rslearn/data_sources/openstreetmap.py,sha256=TzZfouc2Z4_xjx2v_uv7aPn4tVW3flRVQN4qBfl507E,18161
25
26
  rslearn/data_sources/planet.py,sha256=6FWQ0bl1k3jwvwp4EVGi2qs3OD1QhnKOKP36mN4HELI,9446
26
27
  rslearn/data_sources/planet_basemap.py,sha256=e9R6FlagJjg8Z6Rc1dC6zK3xMkCohz8eohXqXmd29xg,9670
27
- rslearn/data_sources/planetary_computer.py,sha256=qgvGe_hQDxAIrRVB9szvJZL5IvE2jTo8UWuKCMzx7jM,29773
28
+ rslearn/data_sources/planetary_computer.py,sha256=nTJ6Jh6CNBdCEIsn7G_xLQ0Nige5evdPdqLYmWTdDl4,20722
29
+ rslearn/data_sources/soilgrids.py,sha256=rwO4goFPQ7lx420FvYBHYFXdihnZqn_-IjdqtxQ9j2g,12455
30
+ rslearn/data_sources/stac.py,sha256=1qUbTD1fNSvBCX9QIXtyb9mGQ4K8ubRNIeEJs_I3QFU,9889
28
31
  rslearn/data_sources/usda_cdl.py,sha256=_WvxZkm0fbXfniRs6NT8iVCbTTmVPflDhsFT2ci6_Dk,6879
29
32
  rslearn/data_sources/usgs_landsat.py,sha256=kPOb3hsZe5-guUcFZZkwzcRpYZ3Zo7Bk4E829q_xiyU,18516
30
33
  rslearn/data_sources/utils.py,sha256=v_90ALOuts7RHNcx-j8o-aQ_aFjh8ZhXrmsaa9uEGDA,11651
@@ -46,7 +49,7 @@ rslearn/dataset/storage/file.py,sha256=g9HZ3CD4QcgyVNsBaXhjIKQgDOAeZ4R08sJ7ntx4w
46
49
  rslearn/dataset/storage/storage.py,sha256=DxZ7iwV938PiLwdQzb5EXSb4Mj8bRGmOTmA9fzq_Ge8,4840
47
50
  rslearn/models/__init__.py,sha256=_vWoF9d2Slah8-6XhYhdU4SRsy_CNxXjCGQTD2yvu3Q,22
48
51
  rslearn/models/anysat.py,sha256=nzk6hB83ltNFNXYRNA1rTvq2AQcAhwyvgBaZui1M37o,8107
49
- rslearn/models/attention_pooling.py,sha256=VeRoBLk0326Kpj780Pw8EiSFMU5_K9qg6HQO-B2r2PU,7044
52
+ rslearn/models/attention_pooling.py,sha256=Kss1W_HYNzfX78RVDi18m0-cG2BoPsC240u0oEqJ0d4,7187
50
53
  rslearn/models/clip.py,sha256=QG1oUFqcVuNEhx7BNfJ1FnxIOMNUwRNBwXCe3CR6wFI,2415
51
54
  rslearn/models/component.py,sha256=uikFDzPYaW_LSXsrSsES1aup4IDIuWHsitWLpKgF7zU,3432
52
55
  rslearn/models/concatenate_features.py,sha256=Attemr5KurxlOojpclD0Pd5Cu2KHpNdpXe8jCSjpJ9U,3818
@@ -113,7 +116,7 @@ rslearn/train/__init__.py,sha256=fnJyY4aHs5zQqbDKSfXsJZXY_M9fbTsf7dRYaPwZr2M,30
113
116
  rslearn/train/all_patches_dataset.py,sha256=EVoYCmS3g4OfWPt5CZzwHVx9isbnWh5HIGA0RBqPFeA,21145
114
117
  rslearn/train/data_module.py,sha256=pgut8rEWHIieZ7RR8dUvhtlNqk0egEdznYF3tCvqdHg,23552
115
118
  rslearn/train/dataset.py,sha256=Jy1jU3GigfHaFeX9rbveX9bqy2Pd5Wh_vquD6_aFnS8,36522
116
- rslearn/train/lightning_module.py,sha256=HA9e-74oUZR5s7piQP9Mwxwz0vw0-p4HdmijfgBSpU0,14776
119
+ rslearn/train/lightning_module.py,sha256=7WBAgdJhcMHueLKE2DthSFmNYvlNUh1dB4sibkqCsRA,14761
117
120
  rslearn/train/model_context.py,sha256=6o66BY6okBK-D5e0JUwPd7fxD_XehVaqxdQkJJKmQ3E,2580
118
121
  rslearn/train/optimizer.py,sha256=EKSqkmERalDA0bF32Gey7n6z69KLyaUWKlRsGJfKBmE,927
119
122
  rslearn/train/prediction_writer.py,sha256=rW0BUaYT_F1QqmpnQlbrLiLya1iBfC5Pb78G_NlF-vA,15956
@@ -126,12 +129,12 @@ rslearn/train/callbacks/peft.py,sha256=wEOKsS3RhsRaZTXn_Kz2wdsZdIiIaZPdCJWtdJBur
126
129
  rslearn/train/tasks/__init__.py,sha256=dag1u72x1-me6y0YcOubUo5MYZ0Tjf6-dOir9UeFNMs,75
127
130
  rslearn/train/tasks/classification.py,sha256=72ZBcbunMsdPYQN53S-4GfiLIDrr1X3Hni07dBJ0pu0,14261
128
131
  rslearn/train/tasks/detection.py,sha256=B0tfB7UGIbRtjnye3PhzLmfeQ4X7ImO3A-_LeNhBA54,21988
129
- rslearn/train/tasks/embedding.py,sha256=98ykdmfaxQjsH0UrUdTGmz1f0hCMPcNYTzt1YFqNQwQ,3869
132
+ rslearn/train/tasks/embedding.py,sha256=NdJEAaDWlWYzvOBVf7eIHfFOzqTgavfFH1J1gMbAMVo,3891
130
133
  rslearn/train/tasks/multi_task.py,sha256=1ML9mZ-kM3JfElisLOWBUn4k12gsKTFjoYYgamnyxt8,6124
131
134
  rslearn/train/tasks/per_pixel_regression.py,sha256=znCLFaZbGx8lvIkntDXjcX7yy7giyyBdWN-TwTGaPV4,10197
132
135
  rslearn/train/tasks/regression.py,sha256=bVS_ApZSpbL0NaaM8Mu5Bsu4SBUyLpVtrPslulvvZHs,12695
133
136
  rslearn/train/tasks/segmentation.py,sha256=ie9ZV-sklLjQs35caiEglC1xff6dxeug_N-f_A8VosA,23034
134
- rslearn/train/tasks/task.py,sha256=B-z5XheXPTDaKauYzwze5ZD_O43R9uF76awgEk05bGE,3954
137
+ rslearn/train/tasks/task.py,sha256=nMPunl9OlnOimr48saeTnwKMQ7Du4syGrwNKVQq4FL4,4110
135
138
  rslearn/train/transforms/__init__.py,sha256=BkCAzm4f-8TEhPIuyvCj7eJGh36aMkZFYlq-H_jkSvY,778
136
139
  rslearn/train/transforms/concatenate.py,sha256=hVVBaxIdk1Cx8JHPirj54TGpbWAJx5y_xD7k1rmGmT0,3166
137
140
  rslearn/train/transforms/crop.py,sha256=d5mrC8k7g4zz9J0RJrjz_pS1q06HfhUdzH6dUlL3Wqc,4668
@@ -147,7 +150,7 @@ rslearn/utils/__init__.py,sha256=GNvdTUmXakiEMnLdje7k1fe5aC7SFVqP757kbpN6Fzw,558
147
150
  rslearn/utils/array.py,sha256=RC7ygtPnQwU6Lb9kwORvNxatJcaJ76JPsykQvndAfes,2444
148
151
  rslearn/utils/feature.py,sha256=lsg0WThZDJzo1mrbaL04dXYI5G3x-n5FG9aEjj7uUaI,1649
149
152
  rslearn/utils/fsspec.py,sha256=h3fER_bkewzR9liEAULXguTIvXLUXA17pC_yZoWN5Tk,5902
150
- rslearn/utils/geometry.py,sha256=Z4alE4u0xa3fKGwoa4WQN5ZCjeqkPCJWfgcn8aw9t8I,21487
153
+ rslearn/utils/geometry.py,sha256=S60uEvCQ3SyR2-3TJ1yUucFmGRM_rcoIT_gH83PN3RE,21485
151
154
  rslearn/utils/get_utm_ups_crs.py,sha256=kUrcyjCK7KWvuP1XR-nURPeRqYeRO-3L8QUJ1QTF9Ps,3599
152
155
  rslearn/utils/grid_index.py,sha256=hRmrtgpqN1pLa-djnZtgSXqKJlbgGyttGnCEmPLD0zo,2347
153
156
  rslearn/utils/jsonargparse.py,sha256=TRyZA151KzhjJlZczIHYguEA-YxCDYaZ2IwCRgx76nM,4791
@@ -156,12 +159,13 @@ rslearn/utils/raster_format.py,sha256=qZpbODF4I7BsOxf43O6vTmH2TSNw6N8PP0wsFUVvdI
156
159
  rslearn/utils/rtree_index.py,sha256=j0Zwrq3pXuAJ-hKpiRFQ7VNtvO3fZYk-Em2uBPAqfx4,6460
157
160
  rslearn/utils/spatial_index.py,sha256=eomJAUgzmjir8j9HZnSgQoJHwN9H0wGTjmJkMkLLfsU,762
158
161
  rslearn/utils/sqlite_index.py,sha256=YGOJi66544e6JNtfSft6YIlHklFdSJO2duxQ4TJ2iu4,2920
162
+ rslearn/utils/stac.py,sha256=z93N5ZeEe1oUikX5ILMA5sQEZX276sAeMjsg0TShnSk,5776
159
163
  rslearn/utils/time.py,sha256=2ilSLG94_sxLP3y5RSV5L5CG8CoND_dbdzYEHVtN-I8,387
160
164
  rslearn/utils/vector_format.py,sha256=4ZDYpfBLLxguJkiIaavTagiQK2Sv4Rz9NumbHlq-3Lw,15041
161
- rslearn-0.0.21.dist-info/licenses/LICENSE,sha256=_99ZWPoLdlUbqZoSC5DF4ihiNwl5rTEmBaq2fACecdg,11352
162
- rslearn-0.0.21.dist-info/licenses/NOTICE,sha256=wLPr6rwV_jCg-xEknNGwhnkfRfuoOE9MZ-lru2yZyLI,5070
163
- rslearn-0.0.21.dist-info/METADATA,sha256=SUDvVod3HgoDdLYjRz9dwOL0c6V0SF-dTYuzsA4JJYk,37853
164
- rslearn-0.0.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
165
- rslearn-0.0.21.dist-info/entry_points.txt,sha256=doTBQ57NT7nq-dgYGgTTw6mafcGWb_4PWYtYR4rGm50,46
166
- rslearn-0.0.21.dist-info/top_level.txt,sha256=XDKo90WBH8P9RQumHxo0giLJsoufT4r9odv-WE6Ahk4,8
167
- rslearn-0.0.21.dist-info/RECORD,,
165
+ rslearn-0.0.22.dist-info/licenses/LICENSE,sha256=_99ZWPoLdlUbqZoSC5DF4ihiNwl5rTEmBaq2fACecdg,11352
166
+ rslearn-0.0.22.dist-info/licenses/NOTICE,sha256=wLPr6rwV_jCg-xEknNGwhnkfRfuoOE9MZ-lru2yZyLI,5070
167
+ rslearn-0.0.22.dist-info/METADATA,sha256=UArAfc_JYTffP8-cOwQf5mxh6XUtsRv5cwzFiLWNzLU,37936
168
+ rslearn-0.0.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
169
+ rslearn-0.0.22.dist-info/entry_points.txt,sha256=doTBQ57NT7nq-dgYGgTTw6mafcGWb_4PWYtYR4rGm50,46
170
+ rslearn-0.0.22.dist-info/top_level.txt,sha256=XDKo90WBH8P9RQumHxo0giLJsoufT4r9odv-WE6Ahk4,8
171
+ rslearn-0.0.22.dist-info/RECORD,,