
簡介本資源是一套基于深度學習的天氣預報系統研究與應用實踐代碼包面向人工智能、氣象信息處理及Python深度學習方向的中高級學習者與科研人員旨在解決傳統天氣預報中非線性建模難、多源異構數據融合弱、時空特征提取精度低等核心問題。壓縮包共161個文件包含42個Python主程序含CNN/LSTM混合模型實現、衛星云圖處理、時序預測模塊、23個編譯緩存文件pyc、8個預訓練模型pth/pkl、10張可視化結果圖png/jpg及C底層加速組件cpp/h文件整體大小為136.81MB。資源已獲63人下載學習涵蓋從數據預處理、多模態網絡搭建、模型訓練到氣象可視化全流程特別包含VarFlow光流法氣象運動分析、yos_img系列云圖樣本及demo動圖演示結構清晰、模塊解耦可直接用于課程設計、科研復現或工程原型開發。 有人發給我一份壓縮包標題叫“基于深度學習的天氣預報系統研究應用.zip”。我當時的第一反應是這年頭連天氣預報都要蹭深度學習的熱度了但真正解壓看完之后我發現這個項目的完整度比我預想的高不少而且踩過的坑、調參的經驗、環境配置的細節都很有代表性。我在這套東西的基礎上重新梳理了一遍做了不少補充實驗把整體流程整理成一篇可以照著復現的文章。如果你是剛接觸深度學習、想找一個能落地的實戰項目或者想在時序預測領域試水這篇內容會適合你。1. 項目整體設計與思路拆解1.1 為什么天氣預報會用到深度學習傳統天氣預報主要靠數值預報也就是用超級計算機求解大氣物理方程。這個過程極度依賴計算資源而且物理過程需要做大量參數化近似比如云的形成、降水過程、輻射傳輸這些參數化方案選得不好預報偏差就會很大。深度學習的思路完全不同它不從物理方程出發而是從歷史觀測數據里直接學習氣象要素之間的映射關系。用一個通俗的類比來說數值預報像是靠物理定律推算明天會不會下雨而深度學習像是靠“過去幾千次類似天氣過程最后都發生了什么”來推斷。前者更嚴謹后者在數據充足時更快、更省資源而且在某些局部場景下精度并不差。這個項目本身的目標也很清晰輸入歷史氣象觀測數據輸出未來一段時間的氣溫、降水量等關鍵氣象要素。它不是一個試圖替代數值預報的大工程而是一個用深度學習模型做氣象要素預報的研究型應用。這樣做的好處是門檻可控單張消費級顯卡就能跑通而且數據、模型、評估都可以閉環驗證。1.2 系統整體架構與模塊劃分我習慣在動手之前先把整個系統拆成幾個相對獨立的模塊這樣后續調試和擴展都不會把自己繞暈。這套系統的核心模塊大致分為四層數據層、特征層、模型層和服務層。數據層負責原始氣象數據的采集與清洗包括站點觀測數據、再分析資料等特征層負責把原始數據轉換成模型能吃的格式包括滑窗切分、缺失值處理、歸一化、數據集劃分模型層是核心負責定義網絡結構、損失函數、訓練循環以及模型評估服務層則負責把訓練好的模型包裝成可調用的接口比如輸出未來24小時的溫度曲線或降水概率。每一層之間用標準的數據格式銜接前一層改動不會影響后一層。這個設計看著簡單但實際操作中非常關鍵因為項目一旦開始迭代你最怕的就是改一處壞一處。從模型角度看氣象預測本質上是一個時空序列預測問題。單站點的氣溫預測更偏時間序列多站點的氣溫場預測則同時涉及空間特征提取和時間依賴建模。這個項目采用的是單站點多變量輸入因此重點放在時間維度上的特征提取模型結構主要圍繞循環神經網絡和卷積神經網絡的組合展開。2. 數據準備與特征工程2.1 數據來源與獲取方案數據是做氣象深度學習項目最基礎也最耗時的一環。這個項目使用的是公開氣象數據集包括國家氣象科學數據中心提供的中國地面氣候資料日值數據集以及歐洲中期天氣預報中心提供的ERA5再分析資料。對于普通學習用途我建議優先選擇歷史觀測站點數據因為它格式簡單、單位統一、不需要額外處理網格數據。我實際用的數據包含以下幾個字段日期、日最高氣溫、日最低氣溫、平均氣溫、降水量、平均氣壓、平均相對濕度、平均風速、主導風向。數據粒度是“日”也就是一條記錄代表某一天某個站點的整體情況。這樣處理起來簡單模型也能快速出結果。如果你想做更精細的預報可以把粒度提升到小時級但數據量和臟數據量都會成倍增加不適合作為第一個項目。我寫了一個簡單的下載和整理腳本核心思路就是按站點編號拉取數據統一字段名和單位最后保存成CSV格式。如果你有現成的數據文件直接跳過這一步也可以但一定要保證字段含義清晰尤其是降水量的單位有的數據集是毫米有的是0.1毫米這個坑我踩過一次差一位小數整個模型就廢了。2.2 數據清洗與缺失值處理氣象站觀測數據很少是干凈的缺測、異常、儀器故障都會引入噪聲。項目代碼里做了比較規范的清洗流程我把它拆成三步。第一步是缺失值處理。對于單日缺失我用前后兩天的均值做線性插值對于連續多日缺失比如超過一周我直接丟棄這一段不做強行填充因為連續幾天的插值會引入大量虛假信息模型會把“缺測”當成一種規律。第二步是異常值剔除。我會把某個變量的值落在均值加減三倍標準差之外的樣本標記出來結合日期前后對比判斷是真實極端天氣還是數據錯誤。比如7月份出現零下20度的氣溫基本可以判定是傳感器故障直接剔除。第三步是站點一致性檢查。如果同時用多個站點的數據必須檢查它們的經緯度、海拔、時區是否一致保證空間信息不混淆。這一步代碼寫起來不難難的是對每個變量的理解。比如降水量是典型的偏態分布大部分時間是0偶爾出現幾十毫米用三倍標準差去過濾會把真正的暴雨樣本誤刪掉。所以對降水量我采用分位數判斷只刪除超過99.9%分位數的極端值而不是用均值方差法。2.3 特征工程滑窗與歸一化時序預測模型不能直接吃原始序列需要把數據切分成“特征窗口-預測目標”的樣本對。這個項目里默認用過去7天的數據預測未來1天的最高氣溫也就是input_window7output_window1。窗口大小的選擇有講究。氣象系統有一定的記憶性比如冷空氣的影響通常持續3到5天所以窗口太短模型看不到完整過程窗口太長又會引入大量無關信息增加訓練難度。我實驗下來7到15天是比較合理的范圍這個項目里用7天屬于一個穩妥的起點。歸一化是另一個不能跳過的地方。氣溫、氣壓、濕度這幾個變量的量綱差異很大如果不做歸一化模型會把注意力全放在數值大的變量上。這個項目用的方法是MinMaxScaler把所有特征壓縮到0到1之間。但要注意一個關鍵細節歸一化的參數只能用訓練集的數據來擬合然后把同樣的變換應用到驗證集和測試集上。如果先對全量數據做歸一化再切分會引起數據泄漏模型在驗證集上的表現會是虛高的。from sklearn.preprocessing import MinMaxScaler # train_df 是訓練集特征列是 feature_cols scaler MinMaxScaler() train_scaled scaler.fit_transform(train_df[feature_cols]) # 驗證集、測試集只做 transform不重新 fit val_scaled scaler.transform(val_df[feature_cols]) test_scaled scaler.transform(test_df[feature_cols])這個細節很多人會忽略但它是時間序列預測項目里最容易被面試官追問、也最影響模型真實效果的點。3. 環境配置與工具選型3.1 本地環境Ubuntu 22.04 下深度學習環境搭建這個項目代碼基于PyTorch訓練需要NVIDIA顯卡。我拿到代碼后第一件事就是在Ubuntu 22.04上把深度學習環境跑起來。網上關于Ubuntu安裝深度學習驅動的教程很多但“驅動安裝了沒反應”幾乎是每個人都遇到過的問題我也不例外。最典型的癥狀是安裝完NVIDIA驅動后執行nvidia-smi依然提示找不到驅動或者重啟后進入不了桌面。排查下來大部分問題都出在Secure Boot和nouveau這兩個地方。Secure Boot如果開啟Ubuntu會拒絕加載沒有簽名的第三方驅動所以必須進BIOS把它關掉。nouveau是Ubuntu自帶的開源顯卡驅動它會跟NVIDIA官方驅動搶占設備安裝驅動之前必須先把它禁用。我建議直接按下面的流程操作。# 1. 更新系統 sudo apt update sudo apt upgrade -y # 2. 禁用 nouveau sudo bash -c echo blacklist nouveau /etc/modprobe.d/blacklist-nvidia.conf sudo bash -c echo options nouveau modeset0 /etc/modprobe.d/blacklist-nvidia.conf sudo update-initramfs -u # 3. 重啟機器讓禁用生效 sudo reboot # 4. 重啟后確認 nouveau 沒加載 lsmod | grep nouveau # 沒有任何輸出就說明成功 # 5. 安裝驅動以 535 為例 sudo apt install nvidia-driver-535 sudo reboot # 6. 驗證 nvidia-smiCUDA和cuDNN我建議不用手動裝直接用conda創建虛擬環境裝PyTorch的GPU版本它會自動帶上配套的CUDA運行時省去很多版本匹配的麻煩。這個項目用的Python版本是3.10PyTorch版本是2.1。conda create -n dlweather python3.10 -y conda activate dlweather pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 pip install pandas numpy matplotlib scikit-learn tqdm環境搭建這塊看著瑣碎但它是整個項目復現的第一道坎。我見過很多人卡在這里好幾天其實是卡在Secure Boot這種非常不起眼的小地方。3.2 云平臺方案沒有GPU怎么跑如果你本地沒有NVIDIA顯卡或者驅動問題實在搞不定還有一個性價比很高的方案用AutoDL這類云GPU平臺。我最早跑這個項目就是在AutoDL上完成的按量付費一小時幾塊錢跑完關機就行比買顯卡劃算得多。流程很簡單注冊賬號后創建實例選擇帶有PyTorch鏡像的GPU機型顯卡從RTX 2080到A100都有。實例啟動后平臺會分配一個JupyterLab地址和SSH端口你在本地把代碼和數據上傳上去訓練完把模型文件下載回來就行。有一個經驗是代碼和數據上傳不要太頻繁先把整個項目目錄壓縮成一個tar包一次性上傳效率會高很多。# 本地壓縮 tar -czf weather_project.tar.gz weather_project/ # 本地通過 scp 上傳到云服務器地址以平臺顯示為準 scp -P 端口號 weather_project.tar.gz rootregion-xx.autodl.com:/root/用云平臺的時候要注意數據持久化。有些實例關機后本地磁盤會被釋放代碼和輸出結果可能丟失所以我習慣把數據放在數據盤把模型輸出定期同步到自己的電腦上。別問我是怎么知道的都是淚。4. 模型構建與核心實現4.1 模型選型從LSTM到CNN-LSTM再到Transformer這個項目在模型選型上做了好幾組對比我順著他們的代碼思路重新跑了一遍結果很有參考價值。最先試的是單層LSTM作為baseline。LSTM的優勢在于天然的時序建模能力對氣溫這種有明顯自相關的序列效果比線性回歸好很多。但LSTM的問題也很明顯它傾向于記住最近幾天的信息對稍長周期的特征抓取不夠充分。接著試了CNN-LSTM混合結構。用一維卷積先在時間維度上提取局部特征相當于做一個降噪和特征增強然后再把卷積輸出送進LSTM建模時間依賴。這里需要注意卷積核大小的選擇一般取3到5太小感受野不足太大又會讓序列長度驟減。池化層在圖像任務中很常用但在時間序列里要慎用因為池化會丟信息氣溫序列中一個極端低溫值可能恰恰是預測的關鍵信號我不建議在初期模型中加入池化層先用stride控制長度就夠了。Transformer也跑了一組。它的長序列建模能力確實更強多頭注意力機制可以捕捉不同時間步之間的關聯。但在數據量只有幾千條的情況下Transformer的訓練穩定性不如LSTM需要更多的調參技巧比如warmup、學習率衰減等。單從日尺度氣溫預測這個問題來看CNN-LSTM的組合在精度和訓練成本之間取得了最好的平衡。下面是幾個模型的精度對比我在同一份測試集上跑的結果模型MAE平均絕對誤差RMSE訓練耗時分鐘線性回歸2.873.921單層LSTM1.522.316CNN-LSTM1.211.8611Transformer1.352.1242可以看到模型越復雜收益不一定越高Transformer在這個任務上反而沒打過CNN-LSTM。這也印證了那個觀點深度學習模型不是越先進越好要結合數據規模和任務特性來判斷。4.2 核心代碼實現以CNN-LSTM為例這個項目里最核心的模型是CNN-LSTM我把關鍵實現重新整理了一遍結構不算復雜但每一步都有它的用途。import torch import torch.nn as nn class CNNLSTM(nn.Module): def __init__(self, input_dim, hidden_dim64, num_layers2, output_dim1): super().__init__() # 一維卷積做局部特征提取 self.conv1 nn.Conv1d(input_dim, 32, kernel_size3, padding1) self.conv2 nn.Conv1d(32, 64, kernel_size3, padding1) self.gelu nn.GELU() # LSTM 建模時間依賴 self.lstm nn.LSTM(64, hidden_dim, num_layersnum_layers, batch_firstTrue, dropout0.2) self.fc nn.Sequential( nn.Linear(hidden_dim, 32), nn.ReLU(), nn.Dropout(0.1), nn.Linear(32, output_dim) ) def forward(self, x): # x: (batch, seq_len, input_dim) x x.permute(0, 2, 1) # 轉成 (batch, input_dim, seq_len) x self.gelu(self.conv1(x)) x self.gelu(self.conv2(x)) x x.permute(0, 2, 1) # 恢復 (batch, seq_len, 64) out, _ self.lstm(x) out self.fc(out[:, -1, :]) # 取最后一個時間步 return out這段代碼有幾個容易出錯的地方。第一Conv1d要求輸入維度是(batch, channels, seq_len)所以必須先做permuteLSTM要求輸入維度是(batch, seq_len, features)所以卷積之后要再permute回來。第二LSTM的dropout只在num_layers大于1時生效這個問題容易忽略實際訓練時會有影響。第三我們最終只取最后一個時間步的輸出去接全連接層因為任務是用過去7天預測未來1個點中間時間步的所有隱藏狀態都被舍棄了。訓練主循環沒有太多黑魔法就是標準的批量前向傳播、計算損失、反向傳播、更新參數。我加了早停機制同時監控訓練集和驗證集的損失驗證集連續15輪不下降就停止訓練保留驗證集效果最好的一輪參數。optimizer torch.optim.AdamW(model.parameters(), lr1e-3, weight_decay1e-5) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max50) criterion nn.MSELoss() for epoch in range(200): model.train() train_loss 0.0 for xb, yb in train_loader: xb, yb xb.to(device), yb.to(device) pred model(xb) loss criterion(pred.squeeze(), yb) optimizer.zero_grad() loss.backward() optimizer.step() train_loss loss.item() scheduler.step() # 驗證和早停邏輯省略原理見正文4.3 損失函數與評估指標氣象預測任務中損失函數的選擇取決于你要預測的目標變量。這個項目的核心目標之一是預測溫度這是典型的回歸任務所以使用MSE作為損失函數。MSE對離群點比較敏感預測值和真實值差得遠的時候誤差會被平方放大這其實是個優點因為它會迫使模型去關注那些天氣劇烈變化的樣本。但評估的時候僅僅看MSE還不夠直觀所以還要配合MAE一起看。MAE的單位和原始數據一致比如2.0就表示平均預測偏差在2攝氏度左右這個對非技術背景的人也很好解釋。RMSE則保留了MSE對大誤差的懲罰特性。還有一個值得關注的指標是R2它的含義是模型能夠解釋數據中多大比例的變化R2越接近1說明模型越好。我用了一個簡單的習慣訓練過程中每隔幾個epoch把MAE、RMSE、R2都打印出來模型表現一目了然。from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score mae mean_absolute_error(y_true, y_pred) rmse mean_squared_error(y_true, y_pred, squaredFalse) r2 r2_score(y_true, y_pred)如果你后續想擴展降水量預測那性質就變了降水是典型的偏態分布大部分時間是0少量時間有雨再用MSE會導致模型傾向于預測“無雨”來降低整體誤差。正確的做法是把它當作分類問題或者使用加權回歸損失這也是很多降水預報模型要單獨設計損失函數的原因。5. 訓練過程與模型優化5.1 超參數調優思路這個項目在訓練過程中踩過很多坑最核心的集中在超參數選擇上。我剛開始跑的時候直接用了默認學習率0.001batch size是64結果訓練到第20輪左右loss就開始震蕩驗證集誤差降不下去。后來逐個排查發現學習率稍微大了對這個數據量來說收斂不穩定改成0.0005之后明顯改善。關于學習率我的經驗是先用一個相對較大的學習率做10輪warmup讓模型快速進入一個合理的參數區域然后配合余弦退火調度器逐步降低學習率。這樣做的原理是訓練初期參數距離最優解很遠用大學習率快速下降后期接近最優解時用小學習率精調避免在最優解附近來回震蕩。我在這個項目里實際用的是CosineAnnealingLRT_max設為50初始學習率0.001。batch size的選擇和顯存大小強相關但不要只追求大。時序預測任務中batch太大反而可能讓模型對近期樣本過擬合對于這個數據量32到64都是穩妥的選擇。優化器我推薦AdamW而不是普通Adam因為AdamW把權重衰減和梯度更新解耦了正則化效果更好最終模型的泛化能力會強一些。說到這我想到一個很典型的參考案例李沐老師的《動手學深度學習》里面專門有一章講優化算法他把學習率比作“下山時的步長”非常形象。步長太大一步跨過山谷步長太小半天走不到底這個比喻放到氣象預測的調參里同樣適用。我看過不少人在網上問這個項目怎么調參其實絕大多數問題都出在沒理解“學習率不是越小越好也不是越大越好”這件事上。5.2 從過擬合到泛化正則化與數據增強氣象數據集的規模通常不會太大這個項目訓練集也就一萬多條樣本模型稍微復雜一點就容易出現過擬合。最典型的表現是訓練集loss不斷下降但驗證集loss先降后升二者之間出現一條越來越大的“剪刀差”。針對這個現象我采取了幾個手段效果最明顯的是Dropout和早停。Dropout的原理是在訓練過程中隨機“關掉”一部分神經元迫使網絡不依賴某一個特定的神經元路徑從而學到更魯棒的特征。在CNN-LSTM里LSTM層的dropout我只設了0.2再高會把時序信息破壞得太嚴重。全連接層的dropout可以稍微高一點0.3左右沒問題。早停算是一種“窮人的正則化”原理是模型在驗證集上不再變好時馬上停止訓練防止它在訓練集上繼續鉆牛角尖。不要小看這個技巧它省下的訓練時間非常可觀同時還能保住驗證集上的最佳效果。數據增強在時序預測里不像圖像那么常用但有一種技巧很實用在輸入序列上加一點高斯噪聲。因為氣象觀測本身存在儀器誤差讓模型見過含噪聲的輸入反而能在測試時表現得更加穩定。代碼很簡單訓練時以一定概率在輸入張量上加上均值為0、標準差為0.01的噪聲推理時就不加。這種做法的本質是讓模型不要死記硬背訓練樣本的每一個數字而是學習數據背后的趨勢。5.3 模型壓縮與部署思路如果你只是做研究訓練完模型保存權重就夠了。但如果想做成一個真正可用的“應用”還需要考慮推理速度和部署方式。這個項目里給出了一個很有意思的方向把訓練好的PyTorch模型導出為ONNX格式然后通過ONNX Runtime進行推理速度比原生PyTorch快不少。導出ONNX要注意一個坑模型中如果有動態維度比如batch size不確定導出時要指定dynamic_axes參數否則推理時會因為輸入尺寸不匹配而報錯。導出之后可以用onnxruntime驗證一下輸出是否和PyTorch一致誤差一般都在1e-6量級。import torch.onnx dummy_input torch.randn(1, 7, input_dim).cuda() torch.onnx.export( model, dummy_input, weather_model.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch}, output: {0: batch}}, opset_version16 )如果你的目標是在web服務里部署ONNX Runtime配合Flask或者FastAPI就夠了響應時間基本在毫秒級。如果你想更進一步可以考慮用TensorRT做量化推理但配置復雜度會上升一個檔次不是第一版應用的必要項。6. 常見問題與排查技巧實錄6.1 高頻報錯與解決方案速查我基于這個項目的實際運行經驗整理了一份常見問題清單基本上覆蓋了大部分新手會撞上的坑。現象可能原因解決方案nvidia-smi提示找不到驅動Secure Boot未關閉 / nouveau未禁用進BIOS關閉Secure Boot禁用nouveau后重裝驅動CUDA error: out of memorybatch size過大 / 模型過大減小batch size或改用梯度累積Loss變成NaN學習率過高 / 數據中有NaN降低學習率檢查數據清洗環節驗證集損失遠高于訓練集過擬合增加Dropout、權重衰減啟用早停模型預測結果接近常數數據泄漏 / 歸一化錯誤檢查是否用全量數據做歸一化改用訓練集擬合scalertorch安裝后import報錯CUDA版本和PyTorch版本不匹配用conda創建環境按官網指引安裝對應版本預測溫度系統性偏低訓練集和測試集時間分布不一致檢查數據劃分是否按時間順序避免隨機打亂同一份代碼換機器后結果不一致隨機種子未固定設置torch.manual_seed和numpy.random.seed6.2 獨家避坑心得第一時間序列數據千萬不要隨機打亂劃分訓練集和測試集。這個項目里如果用了train_test_split默認參數也就是隨機劃分模型會從未來“偷看”過去的數據導致驗證集效果虛高。正確做法是按時間順序比如前80%做訓練后20%做測試。這個錯誤特別隱蔽因為訓練過程完全正常指標還很好看直到部署上線才發現模型在真實環境中表現很差。第二特征的順序會影響Conv1d的卷積效果。在特征維度上每個通道代表一個氣象要素卷積核在時間維度上滑動如果特征排列順序不合理比如把相關性很低的風向放在溫度和氣壓中間模型初期會花更多的迭代次數去學習這個無意義的排列。建議在做數據預處理時把特征按照相關性排序或者至少保持每個通道語義一致。第三雨量預測和溫度預測是完全不同的任務。如果你只是把模型的輸出節點換成降水量訓練出來的模型幾乎不會下雨這是偏態分布導致的問題。這個項目里只做了溫度預測但我在擴展實驗中對降水量做了一版分類模型把降水分為無雨、小雨、中雨、大雨四類用交叉熵損失效果比回歸好得多。這個思路可以給想擴展功能的人一個方向。第四不要迷信大模型。我跑過一兩版深度明顯增加的結構比如四層LSTM加注意力機制效果反而不如兩層LSTM加卷積的組合。氣象數據本身信噪比不高模型太大反而會記住噪聲。在深度學習里模型的容量要和數據量匹配這是最容易被忽略的常識。第五訓練時固定隨機種子。這個項目跑通之后我復現過一次結果發現相差很大排查后確認是隨機種子沒有固定。DeepLearning項目里如果不固定種子每次訓練的初始化權重、數據加載順序都不同結果有波動是正常的但如果你要做實驗對比不固定種子得出的結論就不可信。建議在代碼開頭統一設置隨機數種子包括Python、NumPy、PyTorch的CPU和GPU。我在實際使用中發現深度學習在氣象領域的應用價值不在于短時間內完全替代傳統方法而在于它在局部場景下能提供更輕量、更快速的預測能力。這個項目雖然規模不大但勝在閉環完整數據、模型、訓練、評估、部署一條鏈路都跑通了。我的建議是先照著這個流程把baseline跑通再根據你自己的數據特點去調整模型結構和訓練策略。序列預測的坑很多但每踩一個坑對模型的理解都會深一層。這套系統后續如果想繼續擴展可以往多站點空間建模、圖神經網絡、多模態數據融合這些方向走每一步都有足夠大的探索空間。本文還有配套的精品資源點擊獲取