Вкратце мой вопрос: детально ли описана ниже сеть долгосрочной краткосрочной памяти, предназначенная для генерации новых танцевальных последовательностей с учетом данных тренировок танцевальных последовательностей?
Контекст: я работаю с танцором, который хочет использоватьнейронная сеть для генерации новых танцевальных последовательностей.Она прислала мне черновую бумагу 2016 , которая выполнила эту задачу, используя сеть LSTM со слоем сети плотности смеси в конце.Однако после добавления слоя MDN в мою сеть LSTM моя потеря становится отрицательной, и результаты кажутся хаотичными.Это может быть связано с очень маленькими данными обучения, но я хотел бы проверить основы модели, прежде чем увеличивать размер данных тренировки.Если кто-то может посоветовать, упускает ли из представленной ниже модели что-то фундаментальное (что весьма вероятно), я был бы полностью признателен за их отзывы.
Образец данных, которые я передаю в сеть (X
ниже)имеет форму (626, 55, 3), которая соответствует 626 моментальным снимкам 55 позиций тела, каждая из которых имеет 3 координаты (x, y, затем z).Итак, X 1 [11] [2] - это позиция z 11-й части тела в момент времени 1:
import requests
import numpy as np
# download the data
requests.get('https://s3.amazonaws.com/duhaime/blog/dancing-with-robots/dance.npy')
# X.shape = time_intervals, n_body_parts, 3
X = np.load('dance.npy')
Чтобы убедиться, что данные были извлечены правильно, я визуализирую первыйнесколько кадров X
:
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt
from IPython.display import HTML
from matplotlib import animation
import matplotlib
matplotlib.rcParams['animation.embed_limit'] = 2**128
def update_points(time, points, X):
arr = np.array([[ X[time][i][0], X[time][i][1] ] for i in range(int(X.shape[1]))])
points.set_offsets(arr) # set x, y values
points.set_3d_properties(X[time][:,2][:], zdir='z') # set z value
def get_plot(X, lim=2, frames=200, duration=45):
fig = plt.figure()
ax = p3.Axes3D(fig)
ax.set_xlim(-lim, lim)
ax.set_ylim(-lim, lim)
ax.set_zlim(-lim, lim)
points = ax.scatter(X[0][:,0][:], X[0][:,1][:], X[0][:,2][:], depthshade=False) # x,y,z vals
return animation.FuncAnimation(fig,
update_points,
frames,
interval=duration,
fargs=(points, X),
blit=False
).to_jshtml()
HTML(get_plot(X, frames=int(X.shape[0])))
Это создает небольшую танцевальную последовательность, подобную этой:
Пока все хорошо,Далее я центрирую элементы измерений x, y и z:
X -= np.amin(X, axis=(0, 1))
X /= np.amax(X, axis=(0, 1))
Визуализация результирующего X
с помощью HTML(get_plot(X, frames=int(X.shape[0])))
показывает, что эти строки центрируют данные очень хорошо.Затем я строю саму модель, используя Sequential API в Keras:
from keras.models import Sequential, Model
from keras.layers import Dense, LSTM, Dropout, Activation
from keras.layers.advanced_activations import LeakyReLU
from keras.losses import mean_squared_error
from keras.optimizers import Adam
import keras, os
# config
look_back = 32 # number of previous time frames to use to predict the positions at time i
lstm_cells = 256 # number of cells in each LSTM "layer"
n_features = int(X.shape[1]) * int(X.shape[2]) # number of coordinate values to be predicted by each of `m` models
input_shape = (look_back, n_features) # shape of inputs
m = 32 # number of gaussian models to build
# set boolean controlling whether we use MDN or not
use_mdn = True
model = Sequential()
model.add(LSTM(lstm_cells, return_sequences=True, input_shape=input_shape))
model.add(LSTM(lstm_cells, return_sequences=True))
model.add(LSTM(lstm_cells))
if use_mdn:
model.add(MDN(n_features, m))
model.compile(loss=get_mixture_loss_func(n_features, m), optimizer=Adam(lr=0.000001))
else:
model.add(Dense(n_features, activation='tanh'))
model.compile(loss=mean_squared_error, optimizer='sgd')
model.summary()
Как только модель построена, я размещаю данные в X
для подготовки к обучению.Здесь мы хотим предсказать положения x, y, z 55 частей тела в определенное время, изучив положения каждой части тела на предыдущих look_back
временных срезах:
# get training data in right shape
train_x = []
train_y = []
n_time, n_obs, n_attrs = [int(i) for i in X.shape]
for i in range(look_back, n_time-1, 1):
train_x.append( X[i-look_back:i].reshape(look_back, n_obs * n_attrs) )
train_y.append( X[i+1].ravel() )
train_x = np.array(train_x)
train_y = np.array(train_y)
И, наконец, яобучаем модель:
from livelossplot import PlotLossesKeras
# fit the model
model.fit(train_x, train_y, epochs=1024, batch_size=1, callbacks=[PlotLossesKeras()])
После тренировки я визуализирую новые временные интервалы, созданные моделью:
# generate `n_frames` of new output time slices
n_frames = 3000
# seed the data to plot with the first `look_back` animation frames
data = X[0:look_back]
x0, x1, x2 = [int(i) for i in train_x.shape]
d0, d1, d2 = [int(i) for i in data.shape]
for i in range(look_back, n_frames, 1):
# get the model's prediction for the next position of points at time `i`
result = model.predict(train_x[i].reshape(1, x1, x2))
# if using the mixed density network, pull out vals that describe vertex positions
if use_mdn:
result = np.apply_along_axis(sample_from_output, 1, result, n_features, m, temp=1.0)
# reshape the result into the form of rows in `X`
result = result.reshape(1, d1, d2)
# push the result into the shape of `train_x` observations
stacked = np.vstack((data[i-look_back+1:i], result)).reshape(1, x1, x2)
# add the result to the `train_x` observations
train_x = np.vstack((train_x, stacked))
# add the result to the dataset for plotting
data = np.vstack((data[:i], result))
Если я установлю use_mdn
на False
выше и вместо этого используюпростая потеря суммы квадратов ошибок (потеря L2), тогда результирующая визуализация кажется немного жуткой, но все же имеет в целом человеческую форму.
Однако, если я установлю use_mdn
на True
и используюПользовательская функция потери MDN, результаты довольно странные.Я признаю, что уровень MDN добавляет огромное количество параметров, которые необходимо обучить, и, вероятно, требует большего количества обучающих данных на порядки для достижения результата, такого же человеческого, как выход функции потерь L2.
Тем не менееЯ хотел бы спросить, видят ли другие, кто работал с нейронными моделями более широко, чем я, что-то в корне неверное с вышеуказанным подходом.Любое понимание этого вопроса было бы чрезвычайно полезно.