这个例子展示了如何使用神经图像评估(NIMA)卷积神经网络(CNN)来分析图像的美学质量。
图像质量度量提供了图像质量的客观度量。一个有效的度量标准提供定量的分数,与人类观察者对质量的主观感知密切相关。质量度量使图像处理算法的比较成为可能。
尼玛[1]是一种不依赖原始参考图像预测图像质量的无参考技术,而原始参考图像通常是不可用的。NIMA使用CNN来预测每个图像质量分数的分布。
使用helper函数下载预训练的NIMA神经网络downloadTrainedNIMANet
.helper函数作为支持文件附加到示例中。金宝app该模型预测了每个图像在[1,10]范围内的质量分数分布,其中1和10分别是分数的最低和最高可能值。分数越高,图像质量越好。
imageDir = fullfile (tempdir,“LIVEInTheWild”);如果~存在(imageDir“dir”mkdir (imageDir);结束trainedNIMA_url =“https://ssd.mathworks.com/金宝appsupportfiles/image/data/trainedNIMA.zip”;downloadTrainedNIMANet (trainedNIMA_url imageDir);负载(fullfile (imageDir“trainedNIMA.mat”));
您可以通过比较高质量图像和低质量图像的预测分数来评估NIMA模型的有效性。
在工作区中读取高质量的图像。
imOriginal = imread (“kobi.png”);
通过应用高斯模糊降低图像的美学质量。显示原始图像和模糊图像在蒙太奇。主观上,模糊图像的审美质量比原始图像的质量差。
imBlur = imgaussfilt (imOriginal 5);蒙太奇({imOriginal, imBlur})
预测两幅图像的NIMA质量分数分布predictNIMAScore
helper函数。这个函数作为支持文件附加到示例中。金宝app
的predictNIMAScore
函数返回图像的NIMA评分分布的平均值和标准偏差。预测的平均分数是对图像质量的衡量。分数的标准偏差可以被认为是预测平均分数的置信水平的一种度量。
[meanOriginal, stdOriginal] = predictNIMAScore (dlnet imOriginal);[meanBlur, stdBlur] = predictNIMAScore (dlnet imBlur);
将图像与NIMA模型预测的分数分布的平均值和标准差一起显示。的
NIMA模型正确地预测了与主观视觉评估一致的这些图像的分数。
图t = tiledlayout(1,2);displayImageAndScoresForNIMA (t, imOriginal meanOriginal stdOriginal,的“原始图像”) displayImageAndScoresForNIMA (t imBlur meanBlur stdBlur,“模糊图像”)
本示例的其余部分将展示如何训练和评估NIMA模型。
本例使用LIVE In the Wild数据集[2],这是一个公共领域的主观图像质量挑战数据库。该数据集包含了1162张由移动设备拍摄的照片,另外还有7张图片提供给训练人类得分者。每幅图片由175个人在[1100]的范围内平均打分。数据集提供了每个图像的主观评分的平均值和标准偏差。
请按照中所列的说明下载数据集LIVE In the Wild Image Quality Challenge数据库.将数据提取到指定的目录imageDir
变量。当提取成功时,imageDir
包含两个目录:数据
和图片
.
获取图像的文件路径。
imageData =负载(fullfile (imageDir“数据”,“AllImages_release.mat”));imageData = imageData.AllImages_release;nImg =长度(imageData);imageList (1:7) = fullfile (imageDir“图片”,“trainingImages”imageData (1:7));imageList (8: nImg) = fullfile (imageDir,“图片”imageData(8:结束));
创建一个管理映像数据的映像数据存储。
imd = imageDatastore (imageList);
加载图像对应的均值和标准差数据。
meanData =负载(fullfile (imageDir“数据”,“AllMOS_release.mat”));meanData = meanData.AllMOS_release;stdData =负载(fullfile (imageDir“数据”,“AllStdDev_release.mat”));stdData = stdData.AllStdDev_release;
可选地,显示一些样本图像从数据集与相应的平均值和标准偏差值。
图t = tiledlayout(1,3);idx1 = 785;idx1 displayImageAndScoresForNIMA (t, readimage (imd),...meanData (idx1) stdData (idx1),“图像”+imageData(idx1) idx2 = 203;idx2 displayImageAndScoresForNIMA (t, readimage (imd),...meanData (idx2) stdData (idx2),“图像”+imageData(idx2) idx3 = 0;idx3 displayImageAndScoresForNIMA (t, readimage (imd),...meanData (idx3) stdData (idx3),“图像”+ imageData (idx3))
对图像进行预处理,将其调整为256 × 256像素。
rescaleSize = [256 256];imd =变换(imd, @ (x) imresize (x, rescaleSize));
NIMA模型需要人类得分的分布,但是LIVE数据集只提供分布的平均值和标准偏差。控件来近似LIVE数据集中每个图像的底层分布createNIMAScoreDistribution
helper函数。这个函数作为支持文件附加到示例中。金宝app
的createNIMAScoreDistribution
将分数重新标度到范围[1,10],然后由平均值和标准差值生成分数的最大熵分布。
newMaxScore = 10;概率= createNIMAScoreDistribution (meanData stdData);cumProb = cumsum(问题2);
创建一个arrayDatastore
它管理分数分布。
probDS = arrayDatastore (cumProb ',“IterationDimension”2);
合并包含图像数据和分数分布数据的数据存储。
probDS dsCombined =结合(imd);
预览从组合数据存储读取的输出。
sampleRead =预览(dsCombined)
sampleRead =1×2单元阵列{256×256×3 uint8} {10×1 double}
图tiledlayout(1,2) nexttile imshow(sampleRead{1}) title(“来自数据集的样本图像”) nexttile plot(sampleRead{2}) title(“累积分数分配”)
将数据划分为训练集、验证集和测试集。分配70%的数据用于培训,15%用于验证,其余的用于测试。
numTrain = floor(0.70 * nImg);numVal = floor(0.15 * nImg);Idx = randperm (nImg);idxTrain = Idx (1: numTrain);idxVal = Idx (numTrain + 1: numTrain + numVal);idxTest = Idx (numTrain + numVal + 1: nImg);dsTrain =子集(dsCombined idxTrain);dsVal =子集(dsCombined idxVal);dst =子集(dsCombined idxTest);
增强训练数据使用augmentImageTest
helper函数。这个函数作为支持文件附加到示例中。金宝app的augmentDataForNIMA
函数对每个训练图像执行这些增强操作:
将图像裁剪为224 × 244像素,以减少过拟合。
以50%的概率水平翻转图像。
inputSize = [224 224];dsTrain =变换(dsTrain @ (x) augmentDataForNIMA (x, inputSize));
网络的输入层对训练图像进行z-score归一化。计算用于z分数归一化的训练图像的平均值和标准偏差。
meanImage = 0 ([inputSize 3]);meanImageSq = 0 ([inputSize 3]);而hasdata(dsTrain) dat = read(dsTrain);img =双(dat {1});meanImage = meanImage + img;meanImageSq + img.^2;结束meanImage = meanImage / numTrain;meanImageSq = meanImageSq / numTrain;varImage = meanImageSq - meanImage.^2;stdImage =√varImage);
将数据存储重置为初始状态。
重置(dsTrain);
创建一个minibatchqueue
对象,该对象在自定义训练循环中管理观察的小批处理。的minibatchqueue
对象还将数据强制转换为dlarray
对象,在深度学习应用程序中实现自动区分。
指定迷你批处理数据提取格式为'SSCB”
(spatial, spatial, channel, batch)。设置“DispatchInBackground”
返回的布尔值的名称-值参数canUseGPU
.如果支持的金宝appGPU可用来进行计算,则minibatchqueue
对象在训练期间在后台的并行池中预处理小批。
miniBatchSize = 128;mbqTrain = minibatchqueue (dsTrain,“MiniBatchSize”miniBatchSize,...“PartialMiniBatch”,“丢弃”,“MiniBatchFormat”, {“SSCB”,”},...“DispatchInBackground”, canUseGPU);mbqVal = minibatchqueue (dsVal,“MiniBatchSize”miniBatchSize,...“MiniBatchFormat”, {“SSCB”,”},“DispatchInBackground”, canUseGPU);
本例从一个MobileNet-v2开始[3]CNN接受ImageNet培训[4].该示例修改了网络,将MobileNet-v2网络的最后一层替换为具有10个神经元的完全连接层,每个神经元代表从1到10的离散分数。该网络预测每幅图像得分的概率。本示例使用softmax激活层对全连接层的输出进行归一化。
的mobilenetv2
函数返回一个预先训练的MobileNet-v2网络。该功能需要深度学习工具箱™模型MobileNet-v2网络金宝app支持包。如果没有安装此支金宝app持包,则该函数将提供下载链接。
网= mobilenetv2;
将网络转换成layerGraph
对象。
lgraph = layerGraph(净);
该网络的图像输入大小为224 × 224像素。将输入层替换为图像输入层,该图像输入层使用训练图像的均值和标准偏差对图像数据执行z-score归一化。
inLayer = imageInputLayer([inputSize 3],“名字”,“输入”,“归一化”,“zscore”,“的意思是”meanImage,“StandardDeviation”, stdImage);lgraph = replaceLayer (lgraph,“input_1”、镶嵌者);
将原来的最终分类层替换为10个神经元完全连接的层。添加一个softmax层来规范输出。设置全连接层学习速率为CNN基线层学习速率的10倍。申请75%的辍学率
lgraph = removeLayers (lgraph, {“ClassificationLayer_Logits”,“Logits_softmax”,分对数的});newFinalLayers = [dropoutLayer(0.75,“名字”,“下降”) fullyConnectedLayer (newMaxScore“名字”,“俱乐部”,“WeightLearnRateFactor”10“BiasLearnRateFactor”(10) softmaxLayer“名字”,“概率”));lgraph = addLayers (lgraph newFinalLayers);lgraph = connectLayers (lgraph,“global_average_pooling2d_1”,“下降”);dlnet = dlnetwork (lgraph);
可视化网络使用深层网络设计师应用程序。
deepNetworkDesigner (lgraph)
的modelGradients
辅助函数计算训练网络的每次迭代的梯度和损失。函数定义在金宝app支持功能这个例子的一部分。
NIMA网络的目标是使地面真实值与预测分数分布之间的移动距离(EMD)最小。EMD损失在惩罚错误分类时考虑了类之间的距离。因此,EMD损耗比典型的softmax交叉熵损耗在分类任务中的性能更好[5].这个例子计算EMD损失使用earthMoverDistance
函数中定义的金宝app支持功能这个例子的一部分。
对于EMD损失函数,使用r规范距离r= 2。当你使用梯度下降时,这个距离可以很容易地进行优化。
指定SGDM优化选项。为150个时代训练网络。
numEpochs = 150;动量= 0.9;initialLearnRate = 3 e - 3;衰变= 0.95;
默认情况下,示例加载的是NIMA网络的预训练版本。预先训练过的网络使您无需等待训练完成就可以运行整个示例。
要训练网络,设置doTraining
变量为真正的
.在自定义训练循环中训练模型。每一次迭代:
属性读取当前小批处理的数据下一个
函数。
方法评估模型梯度dlfeval
函数和modelGradients
helper函数。
使用sgdmupdate
函数。
在可用的GPU上进行训练。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU。有关更多信息,请参见GPU支金宝app持情况(并行计算工具箱).
doTraining = false;如果doTraining迭代= 0;速度= [];开始=抽搐;[hFig, lineLossTrain lineLossVal] = initializeTrainingPlotNIMA;为纪元= 1:numEpochs shuffle (mbqTrain);learnRate = initialLearnRate /(1 +衰变*地板(时代/ 10));而hasdata(mbqTrain) iteration = iteration + 1;[dlX, cdfY] =下一个(mbqTrain);(研究生,亏损)= dlfeval (@modelGradients、dlnet dlX, cdfY);[dlnet,速度]= sgdmupdate (dlnet、毕业生、速度、learnRate动量);updateTrainingPlotNIMA (lineLossTrain损失、时代、迭代,开始)结束%在绘图中添加验证数据[lossVal, ~ ~] = modelPredictions (dlnet mbqVal);时代,updateTrainingPlotNIMA (lineLossVal lossVal迭代,开始)结束%保存训练过的网络modelDateTime =字符串(datetime (“现在”,“格式”,“yyyy-MM-dd-HH-mm-ss”));保存(strcat (“trainedNIMA——”modelDateTime,“时代——”num2str (numEpochs),“.mat”),“dlnet”);其他的负载(fullfile (imageDir“trainedNIMA.mat”));结束
使用三个指标评估模型在测试数据集上的性能:EMD、二值分类精度和相关系数。NIMA网络在测试数据集上的性能与Talebi和Milanfar报告的参考NIMA模型的性能一致[1].
创建一个minibatchqueue
对象,该对象管理测试数据的小批处理。
mbqTest = minibatchqueue (dst,“MiniBatchSize”miniBatchSize,“MiniBatchFormat”, {“SSCB”,”});
方法计算小批量试验数据的预测概率和地面真实累积概率modelPredictions
函数。函数定义在金宝app支持功能这个例子的一部分。
[YPredTest, ~, cdfYTest] = modelPredictions (dlnet mbqTest);
计算地面真实值和预测分布的平均值和标准差值。
'; '; ';stdPred = sqrt(extractdata(YPredTest)'*(((1:10).^2)' - meanPred.^2);origCdf = extractdata (cdfYTest);origPdf = [origCdf (1:);diff (origCdf)];meanorigin = origPdf' * (1:10)';stdOrig =√origPdf‘*((1:10)^ 2)”——meanOrig。^ 2);
计算地面真实值和预测得分分布的EMD。要进行预测,请使用r规范距离r= 1。EMD值表明预测和地面真值分布的贴近度。
emdt = earthMoverDistance (YPredTest cdfYTest 1)
EMDTest = 1×1 single gpuArray dlarray 0.1158
对于二值分类精度,将分布转换为两种分类:高质量和低质量。将平均分数大于阈值的图像分类为高质量图像。
qualityThreshold = 5;binaryPred = meanPred >质量阈值;binaryorigin = meanorigin >质量阈值;
计算二值分类精度。
binaryAccuracy = 100 * sum(binaryPred== binaryorigin)/length(binaryPred)
binaryAccuracy = 84.6591
相关值越大,表明地面真实值与预测分数之间存在较大的正相关关系。计算平均分数的线性相关系数(LCC)和斯皮尔曼等级相关系数(SRCC)。
meanLCC = corr (meanOrig meanPred)
meanLCC = gpuArray single 0.7265
meanSRCC = corr (meanOrig meanPred,“类型”,“枪兵”)
meanSRCC = gpuArray single 0.6451
的modelGradients
函数接受输入adlnetwork
对象dlnet
以及一小批输入数据dlX
对应的目标累积概率cdfY
.函数返回损失相对于中可学习参数的梯度dlnet
以及损失。要自动计算梯度,请使用dlgradient
函数。
函数[gradient,loss] = modelGradients(dlnet,dlX,cdfY)损失= earthMoverDistance (dlYPred cdfY 2);梯度= dlgradient(损失、dlnet.Learnables);结束
的earthMoverDistance
函数计算特定区域的地面真实值与预测分布之间的EMDr规范值。的earthMoverDistance
使用computeCDF
辅助函数来计算预测分布的累积概率。
函数损失= earthMoverDistance(YPred,cdfY,r) N = size(cdfY,1);cdfYPred = computeCDF (YPred);cdfDiff = (1/N) * (abs(cdfY - cdfYPred).^r);lossArray = (cdfDiff, 1)总和。^ (1 / r);损失=意味着(lossArray);结束函数cdfY = computeCDF (Y)给定一个概率质量函数Y,计算累积概率[N, miniBatchSize] =大小(Y);L = repmat (triu ((N)), 1, 1, miniBatchSize);L3d = permute(L,[1 3 2]);刺激= y * L3d;prodSum =总和(prod 1);cdfY =重塑(prodSum(:)“miniBatchSize, N)”;结束
的modelPredictions
函数计算估计的概率,损失,和地面真相累积概率的小批数据。
函数[dlYPred,loss, cdfyorigin] = modelPredictions(dlnet,mbq) reset(mbq);损失= 0;numObservations = 0;dlYPred = [];cdfYOrig = [];而hasdata(mbq) [dlX,cdfY] = next(mbq);miniBatchSize =大小(dlX 4);海底=预测(dlnet dlX);loss = loss + earthMoverDistance(dlY,cdfY,2)*miniBatchSize;dlYPred = [dlYPred d];cdfyorigin = [cdfyorigin cdfY];nummobservations = nummobservations + miniBatchSize;结束loss = loss / numobations;结束
Talebi, Hossein和Peyman Milanfar。NIMA:神经图像评估《图像处理技术》,第27期。8(2018年8月):3998-4011。https://doi.org/10.1109/TIP.2018.2831899.
[2] LIVE:图像和视频工程实验室。"LIVE In the Wild图像质量挑战数据库"https://live.ece.utexas.edu/research/ChallengeDB/index.html.
[3] Sandler, Mark, Andrew Howard, Menglong Zhu, Andrey Zhmoginov, and Liang-Chieh Chen。MobileNetV2:反向残差和线性瓶颈2018 IEEE/CVF计算机视觉与模式识别大会,4510-20。盐湖城,UT: IEEE, 2018。https://doi.org/10.1109/CVPR.2018.00474.
[4] ImageNet。https://www.image-net.org.
侯乐,余晨平,迪米特里斯·萨马拉斯。“用于训练深度神经网络的基于距离的平方挖土机损失”。预印本,2016年11月30日提交。https://arxiv.org/abs/1611.05916.
mobilenetv2
|变换
|layerGraph
|dlnetwork
|minibatchqueue
|预测
|dlfeval
|sgdmupdate