8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia [laboratoria]
\n",
"
Rafał Jaworski (2021)
\n",
"
\n",
"\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "hungarian-davis",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "posted-commons",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "referenced-implement",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "disturbed-january",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "dental-combination",
"metadata": {},
"source": [
"### Ć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."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d4f068df",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/opt/anaconda3/lib/python3.11/site-packages/nltk/translate/bleu_score.py:552: UserWarning: \n",
"The hypothesis contains 0 counts of 3-gram overlaps.\n",
"Therefore the BLEU score evaluates to 0, independently of\n",
"how many N-gram overlaps of lower order it contains.\n",
"Consider using lower n-gram order or use SmoothingFunction()\n",
" warnings.warn(_msg)\n",
"/opt/anaconda3/lib/python3.11/site-packages/nltk/translate/bleu_score.py:552: UserWarning: \n",
"The hypothesis contains 0 counts of 4-gram overlaps.\n",
"Therefore the BLEU score evaluates to 0, independently of\n",
"how many N-gram overlaps of lower order it contains.\n",
"Consider using lower n-gram order or use SmoothingFunction()\n",
" warnings.warn(_msg)\n"
]
},
{
"data": {
"text/plain": [
"3.984587822441638e-156"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import zipfile\n",
"import nltk.translate.bleu_score as bleu\n",
"import string\n",
"\n",
"def remove_punctuation(text):\n",
" text_without_punctuations = text.translate(str.maketrans('', '', string.punctuation))\n",
" sentences = text_without_punctuations.split('\\n')\n",
" return [[word.lower() for word in sentence.split()] for sentence in sentences if sentence != '']\n",
"\n",
"def calculate_bleu():\n",
" zip = zipfile.ZipFile('data/corpus_corrected.zip')\n",
" files = {name: remove_punctuation(zip.read(name).decode('utf-8'))\n",
" for name in zip.namelist()}\n",
" \n",
" corpus_de_human, corpus_de_nmt = files['corpus_de_human.txt'], files['corpus_de_nmt.txt']\n",
" \n",
" return bleu.corpus_bleu(corpus_de_human, corpus_de_nmt)\n",
"\n",
"calculate_bleu()"
]
},
{
"cell_type": "markdown",
"id": "jewish-ethics",
"metadata": {},
"source": [
"### Ć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?"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "lasting-rolling",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 to 100 - 4.97555004481153e-232\n",
"500 to 600 - 5.956707985683837e-232\n",
"800 to 900 - 4.774461089627919e-232\n",
"200 to 300 - 5.56331772444502e-232\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/opt/anaconda3/lib/python3.11/site-packages/nltk/translate/bleu_score.py:552: UserWarning: \n",
"The hypothesis contains 0 counts of 2-gram overlaps.\n",
"Therefore the BLEU score evaluates to 0, independently of\n",
"how many N-gram overlaps of lower order it contains.\n",
"Consider using lower n-gram order or use SmoothingFunction()\n",
" warnings.warn(_msg)\n"
]
}
],
"source": [
"\n",
"def analyze_bleu(start_sentence_index, finish_sentence_index):\n",
" zip = zipfile.ZipFile('data/corpus_corrected.zip')\n",
" files = {name: remove_punctuation(zip.read(name).decode('utf-8'))\n",
" for name in zip.namelist()}\n",
" \n",
" corpus_de_human, corpus_de_nmt = files['corpus_de_human.txt'][start_sentence_index:finish_sentence_index], files['corpus_de_nmt.txt'][start_sentence_index:finish_sentence_index]\n",
" \n",
" return bleu.corpus_bleu(corpus_de_human, corpus_de_nmt)\n",
"\n",
"\n",
"print(\"0 to 100 - \"+str(analyze_bleu(0, 100)))\n",
"print(\"500 to 600 - \"+str(analyze_bleu(500, 600)))\n",
"print(\"800 to 900 - \"+str(analyze_bleu(800, 900)))\n",
"print(\"200 to 300 - \"+str(analyze_bleu(200, 300)))\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "listed-bikini",
"metadata": {},
"source": [
"Inną metodą oceny jakości tłumaczenia maszynowego jest parametr WER - Word Error Rate. Definiuje się on w następujący sposób:\n",
"\n",
"$WER = \\frac{S+D+I}{N}=\\frac{S+D+I}{S+D+C}$\n",
"\n",
"gdzie:\n",
" * S - liczba substytucji (słów)\n",
" * D - liczba usunięć\n",
" * I - liczba wstawień\n",
" * C - liczba poprawnych śłów\n",
" * N - liczba słów w tłumaczeniu referencyjnym (N=S+D+C)"
]
},
{
"cell_type": "markdown",
"id": "fb4f02ae",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"id": "conscious-cookbook",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "split-palace",
"metadata": {},
"source": [
"### Ćwiczenie 3: Oblicz wartość WER dla przykładowego korpusu. Skorzystaj z gotowej implementacji WER."
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "occupied-swing",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.17355216569308377"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from jiwer import wer\n",
"import zipfile\n",
"\n",
"def calculate_wer():\n",
" ourZip = zipfile.ZipFile('data/corpus_corrected.zip')\n",
" files = {name: remove_punctuation(ourZip.read(name).decode('utf-8'))\n",
" for name in ourZip.namelist()}\n",
" \n",
" corpus_de_human, corpus_de_nmt = files['corpus_de_human.txt'], files['corpus_de_nmt.txt']\n",
"\n",
" sum_wer = 0\n",
" for human_sent, nmt_sent in zip(corpus_de_human, corpus_de_nmt):\n",
" sum_wer+= wer(\" \".join(human_sent), \" \".join(nmt_sent))\n",
"\n",
" return sum_wer/(len(corpus_de_human))\n",
"\n",
"calculate_wer()"
]
},
{
"cell_type": "markdown",
"id": "stretch-wound",
"metadata": {},
"source": [
"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."
]
},
{
"cell_type": "markdown",
"id": "abstract-wilderness",
"metadata": {},
"source": [
"### Ćwiczenie 4: Oblicz średnią wartość dystansu Levenshteina pomiędzy zdaniami przetłumaczonymi automatycznie oraz przez człowieka. Użyj implementacji z ćwiczeń nr 2."
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "immediate-element",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2.653"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import Levenshtein\n",
"\n",
"def calculate_levenshtein():\n",
" ourZip = zipfile.ZipFile('data/corpus_corrected.zip')\n",
" files = {name: remove_punctuation(ourZip.read(name).decode('utf-8'))\n",
" for name in ourZip.namelist()}\n",
" \n",
" corpus_de_human, corpus_de_nmt = files['corpus_de_human.txt'], files['corpus_de_nmt.txt']\n",
"\n",
" sum_disatnce = 0\n",
" for human_element, nmt_element in zip(corpus_de_human, corpus_de_nmt):\n",
" sum_disatnce+= Levenshtein.distance(human_element, nmt_element)\n",
"\n",
" return sum_disatnce/(len(corpus_de_human))\n",
"\n",
"calculate_levenshtein()\n"
]
},
{
"cell_type": "markdown",
"id": "filled-burton",
"metadata": {},
"source": [
"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:"
]
},
{
"cell_type": "markdown",
"id": "grateful-recruitment",
"metadata": {},
"source": [
"### Ćwiczenie 5: Dla każdej trójki zdań z korpusu przykładowego wykonaj następujące kroki:\n",
" * Przetłumacz każde angielskie słowo na niemiecki przy użyciu modułu PyDictionary.\n",
" * Sprawdź, które z niemieckich tłumaczeń zawiera więcej spośród tych przetłumaczonych słów - automatyczne, czy ludzkie.\n",
"Następnie wypisz statystyki zbiorcze. Które tłumaczenie zawiera więcej słownikowych tłumaczeń słów ze źródła?"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "descending-easter",
"metadata": {},
"outputs": [],
"source": [
"from PyDictionary import PyDictionary\n",
"import zipfile\n",
"import re\n",
"\n",
"def transalate(word_list):\n",
" transalted_words = {}\n",
" for word in word_list:\n",
" try:\n",
" translation = PyDictionary().translate(word, 'German')\n",
" if translation:\n",
" transalted_words[word] = translation\n",
" except Exception as e:\n",
" print('Exception')\n",
"\n",
" return transalted_words\n",
"\n",
"def analyze_translations():\n",
" ourZip = zipfile.ZipFile('data/corpus_corrected.zip')\n",
" files = {name: remove_punctuation(ourZip.read(name).decode('utf-8'))\n",
" for name in ourZip.namelist()}\n",
" \n",
" corpus_de_human, corpus_de_nmt, corpus_en = files['corpus_de_human.txt'], files['corpus_de_nmt.txt'], files['corpus_en.txt']\n",
"\n",
" nmt_sum = 0\n",
" human_sum = 0\n",
"\n",
" for human_element, nmt_element, element in zip(corpus_de_human, corpus_de_nmt, corpus_en):\n",
" transalted_words = transalate(element)\n",
"\n",
" nmt_sum += sum(1 for word in nmt_element if transalted_words.get(word.lower()))\n",
"\n",
" human_sum += sum(1 for word in human_element if transalted_words.get(word.lower()))\n",
"\n",
"\n",
" print(nmt_sum)\n",
" print(human_sum)\n",
"\n",
"#I think the PyDictionary mode doesn't work, the info from https://github.com/geekpradd/PyDictionary\n",
"#NOTE: Mainintaing this module requires constantly changing the scrapping endpoints which unfortunately I no longer have the bandwidth to do so, so this module is DEPRECATED. Kindly use other substitutes available on PyPI. Thanks!\n",
"#PyDictionary is a Dictionary Module for Python 2/3 to get meanings, translations, synonyms and Antonyms of words. It uses WordNet for getting meanings, Google for translations, and synonym.com for getting synonyms and antonyms.\n",
"#This module uses Python Requests, BeautifulSoup4 and goslate as dependencies\n",
" \n"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.7"
},
"subtitle": "8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}