Skip to content

Commit 23df91e

Browse files
author
danielpovey
committed
sandbox/nnet3: adding some more (sketches of) code
git-svn-id: http://svn.code.sf.net/p/kaldi/code@5046 5e6a8d80-dfce-4ca6-a32a-6e07a63d50c8
1 parent edf24b1 commit 23df91e

7 files changed

Lines changed: 394 additions & 67 deletions

File tree

‎src/nnet3/nnet-compile.cc‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2015 Johns Hopkins University (author: Daniel Povey)
2+
3+
// See ../../COPYING for clarification regarding multiple authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12+
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
13+
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
14+
// MERCHANTABLITY OR NON-INFRINGEMENT.
15+
// See the Apache 2 License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#include <iterator>
19+
#include <sstream>
20+
#include "nnet2/nnet-compile.h"
21+
22+
namespace kaldi {
23+
namespace nnet2 {
24+
25+
26+
27+
28+
} // namespace nnet2
29+
} // namespace kaldi

‎src/nnet3/nnet-compile.h‎

Lines changed: 132 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,10 @@
2929
namespace kaldi {
3030
namespace nnet3 {
3131

32-
// Options class for the process of turning a ComputationSpecification into a
33-
// NnetComputation.
34-
struct NnetCompileConfig {
35-
36-
void Register(OptionsItf *po) {
37-
}
38-
};
39-
4032
// The first step in compilation is to turn the ComputationSpecification
4133
// into a ConcreteComputationGraph, where for each Cindex we have a list of
42-
// other Cindexes that it depends on.
34+
// other Cindexes that it depends on, and compute the shortest distance to
35+
// the input.
4336
struct ConcreteComputationGraph {
4437

4538
// Maps each Cindex to an integer (call this cindex_id) that uniquely
@@ -56,70 +49,149 @@ struct ConcreteComputationGraph {
5649
// calling GetInputIndexes on the relevant Component (with the relevant
5750
// Index), and then calling MapToInput on its InputDescriptor.
5851
std::vector<std::vector<int32> > dependencies;
59-
60-
61-
};
62-
6352

53+
// a vector of node type indexed by node-index (as used in the Nnet);
54+
// this is just worked out from the Nnet. This information is needed
55+
// in some computations relating to ConcreteComputationGraph.
56+
std::vector<NetworkNode::NodeType> node_type;
6457

58+
59+
};
6560

66-
} // namespace nnet2
67-
} // namespace kaldi
6861

62+
void ComputeComputationGraph(const ComputationRequest &computation_request,
63+
const Nnet &nnet,
64+
ConcreteComputationGraph *computation_graph);
6965

70-
#endif
7166

72-
/*
73-
Compilation model...
7467

75-
list of objects to learn and have stats for (e.g. SoftmaxComponent, AffineComponent, FixedAffineComponent)
7668

77-
Then a compilation method to go from either a training or test setup, to an
78-
NnetComputation.
79-
An NnetComputation is:
80-
81-
A number of declarations of matrices, with sizes, each being the input or output of a
82-
particular layer (may be both the input of one layer and the output of
83-
another). Also declarations of sub-matrices.
84-
A number of commands, such as:
85-
Initialize matrix; zero matrix; deinitialize matrix; do Propagate or Backprop;
86-
do forward or backward of AddMatrix or CopyMatrix.
69+
// This class creates an initial version of the NnetComputation, without any
70+
// optimization or sharing of matrices.
71+
void ComputationCreator {
72+
public:
73+
ComputationCreator(const ComputationRequest &request,
74+
const Nnet &nnet,
75+
const ConcreteComputationGraph &computation_graph);
8776

88-
Get rid of all this complexity and just accept redundant copy?? I.e. do it all in C++?
89-
-- Linear list of components, each with list of inputs, if needed? Sharing of parameters
90-
between components? [ComponentInstance vs. Component]
91-
[?
92-
93-
Given required output indexes, and maybe some background info,
77+
void CreateComputation(NnetComputation *computation);
78+
79+
private:
80+
const ComputationRequest &request_;
81+
const ConcreteComputationGraph &computation_graph_;
82+
/// shortest_distance_ is shortest distance from inputs (distance 0) to each
83+
/// cindex_id in the computation graph.
84+
std::vector<int32> shortest_distance_;
85+
/// steps_[i] lists the cindex_ids at the output of the i'th component computation.
86+
std::vector<std::vector<int32> > steps_;
87+
88+
// This maps each cindex_id to the location
89+
std::vector<std::pair<int32, int32> > cindex_id_to_location_;
90+
91+
// Some generic information about each step of the computation... a step
92+
// is an instance of a NetworkNode, but a NetworkNode may in unrolled computations
93+
// have multiple steps.
94+
struct StepInfo {
95+
int32 node_id; // network-node id.
96+
Network::NodeType node_type; // the type of the node: {kComponent,kInput,kOutput}.
97+
int32 input_matrix; // matrix index of input matrix.
98+
int32 output; // matrix index of output matrix.
99+
int32 output_deriv; // matrix index of output derivative
100+
int32 input_deriv; // matrix index of input derivative.
101+
std::vector<Index> input_indexes;
102+
LocationInfo(): input(-1), output(-1), output_deriv(-1), input_deriv(-1) { }
103+
};
104+
105+
// This
106+
std::vector<StepInfo> step_info_;
107+
108+
/// Indexed by the same index as steps_, gives us the input matrix index for
109+
/// this step.
110+
std::vector<int32> input_matrices_;
111+
/// Indexed by the same index as steps_, gives us the list of indexes at the
112+
/// input location for each step.
113+
std::vector<std::vector<Index> > input_indexes_;
114+
115+
116+
// Computes, for each cindex_id, the shortest distance to the input (0 for input
117+
// components). It is an error if some cindex_ids are not reachable from the
118+
// input.
119+
static void ComputeShortestDistances(
120+
const ConcreteComputationGraph &computation_graph,
121+
std::vector<int32> *shortest_distance);
122+
123+
124+
// This works out the steps of the computation and their order. Once you have
125+
// the shortest-distances from the input to the Cindexes, this function orders
126+
// the Cindexes from closest to furthest the input, and then within each
127+
// category that has the same distance to the input, orders the Cindexes by the
128+
// component index. This gives us categories with the same component index and
129+
// the same distance to the input, and those categories are the steps of the
130+
// computation. As special cases, all the accessed input nodes are listed first
131+
// and all the output nodes are listed last, with each input/output node
132+
// as a single step; and it makes sure that the order of the Cindexes at
133+
// the input and output steps is the same as the order specified in the
134+
// ComputationRequest.
135+
static void ComputeComputationOrder(
136+
const ComputationRequest &request,
137+
const ConcreteComputationGraph &computation_graph,
138+
const std::vector<int32> &shortest_distance,
139+
std::vector<std::vector<int32> > *steps);
140+
141+
// This function computes a vector that maps each cindex_id to the
142+
// corresponding two indices into "steps"; this also gives us
143+
// the location as (matrix-index, row-index) of each Cindex.
144+
static void ComputeLocationInfo(
145+
const std::vector<std::vector<int32> > &steps,
146+
std::vector<std::pair<int32, int32> > *cindex_id_to_location);
147+
148+
149+
// Assign some basic information about the steps of the computation, chiefly
150+
// the locations of the input and output matrices and the corresponding
151+
// derivatives; and index information about the input of each
152+
// step (only for real Components[?]).
153+
// Note, matrix-index zero is at this stage reserved for the empty matrix.
154+
// In the "computation" object, we store the sizes of these matrices.
155+
static void GetStepInfo(const ComputationRequest &request,
156+
const Nnet &nnet,
157+
std::vector<StepInfo> *step_info,
158+
NnetComputation *computation);
159+
160+
// [to be called after step_info_ is set up]. Adds to the computation the
161+
// commands that initialize all the matrices. Also defines sub-matrices
162+
// corresponding to each matrix, with the same index.
163+
void SetUpForwardMatrices(NnetComputation *computation);
164+
165+
// Adds to "computation" the commands to set up the input matrix for a step
166+
// ("step" must correspond to a Component or an output node). This
167+
// involves processing the InputDescriptor.
168+
void SetUpInputForward(int32 step, NnetComputation *computation);
169+
170+
// Adds to "computation" the command for the forward computation for this step
171+
// (which must correspond to a real component).
172+
void DoForwardComputation(int32 step, NnetComputation *computation);
173+
174+
// Adds to "computation" the commands to do backprop from the input
175+
// matrix for a step ("step" must correspond to a Component or an output
176+
// node). This involves processing the InputDescriptor.
177+
void BackpropFromInputBackward(int32 step, NnetComputation *computation);
94178

95-
179+
// Adds to "computation" the command for the backward computation for this step
180+
// (which must correspond to a real component).
181+
void DoBackwardComputation(int32 step, NnetComputation *computation);
182+
183+
// [to be called after step_info_ is set up and all the forward and backprop
184+
// commands have been added]. Adds to the computation the commands that
185+
// deinitialize all the matrices.
186+
void DestroyMatrices(NnetComputation *computation);
96187

97-
need e.g. out[1]
188+
};
98189

99-
out_obj=SoftmaxObject
100190

101-
out(t,n,x) = SoftmaxComponent(dim=1000), input=layer10(t,n,x)
102-
layer10(t,n,x) = AffineComponent(input-dim=1000, output-dim=1000), input=layer9(t,n,x)
103-
layer9(t,n,x) = RectifiedLinearComponent(dim=1000), input=Append(layer8(t-4,n,x), layer8(t+4,n,x))
104-
layer8(.....) =
105-
... below, input is a matrix! ...
106-
layer5(0,n,x) = AggregateComponent(dim=1000, sub-dim=5000), input=layer4(*, n, x) <--- The * could be, say, [100,200,300]
107-
<--- layer4 would have to have indexes declared.
108-
... this is many-to-one, so input would have to have a set of
109191

110-
layer1[t-5],layer1[t+5]
192+
} // namespace nnet2
193+
} // namespace kaldi
111194

112-
---
113-
At some point we generate a program.
114-
Training program example:
115195

116-
Declare matrices and sub-matrices (m), and "real components" (c),
117-
and backprop quantities n.
118-
119-
Assume input provided as m[0], output will be given as various
120-
parts of the matrices, including the output itself]. (e.g. DeclareOutput(...), meaning
121-
we can't delete it.)
122-
123-
124-
125-
*/
196+
#endif
197+

‎src/nnet3/nnet-component-itf.h‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,15 @@ enum ComponentProperties {
5353
// Note: if doing backprop, you'd also need to check
5454
// that the kBackpropNeedsInput property is not true.
5555
kBackpropInPlace = 0x080 // true if we can do the backprop operation in-place
56-
// (input and output matrices may be the same).
56+
// (input and output matrices may be the same).
57+
kPropagateAdds = 0x100, // true if the Propagate function adds to, rather
58+
// than setting, its output. The Component chooses
59+
// whether to add or set, and the calling code has to
60+
// accommodate it.
61+
kBackpropAdds = 0x200, // true if the Backprop function adds to, rather than
62+
// setting, its output. The Component chooses
63+
// whether to add or set, and the calling code has to
64+
// accommodate it.
5765
};
5866

5967

@@ -78,6 +86,9 @@ class Component {
7886
/// Propagate function. For simple components, "indexes" will be NULL. If
7987
/// Properties()&kPropagateInPlace, then "in" and "out" are allowed to be the
8088
/// same matrix.
89+
/// Computes the output of the operation given the input. If the "out" matrix
90+
/// is nonzero initially, the behavior depends on the Component, chosen
91+
/// according to the convenience of the Component itself
8192
virtual void Propagate(const ComponentPrecomputedIndexes *indexes,
8293
const CuMatrixBase<BaseFloat> &in,
8394
CuMatrixBase<BaseFloat> *out) const = 0;

‎src/nnet3/nnet-computation.h‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ struct ComputationRequest {
101101
// struct NnetComputation defines the specific steps of a neural-net
102102
// computation. View this as a compiled program; given the Nnet and the
103103
// ComputationRequest, we compile to struct NnetComputation.
104+
104105
struct NnetComputation {
105106
struct MatrixInfo {
106107
int32 num_rows;
@@ -130,7 +131,7 @@ struct NnetComputation {
130131
kResizeMatrixEmpty, kPropagate, kBackprop, kMatrixCopy, kMatrixAdd,
131132
kCopyRows, kCopyToRows, kAddRows, kAddToRows,
132133
kCopyRowsMulti, kCopyToRowsMulti, kAddRowsMulti,
133-
kAddToRowsMulti } computation_type;
134+
kAddToRowsMulti, kNoOperation, kNoOperationMarker } computation_type;
134135
// kResizeMatrixZeroed, kResizeMatrixUndefined: arg1 = index of matrix; arg2,arg3 are rows,cols.
135136
// kResizeMatrixEmpty: arg1 = index of matrix.
136137
// kPropagate: arg1 = index of component in nnet; arg2 is index of ComponentPrecomputedIndexes
@@ -148,6 +149,10 @@ struct NnetComputation {
148149
// "indexes_multi", of which each pair is (sub-matrix index, row index)
149150
// [note: any negative sub-matrix index will be converted to a NULL
150151
// pointer argument].
152+
// kNoOperation: no operation (sometimes useful during compilation but not
153+
// present in final "code").
154+
// kNoOperationMarker: no operation (sometimes useful during compilation but not
155+
// present in final "code"). Used during compilation only.
151156
int32 arg1;
152157
int32 arg2;
153158
int32 arg3;
@@ -195,15 +200,23 @@ struct NnetComputation {
195200
// don't include the info for those).
196201
std::unordered_map<int32, NodeInfo> node_info;
197202

198-
// The steps of the forward computation
199-
std::vector<ComputationStep> forward_computation;
203+
// The steps of the forward computation, and of the backward computation if
204+
// we're doing it.
205+
std::vector<ComputationStep> computation;
206+
207+
// the number of steps in the forward computation, so steps with index >= forward_computation_end
208+
// are part of the backward computation.
209+
int32 forward_computation_end;
200210

201-
// The steps of the backward computation (or the empty vector of we're
202-
// not doing any backward computation).
203-
std::vector<ComputationStep> backward_computation;
204211
};
205212

206213

214+
// This operator is to print out the NnetComputation in a human-readable way, for
215+
// debugging purposes.
216+
// We don't give Read and Write functions to struct NnetComputation, because we
217+
// don't anticipate needing to write it to disk.
218+
std::ostream &operator << (std::ostream &os,
219+
NnetComputation &computation);
207220

208221

209222

‎src/nnet3/nnet-descriptor.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ namespace nnet3 {
6565
// this class and things like copying and assignment will work correctly without
6666
// having to worry about memory allocation: we can't make a std::vector of an
6767
// abstract base-class.
68+
// note: nodes of type kOutput (i.e. output nodes of the network) cannot appear
69+
// as inputs in any descriptor. This is to simplify compilation.
6870
class ForwardingDescriptor {
6971
public:
7072
// Given an Index that's requested at the input of this Component (or at

‎src/nnet3/nnet-optimize.cc‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2015 Johns Hopkins University (author: Daniel Povey)
2+
3+
// See ../../COPYING for clarification regarding multiple authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12+
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
13+
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
14+
// MERCHANTABLITY OR NON-INFRINGEMENT.
15+
// See the Apache 2 License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#include <iterator>
19+
#include <sstream>
20+
#include "nnet2/nnet-compile.h"
21+
22+
namespace kaldi {
23+
namespace nnet2 {
24+
25+
26+
27+
28+
} // namespace nnet2
29+
} // namespace kaldi

0 commit comments

Comments
 (0)