2020研究生数学建模E题--AlexNet深度网络解法(大雾能见度估计与预测)(含代码)
一、E题赛题
2020研究生数学建模赛题链接:https://download.csdn.net/download/qq_35759272/13028941
第二题问题:
二、赛题分析
第二题的目的是让我们根据视频分析能见度大小。
大部分想到的是方法一
方法一:提取视频中的特征学习,将其与能见度数据简历关系即可。
如果仅采用单张图像,利用雾提取方法(其实就是分类方法,将雾分类出来,常用的包括决策数、支持向量机、神经网络等等),这类算法能够提取出雾的面积,但得不到厚度信息。
弊端:但是这种分析思路正如题目所说的问题:只选取少量视频、截取图像中的某些固有特征,未能有效利用图像的连续信息估计是不准的。
再分析:所以这里需要加入视频数据的连续信息,连续信息相对于单项图像而言能够反映变化的信息——雾霾浓度。
方法二:因此用非监督分类的方法进行雾浓度的划分,得出更为细致的特征信息,这样就能得出一系列图像信息。又因为视频设置是在固定位置进行的,因此整个场景中变化最大的应该是雾,将图像的变化信息进行提取,然后找到对应的能见度差距也是一种对应关系。
三、解题
3.1 数据预处理
和题目给个截图保持一致,用视频播放软件PotPlayer每15秒截图一次。雾霾浓度随时间短变化越来越高,可以分时间段,将图片雾霾浓度分为超大雾、大雾、中雾、小雾、消散五类,作为训练集和验证集的数据。
3.2 AlexNet深度网络
(1)AlexNet结构图:
简单解释:网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布。
要想知道每一层的大小怎么计算得到的,推荐看一下:卷积神经网络之AlexNet
(2)AlexNet结构细分图:
(4)各层的作用
<1>卷积层:获取图片特征值,主要获取图片的低频成分,也就是大雾浓度的变化值;
<2>全连接层:(fully connected layers,FC)在整个卷积神经网络中起到“分类器”的作用;
<3>池化层:降维、去除冗余信息、对特征进行压缩、简化网络复杂度、减小计算量、减小内存消耗;
<4>激活层:加入非线性因素的,将特征映射到高维的非线性区间进行解释,解决线性模型所不能解决的问题。
(5)Python+Tensorflow程序实现AlexNet网络
# -*- coding=UTF-8 -*-
import tensorflow as tf
# 输入数据
import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
# 定义网络超参数
learning_rate = 0.001
training_iters = 200000
batch_size = 64
display_step = 20
# 定义网络参数
n_input = 784 # 输入的维度
n_classes = 10 # 标签的维度
dropout = 0.8 # Dropout 的概率
# 占位符输入
x = tf.placeholder(tf.types.float32, [None, n_input])
y = tf.placeholder(tf.types.float32, [None, n_classes])
keep_prob = tf.placeholder(tf.types.float32)
# 卷积操作
def conv2d(name, l_input, w, b):
return tf.nn.relu(tf.nn.bias_add( \
tf.nn.conv2d(l_input, w, strides=[1, 1, 1, 1], padding='SAME'),b) \
, name=name)
# 最大下采样操作
def max_pool(name, l_input, k):
return tf.nn.max_pool(l_input, ksize=[1, k, k, 1], \
strides=[1, k, k, 1], padding='SAME', name=name)
# 归一化操作
def norm(name, l_input, lsize=4):
return tf.nn.lrn(l_input, lsize, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=name)
# 定义整个网络
def alex_net(_X, _weights, _biases, _dropout):
_X = tf.reshape(_X, shape=[-1, 28, 28, 1]) # 向量转为矩阵
# 卷积层
conv1 = conv2d('conv1', _X, _weights['wc1'], _biases['bc1'])
# 下采样层
pool1 = max_pool('pool1', conv1, k=2)
# 归一化层
norm1 = norm('norm1', pool1, lsize=4)
# Dropout
norm1 = tf.nn.dropout(norm1, _dropout)
# 卷积
conv2 = conv2d('conv2', norm1, _weights['wc2'], _biases['bc2'])
# 下采样
pool2 = max_pool('pool2', conv2, k=2)
# 归一化
norm2 = norm('norm2', pool2, lsize=4)
# Dropout
norm2 = tf.nn.dropout(norm2, _dropout)
# 卷积
conv3 = conv2d('conv3', norm2, _weights['wc3'], _biases['bc3'])
# 下采样
pool3 = max_pool('pool3', conv3, k=2)
# 归一化
norm3 = norm('norm3', pool3, lsize=4)
# Dropout
norm3 = tf.nn.dropout(norm3, _dropout)
# 全连接层,先把特征图转为向量
dense1 = tf.reshape(norm3, [-1, _weights['wd1'].get_shape().as_list()[0]])
dense1 = tf.nn.relu(tf.matmul(dense1, _weights['wd1']) + _biases['bd1'], name='fc1')
# 全连接层
dense2 = tf.nn.relu(tf.matmul(dense1, _weights['wd2']) + _biases['bd2'], name='fc2')
# Relu activation
# 网络输出层
out = tf.matmul(dense2, _weights['out']) + _biases['out']
return out
# 存储所有的网络参数
weights = {
'wc1': tf.Variable(tf.random_normal([3, 3, 1, 64])),
'wc2': tf.Variable(tf.random_normal([3, 3, 64, 128])),
'wc3': tf.Variable(tf.random_normal([3, 3, 128, 256])),
'wd1': tf.Variable(tf.random_normal([4*4*256, 1024])),
'wd2': tf.Variable(tf.random_normal([1024, 1024])),
'out': tf.Variable(tf.random_normal([1024, 10]))
}
biases = {
'bc1': tf.Variable(tf.random_normal([64])),
'bc2': tf.Variable(tf.random_normal([128])),
'bc3': tf.Variable(tf.random_normal([256])),
'bd1': tf.Variable(tf.random_normal([1024])),
'bd2': tf.Variable(tf.random_normal([1024])),
'out': tf.Variable(tf.random_normal([n_classes]))
}
# 构建模型
pred = alex_net(x, weights, biases, keep_prob)
# 定义损失函数和学习步骤
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
# 测试网络
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# 初始化所有的共享变量
init = tf.initialize_all_variables()
# 开启一个训练
with tf.Session() as sess:
sess.run(init)
step = 1
# Keep training until reach max iterations
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# 获取批数据
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys, keep_prob: dropout})
if step % display_step == 0:
# 计算精度
acc = sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})
# 计算损失值
loss = sess.run(cost, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})
print "Iter " + str(step*batch_size) + ", Minibatch Loss= " + "{:.6f}".format(loss) + ", Training Accuracy= " + "{:.5f}".format(acc)
step += 1
print "Optimization Finished!"
# 计算测试精度
print "Testing Accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images[:256], y: mnist.test.labels[:256], keep_prob: 1.})
(6)AlexNet网络解题(MATLAB)
%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272/article/details/109252165改写
%% 加载数据集
unzip('MerchData.zip')
%unzip 提取zip文件的内容
%Location = 'E:\Image_Set';%使用自己的数据集进行训练
imds = imageDatastore('MerchData', ...%若使用自己的数据集,将其改为Location
'IncludeSubfolders',true, ...
'LabelSource','foldernames');
%imageDatastore 图像数据的数据存储 /...续行
% imds = imageDatastore(location,Name,Value)
% location-要包括在数据存储中的文件或文件夹
% Name-相对组参数
% 'IncludeSubfolders'-子文件夹包含标记
% ture or false | 0 or 1 (逗号隔开)
% ————指定ture可包含每个文件夹中的所有文件和子文件夹,指定false则仅包含每个文件夹中的文件
% 'FileExtensions'-图像文件扩展名
% 'AlternateFileSystemRoots'-备用文件系统根路径
% 'LabelSource'-提供标签数据的源
% 指定为以逗号分隔的对组,如果指定了'none',则Labels属性为空。如果指定了'foldernames',将根据文件夹名称分配标签并
% 存储在Labels属性中
[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized');%随机拆分imds中的文件,前70%放入imdsTrain中,剩余30%翻入imdsValidation中
% splitEachLabel-按比例拆分ImageDatastor标签
% [imds1,imds2] = splitEachLabel(imds,p)
% 可将imds中的图像文件拆分为两个新的数据存储,imds1和imds2.新的数据存储imds1包含每个标签前百分之p个文件,imds2中包含剩余的文件
numTrainImages = numel(imdsTrain.Labels);%numel数组中的元素数目
%随机显示数据集中的图像
% idx = randperm(numTrainImages,16);
% % randperm——随机置换
% % p = randperm(n,k)返回行向量,其中包含1到n自检随机选择的k个唯一整数
% figure
% for i = 1:16
% subplot(4,4,i)
% I = readimage(imdsTrain,idx(i));
% % img = readimage(imds,i)——从数据存储imds中读取地i个图像文件并返回图像数据img
% imshow(I)
% end
%% 加载预训练网络
Alexnet_Train = alexnet;
%net.Layers %展示这个网络架构,这个网络有5个卷积层和3个全连接层
inputSize = Alexnet_Train.Layers(1).InputSize;
% 第一层是图像输入层,要求输入图像的尺寸为227*227*3 这里的3是颜色通道的数字
%% 替换最后三层
layersTransfer = Alexnet_Train.Layers(1:end-3);
% Extract all layers, exceptthe last three ,from the pretrained network
% 预处理网络的最后三层被配置为1000个类。这三层必须针对新的分类问题进行调整
numClasses = numel(categories(imdsTrain.Labels));%数据集中类的数目
layers = [
layersTransfer
fullyConnectedLayer(numClasses,'WeightLearnRateFactor',20,'BiasLearnRateFactor',20)
softmaxLayer
classificationLayer];
% Transfer the layers to the new classification task by replacing the last three layers with a fully connected layer,
%a softmax layer, and a classification output layer. Specify the options of the new fully connected layer according
%to the new data. Set the fully connected layer to have the same size as the number of classes in the new data.
%To learn faster in the new layers than in the transferred layers, increase the WeightLearnRateFactor and
%BiasLearnRateFactor values of the fully connected layer.
% 通过将最后三个图层替换为完全连接图层,softmax图层和分类输出图层,将图层转移到新的分类任务。根据新的数据指定新的完全连接层的
% 选项。将完全连接层设置为与新数据中的类数大小相同。要在新层中比传输层更快的学习,增加完全连接层的WeightLearnRateFactor 和
% BiasLearnRateFactor的值
%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272/article/details/109252165改写
%% 训练网络
%用于数据增强,增加数据量
% The network requires input images of size 227-by-227-by-3, but the images in the image datastores have different sizes.
% Use an augmented image datastore to automatically resize the training images. Specify additional augmentation operations
% to perform on the training images: randomly flip the training images along the vertical axis, and randomly translate them up
% to 30 pixels horizontally and vertically. Data augmentation helps prevent the network from overfitting and memorizing the exact details of the training images.
% 这个网络要求的尺寸是227*227*3,但是在图像存储中的图像有不同的尺寸,使用增强数据存储自动调整训练图像大小。在训练图像中指定
% 额外的增强操作:沿着垂直轴随机翻转训练图像,水平和垂直随机移动30个像素单位
pixelRange = [-30 30];
imageAugmenter = imageDataAugmenter( ...
'RandXReflection',true, ...
'RandXTranslation',pixelRange, ...
'RandYTranslation',pixelRange);
% imageDataAugmenter——配置图像数据扩充
% aug = imageDataAugmenter(Name,Value)
% RandXReflection——左右方向的随机反射,当为真(ture/1)时每个图像都以50%的概率随机反射,当为假(falsw/0)时,不会反射图像
% RandYReflection——上下方向的随机反射,当为真(ture/1)时每个图像都以50%的概率随机反射,当为假(falsw/0)时,不会反射图像
% RandRotation——随机旋转
% 'RandRotation',[num1 num2]第二个元素必须大于等于第一个元素,角度从指定间隔内的连续均匀分布中随机选取
% RandScale——均匀标度范围(应用于输入图像的均匀(各向同性)缩放范围)
% 'RandScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
% RandXScale——均匀标度范围(应用于输入图像的水平缩放范围)
% 'RandXScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
% RandYScale——均匀标度范围(应用于输入图像的垂直缩放范围)
% 'RandYScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
% RandXShear——水平剪切范围
% 'RandXShear',[num1 num2]第二个元素必须大于等于第一个元素,水平剪切角从指定间隔内的连续均匀分布中随机选取
% RandYShear——垂直剪切范围
% 'RandYShear',[num1 num2]第二个元素必须大于等于第一个元素,垂直剪切角从指定间隔内的连续均匀分布中随机选取
% RandXTranslation——水平转换范围
% 'RandXTranslation',[num1 num2]第二个元素必须大于等于第一个元素,水平平移距离从指定间隔内的连续均匀分布中随机选取
% RandYTranslation——垂直转换范围
% 'RandYTranslation',[num1 num2]第二个元素必须大于等于第一个元素,垂直平移距离从指定间隔内的连续均匀分布中随机选取
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ...
'DataAugmentation',imageAugmenter);
% augmentedImageDatastore——将批处理转化为增强图像数据
% DataAugmentation——图像数据扩充
% To automatically resize the validation images without performing further data augmentation, use an augmented image datastore
%without specifying any additional preprocessing operations.
% 自动调整验证图像大小而不进行其他数据增强。使用扩充图像数据存储而不指定其他预处理操作。
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);
% Specify the training options. For transfer learning, keep the features from the early layers of the pretrained network (the transferred layer weights).
%To slow down learning in the transferred layers, set the initial learning rate to a small value. In the previous step, you increased the learning rate factors
%for the fully connected layer to speed up learning in the new final layers. This combination of learning rate settings results in fast learning only in the new
%layers and slower learning in the other layers. When performing transfer learning, you do not need to train for as many epochs. An epoch is a full training cycle
%on the entire training data set. Specify the mini-batch size and validation data. The software validates the network every ValidationFrequency iterations during training.
% 指定训练选项,对于传输学习保留来自预训练网络早期层中的特征。为了延缓在传输层中的学习,将初始学习速率设置为一个小值。在前一步中
% 增加了完全连接层的学习因子去加速新的最终层中的学习。这种学习速率的结合会导致新层中学习速度加快,其他层中学习速度变慢。在进行转换学习时
% 你不需要这么多的时间段进行训练。一个时间段是整个训练数据集上的完全训练循环。指定最小批量和验证数据。软件在训练期间每次验证迭代都会验证网络
options = trainingOptions('sgdm', ...
'MiniBatchSize',10, ...
'MaxEpochs',6, ...
'InitialLearnRate',1e-4, ...
'ValidationData',augimdsValidation, ...
'ValidationFrequency',3, ...
'ValidationPatience',Inf, ...
'Verbose',true,...
'Plots','training-progress');
% trainingOptions——深度学习神经网络训练选项
% 语法——options = trainingOptions(solverName,Name,Value)
% solverName——训练网络检算器
% 'sgdm'——使用随机梯度下降动量(SGDM)优化器。
% 'rmsprop'——使用RMSProp优化器
% 'adam'——使用adam优化器
% 绘图和显示
% 'plots'——在网络训练时显示的图
% 'none'or'default' 在训练时期不显示图
% 'taining-progress' 显示训练过程。这个图显示了最小批量损失和准确性,验证损失和准确性,和训练过程中的额外信息。对训练过程的更多信息,查看Monitor Deep Learning Training Progress.
% Verbose——显示训练过程信息指示器
% MaxEpochs——最大训练周期数
% 用于训练的最大周期数, 'MaxEpochs',正整数
% MiniBatchSize——最小批量的大小
% 用于每个训练迭代的小批量大小 'MiniBatchSize',正整数 小批量是训练集的一个子集,用于评估损失函数的梯度并更新权重
% ValidationData——训练期间用于验证的数据
% ValidationFrequency——网络验证频率
% 以迭代次数表示网络验证频率 'ValidationFrequency',正整数
% ValidationPatience——停止验证的patience
% 'ValidationPatience',inf or 正整数 若使用默认inf训练将在最大的epoch数后停止
% InitialLearnRate——初始学习率
% 'InitialLearnRate',正数 'sgdm'解算器的默认值为0.01,'rmsprop' 'adam' 解算器的默认值为0.001.
% 如果学习率太低,那么培训需要很长时间,如果学习率太高那么训练可能达不到最佳结果或出现分歧
Train = trainNetwork(augimdsTrain,layers,options);
% trainNetwork——训练神经网络进行深度学习、
%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272改写
%% 验证训练好的模型
[YPred,scores] = classify(Train,augimdsValidation);
% classify——使用经过训练的神经网络对数据进行分类
idx = randperm(numel(imdsValidation.Files),6);
% randperm——随机置换
% p = randperm (n,k) 返回行向量,其中包含1到n之间随机选择k个唯一整数
%随机显示使用训练好的模型进行分类的图片及其标签和概率
figure
for i = 1:6
subplot(2,3,i)
I = readimage(imdsValidation,idx(i));
imshow(I)
label = YPred(idx(i));
title(string(label) + "," + num2str(100*max(scores(idx(i),:)),3) + "%");
end
YValidation = imdsValidation.Labels;
accuracy = mean(YPred == YValidation);
disp(['accuracy:',num2str(accuracy)]); % 输出预测精度结果
%% 保存训练好的模型
save Alexnet_01 Train;
完整MATLAB程序和采集数据以及AlexNet工具包最终以链接形式上传,见评论区!!!
3.3 运行结果
(1)训练结果图:
损失函数loss呈现递减趋势,最后接近于0;验证准确率呈现上升趋势,最后接近100%。
<1>训练周期:
轮次:第6轮
历时:28秒
迭代:30次(每轮的迭代次数:5)
<2>验证:
频率:3次迭代
<3> 其他信息:
硬件资源:单GPU
学习率调度:常数
学习率:0.0001
(2)分类结果图:
与测试集的分类完全符合,每一分类准确率都接近100%,效果很好,其实并不意外,因为数据集还没有过万,很容易达到高准确率。
注:由于图片过大,截图不清楚,我尽力了,你们自己运行程序放到Word里面,会是清晰的图片的,单独截图看中间的两张图片是这样:
“中雾”,“大雾”是对图片预测的结果,“100%”、“91.9%”代表预测准确率。
四 模型评估/AlexNet网络优点
4.1 使用Relu作为激活函数
AlexNet成功使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid函数(ReLU之前已经提出,在AlexNet才大放异彩),成功解决了Sigmoid在网络较深时的梯度弥散(消失)现象。
4.2 局部相应归一化(Local corresponding normalization)
ReLU具有的特性是,它不需要通过输入归一化来防止饱和。如果至少一些训练样本对ReLU产生了正输入,那么那个神经元上将发生学习。而局部响应归一化有助于泛化。
4.3 Dropout
训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。在AlexNet中主要是最后的几个全连接层使用了Dropout。
4.4 层叠池化
在LeNet中池化是不重叠的,即池化的窗口的大小和步长是相等的,如下
在AlexNet中使用的池化(Pooling)却是可重叠的,也就是说,在池化的时候,每次移动的步长小于池化的窗口长度。AlexNet池化的大小为3×3的正方形,每次池化移动步长为2,这样就会出现重叠。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。与非重叠方案s=2,z=2相比,输出的维度是相等的,并且能在一定程度上抑制过拟合。
五 上传文件使用说明
评论区(全部文件)上传的文件如下:
(1)首先安装文件alexnet.mlpkginstall,安装文件如果失效,可以去官网下载。alexnet.mlpkginstall安装文件双击是运行不了的,要放到MATLAB软件里面,在软件里面双击打开:
安装完成即可
(2)MerchData.zip是比赛的视频截图分类文件,不需要解压,博主已经在程序里面写了解压程序。
截图文件也可以单独在https://download.csdn.net/download/qq_35759272/13070685链接下载。
(3)运行AlexNet_test.m程序即可,结果类似上面图片。
附:
第三题解题——基于辅助车道线的大雾能见度估计模型
(1)对于机场视频可以采用——基于暗通道优先算法的能见度估计模型
文章链接:2020华为杯E题–基于暗通道优先算法的能见度估计模型(附代码)。
(2)对于高速公路视频截图数据采用——基于辅助车道线的大雾能见度估计与预测模型
文章链接:2020华为杯E题–基于辅助车道线的大雾能见度估计与预测(附代码)
第四题解题——基于灰色预测的大雾能见度预测模型
解题文章链接:2020华为杯E题——基于灰色预测的大雾能见度预测模型(附代码)
!!!!!第一次参加数学建模的朋友,推荐浏览博客文章:如何在数学建模比赛中稳拿奖——个人100%获奖经历分享