一个神经网络的训练算法就是让权重的值调整到最佳,以使得整个网络的预测(或者分类)效果最好。
一般来说更多神经元的神经网络可以表达更复杂的函数。然而这既是优势也是不足,优势是可以分类更复杂的数据,不足是可能会造成对训练数据的过拟合。过拟合(Overfitting)是指网络对数据中的噪声有很强的拟合能力,而没有重视数据之间潜在的基本关系。
如果面对的是二分类的问题,以考虑使用Sigmoid函数作为隐藏层和输出层之间的激活函数;如果面对的是多分类的同题,则可以考虑使用Softmax作为隐藏层和输出层之间的激活函数
Sigmoid函数容易造成梯度消失,在靠近0和1的时候,曲线变得非常平缓,所以在初始化的时候需要注意权重的大小,过大会导致神经元变得饱和,从而无法更新参数。
import numpy as np def_sigmoid(x): return 1 / (1+np.exp(-x))
2.Tanh函数
Tanh函数和Sigmoid函数的曲线是比较相近的。相同的是,这两个函数在输入很大或是很小的时候,输出都几乎是平滑的,当梯度很小时,将不利于权重更新;不同之处在于输出区间,tanh的输出区间是在(-1,1)之间,而且整个函数是以0为中心的,这个特点比Sigmoid要好。这个性质使得 tanh
函数在神经网络中非常有用,因为它可以帮助防止梯度消失或梯度爆炸的问题,尤其是在使用反向传播算法进行训练时。
3.ReLU函数
线性整流函数(Rectified Linear Unit,ReLU),又称为修正性线性单元,ReLU是一个分段函数,其公式为f(x)=max(0,x),大于0的数将直接输出,小于0的数则输出为0,在0这个地方虽然不连续,但其也同样适合做激活函数。ReLU是目前应用较为广泛的激活函数,其优点为在随机梯度下降的训练中收敛很快,在输入为正数的时候,不存在梯度饱和的问题,RELU函数只有线性关系,不管是前向传播还是反向传播都比Sigmoid函数要快很多。(sigmoid函数要计算指数,速度会比较慢)
import numpy as np def_relu_(x): return np.maxium(0,x)
4、前向传播
神经网络前向传递过程的四个关键步骤具体说明如下。
1)输入层的每个节点,都需要与隐藏层的每个节点做点对点的计算,计算的方法是加权求和+激活函数。
2)利用隐藏层计算出的每个值,再使用相同的方法,与输出层进行计算(简单神经网络结构)。
3)隐藏层大量使用ReLU函数之前广泛使用Sigmoid作为激活函数,而输出层如果是二分类问题则一般使用Sigmoid函数;如果是多分类问题则一般使用Softmax作为激活函数。
4)起初输人层的数值将通过网络计算分别传播到隐藏层,再以相同的方式传播到输出层,最终的输出值将与样本值进行比较,计算出误差,这个过程称为前向传播。
import numpy as np def _sigmoid(in_data): return 1 / (1 + np.exp(-in_data)) #输入层 x = np.array([0.9,0.1,0.8]) #隐藏层:需要计算输入到中间层每个节点的组合,中间隐藏层的每个节点都与输入层的每个节点相连所以w1是一个3*3的矩阵 #因此每个节点都得到输入信号的部分信息。 #第一个输入节点和中间隐藏层第一个节点之间的权重为w11=0.9,输入的第二个节点和隐藏层的第二节点之间的链接的权重为w22 = 0.8 w1 = np.array([[0.9,0.3,0.4], [0.2,0.8,0.2], [0.1,0.5,0.6]]) #因为输出层有3个节点,所以w2也是一个3*3的矩阵 w2 = np.array([ [0.3,0.7,0.5], [0.6,0.5,0.2], [0.8,0.1,0.9] ]) Xhidden = _sigmoid(w1.dot(x)) print(Xhidden) Xoutput = w2.dot(Xhidden) print(Xoutput) #最终输出的结果
5、在神经网络中,Bias(偏置)是神经元输出中的一个可调整参数,用于控制神经元的激活阈值。
- 作用:
- 提高模型的表达力:Bias可以增加模型的灵活性,使模型能够更好地拟合数据。
- 保证激活函数工作在非线性区域:对于某些激活函数(如sigmoid、tanh),Bias可以确保神经元在输入为0时也能在非线性区域工作,从而提高模型的非线性表达能力。
- 防止过拟合:通过适当的正则化方法(如L1、L2正则化),可以对Bias进行约束,帮助防止模型过拟合。
6、softmax函数
i表示类别索引/
zi表示是当前的元素的指数与所有元素指数和的比值,softmax将多分类的输出值转让为相对概率
#x为输入的向量 def _softmax(x): exp _x = np.exp(x) return exp_x / np.sum(exp_x)
7、one hotencoding
独热码,有多少个状态就有多少比特,只有一个比特为1,其他全为0
假如多个特征需要独热编码,那么就依次将每个特征的独热编码拼接起来。
8、输出层的神经元个数一般与类别的数量保持一致。比如在手写数字识别中,0-9个数字,输出层就设置10个神经元。
MNIST数据集的前向传播
- 数据的读取
#MNIST dataset train_dataset = dsets.MN1ST(root = '/ml/pymnint', #选择数据的根目录 train = True, #选择训练集 tranaform = transforms .ToTensor (),#转横成tensor 变量 download = False)#不从网络上下载图片 tent_datanet - dsets.MNIST(root = '/ml/pymniat', #选择数据的根节录 train =False, #选择测试集 transform = transforms.ToTensor(),#特换成tensor download=False) #不从网络上下载图片
2 、初始化init-network函数,设置了 weight_ scale变量用于控制随机权重不要过大,我们将bias统一设置为1
def init_network(): network={} weight_scale = 1e-3 network['Wl']=np.random,randn(784,50) * weight_acale
network['b1']=np.ones(50) network['W2']=np.random.randn (50,100) * weight_ucalo
network['b2']=np.ones(100) network['w3']=np.random.randn(100,10) * weight_scale
network['b3']=np.ones(10) return network
3、实现forward函数
def forward(network,x): w1,w2,w3 = network['W1'),network['w2'],network['W3'] b1,b2,b3 = network[b1'],network['b2'],network['b3'] a1 =x,dot(w1)+bi z1=_relu(al) a2 = z1.dot(w2) + b2 z2= _relu(a2) a3 = z2.dot (w3) + b3 y= a3 return y
最后,测试下在测试集下使用神经网络(仅包含前向传播)的准确度能达到多少函数以Numpy数组的形式输出与各个标签对应的概率。比如输出[0.1,0.5,0.3...., 0.04]的数组,该数组表示“0”的概率为0.1,“1”的概率为0.5等。之后,我们取出这个概率到表中的最大值的索引(第几个元素的概率最高)作为预测结果(使用np.argmax(x)函数取出数组中的最大值的索引)。最后通过比较神经网络所预测的分类答案和正确标签,输出回答正确的概率。
network = init_network() accuracy_cnt = 0 x = test_dataset.test_data.numpy().reshape(-1,28*28) labels = test_dataset.test_labels.numpy() #tensor转labels for i in range(len(x)): y = forward(network,x[i]) p = np.argmax(y) #获取概率最高的元素的索引 if p == labels[i]: accuracy_cnt +=1 print("Accuracy:" + str(float(accuracy_cnt) /len(x) *100) +"%")
批处理
从逐一处理到批处理,需要对softmax做修改,因为softmax只支持向量
import numpy as np def_softmax(x): if x.ndim= 2: c=np,max(x,axis=0) x = x.T-c #溢出对策 y=np.exp(x) / np.sum(np.exp(x),axis=0) return y.T c = np.max(x) exp_x=np.exp(x-c) return exp_x / np.sum(exp_x)
另一个需要修改的地方为
accuracy_cnt=0 batch_eize = 100 x= test_dataset.test_data.numpy().reshape(-1,28*28) labels = test_dataset.test_labels.numpy() for i in range(0,len(x),batch_size): x_batch =x[i:i+batch_size] y_batch = forward(network,x_batch) p=np.argmax(y_batch,axis=1) accuracy_cnt += np.sum(p == labels[i:i+batch_size])累积整体的准确预测数 print ("Accuracy : " + str(float (accuracy_cnt)/ len(x) * 100)+"%")
对于Sigmoid 激活函数,我们使用a作为矩阵,a1作为向量进行测试
import nuspy as np a=np.array(ll-1,1,2,3), [-2,-1,4,5]]) a1 =np.array([-1,1,2,3]) def _sigmoidlin_data): return 1 / (1 +np.exp(-in_datal) print(_sigmoid(a1)) print(_sigmoid(a))
输入x变为矩阵后,对于sigmoid函数以及relu函数都不会产生影响
9、广播原则
在Softmax 的代码修改中,我们使用了Python中的广播原则,广播原则指的是如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符,或者其中一方的长度为1,则认为它们是广播兼容的。广播会在缺失和(或)长度为1的维度上进行。这句话乃是理解广播的核心。广播主要发生在两种情况:一种是两个数组的维数不相等,但是它们的后缘维度的轴长相符;另外一种是有一方的长度为1
import numpy as np arrl=np.array([[0,0,0],[1,1,1],[2,2,2],[3,3,311) arr2 =np.array([1,2,31) arr_sum = arr1 + arr2 print(arr1.shape) print(arr2.shape) print(arr_sum)
10、损失函数
均方误差
均方误差(meansquarederror)是各数据偏离真实值的距离平方和的平均数,也即误差平方和的平均数,用σ表示。均方误差可以用作机器学习中的损失函数,用于预测和回归。程中更加关注那些预测偏差较大的样本。然而,均方误差对异常值(即远离其他数据点的值)非常敏感,因为异常值的平方会很大,从而可能对均方误差产生显著影响。
def mean_squared_error(p,y); return np.sum((p-y)**2)/y.shape[0]
import numpy as np y= np.array([0,1,0,01) p=np.array([0.2,0.6,0.1,0.1]) def mean_squared_error (p,y): return np.sum((p-y)**2)/y.shape[0] print(mean_squared_error(p,y))
交叉熵误差
为了最小化loss值,我们的目标就变成了使得y-predict2的概率尽可能地大
def cross_entropy_error(p,y): return np.sum(-y*np.log(p))
举例
import numpy as np def cross_entropy-error (p,y): delt=1e-7 return np.sum(-y*np.log (p+delta)) y = np.array([0,1.0.0]) p=np.array([0.3,0.2,0.1,0.4]) print(cross_entropy_error(p,y))
Mini-batch
Mini-batch是一个一次训练数据集的一小部分,而不是整个训练集的技术。它可以使内存较小、不能同时训练整个数据集的电脑也可以训练模型
def cross_entroy_error(p,y) delta = 1e-7 batch_size = p.shape[0] return -np.sum(y*np.log(p+delta)) / batch_size
11、最优化
最优化就是找到能够使损失函数值最小化的一系列W
随机初始化
accuracy_cnt = 0#初始化一个计数器,
batch_size = 100
x = test_dataset.test_data.numpy().reshape(-1,28*28)
labels = test_dataset.test_labels
finallabels = labels.reshape(labels.shape[0],1)
bestloss = float('inf')#bestloss
初始化为正无穷大
for i in range(0,int(len(x)),batch_size):
network = init_network()
x_batch = x[i:i+batch_size]
y_batch = forward(network, x_batch)
one_hot_labels = torch.zeros(batch_size, 10).scatter_(1, finallabels[i:i+batch_size], 1)
loss = cross_entropy_error(one_hot_labels.numpy(),y_batch)
if loss < bestloss:
bestloss = loss
bestw1,bestw2,bestw3 = network['W1'],network['W2'],network['W3']
print("best loss: is %f " %(bestloss))
将数据转成one-hot类型。one_hot_labels = torch.zeros(batch_size, 10).scatter_(1, finallabels[i:i+batch_size], 1)标签:图像识别,network,labels,batch,神经网络,深度,np,return,函数 From: https://www.cnblogs.com/candice1/p/18330728
#scatter_
是一个在张量上进行原地操作的方法。第一个参数1
指定了要在第二维上进行操作,即按照列进行散布,最后一个参数1
指定要放置的值,这里是将索引指定位置的元素设置为1
。