首页 > 编程知识 正文

使用神经网络进行分类的步骤,三层神经网络如何实现分类

时间:2023-05-04 23:08:08 阅读:189133 作者:518

本文由**罗欢喜的老鼠stupidme.me.lzy@gmail.com**原创,转载请注明作者和出处。未经授权,不得用于商业用途。

不使用任何深度学习框架,实现一个简单的神经网络用来分类。 手把手带你搭建神经网络,包括损失函数的选择,已经手写反向传播代码。

生成一些数据

生成一些数据,这些数据不太容易线性分类。

import numpy as npimport matplotlib.pyplot as pltN = 100 # 每一个类别的生成的点的数量D = 2 # 每个点的维度,这里使用平面,所以是2维数据K = 3 # 类别数量,我们一共生成3个类别的点# 所有的样本数据,一共300个点,每个点用2个维度表示# 所有训练数据就是一个300*2的二维矩阵X = np.zeros((N*K, D))# 标签数据,一共是300个点,每个点对应一个类别,# 所以标签是一个300*1的矩阵y = np.zeros(N*K, dtype='uint8')# 生成训练数据for j in range(K): ix = range(N*j, N*(j+1)) r = np.linspace(0.0, 1, N) t = np.linspace(j*4, (j+1)*4, N) + np.random.randn(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, s=40, cmap=plt.cm.Spectral)plt.show()复制代码

训练一个Softmax线性分类器

使用softmax和cross-entropy loss,训练一个线性分类器。

实际上就是直接用softmax做多分类,使用交叉熵损失作为损失函数,训练一个线性分类模型。

import numpy as npimport matplotlib.pyplot as pltN = 100D = 2K = 3X = np.zeros((N*K, D))y = np.zeros(N*K, dtype='uint8')for j in range(K): ix = range(N*j, N*(j+1)) r = np.linspace(0.0, 1, N) t = np.linspace(j*4, (j+1)*4, N) + np.random.randn(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, s=40, cmap=plt.cm.Spectral)# plt.show()# 初始化权重和偏置W = 0.01 * np.random.randn(D, K)b = np.zeros((1, K))step_size = 1e-0reg = 1e-3 # regularization strength# 获取训练样本数量num_examples = X.shape[0]for i in range(200): # 计算分类得分 scores = np.dot(X, W) + b # 计算 softmax得分 exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # 使用交叉熵损失 correct_log_probs = -np.log(probs[range(num_examples), y]) # 计算训练集的data loss,总的损失除以样本数量 data_loss = np.sum(correct_log_probs) / num_examples # 计算正则项损失reg loss,使用L2正则 # reg就是lambda reg_loss = 0.5 * reg * np.sum(W * W) # 计算总的损失函数 loss = data_loss + reg_loss if i%10 == 0: print("iteration %4d loss: %f" % (i, loss)) # 计算梯度,反向传播 # 为什么 dscores = probs ?? dscores = probs dscores[range(num_examples), y] -= 1 dscores /= num_examples dW = np.dot(X.T, dscores) db = np.sum(dscores, axis=0, keepdims=True) dW += reg * W # 正则项的梯度,dW不是第一次出现,必须累加 # 更新参数 W += -step_size * dW b += -step_size * db # 训练结束,估算准确率scores = np.dot(X, W) + b# 在第二个维度(类别维度)取出概率最高的分类predicted_class = np.argmax(scores, axis=1)print("Training accuracy: %.2f" % (np.mean(predicted_class == y)))复制代码 iteration 0 loss: 1.097993iteration 10 loss: 0.908688iteration 20 loss: 0.838372iteration 30 loss: 0.806482iteration 40 loss: 0.789911iteration 50 loss: 0.780488iteration 60 loss: 0.774783iteration 70 loss: 0.771169iteration 80 loss: 0.768801iteration 90 loss: 0.767208iteration 100 loss: 0.766114iteration 110 loss: 0.765351iteration 120 loss: 0.764811iteration 130 loss: 0.764425iteration 140 loss: 0.764147iteration 150 loss: 0.763945iteration 160 loss: 0.763797iteration 170 loss: 0.763688iteration 180 loss: 0.763608iteration 190 loss: 0.763548Training accuracy: 0.51复制代码

上面代码中,有一个疑问:为什么dscores = probs?

Softmax函数得到的是一个归一化后的概率向量,我们用 表示类别为k的概率。那么:

那么我们的交叉熵损失为:

那么,有:

这个式子表明:增加正确分类的分数,可以使得损失降低

假设概率向量

并且第二个0.3是正确分类的概率值。那么我们的梯度是怎么样的呢?

根据上面的公式,只有在正确分类处,梯度变成原来分类概率-1,其他位置,梯度就等于原来的分类概率,也就是:

而这里的f不就是我们的scores函数吗?

也就是说

那么,对于的地方,我们就好了。

于是,我们有了以下公式:

# 一般情况下的df,也就是dscoresdscores = probs# 预测分类正好是正确分类的情况,需要在该位置的梯度值减去1dscores[range(num_examples), y] -= 1# 平均dscores /= num_examples复制代码

总之,这是因为softmax这个函数自身的性质!!!

可以看到,正确率只有 0.51。

也算是预料之中,因为数据本来线性特征就不明显。强行上线性分类器,当然效果不佳了。

斯坦福cs231n有一个图,展示了这个模型的决策边界:

训练一个神经网络

上面的softmax线性分类器效果不佳,我们训练一个神经网络试试看。

代码如下:

import numpy as npN = 100D = 2K = 3X = np.zeros((N*K, D))y = np.zeros(N*K, dtype='uint8')for j in range(K): ix = range(N*j, N*(j+1)) r = np.linspace(0.0, 1, N) t = np.linspace(j*4, (j+1)*4, N) + np.random.randn(N)*0.2 X[ix] = np.c_[r*np.sin(t), r*np.cos(t)] y[ix] = jh = 100 # 隐藏层的神经元数量# 第一个层的权重和偏置初始化W1 = 0.01 * np.random.randn(D, h)b1 = np.zeros((1, h))# 第二层的权重和偏置初始化W2 = 0.01 * np.random.randn(h, K)b2 = np.zeros((1, K))step_size = 1e-0reg = 1e-3 # regularization strength# 获取训练样本数量num_examples = X.shape[0]for i in range(10000): # 计算第一个隐藏层的输出,使用ReLU激活函数 hidden_layer = np.maximum(0, np.dot(X, W1) + b1) # 计算输出层的结果,也就是最终的分类得分 scores = np.dot(hidden_layer, W2) + b2 # softmax exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K] # 计算损失,和之前的一样 correct_logprobs = -np.log(probs[range(num_examples),y]) data_loss = np.sum(correct_logprobs)/num_examples reg_loss = 0.5*reg*np.sum(W1*W1) + 0.5*reg*np.sum(W2*W2) loss = data_loss + reg_loss if i % 1000 == 0: print ("iteration %4d loss %f" % (i, loss)) # 计算scores的梯度 dscores = probs dscores[range(num_examples),y] -= 1 dscores /= num_examples # 计算梯度,反向传播 dW2 = np.dot(hidden_layer.T, dscores) db2 = np.sum(dscores, axis=0, keepdims=True) # 反向传播隐藏层 dhidden = np.dot(dscores, W2.T) # 反向传播ReLu函数 dhidden[hidden_layer <= 0] = 0 dW1 = np.dot(X.T, dhidden) db1 = np.sum(dhidden, axis=0, keepdims=True) # 加上正则项 dW2 += reg * W2 dW1 += reg * W1 # 更新参数 W1 += -step_size * dW1 b1 += -step_size * db1 W2 += -step_size * dW2 b2 += -step_size * db2# 训练结束,估算正确率hidden_layer = np.maximum(0, np.dot(X, W1) + b1)scores = np.dot(hidden_layer, W2) + b2predicted_class = np.argmax(scores, axis=1)print("Training accuracy: %.2f" % (np.mean(predicted_class == y)))复制代码 iteration 0 loss 1.109818iteration 1000 loss 0.277248iteration 2000 loss 0.202578iteration 3000 loss 0.192406iteration 4000 loss 0.189857iteration 5000 loss 0.189404iteration 6000 loss 0.189292iteration 7000 loss 0.189199iteration 8000 loss 0.189143iteration 9000 loss 0.189097Training accuracy: 0.99复制代码

可以看到,正确率已经提升到0.99。

斯坦福cs231n也有一张图,展示了这个神经网络的决策边界:

联系我 Email: stupidme.me.lzy@gmail.comWeChat: luozhouyang0528 个人公众号,你可能会感兴趣

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。