(三)PyTorch——多層神經網絡

線性迴歸中,公式是y=wx+b;在Logistic迴歸中,公式是y=Sigmoid(wx+b),可以看成是單層神經網絡,其中sigmod稱爲激活函數。

 

 

 左邊是一張神經元的圖片,神經元通過突觸接受輸入,然後通過神經激活的方式傳輸給後面的神經元。這對比於右邊的神經網絡,首先接受數據輸入,然後通過計算得到結果,接着經過激活函數,再傳給第二層的神經元。

 

激活函數:加入非線性的因素,以解決線性模型表達能力不足的缺陷。

 線性整流函數:

 雙曲正切:

S型函數: 

 

 

 ReLU激活函數:現在神經網絡中90%的情況都是使用這個激活函數。一般一個一層的神經網絡的公式就是y = max(0, wx + b),一個兩層的神經網絡就是y= W2 max(0,w1x + b1)+ b2,非常簡單,但是卻很有效,使用這個激活函數能夠加快梯度下降法的
收斂速度,同時對比與其他的激活函數,這個激活函數計算更加簡單。

 

 

神經網絡的結構:

神經網絡就是很多個神經元堆在一起形成一層神經網絡,那麼多個層堆疊在一起就是深層神經網絡,我們可以通過下面的圖展示一個兩層的神經網絡和三層的神經網絡

 

可以看到,神經網絡的結構其實非常簡單,主要有輸入層,隱藏層,輸出層構成,輸入層需要根據特徵數目來決定,輸出層根據解決的問題來決定,隱藏層的網路層數以及每層的神經元數就是可以調節的參數,而不同的層數和每層的參數對模型的影響非常大。


多層神經網絡,Sequential和Module

 

 

import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

def plot_decision_boundary(model,x,y):
    #Set min and max values and give it some padding
    x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
    y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
    h=0.01
    #Generate a grid of points with distance h between them
    xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
    #Predict the function value for the whole grid
    Z=model(np.c_[xx.ravel(),yy.ravel()])
    Z=Z.reshape(xx.shape)
    #plot the contour and training examples
    plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(x[:,0],x[:,1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
    plt.show()

np.random.seed(1)
m=400#樣本數量
N=int(m/2)#每一類點的個數
D=2#維度
x=np.zeros((m,D))
y=np.zeros((m,1),dtype='uint8')#label 向量,0表示紅色,1表示藍色
a=4

for j in range(2):
    ix=range(N*j,N*(j+1))
    t=np.linspace(j*3.12,(j+1)*3.12,N)+np.random.rand(N)*0.2
    r=a*np.sin(4*t)+np.random.rand(N)*0.2
    x[ix]=np.c_[r*np.sin(t),r*np.cos(t)]
    y[ix]=j

plt.scatter(x[:,0],x[:,-1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
plt.show()

 

 


#首先使用logistic迴歸解決
x=torch.from_numpy(x).float()
y=torch.from_numpy(y).float()

w=nn.Parameter(torch.randn(2,1))
b=nn.Parameter(torch.zeros(1))

optimizer=torch.optim.SGD([w,b],1e-1)

def logistic_regression(x):
    return torch.mm(x,w)+b

criterion=nn.BCEWithLogitsLoss()

for e in range(100):
    out=logistic_regression(Variable(x))
    loss=criterion(out,Variable(y))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if(e+1)%20==0:
        print('epoch:{}.loss:{}'.format(e+1,loss.item()))

def plot_logistic(x):
    x=Variable(torch.from_numpy(x).float())
    out=F.sigmoid(logistic_regression(x))
    out=(out>0.5)*1
    return out.data.numpy()

plot_decision_boundary(lambda x:plot_logistic(x),x.numpy(),y.numpy())
plt.title('logistic regression')

 

 

logistic 迴歸並不能很好的區分開這個複雜的數據集。使用神經網絡
 代碼:

import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

def plot_decision_boundary(model,x,y):
    #Set min and max values and give it some padding
    x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
    y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
    h=0.01
    #Generate a grid of points with distance h between them
    xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
    #Predict the function value for the whole grid
    Z=model(np.c_[xx.ravel(),yy.ravel()])
    Z=Z.reshape(xx.shape)
    #plot the contour and training examples
    plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(x[:,0],x[:,1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
    plt.show()

np.random.seed(1)
m=400#樣本數量
N=int(m/2)#每一類點的個數
D=2#維度
x=np.zeros((m,D))
y=np.zeros((m,1),dtype='uint8')#label 向量,0表示紅色,1表示藍色
a=4

for j in range(2):
    ix=range(N*j,N*(j+1))
    t=np.linspace(j*3.12,(j+1)*3.12,N)+np.random.rand(N)*0.2
    r=a*np.sin(4*t)+np.random.rand(N)*0.2
    x[ix]=np.c_[r*np.sin(t),r*np.cos(t)]
    y[ix]=j

plt.scatter(x[:,0],x[:,-1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
plt.show()

#首先使用logistic迴歸解決
x=torch.from_numpy(x).float()
y=torch.from_numpy(y).float()

w=nn.Parameter(torch.randn(2,1))
b=nn.Parameter(torch.zeros(1))

optimizer=torch.optim.SGD([w,b],1e-1)

def logistic_regression(x):
    return torch.mm(x,w)+b

criterion=nn.BCEWithLogitsLoss()

for e in range(100):
    out=logistic_regression(Variable(x))
    loss=criterion(out,Variable(y))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if(e+1)%20==0:
        print('epoch:{}.loss:{}'.format(e+1,loss.item()))

def plot_logistic(x):
    x=Variable(torch.from_numpy(x).float())
    out=F.sigmoid(logistic_regression(x))
    out=(out>0.5)*1
    return out.data.numpy()

plot_decision_boundary(lambda x:plot_logistic(x),x.numpy(),y.numpy())
plt.title('logistic regression')

#定義兩層神經網絡的參數
w1=nn.Parameter(torch.randn(2,4)*0.01)#隱藏層神經元個數2
b1=nn.Parameter(torch.zeros(4))

w2=nn.Parameter(torch.randn(4,1)*0.01)
b2=nn.Parameter(torch.zeros(1))

#定義模型
def two_network(x):
    x1=torch.mm(x,w1)+b1
    x1=F.tanh(x1)#使用的PyTorch自帶的tanh激活函數
    x2=torch.mm(x1,w2)+b2
    return x2

optimizer=torch.optim.SGD([w1,w2,b1,b2],1.)
criterion=nn.BCEWithLogitsLoss()
#訓練10000次
for e in range(10000):
    out=two_network(Variable(x))
    loss=criterion(out,Variable(y))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if(e+1)%10000==0:
        print('epoch:{},loss:{}'.format(e+1,loss.item()))

def plot_network(x):
    x=Variable(torch.from_numpy(x).float())
    x1=torch.mm(x,w1)+b1
    x1=F.tanh(x1)
    x2=torch.mm(x1,w2)+b2
    out=F.sigmoid(x2)
    out=(out>0.5)*1
    return out.data.numpy()

plot_decision_boundary(lambda x:plot_network(x),x.numpy(),y.numpy())
plt.title('2 layer network')

 可以看到神經網絡能夠非常好地分類這個複雜的數據,和前面的logistic迴歸相比,神經網絡因爲有了激活函數的存在,成了一個非線性分類器,所以神經網絡分類的邊界更加複雜。

 

Sequential和Module

使用Sequential和Module定義上面的神經網絡:

#Sequential
seq_net=nn.Sequential(
    nn.Linear(2,4),#pyTorch中的線性層,wx+b
    nn.Tanh(),
    nn.Linear(4,1)
)
#序列模塊可以通過索引訪問每一層
seq_net[0]#第一層
print(seq_net[0])
#打印出第一層的權重
w0=seq_net[0].weight
print(w0)

 

 

 PyTorch自帶的模塊比自己寫的更加穩定。

import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

def plot_decision_boundary(model,x,y):
    #Set min and max values and give it some padding
    x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
    y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
    h=0.01
    #Generate a grid of points with distance h between them
    xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
    #Predict the function value for the whole grid
    Z=model(np.c_[xx.ravel(),yy.ravel()])
    Z=Z.reshape(xx.shape)
    #plot the contour and training examples
    plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(x[:,0],x[:,1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
    plt.show()

np.random.seed(1)
m=400#樣本數量
N=int(m/2)#每一類點的個數
D=2#維度
x=np.zeros((m,D))
y=np.zeros((m,1),dtype='uint8')#label 向量,0表示紅色,1表示藍色
a=4

for j in range(2):
    ix=range(N*j,N*(j+1))
    t=np.linspace(j*3.12,(j+1)*3.12,N)+np.random.rand(N)*0.2
    r=a*np.sin(4*t)+np.random.rand(N)*0.2
    x[ix]=np.c_[r*np.sin(t),r*np.cos(t)]
    y[ix]=j

plt.scatter(x[:,0],x[:,-1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
plt.show()

#首先使用logistic迴歸解決
x=torch.from_numpy(x).float()
y=torch.from_numpy(y).float()

w=nn.Parameter(torch.randn(2,1))
b=nn.Parameter(torch.zeros(1))

optimizer=torch.optim.SGD([w,b],1e-1)

def logistic_regression(x):
    return torch.mm(x,w)+b

criterion=nn.BCEWithLogitsLoss()


def plot_logistic(x):
    x=Variable(torch.from_numpy(x).float())
    out=F.sigmoid(logistic_regression(x))
    out=(out>0.5)*1
    return out.data.numpy()

plot_decision_boundary(lambda x:plot_logistic(x),x.numpy(),y.numpy())
plt.title('logistic regression')



#Sequential
seq_net=nn.Sequential(
    nn.Linear(2,4),#pyTorch中的線性層,wx+b
    nn.Tanh(),
    nn.Linear(4,1)
)

#通過parameters可以取得模型的參數
param=seq_net.parameters()

#定義優化器
optim=torch.optim.SGD(param,1.)
#訓練10000次
for e in range(10000):
    out=seq_net(Variable(x))
    loss=criterion(out,Variable(y))
    optim.zero_grad()
    loss.backward()
    optim.step()
    if(e+1)%1000==0:
        print('epoch:{},loss:{}'.format(e+1,loss.item()))

def plot_seq(x):
    out=F.sigmoid(seq_net(Variable(torch.from_numpy(x).float()))).data.numpy()
    out=(out>0.5)*1
    return out

plot_decision_boundary(lambda x:plot_seq(x),x.numpy(),y.numpy())
plt.title('sequential')

 

 

 

 保存模型:

#將參數和模型保存在一起(第一個參數是要保存的模型,第二個參數是保存的路徑)

torch.save(seq_net,'save_seq_net.pth')

#讀取保存的模型

seq_net1=torch.load('save_seq_net.pth') 

 

# 只保存模型參數,而不保存模型

torch.save(seq_net.state_dict(),'save_net_params.'pth)

#重新讀入參數

seq_net2=nn.Sequential(

    nn.Linear(2,4),

    nn.Tanh(),

    nn.Linear(4,1)

seq_net2.load_state_dict(torch.load('save_seq_net_params.pth'))

 

Module模板:

class 網絡名字(nn.Module):
    def __init__(self,一些定義的參數):
        super(網路名,self).__init__()
        self.layer1=nn.Linear(num_input,num_hidden)
        self.layer2=nnn.Sequential(……)
        ……
        定義需要用的網絡層
        
    def forward(self,x):#定義前向傳播
        x1=self.layer1(x)
        x2=self.layer2(x)
        x=x1+x2
        ……
        return x
    

 

按照模板實現上面的神經網絡:

import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

def plot_decision_boundary(model,x,y):
    #Set min and max values and give it some padding
    x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
    y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
    h=0.01
    #Generate a grid of points with distance h between them
    xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
    #Predict the function value for the whole grid
    Z=model(np.c_[xx.ravel(),yy.ravel()])
    Z=Z.reshape(xx.shape)
    #plot the contour and training examples
    plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(x[:,0],x[:,1],c=y.reshape(-1),s=40,cmap=plt.cm.Spectral)
    plt.show()

np.random.seed(1)
m=400#樣本數量
N=int(m/2)#每一類點的個數
D=2#維度
x=np.zeros((m,D))
y=np.zeros((m,1),dtype='uint8')#label 向量,0表示紅色,1表示藍色
a=4


for j in range(2):
    ix=range(N*j,N*(j+1))
    t=np.linspace(j*3.12,(j+1)*3.12,N)+np.random.rand(N)*0.2
    r=a*np.sin(4*t)+np.random.rand(N)*0.2
    x[ix]=np.c_[r*np.sin(t),r*np.cos(t)]
    y[ix]=j

x=torch.from_numpy(x).float()
y=torch.from_numpy(y).float()

class module_net(nn.Module):
    def __init__(self,num_input,num_hidden,num_output):
        super(module_net,self).__init__()
        self.layer1=nn.Linear(num_input,num_hidden)
        self.layer2=nn.Tanh()
        self.layer3=nn.Linear(num_hidden,num_output)

    def forward(self,x):#定義前向傳播
        x=self.layer1(x)
        x=self.layer2(x)
        x=self.layer3(x)
        return x

mo_net=module_net(2,4,1)

#訪問模型中的某次可以直接通過名字
#第一層
l1=mo_net.layer1
print(l1)
#打印出第一層的權重
print(l1.weight)

criterion=nn.BCEWithLogitsLoss()

#定義優化器
optim=torch.optim.SGD(mo_net.parameters(),1)

#訓練10000次
for e in range(10000):
    out=mo_net(Variable(x))
    loss=criterion(out,Variable(y))
    optim.zero_grad()
    loss.backward()
    optim.step()
    if(e+1)%1000==0:
        print('epoch:{},loss:{}'.format(e+1,loss.item()))


#保存模型
torch.save(mo_net.state_dict(),'module_net.pth')




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章