CoolFace
Modelpublic

OneScience-Group/FourCastNet

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
0likes40downloads
fourcastnet.py161 linesDownload Raw Back to model
1import numpy as np2import torch3import torch.nn as nn4from timm.models.layers import trunc_normal_5from einops import rearrange6 7from onescience.modules.embedding.fourcastnetembedding import FourCastNetEmbedding8from onescience.modules.fuser.fourcastnetfuser import FourCastNetFuser9 10 11class FourCastNet(nn.Module):12    """13    FourCastNet 的主模型实现。14 15    该模型使用以下组件完成输入编码与主干特征提取:16 17    - `OneEmbedding(style="FourCastNetEmbedding")`18      - 将二维气象场切分为二维 patch token 序列19    - `OneFuser(style="FourCastNetFuser")`20      - 在二维 patch 网格上重复执行 AFNO 频域混合与 MLP 通道混合21 22    在当前实现中:23 24    - 输入为二维单时刻气象场 `(Batch, Channels, Height, Width)`25    - patch embedding 输出会加上可学习位置编码26    - token 序列随后恢复成 `(PatchGridHeight, PatchGridWidth)` 二维网格27    - 多层 `FourCastNetFuser` 在 patch 网格上完成主干特征提取28    - 最终通过线性头恢复回目标变量场29 30    Args:31        img_size (tuple[int, int]):32            输入空间尺寸 `(Height, Width)`。33        patch_size (tuple[int, int]):34            patch 切分尺寸 `(PatchHeight, PatchWidth)`。35        in_chans (int):36            输入变量通道数。37        out_chans (int):38            输出变量通道数。39        embed_dim (int):40            patch embedding 特征维度。41        depth (int):42            主干 `FourCastNetFuser` 堆叠层数。43        mlp_ratio (float):44            每层 MLP 隐层放大倍数。45        drop_rate (float):46            dropout 比例。47        drop_path_rate (float):48            按层递增的 Stochastic Depth 最大比例。49        num_blocks (int):50            AFNO 的通道分块数。51        sparsity_threshold (float):52            AFNO 的 soft shrink 阈值。53        hard_thresholding_fraction (float):54            AFNO 保留的频率模式比例。55    """56 57    def __init__(58        self,59        img_size=(720, 1440),60        patch_size=(8, 8),61        in_chans=19,62        out_chans=19,63        embed_dim=768,64        depth=12,65        mlp_ratio=4.0,66        drop_rate=0.0,67        drop_path_rate=0.0,68        num_blocks=8,69        sparsity_threshold=0.01,70        hard_thresholding_fraction=1.0,71    ):72        super().__init__()73        self.img_size = img_size74        self.patch_size = patch_size75        self.in_chans = in_chans76        self.out_chans = out_chans77        self.num_features = self.embed_dim = embed_dim78        self.num_blocks = num_blocks79 80        num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0])81        drop_path = np.linspace(0, drop_path_rate, depth).tolist()82 83        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim))84        self.pos_drop = nn.Dropout(p=drop_rate)85        self.patch_grid_height = img_size[0] // self.patch_size[0]86        self.patch_grid_width = img_size[1] // self.patch_size[1]87 88        self.patch_embed = FourCastNetEmbedding(89            img_size=img_size,90            patch_size=patch_size,91            in_chans=in_chans,92            embed_dim=embed_dim,93        )94 95        self.blocks = nn.ModuleList([96            FourCastNetFuser(97                dim=embed_dim,98                mlp_ratio=mlp_ratio,99                drop=drop_rate,100                drop_path=drop_path[i],101                num_blocks=num_blocks,102                sparsity_threshold=sparsity_threshold,103                hard_thresholding_fraction=hard_thresholding_fraction,104            )105            for i in range(depth)106        ])107 108        self.head = nn.Linear(109            embed_dim,110            self.out_chans * self.patch_size[0] * self.patch_size[1],111            bias=False,112        )113 114        trunc_normal_(self.pos_embed, std=0.02)115        self.apply(self._init_weights)116 117    def _init_weights(self, m):118        if isinstance(m, nn.Linear):119            trunc_normal_(m.weight, std=0.02)120            if isinstance(m, nn.Linear) and m.bias is not None:121                nn.init.constant_(m.bias, 0)122        elif isinstance(m, nn.LayerNorm):123            nn.init.constant_(m.bias, 0)124            nn.init.constant_(m.weight, 1.0)125 126    @torch.jit.ignore127    def no_weight_decay(self):128        return {'pos_embed', 'cls_token'}129 130 131    def forward(self, x):132        """133        Args:134            x (torch.Tensor):135                输入张量,形状为 `(Batch, Channels, Height, Width)`。136 137        Returns:138            torch.Tensor:139                输出张量,形状为 `(Batch, out_chans, Height, Width)`。140        """141        Batch = x.shape[0]142 143        x = self.patch_embed(x)144        x = x + self.pos_embed145        x = self.pos_drop(x)146 147        x = x.reshape(Batch, self.patch_grid_height, self.patch_grid_width, self.embed_dim)148        for blk in self.blocks:149            x = blk(x)150 151        x = self.head(x)152        x = rearrange(153            x,154            "b h w (p1 p2 c_out) -> b c_out (h p1) (w p2)",155            p1=self.patch_size[0],156            p2=self.patch_size[1],157            h=self.patch_grid_height,158            w=self.patch_grid_width,159        )160        return x161