Как вы вообще даете (openFST-made) вход FST? Куда идет вывод?
Прежде чем начать, обратите внимание, что я использую оболочку Linux (через using subprocess.call()
от Python), и я использую openFST.
Я просматривал документы и вопросы об openFST, но, похоже, я не могу найти ответ на этот вопрос: как на самом деле дать вклад в определенный, скомпилированный и составленный FST openFST? Куда идет вывод? Я просто выполняю 'fstproject'? Если да, то как, скажем, дать ему строку для преобразования и распечатать различные преобразования, когда будет достигнуто конечное состояние?
Я прошу прощения, если этот вопрос кажется очевидным. Я пока не очень знаком с openFST.
3 ответа
Одним из способов является создание вашей машины, которая выполняет преобразование. Очень простым примером будет верхний регистр строки.
M.wfst
0 0 a A
0 0 b B
0 0 c C
0
Файл сопровождающих символов содержит строку для каждого символа алфавита. Примечание 0 зарезервировано для нулевых (epsilon) переходов и имеет особое значение во многих операциях.
M.syms
<epsilon> 0
a 1
b 2
c 3
A 4
B 5
C 6
Затем скомпилируйте машину
fstcompile --isymbols=M.syms --osymbols=M.syms M.wfst > M.ofst
Для входной строки "abc" создайте автомат с линейной цепью, это цепочка слева направо с дугой для каждого символа. Это акцептор, поэтому нам нужен только столбец для входных символов.
I.wfst
0 1 a
1 2 b
2 3 c
3
Компилировать как акцептор
fstcompile --isymbols=M.syms --acceptor I.wfst > I.ofst
Затем составьте машины и распечатайте
fstcompose I.ofst M.ofst | fstprint --isymbols=M.syms --osymbols=M.syms
Это даст выход
0 1 a A
1 2 b B
2 3 c C
3
Выходные данные fstcompose представляют собой решетку всех преобразований входной строки. (В этом случае есть только один). Если M.ofst более сложный, fstshortestpath может использоваться для извлечения n-строк с использованием флагов --unique -nshortest=n. Этот вывод снова является преобразователем, вы можете либо удалить вывод fstprint, либо использовать код C++ и библиотеку OpenFst для запуска поиска в глубину для извлечения строк.
Вставка fstproject --project_output преобразует вывод в акцептор, содержащий только метки вывода.
fstcompose I.ofst M.ofst | fstproject --project_output | fstprint --isymbols=M.syms --osymbols=M.syms
Дает следующее
0 1 A A
1 2 B B
2 3 C C
3
Это акцептор, так как метки входа и выхода одинаковы, параметры --acceptor могут использоваться для генерации более краткого вывода.
fstcompose I.ofst M.ofst | fstproject --project_output | fstprint --isymbols=M.syms --acceptor
Пример от Пола Диксона великолепен. Поскольку OP использует Python, я подумал, что я хотел бы добавить быстрый пример того, как вы можете "запускать" преобразователи с помощью оболочки Open FST Python. Обидно, что вы не можете создать "линейные автоматы" с Open FST, но это просто автоматизировать, как показано ниже:
def linear_fst(elements, automata_op, keep_isymbols=True, **kwargs):
"""Produce a linear automata."""
compiler = fst.Compiler(isymbols=automata_op.input_symbols().copy(),
acceptor=keep_isymbols,
keep_isymbols=keep_isymbols,
**kwargs)
for i, el in enumerate(elements):
print >> compiler, "{} {} {}".format(i, i+1, el)
print >> compiler, str(i+1)
return compiler.compile()
def apply_fst(elements, automata_op, is_project=True, **kwargs):
"""Compose a linear automata generated from `elements` with `automata_op`.
Args:
elements (list): ordered list of edge symbols for a linear automata.
automata_op (Fst): automata that will be applied.
is_project (bool, optional): whether to keep only the output labels.
kwargs:
Additional arguments to the compiler of the linear automata .
"""
linear_automata = linear_fst(elements, automata_op, **kwargs)
out = fst.compose(linear_automata, automata_op)
if is_project:
out.project(project_output=True)
return out
Давайте определим простой преобразователь, который заглавными буквами "а":
f_ST = fst.SymbolTable()
f_ST.add_symbol("<eps>", 0)
f_ST.add_symbol("A", 1)
f_ST.add_symbol("a", 2)
f_ST.add_symbol("b", 3)
compiler = fst.Compiler(isymbols=f_ST, osymbols=f_ST, keep_isymbols=True, keep_osymbols=True)
print >> compiler, "0 0 a A"
print >> compiler, "0 0 b b"
print >> compiler, "0"
caps_A = compiler.compile()
caps_A
Теперь мы можем просто применить преобразователь, используя:
apply_fst(list("abab"), caps_A)
Чтобы увидеть, как использовать его для акцептора, посмотрите на мой другой ответ
Обновление ответа Янна Дюбуа на python3:
import pywrapfst as fst
print("")
f_ST: fst.SymbolTable
def linear_fst(elements, automata_op, keep_isymbols=True, **kwargs):
"""Produce a linear automata."""
compiler = fst.Compiler(
isymbols=f_ST, # There should be some way to get this from automata_op
acceptor=keep_isymbols,
keep_isymbols=keep_isymbols,
**kwargs
)
for i, el in enumerate(elements):
print("{} {} {}".format(i, i + 1, el), end="", file=compiler)
print(str(i + 1), end="", file=compiler)
lf = compiler.compile()
return lf
def apply_fst(elements, automata_op, print_la=True, is_project=False, **kwargs):
"""Compose a linear automata generated from `elements` with `automata_op`.
Args:
elements (list): ordered list of edge symbols for a linear automata.
automata_op (Fst): automata that will be applied.
print_la (bool, optional): print linear automata as text representation
is_project (str, optional): whether to keep only the "input" or "output" labels.
kwargs: Additional arguments to the compiler of the linear automata .
"""
linear_automata = linear_fst(elements, automata_op, **kwargs)
if print_la:
print("Linear Automata:\n", linear_automata)
out = fst.compose(linear_automata, automata_op)
if is_project:
out.project("output")
return out
f_ST = fst.SymbolTable()
f_ST.add_symbol("<eps>", 0)
f_ST.add_symbol("A", 1)
f_ST.add_symbol("a", 2)
f_ST.add_symbol("b", 3)
compiler = fst.Compiler(
isymbols=f_ST, osymbols=f_ST, keep_isymbols=True, keep_osymbols=True
)
print("0 0 a A", end="", file=compiler)
print("0 0 b b", end="", file=compiler)
print("0", end="", file=compiler)
caps_A = compiler.compile()
print("Uppercase Transducer with", caps_A.num_states(), "states:\n", caps_A)
caps_I = apply_fst(list("abab"), caps_A)
print("Output:\n", caps_I)
Это печатает:
Uppercase Transducer with 1 states:
0 0 a A
0 0 b b
0
Linear Automata:
0 1 a 2
1 2 b 3
2 3 a 2
3 4 b 3
4
Output:
0 1 a A
1 2 b b
2 3 a A
3 4 b b
4