![]() | ![]() | ![]() |
Genel Bakış
Bu not defteri, inceleme metnini kullanarak film incelemelerini olumlu veya olumsuz olarak sınıflandırır. Bu, önemli ve yaygın olarak uygulanabilen bir makine öğrenimi problemi olan ikili sınıflandırma örneğidir.
Verilen girdiden bir grafik oluşturarak bu not defterinde grafik düzenleme kullanımını göstereceğiz. Giriş açık bir grafik içermediğinde, Sinirsel Yapılandırılmış Öğrenme (NSL) çerçevesini kullanarak grafiğe göre düzenlenmiş bir model oluşturmanın genel tarifi aşağıdaki gibidir:
- Girişteki her bir metin örneği için yerleştirmeler oluşturun. Bu, word2vec , Swivel , BERT vb. Gibi önceden eğitilmiş modeller kullanılarak yapılabilir.
- 'L2' mesafesi, 'kosinüs' mesafesi vb. Gibi bir benzerlik ölçüsü kullanarak bu yerleştirmelere dayalı 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.
- Yukarıdaki sentezlenmiş grafikten ve örnek özelliklerden eğitim verileri oluşturun. Elde edilen eğitim verileri, orijinal düğüm özelliklerine ek olarak komşu özellikleri de içerecektir.
- Keras sıralı, işlevsel veya alt sınıf API'sini kullanarak temel model olarak bir sinir ağı oluşturun.
- 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 düzenlenme terimi olarak bir grafik düzenleme kaybı içerecektir.
- Grafik Keras modelini eğitin ve değerlendirin.
Gereksinimler
- Sinirsel Yapılandırılmış Öğrenme paketini yükleyin.
- Tensorflow-hub'ı kurun.
pip install --quiet neural-structured-learning
pip install --quiet tensorflow-hub
Bağımlılıklar ve ithalatlar
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 incelemesinin metnini içerir. Bunlar, eğitim için 25.000 inceleme ve test için 25.000 incelemeye bölünmüştür. Eğitim ve test setleri dengelidir , yani eşit sayıda olumlu ve olumsuz inceleme içerirler.
Bu eğiticide, IMDB veri kümesinin önceden işlenmiş bir sürümünü kullanacağız.
Önceden işlenmiş IMDB veri kümesini indirin
IMDB veri kümesi, TensorFlow ile paketlenmiş olarak gelir. İncelemelerin (kelime dizileri), her bir tamsayının bir sözlükteki belirli bir sözcüğü temsil ettiği tam sayı dizilerine dönüştürüldüğü şekilde önceden işlenmiştir.
Aşağıdaki kod, IMDB veri kümesini indirir (veya önceden indirilmişse önbelleğe alınmış bir kopyayı 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. Kelime dağarcığının boyutunu yönetilebilir durumda tutmak için nadir kelimeler atılır.
Verileri keşfedin
Verinin formatını anlamak için biraz zaman ayıralım. Veri kümesi önceden işlenmiş olarak gelir: her örnek, film incelemesinin kelimelerini temsil eden bir tamsayı dizisidir. Her etiket, 0 veya 1 tamsayı değeridir; burada 0, olumsuz 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
İnceleme metni, her bir tamsayının sözlükteki belirli bir kelimeyi temsil ettiği tam sayılara dönüştürüldü. İ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 dönüştürün
Tam sayıların karşılık gelen metne nasıl dönüştürüleceğini bilmek faydalı olabilir. Burada, tamsayı ile dizgi eşlemesini 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 incelemenin metnini görüntülemek için 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 oluşturma, metin örnekleri için yerleştirmeler oluşturmayı ve ardından yerleştirmeleri karşılaştırmak için bir benzerlik işlevi kullanmayı içerir.
Daha fazla ilerlemeden önce, ilk olarak bu öğretici tarafından oluşturulan yapıları depolamak için bir dizin oluşturuyoruz.
mkdir -p /tmp/imdb
Örnek yerleştirmeler oluşturun
tf.train.Example
her örnek için tf.train.Example
biçiminde yerleştirmeler oluşturmak için önceden eğitilmiş Döner yerleştirmeleri kullanacağız. Ortaya çıkan yerleştirmeleri, her numunenin kimliğini temsil eden ek bir özellik ile birlikte TFRecord
formatında TFRecord
. Bu önemlidir ve örnek yerleştirmeleri daha sonra grafikteki karşılık gelen düğümlerle 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
Artık örnek yerleştirmelerimiz olduğuna göre, bunları bir 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.
Sinirsel Yapılandırılmış Öğrenme, örnek gömmelere dayalı bir grafik oluşturmak için bir grafik oluşturma kitaplığı 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ı çıkarmak için kullanılabilecek bir benzerlik eşiği belirlememize olanak tanır. Bu örnekte, benzerlik eşiği olarak 0.99 ve rastgele çekirdek olarak 12345 kullanarak, 429.415 çift yönlü kenarı olan bir grafik elde ediyoruz. Burada, grafik oluşturmayı hızlandırmak için grafik oluşturucunun yerellik duyarlı hashing (LSH) desteğini kullanıyoruz. Grafik oluşturucunun LSH desteğini kullanmayla ilgili ayrıntılar için build_graph_from_config
API belgelerine bakın.
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)
Her iki yönlü kenar, çıktı TSV dosyasında iki yönlendirilmiş kenarla temsil edilir, böylece dosya 429.415 * 2 = 858.830 toplam satır içerir:
wc -l /tmp/imdb/graph_99.tsv
858830 /tmp/imdb/graph_99.tsv
Örnek özellikler
tf.train.Example
formatını kullanarak problemimiz için örnek özellikler oluşturup bunları TFRecord
formatında TFRecord
. Her örnek aşağıdaki üç özelliği içerecektir:
- id : Örneğin düğüm kimliği.
- kelimeler : Kelime kimliklerini içeren bir int64 listesi.
- etiket : İncelemenin hedef sınıfını tanımlayan bir tekli 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ı ile eğitim verilerini artırın
Örnek özelliklere ve sentezlenmiş grafiğe sahip olduğumuz için, Sinirsel Yapılandırılmış Öğrenme için artırılmış eğitim verilerini oluşturabiliriz. NSL çerçevesi, grafiğin düzenlenmesi için son eğitim verilerini üretmek üzere grafiği ve örnek özellikleri birleştiren bir kitaplık sağlar. Elde edilen eğitim verileri, orijinal örnek özelliklerin yanı sıra karşılık gelen komşularının özelliklerini içerecektir.
Bu öğreticide, yönsüz kenarları ele 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üzenleme olmadan temel bir model oluşturmaya hazırız. Bu modeli oluşturmak için ya grafiğin oluşturulmasında kullanılan düğünleri kullanabiliriz ya da sınıflandırma görevi ile birlikte yeni yerleştirmeleri öğrenebiliriz. Bu defterin amacı için ikincisini yapacağız.
Global değişkenler
NBR_FEATURE_PREFIX = 'NL_nbr_'
NBR_WEIGHT_SUFFIX = '_weight'
Hiperparametreler
Biz bir örneğini kullanacak HParams
eğitim ve değerlendirme için kullanılan çeşitli hyperparameters ve sabitleri içermek. Her birini aşağıda kısaca açıklıyoruz:
sınıf_sayısı : 2 sınıf vardır - pozitif ve negatif .
max_seq_length : Bu, bu örnekteki her film incelemesinde dikkate alınan maksimum kelime sayısıdır.
kelime_boyutu : Bu, bu örnek için düşünülen kelime dağarcığının boyutudur.
mesafe_türü : Bu, numuneyi komşularıyla düzenlemek için kullanılan mesafe ölçüsüdür.
graph_regularization_multiplier : Bu, genel kayıp fonksiyonundaki grafik düzenleme teriminin göreli ağırlığını kontrol eder.
num_neighbors : Grafik düzenlenmesi için kullanılan komşuların sayısı. Bu değer,
max_nbrs
çağrılırken yukarıda kullanılanmax_nbrs
bağımsız değişkeninden küçük veya ona eşitnsl.tools.pack_nbrs
.num_fc_units : Sinir ağının tam olarak bağlı katmanındaki birimlerin sayısı.
train_epochs : Eğitim dönemi sayısı.
batch_size : Eğitim ve değerlendirme için kullanılan parti boyutu.
eval_steps : Değerlendirmenin tamamlandığını düşünmeden ö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üştürme birkaç şekilde yapılabilir:
Dizileri, tek sıcak kodlamaya benzer şekilde, kelime oluşumunu gösteren
0
ve1
s vektörlerine dönüştürün. Örneğin,[3, 5]
dizisi, birler olan3
ve5
indisleri dışında tümü sıfır olan10000
boyutlu bir vektör olacaktır. Ardından, bunu ağımızdaki kayan nokta vektör verilerini işleyebilen ilk katman (Dense
katman) yapın. Ancak bu yaklaşım, yoğun bellek gerektirir ve birnum_words * num_reviews
boyut matrisi gerektirir.Alternatif olarak, dizileri aynı uzunlukta olacak şekilde
max_length * num_reviews
, ardındanmax_length * num_reviews
şeklinde bir tamsayı tensörü oluşturabiliriz. Ağımızdaki ilk katman olarak bu şekli işleyebilen bir gömme katmanı kullanabiliriz.
Bu eğitimde ikinci yaklaşımı kullanacağız.
Film incelemelerinin 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
Bir sinir ağı, katmanların üst üste dizilmesiyle oluşturulur - bu, iki ana mimari karar gerektirir:
- Modelde kaç katman kullanılmalı?
- Her katman için kaç tane gizli birim kullanılacak?
Bu örnekte, giriş verileri bir dizi kelime indeksinden oluşur. Tahmin edilecek etiketler 0 veya 1'dir.
Bu eğitimde temel modelimiz olarak çift 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 sıralı olarak istiflenir:
- İlk katman, tamsayı ile kodlanmış kelimeleri alan bir
Input
katmanıdır. - Bir sonraki katman, tamsayı olarak kodlanmış kelimeleri alan ve her kelime dizini için gömme vektörünü arayan bir
Embedding
katmanıdır. Bu vektörler model trenler olarak öğrenilir. Vektörler, çıktı dizisine bir boyut ekler. Ortaya çıkan boyutlar:(batch, sequence, embedding)
. - Daha sonra, çift yönlü bir LSTM katmanı, her örnek için sabit uzunlukta bir çıktı vektörü döndürür.
- Bu sabit uzunluktaki çıkış vektörü, 64 gizli birim içeren tam bağlı (
Dense
) bir katman aracılığıylaDense
. - 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 kaymandır.
Gizli birimler
Yukarıdaki model, giriş ve çıkış arasında ve Embedding
katmanı hariç olmak üzere iki ara veya "gizli" katmana sahiptir. Çıktı sayısı (birimler, düğümler veya nöronlar), katman için temsili alanın boyutudur. Başka bir deyişle, bir iç temsili öğrenirken ağa izin verilen özgürlük miktarı.
Bir modelde daha fazla gizli birim (daha yüksek boyutlu bir temsil alanı) ve / veya daha fazla katman varsa, ağ daha karmaşık gösterimleri öğrenebilir. Ancak, ağı hesaplama açısından daha pahalı hale getirir ve istenmeyen kalıpların öğrenilmesine yol açabilir - eğitim verilerinde performansı artıran ancak test verilerinde olmayan örüntüler. Buna aşırı uyum denir.
Kayıp işlevi ve optimize edici
Bir modelin bir kayıp işlevine 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 çıkardığı için (sigmoid aktivasyonlu tek birimlik bir katman), binary_crossentropy
loss fonksiyonunu kullanacağız.
model.compile(
optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
Doğrulama seti oluşturun
Eğitim yaparken, modelin doğruluğunu daha önce görmediği veriler üzerinde kontrol etmek istiyoruz. Orijinal eğitim verilerinin bir kısmını ayırarak bir doğrulama kümesi oluşturun. (Neden test setini şimdi kullanmıyoruz? Amacımız, modelimizi yalnızca eğitim verilerini kullanarak geliştirmek ve ayarlamak, ardından doğruluğumuzu değerlendirmek için test verilerini yalnızca bir kez kullanmaktır).
Bu eğiticide, ilk eğitim örneklerinin yaklaşık% 10'unu (25000'in% 10'u) eğitim için etiketli veriler ve geri kalanını doğrulama verileri olarak alıyoruz. İlk eğitim / test bölümü 50/50 (her biri 25000 örnek) olduğundan, şu anda sahip olduğumuz etkili eğitim / doğrulama / test bölümü 5/45/50'dir.
'Train_dataset'in zaten toplu ve karıştırıldığını 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. Eğitim sırasında modelin doğrulama setindeki 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 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
Modeli değerlendirin
Şimdi modelin nasıl performans gösterdiğini görelim. İki değer döndürülecek. 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 [==============================] - 16s 82ms/step - loss: 0.3748 - accuracy: 0.8500 [0.37483155727386475, 0.8500000238418579]
Zaman içindeki doğruluk / kayıp grafiği oluşturun
model.fit()
, eğitim sırasında olan her şeyi içeren bir sözlüğü 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ı, karşılaştırma için eğitim ve doğrulama kaybının yanı sıra eğitim ve doğrulama doğruluğunu planlamak 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()
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()
Her çağda eğitim kaybının azaldığını ve eğitim doğruluğunun her çağda arttığını fark edin. Gradyan iniş optimizasyonu kullanılırken bu beklenen bir durumdur - her yinelemede istenen miktarı en aza indirmelidir.
Grafik düzenleme
Artık yukarıda oluşturduğumuz temel modeli kullanarak grafik düzenlemeyi denemeye hazırız. Temel (bi-LSTM) modeli grafik düzenlileştirmeyi içerecek şekilde sarmak için Sinirsel Yapılandırılmış Öğrenme çerçevesi tarafından sağlanan GraphRegularization
sarmalayıcı sınıfını kullanacağız. Grafiğe göre düzenlenmiş modeli eğitme ve değerlendirme adımlarının geri kalanı, temel modelinkine benzer.
Grafiğe göre düzenlenmiş model oluşturun
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.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
Modeli değerlendirin
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]
Zaman içindeki doğruluk / kayıp grafiği oluşturun
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ş vardır: eğitim kaybı, eğitim doğruluğu, eğitim grafiği kaybı, doğrulama kaybı ve doğrulama doğruluğu. Karşılaştırma için hepsini birlikte planlayabiliriz. Grafik kaybının yalnızca eğitim 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()
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()
Yarı denetimli öğrenmenin gücü
Yarı denetimli öğrenme ve daha spesifik olarak, bu eğitim bağlamında grafik düzenleme, eğitim verilerinin 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 benzerlikten yararlanılarak telafi edilir.
Denetim oranını , eğitim numunelerinin eğitim, doğrulama ve test numunelerini içeren toplam numune sayısına oranı olarak tanımlıyoruz. Bu defterde, hem temel modeli hem de grafiğe göre düzenlenmiş modeli eğitmek için 0,05'lik bir denetim oranı (yani, etiketli verilerin% 5'i) kullandık. Denetim oranının model doğruluğu üzerindeki etkisini aşağıdaki hücrede gösteriyoruz.
# 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>
Gözlem oranı azaldıkça model doğruluğunun da azaldığı gözlemlenebilir. Bu, kullanılan model mimarisinden bağımsız olarak hem temel model hem de grafiğe göre düzenlenmiş model için geçerlidir. Ancak, grafiğe göre düzenlenmiş modelin her iki mimari için de temel modelden daha iyi performans gösterdiğine dikkat edin. Özellikle, Bi-LSTM modeli için, denetim oranı 0.01 olduğunda, grafiğe göre düzenlenmiş modelin doğruluğu, temel modelinkinden ~% 20 daha yüksektir. Bunun başlıca nedeni, eğitim örneklerinin kendilerine ek olarak eğitim örnekleri arasındaki yapısal benzerliğin kullanıldığı, grafikle düzenlenmiş model için yarı denetimli öğrenmedir.
Sonuç
Girdi, açık bir grafik içermese bile, Sinirsel Yapılandırılmış Öğrenme (NSL) çerçevesini kullanarak grafik düzenlemesinin kullanımını gösterdik. İnceleme yerleştirmelerine dayalı bir benzerlik grafiği sentezlediğimiz IMDB film incelemelerinin duyarlılık sınıflandırması görevini ele aldık. Kullanıcıları, değişen hiperparametreler, denetim miktarı ve farklı model mimarileri kullanarak daha fazla deneme yapmaya teşvik ediyoruz.