寒假擼了幾把深度學習,感覺頗有意思。
在數(shù)據(jù)科學中,回歸是最基礎的計算。通俗來講,回歸就是找出一堆數(shù)據(jù)之間的函數(shù)關系。線性回歸是最簡單的回歸,很容易利用最小二乘法解決。非線性回歸也可以使用最小二乘法去處理,然而如果數(shù)據(jù)之間看不到明顯的函數(shù)關系,最小二乘法利用起來就比較麻煩,比如下面的數(shù)據(jù)點就很難找到一個合適的數(shù)學函數(shù)進行擬合。
利用神經(jīng)網(wǎng)絡可以對上面的數(shù)據(jù)點進行擬合,下面是一個最簡單的利用Pytorch進行非線性回歸的代碼。
import torchfrom torch import nn,optimimport matplotlib.pyplot as pltimport pandas as pd data = pd.read_csv('temp.csv' ) x = torch.from_numpy(data['time' ].values.reshape(-1 ,1 )).type(torch.float32) y = torch.from_numpy(data['deltaT' ].values.reshape(-1 ,1 )).type(torch.float32)class NonLinearNet (nn.Module) : def __init__ (self) : super(NonLinearNet,self).__init__() self.linear = nn.Sequential( nn.Linear(1 ,20 ), nn.ReLU(), nn.Linear(20 ,12 ), nn.ReLU(), nn.Linear(12 ,1 ) ) def forward (self,x) : out = self.linear(x) return out model = NonLinearNet() loss_fn = nn.MSELoss() optimizer = optim.Adam(model.parameters(),lr = 0.005 )for epoch in range(10000 ): output = model(x) loss = loss_fn(output,y) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 500 == 499 : print('epoch:%d,loss=%.3f' %(epoch+1 ,loss.item())) plt.cla() plt.scatter(x, y, s=3 , color='blue' ) y_pred = model(x) plt.plot(x, y_pred.detach().numpy(), lw=2 , color='red' ) plt.grid() plt.title('epoch:%d,loss=%.3f' %(epoch+1 ,loss.item())) plt.pause(0.05 ) plt.show()
這里數(shù)據(jù)規(guī)模很小,沒有使用GPU計算。擬合過程如下圖所示。
訓練完畢后可以將模型保存下來,可以利用下面的代碼:
torch.save(model.state_dict(),'NonLinearNet.pkl' )
后面就可以直接加載模型對輸入的X數(shù)據(jù)進行Y值預測了,如下面的示例代碼計算x=700時的Y值。
model = NonLinearNet() state_dict = torch.load('NonLinearNet.pkl' ) model.load_state_dict(state_dict) test_x = torch.tensor([[700.0 ]],dtype=torch.float32) print(model(test_x))
程序輸出結(jié)果為:
tensor([[52.3139 ]], grad_fn=<AddmmBackward>)
預測Y=52.3139。
當然這里只是隨便舉了個例子。神經(jīng)網(wǎng)絡也有一大堆莫名其妙的麻煩問題有待解決,比如復現(xiàn)性很差,比如過擬合等等,一不留神就變成了神經(jīng)病網(wǎng)絡,這個有興趣的道友可以自己嘗試。
利用神經(jīng)網(wǎng)絡處理擬合問題一個最大的好處是,每次只需要提供不同的數(shù)據(jù)而無需修改代碼。下面看看擬合100個點的正弦數(shù)據(jù)。代碼很簡單,如下所示。
import torchfrom torch import nn,optimimport matplotlib.pyplot as pltimport pandas as pdimport numpy as np# 準備數(shù)據(jù) x = np.linspace(0 ,2 *np.pi,num=100 ).reshape(-1 ,1 ) ysin = np.sin(x).reshape(-1 ,1 )class NonLinearNet (nn.Module) : def __init__ (self) : super(NonLinearNet,self).__init__() self.linear = nn.Sequential( nn.Linear(1 ,20 ), nn.ReLU(), nn.Linear(20 ,12 ), nn.ReLU(), nn.Linear(12 ,4 ), nn.ReLU(), nn.Linear(4 ,1 ) ) def forward (self,x) : out = self.linear(x) return out model = NonLinearNet() loss_fn = nn.MSELoss() optimizer = optim.Adam(model.parameters(),lr = 0.002 )for epoch in range(10000 ): x = torch.Tensor(x) y = torch.Tensor(ysin) output = model(x) loss = loss_fn(output,y) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 1000 == 999 : print('epoch:%d,loss=%.3f' %(epoch+1 ,loss.item())) plt.cla() plt.scatter(x, y, s=3 , color='blue' ) y_pred = model(x) plt.plot(x, y_pred.detach().numpy(), lw=2 , color='red' ) plt.grid() plt.title('epoch:%d,loss=%.5f' %(epoch+1 ,loss.item())) plt.pause(0.05 ) plt.show()
訓練過程如下圖所示。
來預測一個sin(3*pi)的值。
下一次要訓練余弦數(shù)據(jù),此時只需要替換源數(shù)據(jù)即可。代碼如下所示。
import torchfrom torch import nn,optimimport matplotlib.pyplot as pltimport pandas as pdimport numpy as np# 準備數(shù)據(jù) x = np.linspace(0 ,2 *np.pi,num=100 ).reshape(-1 ,1 )# ysin = np.sin(x).reshape(-1,1) ycos = np.cos(x).reshape(-1 ,1 )class NonLinearNet (nn.Module) : def __init__ (self) : super(NonLinearNet,self).__init__() self.linear = nn.Sequential( nn.Linear(1 ,20 ), nn.ReLU(), nn.Linear(20 ,12 ), nn.ReLU(), nn.Linear(12 ,4 ), nn.ReLU(), nn.Linear(4 ,1 ) ) def forward (self,x) : out = self.linear(x) return out model = NonLinearNet() loss_fn = nn.MSELoss() optimizer = optim.Adam(model.parameters(),lr = 0.002 )for epoch in range(10000 ): x = torch.Tensor(x) y = torch.Tensor(ycos) output = model(x) loss = loss_fn(output,y) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 1000 == 999 : print('epoch:%d,loss=%.3f' %(epoch+1 ,loss.item())) plt.cla() plt.scatter(x, y, s=3 , color='blue' ) y_pred = model(x) plt.plot(x, y_pred.detach().numpy(), lw=2 , color='red' ) plt.grid() plt.title('epoch:%d,loss=%.5f' %(epoch+1 ,loss.item())) plt.pause(0.05 ) plt.show()
余弦數(shù)據(jù)訓練過程如下圖所示。