Некоторые части будут отредактированы и доработаны для лучшего понимания, однако я подтверждаю, что следующий пост основан на учебнике TensorFlow, представленном в:
Для получения более подробных объяснений и базовых знаний о кодах и наборах данных вы всегда можете воспользоваться ссылкой.
Введение
Основные факты об этом сообщении.
Этот пост посвящен пониманию базовой нейронной сети, касающейся данных изображения. Это можно рассматривать как следующий шаг к последней публикации; загрузка изображения в tf.data. Однако в наборе данных flowers_photo не было тестового набора данных, поэтому мы будем использовать изображения CIFAR.
Кроме того, мы не будем использовать tf.data для загрузки изображений. Вместо этого мы просто загрузим изображения напрямую в (train_images, train_labels), (test_images, test_labels). Мы сохраним эту часть простой, чтобы сосредоточиться на CNN.
Этот пост предназначен для студентов бакалавриата, которые будут / будут испытывать трудности на шестой неделе. Надеюсь, это спасет вас, ребята! 👊
Что мы делаем дальше?
Загрузка - это вы перетаскиваете изображение в окно поиска Google. (Вы помните пример из нашего последнего сообщения?) Теперь мы более подробно рассмотрим, как Google конвертирует изображение в формат, который ей понятен. Один из методов называется CNN (сверточная нейронная сеть); сеть, имеющая хотя бы один сверточный слой.
II. Техническая настройка
from __future__ import absolute_import, division, print_function, unicode_literals
try:
# %tensorflow_version only exists in Colab.
%tensorflow_version 2.x
except Exception:
pass
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
Нам нравятся эти строки? PLZ Да! Вы должны знать, что вам не нужно знать слово в слово.
- из tensorflow.keras import наборы данных, слои, модели: мы будем использовать последовательный API keras для моделирования
- import matplotlib.pyplot как plt: мы будем рисовать графики, чтобы показать некоторые изображения.
III. Набор данных CIFAR10
Основная информация о наборе данных CIFAR10.
Он имеет 60K 32 * 32 цветных изображений 10 классов по 6K изображений на класс. У нас есть 50K обучающих изображений и 10K тестовых изображений. У нас есть набор данных, в котором изображения уже разделены на 6 групп (по 1К изображений в каждой); 5 партий для обучения и 1 партия для теста с произвольным смешением классов. Они уже закончили предварительную обработку! 👍
У нас есть 10 классов с именами; 'airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'.
Сначала мы загрузим наш набор данных cifar10.
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()
Затем мы нормализуем значения пикселей до диапазона от 0 до 1.
train_images, test_images = train_images / 255.0, test_images / 255.0
Что такое значения пикселей?
Совершенно естественно, что вы не можете понять, почему мы делим изображения на 255. Давайте посмотрим.
RGB представляет красный, зеленый и синий. Хотя мы не уверены, как живые существа распознают изображения и цвета, компьютеры сохраняют и понимают изображения в соответствии со значениями пикселей RGB.
Каждый R, G, B может иметь число от 0 до 255, а цветной пиксель сохраняется в векторе строк размером 1 на 3 (R, G, B). Вот почему у цветного изображения color_channels равно 3.
Затем у цветного изображения есть 3 сетки (по одной для каждого RGB) с размером image_height и image_width.
«Нормализация» обычно означает несколько разных вещей, однако в данном контексте это означает, что наши числа будут находиться в диапазоне от 0 до 1 для простоты вычислений.
Покажите картинки
Мы хотим видеть изображения собственными глазами. Мы отобразим 10 изображений с соответствующими именами классов под каждым изображением.
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
plt.figure(figsize=(10,10)) for i in range(10): plt.subplot(5,5,i+1) plt.xticks([]) plt.yticks([]) plt.grid(False) plt.imshow(train_images[i], cmap=plt.cm.binary) # The CIFAR labels happen to be arrays, # which is why you need the extra index plt.xlabel(class_names[train_labels[i][0]]) plt.show()
IV. Создайте сверточную базу
i) Во-первых, мы хотели бы упростить способ построения модели.
Ниже приводится полная модель, которую мы будем создавать в этой публикации.
model = tf.keras.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)), tf.keras.layers.MaxPooling2D((2,2)), tf.keras.layers.Conv2D(64, (3, 3), activation='relu'), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(64, (3, 3), activation='relu'), tf.keras.layers.Flatten(), tf.keras.layers.Dense(64,activation='relu'), tf.keras.layers.Dense(10,activation='softmax') ])
Однако мы можем использовать метод model.add, чтобы пропустить повторяющиеся слои tf.keras.layers. Идея состоит в том, что после создания свободной последовательной модели мы будем добавлять слои.
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu'))
ii) Что такое свертка и MaxPooling?
1 - Свертка: процесс применения ядра или фильтра к изображению.
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))
- input_shape = (32,32,3)
Мы рассмотрели это! у нас есть изображение размером image_height = 32, image_width = 32, с color_channels равным 3 (цвет). - Activation = ‘relu’
relu - это сокращение от Выпрямленная линейная единица и наиболее часто используемая функция активации. Эта функция возвращает 0, если вход меньше или равен 0, и если вход положительный, то выход будет равен входу. Это облегчает решение «нелинейных» проблем.
Если вы не знаете, какую функцию активации использовать, вас ждет relu. - (3,3): ядро - сетка 3 * 3
- 32 - количество фильтров ядра
[Пример] Для простоты мы возьмем изображение размером 6 на 6 пикселей с шкалой серого, в котором каждый пиксель имеет номер от 0 (черный ) до 255 (белый).
2*1 + 5*2+4*1 + 13*2 + 25*4 +15*2 +8*1+6*2+6*1=198
Тогда как насчет значений на полях? Нулевое заполнение может быть вариантом.
Представим, что матрица 2 на 2 окружена нулями. т.е.
0 0 0
0 1 0
0 8 2
0 * 1 + 0 * 2 + 0 * 1 + 0 * 2 + 1 * 4 + 0 * 2 + 0 * 1 + 8 * 2 + 2 * 1 = 4 + 16 + 2 = 22.
В кодировке мы можем заполнить нулями, присвоив padding = 'same'
т.е. model.add (Layers.Conv2D (32, (3, 3) , padding = 'same', Activation = 'relu', input_shape = (32, 32, 3)))
Кроме того, у нас может быть 'no padding', который просто не будет учитывать значения на полях, не определяя переменную заполнения (как в нашем примере) или определяя padding = 'действительный'. В случае отсутствия заполнения мы видим, что размер вывода уменьшается до 4 на 4.
Хотя мы смотрим на произвольное ядро, в зависимости от типов фильтров, все они имеют имена. Кроме того, поскольку у нас нет отрицательных или нулевых значений в нашей запутанной сетке, нет места для «RELU», но если бы оно было, оно будет мешать.
Можно сказать, что обучение - это процесс поиска лучшего ядра / фильтра 3 на 3. Каждое число в фильтрах концептуально совпадает с весами в линейной регрессии.
2 - MaxPooling: объединение максимального значения в запутанном изображении. Это метод понижающей дискретизации.
layers.MaxPooling2D((2, 2))
Мы создали запутанную сетку изображений, затем будем перемещаться по нашему ядру 2 на 2 и выбирать максимальное значение.
Также может быть назначена переменная stride, которая представляет собой количество пикселей, которые ядро 2 на 2 будет перемещать по запутанному изображению.
Вы видите, что размер нового изображения уменьшился вдвое?
IV-а. Краткое описание модели
model.summary () выведет это:
Как обычно, давайте интерпретируем числа, которые появляются в сводной таблице.
1 - model.add (Layers.Conv2D (32, (3, 3), padding = 'same', activate = 'relu', input_shape = (32, 32, 3)) → (Нет, 30,30,32), параметр # 896
- Как мы и ожидали, наш ввод (32,32) был уменьшен до (30,30) для процесса без заполнения на 2 пикселя каждый.
- 32 исходит из числа ядер. Каждое ядро создаст одно запутанное изображение. Таким образом, всего будет 32 выходных канала сверток или карт функций.
- Сколько у нас параметров?
У нас есть ядро размером 3 * 3 пикселя для каждого RGB. Итак, у нас есть 3 * 3 * 3 = 27 пикселей (весов) и 1 смещение для одного ядра. Подводя итог, (27 + 1) * 32 = 896 - это количество параметров.
2 —model.add (sizes.MaxPooling2D ((2, 2))) → (Нет, 15,15,32)
- Мы сделали «понижающую дискретизацию» с помощью MaxPooling с сеткой 2 на 2, которая уменьшит размер изображения вдвое, сохранив количество функций; 32.
3 - model.add (Layers.Conv2D (64, (3, 3), activate = ’relu’)) → (Нет, 13,13,64), параметр # 18496
- Выходные данные первого сверточного слоя были уменьшены с помощью предыдущего MaxPooling. Теперь субдискретизированная карта функций 15 на 15 снова будет проходить через фильтр свертки. Поскольку пиксели на полях удаляются из-за отсутствия заполнения, оно уменьшается до 13 на 13.
- Этот сверточный слой имеет 64 ядра, которые имеют размер 3 на 3 пикселя.
- Поскольку размер ввода был уменьшен, у нашего ИИ осталась некоторая емкость для дополнительных фильтров. Итак, во втором слое свертки у нас может быть 64 фильтра.
- Сколько у нас параметров?
Из первого сверточного слоя у нас есть 32 карты характеристик; наш 2-й сверточный слой принимает выходной канал из предыдущего сверточного слоя (или карту объектов) в качестве входных и выводит 64 объекта.
У нас по-прежнему размер фильтра 3 на 3.
Итак, у нас есть (3 * 3 * 32) веса и 1 смещение для каждого фильтра. Подводя итог, на втором уровне conv2d_7 есть параметры (3 * 3 * 32 + 1) * 64 = 18496.
Боковое примечание) 32 карты характеристик являются выходом 1-го сверточного слоя и входом 2-го сверточного слоя одновременно. Вы помните промежуточный продукт и конечный продукт из части «Введение в экономику ВВП»? Примените эту аналогию к CNN.
4 - model.add (sizes.MaxPooling2D ((2, 2))) → (None, 6,6,64)
- Опять же, размер изображения уменьшился вдвое, сохранив те же 64 функции.
5 - model.add (sizes.Conv2D (64, (3, 3), activate = ’relu’)) → (None, 4,4,64) param # 36928
- Здесь снова два пикселя от ширины изображения и высоты изображения удалены из-за отсутствия заполнения, и этот сверточный слой имеет 64 ядра, которые имеют размер 3 на 3 пикселя.
- Сколько у нас параметров?
Из второго сверточного слоя у нас есть 64 карты объектов на входе и 64 объекта на выходе. У нас по-прежнему размер фильтра 3 на 3.
Итак, у нас есть (3 * 3 * 64) веса и 1 смещение для каждого фильтра. Подводя итог, на втором уровне conv2d_8 есть параметры (3 * 3 * 64 + 1) * 64 = 36928.
Наконец, 896 + 18496 + 36928 = 56320.
V. Добавьте плотные слои сверху
Мы должны провести классификацию, поэтому нам понадобится один или несколько плотных слоев. Поскольку плотный слой принимает в качестве вектора одномерный вектор, мы должны разбить и уложить выходные данные предыдущего сверточного слоя. Мы должны преобразовать трехмерный тензор (4,4,64) в одномерный тензор или вектор с 4 * 4 * 64 = 1024 элементами. Слой flatten () позволяет это.
Независимо от того, сколько у нас плотных слоев, у нас должен быть последний слой с 10 слоями (= количество классов) с функцией активации softmax.
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
V-а. Краткое описание модели
6 - model.add (sizes.Flatten ()) → (None, 1024)
Вход от последнего сверточного слоя имел выходной канал размером 4 * 4 и имел 64 канала. их. Сглаженный слой поместит все это как одномерный вектор, имеющий 4 * 4 * 64 элемента.
7 - model.add (Layers.Dense (64, Activation = 'relu')) → (None, 64) param # 65600
У нас есть 64 узла в этом плотном слое и 1024 входа от плоского слоя. Здесь у нас есть 1024 веса и 1 смещение для каждого узла. (1024 + 1) * 64 = 65600.
8 - model.add (Layers.Dense (10, activate = 'softmax')) → (None, 10), param # 650
У нас есть 10 узлов в этом плотном слое и 64 входы из предыдущего плотного слоя. (64 + 1) * 10 = 650.
Наконец, 896 + 18496 + 36928 + 65600 + 650 = 122570
VI. Скомпилируйте и обучите модель
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
VII. Оценить модель
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
У нас есть выход 10000 / 1–1 с - потеря: 0,8848 - точность: 0,7142.
Это не ужасно, но мало.
Продолжайте учиться и повышайте свою точность!
Спасибо, что прочитали такой длинный рассказ.
Надеюсь, это было не слишком сложно для вас.
Любые вопросы или комментарии всегда приветствуются.
Также, если в этом посте были ошибки, оставьте, пожалуйста, комментарий. Это поможет нам улучшить качество наших работ.
Еще раз спасибо и желаю приятного и напряженного дня! 👏 👏