Мои прошлые блоги TensorFlow освещали основы Tensorflow, построение классификатора с использованием TensorFlow и TensorFlow-lite. Теперь я расскажу, как создать сверточную нейронную сеть (CNN) из скретч для набора данных MNIST .

Надеюсь, вы знакомы с базовой структурой CNN. Если нет, просто исследуйте здесь.

Это блог, в котором весь код !!

Этот блог разделен на следующие основные части:

  • Определение функций для ваших слоев
  • Создание вашей модели, добавление оптимизатора и прочего
  • Настраиваемые генераторы для обучения и проверки.
  • Обучение, проверка и окончательные прогнозы с использованием TensorFlow.session ()

Когда вы закончите обновлять свои концепции CNN, давайте запишем все, что нам нужно для полной модели CNN:

  • Входы и цель (одна горячая кодировка)
  • Слои (свертка, выпадение, максимальный / средний слой пула, плотный, плоский)
  • Оптимизатор
  • Функция потерь
  • Метрика (я бы использовал точность)

И мы закончили !!!

Просто, но не просто

Все коды, указанные в сообщении, можно найти здесь.

Мы также должны помнить, что MNIST имеет формат 1 x 784 для изображений. Следовательно, его необходимо изменить, чтобы сформировать изображение 28 x 28 x 1. Вы можете использовать приведенный ниже код для этого

x=x.values.reshape(-1,28,28,1)
tester=y.values.reshape(-1,28,28,1)

Здесь x и y - это данные для обучения и тестирования соответственно. Reshape принимает 4 аргумента:

Последние три относятся к ширине, высоте и каналу (1 для оттенков серого). Первый аргумент «-1» представляет любое число. Это обозначение используется, поскольку «-1» будет включать размер выборки. Как если бы 10 изображений были в обучении. set ,, -1 будет автоматически заменен на 10 (magic😇😇)

Сделайте одно горячее кодирование вашей цели, используя приведенный ниже код

from keras.utils.np_utils import to_categorical
z=to_categorical(z,num_classes=10)

Поскольку MNIST имеет 10 категорий (0–9), num_classes = 10, z - целевая переменная.

Итак, начнем !!!

  • Ниже приведен блок кода со всеми определенными функциями для различных требуемых уровней.
import tensorflow as tf
def conv2d(x,w):
    weights=tf.Variable(tf.random.normal(w))
    return tf.nn.relu(tf.nn.conv2d(x,weights,[1,1,1,1],padding='SAME'))
def dropout(x,prob):
    return tf.nn.dropout(x,prob)
def max_pool(x,k):
    return tf.nn.max_pool(x,k,[1,2,2,1],padding='SAME')
def fully_connected(x,size):
    weights=tf.Variable(tf.random.normal([int(x.get_shape()[1]),size],mean=0,stddev=1))
    return tf.matmul(x,weights)

Начиная с самого первого:

  • Conv2d (x, w): эта функция используется для создания 2D-слоя свертки. «Вес» в основном относится к фильтрам свертки, которые мы хотим применить к 4 измерениям. Он был инициализирован с использованием нормального распределения.

[ширина, высота, input_channel, output_channel]

Это сильно отличается от того, что мы используем в Керасе !!

Ширина и высота относятся к размерам фильтра, input_channel - это количество каналов во входном изображении (в градациях серого - 1 / в случае RGB - 3), а выходные каналы относятся к количеству используемых фильтров.

Переход к следующей строке:

Уровень tf.nn.conv2d реализует для нас слой Conv2D. Используемые 4 параметра: входные данные, веса, шаг и отступы.

Как шаг = [1,1,1,1]. Лучшее объяснение этому приведено ниже:

Теперь поговорим о padding = ’SAME / VALID’, снова следуйте изображению ниже.

Двигаясь дальше,

def dropout(x,prob):
    return tf.nn.dropout(x,prob)

Следующая функция - добавить выпадающий слой. Просто помните, что в старых версиях вероятностью является keep_probability, т. Е. если я упомяну 0.9, 10% узлов будут отброшены, что в Керасе наоборот.

def max_pool(x,k):
    return tf.nn.max_pool(x,k,[1,2,2,1],padding='SAME')

Далее следует слой max_pool. Его также можно заменить слоем average_pool с теми же параметрами. Здесь также 4 параметра в значительной степени похожи, за исключением 'K', который выглядит примерно так [a, b, c, d]. Опять же, a и d представляют пакет и глубину (канал) и не изменяются в целом ( сохранено 1). 'b' и 'c' обозначают размер пула, который может быть 2 x 2, 3 x 3 и т. д.

Теперь самая важная часть

def fully_connected(x,size):
    weights=tf.Variable(tf.random.normal([int(x.get_shape()[1]),size],mean=0,stddev=1))
    return tf.matmul(x,weights)

Это полностью связанный слой / плотный слой. Здесь size = количество узлов для плотного слоя. Снова инициализация весов с помощью normal_distribution. Чтобы понять тензорные формы, посмотрите ниже:

tf.matmul представляет собой матричное умножение (прямое распространение, если вы помните !!!)

Сделано с очень сложными концепциями !!

Вы думаете, что это сделано !!! Это только начало.

Давайте теперь создадим нашу первую CNN:

tf.reset_default_graph()
inp=tf.placeholder(tf.float32,shape=(None,28,28,1),name='input')
target=tf.placeholder(tf.float32,shape=(None,10),name='target')
l1=conv2d(inp,[5,5,1,32])
l2=max_pool(l1,[1,2,2,1])
l9=dropout(l2,0.9)
l3=conv2d(l9,[5,5,32,64])
l4=max_pool(l3,[1,2,2,1])
l0=dropout(l4,0.9)
l5=tf.reshape(l0,[-1,7*7*64])
l6=fully_connected(l5,10)
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=target,logits=l6))
opt=tf.train.AdamOptimizer(0.005).minimize(cost)
prediction=tf.argmax(l6,1)
result=tf.equal(tf.argmax(l6,1),tf.argmax(target,1))
accuracy=tf.reduce_mean(tf.cast(result,tf.float32))

Сделайте глубокий вдох и ПОГРУЗИТЕСЬ

Следуя кодам построчно:

  • Сбросить график по умолчанию
  • inp = принимает входные данные, используя заполнитель фигуры (Нет, 28,28,1). Здесь «None» используется для включения размера пакета. Rest - это размер изображения (ширина, высота, канал).
  • target = целевая переменная
  • l1_layer: 1-й слой Conv2D с размером фильтра 5 x 5, входным каналом 1 и количеством фильтров = 32
  • l2_layer: слой Max_Pool с размером пула 2x2
  • l9_layer: выпадение 10% узлов (концепция keep_probability используется только в старых версиях). 0.9 означает сохранение 90% узлов
  • l3_layer: 2-й слой Conv2D с размером ядра 5 x 5, входной канал = 32 (поскольку мы использовали 32 фильтра в предыдущем уровне пула), а выходные каналы - 64
  • l4_layer: аналогичный слой Max_Pool
  • l0: выпадающий слой

Помните, что перед вызовом любого плотного / полностью связанного слоя сведите изображение к 1D-массиву.

l5=tf.reshape(l0,[-1,7*7*64])
l6=fully_connected(l5,10)
  • l5_layer: он используется для сглаживания изображений, а l6 - это полностью связанный слой, который мы использовали. 10 представляет количество классов (0–9 цифр в MNIST).

[-1,7 * 7 * 64] - это форма, в которой оно должно быть сглажено. 7 * 7 * 64 используется, поскольку слой Max-Pool, используемый дважды, имеет размер 2x2. Следовательно, ширина и высота изображения уменьшаются на коэффициент 4. Следовательно, размеры изменяются с 28 x 28 до 7 x 7. 64 - это количество каналов, поскольку на выходе 2-го слоя Conv2D было 64 канала.

cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=target,logits=l6))
opt=tf.train.AdamOptimizer(0.005).minimize(cost)
prediction=tf.argmax(l6,1)
result=tf.equal(tf.argmax(l6,1),tf.argmax(target,1))
accuracy=tf.reduce_mean(tf.cast(result,tf.float32))
  • Эта функция является нашей функцией потерь / затрат. 'Logits' - это прогнозы, а метки - это целевая переменная. Чтобы понять softmax_cross_entropy_with_logits, обратитесь к моему предыдущему блогу. Reduce_mean () усредняет потери для всех изображений пакета
  • «Opt» - это оптимизатор, используемый для минимизации затрат, рассчитанных выше.
  • прогнозирование берет индекс с наивысшим прогнозируемым значением из вектора размера 10 (выход последнего полностью подключенного уровня). Второй параметр, т.е. 1, представляет ось
  • «Результат» должен соответствовать тому, какие прогнозы верны. Он проверяет, равны ли максимальный аргумент от цели (One Hot Encoded, помните) и прогнозы.
  • Точность просто вычисляет среднее значение по тензору результата, который имеет значения либо 0 (не равно), либо 1 (равно).

То же самое и с сетью

А теперь кто будет его запускать ???

ТЫ КОНЕЧНО!!!

Пожалуйста, помогите себе с настраиваемыми генераторами, используемыми для обучения и тестирования. Воспользуйтесь помощью здесь.

def train_gen():
    image=[]
    label=[]
    count=0
    for x,y in zip(xtrain,ztrain):
                if count<8:
                    count+=1
                    image.append(x)
                    label.append(y)
                if count==8:
                        yield np.array(image).reshape(-1,28,28,1),np.array(label).reshape(-1,10)
                        count=0
                        image=[]
                        label=[]
                
def val_gen():
        image=[]
        label=[]
        count=0
        for x,y in zip(xtest,ztest):
                if count<64:
                    count+=1
                    image.append(x)
                    label.append(y)
                if count==64:
                        yield np.array(image).reshape(-1,28,28,1),np.array(label).reshape(-1,10)
                        count=0
                        image=[]
                        label=[]

Теперь конечный пункт назначения, обучение и проверка сети:

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for q in range(5):
        z=train_gen()
        print("EPOCH="+str(q))
        for x,y in z:
                a,b,c=sess.run([cost,opt,accuracy],feed_dict={'input:0':x,'target:0':y})
        result=sess.run([cost,accuracy],feed_dict={'input:0':np.array(xtest).reshape(-1,28,28,1),'target:0':np.array(ztest).reshape(-1,10)})
        print("Epoch "+str(q)+" accuracy"+str(result[1])+" loss="+str(result[0]))
    f=sess.run([prediction],feed_dict={'input:0':tester})

Поскольку я объяснял подобный код в моем предыдущем блоге, я бы просто рассмотрел несколько основных моментов:

  • 500 - это эпохи
  • xtest (input) и ztest (target) предназначены для проверки. Поскольку я не использовал генератор (хотя и создал его), размер изображений нужно изменить только в feed_dict.
  • "F" используется для получения прогнозов от модели.

Наконец-то марафон окончен !!

Ссылка на код:

Https://www.kaggle.com/mehulgupta2016154/fork-of-my-first-cnn?scriptVersionId=20845084

Хотите узнать больше !! сходить с ума внизу.