{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "b518b04cbfe0" }, "source": [ "##### Copyright 2020 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T22:30:32.590143Z", "iopub.status.busy": "2022-12-14T22:30:32.589564Z", "iopub.status.idle": "2022-12-14T22:30:32.593626Z", "shell.execute_reply": "2022-12-14T22:30:32.593055Z" }, "id": "906e07f6e562" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "8bd329a4bbca" }, "source": [ "# Keras로 마스킹 및 패딩하기" ] }, { "cell_type": "markdown", "metadata": { "id": "8b208d0913b8" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
TensorFlow.org에서 보기\n", " Google Colab에서 실행하기\n", "GitHub에서소스 보기노트북 다운로드하기
" ] }, { "cell_type": "markdown", "metadata": { "id": "8d4ac441b1fc" }, "source": [ "## 설치하기" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:32.597401Z", "iopub.status.busy": "2022-12-14T22:30:32.596894Z", "iopub.status.idle": "2022-12-14T22:30:34.560079Z", "shell.execute_reply": "2022-12-14T22:30:34.559257Z" }, "id": "ec52be14e686" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:30:33.575697: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:30:33.575792: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:30:33.575802: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] } ], "source": [ "import numpy as np\n", "import tensorflow as tf\n", "from tensorflow import keras\n", "from tensorflow.keras import layers" ] }, { "cell_type": "markdown", "metadata": { "id": "e94d7a46bda8" }, "source": [ "## 소개\n", "\n", "**마스킹** 은 시퀀스 처리 레이어에 입력의 특정 시간 단계가 누락되어 데이터를 처리 할 때 건너 뛰도록 지시하는 방법입니다.\n", "\n", "**패딩**은 마스킹된 스텝이 시퀀스의 시작 또는 끝에 위치하는 특수한 형태의 마스킹입니다. 패딩이 필요한 이유는 시퀀스 데이터를 연속 배치로 인코딩해야 하는 데 있습니다. 배치의 모든 시퀀스를 지정된 표준 길이에 맞추려면 일부 시퀀스를 패딩 처리하거나 잘라내야 합니다.\n", "\n", "자세히 살펴보겠습니다." ] }, { "cell_type": "markdown", "metadata": { "id": "ac6b121d6be0" }, "source": [ "## 패딩 시퀀스 데이터\n", "\n", "시퀀스 데이터를 처리 할 때 개별 샘플의 길이가 다른 것이 매우 일반적입니다. 다음 예제를 고려하십시오 (텍스트로 단어로 토큰 화됨).\n", "\n", "```\n", "[\n", " [\"Hello\", \"world\", \"!\"],\n", " [\"How\", \"are\", \"you\", \"doing\", \"today\"],\n", " [\"The\", \"weather\", \"will\", \"be\", \"nice\", \"tomorrow\"],\n", "]\n", "```\n", "\n", "어휘 조회 후 데이터는 다음과 같이 정수로 벡터화 될 수 있습니다.\n", "\n", "```\n", "[\n", " [71, 1331, 4231]\n", " [73, 8, 3215, 55, 927],\n", " [83, 91, 1, 645, 1253, 927],\n", "]\n", "```\n", "\n", "데이터는 개별 샘플의 길이가 각각 3, 5 및 6인 중첩된 목록입니다. 딥 러닝 모델의 입력 데이터는 단일 텐서(이 경우, 예를 들어 `(batch_size, 6, vocab_size)` 형상의 텐서)여야 하므로 가장 긴 항목보다 짧은 샘플은 일부 자리 표시자 값으로 패딩 처리해야 합니다(또는, 짧은 샘플을 패딩 처리하기 전에 긴 샘플을 잘라낼 수도 있음).\n", "\n", "Keras는 Python 목록을 잘라서 공통 길이로 패딩 처리하는 유틸리티 기능을 제공합니다: `tf.keras.preprocessing.sequence.pad_sequences`." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:34.564256Z", "iopub.status.busy": "2022-12-14T22:30:34.563823Z", "iopub.status.idle": "2022-12-14T22:30:34.569402Z", "shell.execute_reply": "2022-12-14T22:30:34.568810Z" }, "id": "bb64fb185a05" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 711 632 71 0 0 0]\n", " [ 73 8 3215 55 927 0]\n", " [ 83 91 1 645 1253 927]]\n" ] } ], "source": [ "raw_inputs = [\n", " [711, 632, 71],\n", " [73, 8, 3215, 55, 927],\n", " [83, 91, 1, 645, 1253, 927],\n", "]\n", "\n", "# By default, this will pad using 0s; it is configurable via the\n", "# \"value\" parameter.\n", "# Note that you could \"pre\" padding (at the beginning) or\n", "# \"post\" padding (at the end).\n", "# We recommend using \"post\" padding when working with RNN layers\n", "# (in order to be able to use the\n", "# CuDNN implementation of the layers).\n", "padded_inputs = tf.keras.preprocessing.sequence.pad_sequences(\n", " raw_inputs, padding=\"post\"\n", ")\n", "print(padded_inputs)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "03092b2da690" }, "source": [ "## 마스킹\n", "\n", "이제 모든 샘플의 길이가 균일하므로 데이터의 일부가 실제로 채워져 있다는 사실을 모델에 알려야합니다. 그 메커니즘은 **마스킹** 입니다.\n", "\n", "Keras 모델에서 입력 마스크를 도입하는 세 가지 방법이 있습니다.\n", "\n", "- `keras.layers.Masking` 레이어를 추가하십시오.\n", "- `mask_zero=True` 로 `keras.layers.Embedding` 레이어를 구성하십시오.\n", "- 이 인수를 지원하는 계층 (예 : RNN 계층)을 호출 할 때 `mask` 인수를 수동으로 전달하십시오." ] }, { "cell_type": "markdown", "metadata": { "id": "6103601e5fff" }, "source": [ "## 마스크 생성 레이어 : `Embedding` 및 `Masking`\n", "\n", "후드 아래에서이 레이어는 마스크 텐서 (모양 `(batch, sequence_length)` 가진 2D 텐서)를 만들어 `Masking` 또는 `Embedding` 레이어에서 반환 한 텐서 출력에 연결합니다." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:34.572796Z", "iopub.status.busy": "2022-12-14T22:30:34.572272Z", "iopub.status.idle": "2022-12-14T22:30:38.055769Z", "shell.execute_reply": "2022-12-14T22:30:38.055105Z" }, "id": "b2363b293483" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ True True True False False False]\n", " [ True True True True True False]\n", " [ True True True True True True]], shape=(3, 6), dtype=bool)\n", "tf.Tensor(\n", "[[ True True True False False False]\n", " [ True True True True True False]\n", " [ True True True True True True]], shape=(3, 6), dtype=bool)\n" ] } ], "source": [ "embedding = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)\n", "masked_output = embedding(padded_inputs)\n", "\n", "print(masked_output._keras_mask)\n", "\n", "masking_layer = layers.Masking()\n", "# Simulate the embedding lookup by expanding the 2D input to 3D,\n", "# with embedding dimension of 10.\n", "unmasked_embedding = tf.cast(\n", " tf.tile(tf.expand_dims(padded_inputs, axis=-1), [1, 1, 10]), tf.float32\n", ")\n", "\n", "masked_embedding = masking_layer(unmasked_embedding)\n", "print(masked_embedding._keras_mask)" ] }, { "cell_type": "markdown", "metadata": { "id": "17e4bdb563b2" }, "source": [ "인쇄 된 결과에서 볼 수 있듯이 마스크는 모양이 `(batch_size, sequence_length)` 인 2D 부울 텐서이며, 각 개별 `False` 항목은 처리 중에 해당 시간 단계를 무시해야 함을 나타냅니다." ] }, { "cell_type": "markdown", "metadata": { "id": "cf11a0399fcf" }, "source": [ "## 함수형 API 및 순차형 API의 마스크 전파\n", "\n", "함수형 API 또는 순차형 API를 사용하는 경우 `Embedding` 또는 `Masking` 레이어에서 생성된 마스크는 이를 사용할 수 있는 모든 레이어(예: RNN 레이어)를 대상으로 네트워크를 통해 전파됩니다. Keras는 입력에 해당하는 마스크를 자동으로 가져와서 그 사용 방법을 알고 있는 모든 레이어로 전달합니다.\n", "\n", "For instance, in the following Sequential model, the `LSTM` layer will automatically receive a mask, which means it will ignore padded values:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:38.059691Z", "iopub.status.busy": "2022-12-14T22:30:38.059260Z", "iopub.status.idle": "2022-12-14T22:30:38.966862Z", "shell.execute_reply": "2022-12-14T22:30:38.966117Z" }, "id": "0adbecda288a" }, "outputs": [], "source": [ "model = keras.Sequential(\n", " [layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True), layers.LSTM(32),]\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "a8ac6481a1d5" }, "source": [ "다음과 같은 함수형 API 모델의 경우에도 마찬가지입니다." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:38.971419Z", "iopub.status.busy": "2022-12-14T22:30:38.970758Z", "iopub.status.idle": "2022-12-14T22:30:39.730323Z", "shell.execute_reply": "2022-12-14T22:30:39.729604Z" }, "id": "f374ab06743d" }, "outputs": [], "source": [ "inputs = keras.Input(shape=(None,), dtype=\"int32\")\n", "x = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)(inputs)\n", "outputs = layers.LSTM(32)(x)\n", "\n", "model = keras.Model(inputs, outputs)" ] }, { "cell_type": "markdown", "metadata": { "id": "2f2c4b96ecb5" }, "source": [ "## 마스크 텐서를 레이어로 직접 전달" ] }, { "cell_type": "markdown", "metadata": { "id": "11dccb581014" }, "source": [ "마스크를 처리 할 수있는 레이어 (예 : `LSTM` 레이어)는 `__call__` 메서드에 `mask` 인수가 있습니다.\n", "\n", "한편 마스크 (예 : `Embedding` )를 생성하는 레이어는 호출 할 수있는 `compute_mask(input, previous_mask)` 메소드를 노출합니다.\n", "\n", "따라서 마스크 생성 레이어의 `compute_mask()` 메서드 출력을 다음과 같이 마스크 소비 레이어의 `__call__` 메서드로 전달할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:39.734966Z", "iopub.status.busy": "2022-12-14T22:30:39.734294Z", "iopub.status.idle": "2022-12-14T22:30:40.169086Z", "shell.execute_reply": "2022-12-14T22:30:40.168405Z" }, "id": "1955aa63896b" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class MyLayer(layers.Layer):\n", " def __init__(self, **kwargs):\n", " super(MyLayer, self).__init__(**kwargs)\n", " self.embedding = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)\n", " self.lstm = layers.LSTM(32)\n", "\n", " def call(self, inputs):\n", " x = self.embedding(inputs)\n", " # Note that you could also prepare a `mask` tensor manually.\n", " # It only needs to be a boolean tensor\n", " # with the right shape, i.e. (batch_size, timesteps).\n", " mask = self.embedding.compute_mask(inputs)\n", " output = self.lstm(x, mask=mask) # The layer will ignore the masked values\n", " return output\n", "\n", "\n", "layer = MyLayer()\n", "x = np.random.random((32, 10)) * 100\n", "x = x.astype(\"int32\")\n", "layer(x)" ] }, { "cell_type": "markdown", "metadata": { "id": "b04dd330f848" }, "source": [ "## 사용자 정의 레이어에서 마스킹 지원" ] }, { "cell_type": "markdown", "metadata": { "id": "8451a1a8ff27" }, "source": [ "Sometimes, you may need to write layers that generate a mask (like `Embedding`), or layers that need to modify the current mask.\n", "\n", "For instance, any layer that produces a tensor with a different time dimension than its input, such as a `Concatenate` layer that concatenates on the time dimension, will need to modify the current mask so that downstream layers will be able to properly take masked timesteps into account.\n", "\n", "이렇게 하려면 입력과 현재 마스크가 지정되었을 때 새 마스크를 생성하는 `layer.compute_mask()` 메서드를 레이어에서 구현해야 합니다.\n", "\n", "다음은 현재 마스크를 수정해야하는 `TemporalSplit` 레이어의 예제입니다." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:40.173111Z", "iopub.status.busy": "2022-12-14T22:30:40.172563Z", "iopub.status.idle": "2022-12-14T22:30:40.181065Z", "shell.execute_reply": "2022-12-14T22:30:40.180418Z" }, "id": "a06fb2194c0d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ True True True]\n", " [ True True True]\n", " [ True True True]], shape=(3, 3), dtype=bool)\n", "tf.Tensor(\n", "[[False False False]\n", " [ True True False]\n", " [ True True True]], shape=(3, 3), dtype=bool)\n" ] } ], "source": [ "class TemporalSplit(keras.layers.Layer):\n", " \"\"\"Split the input tensor into 2 tensors along the time dimension.\"\"\"\n", "\n", " def call(self, inputs):\n", " # Expect the input to be 3D and mask to be 2D, split the input tensor into 2\n", " # subtensors along the time axis (axis 1).\n", " return tf.split(inputs, 2, axis=1)\n", "\n", " def compute_mask(self, inputs, mask=None):\n", " # Also split the mask into 2 if it presents.\n", " if mask is None:\n", " return None\n", " return tf.split(mask, 2, axis=1)\n", "\n", "\n", "first_half, second_half = TemporalSplit()(masked_embedding)\n", "print(first_half._keras_mask)\n", "print(second_half._keras_mask)" ] }, { "cell_type": "markdown", "metadata": { "id": "282b867dcd95" }, "source": [ "입력 값에서 마스크를 생성 할 수있는 `CustomEmbedding` 레이어의 다른 예는 다음과 같습니다." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:40.184432Z", "iopub.status.busy": "2022-12-14T22:30:40.183939Z", "iopub.status.idle": "2022-12-14T22:30:40.198115Z", "shell.execute_reply": "2022-12-14T22:30:40.197433Z" }, "id": "e760655cd39c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ True True True True True True True True False True]\n", " [ True True True True True True True True False True]\n", " [ True True True True True True True True True True]], shape=(3, 10), dtype=bool)\n" ] } ], "source": [ "class CustomEmbedding(keras.layers.Layer):\n", " def __init__(self, input_dim, output_dim, mask_zero=False, **kwargs):\n", " super(CustomEmbedding, self).__init__(**kwargs)\n", " self.input_dim = input_dim\n", " self.output_dim = output_dim\n", " self.mask_zero = mask_zero\n", "\n", " def build(self, input_shape):\n", " self.embeddings = self.add_weight(\n", " shape=(self.input_dim, self.output_dim),\n", " initializer=\"random_normal\",\n", " dtype=\"float32\",\n", " )\n", "\n", " def call(self, inputs):\n", " return tf.nn.embedding_lookup(self.embeddings, inputs)\n", "\n", " def compute_mask(self, inputs, mask=None):\n", " if not self.mask_zero:\n", " return None\n", " return tf.not_equal(inputs, 0)\n", "\n", "\n", "layer = CustomEmbedding(10, 32, mask_zero=True)\n", "x = np.random.random((3, 10)) * 9\n", "x = x.astype(\"int32\")\n", "\n", "y = layer(x)\n", "mask = layer.compute_mask(x)\n", "\n", "print(mask)" ] }, { "cell_type": "markdown", "metadata": { "id": "bb34149eb837" }, "source": [ "## 호환 가능한 레이어에서 전파를 마스크하도록 선택\n", "\n", "대부분의 레이어는 시간 차원을 수정하지 않으므로 현재 마스크를 수정할 필요가 없습니다. 그러나 그들은 여전히 현재 마스크를 변경하지 않고 다음 레이어로 **전파** 할 수 있기를 원할 수 있습니다. **이것은 옵트 인 동작입니다.** 기본적으로 사용자 정의 레이어는 현재 마스크를 제거합니다 (프레임 워크에서 마스크 전파가 안전한지 여부를 알 수있는 방법이 없기 때문에).\n", "\n", "시간 차원을 수정하지 않는 사용자 정의 레이어가 있고 현재 입력 마스크를 전파 할 수 있으려면 레이어 생성자에서 `self.supports_masking = True` 를 설정해야합니다. 이 경우 `compute_mask()` 의 기본 동작은 현재 마스크를 통과하는 것입니다.\n", "\n", "마스크 전파가 허용 된 레이어의 예는 다음과 같습니다." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:40.201532Z", "iopub.status.busy": "2022-12-14T22:30:40.200931Z", "iopub.status.idle": "2022-12-14T22:30:40.204922Z", "shell.execute_reply": "2022-12-14T22:30:40.204222Z" }, "id": "895c35534d06" }, "outputs": [], "source": [ "class MyActivation(keras.layers.Layer):\n", " def __init__(self, **kwargs):\n", " super(MyActivation, self).__init__(**kwargs)\n", " # Signal that the layer is safe for mask propagation\n", " self.supports_masking = True\n", "\n", " def call(self, inputs):\n", " return tf.nn.relu(inputs)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "a2e1e0a81995" }, "source": [ "이제 마스크를 생성하는 레이어(예: `Embedding`)와 마스크를 소비하는 레이어(예: `LSTM`) 사이에서 이 사용자 정의 레이어를 사용하여 마스크 소비 레이어까지 마스크를 전달할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:40.208120Z", "iopub.status.busy": "2022-12-14T22:30:40.207499Z", "iopub.status.idle": "2022-12-14T22:30:40.999948Z", "shell.execute_reply": "2022-12-14T22:30:40.999122Z" }, "id": "486e39e9a9a7" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mask found: KerasTensor(type_spec=TensorSpec(shape=(None, None), dtype=tf.bool, name=None), name='Placeholder_1:0')\n" ] } ], "source": [ "inputs = keras.Input(shape=(None,), dtype=\"int32\")\n", "x = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)(inputs)\n", "x = MyActivation()(x) # Will pass the mask along\n", "print(\"Mask found:\", x._keras_mask)\n", "outputs = layers.LSTM(32)(x) # Will receive the mask\n", "\n", "model = keras.Model(inputs, outputs)" ] }, { "cell_type": "markdown", "metadata": { "id": "55ab9c02f4ba" }, "source": [ "## 마스크 정보가 필요한 레이어 작성\n", "\n", "일부 레이어는 마스크 *소비자*입니다. 이러한 레이어는 `call`에서 `mask` 인수를 허용하고 이를 사용하여 특정 타임스텝을 건너뛸지 여부를 결정합니다.\n", "\n", "이러한 계층을 작성하려면 `call` 서명에 `mask=None` 인수를 추가하면됩니다. 입력과 관련된 마스크는 가능할 때마다 레이어로 전달됩니다.\n", "\n", "다음은 간단한 예입니다. 마스크 된 시간 단계를 버리고 입력 시퀀스의 시간 차원 (축 1)에 대한 소프트 맥스를 계산하는 레이어입니다." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:41.004198Z", "iopub.status.busy": "2022-12-14T22:30:41.003677Z", "iopub.status.idle": "2022-12-14T22:30:41.096654Z", "shell.execute_reply": "2022-12-14T22:30:41.095999Z" }, "id": "9774bcd59908" }, "outputs": [], "source": [ "class TemporalSoftmax(keras.layers.Layer):\n", " def call(self, inputs, mask=None):\n", " broadcast_float_mask = tf.expand_dims(tf.cast(mask, \"float32\"), -1)\n", " inputs_exp = tf.exp(inputs) * broadcast_float_mask\n", " inputs_sum = tf.reduce_sum(\n", " inputs_exp * broadcast_float_mask, axis=-1, keepdims=True\n", " )\n", " return inputs_exp / inputs_sum\n", "\n", "\n", "inputs = keras.Input(shape=(None,), dtype=\"int32\")\n", "x = layers.Embedding(input_dim=10, output_dim=32, mask_zero=True)(inputs)\n", "x = layers.Dense(1)(x)\n", "outputs = TemporalSoftmax()(x)\n", "\n", "model = keras.Model(inputs, outputs)\n", "y = model(np.random.randint(0, 10, size=(32, 100)), np.random.random((32, 100, 1)))" ] }, { "cell_type": "markdown", "metadata": { "id": "6373f43bbe18" }, "source": [ "## 요약\n", "\n", "이것이 Keras의 패딩 및 마스킹에 대해 알아야 할 전부입니다. 요약하자면:\n", "\n", "- \"Masking\"은 레이어가 시퀀스 입력에서 특정 시간 단계를 건너 뛰거나 무시할 때를 알 수있는 방법입니다.\n", "- 일부 레이어는 마스크 생성기입니다. `Embedding` 하면 입력 값에서 마스크를 생성 할 수 있으며 ( `mask_zero=True` ) `Masking` 레이어도 생성 할 수 있습니다.\n", "- 일부 레이어는 마스크 소비자입니다. `__call__` 메서드에 `mask` 인수를 표시합니다. 이것은 RNN 계층의 경우입니다.\n", "- 함수형 API 및 Sequential API에서 마스크 정보는 자동으로 전파됩니다.\n", "- 독립형 방식으로 레이어를 사용하는 경우 `mask` 인수를 레이어에 수동으로 전달할 수 있습니다.\n", "- 현재 마스크를 수정하거나 새 마스크를 생성하거나 입력과 관련된 마스크를 사용하는 레이어를 쉽게 작성할 수 있습니다." ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "masking_and_padding.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "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.16" } }, "nbformat": 4, "nbformat_minor": 0 }