PyTorch实战1——预测未来某地区租赁单车的使用情况
傳送門:藍(lán)橋云課實(shí)驗(yàn)
目錄
- 1. 實(shí)驗(yàn)環(huán)境
- 2. 實(shí)驗(yàn)?zāi)康?/li>
- 3. 相關(guān)原理
- 4. 實(shí)驗(yàn)步驟
- 4.1 數(shù)據(jù)預(yù)處理
- 4.1.1 對于類型變量的處理
- 4.1.2 對于數(shù)值類型變量進(jìn)行標(biāo)準(zhǔn)化
- 4.1.3 數(shù)據(jù)集分割
- 4.2 創(chuàng)建模型
- 手寫用Tensor運(yùn)算的人工神經(jīng)網(wǎng)絡(luò)
- 4.3 訓(xùn)練模型
- 4.3.1 數(shù)據(jù)的分批次處理
- 4.4 測試模型
1. 實(shí)驗(yàn)環(huán)境
Jupyter Notebook
Python 3.7
PyTorch 1.4.0
2. 實(shí)驗(yàn)?zāi)康?/h1>
構(gòu)建人工神經(jīng)網(wǎng)絡(luò),并用它來預(yù)測未來某地區(qū)租賃單車的使用情況。
3. 相關(guān)原理
數(shù)據(jù)歸一化、類型變量的轉(zhuǎn)換。
搭建基本神經(jīng)網(wǎng)絡(luò)的方法。
數(shù)據(jù)分批次訓(xùn)練原則。
測試及簡單分析神經(jīng)網(wǎng)絡(luò)的方法
4. 實(shí)驗(yàn)步驟
#數(shù)據(jù)的下載與解壓: !wget http://labfile.oss.aliyuncs.com/courses/1073/bike-sharing-dataset.zip !unzip bike-sharing-dataset.zip數(shù)據(jù)都在文件“hour.csv”中,該文件大小為 1.2M,完全可以直接讀取到內(nèi)存中
數(shù)據(jù)文件記錄了每小時(shí)(hr)共享單車的使用數(shù)量(cnt),除了這兩個(gè)數(shù)據(jù)項(xiàng)外,還包括當(dāng)天的日期(dteday),季節(jié)(season),星期幾(weekday),是否是假期(holiday),當(dāng)天的溫度、濕度、風(fēng)速、用戶是否注冊等等,我們就是要使用這些數(shù)據(jù)訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型。
4.1 數(shù)據(jù)預(yù)處理
import numpy as np import pandas as pd #讀取csv文件的庫 import matplotlib.pyplot as plt import torch from torch.autograd import Variable import torch.optim as optim# 讓輸出的圖形直接在Notebook中顯示 %matplotlib inline#首先,讓我們再來看看數(shù)據(jù)長什么樣子 #讀取數(shù)據(jù)到內(nèi)存中,rides為一個(gè)dataframe對象 data_path = 'bike-sharing-dataset/hour.csv' rides = pd.read_csv(data_path) rides.head() #運(yùn)用 pandas 模塊的 head 方法,將數(shù)據(jù)的數(shù)據(jù)表頭和部分?jǐn)?shù)據(jù)項(xiàng)打印出來。4.1.1 對于類型變量的處理
類型變量是指這個(gè)變量的不同值僅僅表達(dá)不同的類型,值的大小不同但沒有高低之分。
有很多變量都屬于類型變量,例如 season=1,2,3,4 代表四季。
我們不能將 season 變量直接輸入到神經(jīng)網(wǎng)絡(luò),這是因?yàn)?season 數(shù)值越高并不表示相應(yīng)的信號強(qiáng)度越大。
解決方案是將類型變量用一個(gè)“一位熱碼“(one-hot)來編碼,也就是:
𝑠𝑒𝑎𝑠𝑜𝑛=1→(1,0,0,0)
𝑠𝑒𝑎𝑠𝑜𝑛=2→(0,1,0,0)
𝑠𝑒𝑎𝑠𝑜𝑛=3→(0,0,1,0)
𝑠𝑒𝑎𝑠𝑜𝑛=4→(0,0,0,1)
因此,如果一個(gè)類型變量有 n 個(gè)不同取值,那么我 one-hot 所對應(yīng)的向量長度就為 n。
例如:
從顯示出的數(shù)據(jù)中可以看到一年四季、12 個(gè)月份、24 個(gè)小時(shí)數(shù)、一周 7 天、天氣情況都已經(jīng)被轉(zhuǎn)化成了 one-hot 變量。
4.1.2 對于數(shù)值類型變量進(jìn)行標(biāo)準(zhǔn)化
由于每個(gè)數(shù)值型變量都是相互獨(dú)立的,所以它們的數(shù)值絕對大小與問題本身沒有關(guān)系。(更看重變化趨勢而非數(shù)值大小)
為了消除數(shù)值大小的差異,我們對每一個(gè)數(shù)值型變量進(jìn)行標(biāo)準(zhǔn)化處理,也就是讓其數(shù)值都圍繞著0左右波動。
比如,對于溫度 temp 這個(gè)變量來說,它在整個(gè)數(shù)據(jù)庫取值的平均值為 mean(temp),方差為 std(temp),所以,歸一化的溫度計(jì)算為:
這樣做的好處就是可以將不同的取值范圍的變量設(shè)置為讓它們處于一個(gè)平等的地位。
4.1.3 數(shù)據(jù)集分割
首先,在變量集合上,我們分為了特征和目標(biāo)兩個(gè)集合。
其中,特征變量集合包括:年份(yr),是否節(jié)假日( holiday),溫度(temp),濕度(hum),風(fēng)速(windspeed),季節(jié)1~4(season),天氣1~4(weathersit,不同天氣種類),月份1~12(mnth),小時(shí)0~23(hr),星期0~6(weekday),它們是輸入給神經(jīng)網(wǎng)絡(luò)的變量;
目標(biāo)變量包括:用戶數(shù)(cnt),臨時(shí)用戶數(shù)(casual),以及注冊用戶數(shù)(registered),其中我們僅僅將 cnt 作為我們的目標(biāo)變量,另外兩個(gè)暫時(shí)不做任何處理。
這樣我們就將利用 56 個(gè)特征變量作為神經(jīng)網(wǎng)絡(luò)的輸入,來預(yù)測 1 個(gè)變量作為神經(jīng)網(wǎng)絡(luò)的輸出。
接下來,我們再將 17379 條紀(jì)錄劃分為兩個(gè)集合,分別為前 16875 條記錄作為訓(xùn)練集訓(xùn)練我們的神經(jīng)網(wǎng)絡(luò);后 21 天的數(shù)據(jù),也就是 21x24=504 條記錄作為測試集來檢驗(yàn)我們的模型的預(yù)測效果。這一部分?jǐn)?shù)據(jù)是不參與神經(jīng)網(wǎng)絡(luò)訓(xùn)練的。
4.2 創(chuàng)建模型
# 定義神經(jīng)網(wǎng)絡(luò)架構(gòu),features.shape[1]個(gè)輸入層單元,10個(gè)隱含層,1個(gè)輸出層 input_size = features.shape[1] hidden_size = 10 output_size = 1 batch_size = 128 neu = torch.nn.Sequential( #調(diào)用 torch.nn.Sequential 來構(gòu)造的神經(jīng)網(wǎng)絡(luò)torch.nn.Linear(input_size, hidden_size), #從輸入到隱含層的線性映射torch.nn.Sigmoid(),torch.nn.Linear(hidden_size, output_size), #從隱含到輸出的線性映射 ) cost = torch.nn.MSELoss() # PyTorch 自帶的損失函數(shù) #neu.parameters():neu包含的所有權(quán)重和偏置 lr=0.01:執(zhí)行梯度下降算法的學(xué)習(xí)率 optimizer = torch.optim.SGD(neu.parameters(), lr = 0.01) #PyTorch自帶了優(yōu)化器來自動實(shí)現(xiàn)優(yōu)化算法注:torch.nn.Sequential :作用是將一系列的運(yùn)算模塊按順序搭建成一個(gè)多層的神經(jīng)網(wǎng)絡(luò)。
torch.nn.Sigmoid():隱含層的非線性 Sigmoid 函數(shù)
torch.nn.MSELoss :是 PyTorch 自帶的一個(gè)封裝好的計(jì)算均方誤差的損失函數(shù),它是一個(gè)函數(shù)指針,賦予了變量 cost
cost(x,y) :計(jì)算時(shí)調(diào)用這個(gè)函數(shù),就可以計(jì)算預(yù)測向量 x 和目標(biāo)向量 y 之間的均方誤差。
torch.optim.SGD :調(diào)用了 PyTorch 自帶的隨機(jī)梯度下降算法(Stochastic Gradient Descent,SGD)作為優(yōu)化器。
手寫用Tensor運(yùn)算的人工神經(jīng)網(wǎng)絡(luò)
# 定義神經(jīng)網(wǎng)絡(luò)架構(gòu),features.shape[1]個(gè)輸入層單元,10個(gè)隱含層,1個(gè)輸出層 input_size = features.shape[1] #輸入層單元個(gè)數(shù) hidden_size = 10 #隱含層單元個(gè)數(shù) output_size = 1 #輸出層單元個(gè)數(shù) batch_size = 128 #每隔batch的記錄數(shù) weights1 = Variable(torch.randn([input_size, hidden_size]), requires_grad = True) #第一到二層權(quán)重 biases1 = Variable(torch.randn([hidden_size]), requires_grad = True) #隱含層偏置 weights2 = Variable(torch.randn([hidden_size, output_size]), requires_grad = True) #隱含層到輸出層權(quán)重 def neu(x):#計(jì)算隱含層輸出#x為batch_size * input_size的矩陣,weights1為input_size*hidden_size矩陣,#biases為hidden_size向量,輸出為batch_size * hidden_size矩陣 hidden = x.mm(weights1) + biases1.expand(x.size()[0], hidden_size)hidden = torch.sigmoid(hidden)#輸入batch_size * hidden_size矩陣,mm上weights2, hidden_size*output_size矩陣,#輸出batch_size*output_size矩陣output = hidden.mm(weights2)return output def cost(x, y):# 計(jì)算損失函數(shù)error = torch.mean((x - y)**2)return error def zero_grad():# 清空每個(gè)參數(shù)的梯度信息if weights1.grad is not None and biases1.grad is not None and weights2.grad is not None:weights1.grad.data.zero_()weights2.grad.data.zero_()biases1.grad.data.zero_() def optimizer_step(learning_rate):# 梯度下降算法weights1.data.add_(- learning_rate * weights1.grad.data)weights2.data.add_(- learning_rate * weights2.grad.data)biases1.data.add_(- learning_rate * biases1.grad.data)4.3 訓(xùn)練模型
4.3.1 數(shù)據(jù)的分批次處理
設(shè)置每批處理的數(shù)據(jù)大小 batch_size = 128
# 神經(jīng)網(wǎng)絡(luò)訓(xùn)練循環(huán) losses = [] for i in range(1000):# 每128個(gè)樣本點(diǎn)被劃分為一個(gè)撮,在循環(huán)的時(shí)候一批一批地讀取batch_loss = []# start和end分別是提取一個(gè)batch數(shù)據(jù)的起始和終止下標(biāo)for start in range(0, len(X), batch_size):end = start + batch_size if start + batch_size < len(X) else len(X)xx = Variable(torch.FloatTensor(X[start:end]))yy = Variable(torch.FloatTensor(Y[start:end]))predict = neu(xx)loss = cost(predict, yy)optimizer.zero_grad()loss.backward()optimizer.step()batch_loss.append(loss.data.numpy())# 每隔100步輸出一下?lián)p失值(loss)if i % 100==0:losses.append(np.mean(batch_loss))print(i, np.mean(batch_loss))# 打印輸出損失值 fig = plt.figure(figsize=(10, 7)) plt.plot(np.arange(len(losses))*100,losses, 'o-') plt.xlabel('epoch') plt.ylabel('MSE') 輸出: 0 0.90184915 100 0.26658106 200 0.21872732 300 0.12553026 400 0.085256845 500 0.07389378 ......橫坐標(biāo)表示訓(xùn)練周期,縱坐標(biāo)表示平均誤差。可以看到,平均誤差快速地隨訓(xùn)練周期而下降
4.4 測試模型
# 用訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)在測試集上進(jìn)行預(yù)測 targets = test_targets['cnt'] #讀取測試集的cnt數(shù)值 targets = targets.values.reshape([len(targets),1]) #將數(shù)據(jù)轉(zhuǎn)換成合適的tensor形式 targets = targets.astype(float) #保證數(shù)據(jù)為實(shí)數(shù)# 將屬性和預(yù)測變量包裹在Variable型變量中 x = Variable(torch.FloatTensor(test_features.values)) y = Variable(torch.FloatTensor(targets))# 用神經(jīng)網(wǎng)絡(luò)進(jìn)行預(yù)測 predict = neu(x) predict = predict.data.numpy()# 將后21天的預(yù)測數(shù)據(jù)與真實(shí)數(shù)據(jù)畫在一起并比較 # 橫坐標(biāo)軸是不同的日期,縱坐標(biāo)軸是預(yù)測或者真實(shí)數(shù)據(jù)的值 fig, ax = plt.subplots(figsize = (10, 7))mean, std = scaled_features['cnt'] ax.plot(predict * std + mean, label='Prediction', linestyle = '--') ax.plot(targets * std + mean, label='Data', linestyle = '-') ax.legend() ax.set_xlabel('Date-time') ax.set_ylabel('Counts') # 對橫坐標(biāo)軸進(jìn)行標(biāo)注 dates = pd.to_datetime(rides.loc[test_data.index]['dteday']) dates = dates.apply(lambda d: d.strftime('%b %d')) ax.set_xticks(np.arange(len(dates))[12::24]) _ = ax.set_xticklabels(dates[12::24], rotation=45)
最后就是預(yù)測結(jié)果分析實(shí)驗(yàn)就結(jié)束了
通過數(shù)據(jù)的可視化,兩條曲線基本吻合,但在12.25前后實(shí)際與預(yù)測偏差較大。
考慮現(xiàn)實(shí)12.25是圣誕節(jié),并且之后1.1是元旦節(jié),人們的出行習(xí)慣會有很大不同,又因?yàn)橛?xùn)練樣本只有兩年長度,圣誕節(jié)前后的樣本只有1次,所以沒有辦法對這個(gè)特殊假期的模式進(jìn)行更準(zhǔn)確的預(yù)測。
總結(jié)
以上是生活随笔為你收集整理的PyTorch实战1——预测未来某地区租赁单车的使用情况的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Aria2 Centos7部署
- 下一篇: ecstore session使用