{ "cells": [ { "cell_type": "markdown", "id": "3540236c", "metadata": { "origin_pos": 0 }, "source": [ "# Thực hiện ngắn gọn các mạng nơ-ron tái phát\n", ":label:`sec_rnn-concise`\n", "\n", "Trong khi :numref:`sec_rnn_scratch` được hướng dẫn để xem RNN được thực hiện như thế nào, điều này không thuận tiện hay nhanh chóng. Phần này sẽ chỉ ra cách triển khai cùng một mô hình ngôn ngữ hiệu quả hơn bằng cách sử dụng các hàm được cung cấp bởi các API cấp cao của một khuôn khổ học sâu. Chúng tôi bắt đầu như trước bằng cách đọc tập dữ liệu máy thời gian.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "51394d6f", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:41.085346Z", "iopub.status.busy": "2022-04-26T12:38:41.084757Z", "iopub.status.idle": "2022-04-26T12:38:43.935547Z", "shell.execute_reply": "2022-04-26T12:38:43.934777Z" }, "origin_pos": 2, "tab": [ "pytorch" ] }, "outputs": [], "source": [ "import torch\n", "from torch import nn\n", "from torch.nn import functional as F\n", "from d2l import torch as d2l\n", "\n", "batch_size, num_steps = 32, 35\n", "train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)" ] }, { "cell_type": "markdown", "id": "9dc01dc2", "metadata": { "origin_pos": 4 }, "source": [ "## [**Định nghĩa mẫu**]\n", "\n", "API cấp cao cung cấp triển khai các mạng thần kinh định kỳ. Chúng tôi xây dựng lớp mạng thần kinh tái phát `rnn_layer` với một lớp ẩn duy nhất và 256 đơn vị ẩn. Trên thực tế, chúng tôi thậm chí còn chưa thảo luận về ý nghĩa của việc có nhiều lớp — điều này sẽ xảy ra trong :numref:`sec_deep_rnn`. Hiện tại, đủ để nói rằng nhiều lớp chỉ đơn giản là lên đến đầu ra của một lớp RNN được sử dụng làm đầu vào cho lớp tiếp theo của RNN.\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "537aaf19", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:43.940199Z", "iopub.status.busy": "2022-04-26T12:38:43.939459Z", "iopub.status.idle": "2022-04-26T12:38:43.944820Z", "shell.execute_reply": "2022-04-26T12:38:43.944106Z" }, "origin_pos": 6, "tab": [ "pytorch" ] }, "outputs": [], "source": [ "num_hiddens = 256\n", "rnn_layer = nn.RNN(len(vocab), num_hiddens)" ] }, { "cell_type": "markdown", "id": "8cec4b6c", "metadata": { "origin_pos": 9, "tab": [ "pytorch" ] }, "source": [ "Chúng tôi (** sử dụng một tensor để khởi tạo trạng thái ẩn**), có hình dạng là (số lớp ẩn, kích thước lô, số đơn vị ẩn).\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "a98c7574", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:43.947962Z", "iopub.status.busy": "2022-04-26T12:38:43.947507Z", "iopub.status.idle": "2022-04-26T12:38:43.954208Z", "shell.execute_reply": "2022-04-26T12:38:43.953517Z" }, "origin_pos": 11, "tab": [ "pytorch" ] }, "outputs": [ { "data": { "text/plain": [ "torch.Size([1, 32, 256])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "state = torch.zeros((1, batch_size, num_hiddens))\n", "state.shape" ] }, { "cell_type": "markdown", "id": "e6dc8270", "metadata": { "origin_pos": 13 }, "source": [ "[**Với trạng thái ẩn và đầu vào, chúng ta có thể tính toán đầu ra với trạng thái ẩn cập nhật.**] Cần nhấn mạnh rằng “đầu ra” (`Y`) của `rnn_layer` không * không* liên quan đến tính toán các lớp đầu ra: nó đề cập đến trạng thái ẩn ở bước thời gian * mỗi* và chúng có thể được sử dụng làm đầu vào cho lớp đầu ra tiếp theo.\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "2502b44c", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:43.957320Z", "iopub.status.busy": "2022-04-26T12:38:43.956870Z", "iopub.status.idle": "2022-04-26T12:38:43.969408Z", "shell.execute_reply": "2022-04-26T12:38:43.968761Z" }, "origin_pos": 16, "tab": [ "pytorch" ] }, "outputs": [ { "data": { "text/plain": [ "(torch.Size([35, 32, 256]), torch.Size([1, 32, 256]))" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X = torch.rand(size=(num_steps, batch_size, len(vocab)))\n", "Y, state_new = rnn_layer(X, state)\n", "Y.shape, state_new.shape" ] }, { "cell_type": "markdown", "id": "697e47e3", "metadata": { "origin_pos": 18 }, "source": [ "Tương tự như :numref:`sec_rnn_scratch`, [**chúng tôi định nghĩa một lớp `RNNModel` cho một mô hình RNN hoàn chỉnh**] Lưu ý rằng `rnn_layer` chỉ chứa các lớp tái phát ẩn, chúng ta cần tạo một lớp đầu ra riêng biệt.\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "b83445fb", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:43.972556Z", "iopub.status.busy": "2022-04-26T12:38:43.972095Z", "iopub.status.idle": "2022-04-26T12:38:43.980860Z", "shell.execute_reply": "2022-04-26T12:38:43.980204Z" }, "origin_pos": 20, "tab": [ "pytorch" ] }, "outputs": [], "source": [ "#@save\n", "class RNNModel(nn.Module):\n", " \"\"\"The RNN model.\"\"\"\n", " def __init__(self, rnn_layer, vocab_size, **kwargs):\n", " super(RNNModel, self).__init__(**kwargs)\n", " self.rnn = rnn_layer\n", " self.vocab_size = vocab_size\n", " self.num_hiddens = self.rnn.hidden_size\n", " # If the RNN is bidirectional (to be introduced later),\n", " # `num_directions` should be 2, else it should be 1.\n", " if not self.rnn.bidirectional:\n", " self.num_directions = 1\n", " self.linear = nn.Linear(self.num_hiddens, self.vocab_size)\n", " else:\n", " self.num_directions = 2\n", " self.linear = nn.Linear(self.num_hiddens * 2, self.vocab_size)\n", "\n", " def forward(self, inputs, state):\n", " X = F.one_hot(inputs.T.long(), self.vocab_size)\n", " X = X.to(torch.float32)\n", " Y, state = self.rnn(X, state)\n", " # The fully connected layer will first change the shape of `Y` to\n", " # (`num_steps` * `batch_size`, `num_hiddens`). Its output shape is\n", " # (`num_steps` * `batch_size`, `vocab_size`).\n", " output = self.linear(Y.reshape((-1, Y.shape[-1])))\n", " return output, state\n", "\n", " def begin_state(self, device, batch_size=1):\n", " if not isinstance(self.rnn, nn.LSTM):\n", " # `nn.GRU` takes a tensor as hidden state\n", " return torch.zeros((self.num_directions * self.rnn.num_layers,\n", " batch_size, self.num_hiddens),\n", " device=device)\n", " else:\n", " # `nn.LSTM` takes a tuple of hidden states\n", " return (torch.zeros((\n", " self.num_directions * self.rnn.num_layers,\n", " batch_size, self.num_hiddens), device=device),\n", " torch.zeros((\n", " self.num_directions * self.rnn.num_layers,\n", " batch_size, self.num_hiddens), device=device))" ] }, { "cell_type": "markdown", "id": "0efd9b04", "metadata": { "origin_pos": 22 }, "source": [ "## Đào tạo và dự đoán\n", "\n", "Trước khi đào tạo mô hình, chúng ta hãy [** đưa ra dự đoán với một mô hình có trọng lượng ngẫu nhiên.**]\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "0aa2f656", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:43.984090Z", "iopub.status.busy": "2022-04-26T12:38:43.983543Z", "iopub.status.idle": "2022-04-26T12:38:47.624949Z", "shell.execute_reply": "2022-04-26T12:38:47.624256Z" }, "origin_pos": 24, "tab": [ "pytorch" ] }, "outputs": [ { "data": { "text/plain": [ "'time travellerxxxxxxxxxx'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device = d2l.try_gpu()\n", "net = RNNModel(rnn_layer, vocab_size=len(vocab))\n", "net = net.to(device)\n", "d2l.predict_ch8('time traveller', 10, net, vocab, device)" ] }, { "cell_type": "markdown", "id": "f0e2ee29", "metadata": { "origin_pos": 26 }, "source": [ "Như là khá rõ ràng, mô hình này hoàn toàn không hoạt động. Tiếp theo, chúng tôi gọi `train_ch8` với các siêu tham số tương tự được xác định trong :numref:`sec_rnn_scratch` và [** đào tạo mô hình của chúng tôi với APIs** cấp cao**].\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "01298b34", "metadata": { "execution": { "iopub.execute_input": "2022-04-26T12:38:47.628195Z", "iopub.status.busy": "2022-04-26T12:38:47.627801Z", "iopub.status.idle": "2022-04-26T12:39:11.227532Z", "shell.execute_reply": "2022-04-26T12:39:11.226521Z" }, "origin_pos": 28, "tab": [ "pytorch" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "perplexity 1.3, 286577.9 tokens/sec on cuda:0\n", "time traveller proceeded anyong the eread must uply helo bree th\n", "travelleryou can show black is white by argumed thave back \n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2022-04-26T12:39:11.190804\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.5.1, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "num_epochs, lr = 500, 1\n", "d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, device)" ] }, { "cell_type": "markdown", "id": "71b36e1a", "metadata": { "origin_pos": 30 }, "source": [ "So với phần cuối, mô hình này đạt được sự bối rối tương đương, mặc dù trong một khoảng thời gian ngắn hơn, do mã được tối ưu hóa hơn bởi các API cấp cao của khung học sâu. \n", "\n", "## Tóm tắt\n", "\n", "* API cấp cao của khung học sâu cung cấp một triển khai của lớp RNN.\n", "* Lớp RNN của API cấp cao trả về một đầu ra và trạng thái ẩn cập nhật, trong đó đầu ra không liên quan đến tính toán lớp đầu ra.\n", "* Sử dụng API cấp cao dẫn đến đào tạo RNN nhanh hơn so với sử dụng triển khai từ đầu.\n", "\n", "## Bài tập\n", "\n", "1. Bạn có thể làm cho mô hình RNN overfit bằng cách sử dụng các API cấp cao không?\n", "1. Điều gì sẽ xảy ra nếu bạn tăng số lượng các lớp ẩn trong mô hình RNN? Bạn có thể làm cho mô hình hoạt động?\n", "1. Thực hiện mô hình autoregressive của :numref:`sec_sequence` bằng cách sử dụng một RNN.\n" ] }, { "cell_type": "markdown", "id": "72839ad5", "metadata": { "origin_pos": 32, "tab": [ "pytorch" ] }, "source": [ "[Discussions](https://discuss.d2l.ai/t/1053)\n" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }