0、引言
在感知機一節中講到感知機是一種線性模型,存在的缺點是很難解決非線性問題,比如異或(XOR)就是一種典型的線性不可分的問題,因此有了神經網絡,通過在感知機的結構中添加隱藏層來擬合非線性問題。
1、原理
後續補充。。。。。。。。。。。。。。。
2、代碼實現
神經網絡的構建過程:
- 定義神經網絡結構(指定傳輸層、隱藏層、輸出層大小);
- 初始化模型參數;
- 循環操作:執行前向傳播/計算損失/執行反後向傳播/權值矩陣
常見參數優化算法(如:梯度下降法、隨機梯度下降、牛頓法、擬牛頓法、Adam)數學原理可以看下以下的博客:
https://blog.csdn.net/Zjhao666/article/details/88402518
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.gam.tests.test_gam import sigmoid
#生成數據集
def create_dataset():
np.random.seed(1) #隨機數種子,可以在某個種子堆中調用相同的額隨機數值
#數據量
m = 400
#每個標籤的實例數
N = int(m/2)
#數據維度
D = 2
X = np.zeros((m, D)) #400*2
Y = np.zeros((m,1), dtype = 'uint8')
a = 4
for j in range(2):
ix = range(N*j, N*(j+1))
#linspace(a,b,n) 在[2,3]上生成等間隔的N個數
t = np.linspace(j * 3.12, (j + 1) * 3.12, N) + np.random.randn(N) * 0.2 # theta
r = a * np.sin(4 * t) + np.random.randn(N) * 0.2 # radius
#np.r_是按列連接兩個矩陣,就是把兩矩陣上下相加,要求列數相等。
#np.c_是按行連接兩個矩陣,就是把兩矩陣左右相加,要求行數相等。
X[ix] = np.c_[r * np.sin(t), r * np.cos(t)]
Y[ix] = j
X = X.T
Y = Y.T
return X, Y
#定義一個單隱藏層的神經網絡
def layer_sizes(X, Y):
n_x = X.shape[0] #輸入層大小
n_h = 4 #隱藏層大小
n_y = Y.shape[0] #輸出層大小
return (n_x, n_h, n_y)
#初始化模型參數
def initialize_parameters(n_x, n_h, n_y):
W1 = np.random.randn(n_h, n_x) * 0.01
b1 = np.zeros((n_h, 1))
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros((n_y, 1))
#錯誤檢查,判斷
assert (W1.shape == (n_h, n_x))
assert (b1.shape == (n_h, 1))
assert (W2.shape == (n_y, n_h))
assert (b2.shape == (n_y, 1))
#封裝成字典
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
#前向傳播
def forward_propagation(X, parameters):
# 獲取各參數初始值
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
# 執行前向計算
Z1 = np.dot(W1, X) + b1 #dot矩陣點乘
A1 = np.tanh(Z1) #隱藏層使用tanh激活
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2) #隱藏層使用sigmoid激活,作爲輸出y
assert(A2.shape == (1, X.shape[1]))
#保存前向傳播的結果
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
return A2, cache
#計算當前訓練損失(交叉熵損失)
def compute_cost(A2, Y):
# 訓練樣本量
m = Y.shape[1]
# 計算交叉熵損失
logprobs = np.multiply(np.log(A2),Y) + np.multiply(np.log(1-A2), 1-Y)
cost = -1/m * np.sum(logprobs)
# 維度壓縮
cost = np.squeeze(cost)
assert(isinstance(cost, float))
return cost
#反向傳播(梯度計算)
def backward_propagation(parameters, cache, X, Y):
m = X.shape[1]
# 獲取W1和W2
W1 = parameters['W1']
W2 = parameters['W2']
# 獲取A1和A2
A1 = cache['A1']
A2 = cache['A2']
# 執行反向傳播
dZ2 = A2-Y
dW2 = 1/m * np.dot(dZ2, A1.T)
db2 = 1/m * np.sum(dZ2, axis=1, keepdims=True)
dZ1 = np.dot(W2.T, dZ2)*(1-np.power(A1, 2))
dW1 = 1/m * np.dot(dZ1, X.T)
db1 = 1/m * np.sum(dZ1, axis=1, keepdims=True)
#保存參數值
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
#更新權值,這裏學習率a初始化爲1.2
def update_parameters(parameters, grads, learning_rate=1.2):
# 獲取參數
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
# 獲取梯度
dW1 = grads['dW1']
db1 = grads['db1']
dW2 = grads['dW2']
db2 = grads['db2']
# 參數更新
W1 -= dW1 * learning_rate
b1 -= db1 * learning_rate
W2 -= dW2 * learning_rate
b2 -= db2 * learning_rate
#保存新參數
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
#組合成model,迭代次數爲10000
def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):
np.random.seed(3)
n_x = layer_sizes(X, Y)[0]
n_y = layer_sizes(X, Y)[2]
# 初始化模型參數
parameters = initialize_parameters(n_x, n_h, n_y)
# 梯度下降和參數更新循環
for i in range(0, num_iterations):
# 前向傳播計算
A2, cache = forward_propagation(X, parameters)
# 計算當前損失
cost = compute_cost(A2, Y)
# 反向傳播
grads = backward_propagation(parameters, cache, X, Y)
# 參數更新
parameters = update_parameters(parameters, grads, learning_rate=1.2)
# 打印損失
if print_cost and i % 1000 == 0:
print("Cost after iteration %i: %f" % (i, cost))
return parameters
# 預測函數
def predict(parameters, X):
A2, cache = forward_propagation(X, parameters)
predictions = (A2>0.5)
return predictions
#繪製決策邊界
def plot_decision_boundary(model, X, y):
#邊界最大最小值
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
#網格圖大小
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = model(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.ylabel('x2')
plt.xlabel('x1')
plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)
#繪圖
def plot_Decision_Answer(X, Y):
plt.figure(figsize=(16, 32))
#設置不同隱藏層大小
hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20]
for i, n_h in enumerate(hidden_layer_sizes):
plt.subplot(5, 2, i+1)
plt.title('Hidden Layer of size %d' % n_h)
#加載訓練模型
parameters = nn_model(X, Y, n_h = 4,
num_iterations = 10000,
print_cost=False)
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y[0])
#預測
predictions = predict(parameters, X)
#預測精度計算
accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
print ("Accuracy for {} hidden units: {}%".format(n_h, accuracy))
plt.show()
def main():
X, Y = create_dataset()
# 數據可視化
plt.scatter(X[0, :], X[1, :], c=Y[0], s=40, cmap=plt.cm.Spectral)
# plt.show()
#神經網絡
plot_Decision_Answer(X, Y)
if __name__ == '__main__':
main()
參考資料:
[1]https://blog.csdn.net/Zjhao666/article/details/88402518
[2]https://github.com/luwill/machine-learning-code-writing