Kesalahan Tatabahasa with Tagging

This tutorial is available as an IPython notebook at Malaya/example/tatabahasa-tagging.

This module only trained on standard language structure, so it is not save to use it for local language structure.

[2]:
import malaya
from pprint import pprint

Model

Common Seq2Seq model, P(yt | X, yt-1), one step decoder will generate yt, and this required encoder output and output from last step decoder, yt-1.

So we improve the model to general tags also, P(yt, zt | X, yt-1, zt-1), one step decoder will generate yt and zt, and this required encoder output and outputs from last step decoder, yt-1 and zt-1.

We named this model as TransformerTag.

There is no paper produced for this model, feel free to write a paper about it, check out our implementation at https://github.com/huseinzol05/malaya/tree/master/session/tatabahasa

List available Transformer Tag models

[3]:
malaya.tatabahasa.available_transformer_tagging()
INFO:root:tested on 10k kesalahan tatabahasa texts.
[3]:
Size (MB) Quantized Size (MB) Sequence Accuracy Sequence Tagging Accuracy
small 397.0 100.0 0.860198 0.963267
base 875.0 220.0 0.938972 0.977407

Supported kesalahan tatabahasa

For full description, check out https://tatabahasabm.tripod.com/tata/salahtata.htm

[4]:
malaya.tatabahasa.describe_tagging()
[4]:
class Description salah betul
0 0 PAD
1 1 kesambungan subwords
2 2 tiada kesalahan
3 3 kesalahan frasa nama, Perkara yang diterangkan... Cili sos sos cili
4 4 kesalahan kata jamak mereka-mereka mereka
5 5 kesalahan kata penguat sangat tinggi sekali sangat tinggi
6 6 kata adjektif dan imbuhan "ter" tanpa penguat. Sani mendapat markah yang tertinggi sekali. Sani mendapat markah yang tertinggi.
7 7 kesalahan kata hubung Sally sedang membaca bila saya tiba di rumahnya. Sally sedang membaca apabila saya tiba di ruma...
8 8 kesalahan kata bilangan Beribu peniaga tidak membayar cukai pendapatan. Beribu-ribu peniaga tidak membayar cukai penda...
9 9 kesalahan kata sendi Umar telah berpindah daripada sekolah ini bula... Umar telah berpindah dari sekolah ini bulan lalu.
10 10 kesalahan penjodoh bilangan Setiap orang pelajar Setiap pelajar.
11 11 kesalahan kata ganti diri Pencuri itu telah ditangkap. Beliau dibawa ke ... Pencuri itu telah ditangkap. Dia dibawa ke bal...
12 12 kesalahan ayat pasif Cerpen itu telah dikarang oleh saya. Cerpen itu telah saya karang.
13 13 kesalahan kata tanya Kamu berasal dari manakah ? Kamu berasal dari mana ?
14 14 kesalahan tanda baca Kamu berasal dari manakah . Kamu berasal dari mana ?
15 15 kesalahan kata kerja tak transitif Dia kata kepada saya Dia berkata kepada saya
16 16 kesalahan kata kerja transitif Dia suka baca buku Dia suka membaca buku
17 17 penggunaan kata yang tidak tepat Tembuk Besar negeri Cina dibina oleh Shih Huan... Tembok Besar negeri Cina dibina oleh Shih Huan...

Right now we only able to predict up to 15 different kesalahan tatabahasa, hopefully in the future we can scale this up.

Load Transformer Tag model

def transformer_tagging(model: str = 'base', quantized: bool = False, **kwargs):
    """
    Load Malaya transformer encoder-decoder + tagging model to correct a `kesalahan tatabahasa` text.

    Parameters
    ----------
    model : str, optional (default='base')
        Model architecture supported. Allowed values:

        * ``'small'`` - Malaya Transformer Tag SMALL parameters.
        * ``'base'`` - Malaya Transformer Tag BASE parameters.

    quantized : bool, optional (default=False)
        if True, will load 8-bit quantized model.
        Quantized model not necessary faster, totally depends on the machine.

    Returns
    -------
    result: malaya.model.tf.Tatabahasa class
    """
[1]:
model = malaya.tatabahasa.transformer_tagging(model = 'base')

Load Quantized model

To load 8-bit quantized model, simply pass quantized = True, default is False.

We can expect slightly accuracy drop from quantized model, and not necessary faster than normal 32-bit float model, totally depends on machine.

[2]:
quantized_model = malaya.tatabahasa.transformer_tagging(model = 'base', quantized = True)

Predict using greedy decoder

def greedy_decoder(self, strings: List[str]):
    """
    Fix kesalahan tatatabahasa.

    Parameters
    ----------
    strings : List[str]

    Returns
    -------
    result: List[str]
    """

For TransformerTag model, right now only supported greedy_decoder method.

Randomly picked string in bahasa melayu wikipedia.

[7]:
# https://ms.wikipedia.org/wiki/Bola_sepak
string = 'Pada amnya, hanya penjaga gol sahaja yang dibenarkan menyentuh bola dengan tangan di dalam kawasan golnya'
[8]:
model.greedy_decoder([string])
[8]:
[[('Pada', 2),
  ('amnya', 2),
  (',', 2),
  ('hanya', 2),
  ('penjaga', 2),
  ('gol', 2),
  ('sahaja', 2),
  ('yang', 2),
  ('dibenarkan', 2),
  ('menyentuh', 2),
  ('bola', 2),
  ('dengan', 2),
  ('tangan', 2),
  ('di', 2),
  ('dalam', 2),
  ('kawasan', 2),
  ('golnya', 2)]]

Now assumed we have kesalahan frasa nama, from penjaga gol become gol penjaga.

[9]:
# https://ms.wikipedia.org/wiki/Bola_sepak
string = 'Pada amnya, hanya gol penjaga sahaja yang dibenarkan menyentuh bola dengan tangan di dalam kawasan golnya'
[10]:
model.greedy_decoder([string])
[10]:
[[('Pada', 2),
  ('amnya', 2),
  (',', 2),
  ('hanya', 2),
  ('penjaga', 3),
  ('gol', 3),
  ('sahaja', 2),
  ('yang', 2),
  ('dibenarkan', 2),
  ('menyentuh', 2),
  ('bola', 2),
  ('dengan', 2),
  ('tangan', 2),
  ('di', 2),
  ('dalam', 2),
  ('kawasan', 2),
  ('golnya', 2)]]
[11]:
string = 'Sani mendapat markah yang tertinggi sekali.'
string1 = 'Hassan ialah peserta yang termuda sekali dalam pertandingan itu.'
model.greedy_decoder([string, string1])
[11]:
[[('Sani', 2),
  ('mendapat', 2),
  ('markah', 2),
  ('yang', 2),
  ('tertinggi', 6),
  ('.', 2)],
 [('Hassan', 2),
  ('ialah', 2),
  ('peserta', 2),
  ('yang', 2),
  ('termuda', 6),
  ('dalam', 2),
  ('pertandingan', 2),
  ('itu', 2),
  ('.', 2)]]
[12]:
string = 'Dia kata kepada saya.'
model.greedy_decoder([string])
[12]:
[[('Dia', 2), ('berkata', 15), ('kepada', 2), ('saya', 2), ('.', 2)]]
[13]:
import pickle

with open('tests/dataset-tatabahasa.pkl', 'rb') as fopen:
    test_set = pickle.load(fopen)

len(test_set)
[13]:
100
[14]:
def get_xy(row):
    x, y, tag = [], [], []

    for i in range(len(row[0])):
        t = [row[0][i][0]]
        y.extend(t)
        t = [row[1][i][0]]
        x.extend(t)
        tag.extend([row[1][i][1]] * len(t))

    return ' '.join(x), ' '.join(y), tag
[15]:
x, y, t = get_xy(test_set[0])
x, y, t
[15]:
('Dirk Jan Klaas " Klaas-Jan " Huntelaar ( lahir 12 Ogos 1983 ) merupakan pemain bola sepak Belanda yang bermain seperti posisi penyerang !',
 'Dirk Jan Klaas " Klaas-Jan " Huntelaar ( lahir 12 Ogos 1983 ) merupakan pemain bola sepak Belanda yang bermain di posisi penyerang .',
 [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2, 14])
[16]:
model.greedy_decoder([x])
[16]:
[[('Dirk', 2),
  ('Jan', 2),
  ('Klaas', 2),
  ('"', 2),
  ('Klaas-Jan', 2),
  ('"', 2),
  ('Huntelaar', 2),
  ('(', 2),
  ('lahir', 2),
  ('12', 2),
  ('Ogos', 2),
  ('1983', 2),
  (')', 2),
  ('merupakan', 2),
  ('pemain', 2),
  ('bola', 2),
  ('sepak', 2),
  ('Belanda', 2),
  ('yang', 2),
  ('bermain', 2),
  ('di', 9),
  ('posisi', 2),
  ('penyerang', 2),
  ('.', 14)]]
[17]:
quantized_model.greedy_decoder([x])
[17]:
[[('Dirk', 2),
  ('Jan', 2),
  ('Klaas', 2),
  ('"', 2),
  ('Klaas-Jan', 2),
  ('"', 2),
  ('Huntelaar', 2),
  ('(', 2),
  ('lahir', 2),
  ('12', 2),
  ('Ogos', 2),
  ('1983', 2),
  (')', 2),
  ('merupakan', 2),
  ('pemain', 2),
  ('bola', 2),
  ('sepak', 2),
  ('Belanda', 2),
  ('yang', 2),
  ('bermain', 2),
  ('di', 9),
  ('posisi', 2),
  ('penyerang', 2),
  ('.', 14)]]
[18]:
x, y, t = get_xy(test_set[-1])
x, y, t
[18]:
('Pada tahun 2002 , kedua-dua gol beliau menduduki tempat ke-6 dalam 100 Greatest Sporting Moments oleh saluran Channel 4 UK .',
 'Pada tahun 2002 , kedua-dua gol ini menduduki tempat ke-6 dalam 100 Greatest Sporting Moments oleh saluran Channel 4 UK .',
 [2, 2, 2, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
[19]:
model.greedy_decoder([x])
[19]:
[[('Pada', 2),
  ('tahun', 2),
  ('2002', 2),
  (',', 2),
  ('kedua-dua', 2),
  ('gol', 2),
  ('beliau', 2),
  ('menduduki', 2),
  ('tempat', 2),
  ('ke-6', 2),
  ('dalam', 2),
  ('100', 2),
  ('Greatest', 2),
  ('Sporting', 2),
  ('Moments', 2),
  ('oleh', 2),
  ('saluran', 2),
  ('Channel', 2),
  ('4', 2),
  ('UK', 2),
  ('.', 2)]]
[20]:
x, y, t = get_xy(test_set[-2])
x, y, t
[20]:
('Gol inilah yang bergelar Goal of the Century dengan undian Internet 2000 sejak FIFA .',
 'Gol inilah yang bergelar Goal of the Century di undian Internet 2000 oleh FIFA .',
 [2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 2, 2])
[21]:
model.greedy_decoder([x])
[21]:
[[('Gol', 2),
  ('inilah', 2),
  ('yang', 2),
  ('bergelar', 2),
  ('Goal', 2),
  ('of', 2),
  ('the', 2),
  ('Century', 2),
  ('dengan', 2),
  ('undian', 2),
  ('Internet', 2),
  ('2000', 2),
  ('sejak', 2),
  ('FIFA', 2),
  ('.', 2)]]
[22]:
x, y, t = get_xy(test_set[-3])
x, y, t
[22]:
('Beliau mengambil bola dalam kawasan kepul diri lalu pusing dan luru lebih separuh padang sambil menyentuh bola 11 kali , memintas lima pemain England : ( Glenn Hoddle , Peter Reid , Kenny Sansom , Terry Butcher , dan Terry Fenwick ) serta penjaga gawang Peter Shilton .',
 'Beliau mengambil bola di kawasan pasukan diri lalu berpusing-pusing dan meluru lebih separuh padang sambil menyentuh bola 11 kali , memintas lima pemain England : ( Glenn Hoddle , Peter Reid , Kenny Sansom , Terry Butcher , dan Terry Fenwick ) serta penjaga gawang Peter Shilton .',
 [2,
  2,
  2,
  9,
  2,
  10,
  2,
  2,
  15,
  2,
  15,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2,
  2])
[23]:
model.greedy_decoder([x])
[23]:
[[('Beliau', 2),
  ('mengambil', 2),
  ('bola', 2),
  ('dari', 9),
  ('kawasan', 2),
  ('kaki', 10),
  ('diri', 2),
  ('lalu', 2),
  ('berpusing', 15),
  ('dan', 2),
  ('meluru', 15),
  ('lebih', 2),
  ('separuh', 2),
  ('padang', 2),
  ('sambil', 2),
  ('menyentuh', 2),
  ('bola', 2),
  ('11', 2),
  ('kali', 2),
  (',', 2),
  ('memintas', 2),
  ('lima', 2),
  ('pemain', 2),
  ('England', 2),
  (':', 2),
  ('(', 2),
  ('Glenn', 2),
  ('Hoddle', 2),
  (',', 2),
  ('Peter', 2),
  ('Reid', 2),
  (',', 2),
  ('Kenny', 2),
  ('Sansom', 2),
  (',', 2),
  ('Terry', 2),
  ('Butcher', 2),
  (',', 2),
  ('dan', 2),
  ('Terry', 2),
  ('Fenwick', 2),
  (')', 2),
  ('serta', 2),
  ('penjaga', 2),
  ('gawang', 2),
  ('Peter', 2),
  ('Shilton', 2),
  ('.', 2)]]
[24]:
quantized_model.greedy_decoder([x])
[24]:
[[('Beliau', 2),
  ('mengambil', 2),
  ('bola', 2),
  ('dari', 9),
  ('kawasan', 2),
  ('kaki', 10),
  ('diri', 2),
  ('lalu', 2),
  ('berpusing', 15),
  ('dan', 2),
  ('meluru', 15),
  ('lebih', 2),
  ('separuh', 2),
  ('padang', 2),
  ('sambil', 2),
  ('menyentuh', 2),
  ('bola', 2),
  ('11', 2),
  ('kali', 2),
  (',', 2),
  ('memintas', 2),
  ('lima', 2),
  ('pemain', 2),
  ('England', 2),
  (':', 2),
  ('(', 2),
  ('Glenn', 2),
  ('Hoddle', 2),
  (',', 2),
  ('Peter', 2),
  ('Reid', 2),
  (',', 2),
  ('Kenny', 2),
  ('Sansom', 2),
  (',', 2),
  ('Terry', 2),
  ('Butcher', 2),
  (',', 2),
  ('dan', 2),
  ('Terry', 2),
  ('Fenwick', 2),
  (')', 2),
  ('serta', 2),
  ('penjaga', 2),
  ('gawang', 2),
  ('Peter', 2),
  ('Shilton', 2),
  ('.', 2)]]

More examples

I just copy pasted from https://ms.wikipedia.org/wiki/Kesalahan_biasa_tatabahasa_Melayu

[26]:
string = 'Tidak ada apa yang mereka risaukan waktu itu.'
model.greedy_decoder([string])
[26]:
[[('Tidak', 2),
  ('ada', 2),
  ('apa', 2),
  ('yang', 2),
  ('mereka', 2),
  ('risaukan', 2),
  ('waktu', 2),
  ('itu', 2),
  ('.', 2)]]
[27]:
string = 'Ayahnya setuju walaupun melanggar syarat yang dia sendiri menetapkan.'
model.greedy_decoder([string])
[27]:
[[('Ayahnya', 2),
  ('setuju', 2),
  ('dan', 7),
  ('melanggar', 2),
  ('syarat', 2),
  ('yang', 2),
  ('dia', 2),
  ('sendiri', 2),
  ('menetapkan', 2),
  ('.', 2)]]
[28]:
string = 'Semuanya dia kenal.'
model.greedy_decoder([string])
[28]:
[[('Semuanya', 2), ('dia', 2), ('terkenal', 15), ('.', 2)]]
[29]:
string = 'Dia menjawab seperti disuruh-suruh oleh kuasa yang dia tidak tahu dari mana puncanya.'
model.greedy_decoder([string])
[29]:
[[('Dia', 2),
  ('menjawab', 2),
  ('seperti', 2),
  ('disuruh-suruh', 2),
  ('oleh', 2),
  ('kuasa', 2),
  ('yang', 2),
  ('dia', 2),
  ('tidak', 2),
  ('tahu', 2),
  ('dari', 2),
  ('mana', 2),
  ('puncanya', 2),
  ('.', 2)]]
[30]:
string = 'Bola ini ditendang oleh saya.'
model.greedy_decoder([string])
[30]:
[[('Bola', 2),
  ('ini', 2),
  ('ditendang', 2),
  ('oleh', 2),
  ('saya', 2),
  ('.', 2)]]
[31]:
string = 'Makanan ini kamu telah makan?'
model.greedy_decoder([string])
[31]:
[[('Makanan', 2),
  ('ini', 2),
  ('kamu', 2),
  ('telah', 2),
  ('makan', 2),
  ('.', 14)]]
[32]:
string = 'Segala perubahan yang berlaku kita akan menghadapi sama-sama.'
model.greedy_decoder([string])
[32]:
[[('Segala', 2),
  ('perubahan', 2),
  ('yang', 2),
  ('berlaku', 2),
  ('kita', 2),
  ('akan', 2),
  ('menghadapi', 2),
  ('sama-sama', 2),
  ('.', 2)]]
[33]:
string = 'Kakak saya sedang memasak gulai nangka. Dia menyenduk seketul nangka gulai dan menyuruh saya merasanya.'
model.greedy_decoder([string])
[33]:
[[('Kakak', 2),
  ('saya', 2),
  ('sedang', 2),
  ('memasak', 2),
  ('gulai', 2),
  ('nangka', 2),
  ('.', 2),
  ('Dia', 2),
  ('menyenduk', 2),
  ('seketul', 2),
  ('gulai', 3),
  ('nangka', 3),
  ('dan', 2),
  ('menyuruh', 2),
  ('saya', 2),
  ('merasanya', 2),
  ('.', 2)]]
[34]:
string = 'Sally sedang membaca bila saya tiba di rumahnya.'
model.greedy_decoder([string])
[34]:
[[('Sally', 2),
  ('sedang', 2),
  ('membaca', 2),
  ('bila', 2),
  ('dia', 11),
  ('tiba', 2),
  ('di', 2),
  ('rumahnya', 2),
  ('.', 2)]]
[35]:
string = 'Badannya besar kecuali kakinya kecil.'
model.greedy_decoder([string])
[35]:
[[('Badannya', 2),
  ('besar', 2),
  ('dan', 7),
  ('kakinya', 2),
  ('kecil', 2),
  ('.', 2)]]
[36]:
string = 'Beribu peniaga tidak membayar cukai pendapatan.'
model.greedy_decoder([string])
[36]:
[[('Beribu', 2),
  ('peniaga', 2),
  ('tidak', 2),
  ('membayar', 2),
  ('cukai', 2),
  ('pendapatan', 2),
  ('.', 2)]]
[37]:
string = 'Setengah remaja suka membuang masa di pasar raya.'
model.greedy_decoder([string])
[37]:
[[('Setengah', 2),
  ('remaja', 2),
  ('suka', 2),
  ('membuang', 2),
  ('masa', 2),
  ('di', 2),
  ('pasar', 2),
  ('raya', 2),
  ('.', 2)]]
[38]:
string = 'Umar telah berpindah daripada sekolah ini bulan lalu.'
model.greedy_decoder([string])
[38]:
[[('Umar', 2),
  ('telah', 2),
  ('berpindah', 2),
  ('daripada', 2),
  ('sekolah', 2),
  ('ini', 2),
  ('bulan', 2),
  ('lalu', 2),
  ('.', 2)]]
[39]:
string = 'Para-para peserta sedang berbaris.'
model.greedy_decoder([string])
[39]:
[[('Para', 4), ('peserta', 2), ('sedang', 2), ('berbaris', 2), ('.', 2)]]
[ ]: