مقدمه ای بر رمزگذارهای خودکار

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

این آموزش رمزگذارهای خودکار را با سه مثال معرفی می کند: اصول اولیه، حذف نویز تصویر و تشخیص ناهنجاری.

رمزگذار خودکار نوع خاصی از شبکه عصبی است که برای کپی کردن ورودی خود در خروجی آموزش دیده است. به عنوان مثال، با توجه به تصویری از یک رقم دست‌نویس، یک رمزگذار خودکار ابتدا تصویر را در یک نمایش نهفته با ابعاد پایین‌تر رمزگذاری می‌کند، سپس نمایش نهفته را به یک تصویر رمزگشایی می‌کند. رمزگذار خودکار یاد می گیرد که داده ها را فشرده کند در حالی که خطای بازسازی را به حداقل می رساند.

برای کسب اطلاعات بیشتر در مورد رمزگذارهای خودکار، لطفاً فصل 14 از یادگیری عمیق توسط یان گودفلو، یوشوا بنژیو و آرون کورویل را مطالعه کنید.

TensorFlow و کتابخانه های دیگر را وارد کنید

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers, losses
from tensorflow.keras.datasets import fashion_mnist
from tensorflow.keras.models import Model

مجموعه داده را بارگیری کنید

برای شروع، رمزگذار خودکار اصلی را با استفاده از مجموعه داده Fashion MNIST آموزش خواهید داد. هر تصویر در این مجموعه داده 28x28 پیکسل است.

(x_train, _), (x_test, _) = fashion_mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

print (x_train.shape)
print (x_test.shape)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
40960/29515 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
26435584/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
16384/5148 [===============================================================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
4431872/4422102 [==============================] - 0s 0us/step
(60000, 28, 28)
(10000, 28, 28)

مثال اول: رمزگذار خودکار پایه

نتایج اولیه رمزگذار خودکار

یک رمزگذار خودکار با دو لایه متراکم تعریف کنید: یک encoder که تصاویر را در یک بردار نهفته 64 بعدی فشرده می کند و یک decoder که تصویر اصلی را از فضای پنهان بازسازی می کند.

برای تعریف مدل خود، از Keras Model Subclassing API استفاده کنید.

latent_dim = 64 

class Autoencoder(Model):
  def __init__(self, latent_dim):
    super(Autoencoder, self).__init__()
    self.latent_dim = latent_dim   
    self.encoder = tf.keras.Sequential([
      layers.Flatten(),
      layers.Dense(latent_dim, activation='relu'),
    ])
    self.decoder = tf.keras.Sequential([
      layers.Dense(784, activation='sigmoid'),
      layers.Reshape((28, 28))
    ])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = Autoencoder(latent_dim)
autoencoder.compile(optimizer='adam', loss=losses.MeanSquaredError())

مدل را با استفاده از x_train به عنوان ورودی و هدف آموزش دهید. encoder یاد می گیرد که مجموعه داده را از 784 بعد به فضای پنهان فشرده کند و decoder یاد می گیرد که تصاویر اصلی را بازسازی کند. .

autoencoder.fit(x_train, x_train,
                epochs=10,
                shuffle=True,
                validation_data=(x_test, x_test))
Epoch 1/10
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0243 - val_loss: 0.0140
Epoch 2/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0116 - val_loss: 0.0106
Epoch 3/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0100 - val_loss: 0.0098
Epoch 4/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0094 - val_loss: 0.0094
Epoch 5/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0092 - val_loss: 0.0092
Epoch 6/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0090 - val_loss: 0.0091
Epoch 7/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0090 - val_loss: 0.0090
Epoch 8/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0089 - val_loss: 0.0090
Epoch 9/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0088 - val_loss: 0.0089
Epoch 10/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0088 - val_loss: 0.0089
<keras.callbacks.History at 0x7ff1d35df550>

اکنون که مدل آموزش داده شده است، بیایید آن را با رمزگذاری و رمزگشایی تصاویر از مجموعه آزمایشی آزمایش کنیم.

encoded_imgs = autoencoder.encoder(x_test).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()
n = 10
plt.figure(figsize=(20, 4))
for i in range(n):
  # display original
  ax = plt.subplot(2, n, i + 1)
  plt.imshow(x_test[i])
  plt.title("original")
  plt.gray()
  ax.get_xaxis().set_visible(False)
  ax.get_yaxis().set_visible(False)

  # display reconstruction
  ax = plt.subplot(2, n, i + 1 + n)
  plt.imshow(decoded_imgs[i])
  plt.title("reconstructed")
  plt.gray()
  ax.get_xaxis().set_visible(False)
  ax.get_yaxis().set_visible(False)
plt.show()

png

مثال دوم: حذف نویز تصویر

نتایج حذف نویز تصویر

همچنین می‌توان یک رمزگذار خودکار برای حذف نویز از تصاویر آموزش داد. در بخش زیر، با اعمال نویز تصادفی برای هر تصویر، یک نسخه نویز از مجموعه داده Fashion MNIST ایجاد خواهید کرد. سپس یک رمزگذار خودکار را با استفاده از تصویر نویزدار به عنوان ورودی و تصویر اصلی به عنوان هدف آموزش خواهید داد.

بیایید مجموعه داده را مجدداً وارد کنیم تا تغییراتی که قبلا انجام شده را حذف کنیم.

(x_train, _), (x_test, _) = fashion_mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

print(x_train.shape)
(60000, 28, 28, 1)

اضافه کردن نویز تصادفی به تصاویر

noise_factor = 0.2
x_train_noisy = x_train + noise_factor * tf.random.normal(shape=x_train.shape) 
x_test_noisy = x_test + noise_factor * tf.random.normal(shape=x_test.shape) 

x_train_noisy = tf.clip_by_value(x_train_noisy, clip_value_min=0., clip_value_max=1.)
x_test_noisy = tf.clip_by_value(x_test_noisy, clip_value_min=0., clip_value_max=1.)

تصاویر پر سر و صدا را ترسیم کنید.

n = 10
plt.figure(figsize=(20, 2))
for i in range(n):
    ax = plt.subplot(1, n, i + 1)
    plt.title("original + noise")
    plt.imshow(tf.squeeze(x_test_noisy[i]))
    plt.gray()
plt.show()

png

رمزگذار خودکار کانولوشنال را تعریف کنید

در این مثال، شما یک رمزگذار خودکار کانولوشنال را با استفاده از لایه‌های Conv2D در encoder و لایه‌های Conv2DTranspose در decoder آموزش می‌دهید.

class Denoise(Model):
  def __init__(self):
    super(Denoise, self).__init__()
    self.encoder = tf.keras.Sequential([
      layers.Input(shape=(28, 28, 1)),
      layers.Conv2D(16, (3, 3), activation='relu', padding='same', strides=2),
      layers.Conv2D(8, (3, 3), activation='relu', padding='same', strides=2)])

    self.decoder = tf.keras.Sequential([
      layers.Conv2DTranspose(8, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2DTranspose(16, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2D(1, kernel_size=(3, 3), activation='sigmoid', padding='same')])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = Denoise()
autoencoder.compile(optimizer='adam', loss=losses.MeanSquaredError())
autoencoder.fit(x_train_noisy, x_train,
                epochs=10,
                shuffle=True,
                validation_data=(x_test_noisy, x_test))
Epoch 1/10
1875/1875 [==============================] - 8s 3ms/step - loss: 0.0169 - val_loss: 0.0107
Epoch 2/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0095 - val_loss: 0.0086
Epoch 3/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0082 - val_loss: 0.0080
Epoch 4/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0078 - val_loss: 0.0077
Epoch 5/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0076 - val_loss: 0.0075
Epoch 6/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0074 - val_loss: 0.0074
Epoch 7/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0073 - val_loss: 0.0073
Epoch 8/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0072 - val_loss: 0.0072
Epoch 9/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0071 - val_loss: 0.0071
Epoch 10/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0070 - val_loss: 0.0071
<keras.callbacks.History at 0x7ff1c45a31d0>

بیایید نگاهی به خلاصه ای از رمزگذار بیندازیم. توجه داشته باشید که چگونه تصاویر از 28x28 به 7x7 کوچک می شوند.

autoencoder.encoder.summary()
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 14, 14, 16)        160       
                                                                 
 conv2d_1 (Conv2D)           (None, 7, 7, 8)           1160      
                                                                 
=================================================================
Total params: 1,320
Trainable params: 1,320
Non-trainable params: 0
_________________________________________________________________

رمزگشا تصاویر را از 7*7 به 28*28 نمونه برداری می کند.

autoencoder.decoder.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_transpose (Conv2DTra  (None, 14, 14, 8)        584       
 nspose)                                                         
                                                                 
 conv2d_transpose_1 (Conv2DT  (None, 28, 28, 16)       1168      
 ranspose)                                                       
                                                                 
 conv2d_2 (Conv2D)           (None, 28, 28, 1)         145       
                                                                 
=================================================================
Total params: 1,897
Trainable params: 1,897
Non-trainable params: 0
_________________________________________________________________

ترسیم تصاویر پر سر و صدا و تصاویر حذف شده توسط رمزگذار خودکار.

encoded_imgs = autoencoder.encoder(x_test).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()
n = 10
plt.figure(figsize=(20, 4))
for i in range(n):

    # display original + noise
    ax = plt.subplot(2, n, i + 1)
    plt.title("original + noise")
    plt.imshow(tf.squeeze(x_test_noisy[i]))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # display reconstruction
    bx = plt.subplot(2, n, i + n + 1)
    plt.title("reconstructed")
    plt.imshow(tf.squeeze(decoded_imgs[i]))
    plt.gray()
    bx.get_xaxis().set_visible(False)
    bx.get_yaxis().set_visible(False)
plt.show()

png

مثال سوم: تشخیص ناهنجاری

بررسی اجمالی

در این مثال، شما یک رمزگذار خودکار را برای تشخیص ناهنجاری ها در مجموعه داده ECG5000 آموزش می دهید. این مجموعه داده شامل 5000 الکتروکاردیوگرام است که هر کدام دارای 140 نقطه داده است. شما از یک نسخه ساده شده از مجموعه داده استفاده خواهید کرد، که در آن هر نمونه دارای برچسب 0 (مرتبط با یک ریتم غیرعادی) یا 1 (مرتبط با یک ریتم عادی) است. شما علاقه مند به شناسایی ریتم های غیر طبیعی هستید.

چگونه می توانید ناهنجاری ها را با استفاده از رمزگذار خودکار تشخیص دهید؟ به یاد بیاورید که رمزگذار خودکار برای به حداقل رساندن خطای بازسازی آموزش داده شده است. شما یک رمزگذار خودکار را فقط با ریتم های معمولی آموزش می دهید، سپس از آن برای بازسازی تمام داده ها استفاده می کنید. فرضیه ما این است که ریتم های غیرعادی خطای بازسازی بیشتری خواهند داشت. اگر خطای بازسازی از یک آستانه ثابت فراتر رود، یک ریتم را به عنوان یک ناهنجاری طبقه بندی می کنید.

بارگذاری اطلاعات ECG

مجموعه داده ای که استفاده خواهید کرد بر اساس یکی از داده های timeseriesclassification.com است.

# Download the dataset
dataframe = pd.read_csv('http://storage.googleapis.com/download.tensorflow.org/data/ecg.csv', header=None)
raw_data = dataframe.values
dataframe.head()
# The last element contains the labels
labels = raw_data[:, -1]

# The other data points are the electrocadriogram data
data = raw_data[:, 0:-1]

train_data, test_data, train_labels, test_labels = train_test_split(
    data, labels, test_size=0.2, random_state=21
)

داده ها را به [0,1] عادی کنید.

min_val = tf.reduce_min(train_data)
max_val = tf.reduce_max(train_data)

train_data = (train_data - min_val) / (max_val - min_val)
test_data = (test_data - min_val) / (max_val - min_val)

train_data = tf.cast(train_data, tf.float32)
test_data = tf.cast(test_data, tf.float32)

رمزگذار خودکار را فقط با استفاده از ریتم های معمولی که در این مجموعه داده با 1 برچسب گذاری شده اند، آموزش خواهید داد. ریتم های عادی را از ریتم های غیرعادی جدا کنید.

train_labels = train_labels.astype(bool)
test_labels = test_labels.astype(bool)

normal_train_data = train_data[train_labels]
normal_test_data = test_data[test_labels]

anomalous_train_data = train_data[~train_labels]
anomalous_test_data = test_data[~test_labels]

یک نوار قلب معمولی ترسیم کنید.

plt.grid()
plt.plot(np.arange(140), normal_train_data[0])
plt.title("A Normal ECG")
plt.show()

png

یک نوار قلب غیرعادی را ترسیم کنید.

plt.grid()
plt.plot(np.arange(140), anomalous_train_data[0])
plt.title("An Anomalous ECG")
plt.show()

png

مدل را بسازید

class AnomalyDetector(Model):
  def __init__(self):
    super(AnomalyDetector, self).__init__()
    self.encoder = tf.keras.Sequential([
      layers.Dense(32, activation="relu"),
      layers.Dense(16, activation="relu"),
      layers.Dense(8, activation="relu")])

    self.decoder = tf.keras.Sequential([
      layers.Dense(16, activation="relu"),
      layers.Dense(32, activation="relu"),
      layers.Dense(140, activation="sigmoid")])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = AnomalyDetector()
autoencoder.compile(optimizer='adam', loss='mae')

توجه داشته باشید که رمزگذار خودکار فقط با استفاده از ECG های معمولی آموزش داده می شود، اما با استفاده از مجموعه آزمایش کامل ارزیابی می شود.

history = autoencoder.fit(normal_train_data, normal_train_data, 
          epochs=20, 
          batch_size=512,
          validation_data=(test_data, test_data),
          shuffle=True)
Epoch 1/20
5/5 [==============================] - 1s 33ms/step - loss: 0.0576 - val_loss: 0.0531
Epoch 2/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0552 - val_loss: 0.0514
Epoch 3/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0519 - val_loss: 0.0499
Epoch 4/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0483 - val_loss: 0.0475
Epoch 5/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0445 - val_loss: 0.0451
Epoch 6/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0409 - val_loss: 0.0432
Epoch 7/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0377 - val_loss: 0.0415
Epoch 8/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0348 - val_loss: 0.0401
Epoch 9/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0319 - val_loss: 0.0388
Epoch 10/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0293 - val_loss: 0.0378
Epoch 11/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0273 - val_loss: 0.0369
Epoch 12/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0259 - val_loss: 0.0361
Epoch 13/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0249 - val_loss: 0.0354
Epoch 14/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0239 - val_loss: 0.0346
Epoch 15/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0230 - val_loss: 0.0340
Epoch 16/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0222 - val_loss: 0.0335
Epoch 17/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0215 - val_loss: 0.0331
Epoch 18/20
5/5 [==============================] - 0s 9ms/step - loss: 0.0211 - val_loss: 0.0331
Epoch 19/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0208 - val_loss: 0.0329
Epoch 20/20
5/5 [==============================] - 0s 8ms/step - loss: 0.0206 - val_loss: 0.0327
plt.plot(history.history["loss"], label="Training Loss")
plt.plot(history.history["val_loss"], label="Validation Loss")
plt.legend()
<matplotlib.legend.Legend at 0x7ff1d339b790>

png

اگر خطای بازسازی بیشتر از یک انحراف استاندارد از نمونه های تمرینی معمولی باشد، به زودی ECG را به عنوان غیرعادی طبقه بندی خواهید کرد. ابتدا، بیایید یک ECG معمولی را از مجموعه آموزشی، بازسازی پس از کدگذاری و رمزگشایی توسط رمزگذار خودکار، و خطای بازسازی ترسیم کنیم.

encoded_data = autoencoder.encoder(normal_test_data).numpy()
decoded_data = autoencoder.decoder(encoded_data).numpy()

plt.plot(normal_test_data[0], 'b')
plt.plot(decoded_data[0], 'r')
plt.fill_between(np.arange(140), decoded_data[0], normal_test_data[0], color='lightcoral')
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

png

یک طرح مشابه ایجاد کنید، این بار برای یک نمونه آزمایشی غیرعادی.

encoded_data = autoencoder.encoder(anomalous_test_data).numpy()
decoded_data = autoencoder.decoder(encoded_data).numpy()

plt.plot(anomalous_test_data[0], 'b')
plt.plot(decoded_data[0], 'r')
plt.fill_between(np.arange(140), decoded_data[0], anomalous_test_data[0], color='lightcoral')
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

png

تشخیص ناهنجاری ها

با محاسبه اینکه آیا تلفات بازسازی بیشتر از یک آستانه ثابت است، ناهنجاری ها را تشخیص دهید. در این آموزش میانگین خطای مثال‌های معمولی را از مجموعه آموزشی محاسبه می‌کنید، سپس اگر خطای بازسازی بیشتر از یک انحراف استاندارد از مجموعه آموزشی باشد، نمونه‌های آینده را به عنوان غیرعادی طبقه‌بندی می‌کنید.

خطای بازسازی را در ECGهای معمولی از مجموعه آموزشی ترسیم کنید

reconstructions = autoencoder.predict(normal_train_data)
train_loss = tf.keras.losses.mae(reconstructions, normal_train_data)

plt.hist(train_loss[None,:], bins=50)
plt.xlabel("Train loss")
plt.ylabel("No of examples")
plt.show()

png

مقدار آستانه ای را انتخاب کنید که یک انحراف استاندارد بالاتر از میانگین باشد.

threshold = np.mean(train_loss) + np.std(train_loss)
print("Threshold: ", threshold)
Threshold:  0.03241627

اگر خطای بازسازی را برای مثال‌های غیرعادی در مجموعه آزمایشی بررسی کنید، متوجه خواهید شد که بیشتر آنها خطای بازسازی بیشتری نسبت به آستانه دارند. با تغییر آستانه، می توانید دقت و فراخوانی طبقه بندی کننده خود را تنظیم کنید.

reconstructions = autoencoder.predict(anomalous_test_data)
test_loss = tf.keras.losses.mae(reconstructions, anomalous_test_data)

plt.hist(test_loss[None, :], bins=50)
plt.xlabel("Test loss")
plt.ylabel("No of examples")
plt.show()

png

اگر خطای بازسازی بیشتر از آستانه باشد، ECG را به عنوان یک ناهنجاری طبقه بندی کنید.

def predict(model, data, threshold):
  reconstructions = model(data)
  loss = tf.keras.losses.mae(reconstructions, data)
  return tf.math.less(loss, threshold)

def print_stats(predictions, labels):
  print("Accuracy = {}".format(accuracy_score(labels, predictions)))
  print("Precision = {}".format(precision_score(labels, predictions)))
  print("Recall = {}".format(recall_score(labels, predictions)))
preds = predict(autoencoder, test_data, threshold)
print_stats(preds, test_labels)
Accuracy = 0.944
Precision = 0.9921875
Recall = 0.9071428571428571

مراحل بعدی

برای کسب اطلاعات بیشتر در مورد تشخیص ناهنجاری با رمزگذارهای خودکار، این مثال تعاملی عالی ساخته شده با TensorFlow.js توسط ویکتور دیبیا را بررسی کنید. برای استفاده در دنیای واقعی، می‌توانید یاد بگیرید که ایرباس چگونه ناهنجاری‌ها را در داده‌های تله متری ISS با استفاده از TensorFlow تشخیص می‌دهد. برای کسب اطلاعات بیشتر در مورد اصول اولیه، این پست وبلاگ فرانسوا شوله را بخوانید. برای جزئیات بیشتر، فصل 14 از یادگیری عمیق توسط ایان گودفلو، یوشوا بنجیو و آرون کورویل را بررسی کنید.