63 KiB
Komputerowe wspomaganie tłumaczenia
8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia [laboratoria]
Rafał Jaworski (2021)
W dzisiejszych czasach, niezwykle ważną techniką wspomagania tłumaczenia jest użycie tłumaczenia maszynowego. Tekst źródłowy do tłumaczenia jest najpierw tłumaczony całkowicie autommatycznie, a następnie tłumacz ludzki dokonuje korekty wyniku. Technologia tłumaczenia maszynowego jest już na tyle dojrzała, że oferuje bardzo wysoką jakość wyników. Coraz częstsze stają się scenariusze, w których ludzka korekta to niemal całkowicie machinalne (sic!) zatwierdzanie wyników tłumaczenia maszynowego. Na dzisiejszych zajęciach poznamy techniki ewaluacji tłumaczenia maszynowego oraz sprawdzania jego przydatności w procesie wspomagania tłumaczenia ludzkiego.
Jakość tłumaczenia maszynowego możemy oceniać na dwóch niezależnych płaszczyznach: dokładność i płynność. Płynność jest subiektywnie odbieranym odczuciem, że czytany tekst jest napisany językiem naturalnym i zrozumiałym. Systemy tłumaczenia maszynowego oparte na uczeniu głębokim z wykorzystaniem sieci neuronowych osiągają duży stopień płynności tłumaczenia. Niestety jednak ich dokładność nie zawsze jest równie wysoka.
Dokładność tłumaczenia maszynowego jest parametrem, który łatwiej zmierzyć. Wartość takich pomiarów daje obraz tego, jaka jest faktyczna jakość tłumaczenia maszynowego i jaka jest jego potencjalna przydatność we wspomaganiu tłumaczenia.
Najczęściej stosowaną techniką oceny tłumaczenia maszynowego jest ocena BLEU. Do obliczenia tej oceny potrzebny jest wynik tłumaczenia maszynowego oraz referencyjne tłumaczenie ludzkie wysokiej jakości.
Ćwiczenie 1: Zaimplementuj program do obliczania oceny BLEU dla korpusu w folderze data. Użyj implementacji BLEU z pakietu nltk. Dodatkowe wymaganie techniczne - napisz program tak, aby nie musiał rozpakwowywać pliku zip z korpusem na dysku.
pip install nltk
Defaulting to user installation because normal site-packages is not writeable Collecting nltk Downloading nltk-3.8.1-py3-none-any.whl.metadata (2.8 kB) Requirement already satisfied: click in /usr/local/lib/python3.9/dist-packages (from nltk) (8.1.3) Requirement already satisfied: joblib in /usr/lib/python3/dist-packages (from nltk) (0.17.0) Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.9/dist-packages (from nltk) (2023.5.5) Requirement already satisfied: tqdm in /usr/local/lib/python3.9/dist-packages (from nltk) (4.64.1) Downloading nltk-3.8.1-py3-none-any.whl (1.5 MB) [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.5/1.5 MB[0m [31m17.1 MB/s[0m eta [36m0:00:00[0m00:01[0m0:01[0m [?25hInstalling collected packages: nltk [33m WARNING: The script nltk is installed in '/home/students/s444820/.local/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.[0m[33m [0mSuccessfully installed nltk-3.8.1 Note: you may need to restart the kernel to use updated packages.
import zipfile
import string
from nltk.translate.bleu_score import corpus_bleu
def deletePunctuation(text):
translator = str.maketrans('', '', string.punctuation)
return text.translate(translator)
def tokenization(i):
zip_path = './data/corpus_corrected.zip'
files = ['corpus_de_human.txt', 'corpus_de_nmt.txt', 'corpus_en.txt']
result = []
with zipfile.ZipFile(zip_path, 'r') as zf:
with zf.open(files[i]) as f:
text = f.read().decode('utf-8')
text = text.split("\n")
for sentence in text:
if i == 0:
result.append([deletePunctuation(sentence).split()])
else:
result.append(deletePunctuation(sentence).split())
return result
HUMAN = tokenization(0)
MACHINE = tokenization(1)
STANDARD = tokenization(2)
print(len(HUMAN))
print(len(MACHINE))
#corpus_bleu(HUMAN,MACHINE)
1001 1001
def calculate_bleu():
HUMAN = tokenization(0)
MACHINE = tokenization(1)
return corpus_bleu(HUMAN,MACHINE)
calculate_bleu()
0.7476897494228967
Ćwiczenie 2: Oblicz wartość bleu na różnych fragmentach przykładowego korpusu (np. na pierwszych 100 zdaniach, zdaniach 500-600). Czy w jakimś fragmencie korpusu jakość tłumaczenia znacząco odbiega od średniej?
from nltk.translate.bleu_score import sentence_bleu
import matplotlib.pyplot as plt
def analyze_bleu(interval):
bleuResults = []
errorNumber = 0
er = []
index = 0
x = range(len(HUMAN)-1)
for y in x:
bleu = sentence_bleu(HUMAN[y], MACHINE[y])
if bleu <= 0.7476897494228967:
errorNumber += 1
bleuResults.append(bleu)
if index % interval == 0 and index != 0:
er.append([f"[{index-interval}-{index})",errorNumber])
errorNumber = 0
index += 1
plt.plot(x, bleuResults, 'o',markersize=1.7)
plt.xlabel('Nr zdania')
plt.ylabel('Bleu')
plt.title('Wynik BLEU w zależności od wartości zdań')
plt.grid(True)
plt.show()
maxEr = max(er, key=lambda x: x[1])
return maxEr
analyze_bleu(100)
['[800-900)', 52]
Inną metodą oceny jakości tłumaczenia maszynowego jest parametr WER - Word Error Rate. Definiuje się on w następujący sposób:
$WER = \frac{S+D+I}{N}=\frac{S+D+I}{S+D+C}$
gdzie:
- S - liczba substytucji (słów)
- D - liczba usunięć
- I - liczba wstawień
- C - liczba poprawnych śłów
- N - liczba słów w tłumaczeniu referencyjnym (N=S+D+C)
Miara ta jest zwykle używana w do oceny systemów automatycznego rozpoznawania mowy, jednak w kontekście wspomagania tłumaczenia może być rozumiana jako wielkość nakładu pracy tłumacza nad poprawieniem tłumaczenia maszynowego.
Ćwiczenie 3: Oblicz wartość WER dla przykładowego korpusu. Skorzystaj z gotowej implementacji WER.
from jiwer import wer
def calculate_wer():
x = range(len(HUMAN)-1)
w = 0
for y in x:
w += wer(" ".join(HUMAN[y][0])," ".join(MACHINE[y]))
return w/(len(HUMAN)-1)
calculate_wer()
0.17738143121880412
print(wer(" ".join(HUMAN[0][0])," ".join(MACHINE[0])))
0.0
Poza wymienionymi powyżej, stosować można jeszcze inne miary oparte na porównywaniu tłumaczenia maszynowego z ludzkim. Przypomnijmy sobie jedną, którą stosowaliśmy wcześniej.
Ćwiczenie 4: Oblicz średnią wartość dystansu Levenshteina pomiędzy zdaniami przetłumaczonymi automatycznie oraz przez człowieka. Użyj implementacji z ćwiczeń nr 2.
from Levenshtein import distance as levenshtein_distance
def levenshtein_similarity(x,y):
return 1 - levenshtein_distance(x,y) / max(len(x), len(y))
def calculate_levenshtein():
x = range(len(HUMAN)-1)
l = 0
for y in x:
l += levenshtein_similarity(" ".join(HUMAN[y][0])," ".join(MACHINE[y]))
return l/(len(HUMAN)-1)
calculate_levenshtein()
0.8802718348367172
A teraz sprawdźmy coś jeszcze. W danych przykładowego korpusu znajduje się także angielski tekst źródłowy. Teoretycznie, dobre tłumaczenie niemieckie powinno zawierać jak najwięcej słów z angielskiego źródła. Wykonajmy najstępujący eksperyment:
pip install PyDictionary
[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. [1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. [1;31mClick <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. [1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details.
Ćwiczenie 5: Dla każdej trójki zdań z korpusu przykładowego wykonaj następujące kroki:
- Przetłumacz każde angielskie słowo na niemiecki przy użyciu modułu PyDictionary.
- Sprawdź, które z niemieckich tłumaczeń zawiera więcej spośród tych przetłumaczonych słów - automatyczne, czy ludzkie. Następnie wypisz statystyki zbiorcze. Które tłumaczenie zawiera więcej słownikowych tłumaczeń słów ze źródła?
from PyDictionary import PyDictionary
dictde = PyDictionary()
translation = dictde.translate("happy",'de')
print(translation)
Invalid Word None
def analyze_translations():
result = []
for sentence in STANDARD:
words = []
for word in sentence:
words.append(dictde.translate(word,'de'))
result.append(words)
break
return result
x = 0
y = 0
eh = analyze_translations()
Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word Invalid Word
for i in len(eh) - 1:
for word in eh[i]:
if word in HUMAN[i][0]:
x += 1
if word in MACHINE[i]:
y += 1
print(x)
print(y)
eh[1]
[1;31m---------------------------------------------------------------------------[0m [1;31mIndexError[0m Traceback (most recent call last) Cell [1;32mIn[17], line 1[0m [1;32m----> 1[0m [43meh[49m[43m[[49m[38;5;241;43m1[39;49m[43m][49m [1;31mIndexError[0m: list index out of range