深度学习——第一个ANN网络
深度学习——第一个ANN网络
深度学习学的第一个网络,参考B站视频
网络概述
人工神经网络(Artificial Neural Network,简称ANN )中,每一层都可以用 output = A(W·input+b) 来表示,其中input代表输入,output代表输出,A,W,b是本层网络的参数,A:激活函数,将线性变换转化为非线性变换,W:权重,每一个输入的像素的重要程度,b:偏置值。
本网络的只有一层神经网络,即一层网络层。
输入层网络为:x=A0(input+b),其中A0 :tanh ,b的初始值为 0;
网络层为:output=A1(W·x+b),其中A1:softmax,W的初始值分布为平均分布,b的初始值为0。
训练数据
训练的数据为MNIST,见附录,此数据分为4个文件:2个数据文件:60000个训练数据和10000个测试数据,2个标签文件:与数据对应的标签文件。
设置文件的读入路径:
#引入包来处理路径 from pathlib import Path dataset_path=Path('./MNIST') train_img_path=dataset_path/'train-images.idx3-ubyte' train_lab_path=dataset_path/'train-labels.idx1-ubyte' test_img_path=dataset_path/'t10k-images.idx3-ubyte' test_lab_path=dataset_path/'t10k-labels.idx1-ubyte'
在python中,使用pathlib模块来处理文件和文件夹,其中,Path对象用来操作目录与文件。数据文件与模型文件放到同一包内即可。
具体读入操作如下:
#读取的图片相关信息 #import struct #train_f=open(train_img_path,'rb') ##struct.unpack(format, buffer),format代表构建的格式,>代表存储方向 4个 i:整数 #struct.unpack('>4i',train_f.read(16)) #输出:(2051, 60000, 28, 28) #可以不用struct去读,用numpy中的fromfile函数去读就可以了 #np.fromfile(train_f,dtype=np.uint8).reshape(-1,28*28) import struct #训练集个数,验证集个数,测试集个数 train_num=50000 valid_num=10000 test_num=10000 with open(train_img_path,'rb') as f: struct.unpack('>4i',f.read(16)) tmp_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)/255 train_img=tmp_img[:train_num] valid_img=tmp_img[train_num:] with open(test_img_path,'rb') as f: struct.unpack('>4i',f.read(16)) test_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)/255 with open(train_lab_path,'rb') as f: struct.unpack('>2i',f.read(8)) tmp_lab=np.fromfile(f,dtype=np.uint8) train_lab=tmp_lab[:train_num] valid_lab=tmp_lab[train_num:] with open(test_lab_path,'rb') as f: struct.unpack('>2i',f.read(8)) test_lab=np.fromfile(f,dtype=np.uint8)
因为测试数据test非常珍贵,不能每次都用它来评估模型,所以将训练数据分为train 和 valid。
显示图片
#画图 import matplotlib.pyplot as plt #im = np.reshape(train_im,(28,28)) #plt.imshow(im,cmap='gray') #定义一个图片初始化显示函数 def show_train(index): plt.imshow(train_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(train_lab[index])) def show_valid(index): plt.imshow(valid_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(valid_lab[index])) def show_test(index): plt.imshow(test_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(test_lab[index]))
构建神经网络
对神经网络结构进行初始化,具体如下:
#第一个深度学习网络ANN 人工神经网络 #输入层28*28 #激活函数A=tanh A'=softmax 非线性变换 #模型参数b0 784*1 W 784*10 b1 10*1 import numpy as np import math #两个激活函数 def tanh(x): return np.tanh(x) def softmax(x): exp=np.exp(x-np.max(x)) return exp/exp.sum() #模型的输入输出以及相关参数 #input为28*28 output为10*1 dimensions=[28*28,10]; #激活函数:tanh softmax 归一化 activation=[tanh,softmax]; #模型参数 第0层,第1层 distribution=[ {'b':[0,0]}, {'b':[0,0],'w':[-math.sqrt(6/(dimensions[0]+dimensions[1])),math.sqrt(6/(dimensions[0]+dimensions[1]))]}, ] #初始化参数 def init_parameters_b(layer): dist=distribution[layer]['b'] return np.random.rand(dimensions[layer])*(dist[1]-dist[0])+dist[0] def init_parameters_w(layer): dist=distribution[layer]['w'] return np.random.rand(dimensions[layer-1],dimensions[layer])*(dist[1]-dist[0])+dist[0] #自动调用面对参数进行初始化 def init_parameters(): parameter=[] for i in range(len(distribution)): layer_parameter={} for j in distribution[i].keys(): if j=='b': layer_parameter['b']=init_parameters_b(i) continue if j=='w': layer_parameter['w']=init_parameters_w(i) continue parameter.append(layer_parameter) return parameter #模型最初的参数 parameters=init_parameters()
模型实现预测:
#模型实现 #预测输入为图片和模型参数 def predict(img,parameters): l0_in=img+parameters[0]['b'] l0_out=activation[0](l0_in) #dot代表内积 l1_in=np.dot(l0_out,parameters[1]['w'])+parameters[1]['b'] l1_out=activation[1](l1_in) return l1_out
反向传播
首先需要定义损失函数
#损失函数Loss function 参数影响损失函数,寻找参数使损失函数值最小 #梯度下降 需要先求梯度 #导数性质: 加,数乘,乘,除 #导数链式法则:洋葱一层一层求导 #多元函数的导数:偏导*内层导数的和 #损失函数定义为L=(y0-ypre0)^2+(y1-ypre1)^2+......+(y9-ypre9)^2 #ypre就是模型的output #代入之后,L是关于W,b1,b2的一个函数,然后对W,b1,b2,分别求偏导就可以得到其梯度方向 #激活函数的导数,需要用导数定义证明导数的正确性 def d_softmax(data): sm=softmax(data) return np.diag(sm)-np.outer(sm,sm) #def d_tanh(data): # return np.diag(1/(np.cosh(data))**2) #优化:为了减少计算量 def d_tanh(data): return 1/(np.cosh(data))**2 differential={softmax:d_softmax,tanh:d_tanh} #把label转换为标准向量形式 onehot=np.identity(dimensions[-1]) #定义损失函数 def sqr_loss(img,lab,parameters): y_pred=predict(img,parameters) y=onehot[lab] diff=y-y_pred return np.dot(diff,diff)
根据损失函数对参数求梯度
#求参数的梯度 def grad_parameters(img,lab,parameters): l0_in=img+parameters[0]['b'] l0_out=activation[0](l0_in) #dot代表内积 l1_in=np.dot(l0_out,parameters[1]['w'])+parameters[1]['b'] l1_out=activation[1](l1_in) diff=onehot[lab]-l1_out act1=np.dot(differential[activation[1]](l1_in),diff) grad_b1=-2*act1 grad_w1=-2*np.outer(l0_out,act1) grad_b0=-2*differential[activation[0]](l0_in)*np.dot(parameters[1]['w'],act1) return {'w1':grad_w1,'b1':grad_b1,'b0':grad_b0}
训练模型
梯度计算方法和参数更新方法
#训练神经网络 #划分atch进行训练,防止训练时间过长 batch_size=100 #返回批训练的梯度 def train_batch(current_batch,parameters): grad_accu=grad_parameters(train_img[current_batch*batch_size+0],train_lab[current_batch*batch_size+0],parameters) for img_i in range(1,batch_size): grad_tmp=grad_parameters(train_img[current_batch*batch_size+img_i],train_lab[current_batch*batch_size+img_i],parameters) for key in grad_accu.keys(): grad_accu[key]+=grad_tmp[key] for key in grad_accu.keys(): grad_accu[key]/=batch_size return grad_accu #对参数进行更新 import copy def combine_parameters(parameters,grad,learn_rate): parameter_tmp=copy.deepcopy(parameters) parameter_tmp[0]['b']-=learn_rate*grad['b0'] parameter_tmp[1]['b']-=learn_rate*grad['b1'] parameter_tmp[1]['w']-=learn_rate*grad['w1'] return parameter_tmp
损失和精确度方法
#判断模型精确度 #验证集损失 def valid_loss(parameters): loss_accu=0; for img_i in range(valid_num): loss_accu+=sqr_loss(valid_img[img_i],valid_lab[img_i],parameters) return loss_accu/(valid_num/10000) #是否精确 def valid_accuracy(parameters): correct=[predict(valid_img[img_i],parameters).argmax()==valid_lab[img_i] for img_i in range(valid_num)] return correct.count(True)/len(correct) #训练集损失 def train_loss(parameters): loss_accu=0; for img_i in range(train_num): loss_accu+=sqr_loss(train_img[img_i],train_lab[img_i],parameters) return loss_accu/(train_num/10000) #是否精确 def train_accuracy(parameters): correct=[predict(train_img[img_i],parameters).argmax()==train_lab[img_i] for img_i in range(train_num)] return correct.count(True)/len(correct)
模型的训练过程
#进度条 有更新 from tqdm.notebook import tqdm #定义一些变量对训练过程进行表示 current_epoch=0 train_loss_list=[] valid_loss_list=[] train_accu_list=[] valid_accu_list=[] #对所有train_img进行训练 epoch_num=10 learn_rate=0.1 for epoch in tqdm(range(epoch_num)): for i in range(train_num//batch_size): grad_tmp=train_batch(i,parameters) parameters=combine_parameters(parameters,grad_tmp,learn_rate) current_epoch+=1 train_loss_list.append(train_loss(parameters)) train_accu_list.append(train_accuracy(parameters)) valid_loss_list.append(valid_loss(parameters)) valid_accu_list.append(valid_accuracy(parameters))
模型评估
画图显示损失与精确度
#画图显示损失和准确度 lower=0 plt.plot(valid_loss_list[lower:],color='black',label='validation loss') plt.plot(train_loss_list[lower:],color='red',label='train loss') plt.show() plt.plot(valid_accu_list[lower:],color='black',label='validation accuracy') plt.plot(train_accu_list[lower:],color='red',label='train accuracy') plt.show()
关于学习率过大的问题
#解决学习率过大的问题 rand_batch=np.random.randint(train_num//batch_size) grad_lr=train_batch(rand_batch,parameters) #存学习率和loss lr_list=[] lower=-2 upper=0 step=0.1 for lr_pow in np.linspace(lower,upper,num=20): learn_rate=10**lr_pow parameter_tmp=combine_parameters(parameters,grad_lr,learn_rate) train_loss_tmp=train_loss(parameter_tmp) lr_list.append([lr_pow,train_loss_tmp]) plt.plot(np.array(lr_list)[:,0],np.array(lr_list)[:,1],color='black',label='validation loss') plt.show()
网路可能会出现非全局最优,停在局部最优点。
网络还有可能出现暗点
这些问题在后续的学习中慢慢解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)