При моделировании искусственной нейронной сети столкнулся с таким странным поведением при добавлении к каждому нейрону в цикле делегата. Сейчас код переписал без циклов, но это не есть хорошо.
К сожалению старая версия с циклами не сохранилась. Сейчас это выглядит так:
Layer1.Add(new Neuron(10));
for (int i = 0; i < 10; i++)
{
Layer1[0].X[i] = Layer0[i].OUT;
Layer1[0].W[i] = 1;
}
Layer1[0].activationFunction = new Neuron.ActivationFunction(
delegate
{
double sum = 0;
for (int i = 0; i < Layer1[0].X.Count/2; i++)
{
if (Layer1[0].X[i] == 1)
{
sum += Layer1[0].X[i] * Layer1[0].W[i];
}
else if (Layer1[0].X[i + 5] == 1)
{
sum += Layer1[0].X[i + 5] * Layer1[0].W[i];
}
}
sum = sum / Layer1[0].X.Count;
if(sum >= 0.5) return 1;
else return sum;
});
У части нейронов активационные функции (выход нейрона) одинаковые, собственно активационная функция и назначается с помощью делегата. Отличия ряда нейронов только во входах, они идут с разных выходов нейронов предыдущего слоя. Соответственно их инициализацию я попытался написать с помощью цикла. Тут видно что все действия идут с нулевым нейроном первого слоя.
Дак вот собственно проблема, которую я до конца так и не понял:
Все ниже написанное относится к случаю, если вся инициализация написана через циклы.
Если выполнять программу по шагам в режиме отладки, то во время определения делегатов, они нормально подставляются во все нейроны. Когда же цикл заканчивается, то все делегаты у нейронов пропадают. Абсолютно все...
Однако, если выполнять программу по прежнему в режиме отладки, но пропустить несколько итераций цикла (зажать F10/F11), то делегаты не назначаются нейронам.
Почему такое странное поведение? Причем поведение чего, я так и не понял...
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Svat_P, Вы писали:
A>Похоже, у вас получаются временные объекты, на которые нет ссылок. Со временем они собираются сборщиком мусора.
Здравствуйте, Svat_P, Вы писали:
A>>Похоже, у вас получаются временные объекты, на которые нет ссылок. Со временем они собираются сборщиком мусора. S_P>Хм...А как от этого можно избавиться?
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, Svat_P, Вы писали:
A>>>Похоже, у вас получаются временные объекты, на которые нет ссылок. Со временем они собираются сборщиком мусора. S_P>>Хм...А как от этого можно избавиться?
A>Сохранять эти ссылки куда-то :-)
Вообще, по идее, ссылки все должны сохраниться, тк указатель на коллекцию нейронов храниться в объекте всей нейронной сети. Поэтому и все внутренние ссылки, включая ссылки на делегаты, должны сохраняться, тк они не временные, они входят во всю внутреннюю иерархию объекта.
Здравствуйте, Svat_P, Вы писали:
S_P>Здравствуйте, adontz, Вы писали:
A>>Здравствуйте, Svat_P, Вы писали:
A>>>>Похоже, у вас получаются временные объекты, на которые нет ссылок. Со временем они собираются сборщиком мусора. S_P>>>Хм...А как от этого можно избавиться?
A>>Сохранять эти ссылки куда-то :-)
S_P>Вообще, по идее, ссылки все должны сохраниться, тк указатель на коллекцию нейронов храниться в объекте всей нейронной сети. Поэтому и все внутренние ссылки, включая ссылки на делегаты, должны сохраняться, тк они не временные, они входят во всю внутреннюю иерархию объекта.
Здравствуйте, Svat_P, Вы писали:
S_P>Проблема решена. Решение см здесь
Скопировал код оттуда
Layer1 = new List<Neuron>(6);
for (int j = 0; j < 2; j++)
{
....
Layer1[j].activationFunction = new Neuron.ActivationFunction(
delegate
{
double sum = 0;
for (int i = 0; i < Layer1[j].X.Count / 2; i++)
{
....
});
}
Я не очень понял, что там пропадает, но вот что там происходит на самом деле:
переменная цикла j захватывается. Одна на все созданные функции. И ее значение равно значению j при выходе из цикла, полагаю j=2.
Что бы избежать этого, нужно перед анонимным методом ввести новую переменную int curJ = j;
после чего в теле анонимного метода использовать curJ а не j.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Svat_P, Вы писали:
S_P>>Проблема решена. Решение см здесь
S>Скопировал код оттуда S>
S> Layer1 = new List<Neuron>(6);
S> for (int j = 0; j < 2; j++)
S> {
S> ....
S> Layer1[j].activationFunction = new Neuron.ActivationFunction(
S> delegate
S> {
S> double sum = 0;
S> for (int i = 0; i < Layer1[j].X.Count / 2; i++)
S> {
S> ....
S> });
S> }
S>
S>Я не очень понял, что там пропадает, но вот что там происходит на самом деле: S>переменная цикла j захватывается. Одна на все созданные функции. И ее значение равно значению j при выходе из цикла, полагаю j=2.
S>Что бы избежать этого, нужно перед анонимным методом ввести новую переменную int curJ = j; S>после чего в теле анонимного метода использовать curJ а не j.
Да, теперь я это понял =) Всем большое спасибо, что помогали! =)
Здравствуйте, Svat_P, Вы писали:
S_P>При моделировании искусственной нейронной сети столкнулся с таким странным поведением при добавлении к каждому нейрону в цикле делегата. Сейчас код переписал без циклов, но это не есть хорошо.
Есть подозрения, что было как-то так:
for (int i = 0; i < count; ++i)
{
new ActivationFunction(delegate { return i; });
}
Чтобы работало надо так:
for (int _i = 0; _i < count; ++_i)
{
int i = _i;new ActivationFunction(delegate { return i; });
}
В первом варианте все делегаты работают с одним и тем же экземпляром i, естественно правильно это работать не может.