之前一直调包,最近刷算法题,就突发奇想,想自己试一试实现一个简单的神经网络模型。 首先,初始化参数,这里直接使用用 神经网络中,每个 全连接层的前向传播,简单来说就是 由于是二分类与问题,这里使用 首先读取数据,这里读取 接下来就是模型搭建和训练了,这里搭建两个全连接层,进行训练,代码如下: 自己写的也不确定准不准确,所以就用 惊了,这里准确率的结果居然和我自己写的一模一样,绝对没有造假,不过应该是测试数据不够多的原因。 这里算是完整的自己手动实现了一个简单的神经网络,当然还存在很多缺陷与不足: 另外也是第一次写博客,写的不好请见谅,也请批评指正
记一次自己动手实现一个简单神经网络
从简单的开始,先实现一个二分类模型,使用印第安人糖料病数据集,数据集合源码可直接在github获取:github参数初始化
numpy的初始化数组
,代码如下: # 参数初始化 def inital_parameters(self, m, n): res = [] for i in range(m): res.append(np.random.randn(n)) return np.array(res)
定义激活函数
神经元
都有激活前和激活后的值,也可以认为是神经元的输入和输出,所以我们首先定义激活函数
。本模型中,在第一层全连接层中使用sigmoid
激活函数,第二层使用softmax
激活函数输出结果,这里都是用numpy
的内置方法计算,实现矩阵的并行化计算,具体公式可百度,代码如下: # sigmoid def sigmoid(self, x): return 1 / (1 + np.exp(-x)) # softmax def softmax(self, x): x_exp = np.exp(x) x_sum = np.sum(x_exp, axis=1, keepdims=True) s = x_exp / x_sum return s
前向传播
参数
与输入数据
线性组合和输入神经元,经过激活函数
后输出,要注意矩阵运算时的维度,代码如下: # 全连接层前向传播 def fully_connected_layer(self, x, layer): x, w, b = np.array(x), np.array(self.ws[layer]), np.array(self.bs[layer]) assert len(x[0]) == len(w[0]) assert len(w) == len(b[0]) self.input.append(x) pre_activation = np.sum([np.matmul(x, w.T), b], axis=0) post_activation = self.activate[layer](pre_activation) return post_activation
损失函数
交叉熵
来计算损失函数,并记录初始梯度
,代码如下: # 交叉熵损失函数 def cross_entropy(self, y_, Y): loss = 0 # 记录初始梯度 w_gradients = [[0, 0]] for i in range(len(y_)): predict = y_[i] for j in range(len(predict)): # +0.001,避免除0 w_gradients[0][j] -= 1 / (predict[j] + 0.0001) if j == Y[i]: loss -= np.log(predict[j]) break loss /= len(y_) w_gradients[0][0] /= len(y_) w_gradients[0][1] /= len(y_) self.w_gradient.append(np.array(w_gradients)) self.b_gradient.append(np.array(w_gradients)) return loss
实现BP(Backward Propagation)算法
BP(Backward Propagation)算法
,也是整个神经网络中的最复杂的部分,其核心在于计算梯度时求导的链式法则
,从神经网络最顶层开始,逐步向下层计算梯度,从而得到loss对于每一层参数的梯度。这里使用mini_batch梯度下降法
,加快计算,其中将mini_batch置为1时就是SGD
了,代码如下:# BP算法 def backward_propagation(self, learning_rate, Y, mini_batch_size): # mini_batch gradient_descent for i in range(len(self.ws) - 1, -1, -1): wi = self.ws[i] bi = self.bs[i] # 初始化当前层w的梯度 w_gradients = [[0 for _ in range(len(wi[0]))] for _ in range(len(wi))] # 初始化当前层b的梯度 b_gradients = [[0 for _ in range(len(bi[0]))]] # 上一层的w梯度 w_last_gradient = self.w_gradient[len(self.ws) - i - 1] # 上一层b梯度 b_last_gradient = self.b_gradient[len(self.bs) - i - 1] a_f_gra = self.activate_gradient[i] # mini_batch sample sample = np.random.randint(len(Y), size=mini_batch_size) # 计算当前层w的梯度 for l in range(len(wi)): w = wi[l] for j in range(len(w)): for k in sample: input = self.input[i][k] for m in range(len(w_last_gradient)): w_gradients[l][j] += learning_rate * w_last_gradient[m][l] * a_f_gra(input, j) * input[j] # 计算当前层b的梯度 for l in range(len(bi)): b = bi[l] for j in range(len(b)): for k in sample: input = self.input[i][k] for m in range(len(b_last_gradient)): b_gradients[l][j] += learning_rate * b_last_gradient[m][l] * a_f_gra(input, j) self.w_gradient.append(np.array(w_gradients)) self.b_gradient.append(np.array(b_gradients)) # 把初始梯度删去,然后因为是倒着添加梯度的,所以要倒过来 self.w_gradient.pop(0) self.w_gradient = self.w_gradient[::-1] self.b_gradient.pop(0) self.b_gradient = self.b_gradient[::-1] # w梯度下降 for i in range(len(self.ws)): wi = self.ws[i] for j in range(len(wi)): w = wi[j] for k in range(len(w)): self.ws[i][j][k] -= self.w_gradient[i][j][k] # b梯度下降 for i in range(len(self.bs)): bi = self.bs[i] for j in range(len(bi)): b = bi[j] for k in range(len(b)): self.bs[i][j][k] -= self.b_gradient[i][j][k] # 一轮梯度下降后清空 self.w_gradient = [] self.b_gradient = [] self.input = []
训练和测试
印第安人糖尿病数据集
,总共768条数据,取前700条作为训练数据,后68条作为测试数据,代码如下: # 读取数据 filename = 'data/pima_data.csv' names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] data = read_csv(filename, names=names) array = data.values X = np.array(array[:, 0:8]) Y = array[:, 8] X_normed = X / X.max(axis=0) X_train = X_normed[:700] X_test = X_normed[701:] Y_train = Y[:700] Y_test = Y[701:]
# 模型参数初始化 nn = NerualNetwork() sigmoid = ActivationFunction().sigmoid softmax = ActivationFunction().softmax sigmoid_gradient = ActivationFunction().sigmoid_gradient softmax_gradient = ActivationFunction().softmax_gradient w1, b1 = nn.inital_parameters(5, 8), nn.inital_parameters(1, 5) w2, b2 = nn.inital_parameters(2, 5), nn.inital_parameters(1, 2) # 导入初始化参数 nn.ws = [w1, w2] nn.bs = [b1, b2] # 导入激活函数及其导数 nn.activate = [sigmoid, softmax] nn.activate_gradient = [sigmoid_gradient, softmax_gradient] # 训练 epoch = 500 learning_rate = 0.005 mini_batch_size = 1 plot_x = [] plot_y = [] for i in range(epoch): f_c1 = nn.fully_connected_layer(X_train, 0) y_ = nn.fully_connected_layer(f_c1, 1) train_loss = nn.cross_entropy(y_, Y_train) print('Epoch:', i + 1, ', train_loss=', train_loss) plot_x.append(i + 1) plot_y.append(train_loss) nn.backward_propagation(learning_rate, Y_train, mini_batch_size) plt.xlabel('Epoch') plt.ylabel('loss') plt.plot(plot_x, plot_y) plt.show()
训练结果为:
Epoch: 500 , train_loss= 0.6623333458935591loss趋势图为:
训练完成之后,将训练后的参数用于测试数据中进行测试,并计算准确率
,代码如下: # 测试 f_c1 = nn.fully_connected_layer(X_test, 0) y_ = nn.fully_connected_layer(f_c1, 1) hit = 0 for i in range(len(y_)): predict = list(y_[i]) pr = predict.index(max(predict)) if pr == Y_test[i]: hit += 1 accuracy = hit / len(Y_test) print('accuracy=', accuracy)
测试结果为:
accuracy= 0.5970149253731343pytorch对比
pytorch
来对比一下吧,当然要使用同样的超参数,然后这里就不阐述了,直接上代码: # 读取数据 filename = 'data/pima_data.csv' names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] data = read_csv(filename, names=names) array = data.values X = np.array(array[:, 0:8]) Y = np.array(array[:, 8]) X_normed = X / X.max(axis=0) X_train = X_normed[:700] X_test = X_normed[701:] Y_train = Y[:700] Y_test = Y[701:] X_train = torch.tensor(X_train).float() Y_train = torch.tensor(Y_train).long() X_test = torch.tensor(X_test).float() Y_test = torch.tensor(Y_test).long() # 搭建网络 myNet = nn.Sequential( nn.Linear(8, 5, bias=True), nn.Sigmoid(), nn.Linear(5, 2, bias=True), nn.Softmax() ) # 设置优化器 optimzer = torch.optim.SGD(myNet.parameters(), lr=0.005) loss_func = nn.CrossEntropyLoss() plot_x = [] plot_y = [] for epoch in range(500): out = myNet(X_train) loss = loss_func(out, Y_train) print('Epoch=', epoch+1, ' train_loss=', loss) plot_x.append(epoch + 1) plot_y.append(loss) optimzer.zero_grad() loss.backward() optimzer.step() plt.xlabel('Epoch') plt.ylabel('loss') plt.plot(plot_x, plot_y) plt.show() y_ = np.array(myNet(X_test).data) hit = 0 for i in range(len(y_)): predict = list(y_[i]) pr = predict.index(max(predict)) if pr == Y_test[i]: hit += 1 accuracy = hit / len(Y_test) print('accuracy=', accuracy)
pytorch的训练结果
:
Epoch= 500 train_loss= tensor(0.6753)pytorch的loss趋势图为:
测试结果为:
accuracy= 0.5970149253731343缺陷与不足
(1)参数的初始化不够好
(2)梯度下降时没有使用矩阵并行计算,这里怕写错,所以暂时直接用的for循环,之后再看看修改
(3)训练未设置收敛条件
(4)BP实现的比较仓促,肯定还有很多细节问题,导致我的loss比较陡峭
(5)肯定还有很多很多很多很多问题,请批评指正
(6)肯定还有很多很多很多很多问题,请批评指正
(7)肯定还有很多很多很多很多问题,请批评指正
。。。。。。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算