2024-04-13 08:20:53 +02:00
{
"cells": [
{
"cell_type": "markdown",
"id": "improved-register",
"metadata": {},
"source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
"<h2> 8. <i>Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia</i> [laboratoria]</h2> \n",
"<h3>Rafał Jaworski (2021)</h3>\n",
"</div>\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",
2024-05-05 08:05:59 +02:00
"execution_count": 2,
2024-05-04 14:59:05 +02:00
"id": "d4f068df",
2024-04-13 08:20:53 +02:00
"metadata": {},
2024-05-04 14:59:05 +02:00
"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"
]
},
2024-05-05 08:05:59 +02:00
"execution_count": 2,
2024-05-04 14:59:05 +02:00
"metadata": {},
"output_type": "execute_result"
}
],
2024-04-13 08:20:53 +02:00
"source": [
2024-05-04 14:59:05 +02:00
"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",
2024-04-13 08:20:53 +02:00
"def calculate_bleu():\n",
2024-05-04 14:59:05 +02:00
" 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()"
2024-04-13 08:20:53 +02:00
]
},
{
"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",
2024-05-04 14:59:05 +02:00
"execution_count": 3,
2024-04-13 08:20:53 +02:00
"id": "lasting-rolling",
"metadata": {},
2024-05-04 14:59:05 +02:00
"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"
]
}
],
2024-04-13 08:20:53 +02:00
"source": [
2024-05-04 14:59:05 +02:00
"\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"
2024-04-13 08:20:53 +02:00
]
},
{
"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)"
]
},
2024-05-04 14:59:05 +02:00
{
"cell_type": "markdown",
"id": "fb4f02ae",
"metadata": {},
"source": []
},
2024-04-13 08:20:53 +02:00
{
"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",
2024-05-04 14:59:05 +02:00
"execution_count": 25,
2024-04-13 08:20:53 +02:00
"id": "occupied-swing",
"metadata": {},
2024-05-04 14:59:05 +02:00
"outputs": [
{
"data": {
"text/plain": [
"0.17355216569308377"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
2024-04-13 08:20:53 +02:00
"source": [
2024-05-04 14:59:05 +02:00
"from jiwer import wer\n",
"import zipfile\n",
"\n",
2024-04-13 08:20:53 +02:00
"def calculate_wer():\n",
2024-05-04 14:59:05 +02:00
" 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()"
2024-04-13 08:20:53 +02:00
]
},
{
"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",
2024-05-04 14:59:05 +02:00
"execution_count": 35,
2024-04-13 08:20:53 +02:00
"id": "immediate-element",
"metadata": {},
2024-05-04 14:59:05 +02:00
"outputs": [
{
"data": {
"text/plain": [
"2.653"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
2024-04-13 08:20:53 +02:00
"source": [
2024-05-04 14:59:05 +02:00
"import Levenshtein\n",
"\n",
2024-04-13 08:20:53 +02:00
"def calculate_levenshtein():\n",
2024-05-04 14:59:05 +02:00
" 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"
2024-04-13 08:20:53 +02:00
]
},
{
"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",
2024-05-05 08:05:59 +02:00
"execution_count": 1,
2024-04-13 08:20:53 +02:00
"id": "descending-easter",
"metadata": {},
2024-05-04 14:59:05 +02:00
"outputs": [
{
2024-05-05 08:05:59 +02:00
"ename": "NameError",
"evalue": "name 'remove_punctuation' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[1], line 45\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28mprint\u001b[39m(human_sum)\n\u001b[1;32m 41\u001b[0m \u001b[38;5;66;03m# tranlsations = [PyDictionary().translate(word, 'de') for word in element]\u001b[39;00m\n\u001b[0;32m---> 45\u001b[0m analyze_translations()\n",
"Cell \u001b[0;32mIn[1], line 19\u001b[0m, in \u001b[0;36manalyze_translations\u001b[0;34m()\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21manalyze_translations\u001b[39m():\n\u001b[1;32m 18\u001b[0m ourZip \u001b[38;5;241m=\u001b[39m zipfile\u001b[38;5;241m.\u001b[39mZipFile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdata/corpus_corrected.zip\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m---> 19\u001b[0m files \u001b[38;5;241m=\u001b[39m {name: remove_punctuation(ourZip\u001b[38;5;241m.\u001b[39mread(name)\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name \u001b[38;5;129;01min\u001b[39;00m ourZip\u001b[38;5;241m.\u001b[39mnamelist()}\n\u001b[1;32m 22\u001b[0m corpus_de_human, corpus_de_nmt, corpus_en \u001b[38;5;241m=\u001b[39m files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_de_human.txt\u001b[39m\u001b[38;5;124m'\u001b[39m], files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_de_nmt.txt\u001b[39m\u001b[38;5;124m'\u001b[39m], files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_en.txt\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 24\u001b[0m nmt_sum \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n",
"Cell \u001b[0;32mIn[1], line 19\u001b[0m, in \u001b[0;36m<dictcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21manalyze_translations\u001b[39m():\n\u001b[1;32m 18\u001b[0m ourZip \u001b[38;5;241m=\u001b[39m zipfile\u001b[38;5;241m.\u001b[39mZipFile(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdata/corpus_corrected.zip\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m---> 19\u001b[0m files \u001b[38;5;241m=\u001b[39m {name: remove_punctuation(ourZip\u001b[38;5;241m.\u001b[39mread(name)\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name \u001b[38;5;129;01min\u001b[39;00m ourZip\u001b[38;5;241m.\u001b[39mnamelist()}\n\u001b[1;32m 22\u001b[0m corpus_de_human, corpus_de_nmt, corpus_en \u001b[38;5;241m=\u001b[39m files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_de_human.txt\u001b[39m\u001b[38;5;124m'\u001b[39m], files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_de_nmt.txt\u001b[39m\u001b[38;5;124m'\u001b[39m], files[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcorpus_en.txt\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 24\u001b[0m nmt_sum \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n",
"\u001b[0;31mNameError\u001b[0m: name 'remove_punctuation' is not defined"
2024-05-04 14:59:05 +02:00
]
}
],
2024-04-13 08:20:53 +02:00
"source": [
2024-05-04 14:59:05 +02:00
"from PyDictionary import PyDictionary\n",
"import zipfile\n",
2024-05-05 08:05:59 +02:00
"import re\n",
2024-05-04 14:59:05 +02:00
"\n",
"def transalate(word_list):\n",
" transalted_words = {}\n",
" for word in word_list:\n",
2024-05-05 08:05:59 +02:00
" try:\n",
" translation = PyDictionary().translate(word, 'German')\n",
" if translation:\n",
" transalted_words[word] = translation\n",
" except Exception as e:\n",
" print('Exception')\n",
2024-05-04 14:59:05 +02:00
"\n",
" return transalted_words\n",
"\n",
2024-04-13 08:20:53 +02:00
"def analyze_translations():\n",
2024-05-04 14:59:05 +02:00
" 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",
2024-05-05 08:05:59 +02:00
" nmt_sum = 0\n",
" human_sum = 0\n",
"\n",
2024-05-04 14:59:05 +02:00
" for human_element, nmt_element, element in zip(corpus_de_human, corpus_de_nmt, corpus_en):\n",
" transalted_words = transalate(element)\n",
"\n",
2024-05-05 08:05:59 +02:00
" # words = set(re.findall(r'\\w+', nmt_element.lower()))\n",
" nmt_sum += sum(1 for word in nmt_element if transalted_words.get(word.lower()))\n",
"\n",
" # words = set(re.findall(r'\\w+', human_element.lower()))\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",
"\n",
2024-05-04 14:59:05 +02:00
" # tranlsations = [PyDictionary().translate(word, 'de') for word in element]\n",
" \n",
"\n",
"\n",
"analyze_translations()"
2024-04-13 08:20:53 +02:00
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
2024-05-04 14:59:05 +02:00
"lang": "pl",
2024-04-13 08:20:53 +02:00
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
2024-05-04 14:59:05 +02:00
"version": "3.11.7"
},
"subtitle": "8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
2024-04-13 08:20:53 +02:00
},
"nbformat": 4,
"nbformat_minor": 5
}