深度神经网络
Contents
[TOC]
深度神经网络介绍(Deep Neural Networks,DNN)
FNN模型结构
DNN可以理解为有很多隐藏层的神经网络,又被称为深度前馈网络(DFN),多层感知机(Multi-layer Perceptron,MLP)
DNN模型按照层的位置不同,可以氛围3中神经网络层:输入层、隐藏层和输出层。层与层之间是全连接的。一个线性函数搭配一个激活函数
DNN前向传播
利用若干个权重系数矩阵W、偏置向量b和输入向量X进行一系列线性运算和激活运算。从输入层开始,一层层向后运算,一直运算到输出层,得到输出结果
DNN反向传播
深度学习的目标即找到网络各层中最优的线性系数矩阵W和偏置向量b,让所有输入样本通过网络运算后,预测的输出样本尽可能等于或接近实际的输出样本
需要定义一个损失函数来衡量预测输出值和实际输出值之间的差异,对损失函数进行优化,通过不断迭代对线性系数矩阵和偏置向量b进行更新,让损失函数最小化,不断逼近最小值或满足我们预期的需求。在DNN模型中,损失函数优化极值求解一般是通过梯度下降法来迭代完成的。
DNN在TensorFlow2.0中的一般流程
- 数据加载、归一化和预处理
- 搭建DNN模型
- 定义损失函数和准确率函数
- 模型训练
- 模型预测推理、性能评估
DNN中的过拟合
随着网络层数增多,模型在训练过程中会出现梯度爆炸、梯度消失、欠拟合和过拟合
过拟合一般是指模型的特征维度过多,参数过多,模型过于复杂,参数数量大大高于训练数据数量,训练出的网络层过于完美得适配训练集,但对新的,未知的数据集的预测能力很差
过拟合的解决办法:
– 获取更多数据:从数据源获得更多的数据,或者进行数据增强
– 数据预处理:清洗数据,减少特征维度,实现类别平衡
– 正则化:限制权重过大,减少网络层数,避免模型过于复杂
– 多种模型结合:集成学习的思想
– Dropout:随机从网络中去掉一部分隐藏神经元
– 终止:限制训练时间和次数,及早停止
int num_classes = 10;//MNIST的字符类别为0-9,总共10类
int num_features = 784;//输入图像的特征尺寸,即28*28=784像素
//超参数
float learning_rate = 0.001f;//学习率
int training_steps = 1000;//训练轮数
int batch_size = 256;//批次大小
int display_step = 100;//训练数据显示周期
//神经网络参数
int n_hidden_1 = 128;//隐藏层1的神经元数量
int n_hidden_2 = 256;//隐藏层2的神经元数量
IDatasetV2 train_data;//MNIST数据集
NDArray x_test, y_test, x_train, y_train;//数据集拆分为训练集和测试集
IVariableV1 h1, h2, wout, b1, b2, bout;//带训练的权重变量
float accuracy_test = 0f;//测试集准确率
((x_train, y_train), (x_test, y_test)) = KerasApi.keras.datasets.mnist.load_data(); //下载或加载本地MNIST
(x_train, x_test) = (x_train.reshape((-1, num_features)), x_test.reshape((-1, num_features)));//展平输入数据
(x_train, x_test) = (x_train / 255f, x_test / 255f);//归一化
train_data = tf.data.Dataset.from_tensor_slices(x_train, y_train);//转换为Dataset格式
train_data = train_data.repeat().shuffle(5000).batch(batch_size).prefetch(1).take(training_steps);//数据预处理
//随机初始化网络权重变量并打包成数组,方便后续在梯度求导时作为参数
var random_normal = tf.initializers.random_normal_initializer();
h1 = tf.Variable(random_normal.Apply(new InitializerArgs((num_features, n_hidden_1))));
h2 = tf.Variable(random_normal.Apply(new InitializerArgs((n_hidden_1, n_hidden_2))));
wout = tf.Variable(random_normal.Apply(new InitializerArgs((n_hidden_2, num_classes))));
b1 = tf.Variable(tf.zeros(n_hidden_1));
b2 = tf.Variable(tf.zeros(n_hidden_2));
bout = tf.Variable(tf.zeros(num_classes));
var trainable_variables = new IVariableV1[] { h1, h2, wout, b1, b2, bout };
//采用随机梯度下降优化器
var optimizer = KerasApi.keras.optimizers.SGD(learning_rate);
//搭建网络模型
Tensor neural_net(Tensor x)
{
//隐藏层1采用128个神经元
var layer_1 = tf.add(tf.matmul(x, h1.AsTensor()), b1.AsTensor());
//使用Sigmoid激活函数,增加层输出的非线性特征
layer_1 = tf.nn.sigmoid(layer_1);
//隐藏层2采用256个神经元
var layer_2 = tf.add(tf.matmul(layer_1, h2.AsTensor()), b2.AsTensor());
//使用Sigmoid激活函数,增加层输出的非线性特征
layer_2 = tf.nn.sigmoid(layer_2);
//输出层的神经元数量和标签类型数量相同
var out_layer = tf.matmul(layer_2, wout.AsTensor()) + bout.AsTensor();
//使用Softmax函数将输出类别转换为各类别的概率分布
return tf.nn.softmax(out_layer);
}
//交叉熵损失函数
Tensor cross_entropy(Tensor y_pred,Tensor y_true)
{
//将标签转换为One-Hot格式
y_true = tf.one_hot(y_true, depth: num_classes);
//保持预测值在10^-9和1.0之间,防止下溢出现ln(0)报错
y_pred = tf.clip_by_value(y_pred, 1e-9f, 1.0f);
//计算交叉熵损失
return tf.reduce_mean(-tf.reduce_sum(y_true * tf.math.log(y_pred)));
}
//运行优化器
void run_optimization(OptimizerV2 optimizer,Tensor x,Tensor y, IVariableV1[] trainable_variables)
{
using var g = tf.GradientTape();
var pred = neural_net(x);
var loss = cross_entropy(pred, y);
//计算梯度
var gradients = g.gradient(loss, trainable_variables);
//更新模型权重和偏置项
var a = zip(gradients, trainable_variables.Select(x => x as ResourceVariable));
optimizer.apply_gradients(zip(gradients, trainable_variables.Select(x => x as ResourceVariable)));
}
//模型预测准确率
Tensor accuracy(Tensor y_pred,Tensor y_true)
{
//使用Argmax函数提取预测标签最大的标签,和实际值比较,计算模型预测的准确率
var correct_prediction = tf.equal(tf.arg_max(y_pred, 1), tf.cast(y_true, tf.int64));
return tf.reduce_mean(tf.cast(correct_prediction, tf.float32), axis: -1);
}
//训练模型
foreach (var (step,(batch_x,batch_y)) in enumerate(train_data,1))
{
//运行优化器,进行模型权重和偏置项的更新
run_optimization(optimizer, batch_x, batch_y, trainable_variables);
if(step%display_step==0)
{
var pred = neural_net(batch_x);
var loss = cross_entropy(pred, batch_y);
var acc = accuracy(pred, batch_y);
print("step:{step},lossL{(float)loss},accuracy:{(float)acc}");
}
}
//在验证机上测试模型
{
var pred = neural_net(x_test);
accuracy_test = (float)accuracy(pred, y_test);
print("Test Accuracy:{accuracy_test}");
}
}
Filed under: TensorFlow,人工智能,编程 - @ 2023年4月16日 下午9:22