![]() | ![]() | ![]() | ![]() |
برپایی
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
معرفی
پوشش راه به لایه های دنباله پردازش که timesteps خاص را به یک ورودی از دست رفته، و در نتیجه باید نادیده گرفته شود در هنگام پردازش اطلاعات است.
پارچه کشی، نوع خاصی از پوشش که در آن مراحل پوشانده در شروع یا پایان یک دنباله است. Padding از نیاز به رمزگذاری دادههای توالی به دستههای پیوسته ناشی میشود: برای اینکه همه دنبالهها در یک دسته متناسب با طول استاندارد معین شوند، لازم است برخی از دنبالهها را pad یا کوتاه کنیم.
بیایید نگاهی دقیق بیندازیم.
دادههای توالی پد
هنگام پردازش داده های توالی، بسیار متداول است که نمونه های جداگانه دارای طول های مختلف باشند. مثال زیر را در نظر بگیرید (متن نشانه گذاری شده به صورت کلمات):
[
["Hello", "world", "!"],
["How", "are", "you", "doing", "today"],
["The", "weather", "will", "be", "nice", "tomorrow"],
]
پس از جستجوی واژگان، داده ها ممکن است به صورت اعداد صحیح بردار شوند، به عنوان مثال:
[
[71, 1331, 4231]
[73, 8, 3215, 55, 927],
[83, 91, 1, 645, 1253, 927],
]
داده ها یک لیست تودرتو هستند که در آن نمونه های منفرد به ترتیب دارای طول 3، 5 و 6 هستند. از آنجا که داده های ورودی برای یک مدل یادگیری عمیق باید یک تانسور تک (به عنوان مثال شکل (batch_size, 6, vocab_size)
در این مورد)، نمونه کوتاهتر از طولانی ترین نیاز آیتم به با برخی از ارزش حفره یا سوراخ (روش دیگر، یک خالی شود همچنین ممکن است نمونه های بلند را قبل از قرار دادن نمونه های کوتاه کوتاه کند).
Keras یک تابع مطلوبیت به کوتاه و پد لیست پایتون فراهم می کند به طول معمول: tf.keras.preprocessing.sequence.pad_sequences
.
raw_inputs = [
[711, 632, 71],
[73, 8, 3215, 55, 927],
[83, 91, 1, 645, 1253, 927],
]
# By default, this will pad using 0s; it is configurable via the
# "value" parameter.
# Note that you could "pre" padding (at the beginning) or
# "post" padding (at the end).
# We recommend using "post" padding when working with RNN layers
# (in order to be able to use the
# CuDNN implementation of the layers).
padded_inputs = tf.keras.preprocessing.sequence.pad_sequences(
raw_inputs, padding="post"
)
print(padded_inputs)
[[ 711 632 71 0 0 0] [ 73 8 3215 55 927 0] [ 83 91 1 645 1253 927]]
نقاب زدن
اکنون که تمام نمونه ها دارای طول یکنواخت هستند، باید به مدل اطلاع داده شود که بخشی از داده ها در واقع padding هستند و باید نادیده گرفته شوند. که ساز و پوشش است.
سه راه برای معرفی ماسک ورودی در مدل های Keras وجود دارد:
- اضافه کردن
keras.layers.Masking
لایه. - پیکربندی یک
keras.layers.Embedding
لایه باmask_zero=True
. - تصویب یک
mask
استدلال دستی در هنگام فراخوانی لایه که این استدلال (به عنوان مثال لایه RNN) پشتیبانی می کنند.
لایه های ماسک تولید: Embedding
و Masking
در زیر هود، این لایه ها یک تانسور ماسک (تانسور 2D با شکل ایجاد (batch, sequence_length)
)، و آن را متصل به خروجی تانسور بازگردانده شده توسط Masking
و یا Embedding
لایه.
embedding = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)
masked_output = embedding(padded_inputs)
print(masked_output._keras_mask)
masking_layer = layers.Masking()
# Simulate the embedding lookup by expanding the 2D input to 3D,
# with embedding dimension of 10.
unmasked_embedding = tf.cast(
tf.tile(tf.expand_dims(padded_inputs, axis=-1), [1, 1, 10]), tf.float32
)
masked_embedding = masking_layer(unmasked_embedding)
print(masked_embedding._keras_mask)
tf.Tensor( [[ True True True False False False] [ True True True True True False] [ True True True True True True]], shape=(3, 6), dtype=bool) tf.Tensor( [[ True True True False False False] [ True True True True True False] [ True True True True True True]], shape=(3, 6), dtype=bool)
همانطور که شما می توانید از نتیجه چاپی را ببینید، ماسک یک تانسور بولی 2D با شکل است (batch_size, sequence_length)
، که در آن هر فرد False
ورود نشان می دهد که timestep مربوطه باید در طول پردازش کنه.
انتشار ماسک در Functional API و Sequential API
هنگامی که با استفاده از API کاربردی یا API متوالی، یک ماسک تولید شده توسط یک Embedding
یا Masking
لایه خواهد بود از طریق شبکه برای هر لایه است که قادر به استفاده از آنها (به عنوان مثال، لایه RNN) تکثیر می شود. Keras به طور خودکار ماسک مربوط به یک ورودی را دریافت می کند و آن را به هر لایه ای که می داند چگونه از آن استفاده کند ارسال می کند.
به عنوان مثال، در مدل های متوالی زیر، LSTM
لایه به طور خودکار یک ماسک، که به معنی آن خواهد ارزش خالی چشم پوشی دریافت خواهید کرد:
model = keras.Sequential(
[layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True), layers.LSTM(32),]
)
این مورد برای مدل تابعی API زیر نیز صادق است:
inputs = keras.Input(shape=(None,), dtype="int32")
x = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)(inputs)
outputs = layers.LSTM(32)(x)
model = keras.Model(inputs, outputs)
انتقال تانسورهای ماسک به طور مستقیم به لایه ها
لایه هایی که می توانید از ماسک (مانند رسیدگی LSTM
لایه) یک mask
استدلال در خود __call__
روش.
در همین حال، لایه است که برای تولید یک ماسک (به عنوان مثال Embedding
) افشای یک compute_mask(input, previous_mask)
روشی است که شما می توانید تماس بگیرید.
بنابراین، شما می توانید خروجی از تصویب compute_mask()
روش یک لایه ماسک تولید کننده به __call__
روش یک لایه ماسک گیر، مثل این:
class MyLayer(layers.Layer):
def __init__(self, **kwargs):
super(MyLayer, self).__init__(**kwargs)
self.embedding = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)
self.lstm = layers.LSTM(32)
def call(self, inputs):
x = self.embedding(inputs)
# Note that you could also prepare a `mask` tensor manually.
# It only needs to be a boolean tensor
# with the right shape, i.e. (batch_size, timesteps).
mask = self.embedding.compute_mask(inputs)
output = self.lstm(x, mask=mask) # The layer will ignore the masked values
return output
layer = MyLayer()
x = np.random.random((32, 10)) * 100
x = x.astype("int32")
layer(x)
<tf.Tensor: shape=(32, 32), dtype=float32, numpy= array([[-3.6287602e-04, 8.8942451e-03, -4.5623952e-03, ..., 3.6509466e-04, -4.3871473e-03, -1.7532009e-03], [ 2.6261162e-03, -2.5420082e-03, 7.6517118e-03, ..., 5.8210879e-03, -1.5617531e-03, -1.7562184e-03], [ 6.8687932e-03, 1.2330032e-03, -1.2028826e-02, ..., 2.0486799e-03, 5.7172528e-03, 2.6641595e-03], ..., [-3.4327951e-04, 1.3967649e-03, -1.2102776e-02, ..., 3.8406218e-03, -2.3374180e-03, -4.9669710e-03], [-2.3023323e-03, 1.8474255e-03, 2.7329330e-05, ..., 6.1798934e-03, 4.2709545e-04, 3.9026213e-03], [ 7.4090287e-03, 1.9879336e-03, -2.0261200e-03, ..., 8.2100276e-03, 8.7051848e-03, 9.9167246e-03]], dtype=float32)>
پشتیبانی از پوشش در لایه های سفارشی شما
گاهی اوقات، شما ممکن است به لایه های ارسال که یک ماسک (مانند نیاز Embedding
) و یا لایه های که نیاز به تغییر ماسک جاری است.
به عنوان مثال، هر لایه که تولید یک تانسور با ابعاد زمانی مختلف از ورودی آن، مانند Concatenate
لایه است که الحاق در بعد زمان، نیاز به تغییر ماسک فعلی به طوری که لایه های پایین دست قادر timesteps پوشانده به درستی را به خواهد بود حساب.
برای این کار، لایه خود را باید پیاده سازی layer.compute_mask()
روش، که به تولید یک ماسک جدید با توجه به ورودی و ماسک جاری است.
در اینجا یک مثال از یک است TemporalSplit
لایه است که نیاز به تغییر ماسک جاری است.
class TemporalSplit(keras.layers.Layer):
"""Split the input tensor into 2 tensors along the time dimension."""
def call(self, inputs):
# Expect the input to be 3D and mask to be 2D, split the input tensor into 2
# subtensors along the time axis (axis 1).
return tf.split(inputs, 2, axis=1)
def compute_mask(self, inputs, mask=None):
# Also split the mask into 2 if it presents.
if mask is None:
return None
return tf.split(mask, 2, axis=1)
first_half, second_half = TemporalSplit()(masked_embedding)
print(first_half._keras_mask)
print(second_half._keras_mask)
tf.Tensor( [[ True True True] [ True True True] [ True True True]], shape=(3, 3), dtype=bool) tf.Tensor( [[False False False] [ True True False] [ True True True]], shape=(3, 3), dtype=bool)
در اینجا نمونه ای دیگر از است CustomEmbedding
لایه این است که قادر به تولید یک ماسک از مقادیر ورودی:
class CustomEmbedding(keras.layers.Layer):
def __init__(self, input_dim, output_dim, mask_zero=False, **kwargs):
super(CustomEmbedding, self).__init__(**kwargs)
self.input_dim = input_dim
self.output_dim = output_dim
self.mask_zero = mask_zero
def build(self, input_shape):
self.embeddings = self.add_weight(
shape=(self.input_dim, self.output_dim),
initializer="random_normal",
dtype="float32",
)
def call(self, inputs):
return tf.nn.embedding_lookup(self.embeddings, inputs)
def compute_mask(self, inputs, mask=None):
if not self.mask_zero:
return None
return tf.not_equal(inputs, 0)
layer = CustomEmbedding(10, 32, mask_zero=True)
x = np.random.random((3, 10)) * 9
x = x.astype("int32")
y = layer(x)
mask = layer.compute_mask(x)
print(mask)
tf.Tensor( [[ True True True True True True True True True True] [ True True True True True False True True True True] [ True True True True True True True True False True]], shape=(3, 10), dtype=bool)
انتخاب ماسک انتشار در لایههای سازگار
اکثر لایه ها بعد زمان را تغییر نمی دهند، بنابراین نیازی به تغییر ماسک فعلی نیست. با این حال، آنها هنوز هم ممکن است می خواهم که قادر به انتشار ماسک فعلی، بدون تغییر، به لایه بعدی. این یک رفتار انتخابی است. بهطور پیشفرض، یک لایه سفارشی ماسک فعلی را از بین میبرد (از آنجایی که چارچوب هیچ راهی برای تشخیص اینکه آیا انتشار ماسک برای انجام آن بیخطر است یا خیر) را ندارد.
اگر شما یک لایه های سفارشی که بعد زمان را تغییر دهید، و اگر شما می خواهید آن را قادر به انتشار ماسک ورودی فعلی، شما باید راه self.supports_masking = True
در سازنده لایه. در این مورد، رفتار پیشفرض compute_mask()
است که فقط تصویب ماسک حال حاضر از طریق.
در اینجا نمونه ای از لایه ای است که برای انتشار ماسک در لیست سفید قرار گرفته است:
class MyActivation(keras.layers.Layer):
def __init__(self, **kwargs):
super(MyActivation, self).__init__(**kwargs)
# Signal that the layer is safe for mask propagation
self.supports_masking = True
def call(self, inputs):
return tf.nn.relu(inputs)
شما هم اکنون می توانید این لایه سفارشی استفاده کنید در میان یک لایه ماسک تولید (مانند Embedding
) و یک لایه ماسک گیر (مانند LSTM
)، و آن را به ماسک همراه به طوری که آن لایه ماسک گیر می رسد منتقل می کند.
inputs = keras.Input(shape=(None,), dtype="int32")
x = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)(inputs)
x = MyActivation()(x) # Will pass the mask along
print("Mask found:", x._keras_mask)
outputs = layers.LSTM(32)(x) # Will receive the mask
model = keras.Model(inputs, outputs)
Mask found: KerasTensor(type_spec=TensorSpec(shape=(None, None), dtype=tf.bool, name=None), name='Placeholder_1:0')
نوشتن لایه هایی که به اطلاعات ماسک نیاز دارند
برخی از لایه های مصرف کنندگان ماسک عبارتند از: آنها قبول mask
استدلال در call
و استفاده از آن برای تعیین اینکه آیا به جست و خیز مراحل زمان خاص است.
برای ارسال چنین لایه، شما به سادگی می توانید اضافه کردن mask=None
استدلال خود را call
امضا. ماسک مرتبط با ورودی ها هر زمان که در دسترس باشد به لایه شما ارسال می شود.
در اینجا یک مثال ساده در زیر آورده شده است: لایه ای که یک softmax را در بعد زمانی (محور 1) یک دنباله ورودی محاسبه می کند، در حالی که گام های زمانی ماسک شده را دور می زند.
class TemporalSoftmax(keras.layers.Layer):
def call(self, inputs, mask=None):
broadcast_float_mask = tf.expand_dims(tf.cast(mask, "float32"), -1)
inputs_exp = tf.exp(inputs) * broadcast_float_mask
inputs_sum = tf.reduce_sum(
inputs_exp * broadcast_float_mask, axis=-1, keepdims=True
)
return inputs_exp / inputs_sum
inputs = keras.Input(shape=(None,), dtype="int32")
x = layers.Embedding(input_dim=10, output_dim=32, mask_zero=True)(inputs)
x = layers.Dense(1)(x)
outputs = TemporalSoftmax()(x)
model = keras.Model(inputs, outputs)
y = model(np.random.randint(0, 10, size=(32, 100)), np.random.random((32, 100, 1)))
خلاصه
این تنها چیزی است که باید در مورد بالشتک و ماسک در Keras بدانید. برای جمع بندی:
- «ماسکینگ» به این معناست که لایهها چگونه میتوانند بدانند چه زمانی باید مراحل زمانی خاص را در ورودیهای دنباله نادیده بگیرند.
- برخی از لایه های ماسک ژنراتور عبارتند از:
Embedding
می توانید یک ماسک از مقادیر ورودی تولید (در صورتmask_zero=True
)، و بنابراین می تواندMasking
لایه. - برخی از لایه های ماسک مصرف کنندگان عبارتند از: آنها در معرض
mask
استدلال در خود__call__
روش. این مورد برای لایه های RNN است. - در Functional API و Sequential API، اطلاعات ماسک به طور خودکار منتشر می شود.
- هنگام استفاده از لایه ها در یک راه مستقل نیست، شما می توانید عبور
mask
استدلال به لایه های دستی. - میتوانید به راحتی لایههایی بنویسید که ماسک فعلی را تغییر میدهند، ماسک جدیدی ایجاد میکنند یا ماسک مرتبط با ورودیها را مصرف میکنند.