1 神经网络中的过拟合问题
MNIST(Modified National Institute of Standards and Technology)是一个经典的手写数字分类数据集,广泛用于机器学习、深度学习以及图像处理的教学和研究。MNIST 数据集包含了大量的手写数字图像,常被用作入门级的分类任务。它的任务是从 28x28 像素的灰度图像中识别出数字(0-9)。MNIST 数据集组成: (1) 训练集:60,000张手写数字图像;测试集:10,000张手写数字图像。(2)图像:每张图片是一个28x28的灰度图像,像素值在[0, 255]之间,其中0表示白色,255表示黑色。
1、在 MNIST 数字分类上应用带有 relu 隐藏层的三层神经网络,在训练集上的Error和正确率:
import sys,numpy as np
from keras.datasets import mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data()
#维度分别为(60000,28,28),((60000,)
x_train.shape,y_train.shape
#维度分别为(1000,28*28),((1000,)
#功能:降维,进行标准化
images,labels = (x_train[0:1000].reshape(1000,28*28)/255,y_train[0:1000])
#维度是(1000,10)
one_hot_labels = np.zeros((len(labels),10))
#这个是结果的维度(1000,10),在0-9的的对应位置上标记为1,其余位置标记为0
for i,l in enumerate(labels):
one_hot_labels[i][l] = 1
labels = one_hot_labels
test_images = x_test.reshape(len(x_test),28*28)/255
test_labels = np.zeros((len(y_test),10))
for i,l in enumerate(y_test):
test_labels[i][l] = 1
np.random.seed(1)
relu = lambda x:(x>0) * x
relu2deriv = lambda x:x>0
#三层神经网络 layer0 为 784,layer1 隐藏层为 40,layer2 结果层为10
alpha,interations,hidden_size,pixels_per_image,num_labels = (0.005,350,40,784,10)
#初始化权重
weight_0_1 = 0.2*np.random.random((pixels_per_image,hidden_size)) - 0.1
weight_1_2 = 0.2*np.random.random((hidden_size,num_labels)) - 0.1
#迭代次数
for j in range(interations):
error,correct_cnt = (0.0,0)
#遍历整个test数据集
for i in range(len(images)):
#三层神经网络
layer_0 = images[i:i+1]
#relu实现非线性
layer_1 = relu(np.dot(layer_0,weight_0_1))
layer_2 = np.dot(layer_1,weight_1_2)
#错误
error += np.sum((labels[i:i+1] - layer_2)**2)
#np.argmax返回最大值位置索引
#计算预测分类正确的次数
correct_cnt += int(np.argmax(layer_2) == np.argmax(labels[i:i+1]))
layer_2_delta = (labels[i:i+1] - layer_2)
#反向传播
layer_1_delta = layer_2_delta.dot(weight_1_2.T)*relu2deriv(layer_1)
#更该权重
weight_1_2 += alpha * layer_1.T.dot(layer_2_delta)
weight_0_1 += alpha * layer_0.T.dot(layer_1_delta)
sys.stdout.write("\r" + \
" I:" + str(j) + \
" Error:" + str(error/float(len(images)))[0:5] +\
" Correct:" + str(correct_cnt/float(len(images)))
)
2、在测试集上的Error和正确率:
if(j % 10 == 0 or j == interations-1):
error,correct_cnt = (0.0,0)
for i in range(len(test_images)):
layer_0 = test_images[i:i+1]
layer_1 = relu(np.dot(layer_0,weight_0_1))
layer_2 = np.dot(layer_1,weight_1_2)
error += np.sum((test_labels[i:i+1]-layer_2)**2)
correct_cnt += int(np.argmax(layer_2) == np.argmax(test_labels[i:i+1]))
sys.stdout.write(" Test-Err:" + str(error/float(len(test_images)))[0:5] +\
" Test-Acc:" + str(correct_cnt/float(len(test_images))))
print()
3、神经网络中的过拟合问题。如果你过度训练神经网络,它会变得更糟!神经网络过拟合现象的一个正式的定义是,这个神经网络学习到了数据集中的噪声,而不是仅基于真实的信号做出的决策
2 正则化
1、正则化是使模型泛化到新的数据点(而不仅是记忆训练数据)的方法的子领域。它是能够帮助神经网络学习信号并忽略噪声的一部分方法
2、正则化是用于在机器学习模型中鼓励泛化的方法的一个子集,通常通过提高模型学习训练数据的细粒度细节的难度来实现
3、dropout: 在训练过程中随机关闭神经元 (设置为0)。通过每次随机训练神经网络中的一小部分,dropout 能够让一张大网络像小网络一样进行学习——较小的神经网络不会发生过拟合
4、较小的神经网络没有太多的表达力。它们无法抓住那些可能导致过拟合的更细粒度的细节。它们只留下了捕捉那些更大、更明显、更高级特性的空间
5、神经网络总是随机初始化的。虽然大型非正则化的神经网络更可能对噪声过度拟合,但它们不太可能对相同的噪声过拟合
6、如果你训练 100 个神经网络,它们每个都倾向于捕捉不同的噪声和相似的信号。因此,当这些神经网络出错时,它们犯的错误往往不同。如果把它们整合到一起,让它们平等地投票,则它们的误差往往相互抵消,最终只展示它们学到的共同的东西:信号
7、dropout的真正含义:它是一种噪声。它使得神经网络在训练数据上的训练更加的复杂。它会减慢训练准确率上升的速度
添加 dropout 的实现
#迭代次数
for j in range(interations):
error,correct_cnt = (0.0,0)
#遍历整个test数据集
for i in range(len(images)):
#三层神经网络
layer_0 = images[i:i+1]
#relu实现非线性
layer_1 = relu(np.dot(layer_0,weight_0_1))
#dropout 增加1
dropout_mask = np.random.randint(2,size=layer_1.shape)
layer_1 *= dropout_mask*2
layer_2 = np.dot(layer_1,weight_1_2)
#错误
error += np.sum((labels[i:i+1] - layer_2)**2)
#np.argmax返回最大值位置索引
#计算预测分类正确的次数
correct_cnt += int(np.argmax(layer_2) == np.argmax(labels[i:i+1]))
layer_2_delta = (labels[i:i+1] - layer_2)
#反向传播
layer_1_delta = layer_2_delta.dot(weight_1_2.T)*relu2deriv(layer_1)
#dropout 增加2
layer_1_delta *= dropout_mask
#更该权重
weight_1_2 += alpha * layer_1.T.dot(layer_2_delta)
weight_0_1 += alpha * layer_0.T.dot(layer_1_delta)
sys.stdout.write("\r" + \
" I:" + str(j) + \
" Error:" + str(error/float(len(images)))[0:5] +\
" Correct:" + str(correct_cnt/float(len(images)))
)
增加的三行代码:
#随机关闭50%的节点(生成与layer_1一样shape的矩阵,用0和1填充)
dropout_mask = np.random.randint(2,size=layer_1.shape)
#随机关闭50%的节点后,加权和没有太大的变化
layer_1 *= dropout_mask*2
#反向传播将将对应的delta设置为0
layer_1_delta *= dropout_mask
3 批量梯度下降
之前每次用一个训练样例进行训练,并在每次训练之后更新权重。现在,我们一次用100个训练样例进行训练,在更新权重时使用所有 100 个样例的权重增量的平均值。这样训练精度的上升趋势更平稳了。这种现象是因为单个样例进行训练,在生成权重更新增量时会有非常大的噪声。对这些权重增量更新进行平均可以使学习过程更加平滑
import numpy as np
np.random.seed(1)
def relu(x):
return (x >=0)*x
def relu2deri(output):
return output > 0
batch_size = 100
alpha,interations = (0.001,300)
hidden_size,pixels_per_image,num_labels = (100,784,10)
#初始化权重
weight_0_1 = 0.2*np.random.random((pixels_per_image,hidden_size)) - 0.1
weight_1_2 = 0.2*np.random.random((hidden_size,num_labels)) - 0.1
for j in range(interations):
error,correct_cnt = (0.0,0)
for i in range(int(len(images)/batch_size)):
batch_start,batch_end = ((i*batch_size),((i+1)*batch_size))
#维度(100,784)
layer_0 = images[batch_start:batch_end]
layer_1 = relu(np.dot(layer_0,weight_0_1))
dropout_mask = np.random.randint(2,size=layer_1.shape)
layer_1 *= dropout_mask * 2
layer_2 = np.dot(layer_1,weight_1_2)
error += np.sum((labels[batch_start:batch_end] - layer_2)**2)
for k in range(batch_size):
correct_cnt += int(np.argmax(layer_2[k:k+1]) == np.argmax(labels[batch_start+k:batch_start+k+1]))
#取平均权重
layer_2_delta = (labels[batch_start:batch_end] - layer_2)/batch_size
print(layer_2_delta)
layer_1_delta = layer_2_delta.dot(weight_1_2.T)*relu2deriv(layer_1)
layer_1_delta *= dropout_mask
weight_1_2 += alpha * layer_1.T.dot(layer_2_delta)
weight_0_1 += alpha * layer_0.T.dot(layer_1_delta)
if (j%10 == 0):
test_eror,test_correct_cnt = (0.0,0)
for i in range(len(test_images)):
layer_0 = test_images[i:i+1]
layer_1 = relu(np.dot(layer_0,weight_0_1))
layer_2 = relu(np.dot(layer_1,weight_1_2))
4 参考资料
《深度学习图解》