{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Podział na jednostki podwyrazowe\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Słownik nie może być za duży…\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jeśli używamy wyuczalnych zanurzeń słów (embeddingów), wówczas musimy\n", "je dopisać do listy parametrów całego modelu — jest to $|V|n$ wag,\n", "gdzie $n$ to rozmiar embeddingów; w wypadku uczenia dodatkowo musimy\n", "jeszcze pamiętać związane z embeddingami gradienty. Pamięć RAM karty\n", "graficznej jest rzecz jasna ograniczona, słownik więc nie może być\n", "dowolnie duży. Dla danego modelu karty graficznej dość łatwo ustalić\n", "maksymalny rozmiar słownika — jest „twarde” ograniczenie, które musimy\n", "spełnić.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Czy rzeczywiście słownik może być taki duży?\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ile jest różnych form fleksyjnych w języku polskim? Zobaczmy w słowniku PoliMorf…\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a\n", "aa\n", "AA\n", "Aachen\n", "Aalborg\n", "Aalborgiem\n", "Aalborgowi\n", "Aalborgu\n", "AAP\n", "Aar\n", "Aarem\n", "Aarowi\n", "Aaru\n", "Aarze\n", "Aara\n", "Aarą\n", "Aarę\n", "Aaro\n", "Aary\n", "Aarze\n", "uniq: błąd zapisu: Przerwany potok\n" ] } ], "source": [ "! wget -q 'http://zil.ipipan.waw.pl/PoliMorf?action=AttachFile&do=get&target=PoliMorf-0.6.7.tab.gz' -O - | zcat | cut -f 1 | uniq | head -n 20" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3844535\n" ] } ], "source": [ "! wget -q 'http://zil.ipipan.waw.pl/PoliMorf?action=AttachFile&do=get&target=PoliMorf-0.6.7.tab.gz' -O - | zcat | cut -f 1 | sort -u | wc -l" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Pytanie** W którym języku europejskim wyrazów będzie jeszcze więcej niż języku polskim?\n", "\n", "Tak naprawdę form jest jeszcze więcej, oczywiście PoliMorf nie wyczerpuje zbioru…\n", "\n", "**Pytanie** Podaj przykłady „oczywistych” wyrazów, których nie ma w PoliMorfie. Jak w sposób systematyczny szukać takich wyrazów?\n", "\n", "Z drugiej strony, w PoliMorfie jest dużo dziwnych, „sztucznych” wyrazów.\n", "\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "niebiałościenną\n", "nieponadosobowości\n", "nieknerający\n", "inspektoratów\n", "Korytkowskich\n", "elektrostatyczności\n", "Okola\n", "bezsłowny\n", "indygowcu\n", "gadany\n", "nieładowarkowościach\n", "niepawężnicowate\n", "Thom\n", "poradlmy\n", "olejący\n", "Ziemianinów\n", "stenotropizmami\n", "wigiliowości\n", "pognanej\n", "niekinezyterapeutycznym\n" ] } ], "source": [ "! wget -q 'http://zil.ipipan.waw.pl/PoliMorf?action=AttachFile&do=get&target=PoliMorf-0.6.7.tab.gz' -O - | zcat | cut -f 1 | shuf -n 20" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Inaczej, zobaczmy, ile różnych wyrazów jest w jakimś rzeczywistym zbiorze tekstów, rozpatrzmy\n", "teksty zebrane na potrzeby identyfikacji płci autora tekstu:\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# Out[7]:" ] } ], "source": [ "! git clone --single-branch --depth 1 git://gonito.net/petite-difference-challenge2" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "! xzcat petite-difference-challenge2/train/in.tsv.xz | perl -C -ne 'print \"$&\\n\" while/\\p{L}+/g;' | sort -u > vocab.txt" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ˆ\n", "ˇ\n", "゚\n", "a\n", "A\n", "á\n", "Á\n", "à\n", "À\n", "ă\n", "Ă\n", "â\n", "Â\n", "å\n", "Å\n", "ä\n", "Ä\n", "Ã\n", "ā\n", "aa\n", "aA\n", "Aa\n", "AA\n", "aĂ\n", "AĂ\n", "aâ\n", "aÂ\n", "Aâ\n", "aÅ\n", "aÄ\n", "ª\n", "aaa\n", "aAa\n", "Aaa\n", "AaA\n", "AAa\n", "AAA\n", "aaaa\n", "aAaa\n", "Aaaa\n", "AaAa\n", "AAaa\n", "AAAa\n", "AAAA\n", "aaaaa\n", "Aaaaa\n", "AaaaA\n", "AAaaa\n", "AAAAA\n", "aaaaaa\n" ] } ], "source": [ "! head -n 50 vocab.txt" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2974556 vocab.txt\n" ] } ], "source": [ "! wc -l vocab.txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Co gorsza, nawet jak weźmiemy cały taki słownik bez ograniczeń i tak\n", "nie pokryje on sporej części tekstów przetwarzanych w czasie inferencji.\n", "Zobaczmy, ilu wyrazów ze zbioru deweloperskiego nie będzie w słowniku.\n", "\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "81380\n" ] } ], "source": [ "! cat petite-difference-challenge2/dev-0/in.tsv | perl -C -ne 'print \"$&\\n\" while/\\p{L}+/g;' | sort -u | comm vocab.txt - -13 | wc -l" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Takie wyrazy nazywamy wyrazami **OOV** (*out-of-vocabulary*).\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Obcięcie słownika\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Najprostszy sposób ograniczenia słownika to po prostu obcięcie do $N$ najczęstszych słów.\n", "\n", "Spróbujmy zastosować do korpusu „płci”:\n", "\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sort: błąd zapisu: 'standardowe wyjście': Przerwany potok\n", "sort: błąd zapisu\n" ] } ], "source": [ "! xzcat petite-difference-challenge2/train/in.tsv.xz | perl -C -ne 'print \"$&\\n\" while/\\p{L}+/g;' | sort | uniq -c | sort -k 1rn | head -n 50000 | sort -k 2 > vocab50000.txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Daje to lepszy efekt niż można się spodziewać. Odrzucamy w ten sposób\n", "tylko bardzo rzadkie słowa (albo takie, które wystąpiły tylko raz w\n", "korpusie — tzw. *hapax legomena*), choć tych słów jest bardzo dużo.\n", "\n", "**Zagadka**: 50000 najczęstszych słów (1,9% **typów**) pokrywa jaki odsetek **wystąpień**?\n", "\n", "Rozkład normalny w języku nie jest… normalny — nie spotkamy się z nim\n", "badając języki. W tekstach dominują „skrzywione” rozkłady z długimi,\n", "„chudymi” ogonami.\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "! xzcat petite-difference-challenge2/train/in.tsv.xz | perl -C -ne 'print \"$&\\n\" while/\\p{L}+/g;' | sort | uniq -c | sort -k 1rn | cut -f 1 > freqs.txt" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'word-distribution.png'" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import re\n", "from math import log\n", "\n", "freqs = []\n", "\n", "with open('freqs.txt', 'r') as fh:\n", " for line in fh:\n", " m = re.match(r'\\s*(\\d+)', line)\n", " if m:\n", " freqs.append(log(float(m.group(1))))\n", "\n", "plt.plot(range(len(freqs)), freqs)\n", "fname = 'word-distribution.png'\n", "plt.savefig(fname)\n", "fname" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[file:# Out[25]:\n", "\n", " 'word-distribution.png'\n", "\n", "![img](./obipy-resources/c0TrCn.png)]]\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lematyzacja\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lematyzacja wydaje się dobrym pomysłem, zwłaszcza dla języków dla bogatej fleksji:\n", "\n", "- znacznie redukujemy słownik,\n", "- formy fleksyjne tego samego wyrazu są traktowane tak samo (co wydaje się słuszne).\n", "\n", "W praktyce współcześnie **nie** stosuje się lematyzacji (w połączeniu z\n", "metodami opartymi na sieciach neuronowych):\n", "\n", "- lematyzacja wymaga wiedzy językowej (reguł lub słownika),\n", " wytworzenie takiej wiedzy może być kosztowne, obecnie preferowane\n", " są metody niezależne od języka;\n", "- tracimy pewną informację niesioną przez formę fleksyjną (co w szczególnych\n", " przypadkach może być niefortunne, np. *aspiracja* i *aspiracje*);\n", "- lematyzacja nie jest trywialnym problemem ze względu na niejednoznaczności\n", " (*Lekarzu, lecz się sam*);\n", "- niektóre niejednoznaczności są seryjne, wybór lematu może być arbitralny,\n", " np. czy *posiadanie*, *gotowanie*, *skakanie* to rzeczowniki czy czasowniki?\n", " a *urządzenie*, *mieszkanie*?\n", "- zazwyczaj sieci neuronowe (czy nawet prostsze modele typu Word2vec)\n", " są w stanie nauczyć się rekonstruowania zależności między formami fleksyjnymi\n", " (i więcej: błędnych form, błędów ortograficznych, form archaicznych itd.)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Zejście na poziom znaków\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Skoro słownik wyrazów jest zbyt duży, to może zejść na poziom znaków?\n", "\n", "- pojedynczy znak alfabetu wprawdzie nic nie znaczy (co znaczy *h*?)\n", "\n", "- … ale rozmiar wejścia przy kodowaniu gorącą jedynką\n", " dramatycznie się zmniejsza\n", "\n", "- może działać, jeśli dodać wielowarstwową sieć\n", " neuronową\n", "\n", "- … ale może być bardzo kosztowne obliczeniowo\n", "\n", "A może coś pośredniego między znakami a wyrazami?\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### BPE\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ani znaki, ani wyrazy — coś pomiędzy: jednostki podwyrazowe (*subword\n", "units*). Moglibyśmy np. dzielić wyraz *superkomputera* na dwie\n", "jednostki *super/+/komputera*, a może nawet trzy: *super/+/komputer/+/a*?\n", "\n", "Najpopularniejszy algorytm podziału na jednostki podwyrazowe to BPE\n", "(*byte-pair encoding*), zainspirowany algorytmami kompresji danych.\n", "Lista jednostek jest automatycznie indukowana na podstawie tekstu (nie\n", "potrzeba żadnej wiedzy o języku!). Ich liczba musi być natomiast z góry\n", "określona.\n", "\n", "W kroku początkowym zaznaczamy końce wyrazów (tokenów), robimy to po\n", "to, żeby jednostki podwyrazowe nie przekraczały granic wyrazów.\n", "\n", "Następnie wykonujemy tyle kroków iteracji, ile wynosi rozmiar zadanego\n", "słownika. W każdym kroku szukamy najczęstszego bigramu, od tego\n", "momentu traktujemy go jako całostkę (wkładamy go do „pudełka”).\n", "\n", "![img](./bpe.png)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Implementacja w Pythonie\n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['e$', 'to', 'to$', 'be$', 't$', 'th', 'or', 'or$', 'no', 'not$']" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from collections import Counter\n", "\n", "def replace_bigram(l, b, r):\n", " i = 0\n", " while i < len(l) - 1:\n", " if (l[i], l[i+1]) == b:\n", " l[i:i+2] = [r]\n", " i += 1\n", " return l\n", "\n", "def learn_bpe_vocab(d, max_vocab_size):\n", " d = list(d.replace(' ', '$') + '$')\n", "\n", " vocab = []\n", "\n", " for ix in range(0, max_vocab_size):\n", " bigrams = [(d[i], d[i+1]) for i in range(0, len(d) - 1) if d[i][-1] != '$']\n", " selected_bigram = Counter(bigrams).most_common(1)[0][0]\n", "\n", " new_subword = selected_bigram[0] + selected_bigram[1]\n", " d = replace_bigram(d, selected_bigram, new_subword)\n", "\n", " vocab.append(new_subword)\n", "\n", " return vocab\n", "\n", "vocab1 = learn_bpe_vocab('to be or not to be that is the question', 10)\n", "vocab1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Słownik jednostek podwyrazowych możemy zastosować do dowolnego tekstu, np. do tekstu,\n", "na którym słownik był wyuczony:\n", "\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'to$ be$ or$ not$ to$ be$ th a t$ i s $ th e$ q u e s t i o n $'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def apply_bpe_vocab(vocab, d):\n", " d = list(d.replace(' ', '$') + '$')\n", " vocab_set = set(vocab)\n", "\n", " modified = True\n", " while modified:\n", " ix = 0\n", " modified = False\n", " while ix < len(d) - 1:\n", " bigram = d[ix] + d[ix+1]\n", " if bigram in vocab_set:\n", " d[ix:ix+2] = [bigram]\n", " modified = True\n", " else:\n", " ix += 1\n", "\n", " return d\n", "\n", "' '.join(apply_bpe_vocab(vocab1, 'to be or not to be that is the question'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zauważmy, że oprócz jednostek podwyrazowych zostały izolowane litery,\n", "zazwyczaj dodajemy je do słownika. (I zazwyczaj, słownik jest trochę\n", "większy niż wartość podana jako parametr przy uczeniu BPE — jest\n", "większy o znaki i specjalne tokeny typu `UNK`, `BOS`, `EOS`, `PAD`.)\n", "\n", "**Pytanie**: Jaki problem może pojawić przy zastosowaniu BPE dla tekstu,\n", "gdzie pojawiają się chińskie znaki? Jak można sobie z nim poradzić?\n", "\n", "Słownik jednostek podwyrazowych można stosować dla dowolnego tekstu:\n", "\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'to m $ w i l l $ be$ th e$ b e s t$'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "' '.join(apply_bpe_vocab(vocab1, 'tom will be the best'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jak można zauważyć algorytm BPE daje dwa rodzaje jednostek podwyrazowych:\n", "\n", "- jednostki, które mogą doklejane na początku wyrazu;\n", "- jednostki, które stanowią koniec wyrazu, w szczególności są całym wyrazem.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Gotowa implementacja\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Po raz pierwszy BPE użyto do neuronowego tłumaczenia maszynowego.\n", "Użyjmy modułu autorstwa Rica Sennricha ([https://github.com/rsennrich/subword-nmt](https://github.com/rsennrich/subword-nmt)).\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "! pip install subword-nmt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wyindukujmy słownik dla zbioru uczącego zadania identyfikacji płci\n", "autora tekstu:\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "! xzcat petite-difference-challenge2/train/in.tsv.xz | perl -C -ne 'print \"$&\\n\" while/\\p{L}+/g;' | python -m subword_nmt.learn_bpe -s 50000 -v > bpe_vocab.txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Procedura trwa kilka minut, trzeba uzbroić się w cierpliwość (ale wypisywanie bigramów przyspieszy!).\n", "\n", " pair 0: n i -> ni (frequency 17625075)\n", " pair 1: i e -> ie (frequency 11471590)\n", " pair 2: c z -> cz (frequency 9143490)\n", " pair 3: ni e -> nie (frequency 7901783)\n", " pair 4: p o -> po (frequency 7790826)\n", " pair 5: r z -> rz (frequency 7542046)\n", " pair 6: s t -> st (frequency 7269069)\n", " pair 7: e m -> em (frequency 7207280)\n", " pair 8: d z -> dz (frequency 6860931)\n", " pair 9: s z -> sz (frequency 6609907)\n", " pair 10: r a -> ra (frequency 6601618)\n", " pair 11: o w -> ow (frequency 6395963)\n", " pair 12: i e -> ie (frequency 5906869)\n", " pair 13: n a -> na (frequency 5300380)\n", " pair 14: r o -> ro (frequency 5181363)\n", " pair 15: n a -> na (frequency 5125807)\n", " pair 16: a ł -> ał (frequency 4786696)\n", " pair 17: j e -> je (frequency 4599579)\n", " pair 18: s i -> si (frequency 4300984)\n", " pair 19: a l -> al (frequency 4276823)\n", " pair 20: t e -> te (frequency 4033344)\n", " pair 21: w i -> wi (frequency 3939063)\n", " pair 22: c h -> ch (frequency 3919410)\n", " pair 23: c h -> ch (frequency 3661410)\n", " pair 24: k o -> ko (frequency 3629840)\n", " pair 25: z a -> za (frequency 3625424)\n", " pair 26: t a -> ta (frequency 3570094)\n", " pair 27: p rz -> prz (frequency 3494551)\n", " pair 28: g o -> go (frequency 3279997)\n", " pair 29: a r -> ar (frequency 3081492)\n", " pair 30: si ę -> się (frequency 2973681)\n", " ...\n", " pair 49970: brz mieniu -> brzmieniu (frequency 483)\n", " pair 49971: bieżą cych -> bieżących (frequency 483)\n", " pair 49972: biegu nkę -> biegunkę (frequency 483)\n", " pair 49973: ban kowości -> bankowości (frequency 483)\n", " pair 49974: ba ku -> baku (frequency 483)\n", " pair 49975: ba cznie -> bacznie (frequency 483)\n", " pair 49976: Przypad kowo -> Przypadkowo (frequency 483)\n", " pair 49977: MA Ł -> MAŁ (frequency 483)\n", " pair 49978: Lep pera -> Leppera (frequency 483)\n", " pair 49979: Ko za -> Koza (frequency 483)\n", " pair 49980: Jak byś -> Jakbyś (frequency 483)\n", " pair 49981: Geni alne -> Genialne (frequency 483)\n", " pair 49982: Że nada -> Żenada (frequency 482)\n", " pair 49983: ń czykiem -> ńczykiem (frequency 482)\n", " pair 49984: zwie ń -> zwień (frequency 482)\n", " pair 49985: zost ałaś -> zostałaś (frequency 482)\n", " pair 49986: zni szczona -> zniszczona (frequency 482)\n", " pair 49987: ze stawi -> zestawi (frequency 482)\n", " pair 49988: za sób -> zasób (frequency 482)\n", " pair 49989: węd rówkę -> wędrówkę (frequency 482)\n", " pair 49990: wysko czyła -> wyskoczyła (frequency 482)\n", " pair 49991: wyle czenia -> wyleczenia (frequency 482)\n", " pair 49992: wychowaw cze -> wychowawcze (frequency 482)\n", " pair 49993: w t -> wt (frequency 482)\n", " pair 49994: un da -> unda (frequency 482)\n", " pair 49995: udzie lałem -> udzielałem (frequency 482)\n", " pair 49996: tę czy -> tęczy (frequency 482)\n", " pair 49997: tro sce -> trosce (frequency 482)\n", " pair 49998: słusz ności -> słuszności (frequency 482)\n", " pair 49999: su me -> sume (frequency 482\n", "\n", "Zastosujmy teraz wyindukowany słownik BPE dla jakiegoś rzeczywistego tekstu.\n", "\n" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cier@@ piałem na straszne la@@ gi kilkanaście sekund lub dłużej czarnego ekranu przy próbie przełą@@ czenia się uruchomienia prawie każdej aplikacji Dodatkowo telefon mi się wyłą@@ czał czasem bez powodu sam z siebie albo rese@@ tował Ostatnio nawet przeglądarka zaczęła się często zawie@@ szać i Android proponował wymu@@ szone zamknięcie Do tego te problemy z połączeniem do komputera przez USB " ] } ], "source": [ "! echo 'Cierpiałem na straszne lagi – kilkanaście sekund lub dłużej czarnego ekranu przy próbie przełączenia się / uruchomienia prawie każdej aplikacji. Dodatkowo telefon mi się wyłączał czasem bez powodu – sam z siebie, albo resetował. Ostatnio nawet przeglądarka zaczęła się często zawieszać i Android proponował wymuszone zamknięcie. Do tego te problemy z połączeniem do komputera przez USB.' | perl -C -ne 'print \"$& \" while/\\p{L}+/g;' | python -m subword_nmt.apply_bpe -c bpe_vocab.txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ta konkretna implementacja zaznacza za pomocą sekwencji ~@@ ~ koniec jednostki podwyrazowej.\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.9.2" }, "org": null }, "nbformat": 4, "nbformat_minor": 4 }