TensorFlow - почему эта регрессия sofmax ничего не изучает?
Я стремлюсь делать большие вещи с TensorFlow, но я пытаюсь начать с малого.
У меня есть маленькие серые квадраты (с небольшим шумом), и я хочу классифицировать их по цвету (например, 3 категории: черный, серый, белый). Я написал небольшой класс Python для генерации квадратов и 1-горячих векторов и изменил их базовый пример MNIST, чтобы добавить их.
Но он ничему не научится - например, для 3 категорий он всегда предполагает ≈33% правильности.
import tensorflow as tf
import generate_data.generate_greyscale
data_generator = generate_data.generate_greyscale.GenerateGreyScale(28, 28, 3, 0.05)
ds = data_generator.generate_data(10000)
ds_validation = data_generator.generate_data(500)
xs = ds[0]
ys = ds[1]
num_categories = data_generator.num_categories
x = tf.placeholder("float", [None, 28*28])
W = tf.Variable(tf.zeros([28*28, num_categories]))
b = tf.Variable(tf.zeros([num_categories]))
y = tf.nn.softmax(tf.matmul(x,W) + b)
y_ = tf.placeholder("float", [None,num_categories])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
# let batch_size = 100 --> therefore there are 100 batches of training data
xs = xs.reshape(100, 100, 28*28) # reshape into 100 minibatches of size 100
ys = ys.reshape((100, 100, num_categories)) # reshape into 100 minibatches of size 100
for i in range(100):
batch_xs = xs[i]
batch_ys = ys[i]
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
xs_validation = ds_validation[0]
ys_validation = ds_validation[1]
print sess.run(accuracy, feed_dict={x: xs_validation, y_: ys_validation})
Мой генератор данных выглядит так:
import numpy as np
import random
class GenerateGreyScale():
def __init__(self, num_rows, num_cols, num_categories, noise):
self.num_rows = num_rows
self.num_cols = num_cols
self.num_categories = num_categories
# set a level of noisiness for the data
self.noise = noise
def generate_label(self):
lab = np.zeros(self.num_categories)
lab[random.randint(0, self.num_categories-1)] = 1
return lab
def generate_datum(self, lab):
i = np.where(lab==1)[0][0]
frac = float(1)/(self.num_categories-1) * i
arr = np.random.uniform(max(0, frac-self.noise), min(1, frac+self.noise), self.num_rows*self.num_cols)
return arr
def generate_data(self, num):
data_arr = np.zeros((num, self.num_rows*self.num_cols))
label_arr = np.zeros((num, self.num_categories))
for i in range(0, num):
label = self.generate_label()
datum = self.generate_datum(label)
data_arr[i] = datum
label_arr[i] = label
#data_arr = data_arr.astype(np.float32)
#label_arr = label_arr.astype(np.float32)
return data_arr, label_arr
4 ответа
Хотя ответы dga и syncd были полезны, я попытался использовать инициализацию с ненулевым весом и большие наборы данных, но безрезультатно. Наконец-то сработало использование другого алгоритма оптимизации.
Я заменил:
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
с
train_step = tf.train.AdamOptimizer(0.0005).minimize(cross_entropy)
Я также встроил тренинг для цикла в другой цикл для обучения в течение нескольких эпох, что привело к конвергенции следующим образом:
===# EPOCH 0 #===
Error: 0.370000004768
===# EPOCH 1 #===
Error: 0.333999991417
===# EPOCH 2 #===
Error: 0.282000005245
===# EPOCH 3 #===
Error: 0.222000002861
===# EPOCH 4 #===
Error: 0.152000010014
===# EPOCH 5 #===
Error: 0.111999988556
===# EPOCH 6 #===
Error: 0.0680000185966
===# EPOCH 7 #===
Error: 0.0239999890327
===# EPOCH 8 #===
Error: 0.00999999046326
===# EPOCH 9 #===
Error: 0.00400000810623
РЕДАКТИРОВАТЬ - ПОЧЕМУ ЭТО РАБОТАЕТ: Я полагаю, что проблема заключалась в том, что я не выбирал вручную хороший график обучения, и Адам смог автоматически создать лучший график обучения.
Для начала попробуйте инициализировать матрицу W случайными значениями, а не нулями - вы не дадите оптимизатору ничего, с чем можно работать, когда выходные данные будут иметь все нули для всех входов.
Вместо:
W = tf.Variable(tf.zeros([28*28, num_categories]))
Пытаться:
W = tf.Variable(tf.truncated_normal([28*28, num_categories],
stddev=0.1))
Вы проблема в том, что ваши градиенты увеличиваются / уменьшаются без границ, в результате чего функция потерь становится нан.
Посмотрите на этот вопрос: почему пример TensorFlow не работает при увеличении размера пакета?
Кроме того, убедитесь, что вы запускаете модель для достаточного количества шагов. Вы выполняете его только один раз через набор данных поезда (100 раз * 100 примеров), и этого недостаточно для его сближения. Увеличьте его как минимум до 2000 (пробежав 20 раз по вашему набору данных).
Изменить (не могу комментировать, поэтому я добавлю свои мысли здесь): Суть поста, на который я ссылаюсь, заключается в том, что вы можете использовать GradientDescentOptimizer
До тех пор, пока вы делаете скорость обучения примерно 0,001. Вот в чем проблема, ваша скорость обучения была слишком высока для функции потери, которую вы использовали.
В качестве альтернативы, используйте другую функцию потерь, которая не так сильно увеличивает / уменьшает градиенты. использование tf.reduce_mean
вместо tf.reduce_sum
в определении crossEntropy
,
Нашел этот вопрос, когда у меня возникла похожая проблема.. Я исправил свой, масштабируя функции.
Небольшая предыстория: я следовал учебному пособию по тензорному потоку, однако я хотел использовать данные из Kaggle ( см. Данные здесь) для моделирования, но вначале я обнаружил, что у меня та же проблема: модель просто не учится.. после раундов поиска неисправностей я понял, что данные Kaggle были в совершенно другом масштабе. Поэтому я масштабировал данные так, чтобы они имели ту же шкалу (0,1), что и набор данных MNIST тензорного потока.
Просто подумал, что я бы добавил свои два цента здесь.. на случай, если некоторые новички, которые пытаются следовать настройкам учебника, застрянут, как я =)