В этом примере показано, как анализировать эстетическое качество изображений с помощью сверточной нейронной сети (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 В Диком наборе данных [2], который является общественным достоянием субъективная база данных проблемы качества изображения. Набор данных содержит 1 162 фотографии, полученные мобильными устройствами с 7 дополнительными изображениями, обеспеченными, чтобы обучить человеческие маркеры. Каждое изображение оценивается в среднем 175 индивидуумами по шкале [1, 100]. Набор данных обеспечивает среднее и стандартное отклонение субъективной музыки к каждому изображению.
Загрузите набор данных путем следования инструкциям, обрисованным в общих чертах в LIVE В Дикой Базе данных проблемы Качества изображения. Извлеките данные в директорию, заданную 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));
Создайте datastore изображений, который управляет данными изображения.
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);
Предварительно просмотрите выход чтения от объединенного datastore.
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);
Сбросьте datastore к его начальному состоянию.
reset(dsTrain);
Создайте minibatchqueue
объект, который справляется с мини-пакетной обработкой наблюдений в пользовательском учебном цикле. minibatchqueue
возразите также бросает данные к dlarray
объект, который включает автоматическое дифференцирование в применении глубокого обучения.
Задайте мини-пакетный формат экстракции данных как 'SSCB'
(пространственный, пространственный, канал, пакет). Установите 'DispatchInBackground'
аргумент значения имени к boolean, возвращенному canUseGPU
. Если поддерживаемый графический процессор доступен для расчета, то minibatchqueue
объект предварительно обрабатывает мини-пакеты в фоновом режиме в параллельном пуле во время обучения.
miniBatchSize = 128; mbqTrain = minibatchqueue(dsTrain,'MiniBatchSize',miniBatchSize, ... 'PartialMiniBatch','discard','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. Эта функция требует Модели Deep Learning Toolbox™ для пакета Сетевой поддержки MobileNet-v2. Если этот пакет поддержки не установлен, то функция обеспечивает ссылку на загрузку.
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
функция помощника вычисляет градиенты и потери для каждой итерации обучения сети. Эта функция задана в разделе Supporting Functions этого примера.
Цель сети NIMA состоит в том, чтобы минимизировать наземное расстояние двигателя (EMD) между основной истиной и предсказанными распределениями счета. Потеря EMD рассматривает расстояние между классами при наложении штрафа misclassification. Поэтому потеря EMD выполняет лучше, чем типичная softmax потеря перекрестной энтропии, используемая в задачах классификации [5]. Этот пример вычисляет потерю EMD с помощью earthMoverDistance
функция помощника, которая задана в разделе Supporting Functions этого примера.
Для функции потерь EMD используйте расстояние r-нормы с r = 2. Это расстояние допускает легкую оптимизацию, когда вы работаете с градиентным спуском.
Задайте опции для оптимизации SGDM. Обучите сеть в течение 150 эпох.
numEpochs = 150; momentum = 0.9; initialLearnRate = 3e-3; decay = 0.95;
По умолчанию пример загружает предварительно обученную версию сети NIMA. Предварительно обученная сеть позволяет вам запустить целый пример, не ожидая обучения завершиться.
Чтобы обучить сеть, установите doTraining
переменная в следующем коде к true
. Обучите модель в пользовательском учебном цикле. Для каждой итерации:
Считайте данные для текущего мини-пакета с помощью next
функция.
Оцените градиенты модели с помощью dlfeval
функционируйте и modelGradients
функция помощника.
Обновите сетевые параметры с помощью sgdmupdate
функция.
Обучайтесь на графическом процессоре, если вы доступны. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA® графический процессор. Для получения дополнительной информации смотрите Поддержку графического процессора Релизом (Parallel Computing Toolbox).
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
функция. Эта функция задана в разделе Supporting Functions этого примера.
[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-нормы с 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
функционируйте берет в качестве входа 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-нормы. 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] Talebi, Хоссейн и Пеимен Милэнфэр. “NIMA: Нейронная Оценка Изображений”. Транзакции IEEE на Обработке изображений 27, № 8 (август 2018): 3998–4011. https://doi.org/10.1109/TIP.2018.2831899.
[2] LIVE: Лаборатория для Изображения и Видео Разработки. "LIVE В Дикой Базе данных проблемы Качества изображения". 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. https://www.image-net.org.
[5] Как, Le, Chen-Ping Ю и Димитрис Самарас. “Основанная на расстоянии Потеря Двигателя Земли в квадрате для Учебных Глубоких нейронных сетей”. Предварительно распечатайте, представленный 30 ноября 2016. https://arxiv.org/abs/1611.05916.
mobilenetv2
| transform
| layerGraph
| dlnetwork
| minibatchqueue
| predict
| dlfeval
| sgdmupdate