PyTorch搭建CNN實現風速預測
數據集
數據集為Barcelona某段時間內的氣象數據,其中包括溫度、濕度以及風速等。本文將利用CNN來對風速進行預測。
特征構造
對於風速的預測,除瞭考慮歷史風速數據外,還應該充分考慮其餘氣象因素的影響。因此,我們根據前24個時刻的風速+下一時刻的其餘氣象數據來預測下一時刻的風速。
一維卷積
我們比較熟悉的是CNN處理圖像數據時的二維卷積,此時的卷積是一種局部操作,通過一定大小的卷積核作用於局部圖像區域獲取圖像的局部信息。圖像中不同數據窗口的數據和卷積核做inner product(內積)的操作叫做卷積,其本質是提純,即提取圖像不同頻段的特征。
上面這段話不是很好理解,我們舉一個簡單例子:
假設最左邊的是一個輸入圖片的某一個通道,為5 × 5 5 \times55×5,中間為一個卷積核的一層,3 × 3 3 \times33×3,我們讓卷積核的左上與輸入的左上對齊,然後整個卷積核可以往右或者往下移動,假設每次移動一個小方格,那麼卷積核實際上走過瞭一個3 × 3 3 \times33×3的面積,那麼具體怎麼卷積?比如一開始位於左上角,輸入對應為(1, 1, 1;-1, 0, -3;2, 1, 1),而卷積層一直為(1, 0, 0;0, 0, 0;0, 0, -1),讓二者做內積運算,即1 * 1+(-1 * 1)= 0,這個0便是結果矩陣的左上角。當卷積核掃過圖中陰影部分時,相應的內積為-1,如上圖所示。
因此,二維卷積是將一個特征圖在width和height兩個方向上進行滑動窗口操作,對應位置進行相乘求和。
相比之下,一維卷積通常用於時序預測,一維卷積則隻是在width或者height方向上進行滑動窗口並相乘求和。 如下圖所示:
原始時序數為:(1, 20, 15, 3, 18, 12. 4, 17),維度為8。卷積核的維度為5,卷積核為:(1, 3, 10, 3, 1)。那麼將卷積核作用與上述原始數據後,數據的維度將變為:8-5+1=4。即卷積核中的五個數先和原始數據中前五個數據做卷積,然後移動,和第二個到第六個數據做卷積,以此類推。
數據處理
1.數據預處理
數據預處理階段,主要將某些列上的文本數據轉為數值型數據,同時對原始數據進行歸一化處理。文本數據如下所示:
經過轉換後,上述各個類別分別被賦予不同的數值,比如"sky is clear"為0,"few clouds"為1。
def load_data(): global Max, Min df = pd.read_csv('Barcelona/Barcelona.csv') df.drop_duplicates(subset=[df.columns[0]], inplace=True) # weather_main listType = df['weather_main'].unique() df.fillna(method='ffill', inplace=True) dic = dict.fromkeys(listType) for i in range(len(listType)): dic[listType[i]] = i df['weather_main'] = df['weather_main'].map(dic) # weather_description listType = df['weather_description'].unique() dic = dict.fromkeys(listType) for i in range(len(listType)): dic[listType[i]] = i df['weather_description'] = df['weather_description'].map(dic) # weather_icon listType = df['weather_icon'].unique() dic = dict.fromkeys(listType) for i in range(len(listType)): dic[listType[i]] = i df['weather_icon'] = df['weather_icon'].map(dic) # print(df) columns = df.columns Max = np.max(df['wind_speed']) # 歸一化 Min = np.min(df['wind_speed']) for i in range(2, 17): column = columns[i] if column == 'wind_speed': continue df[column] = df[column].astype('float64') if len(df[df[column] == 0]) == len(df): # 全0 continue mx = np.max(df[column]) mn = np.min(df[column]) df[column] = (df[column] - mn) / (mx - mn) # print(df.isna().sum()) return df
2.數據集構造
利用當前時刻的氣象數據和前24個小時的風速數據來預測當前時刻的風速:
def nn_seq(): """ :param flag: :param data: 待處理的數據 :return: X和Y兩個數據集,X=[當前時刻的year,month, hour, day, lowtemp, hightemp, 前一天當前時刻的負荷以及前23小時負荷] Y=[當前時刻負荷] """ print('處理數據:') data = load_data() speed = data['wind_speed'] speed = speed.tolist() speed = torch.FloatTensor(speed).view(-1) data = data.values.tolist() seq = [] for i in range(len(data) - 30): train_seq = [] train_label = [] for j in range(i, i + 24): train_seq.append(speed[j]) # 添加溫度、濕度、氣壓等信息 for c in range(2, 7): train_seq.append(data[i + 24][c]) for c in range(8, 17): train_seq.append(data[i + 24][c]) train_label.append(speed[i + 24]) train_seq = torch.FloatTensor(train_seq).view(-1) train_label = torch.FloatTensor(train_label).view(-1) seq.append((train_seq, train_label)) # print(seq[:5]) Dtr = seq[0:int(len(seq) * 0.5)] Den = seq[int(len(seq) * 0.50):int(len(seq) * 0.75)] Dte = seq[int(len(seq) * 0.75):len(seq)] return Dtr, Den, Dte
任意輸出其中一條數據:
(tensor([1.0000e+00, 1.0000e+00, 2.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,
1.0000e+00, 1.0000e+00, 0.0000e+00, 1.0000e+00, 5.0000e+00, 0.0000e+00,
2.0000e+00, 0.0000e+00, 0.0000e+00, 5.0000e+00, 0.0000e+00, 2.0000e+00,
2.0000e+00, 5.0000e+00, 6.0000e+00, 5.0000e+00, 5.0000e+00, 5.0000e+00,
5.3102e-01, 5.5466e-01, 4.6885e-01, 1.0066e-03, 5.8000e-01, 6.6667e-01,
0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 9.9338e-01, 0.0000e+00,
0.0000e+00, 0.0000e+00]), tensor([5.]))
數據被劃分為三部分:Dtr、Den以及Dte,Dtr用作訓練集,Dte用作測試集。
CNN模型
1.模型搭建
CNN模型搭建如下:
class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1d = nn.Conv1d(1, 64, kernel_size=2) self.relu = nn.ReLU(inplace=True) self.Linear1 = nn.Linear(64 * 37, 50) self.Linear2 = nn.Linear(50, 1) def forward(self, x): x = self.conv1d(x) x = self.relu(x) x = x.view(-1) x = self.Linear1(x) x = self.relu(x) x = self.Linear2(x) return x
卷積層定義如下:
self.conv1d = nn.Conv1d(1, 64, kernel_size=2)
一維卷積的原始定義為:
nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
這裡channel的概念相當於自然語言處理中的embedding,這裡輸入通道數為1,表示每一個風速數據的向量維度大小為1,輸出channel設置為64,卷積核大小為2。
原數數據的維度為38,即前24小時風速+14種氣象數據。卷積核大小為2,根據前文公式,原始時序數據經過卷積後維度為:
38 – 2 + 1 = 37
一維卷積後是一個ReLU激活函數:
self.relu = nn.ReLU(inplace=True)
接下來是兩個全連接層:
self.Linear1 = nn.Linear(64 * 37, 50) self.Linear2 = nn.Linear(50, 1)
最後輸出維度為1,即我們需要預測的風速。
2.模型訓練
def CNN_train(): Dtr, Den, Dte = nn_seq() print(Dte[0]) epochs = 100 model = CNN().to(device) loss_function = nn.MSELoss().to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 訓練 print(len(Dtr)) Dtr = Dtr[0:5000] for epoch in range(epochs): cnt = 0 for seq, y_train in Dtr: cnt = cnt + 1 seq, y_train = seq.to(device), y_train.to(device) # print(seq.size()) # print(y_train.size()) # 每次更新參數前都梯度歸零和初始化 optimizer.zero_grad() # 註意這裡要對樣本進行reshape, # 轉換成conv1d的input size(batch size, channel, series length) y_pred = model(seq.reshape(1, 1, -1)) loss = loss_function(y_pred, y_train) loss.backward() optimizer.step() if cnt % 500 == 0: print(f'epoch: {epoch:3} loss: {loss.item():10.8f}') print(f'epoch: {epoch:3} loss: {loss.item():10.10f}') state = {'model': model.state_dict(), 'optimizer': optimizer.state_dict()} torch.save(state, 'Barcelona' + CNN_PATH)
一共訓練100輪:
3.模型預測及表現
def CNN_predict(cnn, test_seq): pred = [] for seq, labels in test_seq: seq = seq.to(device) with torch.no_grad(): pred.append(cnn(seq.reshape(1, 1, -1)).item()) pred = np.array([pred]) return pred
測試:
def test(): Dtr, Den, Dte = nn_seq() cnn = CNN().to(device) cnn.load_state_dict(torch.load('Barcelona' + CNN_PATH)['model']) cnn.eval() pred = CNN_predict(cnn, Dte) print(mean_absolute_error(te_y, pred2.T), np.sqrt(mean_squared_error(te_y, pred2.T)))
CNN在Dte上的表現如下表所示:
MAE | RMSE |
---|---|
1.08 | 1.51 |
到此這篇關於PyTorch搭建CNN實現風速預測的文章就介紹到這瞭,更多相關PyTorch CNN風速預測內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- pytorch實現加載保存查看checkpoint文件
- 關於Pytorch中模型的保存與遷移問題
- pytorch教程網絡和損失函數的可視化代碼示例
- pytorch模型的保存和加載、checkpoint操作
- pytorch如何利用ResNet18進行手寫數字識別