KWT-2024/lab/lab_02.ipynb
2024-04-15 19:34:20 +02:00

13 KiB

Logo 1

Komputerowe wspomaganie tłumaczenia

2. Zaawansowane użycie pamięci tłumaczeń [laboratoria]

Rafał Jaworski (2021)

Logo 2

Wiemy już, do czego służy pamięć tłumaczeń. Spróbujmy przeprowadzić mały research, którego celem będzie odkrycie, w jaki sposób do pamięci tłumaczeń podchodzą najwięksi producenci oprogramowania typu CAT.

Ćwiczenie 1: Wykonaj analizę funkcjonalności pamięci tłumaczeń w programach SDL Trados Studio 2021 oraz Kilgray memoQ. Dla obu programów wypisz funkcje, które są związane z TM oraz zaznacz, które funkcje są wspólne dla obu programów oraz których funkcji Tradosa brakuje w memoQ oraz odwrotnie.

Odpowiedź:

Jedną z funkcji dostępnych we wszystkich większych programach do wspomagania tłumaczenia jest znajdowanie bardzo pewnych dopasowań w pamięci tłumaczeń. Są one zwane ICE (In-Context Exact match) lub 101% match. Są to takie dopasowania z pamięci tłumaczeń, dla których nie tylko zdanie źródłowe z TM jest identyczne z tłumaczonym, ale także poprzednie zdanie źródłowe z TM zgadza się z poprzednim zdaniem tłumaczonym oraz następne z TM z następnym tłumaczonym.

Rozważmy przykładową pamięć tłumaczeń z poprzednich zajęć (można do niej dorzucić kilka przykładów):

translation_memory = [
                      ('Wciśnij przycisk Enter', 'Press the ENTER button'), 
                      ('Sprawdź ustawienia sieciowe', 'Check the network settings'),
                      ('Drukarka jest wyłączona', 'The printer is switched off'),
                      ('Wymagane ponowne uruchomienie komputera', 'System restart required')
                     ]

Ćwiczenie 2: Zaimplementuj funkcję ice_lookup, przyjmującą trzy parametry: aktualnie tłumaczone zdanie, poprzednio tłumaczone zdanie, następne zdanie do tłumaczenia. Funkcja powinna zwracać dopasowania typu ICE. Nie pozwól, aby doszło do błędów podczas sprawdzania pierwszego i ostatniego przykładu w pamięci (ze względu na brak odpowiednio poprzedzającego oraz następującego przykładu).

def prepare_dictionary(sentences):
    dict = {}

    for entry in sentences:
        dict[entry[0].lower()] = entry

    return dict

memory_dict = prepare_dictionary(translation_memory)

def ice_lookup(input, prev_sentence, next_sentence): 
    sentence = input.lower()

    if prev_sentence.lower() in memory_dict and next_sentence.lower() in memory_dict and sentence in memory_dict:
        return memory_dict[sentence]

    return []
ice_lookup("Wciśnij przycisk Enter", "Sprawdź ustawienia sieciowe", "Drukarka jest wyłączona")
('Wciśnij przycisk Enter', 'Press the ENTER button')

Inną powszechnie stosowaną techniką przeszukiwania pamięci tłumaczeń jest tzw. fuzzy matching. Technika ta polega na wyszukiwaniu zdań z pamięci, które są tylko podobne do zdania tłumaczonego. Na poprzednich zajęciach wykonywaliśmy funkcję tm_lookup, która pozwalała na różnicę jednego słowa.

Zazwyczaj jednak funkcje fuzzy match posiadają znacznie szersze możliwości. Ich działanie opiera się na zdefiniowaniu funkcji $d$ dystansu pomiędzy zdaniami $x$ i $y$. Matematycznie, funkcja dystansu posiada następujące właściwości:

  1. $\forall_{x,y} d(x,y)\geqslant 0$
  2. $\forall_{x,y} d(x,y)=0 \Leftrightarrow x=y$
  3. $\forall_{x,y} d(x,y)=d(y,x)$
  4. $\forall_{x,y,z} d(x,y) + d(y,z)\geqslant d(x,z)$

Rozważmy następującą funkcję:

def sentence_distance(x,y):
    return abs(len(y) - len(x))

Ćwiczenie 3: Czy to jest poprawna funkcja dystansu? Które warunki spełnia?

Odpowiedź: Nie, nie jest poprawna. Cechy:

  • nieujemna (abs > 0)
  • identyfikacja nie jest spelniona -> moga miec taka sama dlugosc, a byc inne
  • symetryczna - wynik z wartosci bezwglednej
  • nierownosc trojkata nie jest spelniona

A teraz spójrzmy na taką funkcję:

def sentence_distance(x,y):
    if (x == y):
        return 0
    else:
        return 3

Ćwiczenie 4: Czy to jest poprawna funkcja dystansu? Które warunki spełnia?

Odpowiedź: z punktu widzenia cech, wszystkie cechy sa spelnione, jednak funkcja sama w sobie jest bezuyteczna poprzez to, ze wartosci sa stale.

Wprowadźmy jednak inną funkcję dystansu - dystans Levenshteina. Dystans Levenshteina pomiędzy dwoma łańcuchami znaków definiuje się jako minimalną liczbę operacji edycyjnych, które są potrzebne do przekształcenia jednego łańcucha znaków w drugi. Wyróżniamy trzy operacje edycyjne:

  • dodanie znaku
  • usunięcie znaku
  • zamiana znaku na inny

Ćwiczenie 5: Czy dystans Levenshteina jest poprawną funkcją dystansu? Uzasadnij krótko swoją odpowiedź sprawdzając każdy z warunków.

Odpowiedź: Tak, poniewaz spelnia cechy:

  • nieujemnosci - zawsze dodatni lub zero gdy a i b jest rowny sobie
  • symetria - dystans od a i b jest taki sam jak b i a
  • nierownosc trojkata - dystans od ciągu A do C przez B jest zawsze mniejszy lub równy sumie dystansów od A do B i od B do C

W Pythonie dostępna jest biblioteka zawierająca implementację dystansu Levenshteina. Zainstaluj ją w swoim systemie przy użyciu polecenia:

pip3 install python-Levenshtein

I wypróbuj:

from Levenshtein import distance as levenshtein_distance

levenshtein_distance("kotek", "kotki")
2

Funkcja ta daje nam możliwość zdefiniowania podobieństwa pomiędzy zdaniami:

def levenshtein_similarity(x,y):
    return 1 - levenshtein_distance(x,y) / max(len(x), len(y))

Przetestujmy ją!

levenshtein_similarity('Program jest uruchomiony', 'Program jest uruchamiany')
0.9166666666666666
levenshtein_similarity('Spróbuj wyłączyć i włączyć komputer', 'Spróbuj włączyć i wyłączyć komputer')
0.9428571428571428
levenshtein_similarity('Spróbuj wyłączyć i włączyć komputer', 'Nie próbuj wyłączać i włączać drukarki')
0.631578947368421

Ćwiczenie 6: Napisz funkcję fuzzy_lookup, która wyszuka w pamięci tłumaczeń wszystkie zdania, których podobieństwo Levenshteina do zdania wyszukiwanego jest większe lub równe od ustalonego progu.

def fuzzy_lookup(sentence, threshold):
    col = []

    for entry in translation_memory:
        if (levenshtein_similarity(entry[0], sentence)) >= threshold:
            col.append(entry)
            
    return col
fuzzy_lookup('Spróbuj wyłączyć i włączyć komputer', 0.7)
[]
fuzzy_lookup('Wciśnij przycisk escape', 0.7)
[('Wciśnij przycisk Enter', 'Press the ENTER button')]