I was doing a neural net in cpp during free time in order to get some more experience in C++11. However I ran into some problems that a I cannot figure out myself.
struct neuronsLayer
{
vector<real> ac;
neuronsLayer(int s)
{
std::cout<<"neuronLayer 1"<<std::endl;
ac = vector<real>(s,0.1f);
}
neuronsLayer(const neuronsLayer& nl)
{
std::cout<<"neuronLayer 2"<<std::endl;
ac = vector<real>(nl.ac);
}
neuronsLayer(neuronsLayer&& nl)
{
std::cout<<"neuronLayer 3"<<std::endl;
ac = std::move(nl.ac);
}
neuronsLayer operator=(const neuronsLayer& nl)
{
std::cout<<"neuronLayer 4"<<std::endl;
return neuronsLayer(nl);
}
neuronsLayer(){ std::cout<<"neuronLayer 5"<<std::endl;}
~neuronsLayer(){}
};
This is a layer implementation, then :
struct network
{
vector<neuronsLayer> hiddens;
vector<neuronsConnection> synaps;
real alpha;
//std::initializer_list
network(vector<int> layers)
{
alpha = 1.f;
hiddens = vector<neuronsLayer>();//+2
for(int& l : layers)
{
hiddens.push_back(neuronsLayer(l));
}
synaps = vector<neuronsConnection>();
for(int i = 0 ; i < layers.size() -1 ; i++)
{
synaps.push_back(std::move(neuronsConnection(layers[i],layers[i+1])));
}
}
void forward(vector<real> input)
{
hiddens[0].ac = input;
for (int layer = 0; layer < hiddens.size() -1; ++layer)
{
for(int i = 0 ; i < synaps[layer].x ; i++)
{
for(int j = 0 ; j < synaps[layer].y ; j++)
{
hiddens[layer+1].ac[i] += hiddens[layer].ac[j] * synaps[layer].w[i + synaps[layer].x * j]; //+ activation +biais
}
}
for(int i = 0 ; i < hiddens[layer].ac.size() ; i ++)
hiddens[layer+1].ac[i] = 1.f/(1+exp(-hiddens[layer+1].ac[i]));
}
}
void backward(vector<real> expected)
{
vector<real> error(expected);
for(int i = 0 ; i < error.size(); i ++)
{
error[i] = expected[i] - hiddens[hiddens.size() -1].ac[i];
}
for (int layer = 0; layer < hiddens.size() -1; ++layer)
{
for(int i = 0 ; i < synaps[layer].x ; i++)
{
for(int j = 0 ; j < synaps[layer].y ; j++)
{
real dw = error[i]*(1+2*exp(-hiddens[0].ac[i])/(1+exp(-hiddens[0].ac[i])));
synaps[layer].w[i + synaps[layer].x * j] += dw*alpha;
}
}
}
}
And the main :
int main(int argc, char** argv)
{
vector<int> net = {64,2};
network nn(net);
vector<float> o = {1,0};
vector<float> t = {0,1};
auto rOne = std::bind(std::normal_distribution<float>(6,1), std::default_random_engine{});
auto rTwo = std::bind(std::normal_distribution<float>(3,1), std::default_random_engine{});
auto gOne = [&](){
int x=rOne(),y=rOne();
//while(x=rOne > 8 or x < 0);
//while(y=rOne > 8 or y < 0);
std::vector<real> tbr (64,0);
tbr[x + y*8] = 1.0;
return tbr;
};
auto gTwo = [&](){
int x=rTwo(),y=rTwo();
//while(x=rTwo > 8 or x < 0);
//while(y=rTwo > 8 or y < 0);
std::vector<real> tbr (64,0);
tbr[x + y*8] = 1.0;
return tbr;
};
for(int i = 0 ; i < 5000 ; i++)
{
nn.forward(gOne());
nn.backward(o);
nn.forward(gTwo());
nn.backward(t);
}
I have one major problem and two questions :
1) I receive a SEGFAULT during execution when backward is called, it seems that hiddens[0] is empty. So I might (little understatement) have misunderstood how move is working ?
Program received signal SIGSEGV, Segmentation fault.
0x0000000000402159 in network::backward (this=0x7fffffffe190, expected=...) at dnn3.cpp:171
171 real dw = error[i]*(1+2*exp(-hiddens[0].ac[i])/(1+exp( hiddens[0].ac[i])));
(gdb) p i
$1 = 0
(gdb) p hiddens[0].ac[i]
$2 = (__gnu_cxx::__alloc_traits<std::allocator<float> >::value_type &) @0x3f0000003f000000: <error reading variable>
2) Before that the output of the program is :
neuronLayer 1
neuronLayer 3
neuronLayer 1
neuronLayer 3
neuronLayer 2
Why is the copy constructor called ? I create only 2 layers, and both of them are generated following the exact same process, and only one of them is using this constructor. And I can't understand why it's needed.
3) Concerning the bound objects rOne and rTwo, are they always returning the same value ? cause when I poked into the gOne output it seems that it gave back twice the same value. Is that normal ?
Thanks in advance, Marc.
EDIT : As asked :
(gdb) p hiddens
$1 = {<std::_Vector_base<neuronsLayer, std::allocator<neuronsLayer> >> = { _M_impl = {<std::allocator<neuronsLayer>> ={<__gnu_cxx::new_allocator<neuronsLayer>> = {<No data fields>}, <No data fields>},_M_start = 0x60c1a0, _M_finish = 0x60c1d0, _M_end_of_storage = 0x60c1d0}}, <No data fields>}
(gdb) p hiddens[0].ac
$2 = {<std::_Vector_base<float, std::allocator<float> >> = { _M_impl = {<std::allocator<float>> = {<__gnu_cxx::new_allocator<float>> = {<No data fields>}, <No data fields>}, _M_start = 0x3f0000003f000000, _M_finish = 0x3f0000003f000000, _M_end_of_storage = 0x60c2e0}}, <No data fields>}
EDIT 2 :
Breakpoint 1, network::forward (this=0x7fffffffe190, input=...)
(gdb) p hiddens
$1 = {<std::_Vector_base<neuronsLayer, std::allocator<neuronsLayer> >> = {_M_impl = {<std::allocator<neuronsLayer>> = {<__gnu_cxx::new_allocator<neuronsLayer>> = {<No data fields>}, <No data fields>},_M_start = 0x60d1a0, _M_finish = 0x60d1d0, _M_end_of_storage = 0x60d1d0}}, <No data fields>}
(gdb) p hiddens[0]
$2 = (__gnu_cxx::__alloc_traits<std::allocator<neuronsLayer> >::value_type &) @0x60d1a0: { ac = {<std::_Vector_base<float, std::allocator<float> >> = { _M_impl = {<std::allocator<float>> = {<__gnu_cxx::new_allocator<float>> = {<No data fields>}, <No data fields>}, _M_start = 0x60d1e0, _M_finish = 0x60d2e0, _M_end_of_storage = 0x60d2e0}}, <No data fields>}}
(gdb) p hiddens[0].ac
$3 = {<std::_Vector_base<float, std::allocator<float> >> = { _M_impl = {<std::allocator<float>> = {<__gnu_cxx::new_allocator<float>> = {<No data fields>}, <No data fields>}, _M_start = 0x60d1e0, _M_finish = 0x60d2e0, _M_end_of_storage = 0x60d2e0}}, <No data fields>}
(gdb) p hiddens[1]
$4 = (__gnu_cxx::__alloc_traits<std::allocator<neuronsLayer> >::value_type &) @0x60d1b8: { ac = {<std::_Vector_base<float, std::allocator<float> >> = _M_impl = {<std::allocator<float>> = {<__gnu_cxx::new_allocator<float>> = {<No data fields>}, <No data fields>}, _M_start = 0x60d180, _M_finish = 0x60d188, _M_end_of_storage = 0x60d188}}, <No data fields>}}
(gdb) p hiddens[1].ac[0]
$5 = (__gnu_cxx::__alloc_traits<std::allocator<float> >::value_type &) @0x60d180: 0.100000001
(gdb) p hiddens[0].ac[0]
$6 = (__gnu_cxx::__alloc_traits<std::allocator<float> >::value_type &) @0x60d1e0: 0.100000001
The assignment operator did not do what you want. It indeed copied an temporary
neuronsLayer
object according tonl
passed in, not modifying the content of its caller.It should be
EDIT : As asked :
Since
hiddens[0].ac
has_M_start
equal to_M_finish
, it is empty, and thus fetching its 0th element leads to segmentation fault.