مقدمة إلى Autoencoders

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يقدم هذا البرنامج التعليمي برامج التشفير التلقائية مع ثلاثة أمثلة: الأساسيات ، وتقليل التشويش من الصورة ، واكتشاف الشذوذ.

يعد التشفير التلقائي نوعًا خاصًا من الشبكات العصبية التي يتم تدريبها على نسخ مدخلاتها إلى مخرجاتها. على سبيل المثال ، بالنظر إلى صورة رقم مكتوب بخط اليد ، يقوم المشفر التلقائي أولاً بتشفير الصورة في تمثيل كامن ذو أبعاد أقل ، ثم يقوم بفك تشفير التمثيل الكامن إلى صورة ما. يتعلم المشفر التلقائي ضغط البيانات مع تقليل خطأ إعادة الإعمار.

لمعرفة المزيد حول أجهزة التشفير التلقائي ، يرجى قراءة الفصل 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. تبلغ كل صورة في مجموعة البيانات هذه 28 × 28 بكسل.

(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()

بي إن جي

المثال الثاني: تقليل ضوضاء الصورة

نتائج تقليل ضوضاء الصورة

يمكن أيضًا تدريب وحدة التشفير التلقائي على إزالة الضوضاء من الصور. في القسم التالي ، ستقوم بإنشاء نسخة صاخبة من مجموعة بيانات 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()

بي إن جي

حدد المشفر التلقائي التلافيفي

في هذا المثال ، ستقوم بتدريب المشفر التلقائي التلافيفي باستخدام طبقات 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())
l10n-placeholder17 l10n-placeholder18l10n-placeholder18 l10n-placeholder16
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>

دعنا نلقي نظرة على ملخص برنامج التشفير. لاحظ كيف يتم اختزال الصور من 28 × 28 إلى 7 × 7.

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()

بي إن جي

المثال الثالث: كشف الشذوذ

ملخص

في هذا المثال ، ستقوم بتدريب برنامج تشفير تلقائي على اكتشاف الحالات الشاذة في مجموعة بيانات ECG5000 . تحتوي مجموعة البيانات هذه على 5000 مخطط كهربائي للقلب ، لكل منها 140 نقطة بيانات. ستستخدم نسخة مبسطة من مجموعة البيانات ، حيث تم تصنيف كل مثال إما 0 (يتوافق مع إيقاع غير طبيعي) ، أو 1 (يتوافق مع إيقاع عادي). أنت مهتم بالتعرف على الإيقاعات غير الطبيعية.

كيف ستكتشف الحالات الشاذة باستخدام برنامج التشفير التلقائي؟ تذكر أنه تم تدريب وحدة التشفير التلقائي لتقليل خطأ إعادة البناء. ستقوم بتدريب المشفر التلقائي على الإيقاعات العادية فقط ، ثم تستخدمه لإعادة بناء جميع البيانات. فرضيتنا هي أن الإيقاعات غير الطبيعية سيكون لها خطأ أكبر في إعادة البناء. ستصنف بعد ذلك الإيقاع على أنه شذوذ إذا تجاوز خطأ إعادة الإعمار حدًا ثابتًا.

تحميل بيانات تخطيط القلب

تعتمد مجموعة البيانات التي ستستخدمها على مجموعة من 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()

بي إن جي

ارسم مخطط كهربية القلب الشاذ.

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

بي إن جي

بناء النموذج

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')

لاحظ أن جهاز التشفير التلقائي تم تدريبه باستخدام تخطيط القلب العادي فقط ، ولكن يتم تقييمه باستخدام مجموعة الاختبار الكاملة.

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>

بي إن جي

ستصنف قريبًا مخطط كهربية القلب على أنه شاذ إذا كان خطأ إعادة البناء أكبر من انحراف معياري واحد عن أمثلة التدريب العادية. أولاً ، دعنا نرسم مخطط كهربية القلب الطبيعي من مجموعة التدريب ، وإعادة البناء بعد تشفيرها وفك تشفيرها بواسطة وحدة التشفير التلقائي ، وخطأ إعادة البناء.

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()

بي إن جي

قم بإنشاء مخطط مماثل ، هذه المرة للحصول على مثال اختبار شاذ.

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()

بي إن جي

كشف الشذوذ

كشف الحالات الشاذة عن طريق حساب ما إذا كانت خسارة إعادة البناء أكبر من عتبة ثابتة. في هذا البرنامج التعليمي ، ستحسب متوسط ​​الخطأ للأمثلة العادية من مجموعة التدريب ، ثم تصنف الأمثلة المستقبلية على أنها شاذة إذا كان خطأ إعادة الإعمار أعلى من انحراف معياري واحد عن مجموعة التدريب.

ارسم خطأ إعادة البناء على تخطيط القلب الطبيعي من مجموعة التدريب

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()

بي إن جي

اختر قيمة حد تكون انحرافًا معياريًا واحدًا فوق المتوسط.

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()

بي إن جي

صنف مخطط كهربية القلب على أنه شذوذ إذا كان خطأ إعادة البناء أكبر من الحد الأدنى.

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 بواسطة Victor Dibia. بالنسبة لحالة الاستخدام في العالم الحقيقي ، يمكنك معرفة كيف تكتشف Airbus الحالات الشاذة في بيانات القياس عن بُعد لمحطة الفضاء الدولية باستخدام TensorFlow. لمعرفة المزيد حول الأساسيات ، ضع في اعتبارك قراءة منشور المدونة هذا بواسطة François Chollet. لمزيد من التفاصيل ، راجع الفصل 14 من التعلم العميق من تأليف إيان جودفيلو ويوشوا بنجيو وآرون كورفيل.