microsoft / CNTK

Microsoft Cognitive Toolkit (CNTK), an open source deep-learning toolkit
https://docs.microsoft.com/cognitive-toolkit/
Other
17.5k stars 4.29k forks source link

LSTM RNN model C++ #3653

Open Ivashar opened 5 years ago

Ivashar commented 5 years ago

Hello. Can you please tell me how to describe a neural network with 2 hidden layers of 256 LSTM cells each and an output layer consisting of one LSTM unit ???

FunctionPtr classifierRoot = features;
auto pastValueRecurrenceHook = [](const Variable& x) { return PastValue(x); };

for(int k = 0; k < 2; ++k){

for (size_t i = 0; i < numLSTMLayers; ++i) {
    classifierRoot = LSTMPComponentWithSelfStabilization<float>(
        classifierRoot,
        { hiddenDim },
        { cellDim },
        pastValueRecurrenceHook,
        pastValueRecurrenceHook,
        device).first;
}

} auto thoughtVectorFunction = Sequence::Last(classifierRoot);

return FullyConnectedLinearLayer(thoughtVectorFunction, numOutputClasses, device, outputName);

labels = InputVariable({ numOutputClasses }, DataType::Float, L"labels"); trainingLoss = CrossEntropyWithSoftmax(lstmModel, labels, L"lossFunction"); prediction = ClassificationError(lstmModel, labels, L"classificationError");

//create learner 
paramLearner = AdamLearner(lstmModel->Parameters(),
                            learningRate,
                                momentumSchedule, 
                                false);

//create trainer
trainer = CreateTrainer(lstmModel, trainingLoss, prediction, vector<LearnerPtr>({ paramLearner }));

это приводит к ошибки About to throw exception 'Operation 'TransposeTimes': Operand 'Placeholder('lstm Model', [2], [#])' has dynamic axes, that do not match the dynamic axes '[*, #]' of the other operands.'

elevir commented 5 years ago

@Ivashar hello!

Seems like you lost one of dynamic axes by Sequence::Last(classifierRoot);. Try to define input variables which working with output of lstm model as in code below:

InputVariable({ numOutputClasses }, DataType::Float, L"labels", { Axis::DefaultBatchAxis() });
Ivashar commented 5 years ago

@Ivashar hello!

Seems like you lost one of dynamic axes by Sequence::Last(classifierRoot);. Try to define input variables which working with output of lstm model as in code below:

InputVariable({ numOutputClasses }, DataType::Float, L"labels", { Axis::DefaultBatchAxis() });

Спасибо за ответ. Подскажите пожалуйста, как правильно создать сеть с N входами, с 2 скрытыми слоями LSTM по M юнитов, одним выходным юнитом LSTM ??? У меня что то ерунда получается.

elevir commented 5 years ago

@Ivashar отвечу на двух языках, чтобы другие тоже смогли понять мой ответ :) У вас в цикле два слоя создаются и у каждого размер скрытых состояний равен hiddendim. Если он равен N, то на выходе модели размерность тоже будет N. Попробуйте без цикла создать первый слой с размером скрытых состояний равным N, а второй слой с размером скрытых состояний равным 1. Если я, конечно, правильно понял суть проблемы.

I will answer on two languages in order to other users will be able to understand my answer too :) You create two layers with hidden state size eqauls to hiddendim in loop. If size of hiddendim equals to N then output of model will be N too. Try to create lstm layers without loop, first layer must have hidden dim equals to N and second layer must have hidden dim equals to 1. Hope that I correctly understood the problem.

Ivashar commented 5 years ago

@Ivashar отвечу на двух языках, чтобы другие тоже смогли понять мой ответ :) У вас в цикле два слоя создаются и у каждого размер скрытых состояний равен hiddendim. Если он равен N, то на выходе модели размерность тоже будет N. Попробуйте без цикла создать первый слой с размером скрытых состояний равным N, а второй слой с размером скрытых состояний равным 1. Если я, конечно, правильно понял суть проблемы.

I will answer on two languages in order to other users will be able to understand my answer too :) You create two layers with hidden state size eqauls to hiddendim in loop. If size of hiddendim equals to N then output of model will be N too. Try to create lstm layers without loop, first layer must have hidden dim equals to N and second layer must have hidden dim equals to 1. Hope that I correctly understood the problem.

Спасибо за ответ. Можно ли сделать вот так:

for (size_t i = 0; i < numLSTMLayers; ++i) { classifierRoot = LSTMPComponentWithSelfStabilization( classifierRoot, { hiddenDim }, { cellDim }, pastValueRecurrenceHook, pastValueRecurrenceHook, device).first; }

return FullyConnectedLinearLayer(classifierRoot, numOutputClasses, device);

не понятно что делает FullyConnectedLinearLayer(). Вообще подаю на вход MFCC, пытаюсь обучить на большом объёме данных, но обучение не сходится. Болтается вблизи 0.7 (loss).

Меня смущает один нюанс из примеров: //creating LSTM cell for each input variable Function LSTMFunction = LSTMPComponentWithSelfStabilization( input, new int[] { LSTMDim }, new int[] { cellDim }, pastValueRecurrenceHook, pastValueRecurrenceHook, device).Item1;

//after the LSTM sequence is created return the last cell in order to continue generating the network
Function lastCell = CNTKLib.SequenceLast(LSTMFunction);

//implement drop out for 10%
var dropOut = CNTKLib.Dropout(lastCell,0.2, 1);

//create last dense layer before output
var outputLayer =  FullyConnectedLinearLayer(dropOut, outDim, device, outputName);

FullyConnectedLinearLayer() - как я понимаю эта функция создает полноценный нейрон, аналог функции Dense(). Вот собственно что смущает: //after the LSTM sequence is created return the last cell in order to continue generating the network Function lastCell = CNTKLib.SequenceLast(LSTMFunction); написано, что SequenceLast возвращает последнюю ячейку. Получается, что //creating LSTM cell for each input variables Function LSTMFunction = LSTMPComponentWithSelfStabilization( input, new int[] { LSTMDim }, new int[] { cellDim }, pastValueRecurrenceHook, pastValueRecurrenceHook, device).Item1;

создаёт последовательность ячеек, а не широкий слой???

elevir commented 5 years ago

Можно ли сделать вот так:

Можно.

не понятно что делает FullyConnectedLinearLayer(). Вообще подаю на вход MFCC, пытаюсь обучить на большом объёме данных, но обучение не сходится. Болтается вблизи 0.7 (loss).

FullyConnectedLinearLayer() - как я понимаю эта функция создает полноценный нейрон, аналог функции Dense().

FullyConnectedLinearLayer это полносвязный слой, число нейронов в котором задаётся параметром outputDim. Dense это то же самое, только добавляется параметр функции активации.

Вот собственно что смущает: //after the LSTM sequence is created return the last cell in order to continue generating the network Function lastCell = CNTKLib.SequenceLast(LSTMFunction); написано, что SequenceLast возвращает последнюю ячейку.

Получается, что ... создаёт последовательность ячеек, а не широкий слой???

Вообще говоря, если у входных данных есть динамическая ось (не считая ось батча), то все последующие операции также будут возвращать последовательности. Поэтому да, на выходе получается последовательность скрытых состояний, а SequenceLast и SequenceFirst всего лишь возвращают последний и первый элемент последовательности соответственно. Вообще рекомендую ознакомиться с LSTM, например, здесь

а не широкий слой

Про широкий слой не очень понял, что вы имеете в виду.

Можно ли сделать вот так:

Yes, you can.

не понятно что делает FullyConnectedLinearLayer(). Вообще подаю на вход MFCC, пытаюсь обучить на большом объёме данных, но обучение не сходится. Болтается вблизи 0.7 (loss).

FullyConnectedLinearLayer() - как я понимаю эта функция создает полноценный нейрон, аналог функции Dense().

In FullyConnectedLinearLayer a number of neurons is defined by argument outputDim. Dense is fully-connected layer too but also it has activation function as argument.

Вот собственно что смущает: //after the LSTM sequence is created return the last cell in order to continue generating the network Function lastCell = CNTKLib.SequenceLast(LSTMFunction); написано, что SequenceLast возвращает последнюю ячейку.

Получается, что ... создаёт последовательность ячеек, а не широкий слой???

Generally, if input variables have dynamic axis (besides batch axis), then all subsequent layers will return sequential data. Therefore yes, you will get as output a sequence of hidden states. SequenceLast and SequenceFirst just returns last and first element of sequence respectively. I recommend to familiarize with LSTM, for example, here.

а не широкий слой

It's not clear to me what do you mean about wide layer.

elevir commented 5 years ago

@Ivashar по поводу того, что не сходится обучение, попробуйте использовать алгоритм оптимизации функции потерь Адам, либо уменьшите коэффициент скорости обучения у текущего алгоритма. Если не поможет, то возможно сама модель не может обобщить данные и необходимо уже модель корректировать.

About poor convergence of learning curve. Try to use loss optimization algorithm Adam, or try to decrease learning rate of current algorithm. If it won't resolve the problem, then maybe the model can't generalize input data and you need to correct the model.