введение
Эта статья предназначена для изучения Tensorflowофициальная документацияНебольшое понимание процесса, эта статья предполагает, что у вас есть определенное представление о матричных операциях, подробности вы можете увидеть ниже.материал
Скачать данные
Прежде всего, мы должны сначала загрузить данные, Tensorflow предоставляет нам функцию для загрузки, этофункциязаread_data_sets
эта функцияread_data_sets
Функция очень простая.Проверить есть ли файлы в каталоге,скачать их,разобрать и загрузить.С одной стороны нам удобно получать данные,а с другой стороны нам удобно есть прямо из коробки, но поскольку этот адрес загрузки по умолчанию должен быть через стену, я Вот тот, который не нужно переворачивать через стенуадрес, вам просто нужно загрузить функцию ниже
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("input/", one_hot=True, source_url="http://yann.lecun.com/exdb/mnist/")
Через несколько минут данные будут загружены в текущую директориюinput
папку, так что вы можете напрямую загрузить данные изображения в локальную папку в следующий раз, когда вы запустите
данные наблюдения
Для начала посмотрим какие данные скачиваются, открываемinput
В папке мы видим, что Tensorflow загрузил для меня четыре файла, разделенных на две группы: обучающий набор и тестовый набор, каждая группа содержит 2 файла, один из которых представляет собой файл рукописного изображения, а файл метки (каждая рукописная картинка представляет числа)
Загрузка данных изображения довольно проблематична для новичков.Чтобы мы могли сосредоточиться на модели, а не на программировании, Tensorflow напрямую помогает нам хорошо выполнять загрузку данных.Что мы получили вышеmnist
Переменная хранит данные, которые нам нужны для этого проекта, давайте посмотрим на этоmnist
есть что
Что нас больше всего волнует, так этоmnist
Внутри обучающих данных рекомендуется использовать здесьnotebook
Чтобы работать с этим набором данных, мы сначалаmnist
Для чего нужны обучающие данные
mnist
Данные - это картинки выше. Мы бинаризируем каждый пиксель картинки, а затем помещаем их в массив, каждая картинка соответствует массиву
mnist обучающие данные хранятся в этих двух переменных
mnist.train.labels
mnist.train.images
вmnist.train.images
Является(55000, 784)
двумерный массивmnist.train.labels.shape
Является(55000, 10)
Двумерный массив , который у нас есть сейчас, очень прост,55000
значения пикселей изображения для обучения нашей модели, чтобы модель могла предсказывать число, представленное значением пикселя изображения
Эти числа очень легко распознать в глазах людей, но как компьютер может также распознать его?Для этого требуется использование мощности сверточных нейронных сетей.Благодаря сверточной нейронной сети точность работы компьютера может достигать 99% , что очень страшно, и мы, люди, иногда видим что-то не так.
Прежде чем говорить о свертке, давайте поговорим о нашей предыдущей практике, чтобы мы могли узнать, какую оптимизацию выполнила свертка в сравнении.
традиционная практика
На самом деле, с традиционной точки зрения, по сути, распознавание изображений заключается в том, чтобы судить о значении картинки через собственные значения картинки, но картинка очень особенная По сравнению с другими задачами машинного обучения у нее много собственных значений , Здесь мы используем Изображение 28X28 имеет функции 784. Если размер изображения больше, значение этой функции станет очень большим, и мы знаем, что машинному обучению требуется много данных, чтобы иметь возможность работать хорошо, но каждое изображение такой огромный, обучение огромного набора данных Компьютер не может справиться с этим
Следовательно, мы должны уменьшить размерность данных.Существует много методов уменьшения размерности в машинном обучении, таких как PCA и LDA, но у этих методов есть проблема.Они должны рассматривать картинку как целостный вход, то есть предыдущий 28X28 Превратив в массив 784, мы знаем, что этот массив потерял очень важную размерность, внимательно наблюдаем за картинкой выше
На самом деле каждая картинка связана с двумерным распределением чисел.Мы различаем 8 и 0 по количеству закрытых кружков, а 0 и 1 по пустой части в середине, поэтому мы надеемся использовать новый метод определения характеристик изображения, с одной стороны, может сохранить пространственную информацию изображения, а с другой стороны, он может дать одномерный результат конечных данных (число, представленное изображением). Это введение свертки, которая извлекает изображение из двумерной перспективы. По сравнению с традиционным одномерным извлечением, она может в наибольшей степени сохранить информацию об изображении и выполнить глубокое уменьшение размерности.
Узнайте о свертке из проекта
В начале изучения сверточной нейронной сети глубокого обучения я прочитал много материалов, но всегда чувствовал, что у меня нет глубокого понимания.Когда я соприкоснулся с этим проектом, понимание свертки с уровня кода дало мне внезапное осознание.
Прежде всего, давайте поговорим о базовых знаниях библиотеки Tensorflow. Поскольку Python немного медленный, бэкэнд Tensorflow написан на C ++. Таким образом, вы можете понять Tensorflow. Python эквивалентен клиенту, и вы можете использовать сеанс (разговор) Взаимодействие с сервером (C++), в этом случае мы можем наслаждаться удобством и скоростью Python на стороне клиента, а также наслаждаться эффективностью работы C++, но это также приносит проблемы, изначально Python это WYSIWYG, теперь Чтобы что-то запустить, вы должны использовать сеанс, чтобы уведомить сервер о запуске.Многие из наших промежуточных процессов не могут знать, и их можно вывести только из возвращаемых результатов. В официальном руководстве мало говорится о промежуточном процессе, только краткое введение, поэтому, чтобы лучше понять сверточную нейронную сеть, мы запустим Tensorflow уродливым образом, но мы можем понять свертку из этого процесса.
Итак, далее мы запускаем серверную часть для каждой операции и анализируем возвращаемые результаты.Для удобства описания мы предполагаем, что вы выполняетеsession.run
будет запускать это раньшеsession.run(tf.global_variables_initializer())
инициализировать все переменные
PS: причина запуска этого в том, что мы используем сеанс сC++
Interact, если мы «не объявляем» переменную, c++ сообщит об ошибке
Давайте начнем с этого проекта построчно
Подготовить данные
Как мы знаем ранее, свертка предназначена для извлечения нужных признаков из двумерного пространства.Во-первых, мы восстанавливаем данные в двумерном виде.
x_image = tf.reshape(x, [-1,28,28,1])
x - это данные, которые мы ввели выше, давайте проверим их, сначала мы объявимsession
session = tf.Session()
Затем вытащите 50 картинок из набора данных.
data = mnist.train.next_batch(50)[0]
Далее мы смотрим на этоx_image
что стало
session.run(tf.global_variables_initializer())
x_image_data = session.run(x_image, feed_dict={x: data})
Мы входим в обаshape
data.shape, x_image_data.shape
(50, 784) (50, 28, 28, 1)
Мы можем ясно видеть, что мы успешно преобразовали одномерное изображение массива (784) в двумерное изображение массива (28X28), фактически мы создали трехмерное изображение (28 X 28 X 1), но поскольку мы есть только некоторые изображения. Будет несколько цветовых каналов (RGB), поэтому мы объявляем его как 28 X 28 X 1 для совместимости
Хорошо, теперь, когда мы успешно восстановили 1D-изображения в 2D, пришло время их свернуть.
первый уровень
Если вы изучили некоторую обработку сигналов, вы обнаружите, что свертка, используемая в глубоком обучении, на самом деле не является сверткой в первоначальном смысле.У нее нет операции «поворота на 180», но ее форма на самом деле похожа. Эта "продуктовая" операция в основном реализуется через матричные операции.Чтобы лучше понять операцию прокатки, я нашел в Интернете анимации, над которыми усердно трудились предшественники.
Операция свертки — исходная сеть
PS: Это изображение немного отличается от наших данных.У нас есть только один цветовой канал на изображение, это имеет три цветовых канала, а это изображение имеет два ядра свертки, но наш первый слой будет использовать 32, но принцип тот же , если вы действительно не можете понять это, вы можете сначала посмотреть на верхнюю строку
Вернемся к такому рисунку. Крайний левый — вход изображения, средний — ядро свертки, а последний правый — выход. На картинке ясно видно, что свертка отличается от нашей обычной операции. Во-первых, мы являемся вторым входом.Размерные данные, матричные операции выполняются через двумерное ядро свертки, и, наконец, мы выводим двумерные результаты.Это сила свертки, которая не только сохраняет исходную двумерную информацию, но и может использовать эффективные матричные операции для ускорения извлечения признаков.
Теперь вернемся к коду
Во-первых, объявить ядро свертки. Мы можем использовать простой метод, чтобы объявить все ядра свертки как все нулевые матрицы, но это может привести к 0 градиентам, поэтому давайте добавим немного шума. Давайте посмотрим, будет ли ядро свертки, которое добавляет шум какая ценность
initial = tf.truncated_normal([5, 5, 1, 32], stddev=0.1)
W_conv1 = tf.Variable(initial)
session.run(tf.global_variables_initializer())
W_conv1_value = session.run(W_conv1)
W_conv1_value.mean(), W_conv1_value.std()
(0.001365028, 0.08744488)
Мы используемtf.truncated_normal
Функция объявляет 32 случайных ядра свертки 5X5X1, что кажется довольно случайным.
PS: Спереди (5, 5, 1) представлены входная длина, ширина и цветовой канал, а сзади количество выходных выходов.Конечно, я сказал, что это 32, но это вовсе не 32 матрицы, должно быть (номер вывода цветового канала X) Ядро накопления томов, но у нас здесь только один цветовой канал, поэтому их всего 32, мы можем пройтиW_conv1_value.shape
Просмотрите реальный размер (текущий размер (5, 5, 1, 32))
Это ядро свертки соответствует маленькой матрице в середине рисунка выше.Его длина и ширина равны 5, а длина и ширина на рисунке равны 3. Конечно, мы можем изменить эту длину и ширину.Используя 5, наш опыт Ядро свертки может работать лучше в модели.
Далее мы выполним самую важную операцию свертки.Как видно из приведенного выше рисунка, для выполнения свертки трехмерные данные должны быть свернуты с соответствующим ядром свертки.На самом деле, мы также можем видеть важную свертка на рисунке Вещи, размер шага свертки - это позиция, в которую перемещается каждый ящик (размер шага на рисунке равен 2)
Есть и более тайное знание.Вы заметили, что данные на картинке изначально были данными 7Х7, но после преобразования ядром свертки они становятся 3Х3, что влияет на размер изображения после свертки, не только на размер шага, но и размер кадра, если ваш блок равен 7, на картинке осталось только одно значение, поэтому мы избегаем уменьшения размера, мы используем окружающий отступ 0, чтобы свертка самой краевой позиции также стала центром блока , с одной стороны, чтобы избежать потери данных края, с одной стороны, он также может выделить данные края (периферия все 0)
Tensorflow инкапсулировал за нас все вышеперечисленные методы.Мы можем менять министра и метод заполнения, пока передаем параметры в прошлом.Ну и теперь мы можем официально "катить"
session.run(tf.global_variables_initializer())
v = session.run(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='SAME'), feed_dict={x: data})
Теперь посмотрим после рулонаv
изshape
v.shape
(50, 28, 28, 32)
50 представляет 50 данных, (28, 28) представляет собой размерность изображения, это 32 количество ядер свертки, 50 и 32 должны быть фиксированными, это не сложно понять, давайте посмотрим, почему объем "ядра свертки" ",картинка до сих пор держится в 28Х28,это тоже одна из занимающихся Жихупроблема, теперь решим экспериментально
Сначала мы видимtf.nn.conv2d
Функция, он принимает четыре параметра, первое изображение, второе ядро свертки, третий размер шага и четвертый метод свертки.
Первая проблема заключается в том, что после завершения рулона он должен стать 24 X 24. Это понимание правильное. Мы меняем значение padding на VALID и запускаем его снова.
session.run(tf.global_variables_initializer())
v = session.run(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='VALID'), feed_dict={x: data})
v.shape
(50, 24, 24, 32)
Мы получили изображение 24 X 24. В чем разница между SAME и VALID? Эта разница является причиной того, что 0 не заполняется 0. SAME заполняет 0 вокруг изображения, чтобы получить 28 X 28
Мы также обнаружили, что есть также параметр strides, который представляет собой размер шага, заполняемый спереди, а длина и ширина размера шага задаются двумя средними битами (верхние два бита относятся к входу, первый один - количество входных изображений, последний - цветовой канал изображения), здесь мы используем 1 шаг, попробуем 2 шага
v = session.run(tf.nn.conv2d(x_image, W_conv1, strides=[1, 2, 2, 1], padding='SAME'), feed_dict={x: data})
v.shape
(50, 14, 14, 32)
Конечно же, выходное изображение стало 1/2 от 28.
Далее нам нужно кинуть значение свертки в функцию нейрона.Чтобы быть реалистичным, мы добавляем смещениеb_conv1
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
b_conv1 = bias_variable([32])
Здесь мы используем 0,1 для инициализации смещения, следующий шаг — добавить его в функцию нейрона, здесь мы используем распространение массивов numpy для передачи b_conv1 во все измерения 28X28.
h_conv1 = tf.nn.relu(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='SAME') + b_conv1)
v = session.run(h_conv1, feed_dict={x: data})
v.shape
(50, 28, 28, 32)
Мы видим, что данные, сгенерированные нейронной функцией после свертки, составляют (50X28X28X32), а окончательная размерность изменена с 1 на 32, поэтому мы должны использовать точечный метод для уменьшения размерности данных, здесь мы используем метод сверточный пул
Как видно из вышеизложенного, на самом деле очень просто выбрать самый большой
h_pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
Параметры здесь очень простые и я не буду их представлять, после «похудения» размерность данных меняется с (50, 28, 28, 32) на (50, 14, 14, 32), что составляет сократился в 4 раза.
На этом наш первый слой свертки закончился, а следующий слой это второй слой свертки.Зачем нам его снова накатывать, ведь предыдущий слой слишком мало научился, и нам нужно усилить обучение.Этот слой такой же, как и первый слой. слой не имеет значения, поэтому мы просто пропустим этот слой
Вставьте код напрямую (функция не будет скопирована, она есть в документе)
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
полносвязный слой
Когда мы завершаем двухуровневую свертку, наши данные становятся четырехмерным массивом (50, 7, 7, 64).Мы знаем, что наше традиционное машинное обучение фактически использует двумерные массивы в качестве обучающих данных (X представляет функцию, Y представляет выборку), поэтому полносвязный слой должен «обратить объем» свертки, чтобы вы могли легко подключиться к традиционному машинному обучению позже, а данные, которые нам нужны в конце, также являются двумерными выходными данными (для куча данных Унифицированный прогноз, поэтому он здесь называется двумерным), но здесь следует отметить, что полносвязный слой не является выходным слоем, поэтому мы можем задать размерность вывода по желанию, и, наконец, выходной слой закреплен, а затем аналогичная операция полносвязного слоя может вывести то, что мы хотим вывести. Измерение, здесь мы смотрим на переменную веса полносвязного слоя.
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
Здесь мы объявляем весовые переменные полносвязного слояW_fc1
и смещениеb_fc1
, мы можем видетьW_fc1
изshape
Как много
session.run(tf.global_variables_initializer())
session.run(W_fc1).shape
(3136, 1024)
Мы видим, что на самом деле это двумерный массив с размерностью (3136,1024), первое измерение связано с входными данными, а второе измерение влияет на выходное измерение.Мы использовалиtf.nn.conv2d
Операция свертки для преобразования изображения, в полностью связанном слое мы должны использовать матричные операции для преобразования наших размеров.
Операции с матрицами очень интересны. Мы на самом деле упоминали ранее, то есть реализация уменьшения размерности PCA заключается в использовании операций с матрицами для уменьшения размерности. Мы делим данные на X (признак) и Y (количество). После операции с матрицей , мы Количество констант может быть достигнуто, но функции меняются. Это очень мощно. Мы можем изменить параметры матрицы, чтобы динамически изменять количество наших функций.
Однако матричные операции также имеют определенные ограничения, то есть матрицы двух операций должны быть такими же, как длина первой и ширина второй.Это связано с характеристиками матричных операций.Подробности см. к матричным операциям, связаннымматериал
Итак, для выполнения матричных операций первое, что мы делаем, это меняем входные данные.shape
, пусть он изменится с четырехмерного на двумерный, чтобы его можно было сравнить с нашей матрицей весовW_fc1
выполнять операции
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
Мы просто используемtf.reshape
Выходная переменная после свертки второго слоя может быть преобразована в (50, 7764) размерность, так что мы можем напрямую сравнивать весовую матрицу сW_fc1
выполнять операции
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
Здесь мы напрямую помещаем вычисленное значение в функцию активации, чтобы завершить функцию полносвязного слоя.
выходной слой
На самом деле выходной слой очень похож на полносвязный слой.Мы просто преобразуем предыдущие переменные в размеры, которые хотим вывести.Прежде чем делать этот выходной слой, мы должны сначала построить слой.Dropout
слой, который может эффективно избежать проблемы переобучения нейронной сети.Подробности см. в этой статье.бумага
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
Поскольку принцип аналогичен полносвязному слою, я не буду подробно описывать выходной слой.
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
Мы можем видеть, что наш вывод в конце
session.run(tf.global_variables_initializer())
session.run(y_conv, feed_dict={x:data, keep_prob:0.5}).shape
(50, 10)
хорошо, мы, наконец, получаем двумерный массив с 50 результатами прогнозирования (вывод использует метод OneHot)
обратное распространение
Ранее мы получили результат вывода при начальном случайном весе, но этот результат определенно неверен.Мы должны изменить модель, изменив вес каждого слоя, чтобы сделать модель все умнее и умнее, поэтому первым шагом мы должны "самостоятельно" -отражать», чтобы понять, насколько вы далеки от реальных результатов
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
мы представляемy_
как фактическое значение (наша модель предсказывает значениеy
), мы используем здесь перекрестную энтропию, чтобы судить о точности предсказания, но бесполезно знать, что «вы не правы», мы должны «исправить», здесь мы используемAdamOptimizer
Оптимизируйте алгоритм для обратного распространения наших ошибок и позвольте модели «отражать и исправлять»
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
Здесь почти то же самое, мы сформировали замкнутый цикл, прогнозирование->оценка->коррекция->предсказание->..., только пусть он продолжает тренироваться, пока мы не сможем принять его ошибку и наша модель не будет обучена
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
session.run(tf.initialize_all_variables())
for i in range(18000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0}, session=session)
print("step %d, training accuracy %g"%(i, train_accuracy))
if abs(train_accuracy - 1) < 0.01:
break
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}, session=session)
Поскольку мы используемOneHot
метод для вывода предикторов, поэтому мы будем использоватьtf.argmax
Чтобы получить реальное число, которое мы хотим, после 20 000 раундов обучения наша точность может достигать 99%, пока сверточная нейронная сеть проявила свою силу.
Суммировать
Сверточная нейронная сеть является очень важной частью глубокого обучения.Чтобы понять свертку, вы должны знать, почему она используется и каковы преимущества ее использования. В общем, свертка не очень новая вещь, она давно используется в обработке сигналов, но в обработке изображений, поскольку она может сохранять информацию о размерах изображения, она сияет в области глубокого обучения, которое также может быть воспринимается как «Да, золото всегда сияет».
Цитировать
Woohoo.tensor fly.Can/TF doc/tutor…
Матричные операции
Популярное понимание сверточной нейронной сети
Dropout