В этом примере показано, как анализировать эстетическое качество изображений с помощью сверточной нейронной сети (CNN) Neural Image Assessment (NIMA).
Показатели качества изображения обеспечивают объективную меру качества изображения. Эффективная метрика обеспечивает количественные оценки, которые хорошо коррелируют с субъективным восприятием качества наблюдателем-человеком. Показатели качества позволяют сравнивать алгоритмы обработки изображений.
NIMA [1] - это метод без ссылок, который предсказывает качество изображения без использования неточного опорного изображения, которое часто недоступно. NIMA использует CNN для прогнозирования распределения показателей качества для каждого изображения.
Загрузите предварительно обученную нейронную сеть NIMA с помощью функции помощника downloadTrainedNIMANet. Вспомогательная функция прикрепляется к примеру как вспомогательный файл. Эта модель предсказывает распределение показателей качества для каждого изображения в диапазоне [1, 10], где 1 и 10 являются самыми низкими и самыми высокими возможными значениями для оценки, соответственно. Высокий балл указывает на хорошее качество изображения.
imageDir = fullfile(tempdir,"LIVEInTheWild"); if ~exist(imageDir,'dir') mkdir(imageDir); end trainedNIMA_url = 'https://ssd.mathworks.com/supportfiles/image/data/trainedNIMA.zip'; downloadTrainedNIMANet(trainedNIMA_url,imageDir); load(fullfile(imageDir,'trainedNIMA.mat'));
Можно оценить эффективность модели NIMA, сравнив прогнозируемые оценки для высококачественного и более низкого качества изображения.
Чтение высококачественного изображения в рабочую область.
imOriginal = imread('kobi.png'); Уменьшите эстетическое качество изображения, применив размытие по Гауссу. Отображение исходного изображения и размытого изображения при монтаже. Субъективно эстетическое качество размытого изображения хуже, чем качество оригинального изображения.
imBlur = imgaussfilt(imOriginal,5);
montage({imOriginal,imBlur})
Прогнозирование распределения показателей качества NIMA для двух изображений с использованием predictNIMAScore функция помощника. Эта функция присоединена к примеру как вспомогательный файл.
predictNIMAScore функция возвращает среднее и стандартное отклонение распределения баллов NIMA для изображения. Прогнозируемый средний балл является мерой качества изображения. Стандартное отклонение баллов можно считать мерой доверительного уровня прогнозируемого среднего балла.
[meanOriginal,stdOriginal] = predictNIMAScore(dlnet,imOriginal); [meanBlur,stdBlur] = predictNIMAScore(dlnet,imBlur);
Отображение изображений вместе со средним и стандартным отклонением распределения баллов, прогнозируемым моделью NIMA. The Модель NIMA правильно предсказывает оценки для этих изображений, которые согласуются с субъективной визуальной оценкой.
figure t = tiledlayout(1,2); displayImageAndScoresForNIMA(t,imOriginal,meanOriginal,stdOriginal,"Original Image") displayImageAndScoresForNIMA(t,imBlur,meanBlur,stdBlur,"Blurred Image")

В остальном примере показано, как обучать и оценивать модель NIMA.
В этом примере используется набор данных LIVE In the Wild [2], который представляет собой общедоступную базу данных субъективных запросов качества изображения. Набор данных содержит 1162 фотографии, снятые мобильными устройствами, с 7 дополнительными изображениями, предоставленными для обучения человеческих бомбардиров. Каждое изображение оценивается в среднем 175 особями по шкале [1, 100]. Набор данных обеспечивает среднее и стандартное отклонение субъективных оценок для каждого изображения.
Загрузите набор данных, следуя инструкциям, приведенным в разделе LIVE In the Wild Image Quality Challenge Database. Извлеките данные в каталог, указанный imageDir переменная. При успешном извлечении imageDir содержит два каталога: Data и Images.
Получите пути к изображениям.
imageData = load(fullfile(imageDir,'Data','AllImages_release.mat')); imageData = imageData.AllImages_release; nImg = length(imageData); imageList(1:7) = fullfile(imageDir,'Images','trainingImages',imageData(1:7)); imageList(8:nImg) = fullfile(imageDir,'Images',imageData(8:end));
Создайте хранилище данных изображения, которое управляет данными изображения.
imds = imageDatastore(imageList);
Загрузите данные среднего и стандартного отклонения, соответствующие изображениям.
meanData = load(fullfile(imageDir,'Data','AllMOS_release.mat')); meanData = meanData.AllMOS_release; stdData = load(fullfile(imageDir,'Data','AllStdDev_release.mat')); stdData = stdData.AllStdDev_release;
Дополнительно можно отобразить несколько образцов изображений из набора данных с соответствующими значениями среднего и стандартного отклонения.
figure t = tiledlayout(1,3); idx1 = 785; displayImageAndScoresForNIMA(t,readimage(imds,idx1), ... meanData(idx1),stdData(idx1),"Image "+imageData(idx1)) idx2 = 203; displayImageAndScoresForNIMA(t,readimage(imds,idx2), ... meanData(idx2),stdData(idx2),"Image "+imageData(idx2)) idx3 = 777; displayImageAndScoresForNIMA(t,readimage(imds,idx3), ... meanData(idx3),stdData(idx3),"Image "+imageData(idx3))

Выполните предварительную обработку изображений, изменив их размер до 256 на 256 пикселей.
rescaleSize = [256 256]; imds = transform(imds,@(x)imresize(x,rescaleSize));
Модель NIMA требует распределения человеческих баллов, но набор данных LIVE предоставляет только среднее и стандартное отклонение распределения. Аппроксимировать базовое распределение для каждого изображения в наборе данных LIVE с помощью createNIMAScoreDistribution функция помощника. Эта функция присоединена к примеру как вспомогательный файл.
createNIMAScoreDistribution масштабирует баллы до диапазона [1, 10], затем генерирует распределение максимальной энтропии баллов из значений среднего и стандартного отклонения.
newMaxScore = 10; prob = createNIMAScoreDistribution(meanData,stdData); cumProb = cumsum(prob,2);
Создание arrayDatastore который управляет распределением баллов.
probDS = arrayDatastore(cumProb','IterationDimension',2); Объединение хранилищ данных, содержащих данные изображения и данные распределения баллов.
dsCombined = combine(imds,probDS);
Предварительный просмотр результатов чтения из объединенного хранилища данных.
sampleRead = preview(dsCombined)
sampleRead=1×2 cell array
{256×256×3 uint8} {10×1 double}
figure
tiledlayout(1,2)
nexttile
imshow(sampleRead{1})
title("Sample Image from Data Set")
nexttile
plot(sampleRead{2})
title("Cumulative Score Distribution")
Разбейте данные на обучающие, проверочные и тестовые наборы. Распределите 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 = subset(dsCombined,idxTrain); dsVal = subset(dsCombined,idxVal); dsTest = subset(dsCombined,idxTest);
Увеличение данных обучения с помощью augmentImageTest функция помощника. Эта функция присоединена к примеру как вспомогательный файл. augmentDataForNIMA функция выполняет следующие операции по увеличению на каждом обучающем изображении:
Обрезайте изображение до 224 на 244 пикселов, чтобы уменьшить переоборудование.
Переверните изображение по горизонтали с вероятностью 50%.
inputSize = [224 224]; dsTrain = transform(dsTrain,@(x)augmentDataForNIMA(x,inputSize));
Входной уровень сети выполняет нормализацию по шкале z обучающих изображений. Рассчитайте среднее и стандартное отклонение обучающих изображений для использования в нормализации z-показателя.
meanImage = zeros([inputSize 3]); meanImageSq = zeros([inputSize 3]); while hasdata(dsTrain) dat = read(dsTrain); img = double(dat{1}); meanImage = meanImage + img; meanImageSq = meanImageSq + img.^2; end meanImage = meanImage/numTrain; meanImageSq = meanImageSq/numTrain; varImage = meanImageSq - meanImage.^2; stdImage = sqrt(varImage);
Восстановите исходное состояние хранилища данных.
reset(dsTrain);
Этот пример начинается с MobileNet-v2 [3] CNN, обученного на ImageNet [4]. Пример модифицирует сеть, заменяя последний уровень MobileNet-v2 сети полностью связанным слоем с 10 нейронами, каждый из которых представляет дискретную оценку от 1 до 10. Сеть прогнозирует вероятность каждого балла для каждого изображения. Пример нормализует выходы полностью подключенного уровня с помощью уровня активации softmax.
mobilenetv2 функция возвращает предварительно подготовленную сеть MobileNet-v2. Для этой функции требуется модель Deep Learning Toolbox™ для пакета поддержки MobileNet-v2 Network. Если этот пакет поддержки не установлен, функция предоставляет ссылку для загрузки.
net = mobilenetv2;
Преобразование сети в layerGraph объект.
lgraph = layerGraph(net);
Сеть имеет размер входного изображения 224 на 224 пикселя. Замените входной слой на входной слой изображения, который выполняет нормализацию z-показателя для данных изображения с использованием среднего и стандартного отклонения обучающих изображений.
inLayer = imageInputLayer([inputSize 3],'Name','input','Normalization','zscore','Mean',meanImage,'StandardDeviation',stdImage); lgraph = replaceLayer(lgraph,'input_1',inLayer);
Замените исходный окончательный классификационный слой полностью связанным слоем с 10 нейронами. Добавьте уровень softmax для нормализации выходных данных. Установите скорость обучения полностью подключенного уровня в 10 раз больше скорости обучения базовых уровней CNN. Применить отсев 75%.
lgraph = removeLayers(lgraph,{'ClassificationLayer_Logits','Logits_softmax','Logits'});
newFinalLayers = [
dropoutLayer(0.75,'Name','drop')
fullyConnectedLayer(newMaxScore,'Name','fc','WeightLearnRateFactor',10,'BiasLearnRateFactor',10)
softmaxLayer('Name','prob')];
lgraph = addLayers(lgraph,newFinalLayers);
lgraph = connectLayers(lgraph,'global_average_pooling2d_1','drop');
dlnet = dlnetwork(lgraph);Визуализация сети с помощью приложения Deep Network Designer.
deepNetworkDesigner(lgraph)
modelGradients вспомогательная функция вычисляет градиенты и потери для каждой итерации обучения сети. Эта функция определена в разделе «Вспомогательные функции» данного примера.
Целью сети NIMA является минимизация расстояния земного движителя (EMD) между достоверностью земли и прогнозируемыми распределениями баллов. Потеря EMD учитывает расстояние между классами при наказании за неправильную классификацию. Таким образом, потеря EMD лучше, чем типичная потеря взаимной энтропии softmax, используемая в задачах классификации [5]. В этом примере вычисляется потеря EMD с помощью earthMoverDistance вспомогательная функция, которая определена в разделе «Вспомогательные функции» данного примера.
Для функции потерь EMD используйте расстояние r-norm с r = 2. Это расстояние позволяет легко оптимизировать работу с градиентным спуском.
Укажите параметры оптимизации SGDM. Обучение сети за 150 эпох с размером мини-партии 128.
numEpochs = 150; miniBatchSize = 128; momentum = 0.9; initialLearnRate = 3e-3; decay = 0.95;
Создать minibatchqueue объект, который управляет мини-пакетами наблюдений в пользовательском учебном цикле. minibatchqueue объект также передает данные в dlarray объект, обеспечивающий автоматическую дифференциацию в приложениях глубокого обучения.
Укажите формат извлечения данных мини-пакета как 'SSCB' (пространственный, пространственный, канальный, пакетный). Установите 'DispatchInBackground' аргумент name-value к логическому значению, возвращенному canUseGPU. Если поддерживаемый графический процессор доступен для вычисления, то minibatchqueue объект предварительно обрабатывает мини-пакеты в фоновом режиме в параллельном пуле во время обучения.
mbqTrain = minibatchqueue(dsTrain,'MiniBatchSize',miniBatchSize, ... 'PartialMiniBatch','discard','MiniBatchFormat',{'SSCB',''}, ... 'DispatchInBackground',canUseGPU); mbqVal = minibatchqueue(dsVal,'MiniBatchSize',miniBatchSize, ... 'MiniBatchFormat',{'SSCB',''},'DispatchInBackground',canUseGPU);
По умолчанию в примере загружается предварительно подготовленная версия сети NIMA. Предварительно обученная сеть позволяет выполнять весь пример без ожидания завершения обучения.
Для обучения сети установите doTraining переменная в следующем коде true. Обучение модели в индивидуальном цикле обучения. Для каждой итерации:
Считывание данных для текущего мини-пакета с помощью next функция.
Оцените градиенты модели с помощью dlfeval функции и modelGradients функция помощника.
Обновление параметров сети с помощью sgdmupdate функция.
Обучение на GPU, если он доступен. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений).
doTraining = false; if doTraining iteration = 0; velocity = []; start = tic; [hFig,lineLossTrain,lineLossVal] = initializeTrainingPlotNIMA; for epoch = 1:numEpochs shuffle (mbqTrain); learnRate = initialLearnRate/(1+decay*floor(epoch/10)); while hasdata(mbqTrain) iteration = iteration + 1; [dlX,cdfY] = next(mbqTrain); [grad,loss] = dlfeval(@modelGradients,dlnet,dlX,cdfY); [dlnet,velocity] = sgdmupdate(dlnet,grad,velocity,learnRate,momentum); updateTrainingPlotNIMA(lineLossTrain,loss,epoch,iteration,start) end % Add validation data to plot [~,lossVal,~] = modelPredictions(dlnet,mbqVal); updateTrainingPlotNIMA(lineLossVal,lossVal,epoch,iteration,start) end % Save the trained network modelDateTime = string(datetime('now','Format',"yyyy-MM-dd-HH-mm-ss")); save(strcat("trainedNIMA-",modelDateTime,"-Epoch-",num2str(numEpochs),".mat"),'dlnet'); else load(fullfile(imageDir,'trainedNIMA.mat')); end
Оцените производительность модели в наборе тестовых данных, используя три метрики: EMD, точность двоичной классификации и коэффициенты корреляции. Производительность сети NIMA на тестовом наборе данных соответствует производительности эталонной модели NIMA, сообщенной Talebi и Milanfar [1].
Создать minibatchqueue объект, который управляет мини-пакетированием тестовых данных.
mbqTest = minibatchqueue(dsTest,'MiniBatchSize',miniBatchSize,'MiniBatchFormat',{'SSCB',''});
Рассчитайте прогнозируемые вероятности и кумулятивные вероятности истинности земли мини-партий тестовых данных с помощью modelPredictions функция. Эта функция определена в разделе «Вспомогательные функции» данного примера.
[YPredTest,~,cdfYTest] = modelPredictions(dlnet,mbqTest);
Рассчитайте среднее и стандартное значения отклонения истинности земли и прогнозируемых распределений.
meanPred = extractdata(YPredTest)' * (1:10)'; stdPred = sqrt(extractdata(YPredTest)'*((1:10).^2)' - meanPred.^2); origCdf = extractdata(cdfYTest); origPdf = [origCdf(1,:); diff(origCdf)]; meanOrig = origPdf' * (1:10)'; stdOrig = sqrt(origPdf'*((1:10).^2)' - meanOrig.^2);
Вычислите EMD истинности земли и прогнозируемые распределения баллов. Для прогнозирования используйте расстояние r-norm с r = 1. Значение EMD указывает на близость прогнозируемого и базового распределения оценок истинности.
EMDTest = earthMoverDistance(YPredTest,cdfYTest,1)
EMDTest =
1×1 single gpuArray dlarray
0.1158
Для точности двоичной классификации преобразуйте распределения в две классификации: высококачественную и низкокачественную. Классифицируйте изображения со средним баллом выше порога как высококачественные.
qualityThreshold = 5; binaryPred = meanPred > qualityThreshold; binaryOrig = meanOrig > qualityThreshold;
Вычислите точность двоичной классификации.
binaryAccuracy = 100 * sum(binaryPred==binaryOrig)/length(binaryPred)
binaryAccuracy = 84.6591
Большие значения корреляции указывают на большую положительную корреляцию между истинностью основания и прогнозируемыми показателями. Вычислите коэффициент линейной корреляции (LCC) и коэффициент ранговой корреляции Спирмена (SRCC) для средних баллов.
meanLCC = corr(meanOrig,meanPred)
meanLCC =
gpuArray single
0.7265
meanSRCC = corr(meanOrig,meanPred,'type','Spearman')
meanSRCC =
gpuArray single
0.6451
modelGradients функция принимает в качестве входного значения a dlnetwork объект dlnet и мини-пакет входных данных dlX с соответствующими целевыми кумулятивными вероятностями cdfY. Функция возвращает градиенты потерь относительно обучаемых параметров в dlnet а также потери. Для автоматического вычисления градиентов используйте dlgradient функция.
function [gradients,loss] = modelGradients(dlnet,dlX,cdfY) dlYPred = forward(dlnet,dlX); loss = earthMoverDistance(dlYPred,cdfY,2); gradients = dlgradient(loss,dlnet.Learnables); end
earthMoverDistance функция вычисляет EMD между истинностью основания и предсказанными распределениями для заданного значения r-norm. earthMoverDistance использует computeCDF вспомогательная функция для вычисления совокупных вероятностей прогнозируемого распределения.
function loss = earthMoverDistance(YPred,cdfY,r) N = size(cdfY,1); cdfYPred = computeCDF(YPred); cdfDiff = (1/N) * (abs(cdfY - cdfYPred).^r); lossArray = sum(cdfDiff,1).^(1/r); loss = mean(lossArray); end function cdfY = computeCDF(Y) % Given a probability mass function Y, compute the cumulative probabilities [N,miniBatchSize] = size(Y); L = repmat(triu(ones(N)),1,1,miniBatchSize); L3d = permute(L,[1 3 2]); prod = Y.*L3d; prodSum = sum(prod,1); cdfY = reshape(prodSum(:)',miniBatchSize,N)'; end
modelPredictions функция вычисляет оцененные вероятности, потери и кумулятивные вероятности истинности основания мини-пакетов данных.
function [dlYPred,loss,cdfYOrig] = modelPredictions(dlnet,mbq) reset(mbq); loss = 0; numObservations = 0; dlYPred = []; cdfYOrig = []; while hasdata(mbq) [dlX,cdfY] = next(mbq); miniBatchSize = size(dlX,4); dlY = predict(dlnet,dlX); loss = loss + earthMoverDistance(dlY,cdfY,2)*miniBatchSize; dlYPred = [dlYPred dlY]; cdfYOrig = [cdfYOrig cdfY]; numObservations = numObservations + miniBatchSize; end loss = loss / numObservations; end
[1] Талеби, Хоссейн и Пейман Миланфар. «NIMA: оценка нейронных изображений». Транзакции IEEE по обработке изображений 27, № 8 (август 2018 г.): 3998-4011. https://doi.org/10.1109/TIP.2018.2831899.
[2] LIVE: Лаборатория по созданию изображений и видео. «LIVE In the Wild Image Quality Challenge Database». https://live.ece.utexas.edu/research/ChallengeDB/index.html.
[3] Сандлер, Марк, Эндрю Говард, Менглонг Чжу, Андрей Жмогинов и Лян-Чех Чен. «MobileNetV2: инвертированные остатки и линейные узкие места». В 2018 году конференция IEEE/CVF по компьютерному зрению и распознаванию образов, 4510-20. Солт-Лейк-Сити, UT: IEEE, 2018. https://doi.org/10.1109/CVPR.2018.00474.
[4] ImageNet. http://www.image-net.org.
[5] Хоу, Ле, Чэнь-Пин Ю и Димитрис Самарас. «Потери на расстоянии в квадрате земного движителя для обучения глубоким нейронным сетям». Препринт, представлен 30 ноября 2016 года. https://arxiv.org/abs/1611.05916.
dlfeval | dlnetwork | layerGraph | minibatchqueue | mobilenetv2 | predict | sgdmupdate | transform