หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

การจัดลำดับกราฟสำหรับการจำแนกความรู้สึกโดยใช้กราฟสังเคราะห์

ดูใน TensorFlow.org เรียกใช้ใน Google Colab ดูแหล่งที่มาบน GitHub

ภาพรวม

สมุดบันทึกนี้จัดประเภทบทวิจารณ์ภาพยนตร์เป็น เชิงบวก หรือ เชิงลบ โดยใช้ข้อความของบทวิจารณ์ นี่คือตัวอย่างของการจัดประเภท ไบนารี ซึ่งเป็นปัญหาการเรียนรู้ของเครื่องที่สำคัญและใช้ได้อย่างกว้างขวาง

เราจะสาธิตการใช้การทำให้เป็นมาตรฐานของกราฟในสมุดบันทึกนี้โดยการสร้างกราฟจากอินพุตที่กำหนด สูตรทั่วไปสำหรับการสร้างแบบจำลองกราฟที่กำหนดโดยใช้เฟรมเวิร์ก Neural Structured Learning (NSL) เมื่ออินพุตไม่มีกราฟที่ชัดเจนมีดังนี้:

  1. สร้างการฝังสำหรับแต่ละตัวอย่างข้อความในอินพุต ซึ่งสามารถทำได้โดยใช้โมเดลที่ได้รับการฝึกฝนมาก่อนเช่น word2vec , Swivel , BERT เป็นต้น
  2. สร้างกราฟตามการฝังตัวเหล่านี้โดยใช้เมตริกความคล้ายคลึงกันเช่นระยะทาง 'L2' ระยะทาง 'โคไซน์' ฯลฯ โหนดในกราฟสอดคล้องกับตัวอย่างและขอบในกราฟสอดคล้องกับความคล้ายคลึงกันระหว่างคู่ของตัวอย่าง
  3. สร้างข้อมูลการฝึกอบรมจากกราฟสังเคราะห์ข้างต้นและคุณลักษณะตัวอย่าง ข้อมูลการฝึกอบรมที่ได้จะมีคุณลักษณะเพื่อนบ้านเพิ่มเติมจากคุณสมบัติโหนดเดิม
  4. สร้างโครงข่ายประสาทเทียมเป็นแบบจำลองพื้นฐานโดยใช้ Keras sequential, functional หรือ subclass API
  5. ห่อโมเดลพื้นฐานด้วยคลาส GraphRegularization wrapper ซึ่งจัดเตรียมโดยเฟรมเวิร์ก NSL เพื่อสร้างโมเดล Keras กราฟใหม่ โมเดลใหม่นี้จะรวมการสูญเสียการทำให้เป็นมาตรฐานของกราฟเป็นเงื่อนไขการทำให้เป็นมาตรฐานในวัตถุประสงค์การฝึกอบรม
  6. ฝึกอบรมและประเมินโมเดลกราฟ Keras

ข้อกำหนด

  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 เพื่อสร้างการฝังในรูปแบบ tf.train.Example สำหรับแต่ละตัวอย่างในอินพุต เราจะจัดเก็บการฝังผลลัพธ์ในรูปแบบ TFRecord พร้อมกับคุณลักษณะเพิ่มเติมที่แสดงถึง ID ของแต่ละตัวอย่าง นี่เป็นสิ่งสำคัญและจะช่วยให้เราจับคู่การฝังตัวอย่างกับโหนดที่เกี่ยวข้องในกราฟได้ในภายหลัง

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

สร้างกราฟ

ตอนนี้เรามีการฝังตัวอย่างแล้วเราจะใช้มันเพื่อสร้างกราฟความคล้ายคลึงกันกล่าวคือโหนดในกราฟนี้จะสอดคล้องกับตัวอย่างและขอบในกราฟนี้จะสอดคล้องกับความคล้ายคลึงกันระหว่างคู่ของโหนด

Neural Structured Learning มีไลบรารีการสร้างกราฟเพื่อสร้างกราฟตามการฝังตัวอย่าง ใช้ ความคล้ายคลึงกันของโคไซน์ เป็นตัววัดความคล้ายคลึงเพื่อเปรียบเทียบการฝังและสร้างขอบระหว่างพวกเขา นอกจากนี้ยังช่วยให้เราระบุเกณฑ์ความคล้ายคลึงกันซึ่งสามารถใช้เพื่อละทิ้งขอบที่ไม่เหมือนกันออกจากกราฟสุดท้าย ในตัวอย่างนี้โดยใช้ 0.99 เป็นเกณฑ์ความคล้ายคลึงกันและ 12345 เป็นเมล็ดแบบสุ่มเราจะได้กราฟที่มีขอบ 429,415 สองทิศทาง ที่นี่เรากำลังใช้การสนับสนุนของเครื่องมือสร้างกราฟสำหรับ การแฮชตามพื้นที่ (LSH) เพื่อเร่งความเร็วในการสร้างกราฟ สำหรับรายละเอียดเกี่ยวกับการใช้การสนับสนุน LSH ของเครื่องมือสร้างกราฟโปรดดูเอกสาร build_graph_from_config API

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 แต่ละตัวอย่างจะมีคุณสมบัติสามประการดังต่อไปนี้:

  1. id : ID โหนดของตัวอย่าง
  2. คำ : รายการ int64 ที่มีรหัสคำ
  3. ป้ายกำกับ : int64 singleton ที่ระบุคลาสเป้าหมายของบทวิจารณ์
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 เพื่อรวมค่า HParams และค่าคงที่ต่างๆที่ใช้สำหรับการฝึกอบรมและการประเมินผล เราอธิบายสั้น ๆ แต่ละข้อด้านล่าง:

  • num_classes : มี 2 คลาส - บวก และ ลบ

  • max_seq_length : จำนวนคำสูงสุดที่พิจารณาจากบทวิจารณ์ภาพยนตร์แต่ละเรื่องในตัวอย่างนี้

  • vocab_size : นี่คือขนาดของคำศัพท์ที่พิจารณาสำหรับตัวอย่างนี้

  • distance_type : นี่คือเมตริกระยะทางที่ใช้ในการกำหนดตัวอย่างกับเพื่อนบ้าน

  • graph_regularization_multiplier : สิ่งนี้ควบคุมน้ำหนักสัมพัทธ์ของเงื่อนไขการทำให้เป็นมาตรฐานของกราฟในฟังก์ชันการสูญเสียโดยรวม

  • num_neighbors : จำนวนเพื่อนบ้านที่ใช้สำหรับการทำให้เป็นมาตรฐานของกราฟ ค่านี้ต้องน้อยกว่าหรือเท่ากับอาร์กิวเมนต์ 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 เราสามารถใช้เลเยอร์การฝังที่สามารถจัดการกับรูปร่างนี้เป็นเลเยอร์แรกในเครือข่ายของเรา

ในบทช่วยสอนนี้เราจะใช้แนวทางที่สอง

เนื่องจากบทวิจารณ์ภาพยนตร์ต้องมีความยาวเท่ากันเราจึงใช้ฟังก์ชัน 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')

สร้างแบบจำลอง

โครงข่ายประสาทเทียมถูกสร้างขึ้นโดยการซ้อนเลเยอร์ซึ่งต้องอาศัยการตัดสินใจทางสถาปัตยกรรมหลักสองประการ:

  • ต้องใช้กี่ชั้นในแบบจำลอง?
  • ต้องใช้ ยูนิตที่ซ่อนอยู่ กี่ ยูนิต สำหรับแต่ละเลเยอร์

ในตัวอย่างนี้ข้อมูลอินพุตประกอบด้วยอาร์เรย์ของดัชนีคำ ป้ายกำกับที่จะทำนายคือ 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 จำนวนเอาต์พุต (หน่วยโหนดหรือเซลล์ประสาท) คือมิติของพื้นที่ที่เป็นตัวแทนสำหรับเลเยอร์ กล่าวอีกนัยหนึ่งจำนวนอิสระของเครือข่ายจะได้รับอนุญาตเมื่อเรียนรู้การเป็นตัวแทนภายใน

หากโมเดลมีหน่วยที่ซ่อนอยู่มากกว่า (พื้นที่การแสดงมิติที่สูงขึ้น) และ / หรือเลเยอร์มากกว่านั้นเครือข่ายจะสามารถเรียนรู้การแสดงที่ซับซ้อนมากขึ้นได้ อย่างไรก็ตามมันทำให้เครือข่ายมีค่าใช้จ่ายในการคำนวณมากขึ้นและอาจนำไปสู่การเรียนรู้รูปแบบที่ไม่ต้องการซึ่งเป็นรูปแบบที่ปรับปรุงประสิทธิภาพของข้อมูลการฝึกอบรม แต่ไม่ใช่ในข้อมูลการทดสอบ ซึ่งเรียกว่า overfitting

ฟังก์ชันการสูญเสียและเครื่องมือเพิ่มประสิทธิภาพ

โมเดลต้องการฟังก์ชันการสูญเสียและเครื่องมือเพิ่มประสิทธิภาพสำหรับการฝึกอบรม เนื่องจากนี่เป็นปัญหาการจัดประเภทไบนารีและโมเดลแสดงความน่าจะเป็น (เลเยอร์หน่วยเดียวที่มีการกระตุ้น sigmoid) เราจะใช้ฟังก์ชันการสูญเสีย binary_crossentropy

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

สร้างชุดการตรวจสอบความถูกต้อง

เมื่อฝึกอบรมเราต้องการตรวจสอบความถูกต้องของแบบจำลองกับข้อมูลที่ไม่เคยเห็นมาก่อน สร้าง ชุดการตรวจสอบความถูกต้อง โดยแยกส่วนของข้อมูลการฝึกอบรมเดิม (ทำไมไม่ใช้ชุดการทดสอบตอนนี้เป้าหมายของเราคือการพัฒนาและปรับแต่งโมเดลของเราโดยใช้เฉพาะข้อมูลการฝึกอบรมจากนั้นใช้ข้อมูลการทดสอบเพียงครั้งเดียวเพื่อประเมินความแม่นยำของเรา)

ในบทช่วยสอนนี้เราใช้เวลาประมาณ 10% ของตัวอย่างการฝึกอบรมเบื้องต้น (10% ของ 25000) เป็นข้อมูลที่มีป้ายกำกับสำหรับการฝึกอบรมและส่วนที่เหลือเป็นข้อมูลการตรวจสอบความถูกต้อง เนื่องจากการแยกรถไฟ / การทดสอบเริ่มต้นคือ 50/50 (แต่ละตัวอย่าง 25,000 รายการ) การแยกรถไฟ / การตรวจสอบความถูกต้อง / การทดสอบที่มีประสิทธิภาพตอนนี้เรามีคือ 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

สังเกตว่าการสูญเสียการฝึกจะ ลดลง ในแต่ละยุคและความแม่นยำในการฝึกจะ เพิ่มขึ้น ตามแต่ละยุค สิ่งนี้คาดว่าจะเกิดขึ้นเมื่อใช้การเพิ่มประสิทธิภาพการลดระดับการไล่ระดับสี - ควรลดปริมาณที่ต้องการในการทำซ้ำทุกครั้ง

การจัดลำดับกราฟ

ตอนนี้เราพร้อมที่จะลองใช้การทำให้เป็นมาตรฐานกราฟโดยใช้แบบจำลองพื้นฐานที่เราสร้างไว้ข้างต้น เราจะใช้คลาส Wrapper GraphRegularization จัดทำโดย Neural Structured Learning framework เพื่อรวมโมเดลฐาน (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

จะสังเกตได้ว่าเมื่ออัตราส่วน superivision ลดลงความแม่นยำของโมเดลก็จะลดลงเช่นกัน ซึ่งเป็นจริงสำหรับทั้งโมเดลพื้นฐานและสำหรับโมเดลที่เป็นกราฟสม่ำเสมอโดยไม่คำนึงถึงสถาปัตยกรรมโมเดลที่ใช้ อย่างไรก็ตามโปรดสังเกตว่ารูปแบบกราฟที่เป็นมาตรฐานจะทำงานได้ดีกว่าแบบจำลองพื้นฐานสำหรับทั้งสองสถาปัตยกรรม โดยเฉพาะอย่างยิ่งสำหรับรุ่น Bi-LSTM เมื่ออัตราส่วนการกำกับดูแลเท่ากับ 0.01 ความแม่นยำของแบบจำลองกราฟจะสูงกว่าโมเดลพื้นฐาน ประมาณ 20% สาเหตุหลักมาจากการเรียนรู้แบบกึ่งมีผู้ดูแลสำหรับแบบจำลองกราฟที่เป็นมาตรฐานซึ่งมีการใช้ความคล้ายคลึงกันของโครงสร้างระหว่างตัวอย่างการฝึกอบรมนอกเหนือจากตัวอย่างการฝึกอบรมเอง

สรุป

เราได้แสดงให้เห็นถึงการใช้การจัดลำดับกราฟโดยใช้เฟรมเวิร์ก Neural Structured Learning (NSL) แม้ว่าอินพุตจะไม่มีกราฟที่ชัดเจนก็ตาม เราพิจารณางานในการจัดประเภทความรู้สึกของบทวิจารณ์ภาพยนตร์ของ IMDB ซึ่งเราได้สังเคราะห์กราฟความคล้ายคลึงกันตามการฝังบทวิจารณ์ เราขอแนะนำให้ผู้ใช้ทดลองเพิ่มเติมโดยใช้พารามิเตอร์ที่หลากหลายจำนวนการควบคุมดูแลและโดยใช้สถาปัตยกรรมแบบจำลองที่แตกต่างกัน