训练一个神经网络
- 我们搭建由一个输入层,一个隐藏层,一个输出层组成的简单的三层神经网络。
- 输入层中节点数由数据的维度决定,也就是2个。
- 输出层节点数则是由类的数量来决定,也是2个。(我们只有一个预测0和1的输出节点,所以我们只有两类输出,实际中,两个输出节点将更易于在后期进行扩展从而获得更多类别的输出)。
-
以x,y坐标作为输入,输出的则是两种概率,一种是0(代表女),另一种是1(代表男)。
三层神经网络示意图
隐藏层维度可以选择,隐藏层节点越多,实现的功能就越复杂,但是维度过高也是会有代价的。
- 首先,更多的预测以及学习网络参数意味着更高的计算强度,更多的参数也会带来过拟合的风险,如何判断隐藏层的规模?
- 另外,还需要为隐藏层选择激活函数(activation function)。激活函数会将输入转化成输出。非线性的激活函数可以帮助我们处理非线性的假设。通常选用的激活函数有tanh, sigmoid function, ReLUs。
- 这些函数有一个优点,就是通过原始的函数值便可以计算出它们的导数。例如tanh的导数就是1-tanh2x。这让我们可以在推算出tanhx一次后就重复利用这个得到导数值。
- 鉴于我们希望我们的网络输出的值为概率,所以我们将使用softmax作为输出层的激活函数,这个函数可以将原始的数值转化为概率。
我们的网络是如何做出预测的呢?
神经网络是通过前向传播做出预测。如果该网络的输入x是二维的,那么我们可以通过以下方法来计算预测值y
Zi表示第i层的输入,ai表示应用激活函数后的输出。Wi,bi表示需要我们通过训练数据来获取的神经网络参数,可以把它们当做网络层与层之间之间用于转化数据的矩阵。
每个神经元有两个单元组成。一个是权重和输入信号。另一个是非线性单元,叫做激励函数。信号e是激励信号。y = f(e) 是非线性单元的输出,即是神经元的输出。

为了训练神经网络,我们需要训练数据。训练数据由输入信号(x1和x2 )和期望输出z组成。网络的训练过程是一个迭代处理的过程。训练数据集用来在每次迭代过程中更新神经元的权重。每次学习过程由来自训练数据的输入信号开始。我们可以得出每一层的输出。下图说明信号在神经网络的传输路线。w(xm)n 是神经元xm 在第n层输入的连接权重。 yn 表示神经元n的输出。

#定义一些变量和参数,用于梯度下降算法
num_examples=len(X)
nn_input_dim=2#input layer dimensionality
nn_output_dim=2#output layer dimensionality
#grandient descent parameters
epsilon=0.01#learning rate for grandient descent学习率
reg_lambda=0.01#regularization strength正则化强度
网络如何做出预测

-
激活函数tanh图形
tanh(x)
实现基本的三层神经网络
-
定义损失函数, 研究参数是为了找到能够使我们的训练数据集错误率最小化的参数(W1,b1,W2,b2)。该如何定义错误呢?我们在这里用损失函数(loss function)来检测错误。
-
通常对softmax的输出,我们会选择交叉熵损失函数(cross-entropy loss)(或者叫负对数似然)。如果我们有个训练示例,C个类别,那么预测值(hat{y})相对于真实的有标签数据的损失则可以通过如下方法来计算获得:


相差越大,损失就越大。
def calculate_loss(model):
W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
# Forward propagation to calculate our predictions
z1 = X.dot(W1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(W2) + b2
#计算Softmax
exp_scores = np.exp(z2)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
#计算损失函数 loss
corect_logprobs = -np.log(probs[range(num_examples), y])#对Softmax取对数
data_loss = np.sum(corect_logprobs)#损失函数为各输出值的的和
# Add regulatization term to loss (optional)加入L2正则化项,lambda是正则化参数
data_loss += reg_lambda/2 * (np.sum(np.square(W1)) + np.sum(np.square(W2)))
return 1./num_examples * data_loss#?这一句什么意思?




是正则项,lambda是正则化参数。
实现一个用于计算输出的辅助函数
def predict(model, x):
W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
# Forward propagation
z1 = x.dot(W1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(W2) + b2
exp_scores = np.exp(z2)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
return np.argmax(probs, axis=1) #返回最大值
训练神经网络的函数
- 我们我们的目标是找到能最小化损失函数的参数值。我们可以使用梯度下降方法找到最小值。这里,我们使用批量梯度下降法,这种方法的学习速率是固定的,它的衍化版例如SGD(随机梯度下降stochastic gradient descent)或者最小批量梯度下降(minibatch gradient descent)通常在实际使用中会有更好的效果。作为输入,梯度下降法需要各参数对应损失函数的梯度,即
为了计算这些梯度,我们使用后向传播算法,这种方法通过输出计算梯度效率很高。(后向传播算法可参见http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html或者https://www.cnblogs.com/charlotte77/p/5629865.html))。
# This function learns parameters for the neural network and returns the model.
# - nn_hdim: Number of nodes in the hidden layer
# - num_passes: Number of passes through the training data for gradient descent
# - print_loss: If True, print the loss every 1000 iterations
num_example=len(X)
def build_model(nn_hdim, num_passes=20000, print_loss=False):
# Initialize the parameters to random values. We need to learn these.
np.random.seed(0)
w1 = np.random.randn(nn_input_dim, nn_hdim) / np.sqrt(nn_input_dim)
b1 = np.zeros((1, nn_hdim))
w2 = np.random.randn(nn_hdim, nn_output_dim) / np.sqrt(nn_hdim)
b2 = np.zeros((1, nn_output_dim))
# This is what we return at the end
model = {}
# Gradient descent. For each batch...
for i in range(0, num_passes):
# Forward propagation
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_scores = np.exp(z2)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
# Backpropagation
delta3 = probs
delta3[range(num_example), y] -= 1
dw2 = (a1.T).dot(delta3)
db2 = np.sum(delta3, axis=0, keepdims=True)
delta2 = delta3.dot(w2.T) * (1 - np.power(a1, 2))
dw1 = np.dot(X.T, delta2)
db1 = np.sum(delta2, axis=0)
# Add regularization terms (b1 and b2 don't have regularization terms)
dw2 += reg_lambda * w2
dw1 += reg_lambda * w1
# Gradient descent parameter update参数更新
w1 += -epsilon * dw1
b1 += -epsilon * db1
w2 += -epsilon * dw2
b2 += -epsilon * db2
# Assign new parameters to the model
model = { 'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}
# Optionally print the loss.
# This is expensive because it uses the whole dataset, so we don't want to do it too often.
if print_loss and i % 1000 == 0:
print ("Loss after iteration %i: %f" %(i, calculate_loss(model)))
return model
# Build a model with a 3-dimensional hidden layer
model = build_model(3, print_loss=True)
# Plot the decision boundary
plot_decision_boundary(lambda x: predict(model, x))
plt.title("Decision Boundary for hidden layer size 3")
plt.show()

网友评论