{ "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", "
\n", "

Komputerowe wspomaganie tłumaczenia

\n", "

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 }