MIPT, Advanced ML, Spring 2018
HW #7: CNN models
Sergey Kolesnikov, scitator@gmail.com
Оформление дз:
ml.course.mipt@gmail.com
ML2018_fall_<номер_группы>_<фамилия>
, к примеру -- ML2018_fall_495_ivanov
<фамилия>_<группа>_task<номер>.ipnb, к примеру
-- ivanov_401_task7.ipnb
Вопросы:
ml.course.mipt@gmail.com
ML2018_fall Question <Содержание вопроса>
Ниже приводится список вопросов, с ответами на которые может быть полезно разобраться для понимания темы.
Вопрос 1: Чем отличаются современные сверточные сети от сетей 5 летней давности?
Они стали куда более глубокими и распиаренными. Вообще 5 лет назад не слышал о нейросетях, а сейчас каждый второй знакомый о них что-то знает.
Вопрос 2: Какие неприятности могут возникнуть во время обучения современных нейросетей?
Как показало выполнение этого задания, неприятности могут быть как физического характера (мигрень, нервные тики, бессонница, рвотные позывы), так и психологического (желание кпмнуться). Но это еще не все. На более сложных нейросетях во-первых, все это усиливается, а во-вторых, добавляются проблемы непосредственно самих нейросетей: например, возникает переобучение, то есть нейросетка будет запоминать данные, а не закономерности в них. А если делать дропаут, то можно забыть что-то важное. Еще очень редко, но иногда случается, что отмереть могут все нейроны.
Вопрос 3: У вас есть очень маленький датасет из 100 картинок, классификация, но вы очень хотите использовать нейросеть, какие неприятности вас ждут и как их решить? что делать если первый вариант решения не заработает?
Во-первых, нейрости должны обучаться на ооочень большом объеме данных, а у нас 100 картинок. Это сравнительно мало, так что ничего там не обучится. Чтобы решить это, надо сделать аугментацию, то есть надо все картинки как-то размножить, немного изменив (типа отразить, повернуть и все такое).
Но это только цветочки. Осторожно, впереди ягодки! Во-первых, вам надо будет поставить 100500 питоновских библиотек на вашу систему, во-вторых, скорее всего, вам придется писать код на Python (очевидные проблемы: нет статической типизации, все источники в интернете говнокодят аббревиатурами и непонятными именами, нет адекватной проверки написанного, но не выполненного кода), в-третьих, нужно будет заботать нейросети и прочитать тонны документации по выбранной либе, а это неинтересно.
Лично мое решение — вообще не использовать нейросети и машинное обучение. Камон, 100 картинок можно разметить вручную, выйдет куда точнее и быстрее.
Вопрос 4: Можно ли сделать стайл трансфер для музыки и как?
Да, в какой-то степени можно. Есть же стайл-трансфер для картинок. Поэтому можно представить музыку как картинку, сделать стайл-трансфер и получить аудио обратно. Проблема в том, что аудио - это одномерный массив, причем в одной секунде находится около 44000 точек, а песни обычно длятся от 3 минут. Поэтому работать с сырым аудио сложно, системы распознаваия речи обычно работают с низкоразмерными аудио.
Чтобы получить из аудио изображение, нужно применить оконное преобразование Фурье, которое берет музыку и получает два изображения: спектрограмму и фазовую картинку (на фазовую картинку забиваем). Для получения спектрограммы берется по 2000 точек со сдвигом примерно 500 точек. Для каждыйх таких 2000 точек применяется дискретное преобразование Фурье (по сути замена базиса), и новые координаты выстравиваются в столбик. Так получилась спектрограмма. По оси x - время, по оси y - частоты.
Обратное получают картинку с помощью преобразования Гриффина-Лима. Однако нужно будет решать проблемы: надо получить новую фазу, а также запретить сильное перемешивание по вертикали (так как поменять частоты с низких на высокие или наоборот сильно все испортит).
Решив эти проблемы, получим аудио обратно.
(please read it at least diagonally)
Common ways to get bonus points are:
In [1]:
# Load data. It may work slow.
!mkdir cifar10 && curl -o cifar-10-python.tar.gz https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz && tar -xvzf cifar-10-python.tar.gz -C cifar10
In [0]:
import _pickle as pickle
import os
import time
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn
%matplotlib inline
In [3]:
tf.__version__
Out[3]:
In [4]:
tf.test.is_gpu_available()
Out[4]:
In [0]:
tf.set_random_seed(42)
In [0]:
def load_CIFAR_batch(filename):
""" load single batch of cifar """
with open(filename, 'rb') as f:
datadict = pickle.load(f, encoding='iso-8859-1')
X = datadict['data']
Y = datadict['labels']
X = X.reshape(10000, 3, 32, 32).astype("float")
Y = np.array(Y)
return X, Y
def load_CIFAR10(ROOT):
""" load all of cifar """
xs = []
ys = []
for b in range(1,6):
f = os.path.join(ROOT, 'data_batch_%d' % (b, ))
X, Y = load_CIFAR_batch(f)
xs.append(X)
ys.append(Y)
Xtr = np.concatenate(xs)
Ytr = np.concatenate(ys)
del X, Y
Xte, Yte = load_CIFAR_batch(os.path.join(ROOT, 'test_batch'))
return Xtr, Ytr, Xte, Yte
In [0]:
plt.rcParams['figure.figsize'] = (10.0, 8.0)
cifar10_dir = './cifar10/cifar-10-batches-py'
X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)
In [8]:
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
num_classes = len(classes)
samples_per_class = 7
for y, cls in enumerate(classes):
idxs = np.flatnonzero(y_train == y)
idxs = np.random.choice(idxs, samples_per_class, replace=False)
for i, idx in enumerate(idxs):
plt_idx = i * num_classes + y + 1
plt.subplot(samples_per_class, num_classes, plt_idx)
plt.imshow(X_train[idx].astype('uint8').transpose(1, 2, 0))
plt.axis('off')
if i == 0:
plt.title(cls)
plt.show()
In [0]:
input_X = tf.placeholder('float32', shape=(None, 32, 32, 3), name='X')
input_y = tf.placeholder('int64', shape=(None, 1), name='y')
is_training = tf.placeholder('bool', name='train')
layer = tf.layers.conv2d(
inputs=input_X,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
layer = tf.layers.max_pooling2d(
inputs=layer,
pool_size=[3, 3],
strides=2)
layer = tf.nn.local_response_normalization(
layer,
depth_radius=4,
bias=1.0,
alpha=0.001 / 9.0,
beta=0.75)
layer = tf.layers.conv2d(
inputs=layer,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
layer = tf.nn.local_response_normalization(
layer,
depth_radius=4,
bias=1.0,
alpha=0.001 / 9.0,
beta=0.75)
layer = tf.layers.max_pooling2d(
inputs=layer,
pool_size=[2, 2],
strides=2)
layer = tf.reshape(
layer,
[-1, 7 * 7 * 64])
layer = tf.layers.dense(
inputs=layer,
units=384,
activation=tf.nn.relu)
layer = tf.layers.dense(
inputs=layer,
units=192,
activation=tf.nn.relu)
dropout = tf.layers.dropout(
inputs=layer,
rate=0.4,
training=is_training)
logits = tf.layers.dense(
inputs=layer,
units=10)
In [0]:
loss = tf.losses.sparse_softmax_cross_entropy(labels=input_y, logits=logits)
optimizer_step = (tf.train.GradientDescentOptimizer(0.001, use_locking=True).minimize(loss))
predictions = tf.argmax(input=logits, axis=1)
accuracy = tf.metrics.accuracy(labels=input_y, predictions=predictions)
In [0]:
def train_fn(X, y, sess):
'''
returns tuple (loss, accuracy) for model train phase
'''
X = np.transpose(X, (0, 2, 3, 1))
y = np.reshape(y, (-1, 1))
sess.run(optimizer_step, {input_X: X, input_y: y, is_training: True})
current_loss = sess.run(loss, {input_X: X, input_y: y, is_training: True})
current_accuracy = sess.run(accuracy, {input_X: X, input_y: y, is_training: True})[0]
return (current_loss, current_accuracy)
def eval_fn(X, y, sess):
'''
returns tuple (loss, accuracy) for model evaluation phase
'''
X = np.transpose(X, (0, 2, 3, 1))
y = np.reshape(y, (-1, 1))
current_loss = sess.run(loss, {input_X: X, input_y: y, is_training: False})
current_accuracy = sess.run(accuracy, {input_X: X, input_y: y, is_training: False})[0]
return (current_loss, current_accuracy)
def predict_fn(X, sess):
'''
returns y_pred for model predict phase
'''
'''
Функция не используется.
'''
assert(False)
In [0]:
def iterate_minibatches(inputs, targets, batchsize, shuffle=False):
assert len(inputs) == len(targets)
if shuffle:
indices = np.arange(len(inputs))
np.random.shuffle(indices)
for start_idx in range(0, len(inputs) - batchsize + 1, batchsize):
if shuffle:
excerpt = indices[start_idx:start_idx + batchsize]
else:
excerpt = slice(start_idx, start_idx + batchsize)
yield inputs[excerpt], targets[excerpt]
In [0]:
num_epochs = 200
batch_size = 16
In [0]:
X_val = X_test
y_val = y_test
In [0]:
train_losses = []
train_accs = []
valid_losses = []
valid_accs = []
In [16]:
with tf.Session() as sess:
tf.global_variables_initializer().run()
tf.local_variables_initializer().run()
for epoch in range(num_epochs):
# In each epoch, we do a full pass over the training data:
train_loss = 0
train_acc = 0
train_batches = 0
start_time = time.time()
for batch in iterate_minibatches(X_train, y_train, batch_size):
inputs, targets = batch
train_loss_batch, train_acc_batch = train_fn(inputs, targets, sess)
train_loss += train_loss_batch
train_acc += train_acc_batch
train_batches += 1
# And a full pass over the validation data:
valid_loss = 0
valid_acc = 0
valid_batches = 0
for batch in iterate_minibatches(X_val, y_val, batch_size):
inputs, targets = batch
valid_loss_batch, valid_acc_batch = eval_fn(inputs, targets, sess)
valid_loss += valid_loss_batch
valid_acc += valid_acc_batch
valid_batches += 1
train_losses += [train_loss / train_batches]
train_accs += [train_acc / train_batches * 100]
valid_losses += [valid_loss / valid_batches]
valid_accs += [valid_acc / valid_batches * 100]
# Then we print the results for this epoch:
print("Epoch {} of {} took {:.3f}s".format(epoch + 1, num_epochs, time.time() - start_time))
print(" train loss:\t\t{:.6f}".format(train_losses[-1]))
print(" train accuracy:\t\t{:.2f} %".format(train_accs[-1]))
print(" valid loss:\t\t{:.6f}".format(valid_losses[-1]))
print(" valid accuracy:\t\t{:.2f} %".format(valid_accs[-1]))
plt.figure(figsize=(15, 6))
plt.subplot(1, 2, 1)
plt.plot(np.arange(num_epochs) + 1, train_losses, label='train loss')
plt.plot(np.arange(num_epochs) + 1, valid_losses, label='valid loss')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(np.arange(num_epochs) + 1, train_accs, label='train accuracy')
plt.plot(np.arange(num_epochs) + 1, valid_accs, label='valid accuracy')
plt.legend()
plt.show()
test_acc = 0
test_batches = 0
for batch in iterate_minibatches(X_test, y_test, 500):
inputs, targets = batch
_, acc = eval_fn(inputs, targets, sess)
test_acc += acc
test_batches += 1
print("Final results:")
print(" test accuracy:\t\t{:.2f} %".format(
test_acc / test_batches * 100))
if test_acc / test_batches * 100 > 92.5:
print("Achievement unlocked: mage 80 lvl")
else:
print("Feed more!")
A long ago in a galaxy far far away, when it was still more than an hour before deadline, i got an idea:
совпадает с какой-из нейросетей, нагугленных в инете. К счастью, на лекции так официально разрешили делать. Я использовал вот этот источник: http://www.aimechanic.com/2016/10/13/d242-tensorflow-cifar-10-tutorial-detailed-step-by-step-review-part-1/. Единственное, я убрал какие-то непонятные вещи из него (где считают всякие биасы, веса, локали и все такое).
How could i be so naive?!
Да запросто. Я нагугливал и другие архитектуры, но там такой говнокод, что понять, какие слои используются и с какими параметрами, вообще нереально.
я начал подгонять параметры. Так как у слоев нейросети параметров примерно 100500, то я даже не рискнул их трогать. Есть куда более разумные способы получить высший скор. Во-первых, батчсайз. Я попробовал его увеличить — скор упал. Попробовал уменьшить — скор возрос. Попробовал еще уменьшить — скор опять возрос. И так далее. Потом стало безумно бредово, и после первой эпохи скор был порядка 10-11%. Я расстроился и откатил все назад. В итоге выбрал батчсайз 16.
После 10 эпох мой скор был какой-то нормальный (порядка 70%), так что я увеличил число эпох до 25, и выбил около 80%. Затем я сделал 50, и там было уже 87%. Так как уже пора было спать, я не стал долго думать, поставил 200 эпох и уснул. Утром обнаружил 93%.
наконец-то это кончилось.
У меня есть еще тру стори, как колаб дисконнектился в середине вычислений, или по 10 минут не мор инициализировался. И еще много всякой параши происходило во время этого задания.
Конец.
In [0]: