線性迴歸中,公式是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')