Почему свёрточная нейронная сеть доходит только до 70% правильных ответов?

В учебных целях я написал нейронную сеть классификации цифр на основе хороших изображений из датасета Chars74k. Использовал я в основном TensorFlow, Keras использовал только для считывания изображений в массивы NumPy. У нейросети есть один свёрточный слой из свёртки 8х8 на 16 признаков, в качестве функции нелинейности используется ReLU, и подытоживается всё это слоем субдискредитации. Далее идёт обычный полносвязный слой с 4096 входами и 10 выходами. Путём подбора гиперпараметров точность достигает максимума 70%, а затем то возрастает, то падает. В чём может быть проблема? Проблема в архитектура сети (добавить или изменить слои) и/или в подборе гиперпараметров? Исходный код с датасетом можно просмотреть и тут: https://bitbucket.org/smolyardev/chars74k

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing import image
import os


class Batch:
    def __init__(self, data):
        self.i = 0
        self.data = data
        self.data_len = len(data)

    def next(self, step=100):
        if self.i + step < self.data_len:
            res = self.data[self.i:self.i + step]
            self.i += step
        else:
            res = self.data[self.i:]
            self.i = step - (self.data_len - self.i)
            res.extend(self.data[:self.i])
        return res


folder = 'data'
i = 0
train = []
for path in os.listdir(folder):
    imgs = "{}/{}".format(folder, path)
    if os.path.isdir(imgs) and path.startswith("Sample"):
        for ipath in os.listdir(imgs):
            img = "{}/{}".format(imgs, ipath)
            if os.path.isfile(img) and img.endswith(".png"):
                proc = image.load_img(img, target_size=(32, 32))
                data = image.img_to_array(proc)
                data /= 255
                y_data = np.zeros(10)
                y_data[i] = 1.
                train.append({"x": data, "y": y_data})
        i += 1

np.random.shuffle(train)

x = tf.placeholder(dtype=tf.float32, shape=(None, 32, 32, 3))
y = tf.placeholder(dtype=tf.float32, shape=(None, 10))

w1 = tf.Variable(tf.truncated_normal([8, 8, 3, 16], stddev=0.1))
b1 = tf.Variable(tf.constant(0., shape=[16]))

conv1 = tf.nn.conv2d(x, w1, strides=[1, 1, 1, 1], padding="SAME") + b1
h_conv1 = tf.nn.relu(conv1)
pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
flat1 = tf.reshape(pool1, [-1, 4096])

w2 = tf.Variable(tf.truncated_normal([4096, 10], stddev=0.1))
b2 = tf.Variable(tf.constant(0., shape=[10]))
h2 = tf.matmul(flat1, w2) + b2

y_conv = tf.nn.softmax(h2)
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_conv, logits=y))
train_step = tf.train.GradientDescentOptimizer(0.25).minimize(cross_entropy)
correct = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

batch = Batch(train)

for i in range(2000):
    next_tr = batch.next(100)
    n_x = [t['x'] for t in next_tr]
    n_y = [t['y'] for t in next_tr]
    _, res = sess.run((train_step, accuracy), feed_dict={x: n_x, y: n_y})
    if i % 100 == 0:
        print(res)
  • Вопрос задан
  • 1708 просмотров
Пригласить эксперта
Ответы на вопрос 4
Arseny_Info
@Arseny_Info
R&D engineer
Для ответа на такой вопрос не хватает логов обучения. Причем не только по трейну, но и по валидации (судя по коду, валидации сейчас вообще нет).

Гипотезы:
- лучше использовать хотя бы 2-3 сверточных слоя со свертками 3*3, чем один 8*8, т.к. это обеспечит больще нелинейности;
- learning rate = .25 может быть слишком большим, так что в итоге сеть начинает осциллировать вокруг локального минимума.
Ответ написан
begemot_sun
@begemot_sun
Программист в душе.
Давайте начнем с вопроса, что такое НС ?
Все очень просто. Это некая функция от множества переменных f(x1, ..., xn, k1, ... kn).
Что вы делаете, когда обучаете НС ?
Вы находите такое k1 .. kn, чтобы результат функции для всех примеров был с минимальным отклонением.
Т.о. вы осуществляете задачу аппроксимации в многомерном пространстве.
Далее.
Пример на пальцах (на плоскости).
У вас есть парабола. Вы пытаете её аппроксимировать линейной функцией: f(x) = ax+b.
Как думаете какая у вас будет точность ? Точно не 100%.
Т.о. любая аппроксимация, это процесс приближения одной функции к набору точек (или к другой функции).
И если вас не устраивает точность обучения, то достаточно увеличить сложность сети, либо в ширину, либо в глубину. Т.о. вы увеличите сложность аппроксимирующей функции.
Но тут надо смотреть на такое явление как переобучение.
На пальцах, это когда вы линию пытаетесь аппроксимировать параболой. Ваша парабола каждый раз будет вырождаться в линию, а на самом деле это вам не надо. Вам нужно чтобы аппроксимирующая функция обобщила все свойста аппроксимируемой.

Как вам такое объяснение ? :)
Ответ написан
@Tati_m
Скажите, вам будет интересно поучаствовать в проекте по обучения нейронной сети (распознавание изображений)?
Ответ написан
@AlexSku
не буду отвечать из-за модератора
В Alexnet аж 25 слоёв.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы