- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
std::tuple<std::vector<long double> , std::vector<std::vector<long double> > , std::vector<long double> >
inline
training(const std::size_t hidden_neurons,
const long double hlr,
const std::size_t epochs,
const std::vector< long double > train_ou,
const std::vector< std::vector< long double > >& train_in,
volatile bool * reset)
{
auto train_inp = train_in;
auto train_out = train_ou;
// std::cerr << "hidden_neurons: " << hidden_neurons << std::endl;
// std::cerr << "hlr: " << hlr << std::endl;
// std::cerr << "epochs: " << epochs << std::endl;
// std::cerr << "train_inp: " << train_inp << std::endl;
// std::cerr << "train_out: " << train_out << std::endl;
const auto mu_inp = mean( train_inp );
const auto sigma_inp = stand( train_inp );
train_inp = ( train_inp - mu_inp[ 0 ] ) / sigma_inp[ 0 ];
const auto mu_out = mean( train_out );
const auto sigma_out = stand( train_out );
train_out = ( train_out - mu_out ) / sigma_out;
const auto patterns = size( train_inp ).first;
std::cout << "patterns: " << patterns << std::endl;
auto bias = ones( patterns );
train_inp = merge( train_inp, bias );
const auto inputs = size( train_inp ).second;
std::vector< long double > err( epochs );
auto weight_input_hidden = ( randn( inputs, hidden_neurons) - 0.5l ) / 10.0l;
auto weight_hidden_output = ( randn( hidden_neurons ) - 0.5l ) / 10.0l;
for( std::size_t i = 0; i < epochs; ++i ) {
if ( *reset ) {
break;
}
const auto alr = hlr;
const auto blr = alr / 10.0;
for( std::size_t j = 0; j < patterns; ++j ){
const auto patnum = ( static_cast<std::size_t>( round( randd() * patterns + 0.5 ) ) - 1 ) % patterns;
const auto this_pat = train_inp[ patnum ];
const auto act = train_out[ patnum ];
const auto hval = feval( []( const long double & v ){ return std::tanh( v ); }, this_pat * weight_input_hidden );
const auto pred = hval * weight_hidden_output;
const auto error = pred - act;
const auto delta_HO = hval * error * blr;
weight_hidden_output = weight_hidden_output - delta_HO;
const auto m1 = weight_hidden_output * alr * error;
const auto m2 = 1.0l - (hval^2);
const auto m3 = dot_operator( m1, m2, std::multiplies< long double >());
const auto m4 = vec_to_vecvec( m3 );
const auto delta_IH = m4 * this_pat;
weight_input_hidden = weight_input_hidden - trans( delta_IH );
}
const auto p1 = feval( []( const long double& v ){ return std::tanh( v ); }, train_inp * weight_input_hidden );
const auto pred = weight_hidden_output * trans( p1 );
const auto error = pred - train_out;
const auto error_sq = error ^ 2;
err[ i ] = std::sqrt( std::accumulate( error_sq.cbegin(), error_sq.cend(), 0.0, std::plus<long double> () ) );
std::cerr << "err[ i ]: " << err[ i ] << ' ' << i << std::endl;
}
return std::move(std::make_tuple(weight_hidden_output, weight_input_hidden, err));
}
bormand 19.06.2013 05:39 # 0
govnomonad 19.06.2013 06:01 # +2
bormand 19.06.2013 07:11 # 0
const std::vector< long double > train_ou,
const std::vector< std::vector< long double > >& train_in,
roman-kashitsyn 19.06.2013 07:43 # +9
bormand 19.06.2013 07:58 # +1
roman-kashitsyn 19.06.2013 09:43 # +4
Yuuri 20.06.2013 12:47 # +3
bormand 20.06.2013 12:55 # +1
Vasiliy 19.06.2013 08:04 # +6
ехал vec через vec
LispGovno 19.06.2013 08:32 # +1
Автор не умеет пользоваться auto либо std::vector< std::vector. Лишнее копирование.
Не удивлюсь, если ещё где-то подобные косяки есть. Кто-нибудь видит?
someone 19.06.2013 08:37 # +3
defecate-plusplus 19.06.2013 09:25 # +3
особенно внутри цикла
когда надо обучить здоровую нейросетку (и да еще и заюзать генетический алгоритм), такая еботня небось будет считаться не сутки, а месяц
LispGovno 19.06.2013 09:28 # +1
> особенно внутри цикла
Это где например? Больше не вижу.
defecate-plusplus 19.06.2013 09:45 # +1
defecate-plusplus 19.06.2013 09:56 # +2
this_pat - массив - типа очередная строка из входящих данных ("pattern") - копия
hval - массив (но тут я могу ошибаться)
интересно вообще как тут работает train_inp * weight_input_hidden - переопределен где то operator *?
pred - тоже массив (см. hval)
и т.д.
но да, я тут еще раз посмотрел - может и не факт, что сильно оптимальней можно сделать, я слишком анскиллед в ручном кодировании нейросетей
auto вообще усложняет понимание кода
LispGovno 19.06.2013 10:05 # +1
defecate-plusplus 19.06.2013 10:10 # +1
weight_input_hidden = weight_input_hidden - trans( delta_IH );
разве нельзя оптимальней переписать?
LispGovno 19.06.2013 10:18 # 0
По идеи будет быстрее, но это же нужно лишние операторы перегружать, пространство имен какое-то загрязнять. Так что человеку видимо было лень (мне наверное тоже ради одной строки, если не тормозит), а о boost::operators он не знал (хотя если делать через последний, то я уж не помню получится ли оптимальнее).
На самом деле тут все можно переписать через шаблонные выражения (особенно то с учетом auto). Каждая операция накапливает конструирует объект нового типа т_операция<т_источник_данных__или__т_пре дшествующая_операция, ...> и в конце после накопления дерева выражения все это исполняется за раз без лишних обращений к разным страницам. Это будет кешфрендли. Для нейронов с учетом их кол-ва это было особенно бы полезно.
Abbath 19.06.2013 10:45 # 0
Не он один
https://github.com/Abbath/ECOHT-ANN_2/blob/master/Utils.hpp
roman-kashitsyn 19.06.2013 10:50 # 0
Ну и текст коммитов, конечно, шедеврален. разве размер вектора может быть известен во время компиляции в общем случае?
LispGovno 19.06.2013 11:14 # 0
roman-kashitsyn 19.06.2013 11:54 # 0
defecate-plusplus 19.06.2013 10:58 # 0
2) не вижу особого смысла городить return std::move( - это и так и так будет подлежать RVO
3) const double и другие базовые типы - на мой взгляд лишнее
4) рандомайзер можно было бы взять и получше - вон их сколько boost_random.reference.generators
а в остальном нехилый труд вложен
Abbath 19.06.2013 12:47 # +3
std::move ставились в угаре на всякий случай.
конст там везде, где можно.
Вывод этого рандомайзера похож на вывод матлабовского. Подошло.
Авторы 5 раз писали backpropagation. Первые 4 раза получалась классификация, на 5 таки вышла аппроксимация двухмерной функции.
roman-kashitsyn 19.06.2013 12:53 # +1
Героично
an0nym 19.06.2013 14:30 # 0
Если объявления в заголовочном файле, а код отдельно, где ставить inline?
defecate-plusplus 19.06.2013 14:47 # 0
но это в любом случае плохо делить на две части, объясню почему:
такое может прокатить, только если никакой другой юнит трансляции не использует эту функцию - только один единственный (там же, где и будет тело описано)
но раз так - накой его выносить в заголовочный файл, пусть объявляется и описывается прямо в .cpp
не исключаю, что можно в двух юнитах трансляции записать два разных тела инлайновой функции - т.о. будет неплохой способ выстрелить себе в ногу, т.к. скорее всего компилятор в итоге просто возьмет любую из двух
так же не берусь предсказать, что будет, если в одном юните эта функция всё же будет инлайновая (linkonce), а во втором - честно экспортируемая
Abbath 19.06.2013 10:47 # 0
Abbath 21.06.2013 03:26 # 0
nonamez 19.06.2013 09:15 # 0
anonimb84a2f6fd141 21.06.2013 03:40 # −1