# The Nerv NN Package Part of the [Nerv](../README.md) toolkit. ## Description ### Class hierarchy it contains __nerv.LayerRepo__, __nerv.ParamRepo__, and __nerv.DAGLayer__(inherits __nerv.Layer__). ### Class hierarchy and their members #### nerv.ParamRepo Get parameter object by ID. * `table param_table` Contains the mapping of parameter ID to parameter file(__nerv.ChunkFile__) * __nerv.LayerRepo__ Get layer object by ID. * `table layers` Contains the mapping of layer ID to layer object. objects. #### __nerv.DAGLayer__ Inherits __nerv.Layer__. * `layers`: __table__, a mapping from a layer ID to its "ref". A ref is a structure that contains reference to space allocations and other info of the layer. * `inputs`: __table__, a mapping from the inputs ports of the DAG layer to the input ports of the sublayer, the key is the port number, the value is `{ref, port}`. * `outputs`:__table__, the counterpart of `inputs`. * `parsed_conn`: __table__, a list of parsed connections, each entry is of format `{{ref_from, port_from}, {ref_to, port_to}}`. * `queue`: __table__, a list of "ref"s, the propagation of the DAGLayer will follow this order, and back-propagation will follow a reverse order. ## Methods ### __nerv.ParamRepo__ #### nerv.ParamRepo:\_\_init(param\_files) * Parameters: `param_files`: __table__ * Description: `param_files` is a list of file names that stores parameters, the newed __ParamRepo__ will read them from file and store the mapping for future fetching. #### nerv.Param ParamRepo.get_param(ParamRepo self, string pid, table global_conf) * Returns: __nerv.Layer__ * Parameters: `self`: __nerv.ParamRepo__. `pid`: __string__. `global_conf`: __table__. * Description: __ParamRepo__ will find the __nerv.ChunkFile__ `pf` that contains parameter of ID `pid` and return `pf:read_chunk(pid, global_conf)`. ### __nerv.LayerRepo__ #### nerv.LayerRepo:\_\_init(layer\_spec, param\_repo, global\_conf) * Returns: __nerv.LayerRepo__. * Parameters: `self`: __nerv.ParamRepo__. `layer_spec`: __table__. `param_repo`: __nerv.ParamRepo__. `global_conf`: __table__. * Description: __LayerRepo__ will construct the layers specified in `layer_spec`. Every entry in the `layer_spec` table should follow the format below: > layer_spec : {[layer_type1] = llist1, [layer_type2] = llist2, ...} > llist : {layer1, layer2, ...} > layer : layerid = {param_config, layer_config} > param_config : {param1 = paramID1, param2 = paramID2} __LayerRepo__ will merge `param_config` into `layer_config` and construct a layer by calling `layer_type(layerid, global_conf, layer_config)`. #### nerv.LayerRepo.get\_layer(self, lid) * Returns: __nerv.LayerRepo__, the layer with ID `lid`. * Parameters: `self`:__nerv.LayerRepo__. `lid`:__string__. * Description: Returns the layer with ID `lid`. ### nerv.DAGLayer #### nerv.DAGLayer:\_\_init(id, global\_conf, layer\_conf) * Returns: __nerv.DAGLayer__ * Parameters: `id`: __string__ `global_conf`: __table__ `layer_conf`: __table__ * Description: The `layer_conf` should contain `layer_conf.sub_layers` which is a __nerv.LayerRepo__ storing the sub layers of the DAGLayer. It should also contain `layer_conf.connections`, which is a string-to-string mapping table describing the DAG connections. See an example below: ``` dagL = nerv.DAGLayer("DAGL", global_conf, {["dim_in"] = {input_dim, 2}, ["dim_out"] = {}, ["sub_layers"] = layerRepo, ["connections"] = { ["[1]"] = "AffineL[1]", ["AffineL[1]"] = "SoftmaxL[1]", ["[2]"] = "SoftmaxL[2]", }}) ``` #### nerv.DAGLayer.init(self, batch\_size) * Parameters: `self`: __nerv.DAGLayer__ `batch_size`: __int__ * Description: This initialization method will allocate space for output and input matrice, and will call `init()` for each of its sub layers. #### nerv.DAGLayer.propagate(self, input, output) * Parameters: `self`: __nerv.DAGLayer__ `input`: __table__ `output`: __table__ * Description: The same function as __nerv.Layer.propagate__, do propagation for each layer in the order of `self.queue`. #### nerv.DAGLayer.back\_propagate(self, next\_bp\_err, bp\_err, input, output) * Parameters: `self`: __nerv.DAGLayer__ `next_bp_err`: __table__ `bp_err`: __table__ `input`: __table__ `output`: __table__ * Description: The same function as __nerv.Layer.back_propagate__, do back-propagation for each layer in the reverse order of `self.queue`. #### nerv.DAGLayer.update(self, bp\_err, input, output) * Parameters: `self`: __nerv.DAGLayer__ `bp_err`: __table__ `input`: __table__ `output`: __table__ * Description: The same function as __nerv.Layer.update__, do update for each layer in the order of `self.queue`. ## Examples * aaa ``` require 'math' require 'layer.affine' require 'layer.softmax_ce' --[[Example using DAGLayer, a simple two-classification problem]]-- --[[begin global setting and data generation]]-- global_conf = {lrate = 10, wcost = 1e-6, momentum = 0.9, cumat_type = nerv.CuMatrixFloat, } input_dim = 5 data_num = 100 param_fn = "../tmp" ansV = nerv.CuMatrixFloat(input_dim, 1) for i = 0, input_dim - 1, 1 do ansV[i][0] = math.random() - 0.5 end ansB = math.random() - 0.5 print('displaying ansV') print(ansV) print('displaying ansB(bias)') print(ansB) dataM = nerv.CuMatrixFloat(data_num, input_dim) for i = 0, data_num - 1, 1 do for j = 0, input_dim - 1, 1 do dataM[i][j] = math.random() * 2 - 1 end end refM = nerv.CuMatrixFloat(data_num, 1) refM:fill(ansB) refM:mul(dataM, ansV, 1, 1) --refM = dataM * ansV + ansB labelM = nerv.CuMatrixFloat(data_num, 2) for i = 0, data_num - 1, 1 do if (refM[i][0] > 0) then labelM[i][0] = 1 labelM[i][1] = 0 else labelM[i][0] = 0 labelM[i][1] = 1 end end --[[global setting and data generation end]]-- --[[begin network building]]-- --parameters do local affineL_ltp = nerv.LinearTransParam('AffineL_ltp', global_conf) affineL_ltp.trans = nerv.CuMatrixFloat(input_dim, 2) for i = 0, input_dim - 1, 1 do for j = 0, 1, 1 do affineL_ltp.trans[i][j] = math.random() - 0.5 end end local affineL_bp = nerv.BiasParam('AffineL_bp', global_conf) affineL_bp.trans = nerv.CuMatrixFloat(1, 2) for j = 0, 1, 1 do affineL_bp.trans[j] = math.random() - 0.5 end local chunk = nerv.ChunkFile(param_fn, 'w') chunk:write_chunk(affineL_ltp) chunk:write_chunk(affineL_bp) chunk:close() paramRepo = nerv.ParamRepo({param_fn}) end --layers layerRepo = nerv.LayerRepo({ ["nerv.AffineLayer"] = { ["AffineL"] = {{["ltp"] = "AffineL_ltp", ["bp"] = "AffineL_bp"}, {["dim_in"] = {input_dim}, ["dim_out"] = {2}}}, }, ["nerv.SoftmaxCELayer"] = { ["SoftmaxL"] = {{}, {["dim_in"] = {2, 2}, ["dim_out"] = {}}} }, }, paramRepo, global_conf) affineL = layerRepo:get_layer("AffineL") softmaxL = layerRepo:get_layer("SoftmaxL") print('layers initializing...') dagL = nerv.DAGLayer("DAGL", global_conf, {["dim_in"] = {input_dim, 2}, ["dim_out"] = {}, ["sub_layers"] = layerRepo, ["connections"] = { ["[1]"] = "AffineL[1]", ["AffineL[1]"] = "SoftmaxL[1]", ["[2]"] = "SoftmaxL[2]", }}) dagL:init(data_num) --affineL:init() --softmaxL:init() --[[network building end]]-- --[[begin space allocation]]-- print('network input&output&error space allocation...') dagL_input = {dataM, labelM} dagL_output = {} dagL_err = {} dagL_ierr = {nerv.CuMatrixFloat(data_num, input_dim), nerv.CuMatrixFloat(data_num, 2)} --[[space allocation end]]-- --[[begin training]]-- ce_last = 0 for l = 0, 10, 1 do dagL:propagate(dagL_input, dagL_output) dagL:back_propagate(dagL_ierr, dagL_err, dagL_input, dagL_output) dagL:update(dagL_err, dagL_input, dagL_output) if (l % 2 == 0) then nerv.utils.printf("training iteration %d finished\n", l) nerv.utils.printf("cross entropy: %.8f\n", softmaxL.total_ce - ce_last) --nerv.utils.printf("accurate labels: %d\n", calculate_accurate(output, labelM)) nerv.utils.printf("total frames processed: %.8f\n", softmaxL.total_frames) end ce_last = softmaxL.total_ce end --[[end training]]-- ```