Phishing website analyse(二)
自定义深度神经网络函数分析
- 数据集与Phishing website analyse(一)——决策树分析里的一样,数据集不提供,自行百度
代码实现
import numpy as np
import matplotlib.pyplot as plt
# # 加载我们自定义的工具函数
# from testCases import *
# from dnn_utils import *
# 设置一些画图相关的参数
%matplotlib inline
plt.rcParams['figure.figsize'] = (5.0, 4.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
np.random.seed(1)
# 该函数用于初始化所有层的参数w和b
def initialize_parameters_deep(layer_dims):
"""
参数:
layer_dims -- 这个list列表里面,包含了每层的神经元个数。
例如,layer_dims=[5,4,3],表示第一层有5个神经元,第二层有4个,最后一层有3个神经元
返回值:
parameters -- 这个字典里面包含了每层对应的已经初始化了的W和b。
例如,parameters['W1']装载了第一层的w,parameters['b1']装载了第一层的b
"""
np.random.seed(1)
parameters = {}
L = len(layer_dims) # 获取神经网络总共有几层
# 遍历每一层,为每一层的W和b进行初始化
for l in range(1, L):
# 构建并随机初始化该层的W。Wl的维度是(n[l] , n[l-1])
parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(layer_dims[l-1])
# 构建并初始化b
parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))
# 核对一下W和b的维度是预期的维度
assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))
assert(parameters['b' + str(l)].shape == (layer_dims[l], 1))
#就是利用上面的循环,我们就可以为任意层数的神经网络进行参数初始化,只要我们提供每一层的神经元个数就可以了。
return parameters
def linear_forward(A, W, b):
Z = np.dot(W, A) + b
assert(Z.shape == (W.shape[0], A.shape[1]))
cache = (A, W, b) # 将这些变量保存起来,因为后面进行反向传播时会用到它们
return Z, cache
def linear_activation_forward(A_prev, W, b, activation):
"""
Arguments:
A_prev -- 上一层得到的A,输入到本层来计算Z和本层的A。第一层时A_prev就是特征输入X
W -- 本层相关的W
b -- 本层相关的b
activation -- 两个字符串,"sigmoid"或"relu",指示该层应该使用哪种激活函数
"""
Z, linear_cache = linear_forward(A_prev, W, b)
if activation == "sigmoid": # 如果该层使用sigmoid
A = sigmoid(Z)
elif activation == "relu":
A = relu(Z)
assert (A.shape == (W.shape[0], A_prev.shape[1]))
cache = (linear_cache, Z) # 缓存一些变量,后面的反向传播会用到它们
return A, cache
# 这个函数构建了一个完整的前向传播过程。这个前向传播一共有L层,前面的L-1层用的激活函数是relu,最后一层使用sigmoid。
def L_model_forward(X, parameters):
"""
参数:
X -- 输入的特征数据
parameters -- 这个list列表里面包含了每一层的参数w和b
"""
caches = []
A = X
# 获取参数列表的长度,这个长度的一半就是神经网络的层数。
# 为什么是一半呢?因为列表是这样的[w1,b1,w2,b2...wl,bl],里面的w1和b1代表了一层
L = len(parameters) // 2
# 循环L-1次,即进行L-1步前向传播,每一步使用的激活函数都是relu
for l in range(1, L):
A_prev = A
A, cache = linear_activation_forward(A_prev,
parameters['W' + str(l)],
parameters['b' + str(l)],
activation='relu')
caches.append(cache)# 把一些变量数据保存起来,以便后面的反向传播使用
# 进行最后一层的前向传播,这一层的激活函数是sigmoid。得出的AL就是y'预测值
AL, cache = linear_activation_forward(A,
parameters['W' + str(L)],
parameters['b' + str(L)],
activation='sigmoid')
caches.append(cache)
return AL, caches
# 上面已经完成了前向传播了。下面这个函数用于计算成本(单个样本时是损失,多个样本时是成本)。
# 通过每次训练的成本我们就可以知道当前神经网络学习的程度好坏。
def compute_cost(AL, Y):
m = Y.shape[1]
cost = (-1 / m) * np.sum(np.multiply(Y, np.log(AL)) + np.multiply(1 - Y, np.log(1 - AL)))
cost = np.squeeze(cost)# 确保cost是一个数值而不是一个数组的形式
assert(cost.shape == ())
return cost
def linear_backward(dZ, cache):
"""
参数:
dZ -- 后面一层的dZ
cache -- 前向传播时我们保存下来的关于本层的一些变量
"""
A_prev, W, b = cache
m = A_prev.shape[1]
dW = np.dot(dZ, cache[0].T) / m
db = np.sum(dZ, axis=1, keepdims=True) / m
dA_prev = np.dot(cache[1].T, dZ)
assert (dA_prev.shape == A_prev.shape)
assert (dW.shape == W.shape)
assert (db.shape == b.shape)
return dA_prev, dW, db
def linear_activation_backward(dA, cache, activation):
"""
参数:
dA -- 本层的dA
cache -- 前向传播时保存的本层的相关变量
activation -- 指示该层使用的是什么激活函数: "sigmoid" 或 "relu"
"""
linear_cache, activation_cache = cache
if activation == "relu":
dZ = relu_backward(dA, activation_cache)
elif activation == "sigmoid":
dZ = sigmoid_backward(dA, activation_cache)
# 这里我们又顺带根据本层的dZ算出本层的dW和db以及前一层的dA
dA_prev, dW, db = linear_backward(dZ, linear_cache)
return dA_prev, dW, db
# 下面这个函数构建出整个反向传播。
def L_model_backward(AL, Y, caches):
"""
参数:
AL -- 最后一层的A,也就是y',预测出的标签
Y -- 真实标签
caches -- 前向传播时保存的每一层的相关变量,用于辅助计算反向传播
"""
grads = {}
L = len(caches) # 获取神经网络层数。caches列表的长度就等于神经网络的层数
Y = Y.reshape(AL.shape) # 让真实标签的维度和预测标签的维度一致
# 计算出最后一层的dA,前面文章我们以及解释过,最后一层的dA与前面各层的dA的计算公式不同,
# 因为最后一个A是直接作为参数传递到成本函数的,所以不需要链式法则而直接就可以求dA(A相当于成本函数的偏导数)
dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
# 计算最后一层的dW和db,因为最后一层使用的激活函数是sigmoid
current_cache = caches[-1]
grads["dA" + str(L-1)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(
dAL,
current_cache,
activation = "sigmoid")
# 计算前面L-1层到第一层的每层的梯度,这些层都使用relu激活函数
for c in reversed(range(1,L)): # reversed(range(1,L))的结果是L-1,L-2...1。是不包括L的。第0层是输入层,不必计算。
# 这里的c表示当前层
grads["dA" + str(c-1)], grads["dW" + str(c)], grads["db" + str(c)] = linear_activation_backward(
grads["dA" + str(c)],
caches[c-1],
# 这里我们也是需要当前层的caches,但是为什么是c-1呢?因为grads是字典,我们从1开始计数,而caches是列表,
# 是从0开始计数。所以c-1就代表了c层的caches。数组的索引很容易引起莫名其妙的问题,大家编程时一定要留意。
activation = "relu")
return grads
def update_parameters(parameters, grads, learning_rate):
"""
Arguments:
parameters -- 每一层的参数w和b
grads -- 每一层的梯度
learning_rate -- 是学习率,学习步进
"""
L = len(parameters) // 2 # 获取层数。//除法可以得到整数
for l in range(1,L+1):
parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * grads["dW" + str(l)]
parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * grads["db" + str(l)]
return parameters
import numpy as np
import pandas as pd
import tensorflow as tf
origin_data = pd.read_csv('phishing.csv')
data = origin_data.drop('id',axis=1)
train = data[0:int(data.shape[0]*0.8)]
test = data[int(data.shape[0]*0.8):]
def load_phishing_dataset():
train_set_x_orig = np.array(train[train.columns[0:-1]]) # your train set features
train_set_y_orig = np.array(train.Result) # your train set labels
test_set_x_orig = np.array(test[test.columns[0:-1]]) # your test set features
test_set_y_orig = np.array(test.Result) # your test set labels
classes = np.array([-1,1]) # the list of classes
train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
train_x_orig, train_y, test_x_orig, test_y, classes = load_phishing_dataset()
# 利用上面的工具函数构建一个深度神经网络训练模型
def dnn_model(X, Y, layers_dims, learning_rate=0.0001, num_iterations=3000, print_cost=False):
"""
参数:
X -- 数据集
Y -- 数据集标签
layers_dims -- 指示该深度神经网络用多少层,每层有多少个神经元
learning_rate -- 学习率
num_iterations -- 指示需要训练多少次
print_cost -- 指示是否需要在将训练过程中的成本信息打印出来,好知道训练的进度好坏。
返回值:
parameters -- 返回训练好的参数。以后就可以用这些参数来识别新的陌生的图片
"""
np.random.seed(1)
costs = []
# 初始化每层的参数w和b
parameters = initialize_parameters_deep(layers_dims)
# 按照指示的次数来训练深度神经网络
for i in range(0, num_iterations):
# 进行前向传播
AL, caches = L_model_forward(X, parameters)
# 计算成本
cost = compute_cost(AL, Y)
# 进行反向传播
grads = L_model_backward(AL, Y, caches)
# 更新参数,好用这些参数进行下一轮的前向传播
parameters = update_parameters(parameters, grads, learning_rate)
# 打印出成本
if i % 100 == 0:
if print_cost and i > 0:
print ("训练%i次后成本是: %f" % (i, cost))
costs.append(cost)
# 画出成本曲线图
plt.plot(np.squeeze(costs))
plt.ylabel('cost')
plt.xlabel('iterations (per tens)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
return parameters
def sigmoid(Z):
"""
Implements the sigmoid activation in numpy
Arguments:
Z -- numpy array of any shape
Returns:
A -- output of sigmoid(z), same shape as Z
cache -- returns Z as well, useful during backpropagation
"""
A = 1/(1+np.exp(-Z))
return A
def relu(Z):
"""
Implement the RELU function.
Arguments:
Z -- Output of the linear layer, of any shape
Returns:
A -- Post-activation parameter, of the same shape as Z
cache -- a python dictionary containing "A" ; stored for computing the backward pass efficiently
"""
A = np.maximum(0,Z)
assert(A.shape == Z.shape)
return A
def relu_backward(dA, cache):
"""
Implement the backward propagation for a single RELU unit.
Arguments:
dA -- post-activation gradient, of any shape
cache -- 'Z' where we store for computing backward propagation efficiently
Returns:
dZ -- Gradient of the cost with respect to Z
"""
Z = cache
dZ = np.array(dA, copy=True) # just converting dz to a correct object.
# When z <= 0, you should set dz to 0 as well.
dZ[Z <= 0] = 0
assert (dZ.shape == Z.shape)
return dZ
def sigmoid_backward(dA, cache):
"""
Implement the backward propagation for a single SIGMOID unit.
Arguments:
dA -- post-activation gradient, of any shape
cache -- 'Z' where we store for computing backward propagation efficiently
Returns:
dZ -- Gradient of the cost with respect to Z
"""
Z = cache
s = 1/(1+np.exp(-Z))
dZ = dA * s * (1-s)
assert (dZ.shape == Z.shape)
return dZ
# 设置好深度神经网络的层次信息——下面代表了一个4层的神经网络(12288是输入层),
# 第一层有20个神经元,第二层有7个神经元。。。
# 你也可以构建任意层任意神经元数量的神经网络,只需要更改下面这个数组就可以了
layers_dims = [30, 12 ,8, 1]
# 根据上面的层次信息来构建一个深度神经网络,并且用之前加载的数据集来训练这个神经网络,得出训练后的参数
parameters = dnn_model(train_x_orig.T, train_y, layers_dims, num_iterations=10000, print_cost=True)
def predict(X,parameters):
m = X.shape[1]
n = len(parameters) // 2 # number of layers in the neural network
p = np.zeros((1,m))
# 进行一次前向传播,得到预测结果
probas, caches = L_model_forward(X, parameters)
# 将预测结果转化成0和1的形式,即大于0.5\的就是1,否则就是0
for i in range(0, probas.shape[1]):
if probas[0,i] > 0.346:
p[0,i] = 1
else:
p[0,i] = -1
# print('p%i:%f'%(i,probas[0,i] ))
return p
# 对训练数据集进行预测
pred_train = predict(train_x_orig.T,parameters)
print("预测准确率是: " + str(np.sum((pred_train == train_y))/train_x_orig.T.shape[1]))
# 对训练数据集进行预测
pred_train = predict(test_x_orig.T,parameters)
print("预测准确率是: " + str(np.sum((pred_train == test_y))/test_x_orig.T.shape[1]))
my_file2 = test[5:6].drop('Result',axis = 1)
pred_train = predict(my_file2.T,parameters)
pred_train
以上代码都有详细注释,相信有需要的人会仔细看的,就不做分块的展示了,工具使用jupyter notebook,比起上一篇的决策树的方法,深度神经网络就显得强大了,不用去分析太多的数据结构找频繁项集,只需要搞懂深度神经网络的流程和结构就可以实现自己的神经网络程序,准确率也比决策树有很大的提升;神经网路最繁琐的事就是调整模型参数,确定问题,优化方法,这三大任务甚至比创建神经网络更加重要,有需要学习交流可以私聊