使用浅层神经网络进行平面数据分类

本文是基于吴恩达老师的《深度学习》第一课第三周课后题所做,目的是使用浅层神经网络对给定的平面数据进行分类。该算法的实现共分:模型搭建,模型测试,参数调整,算法对比和更换数据五个步骤,详述如下:

一、模型搭建

在该题目中,吴恩达老师事先已贴心的给出了平面数据集,数据文件链接:https://pan.baidu.com/s/1NH_UQfNk4W-dSuYtGwWQHQ 密码:cmer,我们可通过调用planar_utils.py文件中的load_planar_dataset函数生成平面数据集。

X,Y = load_planar_dataset()

plt.scatter(X[0,:],X[1,:],c=np.ravel(Y),s=40,cmap=plt.cm.Spectral)
plt.show()

平面数据集如下图所示(随机生成红、蓝两色数据点,由于本文着重于学习算法,数据集的生成不过多叙述):


按照浅层神经网络构建的思路,我们可将算法划分成七个步骤来实现:

1. 确定各层神经元数量。

各层神经元数量决定了模型的深度,浅层神经网络采用三层结构:输入层、隐藏层、输出层。

def layer_size(X,Y):
    n_x = X.shape[0]
    n_h = 4
    n_y = Y.shape[0]

    return (n_x, n_h, n_y)

为了方便返回值的调用,此处使用元组返回各层神经元数量。

2.初始化权重参数W1,W2和偏置b1,b2。

为保证随机生成的初始值在各次迭代中能够保持一致性,需使用np.random.seed()函数进行约束。在初始权重参数时不可以采用零矩阵,这一点吴恩达老师在课程中重点讲解过,不再赘述。

扫描二维码关注公众号,回复: 1941351 查看本文章
def initialize_parameters(n_x, n_h, n_y):
    np.random.seed(2)

    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

3.前向传播。

计算出A1,Z1和A2,Z2,隐藏层的激励函数采用tanh函数,输出层的激励函数采用sigmoid函数。神经网络前向传播过程中有4个重要公式,需要牢记:


def forward_propagation(X,parameters):
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]

    Z1 = np.dot(W1,X) + b1
    A1 = np.tanh(Z1)
    Z2 = np.dot(W2,A1) + b2
    A2 = sigmoid(Z2)

    assert(A2.shape == (1,X.shape[1]))

    cache = {"Z1" : Z1,
             "A1" : A1,
             "Z2" : Z2,
             "A2" : A2
             }
    return A2, cache

4.计算代价函数Cost/Loss。

代价函数公式为:

def compute_cost(A2,Y,parameters):
    m = Y.shape[1]

    logprobs = np.multiply(np.log(A2),Y) + np.multiply(np.log(1-A2),1-Y)
    cost = - np.sum(logprobs) / m
    cost = np.squeeze(cost)
    
    assert(isinstance(cost, float))

    return cost

5.后向传播。

后向传播通常采用梯度下降法,是该算法中的重中之重,此步骤有六个公式需要牢记(摘引吴恩达老师ppt):


def back_propagation(parameters,cache,X,Y):
    m = X.shape[1]
    
    W1 = parameters["W1"]
    W2 = parameters["W2"]

    A1 = cache["A1"]
    A2 = cache["A2"]

    dZ2 = A2 - Y
    dW2 = np.dot(dZ2,A1.T) / m
    db2 = np.sum(dZ2,axis=1,keepdims=True) / m

    dZ1 = np.dot(W2.T,dZ2) * (1 - np.power(A1,2))
    dW1 = np.dot(dZ1,X.T) / m
    db1 = np.sum(dZ1,axis=1,keepdims=True) / m

    grads = {"dW1" : dW1,
             "db1" : db1,
             "dW2" : dW2,
             "db2" : db2
             }

    return grads

6.参数更新。

使用梯度下降法计算出的偏导数更新参数,学习率α的选择直接影响梯度下降的速度。

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 -= learning_rate * dW1
    b1 -= learning_rate * db1
    W2 -= learning_rate * dW2
    b2 -= learning_rate * db2

    parameters = {"W1" : W1,
                  "b1" : b1,
                  "W2" : W2,
                  "b2" : b2
                  }
    return parameters

7.构建神经网络模型。

将上述函数进行整合,并通过反复迭代步骤3-6,最终生成适用于神经网络模型的参数。

def nn_model(X,Y,n_h,num_iterations = 10000,print_cost = False):
    np.random.seed(3)

    n_x = layer_size(X,Y)[0]
    n_y = layer_size(X,Y)[2]

    
    parameters = initialize_parameters(n_x, n_h, n_y)

    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]

    for i in range(0,num_iterations):
        A2, cache = forward_propagation(X,parameters)
        cost = compute_cost(A2,Y,parameters)
        grads = back_propagation(parameters,cache,X,Y)
        parameters = update_parameters(parameters,grads,learning_rate = 1.2)
        if print_cost and i % 100 == 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

我们可以使用吴恩达老师给出的testCases_v2.py文件中的predict_test_case()函数进行验证测试。

def predict_test_case():
    np.random.seed(1)
    X_assess = np.random.randn(2, 3)
    parameters = {'W1': np.array([[-0.00615039,  0.0169021 ],
        [-0.02311792,  0.03137121],
        [-0.0169217 , -0.01752545],
        [ 0.00935436, -0.05018221]]),
     'W2': np.array([[-0.0104319 , -0.04019007,  0.01607211,  0.04440255]]),
     'b1': np.array([[ -8.97523455e-07],
        [  8.15562092e-06],
        [  6.04810633e-07],
        [ -2.54560700e-06]]),
     'b2': np.array([[  9.14954378e-05]])}
    return parameters, X_assess
parameters, X_assess = predict_test_case()
predictions = predict(parameters, X_assess)
print("predictions mean = " + str(np.mean(predictions)))
预测值为:
predictions mean = 0.6666666666666666

三、算法对比

使用搭建好的浅层神经网络模型对文首给出的平面数据集进行分类:

X,Y = load_planar_dataset()
n_h=4
parameters = nn_model(X,Y,n_h,num_iterations = 5000,print_cost = True)
plot_decision_boundary(lambda x:predict(parameters,x.T), X, Y)
plt.title("decision_boundary for hidden layer size" + str(4))
plt.show()
    
predictions = predict(parameters,X)
accuray = 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,accuray) )

结果如下:



虽然是浅层神经网络但预测精度已经可以达到90.75%,相比逻辑回归算法精度大大提升。下面我们用逻辑回归算法对平面数据集进行分类处理。

clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T,Y.T)

plot_decision_boundary(lambda x : clf.predict(x),X,Y)
plt.title("Logistic Regression")

LR_predictions = clf.predict(X.T)
print('Accuray of lr: %d'%float((np.dot(Y,LR_predictions)+
                                 np.dot(1-Y,1-LR_predictions))/float(Y.size)*100)+
      '%'+"(percentage of correctly labelled datapoints)")

plt.show()

使用逻辑回归分类的精度只有 47%。

四、参数调整

在建立模型时,隐藏层神经元个数我们选择为4个,这个参数的选择有很大的主观性,我们可在模型建立好之后通过试凑法来进行优化。

plt.figure(figsize=(16,32))

hidden_layer_sizes = [1,2,3,4,5,20,50]
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,num_iterations = 5000)
    plot_decision_boundary(lambda x:predict(parameters,x.T), X, Y)
    #plt.title("decision_boundary for hidden layer size" + str(4))
    #plt.show()
    
    predictions = predict(parameters,X)
    accuray = 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,accuray) )



plt.show()

结果如下:


测试精度分别为:

Accuracy for 1 hidden units:61.5%
Accuracy for 2 hidden units:70.5%
Accuracy for 3 hidden units:66.25%
Accuracy for 4 hidden units:90.75%
Accuracy for 5 hidden units:90.5%
Accuracy for 20 hidden units:92.0%
Accuracy for 50 hidden units:90.75%
可见对于本文中采用数据,隐藏层神经元的个数设置在20左右,测试精度最优。

五、更换数据

最后,我们可以通过改变数据集来验证一下模型的泛化性,防止模型出现过拟合。

新的数据集如下图所示:

noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure = load_extra_datasets()
datasets = {"noisy_circles" : noisy_circles,
            "noisy_moons" : noisy_moons,
            "blobs" : blobs,
            "gaussian_quantiles" : gaussian_quantiles
            }
dataset = "noisy_circles"
X,Y = datasets[dataset]
X,Y = X.T,Y.reshape(1,Y.shape[0])

if dataset == "blobs":
    Y = Y % 2

plt.scatter(X[0,:],X[1,:],c=np.ravel(Y),s=40,cmap=plt.cm.Spectral)
plt.show()


预测结果为:



预测精度为85.5%小于原始数据集的90.75%,说明本模型的泛化能力还是比较弱,我们可以通过增加样本数量、调整参数及优化模型等方法进一步改善。

猜你喜欢

转载自blog.csdn.net/u013093426/article/details/80873610
今日推荐