این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

نظم نمودار برای طبقه بندی احساسات با استفاده از نمودارهای سنتز شده

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub

بررسی اجمالی

این دفترچه با استفاده از متن بررسی ، بررسی های فیلم را مثبت یا منفی طبقه بندی می کند. این یک نمونه از طبقه بندی باینری است ، یک نوع مهم و بسیار کاربردی مسئله یادگیری ماشین.

ما با ساختن یک نمودار از ورودی داده شده ، استفاده از تنظیم منظم نمودار را در این نوت بوک نشان خواهیم داد. دستورالعمل کلی برای ساختن یک مدل منظم نمودار با استفاده از چارچوب یادگیری ساختاری عصبی (NSL) در صورتی که ورودی دارای یک نمودار مشخص نباشد به شرح زیر است:

  1. برای هر نمونه متن در ورودی تعبیه کنید. این کار را می توان با استفاده از مدل های از قبل آموزش دیده مانند word2vec ، Swivel ، BERT و غیره انجام داد.
  2. با استفاده از یک متریک شباهت مانند فاصله "L2" ، فاصله "کسین" و غیره ، یک نمودار را بسازید و گره های موجود در نمودار مطابق با نمونه ها و لبه های موجود در نمودار مطابق با شباهت بین جفت نمونه ها هستند.
  3. داده های آموزشی را از نمودار بالا و نمونه های مصنوعی تولید شده تولید کنید. داده های آموزش حاصل علاوه بر ویژگی های گره اصلی ، دارای ویژگی های همسایه نیز خواهد بود.
  4. با استفاده از API متوالی ، کاربردی یا زیر کلاس از یک شبکه عصبی به عنوان یک مدل پایه ایجاد کنید.
  5. مدل پایه را با کلاس بسته بندی GraphRegularization که توسط چارچوب NSL تهیه شده است بپیچید تا یک مدل گراف جدید کراس ایجاد شود. این مدل جدید شامل از دست دادن نظم نمودار به عنوان اصطلاح تنظیم در هدف آموزشی خود خواهد بود.
  6. نمودار کراس را آموزش داده و ارزیابی کنید.

الزامات

  1. بسته یادگیری ساختاری عصبی را نصب کنید.
  2. tensorflow-hub را نصب کنید.
pip install --quiet neural-structured-learning
pip install --quiet tensorflow-hub
WARNING: You are using pip version 20.2.1; however, version 20.2.2 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.
WARNING: You are using pip version 20.2.1; however, version 20.2.2 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

وابستگی ها و واردات

import matplotlib.pyplot as plt
import numpy as np

import neural_structured_learning as nsl

import tensorflow as tf
import tensorflow_hub as hub

# Resets notebook state
tf.keras.backend.clear_session()

print("Version: ", tf.__version__)
print("Eager mode: ", tf.executing_eagerly())
print("Hub version: ", hub.__version__)
print(
    "GPU is",
    "available" if tf.config.list_physical_devices("GPU") else "NOT AVAILABLE")
Version:  2.3.0
Eager mode:  True
Hub version:  0.8.0
GPU is NOT AVAILABLE

مجموعه داده IMDB

مجموعه داده IMDB شامل متن 50،000 بررسی فیلم از بانک اطلاعات فیلم اینترنت است . اینها به 25،000 بررسی برای آموزش و 25،000 بررسی برای آزمایش تقسیم می شوند. مجموعه های آموزشی و تست متعادل هستند ، به این معنی که آنها دارای تعداد برابر نظرات مثبت و منفی هستند.

در این آموزش از نسخه پیش پردازنده داده های IMDB استفاده خواهیم کرد.

مجموعه داده های پیش پردازنده IMDB را بارگیری کنید

مجموعه داده IMDB با TensorFlow بسته بندی شده است. قبلاً از پیش پردازش شده است که بررسی ها (توالی کلمات) به توالی اعداد صحیح تبدیل شده است ، جایی که هر عدد صحیح یک کلمه خاص را در یک فرهنگ لغت نشان می دهد.

کد زیر مجموعه داده IMDB را بارگیری می کند (یا در صورتی که از قبل بارگیری شده است از نسخه ذخیره شده استفاده می کند):

imdb = tf.keras.datasets.imdb
(pp_train_data, pp_train_labels), (pp_test_data, pp_test_labels) = (
    imdb.load_data(num_words=10000))
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17465344/17464789 [==============================] - 0s 0us/step

آرگومان num_words=10000 10،000 کلمه متداول در داده های آموزش را نگه می دارد. کلمات نادر برای کنترل اندازه واژگان قابل کنترل نیست.

داده ها را کاوش کنید

بیایید لحظه ای برای درک فرمت داده ها اقدام کنیم. مجموعه داده از پیش پردازش شده است: هر نمونه مجموعه ای از اعداد صحیح است که کلمات بررسی فیلم را نشان می دهد. هر برچسب یک عدد صحیح یا 0 یا 1 است ، که در آن 0 بررسی منفی است و 1 یک بررسی مثبت است.

print('Training entries: {}, labels: {}'.format(
    len(pp_train_data), len(pp_train_labels)))
training_samples_count = len(pp_train_data)
Training entries: 25000, labels: 25000

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

print(pp_train_data[0])
[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]

بررسی فیلم ممکن است طول های مختلفی داشته باشد. کد زیر تعداد کلمات را در بررسی های اول و دوم نشان می دهد. از آنجا که ورودی های شبکه عصبی باید به همان طول باشند ، باید بعداً این مسئله را برطرف کنیم.

len(pp_train_data[0]), len(pp_train_data[1])
(218, 189)

عدد صحیح را به کلمات تبدیل کنید

این ممکن است مفید باشد که بدانید چگونه عدد صحیح را به متن مربوطه برگردانید. در اینجا ، ما برای جستجوی یک شیء فرهنگ لغت که شامل عدد صحیح به نقشه برداری رشته است ، یک تکیهگر ایجاد خواهیم کرد:

def build_reverse_word_index():
  # A dictionary mapping words to an integer index
  word_index = imdb.get_word_index()

  # The first indices are reserved
  word_index = {k: (v + 3) for k, v in word_index.items()}
  word_index['<PAD>'] = 0
  word_index['<START>'] = 1
  word_index['<UNK>'] = 2  # unknown
  word_index['<UNUSED>'] = 3
  return dict((value, key) for (key, value) in word_index.items())

reverse_word_index = build_reverse_word_index()

def decode_review(text):
  return ' '.join([reverse_word_index.get(i, '?') for i in text])
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb_word_index.json
1646592/1641221 [==============================] - 0s 0us/step

اکنون می توانیم از تابع decode_review برای نمایش متن برای اولین بار استفاده کنیم:

decode_review(pp_train_data[0])
"<START> this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert <UNK> is an amazing actor and now the same being director <UNK> father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for <UNK> and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also <UNK> to the two little boy's that played the <UNK> of norman and paul they were just brilliant children are often left out of the <UNK> list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all"

ساخت نمودار

ساخت نمودار شامل ایجاد تعبیه برای نمونه های متن و سپس استفاده از یک عملکرد مشابهت برای مقایسه تعبیه ها است.

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

mkdir -p /tmp/imdb

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

برای ایجاد جاسازی در قالب tf.train.Example برای هر نمونه از ورودی ، از تعبیه های Swivel از پیش آماده شده استفاده خواهیم کرد. تعبیه های حاصل را با فرمت TFRecord و یک ویژگی اضافی که نشان دهنده شناسه هر نمونه است ، ذخیره خواهیم کرد. این مهم است و به ما این امکان را می دهد که بعداً تعبیه های نمونه با گره های مربوطه را مطابقت دهیم.

pretrained_embedding = 'https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1'

hub_layer = hub.KerasLayer(
    pretrained_embedding, input_shape=[], dtype=tf.string, trainable=True)
def _int64_feature(value):
  """Returns int64 tf.train.Feature."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=value.tolist()))


def _bytes_feature(value):
  """Returns bytes tf.train.Feature."""
  return tf.train.Feature(
      bytes_list=tf.train.BytesList(value=[value.encode('utf-8')]))


def _float_feature(value):
  """Returns float tf.train.Feature."""
  return tf.train.Feature(float_list=tf.train.FloatList(value=value.tolist()))


def create_embedding_example(word_vector, record_id):
  """Create tf.Example containing the sample's embedding and its ID."""

  text = decode_review(word_vector)

  # Shape = [batch_size,].
  sentence_embedding = hub_layer(tf.reshape(text, shape=[-1,]))

  # Flatten the sentence embedding back to 1-D.
  sentence_embedding = tf.reshape(sentence_embedding, shape=[-1])

  features = {
      'id': _bytes_feature(str(record_id)),
      'embedding': _float_feature(sentence_embedding.numpy())
  }
  return tf.train.Example(features=tf.train.Features(feature=features))


def create_embeddings(word_vectors, output_path, starting_record_id):
  record_id = int(starting_record_id)
  with tf.io.TFRecordWriter(output_path) as writer:
    for word_vector in word_vectors:
      example = create_embedding_example(word_vector, record_id)
      record_id = record_id + 1
      writer.write(example.SerializeToString())
  return record_id


# Persist TF.Example features containing embeddings for training data in
# TFRecord format.
create_embeddings(pp_train_data, '/tmp/imdb/embeddings.tfr', 0)
25000

ایجاد یک نمودار

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

یادگیری ساختاری عصبی ، یک کتابخانه ساختمان گرافیکی را برای ساختن یک نمودار بر اساس نمونه های تعبیه شده ، فراهم می کند. از شباهت کسین به عنوان اندازه گیری شباهت برای مقایسه تعبیه ها و ایجاد لبه های بین آنها استفاده می کند. همچنین به ما امکان می دهد آستانه تشابه را تعیین کنیم ، که می تواند برای جدا کردن لبه های متفاوت از نمودار نهایی استفاده شود. در این مثال با استفاده از 0.99 به عنوان آستانه شباهت و 12345 به عنوان بذر تصادفی ، به گرافیکی ختم می شویم که دارای 429.415 لبه دو جهته است. در اینجا ما با استفاده از پشتیبانی سازنده نمودار برای هش حساس به محل (LSH) برای سرعت بخشیدن به ساختمان نمودار. برای جزئیات بیشتر در مورد استفاده از پشتیبانی LSH سازنده نمودار ، به اسناد API build_graph_from_config مراجعه کنید.

graph_builder_config = nsl.configs.GraphBuilderConfig(
    similarity_threshold=0.99, lsh_splits=32, lsh_rounds=15, random_seed=12345)
nsl.tools.build_graph_from_config(['/tmp/imdb/embeddings.tfr'],
                                  '/tmp/imdb/graph_99.tsv',
                                  graph_builder_config)

هر لبه دو جهته توسط دو لبه جهت دار در پرونده TSV خروجی نشان داده می شود ، به طوری که پرونده شامل 429،415 * 2 = 858،830 کل خط:

wc -l /tmp/imdb/graph_99.tsv
858830 /tmp/imdb/graph_99.tsv

ویژگی های نمونه

ما با استفاده از قالب tf.train.Example نمونه ویژگی های نمونه را ایجاد می کنیم و آنها را در قالب TFRecord ادامه می TFRecord . هر نمونه شامل سه ویژگی زیر خواهد بود:

  1. id : شناسه گره نمونه.
  2. کلمات : لیست int64 حاوی شناسه کلمه.
  3. label : singleton int64 که کلاس هدف بررسی را مشخص می کند.
def create_example(word_vector, label, record_id):
  """Create tf.Example containing the sample's word vector, label, and ID."""
  features = {
      'id': _bytes_feature(str(record_id)),
      'words': _int64_feature(np.asarray(word_vector)),
      'label': _int64_feature(np.asarray([label])),
  }
  return tf.train.Example(features=tf.train.Features(feature=features))

def create_records(word_vectors, labels, record_path, starting_record_id):
  record_id = int(starting_record_id)
  with tf.io.TFRecordWriter(record_path) as writer:
    for word_vector, label in zip(word_vectors, labels):
      example = create_example(word_vector, label, record_id)
      record_id = record_id + 1
      writer.write(example.SerializeToString())
  return record_id

# Persist TF.Example features (word vectors and labels) for training and test
# data in TFRecord format.
next_record_id = create_records(pp_train_data, pp_train_labels,
                                '/tmp/imdb/train_data.tfr', 0)
create_records(pp_test_data, pp_test_labels, '/tmp/imdb/test_data.tfr',
               next_record_id)
50000

داده های آموزش افزودنی با همسایگان نمودار

از آنجا که ما ویژگی های نمونه و نمودار سنتز شده را داریم ، می توانیم داده های آموزشی تقویت شده را برای یادگیری ساختاری عصبی تولید کنیم. چارچوب NSL كتابخانه ای را برای تركیب نمودار و ویژگی های نمونه فراهم می كند تا داده های آموزش نهایی را برای منظم سازی نمودار تهیه كند. داده های آموزش حاصل شامل ویژگی های نمونه اصلی و همچنین ویژگی های همسایگان مربوطه می باشد.

در این آموزش لبه های غیرمستقیم را در نظر می گیریم و حداکثر 3 همسایه در هر نمونه برای تقویت داده های آموزش با همسایگان نمودار استفاده می کنیم.

nsl.tools.pack_nbrs(
    '/tmp/imdb/train_data.tfr',
    '',
    '/tmp/imdb/graph_99.tsv',
    '/tmp/imdb/nsl_train_data.tfr',
    add_undirected_edges=True,
    max_nbrs=3)

مدل پایه

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

متغیرهای جهانی

NBR_FEATURE_PREFIX = 'NL_nbr_'
NBR_WEIGHT_SUFFIX = '_weight'

هایپرپارامترها

ما از نمونه ای از HParams تا از هایپرپارامترها و ثابت های مختلفی که برای آموزش و ارزیابی استفاده می شود ، استفاده کند. ما به طور خلاصه هریک از آنها را در زیر شرح می دهیم:

  • num_classes : 2 کلاس وجود دارد - مثبت و منفی .

  • max_seq_l length : این تعداد کلماتی است که از هر بررسی فیلم در این مثال در نظر گرفته شده است.

  • vocab_size : این اندازه واژگان در نظر گرفته شده برای این مثال است.

  • distance_type : این متریک مسافتی است که برای منظم سازی نمونه با همسایگان استفاده می شود.

  • Graph_regularization_multiplier : این وزن نسبی اصطلاح تنظیم نمودار را در عملکرد کلی از دست می دهد.

  • num_neighbours : تعداد همسایگان مورد استفاده برای تنظیم نمودار. این مقدار باید کمتر از یا مساوی آرگومان max_nbrs که در هنگام مراجعه به nsl.tools.pack_nbrs بالا استفاده شده است.

  • num_fc_units : تعداد واحد در لایه کاملاً متصل شبکه عصبی.

  • train_epochs : تعداد دوره های آموزشی.

  • batch_size : اندازه دسته ای که برای آموزش و ارزیابی استفاده می شود.

  • eval_steps : تعداد دسته هایی که قبل از ارزیابی ارزیابی می شوند پردازش می شوند. اگر روی None تنظیم شود ، تمام موارد موجود در مجموعه آزمون ارزیابی می شوند.

class HParams(object):
  """Hyperparameters used for training."""
  def __init__(self):
    ### dataset parameters
    self.num_classes = 2
    self.max_seq_length = 256
    self.vocab_size = 10000
    ### neural graph learning parameters
    self.distance_type = nsl.configs.DistanceType.L2
    self.graph_regularization_multiplier = 0.1
    self.num_neighbors = 2
    ### model architecture
    self.num_embedding_dims = 16
    self.num_lstm_dims = 64
    self.num_fc_units = 64
    ### training parameters
    self.train_epochs = 10
    self.batch_size = 128
    ### eval parameters
    self.eval_steps = None  # All instances in the test set are evaluated.

HPARAMS = HParams()

داده ها را آماده کنید

بررسی ها - آرایه اعداد صحیح - باید قبل از اینکه به شبکه عصبی تغذیه شوند به تنسگرها تبدیل شوند. این تبدیل می تواند از دو طریق انجام شود:

  • آرایه ها را به بردارهای 0 و 1 ثانیه نشان دهید که وقوع کلمه را نشان می دهد ، مشابه رمزگذاری یک داغ. به عنوان مثال ، دنباله [3, 5] به یک وکتور 10000 بعدی تبدیل می شود که همه صفرها به جز شاخص های 3 و 5 ، که هستند. سپس این اولین لایه را در شبکه ما ایجاد کنید - یک لایه Dense - که می تواند داده های بردار نقطه شناور را کنترل کند. این رویکرد حافظه فشرده است ، اما به ماتریس اندازه num_words * num_reviews دارد.

  • روش دیگر ، ما می توانیم آرایه ها را max_length * num_reviews کنیم تا همه آنها طول یکسان داشته باشند ، سپس یک تانسور عدد صحیح از شکل max_length * num_reviews . ما می توانیم از لایه تعبیه شده ای استفاده کنیم که بتواند از این شکل به عنوان اولین لایه در شبکه ما استفاده کند.

در این آموزش از رویکرد دوم استفاده خواهیم کرد.

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

def make_dataset(file_path, training=False):
  """Creates a `tf.data.TFRecordDataset`.

  Args:
    file_path: Name of the file in the `.tfrecord` format containing
      `tf.train.Example` objects.
    training: Boolean indicating if we are in training mode.

  Returns:
    An instance of `tf.data.TFRecordDataset` containing the `tf.train.Example`
    objects.
  """

  def pad_sequence(sequence, max_seq_length):
    """Pads the input sequence (a `tf.SparseTensor`) to `max_seq_length`."""
    pad_size = tf.maximum([0], max_seq_length - tf.shape(sequence)[0])
    padded = tf.concat(
        [sequence.values,
         tf.fill((pad_size), tf.cast(0, sequence.dtype))],
        axis=0)
    # The input sequence may be larger than max_seq_length. Truncate down if
    # necessary.
    return tf.slice(padded, [0], [max_seq_length])

  def parse_example(example_proto):
    """Extracts relevant fields from the `example_proto`.

    Args:
      example_proto: An instance of `tf.train.Example`.

    Returns:
      A pair whose first value is a dictionary containing relevant features
      and whose second value contains the ground truth labels.
    """
    # The 'words' feature is a variable length word ID vector.
    feature_spec = {
        'words': tf.io.VarLenFeature(tf.int64),
        'label': tf.io.FixedLenFeature((), tf.int64, default_value=-1),
    }
    # We also extract corresponding neighbor features in a similar manner to
    # the features above during training.
    if training:
      for i in range(HPARAMS.num_neighbors):
        nbr_feature_key = '{}{}_{}'.format(NBR_FEATURE_PREFIX, i, 'words')
        nbr_weight_key = '{}{}{}'.format(NBR_FEATURE_PREFIX, i,
                                         NBR_WEIGHT_SUFFIX)
        feature_spec[nbr_feature_key] = tf.io.VarLenFeature(tf.int64)

        # We assign a default value of 0.0 for the neighbor weight so that
        # graph regularization is done on samples based on their exact number
        # of neighbors. In other words, non-existent neighbors are discounted.
        feature_spec[nbr_weight_key] = tf.io.FixedLenFeature(
            [1], tf.float32, default_value=tf.constant([0.0]))

    features = tf.io.parse_single_example(example_proto, feature_spec)

    # Since the 'words' feature is a variable length word vector, we pad it to a
    # constant maximum length based on HPARAMS.max_seq_length
    features['words'] = pad_sequence(features['words'], HPARAMS.max_seq_length)
    if training:
      for i in range(HPARAMS.num_neighbors):
        nbr_feature_key = '{}{}_{}'.format(NBR_FEATURE_PREFIX, i, 'words')
        features[nbr_feature_key] = pad_sequence(features[nbr_feature_key],
                                                 HPARAMS.max_seq_length)

    labels = features.pop('label')
    return features, labels

  dataset = tf.data.TFRecordDataset([file_path])
  if training:
    dataset = dataset.shuffle(10000)
  dataset = dataset.map(parse_example)
  dataset = dataset.batch(HPARAMS.batch_size)
  return dataset


train_dataset = make_dataset('/tmp/imdb/nsl_train_data.tfr', True)
test_dataset = make_dataset('/tmp/imdb/test_data.tfr')

مدل را بسازید

یک شبکه عصبی با ایجاد لایه ها ایجاد می شود - این امر نیاز به دو تصمیم اصلی در زمینه معماری دارد:

  • چند لایه برای استفاده در مدل؟
  • چند واحد پنهان برای استفاده از هر لایه؟

در این مثال ، داده های ورودی شامل آرایه ای از شاخص های word است. برچسب های پیش بینی شده 0 یا 1 است.

ما در این آموزش از یک LSTM دو جهته به عنوان مدل پایه استفاده خواهیم کرد.

# This function exists as an alternative to the bi-LSTM model used in this
# notebook.
def make_feed_forward_model():
  """Builds a simple 2 layer feed forward neural network."""
  inputs = tf.keras.Input(
      shape=(HPARAMS.max_seq_length,), dtype='int64', name='words')
  embedding_layer = tf.keras.layers.Embedding(HPARAMS.vocab_size, 16)(inputs)
  pooling_layer = tf.keras.layers.GlobalAveragePooling1D()(embedding_layer)
  dense_layer = tf.keras.layers.Dense(16, activation='relu')(pooling_layer)
  outputs = tf.keras.layers.Dense(1, activation='sigmoid')(dense_layer)
  return tf.keras.Model(inputs=inputs, outputs=outputs)


def make_bilstm_model():
  """Builds a bi-directional LSTM model."""
  inputs = tf.keras.Input(
      shape=(HPARAMS.max_seq_length,), dtype='int64', name='words')
  embedding_layer = tf.keras.layers.Embedding(HPARAMS.vocab_size,
                                              HPARAMS.num_embedding_dims)(
                                                  inputs)
  lstm_layer = tf.keras.layers.Bidirectional(
      tf.keras.layers.LSTM(HPARAMS.num_lstm_dims))(
          embedding_layer)
  dense_layer = tf.keras.layers.Dense(
      HPARAMS.num_fc_units, activation='relu')(
          lstm_layer)
  outputs = tf.keras.layers.Dense(1, activation='sigmoid')(dense_layer)
  return tf.keras.Model(inputs=inputs, outputs=outputs)


# Feel free to use an architecture of your choice.
model = make_bilstm_model()
model.summary()
Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
words (InputLayer)           [(None, 256)]             0         
_________________________________________________________________
embedding (Embedding)        (None, 256, 16)           160000    
_________________________________________________________________
bidirectional (Bidirectional (None, 128)               41472     
_________________________________________________________________
dense (Dense)                (None, 64)                8256      
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 65        
=================================================================
Total params: 209,793
Trainable params: 209,793
Non-trainable params: 0
_________________________________________________________________

برای ساخت طبقه بندی ، لایه ها به طور موقت جمع شده اند:

  1. لایه اول یک لایه Input است که واژگان رمزگذاری شده عدد صحیح را به خود اختصاص می دهد.
  2. لایه بعدی یک لایه Embedding است که واژگان رمزگذاری شده عدد صحیح را در بر می گیرد و بردار تعبیه شده را برای هر شاخص کلمه جستجو می کند. این بردارها به عنوان آموزش مدل یاد می گیرند. بردارها ابعادی به آرایه خروجی اضافه می کنند. ابعاد حاصله عبارتند از: (batch, sequence, embedding) .
  3. در مرحله بعد ، یک لایه LSTM دو طرفه یک بردار خروجی با طول ثابت را برای هر نمونه برمی گرداند.
  4. این بردار خروجی با طول ثابت از طریق یک لایه کاملاً متصل ( Dense ) با 64 واحد مخفی لوله گذاری می شود.
  5. لایه آخر با یک گره خروجی متراکم متصل است. با استفاده از تابع فعال سازی sigmoid ، این مقدار یک شناور بین 0 و 1 است که یک احتمال یا سطح اطمینان را نشان می دهد.

واحدهای پنهان

مدل فوق دارای دو لایه میانی یا "پنهان" ، بین ورودی و خروجی و به جز لایه Embedding است. تعداد خروجی ها (واحد ها ، گره ها یا نورون ها) ابعاد فضای بازنمایی لایه است. به عبارت دیگر ، میزان آزادی شبکه هنگام یادگیری نمایندگی داخلی مجاز است.

اگر یک مدل واحدهای پنهان تر (فضای نمایشی با ابعاد بالاتر) و / یا لایه های بیشتری داشته باشد ، آنگاه شبکه می تواند بازنمایی های پیچیده تری را یاد بگیرد. با این حال ، این شبکه از لحاظ محاسباتی گرانتر عمل می کند و ممکن است منجر به یادگیری الگوهای ناخواسته شود - الگوهای بهبود عملکرد داده های آموزش اما نه بر روی داده های آزمون. به این کار اضافه کردن اضافه می گویند .

عملکرد و بهینه ساز از دست دادن

یک مدل به یک عملکرد ضرر و بهینه ساز برای آموزش نیاز دارد. از آنجا که این یک مشکل طبقه بندی باینری است و مدل یک احتمال را می دهد (یک لایه تک واحدی با فعال سازی سیگموئید) ، ما از تابع از دست دادن binary_crossentropy استفاده binary_crossentropy .

model.compile(
    optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

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

هنگام آموزش ، می خواهیم صحت مدل را در داده هایی که قبلاً دیده نشده است ، بررسی کنیم. با جدا کردن بخشی از داده های آموزش اصلی ، یک مجموعه اعتبار سنجی ایجاد کنید . (چرا اکنون از مجموعه تست استفاده نمی کنیم؟ هدف ما این است که فقط با استفاده از داده های آموزش ، مدل خود را توسعه داده و تنظیم کنیم ، سپس فقط یک بار از داده های آزمون استفاده کنیم تا دقت خود را ارزیابی کنیم).

در این آموزش ، تقریباً 10٪ نمونه های آموزش اولیه (10٪ از 25000) را به عنوان داده های برچسب برای آموزش و مابقی به عنوان داده های اعتبار سنجی می گیریم. از آنجا که تقسیم قطار / تست اولیه 50/50 بود (هر نمونه 25000 نمونه) ، تقسیم قطار / اعتبار سنجی / تست مؤثر که اکنون داریم 5/45/50 است.

توجه داشته باشید که "train_dataset" قبلاً دسته بندی شده و تغییر یافته است.

validation_fraction = 0.9
validation_size = int(validation_fraction *
                      int(training_samples_count / HPARAMS.batch_size))
print(validation_size)
validation_dataset = train_dataset.take(validation_size)
train_dataset = train_dataset.skip(validation_size)
175

آموزش مدل

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

history = model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=HPARAMS.train_epochs,
    verbose=1)
Epoch 1/10

/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py:543: UserWarning: Input dict contained keys ['NL_nbr_0_words', 'NL_nbr_1_words', 'NL_nbr_0_weight', 'NL_nbr_1_weight'] which did not match any model input. They will be ignored by the model.
  [n for n in tensors.keys() if n not in ref_input_names])

21/21 [==============================] - 19s 917ms/step - loss: 0.6930 - accuracy: 0.5081 - val_loss: 0.6924 - val_accuracy: 0.5518
Epoch 2/10
21/21 [==============================] - 18s 878ms/step - loss: 0.6902 - accuracy: 0.5319 - val_loss: 0.6587 - val_accuracy: 0.6465
Epoch 3/10
21/21 [==============================] - 18s 879ms/step - loss: 0.6338 - accuracy: 0.6731 - val_loss: 0.5882 - val_accuracy: 0.7310
Epoch 4/10
21/21 [==============================] - 18s 872ms/step - loss: 0.4889 - accuracy: 0.7854 - val_loss: 0.4445 - val_accuracy: 0.8047
Epoch 5/10
21/21 [==============================] - 18s 872ms/step - loss: 0.3911 - accuracy: 0.8369 - val_loss: 0.3870 - val_accuracy: 0.8352
Epoch 6/10
21/21 [==============================] - 18s 877ms/step - loss: 0.3544 - accuracy: 0.8542 - val_loss: 0.3420 - val_accuracy: 0.8571
Epoch 7/10
21/21 [==============================] - 19s 900ms/step - loss: 0.3262 - accuracy: 0.8700 - val_loss: 0.3135 - val_accuracy: 0.8762
Epoch 8/10
21/21 [==============================] - 18s 871ms/step - loss: 0.2770 - accuracy: 0.8977 - val_loss: 0.2739 - val_accuracy: 0.8923
Epoch 9/10
21/21 [==============================] - 18s 872ms/step - loss: 0.2863 - accuracy: 0.8958 - val_loss: 0.2703 - val_accuracy: 0.8942
Epoch 10/10
21/21 [==============================] - 18s 875ms/step - loss: 0.2232 - accuracy: 0.9150 - val_loss: 0.2543 - val_accuracy: 0.9037

مدل را ارزیابی کنید

حال ، بیایید ببینیم مدل چگونه عمل می کند. دو مقدار بازگردانده می شوند. ضرر (عددی که نشان دهنده خطای ما است ، مقادیر پایین بهتر هستند) و دقت.

results = model.evaluate(test_dataset, steps=HPARAMS.eval_steps)
print(results)
196/196 [==============================] - 16s 82ms/step - loss: 0.3748 - accuracy: 0.8500
[0.37483155727386475, 0.8500000238418579]

با گذشت زمان ، نمودار دقت / اتلاف را ایجاد کنید

model.fit() یک مورد History را که شامل یک فرهنگ لغت است با همه اتفاقاتی که در طول آموزش رخ داده است برمی گرداند:

history_dict = history.history
history_dict.keys()
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

چهار مدخل وجود دارد: یکی برای هر متریک نظارت شده در طول آموزش و اعتبار سنجی. ما می توانیم از اینها برای ترسیم آموزش و از دست دادن اعتبار سنجی برای مقایسه و همچنین آموزش و صحت اعتبار استفاده کنیم:

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "-r^" is for solid red line with triangle markers.
plt.plot(epochs, loss, '-r^', label='Training loss')
# "-b0" is for solid blue line with circle markers.
plt.plot(epochs, val_loss, '-bo', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend(loc='best')

plt.show()

png

plt.clf()   # clear figure

plt.plot(epochs, acc, '-r^', label='Training acc')
plt.plot(epochs, val_acc, '-bo', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='best')

plt.show()

png

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

تنظیم نمودار

اکنون ما آماده هستیم تا با استفاده از الگوی پایه ای که در بالا ساخته ایم ، مرتب سازی نمودار را امتحان کنیم. ما از بسته بندی بسته بندی GraphRegularization که توسط چارچوب یادگیری ساختاری عصبی تهیه شده است استفاده خواهیم کرد تا مدل پایه (bi-LSTM) را بپیچید تا شامل تنظیم منظم نمودار شود. بقیه مراحل آموزش و ارزیابی مدل تنظیم شده نمودار مانند مدل پایه است.

یک مدل منظم نمودار ایجاد کنید

برای ارزیابی سود افزایشی از تنظیم نمودار ، نمونه ای از مدل پایه جدید را ایجاد خواهیم کرد. دلیل این امر این است که model در حال حاضر برای چند تکرار آموزش داده شده است ، و استفاده مجدد از این مدل آموزش دیده برای ایجاد یک مدل منظم از نمودار ، مقایسه ای عادلانه برای model نخواهد بود.

# Build a new base LSTM model.
base_reg_model = make_bilstm_model()
# Wrap the base model with graph regularization.
graph_reg_config = nsl.configs.make_graph_reg_config(
    max_neighbors=HPARAMS.num_neighbors,
    multiplier=HPARAMS.graph_regularization_multiplier,
    distance_type=HPARAMS.distance_type,
    sum_over_axis=-1)
graph_reg_model = nsl.keras.GraphRegularization(base_reg_model,
                                                graph_reg_config)
graph_reg_model.compile(
    optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

آموزش مدل

graph_reg_history = graph_reg_model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=HPARAMS.train_epochs,
    verbose=1)
Epoch 1/10

/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/framework/indexed_slices.py:432: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.
  "Converting sparse IndexedSlices to a dense Tensor of unknown shape. "

21/21 [==============================] - 22s 1s/step - loss: 0.6925 - accuracy: 0.5135 - scaled_graph_loss: 7.8682e-06 - val_loss: 0.6925 - val_accuracy: 0.5207
Epoch 2/10
21/21 [==============================] - 22s 1s/step - loss: 0.6902 - accuracy: 0.5373 - scaled_graph_loss: 2.3502e-05 - val_loss: 0.6591 - val_accuracy: 0.6627
Epoch 3/10
21/21 [==============================] - 21s 981ms/step - loss: 0.6376 - accuracy: 0.6942 - scaled_graph_loss: 0.0028 - val_loss: 0.6867 - val_accuracy: 0.5343
Epoch 4/10
21/21 [==============================] - 20s 975ms/step - loss: 0.6240 - accuracy: 0.7031 - scaled_graph_loss: 9.6606e-04 - val_loss: 0.5891 - val_accuracy: 0.7572
Epoch 5/10
21/21 [==============================] - 20s 973ms/step - loss: 0.5111 - accuracy: 0.7896 - scaled_graph_loss: 0.0059 - val_loss: 0.4260 - val_accuracy: 0.8207
Epoch 6/10
21/21 [==============================] - 21s 981ms/step - loss: 0.3816 - accuracy: 0.8508 - scaled_graph_loss: 0.0157 - val_loss: 0.3182 - val_accuracy: 0.8682
Epoch 7/10
21/21 [==============================] - 20s 976ms/step - loss: 0.3488 - accuracy: 0.8704 - scaled_graph_loss: 0.0202 - val_loss: 0.3156 - val_accuracy: 0.8749
Epoch 8/10
21/21 [==============================] - 20s 973ms/step - loss: 0.3227 - accuracy: 0.8815 - scaled_graph_loss: 0.0198 - val_loss: 0.2746 - val_accuracy: 0.8932
Epoch 9/10
21/21 [==============================] - 21s 1s/step - loss: 0.3058 - accuracy: 0.8958 - scaled_graph_loss: 0.0220 - val_loss: 0.2938 - val_accuracy: 0.8833
Epoch 10/10
21/21 [==============================] - 21s 979ms/step - loss: 0.2789 - accuracy: 0.9008 - scaled_graph_loss: 0.0233 - val_loss: 0.2622 - val_accuracy: 0.8981

مدل را ارزیابی کنید

graph_reg_results = graph_reg_model.evaluate(test_dataset, steps=HPARAMS.eval_steps)
print(graph_reg_results)
196/196 [==============================] - 16s 82ms/step - loss: 0.3543 - accuracy: 0.8508
[0.354336142539978, 0.8507599830627441]

با گذشت زمان ، نمودار صحیح و ضروری ایجاد کنید

graph_reg_history_dict = graph_reg_history.history
graph_reg_history_dict.keys()
dict_keys(['loss', 'accuracy', 'scaled_graph_loss', 'val_loss', 'val_accuracy'])

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

acc = graph_reg_history_dict['accuracy']
val_acc = graph_reg_history_dict['val_accuracy']
loss = graph_reg_history_dict['loss']
graph_loss = graph_reg_history_dict['scaled_graph_loss']
val_loss = graph_reg_history_dict['val_loss']

epochs = range(1, len(acc) + 1)

plt.clf()   # clear figure

# "-r^" is for solid red line with triangle markers.
plt.plot(epochs, loss, '-r^', label='Training loss')
# "-gD" is for solid green line with diamond markers.
plt.plot(epochs, graph_loss, '-gD', label='Training graph loss')
# "-b0" is for solid blue line with circle markers.
plt.plot(epochs, val_loss, '-bo', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend(loc='best')

plt.show()

png

plt.clf()   # clear figure

plt.plot(epochs, acc, '-r^', label='Training acc')
plt.plot(epochs, val_acc, '-bo', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='best')

plt.show()

png

قدرت یادگیری نیمه نظارت

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

ما نسبت نظارت را به عنوان نسبت نمونه های آموزشی به تعداد کل نمونه ها تعریف می کنیم که شامل آموزش ، اعتبار سنجی و نمونه آزمون است. در این نوت بوک ، از یک نسبت نظارت از 0.05 (یعنی 5٪ از داده های برچسب خورده) برای آموزش هم مدل پایه و هم برای مدل تنظیم شده نمودار استفاده کرده ایم. ما تاثیر نسبت نظارت بر دقت مدل در سلول زیر را نشان می دهیم.

# Accuracy values for both the Bi-LSTM model and the feed forward NN model have
# been precomputed for the following supervision ratios.

supervision_ratios = [0.3, 0.15, 0.05, 0.03, 0.02, 0.01, 0.005]

model_tags = ['Bi-LSTM model', 'Feed Forward NN model']
base_model_accs = [[84, 84, 83, 80, 65, 52, 50], [87, 86, 76, 74, 67, 52, 51]]
graph_reg_model_accs = [[84, 84, 83, 83, 65, 63, 50],
                        [87, 86, 80, 75, 67, 52, 50]]

plt.clf()  # clear figure

fig, axes = plt.subplots(1, 2)
fig.set_size_inches((12, 5))

for ax, model_tag, base_model_acc, graph_reg_model_acc in zip(
    axes, model_tags, base_model_accs, graph_reg_model_accs):

  # "-r^" is for solid red line with triangle markers.
  ax.plot(base_model_acc, '-r^', label='Base model')
  # "-gD" is for solid green line with diamond markers.
  ax.plot(graph_reg_model_acc, '-gD', label='Graph-regularized model')
  ax.set_title(model_tag)
  ax.set_xlabel('Supervision ratio')
  ax.set_ylabel('Accuracy(%)')
  ax.set_ylim((25, 100))
  ax.set_xticks(range(len(supervision_ratios)))
  ax.set_xticklabels(supervision_ratios)
  ax.legend(loc='best')

plt.show()
<Figure size 432x288 with 0 Axes>

png

می توان مشاهده کرد که با افزایش نسبت فوق العاده ، دقت مدل نیز کاهش می یابد. این هم برای مدل پایه و هم برای مدل منظم نمودار ، صرف نظر از معماری مدل مورد استفاده صحیح است. با این حال ، توجه داشته باشید که مدل منظم نمودار عملکرد خوبی نسبت به مدل پایه برای هر دو معماری دارد. به طور خاص ، برای مدل Bi-LSTM ، هنگامی که نسبت نظارت 0.01 باشد ، دقت مدل تنظیم شده نمودار 20 ~ بالاتر از مدل پایه است. این امر در درجه اول به دلیل یادگیری نیمه نظارت برای مدل تنظیم شده نمودار است ، که در آن از شباهت ساختاری در بین نمونه های آموزش علاوه بر نمونه های آموزش استفاده می شود.

نتیجه

ما استفاده از تنظیم منظم نمودار را با استفاده از چارچوب یادگیری ساختاری عصبی (NSL) نشان داده ایم حتی وقتی ورودی حاوی یک نمودار مشخص نباشد. ما وظیفه طبقه بندی احساسات از بررسی های فیلم IMDB را در نظر گرفتیم که برای آن یک نمودار شباهت را بر اساس تعبیه های نقد شده سنتز کردیم. ما کاربران را ترغیب می کنیم تا با استفاده از پارامترهای مختلف ، میزان نظارت و با استفاده از معماریهای مدلهای مختلف ، آزمایش بیشتری انجام دهند.