{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[]},"kaggle":{"accelerator":"nvidiaL4","dataSources":[{"sourceId":91496,"databundleVersionId":11802066,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Его величество, \"домашка №1\"","metadata":{"id":"JBA5IPyb4BFH"}},{"cell_type":"markdown","source":"В этой домашней работе вам предоставится уникальная возможность обучить Byte-level BPE токенизатор и небольшую LM. \n\nДомашняя работа состоит из нескольких последовательных блоков: реализация и обучение токенизатора, реализация Transformer модели и обучение модели на датасете с русскими анекдотами!\n\nОбученные токенизатор и модель можно и нужно выложить на [🤗 HuggingFace](https://huggingface.co/). Зарегистрируйтесь там, подпишитесь на [deep vk](https://huggingface.co/deepvk) и создайте себе API токен.\n\nСледуйте ячейкам тетрадки и заполняйте пропущенные ячейки. В конце тетрадки вы найдете задачи со звездочкой, чтобы получить максимальный балл!","metadata":{"id":"cOnY6pwvpghE"}},{"cell_type":"code","source":"# Установим необходимые дополнительные библиотеки\n!pip install google-cloud-bigquery-storage\n%pip install --quiet datasets livelossplot","metadata":{"id":"0byNYx5dzB4b","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:01.013415Z","iopub.execute_input":"2025-10-27T19:08:01.013645Z","iopub.status.idle":"2025-10-27T19:08:29.116592Z","shell.execute_reply.started":"2025-10-27T19:08:01.013629Z","shell.execute_reply":"2025-10-27T19:08:29.115929Z"}},"outputs":[{"name":"stdout","text":"\u001b[33mWARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known')': /simple/google-cloud-bigquery-storage/\u001b[0m\u001b[33m\n\u001b[0mCollecting google-cloud-bigquery-storage\n Downloading google_cloud_bigquery_storage-2.33.1-py3-none-any.whl.metadata (10 kB)\nRequirement already satisfied: google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1 in /usr/local/lib/python3.11/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (1.34.1)\nRequirement already satisfied: google-auth!=2.24.0,!=2.25.0,<3.0.0,>=2.14.1 in /usr/local/lib/python3.11/dist-packages (from google-cloud-bigquery-storage) (2.40.3)\nRequirement already satisfied: proto-plus<2.0.0,>=1.22.3 in /usr/local/lib/python3.11/dist-packages (from google-cloud-bigquery-storage) (1.26.1)\nRequirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<7.0.0,>=3.20.2 in /usr/local/lib/python3.11/dist-packages (from google-cloud-bigquery-storage) (3.20.3)\nRequirement already satisfied: googleapis-common-protos<2.0dev,>=1.56.2 in /usr/local/lib/python3.11/dist-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (1.70.0)\nRequirement already satisfied: requests<3.0.0dev,>=2.18.0 in /usr/local/lib/python3.11/dist-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (2.32.5)\nRequirement already satisfied: grpcio<2.0dev,>=1.33.2 in /usr/local/lib/python3.11/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (1.75.1)\nRequirement already satisfied: grpcio-status<2.0dev,>=1.33.2 in /usr/local/lib/python3.11/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (1.49.0rc1)\nRequirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.11/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=2.14.1->google-cloud-bigquery-storage) (5.5.2)\nRequirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.11/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=2.14.1->google-cloud-bigquery-storage) (0.4.2)\nRequirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.11/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=2.14.1->google-cloud-bigquery-storage) (4.9.1)\nRequirement already satisfied: typing-extensions~=4.12 in /usr/local/lib/python3.11/dist-packages (from grpcio<2.0dev,>=1.33.2->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (4.15.0)\nRequirement already satisfied: pyasn1<0.7.0,>=0.6.1 in /usr/local/lib/python3.11/dist-packages (from pyasn1-modules>=0.2.1->google-auth!=2.24.0,!=2.25.0,<3.0.0,>=2.14.1->google-cloud-bigquery-storage) (0.6.1)\nRequirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0dev,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (3.4.3)\nRequirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0dev,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (3.10)\nRequirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0dev,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (2.5.0)\nRequirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests<3.0.0dev,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-bigquery-storage) (2025.8.3)\nDownloading google_cloud_bigquery_storage-2.33.1-py3-none-any.whl (293 kB)\n\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m293.6/293.6 kB\u001b[0m \u001b[31m9.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n\u001b[?25hInstalling collected packages: google-cloud-bigquery-storage\n\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\nbigframes 2.12.0 requires google-cloud-bigquery[bqstorage,pandas]>=3.31.0, but you have google-cloud-bigquery 3.25.0 which is incompatible.\nbigframes 2.12.0 requires rich<14,>=12.4.4, but you have rich 14.1.0 which is incompatible.\u001b[0m\u001b[31m\n\u001b[0mSuccessfully installed google-cloud-bigquery-storage-2.33.1\n\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m47.7/47.7 MB\u001b[0m \u001b[31m52.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m:00:01\u001b[0m00:01\u001b[0m\n\u001b[?25h\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\npylibcudf-cu12 25.2.2 requires pyarrow<20.0.0a0,>=14.0.0; platform_machine == \"x86_64\", but you have pyarrow 22.0.0 which is incompatible.\ncudf-cu12 25.2.2 requires pyarrow<20.0.0a0,>=14.0.0; platform_machine == \"x86_64\", but you have pyarrow 22.0.0 which is incompatible.\nbigframes 2.12.0 requires google-cloud-bigquery[bqstorage,pandas]>=3.31.0, but you have google-cloud-bigquery 3.25.0 which is incompatible.\nbigframes 2.12.0 requires rich<14,>=12.4.4, but you have rich 14.1.0 which is incompatible.\ncudf-polars-cu12 25.6.0 requires pylibcudf-cu12==25.6.*, but you have pylibcudf-cu12 25.2.2 which is incompatible.\npandas-gbq 0.29.2 requires google-api-core<3.0.0,>=2.10.2, but you have google-api-core 1.34.1 which is incompatible.\u001b[0m\u001b[31m\n\u001b[0mNote: you may need to restart the kernel to use updated packages.\n","output_type":"stream"}],"execution_count":2},{"cell_type":"code","source":"# Необходимые импорты\n\nimport inspect\nimport json\nimport os\nfrom collections import Counter\nfrom dataclasses import dataclass\nfrom functools import lru_cache, partial\nfrom pathlib import Path\n\nimport regex as re\nimport torch\nimport torch.nn as nn\nfrom datasets import load_dataset\nfrom huggingface_hub import HfApi, PyTorchModelHubMixin, interpreter_login, snapshot_download\nfrom huggingface_hub.utils import SoftTemporaryDirectory\nfrom livelossplot import PlotLosses\nfrom torch import Tensor\nfrom torch.nn import functional as F\nfrom torch.utils.data import DataLoader\nfrom tqdm.auto import tqdm, trange","metadata":{"id":"UILR1tu3z9oI","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:29.117726Z","iopub.execute_input":"2025-10-27T19:08:29.118156Z","iopub.status.idle":"2025-10-27T19:08:32.481077Z","shell.execute_reply.started":"2025-10-27T19:08:29.118133Z","shell.execute_reply":"2025-10-27T19:08:32.480480Z"}},"outputs":[],"execution_count":3},{"cell_type":"code","source":"# Этой функцией будут помечены все места, которые необходимо дозаполнить\n# Это могут быть как целые функции, так и отдельные части внутри них\n# Всегда можно воспользоваться интроспекцией и найти места использования этой функции :)\n\n\ndef todo():\n stack = inspect.stack()\n caller_frame = stack[1]\n function_name = caller_frame.function\n line_number = caller_frame.lineno\n raise NotImplementedError(f\"TODO at {function_name}, line {line_number}\")","metadata":{"id":"4p7OLSivnPW0","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:32.481627Z","iopub.execute_input":"2025-10-27T19:08:32.482127Z","iopub.status.idle":"2025-10-27T19:08:32.485527Z","shell.execute_reply.started":"2025-10-27T19:08:32.482107Z","shell.execute_reply":"2025-10-27T19:08:32.485054Z"}},"outputs":[],"execution_count":4},{"cell_type":"code","source":"interpreter_login()","metadata":{"id":"bCkJJp2JK99x","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:32.486600Z","iopub.execute_input":"2025-10-27T19:08:32.486829Z","iopub.status.idle":"2025-10-27T19:08:40.405785Z","shell.execute_reply.started":"2025-10-27T19:08:32.486814Z","shell.execute_reply":"2025-10-27T19:08:40.405250Z"}},"outputs":[{"name":"stdout","text":"\n _| _| _| _| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _|_|_|_| _|_| _|_|_| _|_|_|_|\n _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _|\n _|_|_|_| _| _| _| _|_| _| _|_| _| _| _| _| _| _|_| _|_|_| _|_|_|_| _| _|_|_|\n _| _| _| _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _|\n _| _| _|_| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _| _| _| _|_|_| _|_|_|_|\n\n","output_type":"stream"},{"output_type":"stream","name":"stdin","text":"Enter your token (input will not be visible): ········\nAdd token as git credential? (Y/n) n\n"}],"execution_count":5},{"cell_type":"code","source":"# Подготовим репозиторий для будущей модели и токенизатора\nusername = HfApi().whoami()[\"name\"]\nREPO_NAME = f\"{username}/llm-course-hw1\" # Или как вам хочется\n\nprint(f\"Homework repository: '{REPO_NAME}'\")\n\n# И другие полезные вещи\nSEED = 0xC0FFEE","metadata":{"id":"GVWKkwaryDTq","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:40.406437Z","iopub.execute_input":"2025-10-27T19:08:40.406621Z","iopub.status.idle":"2025-10-27T19:08:40.494525Z","shell.execute_reply.started":"2025-10-27T19:08:40.406605Z","shell.execute_reply":"2025-10-27T19:08:40.494055Z"}},"outputs":[{"name":"stdout","text":"Homework repository: 'Amir337/llm-course-hw1'\n","output_type":"stream"}],"execution_count":6},{"cell_type":"markdown","source":"# Датасет\n\nПервым делом загрузим данные: [🤗 IgorVolochay/russian_jokes](https://huggingface.co/datasets/IgorVolochay/russian_jokes)\n\nИ немного посмотрим на них 👀","metadata":{"id":"GxN5JUbZ3ToV"}},{"cell_type":"code","source":"dataset = load_dataset(\"json\", data_files=\"hf://datasets/IgorVolochay/russian_jokes/dataset.json\")\nprint(\"\\n===\\n\".join(dataset[\"train\"][\"jokes\"][:3]))","metadata":{"id":"rT78JNcqpRXW","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:40.495082Z","iopub.execute_input":"2025-10-27T19:08:40.495252Z","iopub.status.idle":"2025-10-27T19:08:44.265264Z","shell.execute_reply.started":"2025-10-27T19:08:40.495238Z","shell.execute_reply":"2025-10-27T19:08:44.264657Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"dataset.json: 0%| | 0.00/44.2M [00:00 dict[int, str]:\n \"\"\"The original dictionary consists of 256 bytes and their corresponding Unicode characters.\n For example, chr(33) is '!'. However, not all bytes have a visually appealing representation,\n so such characters are skipped and replaced with the first available ones, i.e. shifted by 256.\n \"\"\"\n initial_bytes = (\n list(range(ord(\"!\"), ord(\"~\") + 1)) + list(range(ord(\"¡\"), ord(\"¬\") + 1)) + list(range(ord(\"®\"), ord(\"ÿ\") + 1))\n )\n initial_chars = [chr(it) for it in initial_bytes]\n n = 0\n for byte in range(2**8):\n if byte not in initial_bytes:\n initial_bytes.append(byte)\n initial_chars.append(chr(2**8 + n))\n n += 1\n return dict(sorted(zip(initial_bytes, initial_chars)))","metadata":{"id":"15U6H1iLU3kI","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:44.480360Z","iopub.execute_input":"2025-10-27T19:08:44.480549Z","iopub.status.idle":"2025-10-27T19:08:44.486245Z","shell.execute_reply.started":"2025-10-27T19:08:44.480534Z","shell.execute_reply":"2025-10-27T19:08:44.485733Z"}},"outputs":[],"execution_count":9},{"cell_type":"code","source":"def merge(merge_pair: tuple[str, str], pair_frequences: Counter[tuple[str, str]], words_by_tokens: Counter[tuple[str]]):\n \"\"\"Merges a given pair of tokens and update corresponding stats\n\n Args:\n merge_pair: The pair of tokens to be merged.\n pair_frequences: A counter tracking the frequency of token pairs in the dataset.\n words_by_tokens: A counter mapping tokenized words to their frequencies.\n\n Returns:\n Updated pair frequences and word tokenization w.r.t. to new token.\n \"\"\"\n a, b = merge_pair\n n_tok = a + b\n n_words = Counter()\n for toks, freq in words_by_tokens.items():\n i = 0\n n = len(toks)\n merged = []\n while i < n:\n if i < n - 1 and toks[i] == a and toks[i + 1] == b:\n merged.append(n_tok)\n i += 2\n else:\n merged.append(toks[i])\n i += 1\n n_words[tuple(merged)] += freq\n n_freqs = Counter()\n for toks, freq in n_words.items():\n if len(toks) < 2:\n continue\n for i in range(len(toks) - 1):\n n_freqs[(toks[i], toks[i + 1])] += freq\n\n return n_freqs, n_words\n\ndef train(data: list[str], vocab_size: int = 1024, special_tokens: list[str] = None):\n \"\"\"Train BPE tokenizer on passed data\n\n Args:\n data: List of train documents\n vocab_size: Size of target vocabulary\n special_tokens: List of special tokens to add into vocabulary\n Returns:\n vocabulary: mapping from string token to id\n merges: list of merges, each one is tuple of string tokens\n \"\"\"\n if vocab_size < 256:\n raise ValueError(\"Vocab size can't be less than 256\")\n if special_tokens is None:\n special_tokens = []\n\n # 1. Initialize vocabulary (using inverse one during training)\n id2token = bytes_to_unicode()\n merges = []\n\n # 2. Load data\n words_by_tokens = Counter()\n for sample in tqdm(data, desc=\"Loading data\"):\n # 2.1 Split into words\n words = WHITESPACE_SPLITTER.findall(sample.strip())\n for word in words:\n # 2.2 Tokenize with base vocabulary\n bt = word.encode(\"utf-8\")\n toks = tuple(id2token[b] for b in bt)\n if toks:\n words_by_tokens[toks] += 1\n\n # 3. Calculate statistic of token's pairs\n pair_frequences = Counter()\n for toks, freq in words_by_tokens.items():\n if len(toks) < 2:\n continue\n for i in range(len(toks) - 1):\n pair_frequences[(toks[i], toks[i + 1])] += freq\n\n # 4. Build vocabulary\n pbar = trange(vocab_size, desc=\"Building vocabulary\", initial=len(id2token) + len(special_tokens))\n while len(id2token) < vocab_size - len(special_tokens):\n if len(pair_frequences) == 0:\n print(\"Not enough data to fulfil vocabulary\")\n break\n\n # 4.1 Find the most frequent pair and create new token\n top_pair = pair_frequences.most_common(1)[0][0]\n new_token = top_pair[0] + top_pair[1]\n del pair_frequences[top_pair]\n\n # 4.2 Add to vocabulary\n if new_token in id2token.values():\n continue\n id2token[len(id2token)] = new_token\n merges.append(top_pair)\n\n # 4.3 Update stats and merge the top pair in all tokens\n pair_frequences, words_by_tokens = merge(top_pair, pair_frequences, words_by_tokens)\n\n pbar.update()\n pbar.close()\n\n # 5. Add special tokens\n for special_token in special_tokens:\n id2token[len(id2token)] = special_token\n\n return {v: k for k, v in id2token.items()}, merges","metadata":{"id":"yk919hENEFwL","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:44.486741Z","iopub.execute_input":"2025-10-27T19:08:44.486900Z","iopub.status.idle":"2025-10-27T19:08:44.503225Z","shell.execute_reply.started":"2025-10-27T19:08:44.486888Z","shell.execute_reply":"2025-10-27T19:08:44.502718Z"}},"outputs":[],"execution_count":10},{"cell_type":"code","source":"# Обучаем токенизатор на тренировочных текстах\n# Для нашей задачи хватит и небольшого словаря, но можете пробовать и большего размера обучить!\n\n\nvocab, merges = train(dataset[\"train\"][\"jokes\"], vocab_size=1024, special_tokens=[\"[EOS]\"])","metadata":{"id":"iLwur-KgK990","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:08:44.505231Z","iopub.execute_input":"2025-10-27T19:08:44.505456Z","iopub.status.idle":"2025-10-27T19:18:34.430137Z","shell.execute_reply.started":"2025-10-27T19:08:44.505442Z","shell.execute_reply":"2025-10-27T19:18:34.429442Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"Loading data: 0%| | 0/135497 [00:00 tuple[str]:\n \"\"\"Process word into tokenized representation.\n Word is a tuple of base tokens, i.e. bytes.\n\n Under the hood:\n 1. Tracks the set of token pairs, bi-grams\n 2. While possible, replaces the highest-ranking pair with its union\n\n Args:\n word: list of base string tokens\n Return:\n list of BPE tokens\n \"\"\"\n if len(word) < 2:\n return word\n pairs = set((word[i], word[i + 1]) for i in range(len(word) - 1))\n\n while pairs:\n best_pair = None\n best_rank = float(\"inf\")\n for p in pairs:\n r = self.bpe_ranks.get(p)\n if r is not None and r < best_rank:\n best_rank = r\n best_pair = p\n if best_pair is None:\n break\n a, b = best_pair\n ab = a + b\n i = 0\n new_word = []\n n = len(word)\n while i < n:\n if i < n - 1 and word[i] == a and word[i + 1] == b:\n new_word.append(ab)\n i += 2\n else:\n new_word.append(word[i])\n i += 1\n word = tuple(new_word)\n\n if len(word) < 2:\n break\n pairs = set((word[i], word[i + 1]) for i in range(len(word) - 1))\n\n return word\n\n def encode(self, text: str, add_eos_token: bool = True) -> list[int]:\n \"\"\"Convert string to list of token ids.\n\n Args:\n text: input string, may contain multiple words\n add_eos_token: whether to add eos token id at the end\n Return:\n list of ints, ids of tokenized text\n \"\"\"\n words = WHITESPACE_SPLITTER.findall(text)\n ids: list[int] = []\n for w in words:\n bt = w.encode(\"utf-8\")\n base_tokens = tuple(self.byte_encoder[b] for b in bt)\n bpe_tokens = self.bpe(base_tokens)\n for t in bpe_tokens:\n ids.append(self.token2id[t])\n if add_eos_token:\n ids.append(self.eos_token_id)\n return ids\n\n def decode(self, idx: list[int]) -> str:\n \"\"\"Convert list of tokens' ids to text, opposite to encode method\n\n Args:\n idx: list of tokens' ids\n Return:\n string, decoded text\n \"\"\"\n out_parts: list[str] = []\n byte_buf: list[int] = []\n\n for tid in idx:\n if tid == self.eos_token_id:\n continue\n tok = self.id2token[tid]\n all_base = True\n for ch in tok:\n if ch not in self.byte_decoder:\n all_base = False\n break\n\n if all_base:\n for ch in tok:\n byte_buf.append(self.byte_decoder[ch])\n else:\n if byte_buf:\n out_parts.append(bytes(byte_buf).decode(\"utf-8\", errors=\"replace\"))\n byte_buf = []\n out_parts.append(tok)\n\n if byte_buf:\n out_parts.append(bytes(byte_buf).decode(\"utf-8\", errors=\"replace\"))\n\n return \"\".join(out_parts)\n\n\n def push_to_hub(self, repo_id, *, private=None, token=None):\n api = HfApi()\n repo_id = api.create_repo(repo_id=repo_id, token=token, private=private, exist_ok=True).repo_id\n\n # Push the files to the repo in a single commit\n with SoftTemporaryDirectory() as tmp:\n save_directory = Path(tmp) / repo_id\n save_directory.mkdir(parents=True)\n with open(save_directory / \"vocabulary.json\", \"w\") as f_out:\n print(json.dumps(self.token2id, indent=2), file=f_out)\n with open(save_directory / \"merges.json\", \"w\") as f_out:\n print(json.dumps({\"merges\": self.merges}), file=f_out)\n\n return api.upload_folder(repo_id=repo_id, folder_path=save_directory, token=token)\n\n @classmethod\n def from_pretrained(cls, pretrained_model_name_or_path, *, token=None, **model_kwargs):\n if not os.path.isdir(pretrained_model_name_or_path):\n storage_folder = snapshot_download(repo_id=pretrained_model_name_or_path, token=token)\n else:\n storage_folder = pretrained_model_name_or_path\n storage_folder = Path(storage_folder)\n with open(storage_folder / \"vocabulary.json\", \"r\") as f_in:\n vocab = json.load(f_in)\n with open(storage_folder / \"merges.json\", \"r\") as f_in:\n merges = [tuple(it) for it in json.load(f_in)[\"merges\"]]\n return cls(vocab, merges, **model_kwargs)","metadata":{"id":"ugUz7cma1Czs","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:18:34.437006Z","iopub.execute_input":"2025-10-27T19:18:34.437161Z","iopub.status.idle":"2025-10-27T19:18:34.473991Z","shell.execute_reply.started":"2025-10-27T19:18:34.437149Z","shell.execute_reply":"2025-10-27T19:18:34.473380Z"}},"outputs":[],"execution_count":13},{"cell_type":"code","source":"# Инициализируем токенизатор\n\n\ntokenizer = ByteLevelBPETokenizer(vocab, merges)","metadata":{"id":"xRTQzO3wK991","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:18:34.474472Z","iopub.execute_input":"2025-10-27T19:18:34.474629Z","iopub.status.idle":"2025-10-27T19:18:34.489048Z","shell.execute_reply.started":"2025-10-27T19:18:34.474617Z","shell.execute_reply":"2025-10-27T19:18:34.488566Z"}},"outputs":[],"execution_count":14},{"cell_type":"code","source":"# Загружаем токенизатор на хаб\n\ntokenizer.push_to_hub(REPO_NAME)","metadata":{"id":"-9m_65vBK991","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:18:34.489547Z","iopub.execute_input":"2025-10-27T19:18:34.489703Z","iopub.status.idle":"2025-10-27T19:18:34.954774Z","shell.execute_reply.started":"2025-10-27T19:18:34.489691Z","shell.execute_reply":"2025-10-27T19:18:34.954278Z"}},"outputs":[{"name":"stderr","text":"No files have been modified since last commit. Skipping to prevent empty commit.\n","output_type":"stream"},{"execution_count":15,"output_type":"execute_result","data":{"text/plain":"CommitInfo(commit_url='https://huggingface.co/Amir337/llm-course-hw1/commit/ae0e4748cb7ed19a83d61d7887f08f88e564e65e', commit_message='Upload folder using huggingface_hub', commit_description='', oid='ae0e4748cb7ed19a83d61d7887f08f88e564e65e', pr_url=None, repo_url=RepoUrl('https://huggingface.co/Amir337/llm-course-hw1', endpoint='https://huggingface.co', repo_type='model', repo_id='Amir337/llm-course-hw1'), pr_revision=None, pr_num=None)"},"metadata":{}}],"execution_count":15},{"cell_type":"code","source":"# Скачиваем токенизатор с хаба\n\ntokenizer = ByteLevelBPETokenizer.from_pretrained(REPO_NAME)","metadata":{"id":"S9VohtKrK991","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:18:34.955336Z","iopub.execute_input":"2025-10-27T19:18:34.955552Z","iopub.status.idle":"2025-10-27T19:18:36.337859Z","shell.execute_reply.started":"2025-10-27T19:18:34.955538Z","shell.execute_reply":"2025-10-27T19:18:36.337349Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"Fetching 6 files: 0%| | 0/6 [00:00 Tensor:\n B, L, _ = x.shape\n\n # Q\n q = self.q_proj(x).view(B, L, self.config.n_head, self.head_dim).permute(0, 2, 1, 3)\n\n c = self.c_proj(x)\n kd = self.k_dec(c).view(B, L, self.config.n_kv_head, self.head_dim)\n vd = self.v_dec(c).view(B, L, self.config.n_kv_head, self.head_dim)\n k = kd.permute(0, 2, 1, 3)\n v = vd.permute(0, 2, 1, 3)\n\n if self.q_per_kv > 1:\n k = k.repeat_interleave(self.q_per_kv, dim=1)\n v = v.repeat_interleave(self.q_per_kv, dim=1)\n\n if self.config.use_rope:\n t = torch.arange(L, device=x.device, dtype=torch.float32)\n freqs = torch.outer(t, self.rope_inv_freq)\n cos = freqs.cos().to(q.dtype).view(1, 1, L, -1)\n sin = freqs.sin().to(q.dtype).view(1, 1, L, -1)\n h = self.head_dim // 2\n\n q1, q2 = q[..., :h], q[..., h:]\n k1, k2 = k[..., :h], k[..., h:]\n q = torch.cat([q1 * cos - q2 * sin, q2 * cos + q1 * sin], dim=-1)\n k = torch.cat([k1 * cos - k2 * sin, k2 * cos + k1 * sin], dim=-1)\n\n att = torch.matmul(q, k.transpose(-2, -1)) * self.scale # [B,H,L,L]\n\n if not self.config.use_rope:\n i = torch.arange(L, device=x.device).view(1, 1, L, 1)\n j = torch.arange(L, device=x.device).view(1, 1, 1, L)\n att = att + (self.alibi.to(att.dtype) * (j - i))\n\n att = att.masked_fill(~self.causal_mask[:, :, :L, :L], torch.finfo(att.dtype).min)\n if attention_mask is not None:\n key_mask = attention_mask if attention_mask.dim() == 2 else attention_mask[..., 0]\n key_mask = (key_mask > 0).view(B, 1, 1, L)\n att = att.masked_fill(~key_mask, torch.finfo(att.dtype).min)\n\n att = F.softmax(att, dim=-1)\n att = self.attn_dropout(att)\n\n y = torch.matmul(att, v)\n y = y.permute(0, 2, 1, 3).contiguous().view(B, L, self.config.n_head * self.head_dim)\n y = self.out_proj(y)\n return y\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-27T20:54:53.325127Z","iopub.execute_input":"2025-10-27T20:54:53.325328Z","iopub.status.idle":"2025-10-27T20:54:53.340770Z","shell.execute_reply.started":"2025-10-27T20:54:53.325314Z","shell.execute_reply":"2025-10-27T20:54:53.340205Z"}},"outputs":[],"execution_count":76},{"cell_type":"code","source":"class RMSNorm(nn.Module):\n def __init__(self, dim: int, eps: float = 1e-6):\n \"\"\"Root Mean Square Layer Normalization\n\n Args:\n dim: Feature dimension\n eps: Small constant for numerical stability\n \"\"\"\n super().__init__()\n self.eps = eps\n self.scale = nn.Parameter(torch.ones(dim))\n\n def forward(self, x: Tensor) -> Tensor:\n rms = x.pow(2).mean(dim=-1, keepdim=True)\n x_norm = x * torch.rsqrt(rms + self.eps)\n return self.scale * x_norm\n\n\nclass CausalSelfAttention(nn.Module):\n def __init__(self, config: TransformerConfig):\n \"\"\"Causal Self-Attention with support of\n Grouped-Query Attention and ALiBi for positional encoding\n \"\"\"\n super().__init__()\n self.config = config\n assert self.config.hidden_dim % self.config.n_head == 0\n assert self.config.n_head % self.config.n_kv_head == 0\n self.head_dim = self.config.hidden_dim // self.config.n_head\n self.scale = self.head_dim**-0.5\n self.q_per_kv = self.config.n_head // self.config.n_kv_head\n\n # Init projection layers\n self.q_proj = nn.Linear(self.config.hidden_dim, self.config.n_head * self.head_dim, bias=False)\n self.kv_proj = nn.Linear(self.config.hidden_dim, self.config.n_kv_head * self.head_dim * 2, bias=False)\n self.out_proj = nn.Linear(self.config.n_head * self.head_dim, self.config.hidden_dim, bias=False)\n\n self.attn_dropout = nn.Dropout(self.config.dropout)\n\n self.register_buffer(\"causal_mask\", self._create_causal_mask(self.config.max_seq_len))\n self.register_buffer(\"alibi\", self._build_alibi_bias(self.config.n_head))\n\n # тут RoPE\n half = self.head_dim // 2\n inv = 1.0 / (self.config.rope_theta ** (torch.arange(half, dtype=torch.float32) / half))\n self.register_buffer(\"rope_inv_freq\", inv, persistent=False)\n\n def _build_alibi_bias(self, num_heads: int) -> Tensor:\n \"\"\"Build ALiBi for specified number of heads:\n\n Returns:\n Tensor with ALiBi biases, shape: [1, num heads, 1, 1]\n \"\"\"\n if (num_heads & (num_heads - 1)) == 0:\n start = 2 ** (-8.0 / num_heads)\n slopes = [start ** i for i in range(1, num_heads + 1)]\n else:\n closest = 1 << (num_heads.bit_length() - 1)\n start1 = 2 ** (-8.0 / closest)\n slopes1 = [start1 ** i for i in range(1, closest + 1)]\n start2 = 2 ** (-8.0 / (2 * closest))\n slopes2 = [start2 ** i for i in range(1, 2 * closest + 1)]\n slopes = slopes1 + slopes2[: num_heads - closest]\n return torch.tensor(slopes, dtype=torch.float32).view(1, num_heads, 1, 1)\n\n def _create_causal_mask(self, max_seq_len: int) -> Tensor:\n \"\"\"Create causal mask with ones where tokens can attend to each other.\n\n Returns:\n Tensor with causal mask, shape: [1, 1, seq len, seq len]\n \"\"\"\n mask = torch.tril(torch.ones(max_seq_len, max_seq_len, dtype=torch.bool))\n return mask.view(1, 1, max_seq_len, max_seq_len)\n\n def forward(self, x: Tensor, attention_mask: Tensor = None) -> Tensor:\n \"\"\"Apply Self-Attention to input data with respect to pad tokens.\n\n Args:\n x: input tensor, shape [bs, seq len, hidden dim]\n attention_mask: mask with zeros for pad tokens, shape [bs, seq len, hidden dim]\n Returns:\n result tensor, shape [bs, seq len, hidden dim]\n \"\"\"\n B, L, Z = x.shape\n\n q = self.q_proj(x).view(B, L, self.config.n_head, self.head_dim).permute(0, 2, 1, 3)\n kv = self.kv_proj(x).view(B, L, self.config.n_kv_head, 2, self.head_dim)\n k = kv[:, :, :, 0, :].permute(0, 2, 1, 3)\n v = kv[:, :, :, 1, :].permute(0, 2, 1, 3)\n\n if self.q_per_kv > 1:\n k = k.repeat_interleave(self.q_per_kv, dim=1)\n v = v.repeat_interleave(self.q_per_kv, dim=1)\n\n #RoPE\n if self.config.use_rope:\n t = torch.arange(L, device=x.device, dtype=torch.float32)\n freqs = torch.outer(t, self.rope_inv_freq) # [L, half]\n cos = freqs.cos().to(q.dtype).view(1, 1, L, -1)\n sin = freqs.sin().to(q.dtype).view(1, 1, L, -1)\n\n half = self.head_dim // 2\n q1, q2 = q[..., :half], q[..., half:]\n k1, k2 = k[..., :half], k[..., half:]\n q = torch.cat([q1 * cos - q2 * sin, q2 * cos + q1 * sin], dim=-1)\n k = torch.cat([k1 * cos - k2 * sin, k2 * cos + k1 * sin], dim=-1)\n\n \n att = torch.matmul(q, k.transpose(-2, -1)) * self.scale\n\n if not self.config.use_rope:\n i = torch.arange(L, device=x.device).view(1, 1, L, 1)\n j = torch.arange(L, device=x.device).view(1, 1, 1, L)\n att = att + (self.alibi.to(att.dtype) * (j - i))\n\n causal = self.causal_mask[:, :, :L, :L]\n att = att.masked_fill(~causal, torch.finfo(att.dtype).min)\n\n if attention_mask is not None:\n key_mask = attention_mask\n if key_mask.dim() == 3:\n key_mask = key_mask[..., 0]\n key_mask = (key_mask > 0).view(B, 1, 1, L)\n att = att.masked_fill(~key_mask, torch.finfo(att.dtype).min)\n\n att = F.softmax(att, dim=-1)\n att = self.attn_dropout(att)\n\n y = torch.matmul(att, v)\n y = y.permute(0, 2, 1, 3).contiguous().view(B, L, self.config.n_head * self.head_dim)\n y = self.out_proj(y)\n return y\n\n\nclass SwiGLU(nn.Module):\n def __init__(self, config: TransformerConfig):\n \"\"\"Gated Liner Unit with Swish Activation\"\"\"\n super().__init__()\n self.config = config\n # Init up- and down- projection layers\n self.fc1 = nn.Linear(config.hidden_dim, 2 * config.intermediate_dim, bias=True)\n self.fc2 = nn.Linear(config.intermediate_dim, config.hidden_dim, bias=True)\n\n def forward(self, x: Tensor) -> Tensor:\n \"\"\"Apply SwiGLU to input data.\n\n Args:\n x: input tensor, shape [bs, seq len, hidden dim]\n Returns:\n result tensor, shape [bs, seq len, hidden dim]\n \"\"\"\n h = self.fc1(x)\n a, b = h.chunk(2, dim=-1)\n h = F.silu(a) * b\n h = self.fc2(h)\n return h\n\n\nclass Block(nn.Module):\n def __init__(self, config: TransformerConfig):\n \"\"\"Base Transformer Block\n - Causal Self-Attention and SwiGLU as main elements\n - Pre-normalization via RMSNorm\n - Regularization with dropouts before residuals\n \"\"\"\n super().__init__()\n self.ln_1 = RMSNorm(config.hidden_dim)\n self.res_dropout_1 = nn.Dropout(config.dropout)\n self.attn = CausalSelfAttentionMLA(config) if config.use_mla else CausalSelfAttention(config)\n\n self.ln_2 = RMSNorm(config.hidden_dim)\n self.res_dropout_2 = nn.Dropout(config.dropout)\n self.mlp = SwiGLU(config)\n\n def forward(self, x: Tensor, attention_mask: Tensor = None) -> Tensor:\n \"\"\"Apply Transformer Block to input data.\n\n Args:\n x: input tensor, shape [bs, seq len, hidden dim]\n attention_mask: mask with zeros for pad tokens, shape [bs, seq len, hidden dim]\n Returns:\n result tensor, shape [bs, seq len, hidden dim]\n \"\"\"\n x = x + self.res_dropout_1(self.attn(self.ln_1(x), attention_mask=attention_mask))\n x = x + self.res_dropout_2(self.mlp(self.ln_2(x)))\n return x\n\n\nclass TransformerForCausalLM(nn.Module, PyTorchModelHubMixin):\n def __init__(self, config: TransformerConfig):\n \"\"\"Transformer model for Language Modeling\"\"\"\n super().__init__()\n self.vocab_size = config.vocab_size\n self.max_seq_len = config.max_seq_len\n self.n_layer = config.n_layer\n self.n_head = config.n_head\n self.hidden_dim = config.hidden_dim\n self.dropout = config.dropout\n\n self.token_emb = nn.Embedding(config.vocab_size, config.hidden_dim)\n self.emb_dropout = nn.Dropout(config.dropout)\n self.layers = nn.ModuleList([Block(config) for _ in range(config.n_layer)])\n self.ln_final = RMSNorm(config.hidden_dim)\n self.lm_head = nn.Linear(config.hidden_dim, config.vocab_size, bias=False)\n\n self.apply(self._init_weights)\n\n n_params = sum(p.numel() for p in self.parameters())\n print(f\"Number of parameters: {n_params / 1e6:.2f}M\")\n\n def _init_weights(self, module):\n if isinstance(module, nn.Linear):\n torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)\n if module.bias is not None:\n torch.nn.init.zeros_(module.bias)\n elif isinstance(module, nn.Embedding):\n torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)\n elif isinstance(module, RMSNorm):\n torch.nn.init.ones_(module.scale)\n\n def forward(self, input_ids: torch.Tensor, attention_mask: torch.Tensor = None) -> Tensor:\n \"\"\"Calculate logits for given input ids.\n\n Args:\n x: input tensor, shape [bs, seq len, hidden dim]\n attention_mask: mask with zeros for pad tokens, shape [bs, seq len, hidden dim]\n Returns:\n logits, shape [bs, seq len, hidden dim]\n \"\"\"\n B, L = input_ids.shape\n x = self.token_emb(input_ids)\n x = self.emb_dropout(x)\n for layer in self.layers:\n x = layer(x, attention_mask=attention_mask)\n x = self.ln_final(x)\n logits = self.lm_head(x)\n return logits\n\n @torch.inference_mode()\n def generate(\n self, idx: Tensor, max_new_tokens, eos_token_id, temperature=1.0, do_sample=False, top_k=None\n ) -> Tensor:\n \"\"\"Take a conditioning sequence of indices and complete the sequence max_new_tokens times,\n feeding the predictions back into the model each time.\n\n Args:\n idx: tensor with conditional tokens, shape [seq len]\n max_new_tokens: maximum number of new tokens\n eos_token_id: index of EOS token to stop generation\n temperature, do_sample, top_k: generation parameters\n Return:\n tensor with generated indexes\n \"\"\"\n for _ in range(max_new_tokens):\n idx_cond = idx if idx.shape[1] <= self.max_seq_len else idx[:, -self.max_seq_len :]\n logits = self(idx_cond)\n\n # 1. Pluck the logits at the final step and scale by desired temperature\n logits = logits[:, -1, :] / max(temperature, 1e-8)\n\n # 2. Optionally crop the logits to only the top k options\n if top_k is not None:\n k = min(top_k, logits.size(-1))\n topk_vals, _ = torch.topk(logits, k, dim=-1)\n cutoff = topk_vals[:, [-1]]\n logits = logits.masked_fill(logits < cutoff, float(\"-inf\"))\n\n # 3. apply softmax to convert logits to probabilities\n probs = F.softmax(logits, dim=-1)\n\n # 4. Either sample from the distribution or take the most likely element\n if do_sample:\n idx_next = torch.multinomial(probs, num_samples=1) \n else:\n idx_next = torch.argmax(probs, dim=-1, keepdim=True)\n\n # 5. Append sampled index to the running sequence and continue\n idx = torch.cat((idx, idx_next), dim=1)\n if idx_next == eos_token_id:\n break\n return idx","metadata":{"id":"aYXMb5PEDFkt","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T20:54:55.030416Z","iopub.execute_input":"2025-10-27T20:54:55.030878Z","iopub.status.idle":"2025-10-27T20:54:55.060062Z","shell.execute_reply.started":"2025-10-27T20:54:55.030861Z","shell.execute_reply":"2025-10-27T20:54:55.059508Z"}},"outputs":[],"execution_count":77},{"cell_type":"markdown","source":"# Train Loop [1 + 1 баллов]\n\nНастало время обучать модель.\nНебольшую можно пробовать обучать локально, но лучше всего воспользоваться GPU, например, на Google Colab.\n\nЗа реализацию 1 балл, и еще 1 балл - если модель научилась генерить анекдоты.\n\nНе забудьте проверить, что вы загрузили нужные веса на HF и у проверяющего скачается нужная версия.","metadata":{"id":"IhdavMmSDujw"}},{"cell_type":"code","source":"# Определим датасет и как заворачивать семплы в батч\n# Разные тексты имеют разную длину, поэтому будет падить до самого длина семпла\n# Так же заведем дополнительную маску, чтобы механизм внимания не учитывал падинги\n\n\nclass TextDataset(torch.utils.data.Dataset):\n def __init__(self, texts, tokenizer):\n self.texts = texts\n self.tokenizer = tokenizer\n\n def __len__(self):\n return len(self.texts)\n\n def __getitem__(self, idx):\n texts = self.texts[idx]\n tokenized_sequence = self.tokenizer.encode(texts)\n return tokenized_sequence\n\n\ndef data_collator(\n tokenized_sequences: list[list[int]], pad_token_id: int, max_seq_len: int = None\n) -> tuple[torch.Tensor, torch.Tensor]:\n batch_size = len(tokenized_sequences)\n max_batch_seq_len = min(max_seq_len, max((len(it) for it in tokenized_sequences)))\n\n input_ids = torch.full((batch_size, max_batch_seq_len), pad_token_id, dtype=torch.long)\n attention_mask = torch.zeros((batch_size, max_batch_seq_len), dtype=torch.bool)\n\n for i, tok_seq in enumerate(tokenized_sequences):\n cur_len = min(len(tok_seq), max_batch_seq_len)\n input_ids[i, :cur_len] = torch.tensor(tok_seq[:cur_len], dtype=torch.long)\n attention_mask[i, :cur_len] = 1\n\n return input_ids, attention_mask\n\n\ndef create_dataloader(dataset, pad_token_id, max_seq_len, batch_size, is_train):\n collate_fn = partial(data_collator, pad_token_id=pad_token_id, max_seq_len=max_seq_len)\n return DataLoader(\n dataset, batch_size=batch_size, shuffle=is_train, drop_last=is_train, collate_fn=collate_fn, pin_memory=True\n )\n\n\n_d = TextDataset([\"Привет!\", \"Как твои дела?\", \"Осталось совсем немного до конца\"], tokenizer)\n_dl = create_dataloader(_d, tokenizer.eos_token_id, max_seq_len=16, batch_size=2, is_train=False)\n\nfor i, batch in enumerate(_dl):\n print(f\"Batch #{i}\")\n input_ids, attn_mask = batch\n print(input_ids, attn_mask, sep=\"\\n\\n\")","metadata":{"id":"1wtAiR_aDxed","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:54:30.649529Z","iopub.execute_input":"2025-10-27T19:54:30.650084Z","iopub.status.idle":"2025-10-27T19:54:30.660259Z","shell.execute_reply.started":"2025-10-27T19:54:30.650068Z","shell.execute_reply":"2025-10-27T19:54:30.659682Z"}},"outputs":[{"name":"stdout","text":"Batch #0\ntensor([[ 726, 347, 281, 33, 1023, 1023, 1023, 1023],\n [ 527, 303, 1009, 261, 576, 258, 63, 1023]])\n\ntensor([[ True, True, True, True, True, False, False, False],\n [ True, True, True, True, True, True, True, True]])\nBatch #1\ntensor([[ 488, 294, 298, 644, 827, 263, 323, 276, 323, 531, 692, 596,\n 880, 1023]])\n\ntensor([[True, True, True, True, True, True, True, True, True, True, True, True,\n True, True]])\n","output_type":"stream"}],"execution_count":42},{"cell_type":"code","source":"def get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps):\n \"\"\"Scheduler for Optimizer with linear warmup and linear decay to the end of training\n\n Args:\n optimizer: torch optimizer to control learning rate\n num_warmup_steps: number of warmup steps\n num_training_steps: total number of training steps\n Return:\n torch learning rate scheduler\n \"\"\"\n assert num_training_steps >= num_warmup_steps\n\n def lr_lambda(current_step):\n if current_step < num_warmup_steps:\n return float(current_step) / max(1, num_warmup_steps)\n return max(\n 0.0,\n float(num_training_steps - current_step) / max(1, num_training_steps - num_warmup_steps),\n )\n\n return torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda)\n\n\ndef cross_entropy_loss(input_ids: Tensor, attention_mask: Tensor, logits: Tensor) -> Tensor:\n \"\"\"Calculate Cross-Entropy loss for Language Modeling task\n Under the hood:\n 1. Create targtes based on input ids\n 2. Masked out tokens corresponded to paddings\n 3. Calculate cross entropy loss\n\n Args:\n input_ids: tensor with input ids, shape [bs, seq len]\n attention_mask: mask with zeros for pad tokens, shape [bs, seq len]\n logits: predicted logits, shape [bs, seq len, vocab size]\n Return:\n cross entropy loss, single-item tensor\n \"\"\"\n n_logits = logits[:, :-1, :].contiguous()\n labels = input_ids[:, 1:].contiguous()\n mask = attention_mask[:, 1:].contiguous()\n\n # лосс покадрово без усреднения\n loss_tok = F.cross_entropy(\n n_logits.view(-1, n_logits.size(-1)),\n labels.view(-1),\n reduction=\"none\",\n ).view_as(mask)\n\n valid = mask.float()\n loss = (loss_tok * valid).sum() / valid.sum().clamp_min(1.0)\n return loss","metadata":{"id":"i719AOdQK993","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:54:30.697377Z","iopub.execute_input":"2025-10-27T19:54:30.697550Z","iopub.status.idle":"2025-10-27T19:54:30.703112Z","shell.execute_reply.started":"2025-10-27T19:54:30.697536Z","shell.execute_reply":"2025-10-27T19:54:30.702615Z"}},"outputs":[],"execution_count":43},{"cell_type":"code","source":"# Определим тренера с наиболее важными гиперпараметрами для обучения\n\n\nclass Trainer:\n\n def __init__(\n self,\n learning_rate=3e-4,\n weight_decay=0.01,\n clip_grad_norm=1.0,\n n_steps=10_000,\n val_every_n_steps=1_000,\n plot_every_n_steps=100,\n ):\n self.learning_rate = learning_rate\n self.weight_decay = weight_decay\n self.clip_grad_norm = clip_grad_norm\n self.n_steps = n_steps\n self.val_every_n_steps = val_every_n_steps\n self.plot_every_n_steps = plot_every_n_steps\n\n if torch.cuda.is_available():\n self.device = \"cuda\"\n elif torch.backends.mps.is_available():\n self.device = \"mps\"\n else:\n self.device = \"cpu\"\n print(\"running on device\", self.device)\n\n @torch.no_grad()\n def validate(self, model, val_loader):\n model.eval()\n val_loss = 0.0\n for batch in tqdm(val_loader, desc=\"Validating\", leave=False):\n input_ids, attention_mask = batch\n input_ids = input_ids.to(self.device, non_blocking=True).long()\n attention_mask = attention_mask.to(self.device, non_blocking=True)\n\n logits = model(input_ids, attention_mask) # [bs; seq len; vocab size]\n val_loss += cross_entropy_loss(input_ids, attention_mask, logits)\n return val_loss / len(val_loader)\n\n def run(self, model, train_loader, val_loader):\n model = model.to(self.device)\n optimizer = torch.optim.AdamW(model.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)\n scheduler = get_linear_schedule_with_warmup(\n optimizer, num_warmup_steps=0.1 * self.n_steps, num_training_steps=self.n_steps\n )\n model.train()\n\n plotlosses = PlotLosses(figsize=(15, 9), step_names=\"Step\")\n logs = {\"lr\": 0, \"epoch\": 0}\n\n data_iter = iter(train_loader)\n for iter_num in range(self.n_steps):\n try:\n batch = next(data_iter)\n except StopIteration:\n data_iter = iter(train_loader)\n logs[\"epoch\"] += 1\n batch = next(data_iter)\n\n input_ids, attention_mask = batch\n input_ids = input_ids.to(self.device, non_blocking=True)\n attention_mask = attention_mask.to(self.device, non_blocking=True)\n\n logits = model(input_ids, attention_mask) # [bs; seq len; vocab size]\n loss = cross_entropy_loss(input_ids, attention_mask, logits)\n\n # backprop and update the parameters\n model.zero_grad(set_to_none=True)\n loss.backward()\n torch.nn.utils.clip_grad_norm_(model.parameters(), self.clip_grad_norm)\n optimizer.step()\n scheduler.step()\n\n if iter_num > 0 and iter_num % self.val_every_n_steps == 0:\n val_loss = self.validate(model, val_loader)\n plotlosses.update({\"val_loss\": val_loss.item()}, current_step=iter_num)\n plotlosses.send()\n model.train()\n\n if iter_num % self.plot_every_n_steps == 0:\n logs[\"loss\"] = loss.item()\n logs[\"lr\"] = scheduler.get_last_lr()[0]\n plotlosses.update(logs, current_step=iter_num)\n plotlosses.send()\n\n val_loss = self.validate(model, val_loader)\n plotlosses.update({\"val_loss\": val_loss.item()}, current_step=iter_num)\n plotlosses.send()","metadata":{"id":"SPYdF52zXtoX","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:54:30.783013Z","iopub.execute_input":"2025-10-27T19:54:30.783417Z","iopub.status.idle":"2025-10-27T19:54:30.793399Z","shell.execute_reply.started":"2025-10-27T19:54:30.783402Z","shell.execute_reply":"2025-10-27T19:54:30.792913Z"}},"outputs":[],"execution_count":44},{"cell_type":"code","source":"# Создаем тренировочный и тестовые даталоадеры\n\n\nMAX_SEQ_LEN = 128\nBATCH_SIZE = 16\n\ntrain_dataset = TextDataset(dataset[\"train\"][\"jokes\"], tokenizer)\ntrain_dataloader = create_dataloader(\n train_dataset, tokenizer.eos_token_id, max_seq_len=MAX_SEQ_LEN, batch_size=BATCH_SIZE, is_train=True\n)\n\ntest_dataset = TextDataset(dataset[\"test\"][\"jokes\"], tokenizer)\ntest_dataloader = create_dataloader(\n test_dataset, tokenizer.eos_token_id, max_seq_len=MAX_SEQ_LEN, batch_size=BATCH_SIZE, is_train=False\n)","metadata":{"id":"yK1BpJflMTAi","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:54:30.794289Z","iopub.execute_input":"2025-10-27T19:54:30.794455Z","iopub.status.idle":"2025-10-27T19:54:30.807664Z","shell.execute_reply.started":"2025-10-27T19:54:30.794442Z","shell.execute_reply":"2025-10-27T19:54:30.807176Z"}},"outputs":[],"execution_count":45},{"cell_type":"code","source":"# Инициализируем модель\n\nconfig = model_configs[\"small\"]\nconfig.use_rope = True\nconfig.rope_theta = 10000.0\nmodel = TransformerForCausalLM(config)","metadata":{"id":"53jHSgMZECGl","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:55:01.252088Z","iopub.execute_input":"2025-10-27T19:55:01.252639Z","iopub.status.idle":"2025-10-27T19:55:02.452074Z","shell.execute_reply.started":"2025-10-27T19:55:01.252619Z","shell.execute_reply":"2025-10-27T19:55:02.451366Z"}},"outputs":[{"name":"stdout","text":"Number of parameters: 79.51M\n","output_type":"stream"}],"execution_count":47},{"cell_type":"code","source":"# Инициализируем тренера\n\ntrainer = Trainer(learning_rate=3e-4)","metadata":{"id":"uMUsjHl4Nkoa","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:55:10.188082Z","iopub.execute_input":"2025-10-27T19:55:10.188782Z","iopub.status.idle":"2025-10-27T19:55:10.191837Z","shell.execute_reply.started":"2025-10-27T19:55:10.188754Z","shell.execute_reply":"2025-10-27T19:55:10.191314Z"}},"outputs":[{"name":"stdout","text":"running on device cuda\n","output_type":"stream"}],"execution_count":48},{"cell_type":"code","source":"# Обучение goes brrrr!\n\ntrainer.run(model, train_dataloader, test_dataloader)","metadata":{"id":"1nUgUfpKK993","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T19:55:12.429582Z","iopub.execute_input":"2025-10-27T19:55:12.430297Z","iopub.status.idle":"2025-10-27T20:33:13.569608Z","shell.execute_reply.started":"2025-10-27T19:55:12.430271Z","shell.execute_reply":"2025-10-27T20:33:13.569066Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"
","image/png":"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H32k4uJi5+uvv/5a6enpGjt2rCRpwIABio6O1htvvKGKigrnup9//llbtmzRueeeK8nxAHH66afrvffeU2pqaq1rUF0OAAAAd2QymXTWWWfphx9+cLZDlKTMzEx99tlnGjZsmIKDgyVJubm5tY4NDAxUhw4dnPfYZWVlKi8vr7Wmffv2CgoKqnUfDgA4NrOrAwAANH9PPvmkfv/9dw0ePFg33HCDunXrpry8PK1evVrz5s1TXl6ec214eLiGDRumyZMnKzMzUy+88II6dOigG264QZLk5eWlp556SpMnT9YZZ5yhCRMmKDMzUy+++KISExN11113Oc/10ksvadiwYerXr59uvPFGJSUlKTk5WbNmzdLatWub+msAAAAAGs17772nOXPmHLZ/+vTp+vXXXzVs2DDdcsstMpvNevPNN1VRUaGnn37aua5bt24aPny4+vfvr/DwcK1cuVJff/21pkyZIknavn27Ro4cqfHjx6tbt24ym8367rvvlJmZqSuuuKLJPicAuAOS6ACAY4qJidHy5cv16KOP6ttvv9Vrr72miIgIde/eXU899VSttffff7/Wr1+vGTNmqLi4WCNHjtRrr70mf39/55pJkybJ399fTz75pO69914FBATooosu0lNPPaXQ0FDnut69e2vp0qV68MEH9frrr6u8vFxt27bV+PHjm+qjAwAAACfF66+/fsT9kyZN0p9//qlp06ZpxowZstlsGjx4sD755BMNHjzYue7222/XzJkz9csvv6iiokJt27bVf/7zH91zzz2SpISEBE2YMEHz58/Xxx9/LLPZrC5duujLL7/UJZdc0iSfEQDchcHO78QDABrBggULNGLECH311Ve69NJLXR0OAAAAAABAo6AnOgAAAAAAAAAAdSCJDgAAAAAAAABAHUiiAwAAAAAAAABQB3qiAwAAAAAAAABQByrRAQAAAAAAAACog9nVAbQ0NptNaWlpCgoKksFgcHU4AAAAgJPdbldxcbHi4+NlNDaPehnunwEAANBc1ff+mST6cUpLS1NCQoKrwwAAAADqtHfvXrVu3drVYUji/hkAAADN37Hun0miH6egoCBJji82ODjYxdEAAAAABxUVFSkhIcF5z9occP8MAACA5qq+988k0Y9Tza+gBgcH8xAAAACAZqk5tU3h/hkAAADN3bHun5tHo0QAAAAAAAAAAJoh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TZ06VQ8//LBWr16t3r17a8yYMcrKyjri+s8++0z33XefHn74YW3ZskXvvvuuvvjiC91///1NHDkAAEDTs9rsslcX33oZW/RtINAgZpNRYf7Vw0VL6IsOAACA+mnRT0/PP/+8brjhBk2ePFndunXTG2+8IX9/f7333ntHXL948WINHTpUV155pRITE3XWWWdpwoQJx6xeBwAAcAc1Q0UlKtHhuSLpiw4AAIDj1GKT6JWVlVq1apVGjRrl3Gc0GjVq1CgtWbLkiMeceuqpWrVqlTNpvnv3bs2ePVvnnHNOndepqKhQUVFRrQ0AAKAlshzSA5rBovBUNX3RqUQHAABAfZldHUBD5eTkyGq1KiYmptb+mJgYbd269YjHXHnllcrJydGwYcNkt9tlsVh00003HbWdy4wZM/TII480auwAAACuYDm0Ep3BovBQEVSiAwAA4Dh5VAnSggUL9MQTT+i1117T6tWr9e2332rWrFl67LHH6jxm2rRpKiwsdG579+5twogBAAAaT5X1YCW6iSQ6PFRkoKMSPbeUSnQAAADUT4utRI+MjJTJZFJmZmat/ZmZmYqNjT3iMQ8++KCuueYaXX/99ZKknj17qrS0VDfeeKMeeOABGY8wYMvHx0c+Pj6N/wEAAACamMXmqET3MhlkMJBEh2eKCKASHQAAAMenxVaie3t7q3///po/f75zn81m0/z58zVkyJAjHlNWVnZYotxkMkmS7Hb7kQ4BAABwG5bqSnTzEQoHAE8REUhPdAAAAByfFv0ENXXqVL399tv68MMPtWXLFt18880qLS3V5MmTJUkTJ07UtGnTnOvHjRun119/XZ9//rn27NmjX3/9VQ8++KDGjRvnTKYDAAC4q5rBovRDx/HYv3+/rr76akVERMjPz089e/bUypUrXR1Wg0VW90TPoRIdAAAA9dRi27lI0uWXX67s7Gw99NBDysjIUJ8+fTRnzhznsNHU1NRalef/93//J4PBoP/7v//T/v37FRUVpXHjxunxxx931UcAAABoMjWDRc0mkuion/z8fA0dOlQjRozQzz//rKioKO3YsUNhYWGuDq3BooIclegpuaWyWG0ym1p0XREAAACagMFOH5PjUlRUpJCQEBUWFio4ONjV4QAAANTb5rQinfPSn4oK8tGKB0a5OhycBI19r3rfffdp0aJF+vPPP5tNTCeqymrT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UqJdu3ad0FAmd2IwGHTPmC66Z0xnSdKL83foidlbZLfba62z2+1auD1b5738l65+d5muenuZbDb7kU4JAACAZogkOgAAgAewVifszLRzwXG4++67tXDhQiUnJ2vx4sW66KKLZDKZNGHCBFeH1qzcOqKDHh7XTZL09p979H/fb3QmydfvK9BV7yzTte8t1+Z0x5DVjKJybc+qu688AACAqyQmJuqFF16o9/oFCxbIYDCooKDgpMXUHNDOBQAAwANUOZPo1FCg/vbt26cJEyYoNzdXUVFRGjZsmJYuXaqoqChXh9bsTB6apABvs+79dr0+XZaqonKLbHa7Zq1PlyR5m4yaOKSt1u4t0MqUfC3bnacuscEujhoAALiD4cOHq0+fPseV/K7LihUrFBAQUO/1p556qtLT0xUSEnLC127OSKIDAAB4gJp2Ll60c8Fx+Pzzz10dQosyfmCCfL1NuuuLtfpxXZokyWCQLurbSlNHd1LrMH+98tsOrUzJ1/I9ebr21ETXBgwAADyC3W6X1WqV2XzsVPDxFkt4e3srNja2oaG1GJQiAQAAeICmGixqtVpVXl7OdpI2q9V6Uv/+cOLO7x2vN67ur4gAb43oHKXZt5+m58f3Ueswf0nSoKQISdKyPXmH9U4HAADNi91uV1mlxSVbfe8TJk2apIULF+rFF1+UwWCQwWDQBx98IIPBoJ9//ln9+/eXj4+P/vrrL+3atUsXXHCBYmJiFBgYqIEDB2revHm1zvf3di4Gg0HvvPOOLrroIvn7+6tjx46aOXOm8/2/t3P54IMPFBoaqrlz56pr164KDAzU2WefrfT0dOcxFotFt99+u0JDQxUREaF7771X1157rS688MIG/12dbFSiAwAAeACLrXqw6EnqiW6325WRkeH2vRCbg9DQUMXGxspg4LcKmqvR3WI0utvoI77Xq3WIvM1G5ZRUaE9OqdpFBTZxdAAAoL4OVFnV7aG5Lrn25kfHyN/72KnbF198Udu3b1ePHj306KOPSpI2bdokSbrvvvv07LPPql27dgoLC9PevXt1zjnn6PHHH5ePj48++ugjjRs3Ttu2bVObNm3qvMYjjzyip59+Ws8884xefvllXXXVVUpJSVF4ePgR15eVlenZZ5/Vxx9/LKPRqKuvvlp33323Pv30U0nSU089pU8//VTvv/++unbtqhdffFHff/+9RowYcbxfU5MhiQ4AAOABLNWV6F4nqRK9JoEeHR0tf39/Erwngd1uV1lZmbKysiRJcXFxLo4IDeHrZVKfhFAt35On5XvySKIDAIATEhISIm9vb/n7+zvbqmzdulWS9Oijj2r06IM/2A8PD1fv3r2drx977DF99913mjlzpqZMmVLnNSZNmuQcLP/EE0/opZde0vLly3X22WcfcX1VVZXeeOMNtW/fXpI0ZcoUZ4Jfkl5++WVNmzZNF110kSTplVde0ezZsxvy8ZsMSXQAAAAPUFXdE918EnqiW61WZwI9IiKi0c+Pg/z8/CRJWVlZio6OlslkcnFEaIjBSeHOJPoVg+qu+gIAAK7l52XS5kfHuOzaJ2rAgAG1XpeUlGj69OmaNWuW0tPTZbFYdODAAaWmph71PL169XL+OSAgQMHBwc7CjiPx9/d3JtAlR/FHzfrCwkJlZmZq0KBBzvdNJpP69+8vW/VvzzZHJNEBAAA8gMVW3RPd2PiV6FVVVZIcN8s4+Wq+56qqKpLoLdSgJMevPi/bk+fiSAAAwNEYDIZ6tVRprgICAmq9vvvuu/Xrr7/q2WefVYcOHeTn56dLL71UlZWVRz2Pl5dXrdcGg+GoCe8jrW/ps2AYLAoAAOABLNaT2xNdEi1cmgjfc8vXv22YzEaD9hcc0L78MleHAwAAWjhvb+96DaBftGiRJk2apIsuukg9e/ZUbGyskpOTT36AhwgJCVFMTIxWrFjh3Ge1WrV69eomjeN4kUQHAADwAM5K9JPQzgXA8fH3NqtHqxBJ0nKq0QEAwAlKTEzUsmXLlJycrJycnDqrxDt27Khvv/1Wa9eu1bp163TllVe6pIXKbbfdphkzZuiHH37Qtm3bdMcddyg/P79ZF4uQRAcAAPAAJ3uwKBpmwYIFMhgMKigocHUoaGKDq1u6kEQHAAAn6u6775bJZFK3bt0UFRVVZ4/z559/XmFhYTr11FM1btw4jRkzRv369WviaKV7771XEyZM0MSJEzVkyBAFBgZqzJgx8vX1bfJY6qvlNvUBAABAvVXZTn47FwD1NygpXG/+sZskOgAAOGGdOnXSkiVLau2bNGnSYesSExP122+/1dp366231nr99/YuR+plfmgByPDhw2utmTRp0mHXvvDCC2utMZvNevnll/Xyyy9Lkmw2m7p27arx48cfdq3mgiQ6AACAB6ipRDdTiQ40CwPahstgkHbnlCqruFzRQc238goAAKAxpaSk6JdfftEZZ5yhiooKvfLKK9qzZ4+uvPJKV4dWJ56iAAAAPEDNYFGvJuqJbrfbVVZpafLtSJUyR2Oz2TRjxgwlJSXJz89PvXv31tdffy3pYKuVWbNmqVevXvL19dUpp5yijRs31jrHN998o+7du8vHx0eJiYl67rnnar1fUVGhe++9VwkJCfLx8VGHDh307rvv1lqzatUqDRgwQP7+/jr11FO1bdu2BnzraElC/L3UJTZYkrRiT76LowEAAGg6RqNRH3zwgQYOHKihQ4dqw4YNmjdvnrp27erq0OpEJToAAIAHqKoZLGpsmhqKA1VWdXtobpNc61CbHx0jf+/63+LOmDFDn3zyid544w117NhRf/zxh66++mpFRUU519xzzz168cUXFRsbq/vvv1/jxo3T9u3b5eXlpVWrVmn8+PGaPn26Lr/8ci1evFi33HKLIiIinL/GOnHiRC1ZskQvvfSSevfurT179ignJ6dWHA888ICee+45RUVF6aabbtJ1112nRYsWNcp3guZrcFK4tqQXafmeXJ3bK87V4QAAADSJhISEFnevSxIdAADAAzR1JXpLUFFRoSeeeELz5s3TkCFDJEnt2rXTX3/9pTfffFM33nijJOnhhx/W6NGjJUkffvihWrdure+++07jx4/X888/r5EjR+rBBx+U5OhHuXnzZj3zzDOaNGmStm/fri+//FK//vqrRo0a5bzG3z3++OM644wzJEn33Xefzj33XJWXlzfr4Uo4cYOTwvXB4mQtoy86AABAs0YSHQAAwAM0dU90Py+TNj86pkmu9ffr1tfOnTtVVlbmTJDXqKysVN++fZ2vaxLskhQeHq7OnTtry5YtkqQtW7boggsuqHX80KFD9cILL8hqtWrt2rUymUzOBHldevXq5fxzXJyjIjkrK0tt2rSp9+dByzMwKVyStC2zWAVllQr193ZxRAAAADgSkugAAAAeoMrmqEQ3G5umEt1gMBxXWxVXKCkpkSTNmjVLrVq1qvWej4+Pdu3adcLX8PPzq9c6Ly8v558NBsffka367wzuKzLQR+2jArQru1QrkvM1uluMq0MCAADAETBYFAAAwANYa3qi087FqVu3bvLx8VFqaqo6dOhQa0tISHCuW7p0qfPP+fn52r59u3PoUdeuXQ/r57ho0SJ16tRJJpNJPXv2lM1m08KFC5vmQ6HFGZQUIUlavifXxZEAAACgLs27PAgAAAAnzG63q8ratINFW4KgoCDdfffduuuuu2Sz2TRs2DAVFhZq0aJFCg4OVtu2bSVJjz76qCIiIhQTE6MHHnhAkZGRuvDCCyVJ//rXvzRw4EA99thjuvzyy7VkyRK98soreu211yRJiYmJuvbaa3Xdddc5B4umpKQoKytL48ePd9VHRzMyOClc/1uequX0RQcAAGi2SKIDAAC4uZoqdInBon/32GOPKSoqSjNmzNDu3bsVGhqqfv366f7773e2U3nyySd1xx13aMeOHerTp49+/PFHeXs7elf369dPX375pR566CE99thjiouL06OPPqpJkyY5r/H666/r/vvv1y233KLc3Fy1adNG999/vys+LpqhQdV90TemFamkwqJAHx7RAAAAmhtKkQAAANyc5ZAkelMNFm0pDAaD7rjjDm3dulWVlZXKysrSnDlzdPrppzvXDBs2TBs3blRFRYWWLVtWawioJF1yySXatGmTKisrlZKSorvvvrvW+76+vnr++eeVlpamiooK7dixQ5MnT5YkDR8+XHa7XaGhoc71ffr0kd1uV2Ji4kn73Gg+4kP91DrMT1abXatT8l0dDgAA8ECJiYl64YUXnK8NBoO+//77OtcnJyfLYDBo7dq1J3TdxjpPU+ApCgAAwM1VWQ8OqGyqwaIA6m+wsy86LV0AAIDrpaena+zYsY16zkmTJjlbItZISEhQenq6evTo0ajXOhlIogMAALg5i/XQdi7c/gHNzeDqli4k0QEAQHMQGxsrHx+fk34dk8mk2NhYmc3Nv50dT1EAAABurqq6t7fBIJmoRK+3I7VaAU6Gmr7oa/cWqLzK6uJoAACAk90uVZa6ZrPbjx2fpLfeekvx8fHOeT41LrjgAl133XXatWuXLrjgAsXExCgwMFADBw7UvHnzjnrOv7dzWb58ufr27StfX18NGDBAa9asqbXearXqH//4h5KSkuTn56fOnTvrxRdfdL4/ffp0ffjhh/rhhx9kMBhkMBi0YMGCI7ZzWbhwoQYNGiQfHx/FxcXpvvvuk8Vicb4/fPhw3X777fr3v/+t8PBwxcbGavr06fX6rk5E80/zAwAA4ITUVKJ7GamfAJqjthH+igvxVXphuRbtzNHIrjGuDgkAAEhS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S0vz1PTt29cToJ9/nz179ujUqVOeY2fOnFHz5s0VGRmpm2++WRkZGT95zWfPnlVeXp7Xo6pjJzoAAPihDk2DteTeGL00rJPCgvz1TXah7n07XXf9baP2HjttdXsAAAAAUKVVKEQ/ceKEysrKFBoa6nU8NDRULpfrgs9xuVw/WX/+z5+radKkidd5h8OhBg0aeNVc6DV++B6tW7fW3//+d3300Ud6++235Xa71bNnTx0+fLjca37mmWcUHBzseURGRpZbWxUUFJdq34l8SVI7QnQAAHCOzWbTzZ0uU/Lkfppw7ZXyc9i19qsTGvTS55q5LEO5BSVWtwgAAAAAVdKvurFodRUTE6ORI0eqU6dO6tevnz744AM1btxYr732WrnPmTZtmnJzcz2Pb775phI7rrjdrtMyRmoc6FSTwJp301QAAPC/qed0aEpca332UD/FtQtVmdto4foDunZOit5JO6Qyd4Um/QEAAABAjVehEL1Ro0by8fHRsWPHvI4fO3ZMYWFhF3xOWFjYT9af//Pnav77xqWlpaXKzs72qrnQa/zwPf6br6+vOnfurK+++urCFyzJ6XQqKCjI61GVZRz9btxMVHjV7hMAAFirWcO6eu2ubnp7dLRaNQlQdn6xHv1wh377ylptOpBtdXsAAAAAUGVUKET38/NT165dlZyc7DnmdruVnJysmJiYCz4nJibGq16SkpKSPPUtW7ZUWFiYV01eXp7S0tI8NTExMcrJyVF6erqnZuXKlXK73YqOjvbUrFmzRiUlJV7v07p1a9WvX/+CvZWVlWnHjh0KDw+vyLehSss8Nw+dUS4AAOCX6N2qkVZM7KMZv4lSkL9DGUfzdNuCVD347lZl5RZa3R4AAAAAWK7C41wSEhL0xhtv6K233tKuXbt03333KT8/X3fffbckaeTIkZo2bZqnfuLEiUpMTNScOXO0e/duzZw5U5s3b9aECRMkfTefc9KkSXr66ae1bNky7dixQyNHjlRERITi4+MlSW3bttWgQYM0duxYbdy4UevWrdOECRM0bNgwRURESJLuuOMO+fn5afTo0crIyNDixYv10ksvKSEhwdPLU089pU8//VT79u3Tli1bdOedd+rgwYMaM2bMr/4GVjWZ53ait4sItrgTAABQXfj62HV3r5ZaNaW/hl/TTDabtGzbUV03e7VeTt6ropIyq1sEAAAA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\n"},"metadata":{}},{"name":"stdout","text":"epoch\n\tepoch \t (min: 0.000, max: 1.000, cur: 1.000)\nLoss\n\ttraining \t (min: 2.352, max: 7.058, cur: 2.462)\n\tvalidation \t (min: 2.624, max: 4.044, cur: 2.624)\nlr\n\tlr \t (min: 0.000, max: 0.000, cur: 0.000)\n","output_type":"stream"}],"execution_count":49},{"cell_type":"code","source":"# Смотрим на качество генерации глазами\n# Для маленьких и слабых моделей \"затягиваем\" гайки генерации\n\ntext = \"Заходит в бар\"\ninput_ids = torch.tensor(tokenizer.encode(text)[:-1], device=trainer.device)[None, :]\nprint(input_ids)\nmodel_output = model.generate(\n input_ids, max_new_tokens=200, eos_token_id=tokenizer.eos_token_id, do_sample=True, top_k=10\n)\ntokenizer.decode(model_output[0].tolist())","metadata":{"id":"94zNDLEqdQow","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T20:47:56.568838Z","iopub.execute_input":"2025-10-27T20:47:56.569424Z","iopub.status.idle":"2025-10-27T20:47:57.877185Z","shell.execute_reply.started":"2025-10-27T20:47:56.569401Z","shell.execute_reply":"2025-10-27T20:47:57.876656Z"}},"outputs":[{"name":"stdout","text":"tensor([[717, 258, 618, 275, 302, 338]], device='cuda:0')\n","output_type":"stream"},{"execution_count":68,"output_type":"execute_result","data":{"text/plain":"'Заходит в бар с алкоголем, весь в баре.\\n - Давай. Я хочу спать с тобой, - говорит он, - а я - пиво.\\n - Пойди, - говорит дружок, - я вчера сегодня по пьяни не пил, а сейчас -\\n а я в штопор схожу.\\n '"},"metadata":{}}],"execution_count":68},{"cell_type":"markdown","source":"Поиграйтесь с гиперпараметрами, попробуйте обучить `mini` и `small` версии.\nПостарайтесь добиться как можно более высокого качества как в терминах лосса, так и при визуальной оценке генерации.\n\n### Дополнительные баллы\n\nВы также можно заработать дополнительные баллы:\n- Реализовать Rotary Positional Embedding **[2 балла]**\n- Реализовать Multi-Head Latent Attention **[1 балл]**\n- Оформить репозиторий на 🤗: карточка модели с описанием задания, репортом качества и примерами генерации **[1 балл]**","metadata":{"id":"0WrMwV9zK993"}},{"cell_type":"code","source":"# Загружаем модель на хаб\n\nmodel.push_to_hub(REPO_NAME)","metadata":{"id":"YFi7M9ExHWv9","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T20:36:38.794788Z","iopub.execute_input":"2025-10-27T20:36:38.795474Z","iopub.status.idle":"2025-10-27T20:36:59.712695Z","shell.execute_reply.started":"2025-10-27T20:36:38.795449Z","shell.execute_reply":"2025-10-27T20:36:59.712182Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"Processing Files (0 / 0): | | 0.00B / 0.00B ","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"7e35e0545821430893e8996cfc34a317"}},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"New Data Upload: | | 0.00B / 0.00B ","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"80513ed0a1414907a8de92716c8e4edc"}},"metadata":{}},{"execution_count":53,"output_type":"execute_result","data":{"text/plain":"CommitInfo(commit_url='https://huggingface.co/Amir337/llm-course-hw1/commit/0c73c6964bba59ea2cf758799211e7bd9304e0ec', commit_message='Push model using huggingface_hub.', commit_description='', oid='0c73c6964bba59ea2cf758799211e7bd9304e0ec', pr_url=None, repo_url=RepoUrl('https://huggingface.co/Amir337/llm-course-hw1', endpoint='https://huggingface.co', repo_type='model', repo_id='Amir337/llm-course-hw1'), pr_revision=None, pr_num=None)"},"metadata":{}}],"execution_count":53},{"cell_type":"markdown","source":"Сделал все бонусы.\nРепа: https://huggingface.co/Amir337/llm-course-hw1","metadata":{}},{"cell_type":"markdown","source":"# Специальный раздел для проверяющего","metadata":{"id":"so8bIDy5dKXM"}},{"cell_type":"code","source":"device = torch.device(\"cuda\")\n\ncfg = TransformerConfig(n_layer=12, n_head=12, n_kv_head=6, hidden_dim=768, intermediate_dim=2048,use_rope=True, rope_theta=10000.0)\ntokenizer = ByteLevelBPETokenizer.from_pretrained(REPO_NAME)\ncheck_model = TransformerForCausalLM.from_pretrained(REPO_NAME, config=cfg)\ncheck_model = check_model.to(device)\ncheck_model = check_model.eval()","metadata":{"id":"0ZplshN5HtRb","trusted":true,"execution":{"iopub.status.busy":"2025-10-27T20:55:03.203814Z","iopub.execute_input":"2025-10-27T20:55:03.204602Z","iopub.status.idle":"2025-10-27T20:55:04.718824Z","shell.execute_reply.started":"2025-10-27T20:55:03.204574Z","shell.execute_reply":"2025-10-27T20:55:04.718267Z"}},"outputs":[{"output_type":"display_data","data":{"text/plain":"Fetching 6 files: 0%| | 0/6 [00:00