anchor.diff:      {error, <<"Minimum number of layers is 3">>};
   create_neural_network(NetworkId, Layers, Weights) when is_list(Weights) ->
       create_neural_network(NetworkId, Layers, Weights, sigmoid);
  -create_neural_network(NetworkId, [InputSize | Rest], Activation) when is_atom(Activation) ->
  +create_neural_network(NetworkId, [InputSize | Rest], Activation) when is_atom(Activation) ->
       case lists:member(Activation, supported_activations()) of
           false -> {error, <<"Activation function not supported">>};
           true ->
  
positive.code:     conn :: term()
  }).
  
  -spec start_link(binary(), inet:socket_address() | inet:hostname(), inet:port_number()) -> {ok, pid()} | {error, term()}.
  start_link(NetworkId, Address, Port) ->
      gen_server:start_link(?NETWORK_GID(NetworkId), ?MODULE, [NetworkId, Address, Port], []).
  
negative.code: 
  -spec initialize(binary(), pos_integer(), pos_integer()) -> ok | {error, binary()}.
  initialize(NetworkId, InpSize, OutSize) ->
      initialize(NetworkId, InpSize, OutSize, ?LEARNING_RATE).
  
  -spec initialize(binary(), pos_integer(), pos_integer(), float()) -> ok | {error, binary()}.
  initialize(NetworkId, InpSize, OutSize, LearningRate) ->
      gen_server:call(?NETWORK_GID(NetworkId), {initialize, [InpSize, OutSize, LearningRate]}).
  
  -spec add_layer(binary(), pos_integer()) -> ok | {error, binary()}.
  add_layer(NetworkId, Size) ->
      gen_server:call(?NETWORK_GID(NetworkId), {add_layer, [Size]}).
  
  -spec add_activation(binary(), atom()) -> ok | {error, binary()}.
  add_activation(NetworkId, Activation) ->
      gen_server:call(?NETWORK_GID(NetworkId), {add_activation, [Activation]}).
  
  -spec set_cost(binary(), atom()) -> ok | {error, binary()}.
  set_cost(NetworkId, CostFunc) ->
      gen_server:call(?NETWORK_GID(NetworkId), {set_cost, [CostFunc]}).
  
  -spec add_data_chunk(binary(), list(), list()) -> ok | {error, binary()}.
  add_data_chunk(NetworkId, Inputs, Labels) ->
      add_data_chunk(NetworkId, Inputs, Labels, ?SCALE).
  
  -spec add_data_chunk(binary(), list(), list(), list()) -> ok | {error, binary()}.
  add_data_chunk(NetworkId, Inputs, Labels, Scale) ->
      gen_server:call(?NETWORK_GID(NetworkId), {add_data_chunk, [Inputs, Labels, Scale]}).
  
  -spec set_learning_rate(binary(), float()) -> ok | {error, binary()}.
  set_learning_rate(NetworkId, LearningRate) ->
      gen_server:call(?NETWORK_GID(NetworkId), {set_learning_rate, [LearningRate]}).
  
  -spec train(binary()) -> ok | {error, binary()}.
  train(NetworkId) -> train(NetworkId, ?EPOCHS).
  
  -spec train(binary(), pos_integer()) -> ok | {error, binary()}.
  train(NetworkId, Epochs) when is_integer(Epochs) ->
      train(NetworkId, Epochs, ?BATCH_SIZE).
  
  -spec train(binary(), pos_integer(), pos_integer()) -> ok | {error, binary()}.
  train(NetworkId, Epochs, BatchSize) ->
      gen_server:call(?NETWORK_GID(NetworkId), {train, [Epochs, BatchSize]}).
  
  -spec get_weights(binary()) -> ok | {error, binary()}.
  get_weights(NetworkId) ->
      gen_server:call(?NETWORK_GID(NetworkId), {get_weights, []}).
  
  -spec set_weights(binary(), [float()]) -> ok | {error, binary()}.
  set_weights(NetworkId, Weights) ->
      gen_server:call(?NETWORK_GID(NetworkId), {set_weights, [Weights]}).
  
  -spec predict(binary(), [number()]) -> list() | {error, binary()} .
  predict(NetworkId, [N|_]=Input) when is_number(N) ->
      %% TODO: Check for errors...
      [Result] = predict(NetworkId, [Input]),
      Result;
  predict(NetworkId, Set) ->
      gen_server:call(?NETWORK_GID(NetworkId), {predict, [Set]}).
  
  %% Gen server related functions
  
  