Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge pull request #51 #53

Merged
merged 34 commits into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9ffae3
Added interface for auxiliary labels
danpovey May 5, 2020
a9e1768
Add notes on Python interface
danpovey May 5, 2020
9f76458
Fix typos
danpovey May 6, 2020
09915bb
Merge master
danpovey May 6, 2020
10e6712
Fix conflicts, remove some typedefs
danpovey May 6, 2020
735f83d
Fixes from review
danpovey May 6, 2020
80339a5
Small fixes in determinization code
danpovey May 6, 2020
14b50b1
Merge remote-tracking branch 'upstream/master' into aux_labels
danpovey May 6, 2020
3afad81
Progress on determinization code; add new declarations of un-pruned f…
danpovey May 8, 2020
f78f328
Merge remote-tracking branch 'upstream/master' into aux_labels
danpovey May 8, 2020
14a7cca
Fix compile error
danpovey May 8, 2020
3167864
Resolve conflicts
danpovey May 8, 2020
c8378d4
Add LogAdd
danpovey May 9, 2020
04fafe3
Fix compile errors in util.h
danpovey May 9, 2020
908457b
More progress on determinization code
danpovey May 11, 2020
9218fc1
Merge master
danpovey May 11, 2020
3ed45fa
More progress on determinizaton draft.
danpovey May 12, 2020
a79f527
More work on Determinize code.
danpovey May 13, 2020
151adbb
Draft of ConstFsa interface and CfsaVec
danpovey May 25, 2020
8f729e3
Add interface for ConstFsa; more notes on python interface
danpovey May 25, 2020
ff625fd
Small fixes to ConstFsa interface
danpovey May 26, 2020
283ec84
Changes from review
danpovey May 28, 2020
d9ebcd4
Merge remote-tracking branch 'upstream/master' into cfsa_etc
danpovey May 28, 2020
96a4bd5
Fix style issues
danpovey May 28, 2020
7e54a4d
Add itf for DenseFsa (not compiled)
danpovey May 30, 2020
4407079
Merge remote-tracking branch 'upstream/master' into cfsa_etc
danpovey May 30, 2020
fd34f65
Draft of Array2/Array3
danpovey Jun 4, 2020
97d1496
Merge master
danpovey Jun 4, 2020
f4c6f9f
Some notes on how this would work in Python
danpovey Jun 4, 2020
1a12dc3
Fix conflict
danpovey Jun 4, 2020
8e8b74d
[src] More drafts in array stuff, RE interface of functions.
danpovey Jun 5, 2020
18823fe
Further changes
danpovey Jun 5, 2020
37aafd8
Merge branch 'master'
qindazhu Jun 5, 2020
4dbfb57
merge Dan's PR about Array2
qindazhu Jun 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions k2/csrc/array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// k2/csrc/array.h

// Copyright (c) 2020 Xiaomi Corporation (author: Daniel Povey)

// See ../../LICENSE for clarification regarding multiple authors

#ifndef K2_CSRC_ARRAY_H_
#define K2_CSRC_ARRAY_H_

#include <functional>
#include <limits>
#include <memory>
#include <vector>

namespace k2 {

/*
We will use e.g. StridedPtr<int32_t, T> when the stride is not 1, and
otherwise just T* (which presumably be faster).
*/
template <typename I, typename T>
struct StridedPtr {
T *data;
I stride;
T &operator[](I i) { return data[i]; }
StridedPtr(T *data, I stride) : data(data), stride(stride) {}
};

/* MIGHT NOT NEED THIS */
template <typename I, typename Ptr>
struct Array1 {
// Irregular two dimensional array of something, like vector<vector<X> >
// where Ptr is, or behaves like, X*.
using IndexT = I;
using PtrT = Ptr;

// 'begin' and 'end' are the first and one-past-the-last indexes into `data`
// that we are allowed to use.
IndexT begin;
IndexT end;

PtrT data;
};

/*
This struct stores the size of an Array2 object; it will generally be used as
an output argument by functions that work out this size.
*/
template <typename I>
struct Array2Size {
using IndexT = I;
// `size1` is the top-level size of the array, equal to the object's .size
// element
I size1;
// `size2` is the nunber of elements in the array, equal to
// o->indexes[o->size] - o->indexes[0] (if the Array2 object o is
// initialized).
I size2;
};

template <typename I, typename Ptr>
struct Array2 {
// Irregular two dimensional array of something, like vector<vector<X> >
// where Ptr is, or behaves like, X*.
using IndexT = I;
using PtrT = Ptr;

IndexT size;
const IndexT *indexes; // indexes[0,1,...size] should be defined; note, this
// means the array must be of at least size+1. We
// require that indexes[i] <= indexes[i+1], but it is
// not required that indexes[0] == 0, it may be
// greater than 0.

PtrT data; // `data` might be an actual pointer, or might be some object
// supporting operator []. data[indexes[0]] through
// data[indexes[size] - 1] must be accessible through this
// object.

/* initialized definition:

An Array2 object is initialized if its `size` member is set and its
`indexes` and `data` pointer allocated, and the values of its `indexes`
array are set for indexes[0] and indexes[size].
*/
};

template <typename I, typename Ptr>
struct Array3 {
// Irregular three dimensional array of something, like vector<vector<vetor<X>
// > > where Ptr is or behaves like X*.
using IndexT = I;
using PtrT = Ptr;

IndexT size;
const IndexT *indexes1; // indexes1[0,1,...size] should be defined; note,
// this means the array must be of at least size+1.
// We require that indexes[i] <= indexes[i+1], but it
// is not required that indexes[0] == 0, it may be
// greater than 0.

const IndexT *indexes2; // indexes2[indexes1[0]]
// .. indexes2[indexes1[size]-1] should be defined.

Ptr data; // `data` might be an actual pointer, or might be some object
// supporting operator []. data[indexes[0]] through
// data[indexes[size] - 1] must be accessible through this
// object.

Array2<I, Ptr> operator[](I i) {
// TODO(haowen): fill real data here
Array2<I, Ptr> array;
return array;
}
};

// Note: we can create Array4 later if we need it.

} // namespace k2

#endif // K2_CSRC_ARRAY_H_
37 changes: 37 additions & 0 deletions k2/csrc/aux_labels.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <vector>

#include "k2/csrc/array.h"
#include "k2/csrc/fsa.h"
#include "k2/csrc/fsa_util.h"
#include "k2/csrc/properties.h"
Expand Down Expand Up @@ -46,6 +47,9 @@ struct AuxLabels {
std::vector<int32_t> labels;
};

// TODO(haowen): replace AuxLabels above with below definition
using AuxLabels_ = Array2<int32_t, int32_t>;

// Swap AuxLabels; it's cheap to to this as we are actually doing shallow swap.
void Swap(AuxLabels *labels1, AuxLabels *labels2);

Expand Down Expand Up @@ -95,6 +99,39 @@ void MapAuxLabels2(const AuxLabels &labels_in,
void InvertFst(const Fsa &fsa_in, const AuxLabels &labels_in, Fsa *fsa_out,
AuxLabels *aux_labels_out);

class FstInverter {
/* Constructor. Lightweight. */
FstInverter(const Fsa &fsa_in, const AuxLabels &labels_in);

/*
Do enough work that know now much memory will be needed, and output
that information
@param [out] fsa_size The num-states and num-arcs of the FSA
will be written to here
@param [out] aux_size The number of lists in the AuxLabels
output (==num-arcs) and the number of
elements will be written to here.
*/
void GetSizes(Array2Size<int32_t> *fsa_size, Array2Size<int32_t> *aux_size);

/*
Finish the operation and output inverted FSA to `fsa_out` and
auxiliary labels to `labels_out`.
@param [out] fsa_out The inverted FSA will be written to
here. Must be initialized; search for
'initialized definition' in class Array2
in array.h for meaning.
@param [out] labels_out The auxiliary labels will be written to
here. Must be initialized; search for
'initialized definition' in class Array2
in array.h for meaning.
*/
void GetOutput(Fsa *fsa_out, AuxLabels *labels_out);

private:
// ...
};

} // namespace k2

#endif // K2_CSRC_AUX_LABELS_H_
7 changes: 6 additions & 1 deletion k2/csrc/fsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <vector>

#include "glog/logging.h"
#include "k2/csrc/array.h"
#include "k2/csrc/util.h"

namespace k2 {
Expand Down Expand Up @@ -129,6 +130,10 @@ struct Fsa {
}
};

// TODO(haowen): replace Cfsa and CfsaVec with below definitions
using Cfsa_ = Array2<int32_t, Arc>;
using CfsaVec_ = Array3<int32_t, Arc>;

/*
Cfsa is a 'const' FSA, which we'll use as the input to operations. It is
designed in such a way that the storage underlying it may either be an Fsa
Expand Down Expand Up @@ -157,7 +162,7 @@ struct Cfsa {
// are valid. CAUTION: arc_indexes[0] may be
// greater than zero.

Arc *arcs; // Note: arcs[BeginArcIndex()] through arcs[EndArcIndex() - 1]
Arc *arcs; // Note: arcs[begin_arc] through arcs[end_arc - 1]
// are valid.

Cfsa();
Expand Down
57 changes: 57 additions & 0 deletions notes/array.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@





# defining type k2.Array


class Array:

# `indexes` is a Tensor with one
Tensor indexes;

# `data` is either:
# - of type Tensor (if this corresponds to Array2 == 2-dimensional
# array in C++)
# - of type Array (if this corresponds to Array3 or higher-dimensional
# array in C++)
# The Python code is structured a bit differently from the C++ code,
# due to the differences in the languages.
# When we dispatch things to C++ code there would be some
# big switch statement or if-statement to select the right
# template instantiation.
data;

def __len__(self):
return indexes.shape[0] - 1

@property
def shape(self):
# e.g. if indexes.shape is (15,) and
# data.shape is (150) -> this.shape would be (15,None)
# If data.shape is (150,4), this.shape would be (15,4)
# If data.shape is (150,None) (since data is an Array), this.shape
# would be (150,None,None).
# The Nones are for dimensions where the shape is not known
# because it is variable.
return (indexes.shape[0] - 1, None, *data.shape[1:])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments are confusing compared to
return (indexes.shape[0] - 1, None, *data.shape[1:]).

Could you please make it clearer? @danpovey

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think indexes.shape should be 16 here. Can you please edit though? Sorry I am a bit busy today. I am hoping @qindazhu can have a look at your PR. Thanks so much!!




class Fsa(Array):

# Think of this as a vector of vector of Arc, or in C++,
# an Array2<Arc>.
# An Arc has 3 int32_t's, so this.data is a Tensor with
# dtype int32 and shape (_, 3).



class FsaVec(Array):

# Think of this as a vector of vector of vector of Arc, or in C++,
# an Array3<Arc>.
#
# this.data is an Array, and this.data.data is a Tensor with
# dtype int32 and shape (_, 3).
85 changes: 34 additions & 51 deletions notes/python.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@
# note: fsas_det still has `phone_syms` and `nnet_arc_indexes`, now as sequences.


def PseudoTensor:
"""This is a class that behaves like a torch.Tensor but in fact only supports one kind of
operation, namely indexing with another torch.Tensor"""
def __init__(self, t, divisor):
""" Constructor.
Parameters:
t: torch.LongTensor
divisor: int
"""
self.t = t
self.divisor = divisor
def __getitem__(self, indexes):
return self.t[indexes / divisor]

def DenseFsaVec:

Expand Down Expand Up @@ -246,66 +259,36 @@ def DenseFsaVec:
# loglikes, one per arc of the CfsaVec object. This is
# a repeat of `loglikes` but possibly in a different
# order.


pass

@property
def loglikes(self):
return self.arc_loglikes


def seg_frames_for_arcs(self, arc_indexes):
"""
Returns the frame-indexes relative to the start of each segment
for each of a provided list of arc indexes, as a torch.LongTensor.
"""

# Note: self.seg_frame_indexes will be a torch.IntTensor containing
# the frame index for each arc. Later we'll address not being
# able to index with IntTensor but only LongTensor.
return self.seg_frame_indexes[arc_indexes / self.num_symbols]

def seq_frames_for_arcs(self, arc_indexes):
"""
Returns the frame-indexes relative to the start of each sequence
for each of a provided list of arc indexes, as a torch.LongTensor.

Note: if a returned frame-index equals num_frames, then that
frame was a `final-arc` (a special arc going to the final state),
which cannot be used to index the `loglikes` array provided to
the constructor because it's out-of-range.
"""

# Note: self.seq_frame_indexes will be a torch.IntTensor containing
# the frame index for each arc. Later we'll address not being
# able to index with IntTensor but only LongTensor.
return self.seq_frame_indexes[arc_indexes / self.num_symbols]

def segments_for_arcs(self, arc_indexes):
"""
Return the segment-indexes for each of a provided list of arcs,
which tells you which segment it was a part of.
"""
return self.segment_indexes[arc_indexes / self.num_symbols]

def seqs_for_arcs(self, arc_indexes):
"""
Return the segment-indexes for each of a provided list of arcs,
which tells you which sequence it was a part of.
@property
def seg_frames(self):
"""Return something that 'acts' like a tensor, indexed by arc, of
the frame-index relative to the segment start corresponding to that
arc. NOTE: self.frame_loglikes will actually be a sub-Tensor
of the Tensor created at the C++ level as the DenseFsaVecMeta object.
"""
return self.input_seq_indexes[self.segments_for_arcs(arc_indexes)]






# compute posteriors..
first_pass_posts =



return PseudoTensor(self.frame_loglikes, self.num_symbols)


@property
def seq_frames(self):
""" as for seg_frames"""
pass

@property
def seq_ids(self):
""" as for seg_frames"""
pass

nnet_post = log_softmax(nnet_output) # might use this later for something..
@property
def seg_ids(self):
""" as for seg_frames"""
pass