目錄
- 資料集
- 特征構造
- 一維卷積
- 資料處理
- 1.資料預處理
- 2.資料集構造
- CNN模型
- 1.模型搭建
- 2.模型訓練
- 3.模型預測及表現
資料集

資料集為Barcelona某段時間內的氣象資料,其中包括溫度、濕度以及風速等,本文將利用CNN來對風速進行預測,
特征構造
對于風速的預測,除了考慮歷史風速資料外,還應該充分考慮其余氣象因素的影響,因此,我們根據前24個時刻的風速+下一時刻的其余氣象資料來預測下一時刻的風速,
一維卷積
我們比較熟悉的是CNN處理影像資料時的二維卷積,此時的卷積是一種區域操作,通過一定大小的卷積核作用于區域影像區域獲取影像的區域資訊,影像中不同資料視窗的資料和卷積核做inner product(內積)的操作叫做卷積,其本質是提純,即提取影像不同頻段的特征,
上面這段話不是很好理解,我們舉一個簡單例子:

假設最左邊的是一個輸入圖片的某一個通道,為
5
×
5
5 \times5
5×5,中間為一個卷積核的一層,
3
×
3
3 \times3
3×3,我們讓卷積核的左上與輸入的左上對齊,然后整個卷積核可以往右或者往下移動,假設每次移動一個小方格,那么卷積核實際上走過了一個
3
×
3
3 \times3
3×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 |

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398532.html
標籤:其他
上一篇:STM32之DAC音頻播放
