https://m.toutiao.com/is/AfE658m/ 目錄 一、Pytorch簡介 二、實驗過程 2.1數據集介紹 2.2加載數據 2.3數據預處理 2.3.1特征轉換 2.3.2缺失值處理 2.3.3樣本不平衡處理 2.4特征工程 2.4.1劃分訓練集和測試集 2.4.2數據類型轉換 2.5構建模型 2.5.1可視化神經元 2.5.2激活函 2.5.3訓練神經網絡 2.6保存模型 2.7模型評估 2.8模型預測 三、總結 一、Pytorch簡介 PyTorch是一個基于python的科學計算包,主要針對兩類人群: 作為NumPy的替代品,可以利用GPU的性能進行計算 作為一個高靈活性、速度快的深度學習平臺 在PyTorch中搭建神經網絡并使用真實的天氣信息預測明天是否會下雨。 預處理 CSV 文件并將數據轉換為張量 PyTorch是一個基于python的科學計算包,主要針對兩類人群: 作為NumPy的替代品,可以利用GPU的性能進行計算 作為一個高靈活性、速度快的深度學習平臺 在PyTorch中搭建神經網絡并使用真實的天氣信息預測明天是否會下雨。 預處理 CSV 文件并將數據轉換為張量 使用 PyTorch 構建神經網絡模型 使用 PyTorch 構建神經網絡模型 使用損失函數和優(yōu)化器來訓練模型 評估模型并了解分類不平衡的危害 在開始構建神經網絡之前,首先了解一下幾個重要概念。 torch.Tensor 一個多維數組,支持諸如backward()等的自動求導操作,同時也保存了張量的梯度。 nn.Module 神經網絡模塊。是一種方便封裝參數的方式,具有將參數移動到GPU、導出、加載等功能。 nn.Parameter 張量的一種,當它作為一個屬性分配給一個Module時,它會被自動注冊為一個參數。 autograd.Function 實現了自動求導前向和反向傳播的定義,每個Tensor至少創(chuàng)建一個Function節(jié)點,該節(jié)點連接到創(chuàng)建Tensor的函數并對其歷史進行編碼。 二、實驗過程 2.1數據集介紹 數據集包含來自多個澳大利亞氣象站的每日天氣信息。本次目標是要回答一個簡單的問題:明天會下雨嗎? 2.2加載數據 首先導入本次實驗用到的第三方庫 import torch import osimport numpy as npimport pandas as pdfrom tqdm import tqdmimport seaborn as snsfrom pylab import rcParamsimport matplotlib.pyplot as pltfrom matplotlib import rcfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import confusion_matrix, classification_reportfrom torch import nn, optimimport torch.nn.functional as F %matplotlib inline%config InlineBackend.figure_format='retina' sns.set(style='whitegrid', palette='muted', font_scale=1.2)HAPPY_COLORS_PALETTE = ['#01BEFE', '#FFDD00', '#FF7D00', '#FF006D', '#93D30C', '#8F00FF']sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))rcParams['figure.figsize'] = 12, 6RANDOM_SEED = 42np.random.seed(RANDOM_SEED)torch.manual_seed(RANDOM_SEED) 接下來先通過Pandas讀取導入數據集
這里有很多特征列。也有很多NaN。下面來看看整體數據集大小。 df.shape (145460, 23) 從數據集形狀看,這里數據還不少,超過14.5w條數據。 2.3數據預處理 在數據預處理這,我們并不希望數據集和目標問題有多復雜,嘗試將通過刪除大部分數據來簡化這個問題。這里只使用4個特征來預測明天是否會下雨。在你實際案例中,根據實際問題,特征數量可以比這多,也可以比這少,只要注意下面輸入數據維度即可。
2.3.1特征轉換 因為神經網絡只能處理數字。所以我們將把文字的 yes 和 no 分別轉換為數字1 和 0。 df['RainToday'].replace({'No': 0, 'Yes': 1}, inplace = True)df['RainTomorrow'].replace({'No': 0, 'Yes': 1}, inplace = True) 2.3.2缺失值處理 刪除缺少值的行。也許會有更好的方法來處理這些缺失的行,但我們這里將簡單地處理,直接刪除含有缺失值的行。
2.3.3樣本不平衡處理 到目前為止,我們有了一個可以使用的數據集。這里我們需要回答的一個重要問題是 -- 我們的數據集是否平衡? 或者 明天到底會下多少次雨? 因此通過sns.countplot函數直接定性分析整個樣本集中是否下雨分別多少次,以此判斷正負樣本(是否有雨)是否平衡。 sns.countplot(df.RainTomorrow); 從結果看,下雨次數明顯比不下雨次數要少很多。再通過具體定量計算正負樣本數。
0.0 0.778762 1.0 0.221238 Name: RainTomorrow, dtype: float64 事情看起來不妙。約78%的數據點表示明天不會下雨。這意味著一個預測明天是否下雨的模型在78%的時間里是正確的。 如果想要解決此次樣本不平衡可以采用欠采樣或過采樣處理,以緩解其帶來的影響,我們暫不做任何處理,但愿他對結果影響不大。 2.4特征工程 2.4.1劃分訓練集和測試集 數據預處理的最后一步是將數據分割為訓練集和測試集。這一步大家應該并不陌生,可以直接使用train_test_split()。 X = df[['Rainfall', 'Humidity3pm', 'RainToday', 'Pressure9am']]y = df[['RainTomorrow']]X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_SEED) 2.4.2數據類型轉換 為了符合 PyTorch 所需求的數據類型。使用 python標準庫將數據加載到numpy數組里。然后將這個數組轉化成將全部數據轉換為張量(torch.Tensor)。 注意:Torch張量和NumPy數組將共享它們的底層內存位置,因此當一個改變時,另外也會改變。
PyTorch中也是非常方便,直接通過from_numpy直接轉換。 X_train = torch.from_numpy(X_train.to_numpy()).float()y_train = torch.squeeze(torch.from_numpy(y_train.to_numpy()).float())X_test = torch.from_numpy(X_test.to_numpy()).float()y_test = torch.squeeze(torch.from_numpy(y_test.to_numpy()).float())print(X_train.shape, y_train.shape)print(X_test.shape, y_test.shape) torch.Size([99751, 4]) torch.Size([99751]) 到目前為止,所有數據準備工作已經結束。 2.5構建模型 接下來我們將使用PyTorch建立一個簡單的神經網絡(NN),嘗試預測明天是否會下雨。本次構建的神經網絡結構分為三個層,輸入層、輸出層和隱藏層。 輸入層: 我們的輸入包含四列數據:'Rainfall, Humidity3pm, RainToday, Pressure9am'(降雨量,濕度下午3點,今天下雨,壓力上午9點)。將為此創(chuàng)建一個適當的輸入層。 輸出層: 輸出將是一個介于 0 和 1 之間的數字,代表模型認為明天下雨的可能性。預測將由網絡的輸出層提供給我們。 隱藏層: 將在輸入層和輸出層之間添加兩個隱藏層。這些層的參數(神經元)將決定最終輸出。所有層都將是全連接的,即全連接層。 一個神經網絡的典型訓練過程如下: 定義包含一些可學習參數(或者叫權重)的神經網絡 在輸入數據集上迭代 通過網絡處理輸入 計算loss(輸出和正確答案的距離) 將梯度反向傳播給網絡的參數 更新網絡的權重,一般使用一個簡單的規(guī)則:weight = weight - learning_rate * gradient 可以使用torch.nn包來構建神經網絡。即使用 PyTorch 構建神經網絡的一種簡單方法是創(chuàng)建一個繼承自 torch.nn.Module 的類。 這里將nn.Module子類化(它本身是一個類并且能夠跟蹤狀態(tài))。在這種情況下,我們要創(chuàng)建一個類,該類包含前進步驟的權重,偏差和方法。nn.Module具有許多我們將要使用的屬性和方法(例如.parameters()和.zero_grad())。
我們只需要定義 forward 函數,backward函數會在使用autograd時自動定義,backward函數用來計算導數。我們可以在 forward 函數中使用任何針對張量的操作和計算。 2.5.1可視化神經元 這里的可視化神經元主要基于 net = Net(X_train.shape[1])# pip install graphviz# mac上安裝graphviz 需要用 brew install graphviz ann_viz(net, view=True) 我們首先在構造函數中創(chuàng)建模型的層。forward()方法是奇跡發(fā)生的地方。它接受輸入 并允許它流過每一層。有一個相應的由PyTorch定義到向后傳遞backward()方法,它允許模型從當前發(fā)生的誤差中學習,并修正模型參數。 2.5.2激活函數 細心的小伙伴可能會注意到構建的神經網絡中調用 F.relu 和 torch.sigmoid 。這些是激活函數,那我們?yōu)槭裁葱枰@些? 神經網絡的一個很酷的特性是它們可以近似非線性函數。事實上,已經證明它們可以逼近任何函數。不過,如果想通過堆疊線性層來逼近非線性函數,此時就需要激活函數。激活函數可以讓神經網絡擺脫線性世界并學習更多。通常將其應用于某個層的輸出。 ReLU 從最廣泛使用的激活函數之一的 ReLU 定義開始: 該激活函數簡單易行,其結果就是輸入值與零比較,得到的最大值。 從可視化結果看
Sigmoid 它被定義為: 當需要進行二元決策 / 分類(回答yes或no)時,sigmoid 函數是很有用的。sigmoid 以一種超級的方式將輸入值壓縮在 0 和 1 之間。 從可視化結果看 ax = plt.gca() plt.plot( np.linspace(-10, 10, 100), torch.sigmoid(torch.linspace(-10, 10, steps=100)).numpy())ax.set_ylim([-0.5, 1.5]); 2.5.3訓練神經網絡 目前為止,我們已經看到了如何定義網絡,接下來需要找到預測明天是否會下雨的參數。即需要找到該模型應用于此次問題的最佳參數。而要想做到這點,首先需要一些評價指標來告訴我們,該模型目前做得有多好。接下來需要計算損失,并更新網絡的權重。 損失函數 一個損失函數接受一對(output, target)作為輸入,計算一個值來估計網絡的輸出和目標值相差多少。BCELoss是一個損失函數,其度量兩個向量之間的差。
而在我們的例子中,這兩個向量即是我們的模型的預測和實際值。該損失函數的期望值由 sigmoid 函數輸出。該值越接近 0,模型效果越好。 但是我們如何找到最小化損失函數的參數呢? 優(yōu)化器 假設我們的神經網絡的每個參數都是一個旋鈕。優(yōu)化器的工作是為每個旋鈕找到完美的位置,使損失接近0。實戰(zhàn)中,模型可能包含數百萬甚至數十億個參數。有這么多旋鈕要轉,如果有一個高效的優(yōu)化器可以快速找到解決方案,那就完美了。而理想很豐滿,現實很骨感。深度學習中的優(yōu)化效果只能達到令人滿意的結果。在實踐中,可以提供可接受的準確性的足夠好的參數,就應該心滿意足了。在使用神經網絡時,PyTorch中提供了許多經過良好調試過的優(yōu)化器,可能希望使用各種不同的更新規(guī)則,如SGD、Nesterov-SGD、Adam、RMSProp等。雖然你可以從這些優(yōu)化器中選擇,一般情況下,首選的還是Adam。 optimizer = optim.Adam(net.parameters(), lr=0.001) 一個模型的可學習參數可以通過net.parameters()。 自然地,優(yōu)化器需要輸入參數。第二個參數lr 是 learning rate (學習率),這是要找到的最優(yōu)參數和到達最優(yōu)解的速度之間的權衡。而為此找到最優(yōu)解的方法或過程可能是黑魔法和大量的暴力“實驗”。 在 GPU 上計算 在 GPU 上進行大規(guī)模并行計算是現代深度學習的推動因素之一。為此,您將需要配置 NVIDIA GPU。如果你的設備上裝有GPU,PyTorch 中可以非常輕松地將所有計算傳輸到 GPU。 我們首先檢查 CUDA 設備是否可用。然后,我們將所有訓練和測試數據傳輸到該設備。最后移動模型和損失函數。張量可以使用.to方法移動到任何設備(device)上。
尋找最優(yōu)參數 擁有損失函數固然很好,追蹤模型的準確性是一件更容易理解的事情,而一般通過定義準確性來做模型評價。 def calculate_accuracy(y_true, y_pred):predicted = y_pred.ge(.5).view(-1)return (y_true == predicted).sum().float() / len(y_true) 我們定義一個預值,將連續(xù)概率值轉換為二分類值。即將每個低于 0.5 的值轉換為 0,高于0.5的值設置為 1。最后計算正確值的百分比。所有的模塊都準備好了,我們可以開始訓練我們的模型了。
在訓練期間,我們向模型傳輸數據共計10,000次。每次測量損失時,將誤差傳播到模型中,并要求優(yōu)化器找到更好的參數。用 zero_grad() 方法清零所有參數的梯度緩存,然后進行隨機梯度的反向傳播。如果忽略了這一步,梯度將會累積,導致模型不可用。測試集上的準確率為 83.4% 聽起來挺合理,但可能要讓你失望了,這樣的結果并不是很理想,接下來看看是如何不合理。但首先我們需要學習如何保存和加載訓練好的模型。 2.6保存模型 訓練一個好的模型可能需要很多時間??赡苁菐字堋讉€月甚至幾年。如果在訓練過程了忘記保存,或不知道需要保存模型,這將會是非常痛苦的事情。因此這里需要確保我們知道如何保存寶貴的工作。其實保存很容易,但你不能忘記這件事。 MODEL_PATH = 'model.pth' # 后綴名為 .pthtorch.save(net, MODEL_PATH) # 直接使用torch.save()函數即可 當然恢復模型也很容易,直接使用 torch.load() 函數即可。
2.7模型評估 如果知道你的模型會犯什么樣的錯誤不是很好嗎?當然,這一點是非常難做到的。但是你可以通過一定的方法得到一個估計值。而僅使用準確性來評估并不是一個好方法,尤其在樣本不平衡的二分類數據集上。仔細回想一下,我們的數據是一個很不平衡的數據集,其幾乎不包含明天會降雨樣本。深入研究模型性能的一種方法是評估每個類的精確度和召回率。在我們的例子中,將是結果標簽分別是 no rain 和 rain 。 classes = ['No rain', 'Raining']y_pred = net(X_test)y_pred = y_pred.ge(.5).view(-1).cpu()y_test = y_test.cpu()print(classification_report(y_test, y_pred, target_names=classes)) 精確度最大值為1,表明該模型只適用于識別相關的樣本。召回率最大值為1,表示模型可以在這個類的數據集中找到所有相關的示例??梢钥吹侥P驮跓o雨類方面表現良好,因為樣本中無雨類樣本數量較大。不幸的是,我們不能完全相信有雨類的預測,因為樣本不平衡導致模型傾向于無雨類。可以通過查看一個簡單的混淆矩陣來評估二分類效果。
你可以清楚地看到,當我們的模型預測要下雨時,我們應該抱有懷疑的態(tài)度。 2.8模型預測 使用一些假設的例子上測試下模型。 def will_it_rain(rainfall, humidity, rain_today, pressure):t = torch.as_tensor([rainfall, humidity, rain_today, pressure]) \.float() \.to(device)output = net(t)return output.ge(0.5).item() 這個函數將根據模型預測返回一個布爾值。讓我們試試看:
will_it_rain(rainfall=0, humidity=1,rain_today=False, pressure=100)>>> False 根據一些參數得到了兩種不同的返回值。到這里為止,模型已準備好部署來,但實際情況下,請不要匆忙部署,因為該模型并不是一個最佳的狀態(tài),只是用來掩飾如何使用PyTorch搭建模型! 三、總結 如果你看到這里,將給你點個贊!因為你現在成功搭建了一個可以預測天氣的神經網絡深度學習模型。雖然此次用PyTorch搭建的深度學習模型是一個入門級別的模型,但其他更加復雜的神經網絡模型的核心步驟與此類似。 說實話,構建性能良好的模型真的很難,但在多次搭建模型過程中,你會不斷學到一些技巧,并能夠不斷進步,這將會幫助你以后做的更好。 |
|
來自: 山峰云繞 > 《Python代碼知識游戲黑客編程與英語》