Repository: microsoft/torchgeo

Issue:
Inconsistent patch size of DOFA huge model
### Description

In the implementation file of dofa: https://github.com/microsoft/torchgeo/blob/main/torchgeo/models/dofa.py
It seems the huge version patch_size is confused:
```
def dofa_huge_patch16_224(*args: Any, **kwargs: Any) -> DOFA:
    """Dynamic One-For-All (DOFA) huge patch size 16 model.

    If you use this model in your research, please cite the following paper:

    * https://arxiv.org/abs/2403.15356

    .. versionadded:: 0.6

    Args:
        *args: Additional arguments to pass to :class:`DOFA`.
        **kwargs: Additional keyword arguments to pass to :class:`DOFA`.

    Returns:
        A DOFA huge 16 model.
    """
    kwargs |= {'patch_size': 14, 'embed_dim': 1280, 'depth': 32, 'num_heads': 16}
    model = DOFA(*args, **kwargs)
    return model
```
the function name specifies a patch size of 16, but the function implementation uses a patch size of 14.

### Steps to reproduce

no

### Version

v0.6.2

Hints from issue comments:
@adamjstewart: Thank you for catching this! I think 14 is correct according to https://github.com/zhu-xlab/DOFA/blob/master/models_dwv.py#L113 but I'll double check with the original authors.@adamjstewart: Okay, confirmed it should be 14, not 16. Do you want to open a PR to fix this? Should just be a quick rename in the following places:
```
docs/api/models.rst:.. autofunction:: dofa_huge_patch16_224
tests/models/test_dofa.py:    dofa_huge_patch16_224,
tests/models/test_dofa.py:        dofa_huge_patch16_224()
torchgeo/models/__init__.py:    dofa_huge_patch16_224,
torchgeo/models/__init__.py:    'dofa_huge_patch16_224',
torchgeo/models/dofa.py:def dofa_huge_patch16_224(*args: Any, **kwargs: Any) -> DOFA:
```@mdchuc: Thanks, I created a pull request #2627
Additionally, in the implementation of DOFA, the patch_size is hardcoded to 16, perhap it should be changed to patch_size variable.
class DOFA, from line 296:
```
# MAE encoder specifics
        self.patch_embed = DOFAEmbedding(
            dynamic_embed_dim=128, kernel_size=16, embed_dim=embed_dim
        )
```
I tried to run the huge model with terratorch package and got the inconsistent dimension between image embedding and positional encoding, with positional encoding being shape [1, 257, 1280] and feature shape being [32, 196, 1280] (batch size 32).@adamjstewart: Yes, you are absolutely correct! As you can tell, we didn't do a ton of tests on DOFA-Huge. It's, well... too huge.

Can you add this fix to your PR? I'll fix it in our upstream DOFA repo.

I would also like to add unit tests for this. Do you mind if I push to your PR?@mdchuc: yes that is ok. I will add to my PR.

Solution patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f49379ad..e9033355 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -29,9 +29,9 @@ repos:
           - pillow>=10.4.0
           - pytest>=6.1.2
           - scikit-image>=0.22.0
-          - timm>=1.0.14
+          - timm>=1.0.15
           - torch>=2.6
-          - torchmetrics>=0.10
+          - torchmetrics>=1.6.2
           - torchvision>=0.18
         exclude: (build|data|dist|logo|logs|output)/
   - repo: https://github.com/pre-commit/mirrors-prettier
diff --git a/docs/api/models.rst b/docs/api/models.rst
index 5d8aeb84..f69de422 100644
--- a/docs/api/models.rst
+++ b/docs/api/models.rst
@@ -26,7 +26,7 @@ DOFA
 .. autofunction:: dofa_small_patch16_224
 .. autofunction:: dofa_base_patch16_224
 .. autofunction:: dofa_large_patch16_224
-.. autofunction:: dofa_huge_patch16_224
+.. autofunction:: dofa_huge_patch14_224
 .. autoclass:: DOFABase16_Weights
 .. autoclass:: DOFALarge16_Weights
 
diff --git a/requirements/required.txt b/requirements/required.txt
index e306bc33..2e5c7174 100644
--- a/requirements/required.txt
+++ b/requirements/required.txt
@@ -1,5 +1,5 @@
 # setup
-setuptools==75.8.0
+setuptools==76.0.0
 
 # install
 einops==0.8.1
@@ -13,11 +13,11 @@ pandas==2.2.3
 pillow==11.1.0
 pyproj==3.7.1
 rasterio==1.4.3
-rtree==1.3.0
+rtree==1.4.0
 segmentation-models-pytorch==0.4.0
 shapely==2.0.7
 timm==1.0.15
 torch==2.6.0
-torchmetrics==1.6.1
+torchmetrics==1.6.2
 torchvision==0.21.0
 typing-extensions==4.12.2
diff --git a/requirements/style.txt b/requirements/style.txt
index 95d9319f..68cf2da7 100644
--- a/requirements/style.txt
+++ b/requirements/style.txt
@@ -1,3 +1,3 @@
 # style
 mypy==1.15.0
-ruff==0.9.9
+ruff==0.9.10
diff --git a/torchgeo/models/__init__.py b/torchgeo/models/__init__.py
index 539be671..b0bbe031 100644
--- a/torchgeo/models/__init__.py
+++ b/torchgeo/models/__init__.py
@@ -11,7 +11,7 @@ from .dofa import (
     DOFABase16_Weights,
     DOFALarge16_Weights,
     dofa_base_patch16_224,
-    dofa_huge_patch16_224,
+    dofa_huge_patch14_224,
     dofa_large_patch16_224,
     dofa_small_patch16_224,
 )
@@ -57,7 +57,7 @@ __all__ = (
     'croma_base',
     'croma_large',
     'dofa_base_patch16_224',
-    'dofa_huge_patch16_224',
+    'dofa_huge_patch14_224',
     'dofa_large_patch16_224',
     'dofa_small_patch16_224',
     'get_model',
diff --git a/torchgeo/models/dofa.py b/torchgeo/models/dofa.py
index 7184429a..841b6a96 100644
--- a/torchgeo/models/dofa.py
+++ b/torchgeo/models/dofa.py
@@ -295,7 +295,7 @@ class DOFA(nn.Module):
         # --------------------------------------------------------------------------
         # MAE encoder specifics
         self.patch_embed = DOFAEmbedding(
-            dynamic_embed_dim=128, kernel_size=16, embed_dim=embed_dim
+            dynamic_embed_dim=128, kernel_size=patch_size, embed_dim=embed_dim
         )
         self.num_patches = (img_size // patch_size) ** 2
         self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
@@ -530,8 +530,8 @@ def dofa_large_patch16_224(
     return model
 
 
-def dofa_huge_patch16_224(*args: Any, **kwargs: Any) -> DOFA:
-    """Dynamic One-For-All (DOFA) huge patch size 16 model.
+def dofa_huge_patch14_224(*args: Any, **kwargs: Any) -> DOFA:
+    """Dynamic One-For-All (DOFA) huge patch size 14 model.
 
     If you use this model in your research, please cite the following paper:
 
@@ -544,7 +544,7 @@ def dofa_huge_patch16_224(*args: Any, **kwargs: Any) -> DOFA:
         **kwargs: Additional keyword arguments to pass to :class:`DOFA`.
 
     Returns:
-        A DOFA huge 16 model.
+        A DOFA huge 14 model.
     """
     kwargs |= {'patch_size': 14, 'embed_dim': 1280, 'depth': 32, 'num_heads': 16}
     model = DOFA(*args, **kwargs)
diff --git a/torchgeo/trainers/instance_segmentation.py b/torchgeo/trainers/instance_segmentation.py
index 96997b18..98ebf90b 100644
--- a/torchgeo/trainers/instance_segmentation.py
+++ b/torchgeo/trainers/instance_segmentation.py
@@ -117,7 +117,7 @@ class InstanceSegmentationTask(BaseTask):
            * 'Macro' averaging gives equal weight to each class, and is useful for
              balanced performance assessment across imbalanced classes.
         """
-        metrics = MetricCollection([MeanAveragePrecision(iou_type=('bbox', 'segm'))])  # type: ignore[arg-type]
+        metrics = MetricCollection([MeanAveragePrecision(iou_type=('bbox', 'segm'))])
         self.val_metrics = metrics.clone(prefix='val_')
         self.test_metrics = metrics.clone(prefix='test_')
 


Test patch:
diff --git a/tests/models/test_dofa.py b/tests/models/test_dofa.py
index d6be97c2..8def874a 100644
--- a/tests/models/test_dofa.py
+++ b/tests/models/test_dofa.py
@@ -14,7 +14,7 @@ from torchgeo.models import (
     DOFABase16_Weights,
     DOFALarge16_Weights,
     dofa_base_patch16_224,
-    dofa_huge_patch16_224,
+    dofa_huge_patch14_224,
     dofa_large_patch16_224,
     dofa_small_patch16_224,
 )
@@ -69,7 +69,10 @@ class TestDOFA:
 
 class TestDOFASmall16:
     def test_dofa(self) -> None:
-        dofa_small_patch16_224()
+        model = dofa_small_patch16_224()
+        x = torch.rand(1, 4, 224, 224)
+        wavelengths = [664.6, 559.8, 492.4, 832.8]
+        model(x, wavelengths)
 
 
 class TestDOFABase16:
@@ -95,7 +98,10 @@ class TestDOFABase16:
         return weights
 
     def test_dofa(self) -> None:
-        dofa_base_patch16_224()
+        model = dofa_base_patch16_224()
+        x = torch.rand(1, 4, 224, 224)
+        wavelengths = [664.6, 559.8, 492.4, 832.8]
+        model(x, wavelengths)
 
     def test_dofa_weights(self, mocked_weights: WeightsEnum) -> None:
         dofa_base_patch16_224(weights=mocked_weights)
@@ -135,7 +141,10 @@ class TestDOFALarge16:
         return weights
 
     def test_dofa(self) -> None:
-        dofa_large_patch16_224()
+        model = dofa_large_patch16_224()
+        x = torch.rand(1, 4, 224, 224)
+        wavelengths = [664.6, 559.8, 492.4, 832.8]
+        model(x, wavelengths)
 
     def test_dofa_weights(self, mocked_weights: WeightsEnum) -> None:
         dofa_large_patch16_224(weights=mocked_weights)
@@ -152,6 +161,9 @@ class TestDOFALarge16:
         dofa_large_patch16_224(weights=weights)
 
 
-class TestDOFAHuge16:
+class TestDOFAHuge14:
     def test_dofa(self) -> None:
-        dofa_huge_patch16_224()
+        model = dofa_huge_patch14_224()
+        x = torch.rand(1, 4, 224, 224)
+        wavelengths = [664.6, 559.8, 492.4, 832.8]
+        model(x, wavelengths)