Fsa
In this tutorial, we will show:
How to create an FSA in k2
How to create a 1-D vector of FSAs in k2
Common methods of
k2.Fsa
A single FSA
The following code shows how to create an FSA in k2:
s = '''
0 1 10 0.1
0 2 20 0.2
1 2 30 0.3
1 3 -1 0.4
2 3 -1 0.5
3
'''
fsa = k2.Fsa.from_str(s)
Please refer to k2.Fsa.from_str()
for the format of the string s that must have.
Visualization
The resulting FSA can be visualized via the following two APIs:
Hint
You have to install graphviz in order to use the above two APIs. It can be installed using the following command:
pip install graphviz
The return value of k2.to_dot()
can be visualized automagically in a jupyter notebook.
Fig. 10 is a screenshot of invoking k2.to_dot()
for the above FSA.
k2.Fsa.draw()
is able to save the resulting FSA to a file for offline visualization.
Its return value can also be displayed in a jupyter notebook. A screenshot of running
k2.Fsa.draw()
for the above FSA is shown in
The generated fsa.svg is visualized in Fig. 12.
Symbol table
You can also attach a symbol table to the above FSA:
sym_str = '''
a 10
b 20
c 30
'''
fsa.labels_sym = k2.SymbolTable.from_str(sym_str)
fsa.draw('fsa_symbols.svg', title='An FSA with symbol table')
The visualization result is given in Fig. 13.
To attach a symbol table to an FSA, just assign an instance of class k2.SymbolTable
to the labels_sym
attribute of the FSA.
Auxiliary labels
You can also attach an integer attribute to every arc in the FSA. If the attribute
name is aux_labels
, the resulting FSA is viewed as an FST in k2.
An example is given below.
fsa.aux_labels = torch.tensor([10, 0, 30, -1, -1]).to(torch.int32)
fsa.draw('fsa_aux.svg', title='An FSA with aux_labels')
Hint
We require that aux_labels is either a torch.Tensor with dtype torch.int32
or a ragged tensor of type k2.RaggedInt
.
Also note that the aux_labels for arcs entering the final state are -1.
Auxiliary symbol table
If an FSA is assigned an attribute with name aux_labels_sym
,
its aux_labels
is visualized with human readable strings instead of integer
IDs (the same
The following is an example.
aux_labels_sym = k2.SymbolTable.from_str('''
A 10
B 30
''')
fsa.aux_labels_sym = aux_labels_sym
fsa.draw('fsa_aux_symbols.svg', title='An FSA with aux_symbols')
invert
labels
and aux_labels
can be swapped using k2.Fsa.invert()
or k2.Fsa.invert_()
:
fsa.invert_()
fsa.draw('fsa_invert.svg')
fsa_invert.svg is shown in Fig. 14.
Caution
It is a convention in k2 that a method with name ending with an underscore
changes the object in-place. k2.Fsa.invert()
returns a new FSA,
whereas k2.Fsa.invert_()
modifies self in-place.
scores
scores
is one of the most important attributes of an FSA. There
is a score for every arc and k2.Fsa.scores
returns the scores
of an FSA in a 1-D torch.Tensor with dtype torch.float32:
print(fsa.scores)
# it prints:
# tensor([0.1000, 0.2000, 0.3000, 0.4000, 0.5000])
is_cpu
k2 supports CPU as well as CUDA. You can tell whether an FSA is on CPU with
k2.Fsa.is_cpu()
:
print(fsa.is_cpu())
If fsa is on CPU, the above code prints True; otherwise, it prints False.
is_cuda
To test whether an FSA is on CUDA GPU or not, you can use:
print(fsa.is_cuda())
If it prints True, the fsa is on a CUDA GPU; otherwise, it is on CPU.
to
An FSA can be moved among different devices with k2.Fsa.to()
:
device = torch.device('cpu')
fsa = fsa.to(device)
assert fsa.is_cpu()
assert fsa.device == torch.device('cpu')
fsa = fsa.to('cuda:1')
assert fsa.is_cuda()
assert fsa.device == torch.device('cuda', 1)
Note that you can use k2.Fsa.device
to get the device on which
the current FSA resides.
A list of FSAs: FsaVec
You can use k2.create_fsa_vec()
to create a FsaVec from a list of FSAs.
For example,
fsa_vec = k2.create_fsa_vec([fsa, fsa])
Both FsaVec and FSA are represented by a single Python class k2.Fsa
.
You can tell whether an instance of k2.Fsa
is a single FSA or a FsaVec
from its property k2.Fsa.shape
:
For a single FSA,
k2.Fsa.shape
returns a tuple with two elements (num_states, None)For a FsaVec,
k2.Fsa.shape
returns a tuple with three elements (num_fsas, None, None)