Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

Sentezlenmiş grafikler kullanarak duyarlılık sınıflandırması için grafik düzenlenmesi

TensorFlow.org üzerinde görüntüle Google Colab'da yayınla Kaynağı GitHub'da görüntüle

genel bakış

Bu not defteri, incelemenin metnini kullanarak film incelemelerini pozitif veya negatif olarak sınıflandırır. Bu, önemli ve yaygın olarak uygulanabilir bir makine öğrenimi problemi olan ikili sınıflandırma örneğidir.

Belirtilen girişten bir grafik oluşturarak bu not defterinde grafik düzeninin kullanımını göstereceğiz. Girdi açık bir grafik içermiyorsa Nöral Yapısal Öğrenme (NSL) çerçevesini kullanarak grafik düzenli bir model oluşturmak için genel tarif aşağıdaki gibidir:

  1. Girdideki her bir metin örneği için düğün oluşturun. Bu, word2vec , Swivel , BERT gibi önceden eğitilmiş modeller kullanılarak yapılabilir.
  2. 'L2' mesafesi, 'kosinüs mesafesi' gibi bir benzerlik metriği kullanarak bu düğünlere dayanan bir grafik oluşturun. Grafikteki düğümler örneklere karşılık gelir ve grafikteki kenarlar örnek çiftleri arasındaki benzerliğe karşılık gelir.
  3. Yukarıdaki sentezlenmiş grafik ve örnek özelliklerden antrenman verileri oluşturun. Ortaya çıkan eğitim verileri, orijinal düğüm özelliklerine ek olarak komşu özellikleri de içerecektir.
  4. Keras sıralı, işlevsel veya alt sınıf API'sını kullanarak temel model olarak bir sinir ağı oluşturun.
  5. Yeni bir grafik Keras modeli oluşturmak için, temel modeli NSL çerçevesi tarafından sağlanan GraphRegularization sarmalayıcı sınıfıyla sarın. Bu yeni model, eğitim hedefinde normalleştirme terimi olarak bir grafik normalleştirme kaybını içerecektir.
  6. Grafik Keras modelini eğitin ve değerlendirin.

Gereksinimler

  1. Nöral Yapılandırılmış Öğrenme paketini yükleyin.
  2. Tensorflow-hub'ı takın.
pip install --quiet neural-structured-learning
pip install --quiet tensorflow-hub

Bağımlılıklar ve ithalat

 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 veri kümesi

IMDB veri kümesi , İnternet Film Veritabanı'ndan 50.000 film incelemesi metni içerir. Bunlar eğitim için 25.000 incelemeye ve test için 25.000 incelemeye ayrılmıştır. Eğitim ve test setleri dengelidir , yani eşit sayıda olumlu ve olumsuz yorum içerirler.

Bu öğreticide, IMDB veri kümesinin önceden işlenmiş bir sürümünü kullanacağız.

Önceden işlenmiş IMDB veri kümesini indir

IMDB veri kümesi TensorFlow ile birlikte gelir. İncelemeler (kelime dizileri) tamsayı dizilerine dönüştürülecek şekilde önceden işlenmiştir, burada her tamsayı sözlükte belirli bir kelimeyi temsil eder.

Aşağıdaki kod IMDB veri kümesini indirir (veya önceden indirilmişse önbelleğe alınmış bir kopya kullanır):

 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 bağımsız değişkeni, eğitim verilerinde en sık görülen 10.000 kelimeyi tutar. Kelimelerin boyutunu yönetilebilir tutmak için nadir kelimeler atılır.

Verileri keşfedin

Verilerin biçimini anlayalım. Veri kümesi önceden işlenmiş olarak gelir: her örnek, film incelemesinin sözcüklerini temsil eden bir tamsayı dizisidir. Her etiket, 0 veya 1 olan bir tamsayı değeridir; burada 0, negatif bir incelemedir ve 1, olumlu bir incelemedir.

 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

Yorum metni tamsayılara dönüştürülmüştür, burada her tamsayı sözlükteki belirli bir kelimeyi temsil eder. İlk inceleme şöyle görünüyor:

 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]

Film incelemeleri farklı uzunluklarda olabilir. Aşağıdaki kod, birinci ve ikinci incelemelerdeki kelime sayısını gösterir. Bir sinir ağına girişler aynı uzunlukta olması gerektiğinden, bunu daha sonra çözmemiz gerekecek.

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

Tam sayıları kelimelere geri çevirin

Tamsayıların karşılık gelen metne nasıl dönüştürüleceğini bilmek faydalı olabilir. Burada, dize eşlemesinin tamsayısını içeren bir sözlük nesnesini sorgulamak için bir yardımcı işlev oluşturacağız:

 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

Şimdi ilk inceleme için metni görüntülemek üzere decode_review işlevini kullanabiliriz:

 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"

Grafik yapısı

Grafik yapısı, metin örnekleri için süslemeler oluşturmayı ve ardından düğünleri karşılaştırmak için bir benzerlik işlevi kullanmayı içerir.

Devam etmeden önce, bu eğitici tarafından oluşturulan eserleri saklamak için bir dizin oluşturuyoruz.

mkdir -p /tmp/imdb

Örnek düğünler oluşturun

tf.train.Example her örnek için tf.train.Example biçiminde tf.train.Example oluşturmak için önceden eğitilmiş Döner düğmeler kullanacağız. Ortaya çıkan TFRecord , her örneğin kimliğini temsil eden ek bir özellik ile birlikte TFRecord biçiminde TFRecord . Bu önemlidir ve daha sonra grafikteki karşılık gelen düğümlerle örnek düğünleri eşleştirmemize izin verecektir.

 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

Bir grafik oluşturun

Şimdi örnek düğünlere sahip olduğumuza göre, bunları benzerlik grafiği oluşturmak için kullanacağız, yani, bu grafikteki düğümler örneklere karşılık gelecek ve bu grafikteki kenarlar düğüm çiftleri arasındaki benzerliğe karşılık gelecektir.

Sinir Yapısal Öğrenme, örnek düğünlere dayalı bir grafik oluşturmak için bir grafik oluşturma kütüphanesi sağlar. Düğünleri karşılaştırmak ve aralarında kenarlar oluşturmak için benzerlik ölçüsü olarak kosinüs benzerliğini kullanır. Aynı zamanda, son grafikten farklı kenarları atmak için kullanılabilecek bir benzerlik eşiği belirlememize izin verir. Bu örnekte, benzerlik eşiği olarak 0,99'u kullanarak, 445,327 çift yönlü kenara sahip bir grafik elde ediyoruz.

 nsl.tools.build_graph(['/tmp/imdb/embeddings.tfr'],
                      '/tmp/imdb/graph_99.tsv',
                      similarity_threshold=0.99)
 

Örnek özellikler

tf.train.Example biçimini kullanarak sorunumuz için örnek özellikler oluşturuyoruz ve bunları tf.train.Example biçiminde devam TFRecord . Her örnek aşağıdaki üç özelliği içerecektir:

  1. id : Örneğin düğüm kimliği.
  2. words : Kelime kimlikleri içeren bir int64 listesi.
  3. label : İncelemenin hedef sınıfını tanımlayan bir 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

Grafik komşularıyla eğitim verilerini çoğaltın

Örnek özelliklere ve sentezlenmiş grafiğe sahip olduğumuzdan, Nöral Yapılandırılmış Öğrenme için artırılmış eğitim verilerini üretebiliriz. NSL çerçevesi, grafik düzenleme için son eğitim verilerini üretmek üzere grafiği ve örnek özellikleri birleştirmek için bir kütüphane sağlar. Ortaya çıkan eğitim verileri, orijinal örnek özelliklerini ve ilgili komşularının özelliklerini içerecektir.

Bu eğitimde, yönlendirilmemiş kenarları dikkate alıyoruz ve grafik komşularıyla eğitim verilerini artırmak için örnek başına maksimum 3 komşu kullanıyoruz.

 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)
 

Temel model

Artık grafik düzenlemesiz bir temel model oluşturmaya hazırız. Bu modeli oluşturmak için, grafiği oluştururken kullanılan düğünleri kullanabiliriz veya sınıflandırma göreviyle birlikte yeni düğünleri öğrenebiliriz. Bu dizüstü bilgisayarın amacı için, ikincisini yapacağız.

Global değişkenler

 NBR_FEATURE_PREFIX = 'NL_nbr_'
NBR_WEIGHT_SUFFIX = '_weight'
 

Hyperparameters

Eğitim ve değerlendirme için kullanılan çeşitli hiperparametreleri ve sabitleri HParams için bir HParams örneği kullanacağız. Her birini aşağıda kısaca açıklıyoruz:

  • num_classes : Pozitif ve negatif olmak üzere 2 sınıf vardır.

  • max_seq_length : Bu, bu örnekteki her film incelemesinde ele alınan maksimum kelime sayısıdır.

  • vocab_size : Bu, bu örnek için dikkate alınan kelime dağarcığının boyutudur.

  • distance_type : Bu, örneği komşularıyla düzenli hale getirmek için kullanılan mesafe metriğidir.

  • graph_regularization_multiplier : Genel kayıp fonksiyonundaki grafik düzenleme teriminin göreli ağırlığını kontrol eder.

  • num_neighbors : Grafik düzenleme için kullanılan komşu sayısı. max_nbrs çağrılırken bu nsl.tools.pack_nbrs yukarıda kullanılan max_nbrs bağımsız değişkeninden küçük veya ona eşit olması nsl.tools.pack_nbrs .

  • num_fc_units : Sinir ağının tamamen bağlı katmanındaki birim sayısı.

  • train_epochs : Eğitim dönemi sayısı.

  • batch_size : Eğitim ve değerlendirme için kullanılan parti büyüklüğü.

  • eval_steps : Değerlendirme tamamlanmadan önce işlenecek parti sayısı. None ayarlanırsa, test setindeki tüm örnekler değerlendirilir.

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

Verileri hazırlayın

İncelemeler - tamsayı dizileri - sinir ağına beslenmeden önce tensörlere dönüştürülmelidir. Bu dönüşüm birkaç yolla yapılabilir:

  • Dizileri, bir sıcak kodlamaya benzer şekilde, sözcük oluşumunu gösteren 0 ve 1 sn vektörlere dönüştürün. Örneğin, [3, 5] sekansı [3, 5] endeks 3 ve 5 hariç hepsi sıfır olan 10000 boyutlu bir vektör haline gelecektir. Ardından, bunu ağımızdaki kayan nokta vektör verilerini işleyebilen ilk katman olan Dense katman haline getirin. Bu yaklaşım bellek yoğun olsa da, bir num_words * num_reviews boyut matrisi gerektirir.

  • Alternatif olarak, dizilerin tümünü aynı uzunlukta olacak şekilde max_length * num_reviews , ardından max_length * num_reviews şeklinde bir tamsayı tensörü oluşturabiliriz. Bu şekli ağımızdaki ilk katman olarak işleyebilen bir gömme katmanı kullanabiliriz.

Bu derste ikinci yaklaşımı kullanacağız.

Film incelemeleri aynı uzunlukta olması gerektiğinden, uzunlukları standartlaştırmak için aşağıda tanımlanan pad_sequence işlevini kullanacağız.

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

Modeli oluşturun

Katmanları istifleyerek bir sinir ağı oluşturulur - bu iki ana mimari karar gerektirir:

  • Modelde kaç katman kullanılır?
  • Her katman için kaç gizli birim kullanılır?

Bu örnekte, giriş verileri bir dizi kelime indeksinden oluşur. Tahmin edilecek etiketler 0 veya 1'dir.

Bu derste temel modelimiz olarak iki yönlü bir LSTM kullanacağız.

 # 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
_________________________________________________________________

Katmanlar, sınıflandırıcıyı oluşturmak için etkili bir şekilde ardışık olarak istiflenir:

  1. İlk katman, tamsayı kodlanmış kelimeleri alan bir Input katmanıdır.
  2. Bir sonraki katman, tamsayı olarak kodlanmış kelimeleri alan ve her bir sözcük dizini için gömme vektörünü arayan bir Embedding katmanıdır. Bu vektörler model tren olarak öğrenilir. Vektörler çıkış dizisine bir boyut ekler. Ortaya çıkan boyutlar: (batch, sequence, embedding) .
  3. Daha sonra, çift yönlü bir LSTM katmanı, her örnek için sabit uzunlukta bir çıkış vektörü döndürür.
  4. Bu sabit uzunluktaki çıkış vektörü, 64 gizli birim içeren tam bağlı ( Dense ) bir katmandan geçirilir.
  5. Son katman, tek bir çıkış düğümü ile yoğun bir şekilde bağlanır. sigmoid aktivasyon fonksiyonunu kullanarak, bu değer bir olasılığı veya güven seviyesini temsil eden 0 ile 1 arasında bir kayan değerdir.

Gizli birimler

Yukarıdaki model, giriş ve çıkış arasında ve Embedding katmanı hariç olmak üzere iki ara veya "gizli" katmana sahiptir. Çıktıların sayısı (birimler, düğümler veya nöronlar) katman için temsil boşluğunun boyutudur. Başka bir deyişle, dahili bir temsili öğrenirken ağa izin verilen özgürlük miktarı.

Bir model daha gizli birimlere (daha yüksek boyutlu bir gösterim alanı) ve / veya daha fazla katmana sahipse, ağ daha karmaşık sunumları öğrenebilir. Bununla birlikte, ağı daha hesaplama açısından pahalı hale getirir ve istenmeyen veriler öğrenmeye yol açabilir - eğitim verilerinde performansı artıran ancak test verilerinde olmayan desenler. Buna aşırı takma denir.

Kayıp fonksiyonu ve optimize edici

Bir modelin bir kayıp fonksiyonuna ve eğitim için bir optimize ediciye ihtiyacı vardır. Bu bir ikili sınıflandırma problemi olduğundan ve model bir olasılık (sigmoid aktivasyonlu tek üniteli bir katman) binary_crossentropy , binary_crossentropy kayıp fonksiyonunu kullanacağız.

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

Doğrulama kümesi oluşturma

Egzersiz yaparken, modelin daha önce görmediği veriler üzerindeki doğruluğunu kontrol etmek istiyoruz. Orijinal egzersiz verilerinin bir kısmını ayırarak bir doğrulama kümesi oluşturun. (Neden şimdi test setini kullanmıyorsunuz? Amacımız modelimizi sadece eğitim verilerini kullanarak geliştirmek ve ayarlamak, ardından doğruluğumuzu değerlendirmek için test verilerini sadece bir kez kullanmaktır).

Bu derste, başlangıç ​​eğitim örneklerinin kabaca% 10'unu (25000'in% 10'u) eğitim için etiketlenmiş veriler ve geri kalanını da doğrulama verileri olarak ele alıyoruz. İlk tren / test bölümü 50/50 (her biri 25000 örnek) olduğundan, şu anda elimizde olan etkili tren / validasyon / test bölümü 5/45/50'dir.

'Train_dataset' öğesinin zaten toplu ve karışık olduğunu unutmayın.

 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

Modeli eğitin

Modeli mini gruplar halinde eğitin. Egzersiz yaparken, modelin doğrulama kümesindeki kaybını ve doğruluğunu izleyin:

 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 925ms/step - loss: 0.6930 - accuracy: 0.5092 - val_loss: 0.6924 - val_accuracy: 0.5006
Epoch 2/10
21/21 [==============================] - 19s 894ms/step - loss: 0.6890 - accuracy: 0.5465 - val_loss: 0.7294 - val_accuracy: 0.5698
Epoch 3/10
21/21 [==============================] - 19s 883ms/step - loss: 0.6785 - accuracy: 0.6208 - val_loss: 0.6489 - val_accuracy: 0.7043
Epoch 4/10
21/21 [==============================] - 19s 890ms/step - loss: 0.6592 - accuracy: 0.6400 - val_loss: 0.6523 - val_accuracy: 0.6866
Epoch 5/10
21/21 [==============================] - 19s 883ms/step - loss: 0.6413 - accuracy: 0.6923 - val_loss: 0.6335 - val_accuracy: 0.7004
Epoch 6/10
21/21 [==============================] - 21s 982ms/step - loss: 0.6053 - accuracy: 0.7188 - val_loss: 0.5716 - val_accuracy: 0.7183
Epoch 7/10
21/21 [==============================] - 18s 879ms/step - loss: 0.5204 - accuracy: 0.7619 - val_loss: 0.4511 - val_accuracy: 0.7930
Epoch 8/10
21/21 [==============================] - 19s 882ms/step - loss: 0.4719 - accuracy: 0.7758 - val_loss: 0.4244 - val_accuracy: 0.8094
Epoch 9/10
21/21 [==============================] - 18s 880ms/step - loss: 0.3695 - accuracy: 0.8431 - val_loss: 0.3567 - val_accuracy: 0.8487
Epoch 10/10
21/21 [==============================] - 19s 891ms/step - loss: 0.3504 - accuracy: 0.8500 - val_loss: 0.3219 - val_accuracy: 0.8652

Modeli değerlendirin

Şimdi modelin nasıl performans gösterdiğini görelim. İki değer döndürülecektir. Kayıp (hatamızı temsil eden bir sayı, daha düşük değerler daha iyidir) ve doğruluk.

 results = model.evaluate(test_dataset, steps=HPARAMS.eval_steps)
print(results)
 
196/196 [==============================] - 17s 85ms/step - loss: 0.4116 - accuracy: 0.8221
[0.4116455018520355, 0.8221200108528137]

Zaman içinde doğruluk / kayıp grafiği oluşturma

model.fit() , eğitim sırasında olan her şeyi içeren bir sözlük içeren bir History nesnesi döndürür:

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

Dört giriş vardır: eğitim ve doğrulama sırasında izlenen her metrik için bir giriş. Bunları eğitim ve validasyon kaybını karşılaştırma için ve eğitim ve validasyon doğruluğunu çizmek için kullanabiliriz:

 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

Her çağda egzersiz kaybının azaldığına ve her çağda egzersiz doğruluğunun arttığına dikkat edin. Degrade iniş optimizasyonu kullanılırken bu beklenir - her yinelemede istenen miktarı en aza indirmelidir.

Grafik düzenleme

Şimdi, yukarıda oluşturduğumuz temel modeli kullanarak grafik düzenlemeyi denemeye hazırız. Grafik düzenlemeyi dahil etmek için temel (bi-LSTM) modeli sarmak için Nöral Yapılandırılmış Öğrenme çerçevesi tarafından sağlanan GraphRegularization sarmalayıcı sınıfını kullanacağız. Grafik düzenli modeli eğitim ve değerlendirme adımlarının geri kalanı temel modelinkine benzer.

Grafik düzenli model oluşturma

Grafik düzenlemenin artan faydasını değerlendirmek için yeni bir temel model örneği oluşturacağız. Bunun nedeni model zaten birkaç tekrarlamalar için eğitilmiş ve grafik-regularized model oluşturmak için bu eğitimli modeli yeniden kullanmak için adil bir karşılaştırma olmayacak 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'])
 

Modeli eğitin

 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.6930 - accuracy: 0.5246 - scaled_graph_loss: 2.9800e-06 - val_loss: 0.6929 - val_accuracy: 0.4998
Epoch 2/10
21/21 [==============================] - 21s 988ms/step - loss: 0.6909 - accuracy: 0.5200 - scaled_graph_loss: 7.8452e-06 - val_loss: 0.6838 - val_accuracy: 0.5917
Epoch 3/10
21/21 [==============================] - 21s 980ms/step - loss: 0.6656 - accuracy: 0.6277 - scaled_graph_loss: 6.1205e-04 - val_loss: 0.6591 - val_accuracy: 0.6905
Epoch 4/10
21/21 [==============================] - 21s 981ms/step - loss: 0.6395 - accuracy: 0.6846 - scaled_graph_loss: 0.0016 - val_loss: 0.5860 - val_accuracy: 0.7171
Epoch 5/10
21/21 [==============================] - 21s 980ms/step - loss: 0.5388 - accuracy: 0.7573 - scaled_graph_loss: 0.0043 - val_loss: 0.4910 - val_accuracy: 0.7844
Epoch 6/10
21/21 [==============================] - 21s 989ms/step - loss: 0.4105 - accuracy: 0.8281 - scaled_graph_loss: 0.0146 - val_loss: 0.3353 - val_accuracy: 0.8612
Epoch 7/10
21/21 [==============================] - 21s 986ms/step - loss: 0.3416 - accuracy: 0.8681 - scaled_graph_loss: 0.0203 - val_loss: 0.4134 - val_accuracy: 0.8209
Epoch 8/10
21/21 [==============================] - 21s 981ms/step - loss: 0.4230 - accuracy: 0.8273 - scaled_graph_loss: 0.0144 - val_loss: 0.4755 - val_accuracy: 0.7696
Epoch 9/10
21/21 [==============================] - 22s 1s/step - loss: 0.4905 - accuracy: 0.7950 - scaled_graph_loss: 0.0080 - val_loss: 0.3862 - val_accuracy: 0.8382
Epoch 10/10
21/21 [==============================] - 21s 978ms/step - loss: 0.3384 - accuracy: 0.8754 - scaled_graph_loss: 0.0215 - val_loss: 0.3002 - val_accuracy: 0.8811

Modeli değerlendirin

 graph_reg_results = graph_reg_model.evaluate(test_dataset, steps=HPARAMS.eval_steps)
print(graph_reg_results)
 
196/196 [==============================] - 16s 84ms/step - loss: 0.3852 - accuracy: 0.8301
[0.385225385427475, 0.830079972743988]

Zaman içinde doğruluk / kayıp grafiği oluşturma

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

Sözlükte toplam beş giriş bulunmaktadır: egzersiz kaybı, egzersiz doğruluğu, egzersiz grafiği kaybı, doğrulama kaybı ve doğrulama doğruluğu. Karşılaştırma için hepsini birlikte çizebiliriz. Grafik kaybının sadece egzersiz sırasında hesaplandığını unutmayın.

 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

Yarı denetimli öğrenmenin gücü

Yarı denetimli öğrenme ve daha özel olarak, bu öğretici bağlamında grafik düzenlenmesi, eğitim verisi miktarı az olduğunda gerçekten güçlü olabilir. Eğitim verilerinin eksikliği, geleneksel denetimli öğrenmede mümkün olmayan eğitim örnekleri arasındaki benzerliğin arttırılmasıyla telafi edilir.

Denetim oranını , eğitim örneklerinin eğitim, validasyon ve test örneklerini içeren toplam örnek sayısına oranı olarak tanımlarız. Bu not defterinde, hem temel modeli hem de grafik düzenli modeli eğitmek için 0,05 (yani etiketli verilerin% 5'i) denetim oranını kullandık. Denetim oranının aşağıdaki hücrede model doğruluğu üzerindeki etkisini gösteririz.

 # 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

Süpersizyon oranı azaldıkça model doğruluğunun da azaldığı gözlenebilir. Bu, kullanılan model mimarisine bakılmaksızın, hem temel model hem de grafik düzenli model için geçerlidir. Ancak, grafik düzenli modelin her iki mimaride de temel modelden daha iyi performans gösterdiğine dikkat edin. Özellikle, Bi-LSTM modeli için, denetim oranı 0.01 olduğunda, grafikle düzenlenmiş modelin doğruluğu, temel modelinkinden ~% 20 daha yüksektir. Bunun başlıca nedeni, eğitim örneklerinin yanı sıra eğitim örnekleri arasında yapısal benzerliğin kullanıldığı grafik düzenli model için yarı denetimli öğrenmedir.

Sonuç

Girdi açık bir grafik içermiyor olsa bile, Nöral Yapısal Öğrenme (NSL) çerçevesini kullanarak grafik normalleştirmenin kullanımını gösterdik. İnceleme düğünlerine dayalı bir benzerlik grafiği sentezlediğimiz IMDB film incelemelerinin duyarlı sınıflandırma görevini düşündük. Farklı hiperparametreler, denetim miktarı ve farklı model mimarileri kullanarak kullanıcıları daha fazla denemeye teşvik ediyoruz.