การจัดประเภทข้อความพื้นฐาน

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

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

import matplotlib.pyplot as plt
import os
import re
import shutil
import string
import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import preprocessing
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
print(tf.__version__)
2.5.0

การวิเคราะห์ความรู้สึก

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

คุณจะใช้ ขนาดใหญ่ดูหนังชุดข้อมูล ที่ประกอบด้วยข้อความ 50,000 บทวิจารณ์ภาพยนตร์จากที่ ฐานข้อมูลภาพยนตร์อินเทอร์เน็ต สิ่งเหล่านี้แบ่งออกเป็น 25,000 รีวิวสำหรับการฝึกอบรมและ 25,000 รีวิวสำหรับการทดสอบ การฝึกอบรมและการทดสอบชุดมีความสมดุลหมายถึงพวกเขามีจำนวนเท่ากับความคิดเห็นในเชิงบวกและเชิงลบ

ดาวน์โหลดและสำรวจชุดข้อมูล IMDB

มาดาวน์โหลดและแตกชุดข้อมูล จากนั้นสำรวจโครงสร้างไดเรกทอรี

url = "https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"

dataset = tf.keras.utils.get_file("aclImdb_v1", url,
                                    untar=True, cache_dir='.',
                                    cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')
Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
84131840/84125825 [==============================] - 7s 0us/step
os.listdir(dataset_dir)
['train', 'imdb.vocab', 'README', 'imdbEr.txt', 'test']
train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
['pos',
 'neg',
 'urls_neg.txt',
 'urls_pos.txt',
 'unsup',
 'unsupBow.feat',
 'labeledBow.feat',
 'urls_unsup.txt']

aclImdb/train/pos และ aclImdb/train/neg ไดเรกทอรีประกอบด้วยไฟล์ข้อความจำนวนมากในแต่ละแห่งซึ่งเป็นบทวิจารณ์ภาพยนตร์เดียว ลองดูที่หนึ่งในนั้น

sample_file = os.path.join(train_dir, 'pos/1181_9.txt')
with open(sample_file) as f:
  print(f.read())
Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.

โหลดชุดข้อมูล

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

main_directory/
...class_a/
......a_text_1.txt
......a_text_2.txt
...class_b/
......b_text_1.txt
......b_text_2.txt

เพื่อเตรียมความพร้อมสำหรับการจำแนกประเภทชุดข้อมูลไบนารีคุณจะต้องสองโฟลเดอร์บนดิสก์ที่สอดคล้องกับ class_a และ class_b เหล่านี้จะเป็นบทวิจารณ์ภาพยนตร์ในเชิงบวกและเชิงลบซึ่งสามารถพบได้ใน aclImdb/train/pos และ aclImdb/train/neg เนื่องจากชุดข้อมูล IMDB มีโฟลเดอร์เพิ่มเติม คุณจะต้องลบออกก่อนที่จะใช้ยูทิลิตี้นี้

remove_dir = os.path.join(train_dir, 'unsup')
shutil.rmtree(remove_dir)

ถัดไปคุณจะใช้ text_dataset_from_directory ยูทิลิตี้ในการสร้างที่มีป้ายกำกับ tf.data.Dataset tf.data เป็นคอลเลกชันที่มีประสิทธิภาพของเครื่องมือสำหรับการทำงานกับข้อมูล

เมื่อเรียกใช้การทดสอบการเรียนรู้เครื่องมันเป็นวิธีที่ดีที่สุดที่จะแบ่งชุดข้อมูลของคุณออกเป็นสามแยก: รถไฟ , การตรวจสอบ และ ทดสอบ

ชุดข้อมูล IMDB ถูกแบ่งออกเป็นการฝึกและการทดสอบแล้ว แต่ไม่มีชุดการตรวจสอบความถูกต้อง ลองสร้างชุดการตรวจสอบการใช้ 80:20 แยกข้อมูลการฝึกอบรมโดยใช้ validation_split โต้แย้งด้านล่าง

batch_size = 32
seed = 42

raw_train_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='training', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 20000 files for training.

ดังที่คุณเห็นด้านบน มีตัวอย่าง 25,000 ตัวอย่างในโฟลเดอร์การฝึกอบรม ซึ่งคุณจะใช้ 80% (หรือ 20,000) สำหรับการฝึกอบรม ในขณะที่คุณจะเห็นในช่วงเวลาที่คุณสามารถฝึกรูปแบบโดยผ่านชุดข้อมูลโดยตรงกับ model.fit หากคุณกำลังใหม่เพื่อ tf.data คุณยังสามารถย้ำกว่าชุดข้อมูลและพิมพ์ออกมาไม่กี่ตัวอย่างดังต่อไปนี้

for text_batch, label_batch in raw_train_ds.take(1):
  for i in range(3):
    print("Review", text_batch.numpy()[i])
    print("Label", label_batch.numpy()[i])
Review b'"Pandemonium" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. "Airplane", "The Naked Gun" trilogy, "Blazing Saddles", "High Anxiety", and "Spaceballs" are some of my favorite comedies that spoof a particular genre. "Pandemonium" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\'s all this film has going for it. Geez, "Scream" had more laughs than this film and that was more of a horror film. How bizarre is that?<br /><br />*1/2 (out of four)'
Label 0
Review b"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.<br /><br />So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.<br /><br />This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.<br /><br />Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated."
Label 0
Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the"High Fat Diet" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\'s and that is what this is, a Great Documentary.....'
Label 1

ขอให้สังเกตความคิดเห็นมีข้อความดิบ (ที่มีเครื่องหมายวรรคตอนและเป็นครั้งคราว HTML แท็กเช่น <br/> ) คุณจะแสดงวิธีจัดการกับสิ่งเหล่านี้ในส่วนต่อไปนี้

ป้ายเป็น 0 หรือ 1 เพื่อดูว่าตรงเหล่านี้เพื่อบทวิจารณ์ภาพยนตร์ในเชิงบวกและเชิงลบคุณสามารถตรวจสอบ class_names ทรัพย์สินในชุดข้อมูล

print("Label 0 corresponds to", raw_train_ds.class_names[0])
print("Label 1 corresponds to", raw_train_ds.class_names[1])
Label 0 corresponds to neg
Label 1 corresponds to pos

ถัดไป คุณจะต้องสร้างชุดข้อมูลการตรวจสอบและทดสอบ คุณจะใช้บทวิจารณ์ที่เหลืออีก 5,000 รายการจากชุดการฝึกอบรมเพื่อตรวจสอบความถูกต้อง

raw_val_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='validation', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 5000 files for validation.
raw_test_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/test', 
    batch_size=batch_size)
Found 25000 files belonging to 2 classes.

เตรียมชุดข้อมูลสำหรับการฝึกอบรม

ถัดไปคุณจะสร้างมาตรฐาน, tokenize และ vectorize ข้อมูลโดยใช้ประโยชน์ preprocessing.TextVectorization ชั้น

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

ในขณะที่คุณเห็นข้างต้นคิดเห็นประกอบด้วยแท็ก HTML ต่างๆเช่น <br /> แท็กเหล่านี้จะไม่ถูกลบโดย standardizer ค่าเริ่มต้นใน TextVectorization ชั้น (ซึ่งแปลงข้อความให้เป็นตัวพิมพ์เล็กและแถบเครื่องหมายวรรคตอนโดยเริ่มต้น แต่ไม่ได้ตัด HTML) คุณจะเขียนฟังก์ชันมาตรฐานที่กำหนดเองเพื่อลบ HTML

def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  stripped_html = tf.strings.regex_replace(lowercase, '<br />', ' ')
  return tf.strings.regex_replace(stripped_html,
                                  '[%s]' % re.escape(string.punctuation),
                                  '')

ถัดไปคุณจะสร้าง TextVectorization ชั้น คุณจะใช้เลเยอร์นี้เพื่อสร้างมาตรฐาน สร้างโทเค็น และทำให้ข้อมูลของเราเป็นเวกเตอร์ คุณตั้งค่า output_mode เพื่อ int เพื่อสร้างดัชนีจำนวนเต็มเฉพาะสำหรับแต่ละโทเค็น

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

max_features = 10000
sequence_length = 250

vectorize_layer = TextVectorization(
    standardize=custom_standardization,
    max_tokens=max_features,
    output_mode='int',
    output_sequence_length=sequence_length)

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

# Make a text-only dataset (without labels), then call adapt
train_text = raw_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(train_text)

มาสร้างฟังก์ชันเพื่อดูผลลัพธ์ของการใช้เลเยอร์นี้เพื่อประมวลผลข้อมูลบางส่วนล่วงหน้า

def vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return vectorize_layer(text), label
# retrieve a batch (of 32 reviews and labels) from the dataset
text_batch, label_batch = next(iter(raw_train_ds))
first_review, first_label = text_batch[0], label_batch[0]
print("Review", first_review)
print("Label", raw_train_ds.class_names[first_label])
print("Vectorized review", vectorize_text(first_review, first_label))
Review tf.Tensor(b'Great movie - especially the music - Etta James - "At Last". This speaks volumes when you have finally found that special someone.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[  86,   17,  260,    2,  222,    1,  571,   31,  229,   11, 2418,
           1,   51,   22,   25,  404,  251,   12,  306,  282,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
           0,    0,    0,    0,    0,    0,    0,    0]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

ดังที่คุณเห็นด้านบน แต่ละโทเค็นจะถูกแทนที่ด้วยจำนวนเต็ม คุณสามารถค้นหาโทเค็น (สตริง) ที่จำนวนเต็มแต่ละสอดคล้องกับโดยการเรียก .get_vocabulary() บนชั้น

print("1287 ---> ",vectorize_layer.get_vocabulary()[1287])
print(" 313 ---> ",vectorize_layer.get_vocabulary()[313])
print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))
1287 --->  silent
 313 --->  night
Vocabulary size: 10000

คุณเกือบจะพร้อมที่จะฝึกโมเดลของคุณแล้ว ในขั้นสุดท้ายก่อนการประมวลผล คุณจะใช้เลเยอร์ TextVectorization ที่คุณสร้างไว้ก่อนหน้านี้กับรถไฟ การตรวจสอบ และชุดข้อมูลการทดสอบ

train_ds = raw_train_ds.map(vectorize_text)
val_ds = raw_val_ds.map(vectorize_text)
test_ds = raw_test_ds.map(vectorize_text)

กำหนดค่าชุดข้อมูลสำหรับประสิทธิภาพ

นี่เป็นวิธีสำคัญสองวิธีที่คุณควรใช้เมื่อโหลดข้อมูลเพื่อให้แน่ใจว่า I/O จะไม่ถูกบล็อก

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

.prefetch() คาบเกี่ยวข้อมูล preprocessing และการดำเนินการในขณะที่รูปแบบการฝึกอบรม

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

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)

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

ได้เวลาสร้างโครงข่ายประสาทเทียมของคุณแล้ว:

embedding_dim = 16
model = tf.keras.Sequential([
  layers.Embedding(max_features + 1, embedding_dim),
  layers.Dropout(0.2),
  layers.GlobalAveragePooling1D(),
  layers.Dropout(0.2),
  layers.Dense(1)])

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160016    
_________________________________________________________________
dropout (Dropout)            (None, None, 16)          0         
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 1)                 17        
=================================================================
Total params: 160,033
Trainable params: 160,033
Non-trainable params: 0
_________________________________________________________________

เลเยอร์ถูกซ้อนกันตามลำดับเพื่อสร้างลักษณนาม:

  1. ชั้นแรกเป็น Embedding ชั้น เลเยอร์นี้ใช้การตรวจสอบที่เข้ารหัสเป็นจำนวนเต็มและค้นหาเวกเตอร์ที่ฝังสำหรับดัชนีคำแต่ละคำ เวกเตอร์เหล่านี้เรียนรู้เป็นโมเดลรถไฟ เวกเตอร์เพิ่มมิติให้กับอาร์เรย์เอาต์พุต ขนาดส่งผลมีดังนี้: (batch, sequence, embedding) ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ embeddings ดูที่ คำฝังกวดวิชา
  2. ถัดไป GlobalAveragePooling1D ชั้นส่งกลับเวกเตอร์เอาท์พุทความยาวคงที่สำหรับแต่ละตัวอย่างโดยเฉลี่ยมากกว่ามิติลำดับ ซึ่งช่วยให้โมเดลสามารถจัดการกับอินพุตของความยาวผันแปรได้ด้วยวิธีที่ง่ายที่สุด
  3. เวกเตอร์เอาท์พุทความยาวคงที่นี้เป็นประปาผ่านอย่างเต็มที่ที่เชื่อมต่อ ( Dense ) ชั้นกับ 16 หน่วยซ่อน
  4. เลเยอร์สุดท้ายเชื่อมต่ออย่างแน่นหนาด้วยโหนดเอาต์พุตเดียว

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

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

ตอนนี้ กำหนดค่าโมเดลเพื่อใช้ตัวเพิ่มประสิทธิภาพและฟังก์ชันการสูญเสีย:

model.compile(loss=losses.BinaryCrossentropy(from_logits=True),
              optimizer='adam',
              metrics=tf.metrics.BinaryAccuracy(threshold=0.0))

ฝึกโมเดล

คุณจะฝึกรูปแบบโดยผ่าน dataset วัตถุวิธีพอดี

epochs = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs)
Epoch 1/10
625/625 [==============================] - 4s 4ms/step - loss: 0.6662 - binary_accuracy: 0.6918 - val_loss: 0.6192 - val_binary_accuracy: 0.7720
Epoch 2/10
625/625 [==============================] - 2s 4ms/step - loss: 0.5538 - binary_accuracy: 0.7974 - val_loss: 0.5026 - val_binary_accuracy: 0.8216
Epoch 3/10
625/625 [==============================] - 2s 4ms/step - loss: 0.4483 - binary_accuracy: 0.8421 - val_loss: 0.4228 - val_binary_accuracy: 0.8470
Epoch 4/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3807 - binary_accuracy: 0.8648 - val_loss: 0.3757 - val_binary_accuracy: 0.8600
Epoch 5/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3378 - binary_accuracy: 0.8784 - val_loss: 0.3463 - val_binary_accuracy: 0.8670
Epoch 6/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3069 - binary_accuracy: 0.8874 - val_loss: 0.3271 - val_binary_accuracy: 0.8706
Epoch 7/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2830 - binary_accuracy: 0.8967 - val_loss: 0.3136 - val_binary_accuracy: 0.8732
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2644 - binary_accuracy: 0.9037 - val_loss: 0.3040 - val_binary_accuracy: 0.8760
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2468 - binary_accuracy: 0.9107 - val_loss: 0.2972 - val_binary_accuracy: 0.8784
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2327 - binary_accuracy: 0.9161 - val_loss: 0.2923 - val_binary_accuracy: 0.8792

ประเมินแบบจำลอง

มาดูกันว่าโมเดลทำงานอย่างไร ค่าสองค่าจะถูกส่งกลับ การสูญเสีย (ตัวเลขที่แสดงถึงข้อผิดพลาดของเรา ค่าที่ต่ำกว่าจะดีกว่า) และความแม่นยำ

loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
782/782 [==============================] - 2s 2ms/step - loss: 0.3108 - binary_accuracy: 0.8722
Loss:  0.3108080327510834
Accuracy:  0.8722400069236755

แนวทางที่ค่อนข้างไร้เดียงสานี้มีความแม่นยำประมาณ 86%

สร้างพล็อตของความแม่นยำและการสูญเสียเมื่อเวลาผ่านไป

model.fit() ส่งกลับ History วัตถุที่มีพจนานุกรมกับทุกสิ่งที่เกิดขึ้นในระหว่างการฝึก:

history_dict = history.history
history_dict.keys()
dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])

มีสี่รายการ: หนึ่งรายการสำหรับแต่ละเมตริกที่ถูกตรวจสอบระหว่างการฝึกอบรมและการตรวจสอบ คุณสามารถใช้สิ่งเหล่านี้เพื่อวางแผนการสูญเสียการฝึกอบรมและการตรวจสอบเพื่อการเปรียบเทียบ รวมถึงความแม่นยำของการฝึกอบรมและการตรวจสอบ:

acc = history_dict['binary_accuracy']
val_acc = history_dict['val_binary_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

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

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

png

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')

plt.show()

png

ในพล็อตนี้ จุดแสดงถึงการสูญเสียการฝึกอบรมและความแม่นยำ และเส้นทึบคือการสูญเสียการตรวจสอบและความถูกต้อง

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

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

สำหรับกรณีนี้โดยเฉพาะ คุณสามารถป้องกันไม่ให้เกินกำลังโดยเพียงแค่หยุดการฝึกเมื่อความแม่นยำในการตรวจสอบความถูกต้องไม่เพิ่มขึ้นอีกต่อไป วิธีหนึ่งที่จะทำเช่นนั้นคือการใช้ tf.keras.callbacks.EarlyStopping โทรกลับ

ส่งออกโมเดล

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

export_model = tf.keras.Sequential([
  vectorize_layer,
  model,
  layers.Activation('sigmoid')
])

export_model.compile(
    loss=losses.BinaryCrossentropy(from_logits=False), optimizer="adam", metrics=['accuracy']
)

# Test it with `raw_test_ds`, which yields raw strings
loss, accuracy = export_model.evaluate(raw_test_ds)
print(accuracy)
782/782 [==============================] - 3s 4ms/step - loss: 0.3108 - accuracy: 0.8722
0.8722400069236755

การอนุมานข้อมูลใหม่

ที่จะได้รับการคาดการณ์สำหรับตัวอย่างใหม่คุณก็สามารถโทร model.predict()

examples = [
  "The movie was great!",
  "The movie was okay.",
  "The movie was terrible..."
]

export_model.predict(examples)
array([[0.60349613],
       [0.42510134],
       [0.3445068 ]], dtype=float32)

รวมทั้งข้อความ preprocessing ตรรกะภายในรูปแบบของคุณช่วยให้คุณสามารถส่งออกรูปแบบการผลิตที่ช่วยลดการใช้งานและลดศักยภาพในการ รถไฟ / ทดสอบเอียง

มีข้อควรพิจารณาด้านประสิทธิภาพที่แตกต่างกันเมื่อเลือกตำแหน่งที่จะใช้เลเยอร์ TextVectorization การใช้ภายนอกโมเดลของคุณทำให้คุณสามารถประมวลผล CPU แบบอะซิงโครนัสและการบัฟเฟอร์ข้อมูลของคุณเมื่อฝึก GPU ดังนั้น หากคุณกำลังฝึกโมเดลของคุณบน GPU คุณอาจต้องการใช้ตัวเลือกนี้เพื่อให้ได้ประสิทธิภาพที่ดีที่สุดในขณะที่พัฒนาโมเดลของคุณ จากนั้นสลับไปที่การรวมเลเยอร์ TextVectorization ภายในโมเดลของคุณเมื่อคุณพร้อมที่จะเตรียมพร้อมสำหรับการปรับใช้ .

เยี่ยมชม การกวดวิชา เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการประหยัดรุ่น

แบบฝึกหัด: การจำแนกประเภทหลายคลาสในคำถาม Stack Overflow

บทช่วยสอนนี้แสดงวิธีฝึกตัวแยกประเภทไบนารีตั้งแต่เริ่มต้นบนชุดข้อมูล IMDB ขณะที่การออกกำลังกายคุณสามารถปรับเปลี่ยนสมุดบันทึกนี้ในการฝึกอบรมลักษณนามหลายระดับในการทำนายแท็กของคำถามการเขียนโปรแกรมบน กองมากเกิน

ชุดข้อมูลที่ ได้จัดทำขึ้นเพื่อให้คุณใช้ที่มีร่างกายหลายพันคำถามการเขียนโปรแกรม (ตัวอย่างเช่น "วิธีสามารถเรียงลำดับพจนานุกรมโดยค่าในงูใหญ่?") โพสต์ไปกองมากเกิน แต่ละรายการมีป้ายกำกับด้วยแท็กเดียว (ทั้ง Python, CSharp, JavaScript หรือ Java) งานของคุณคือรับคำถามเป็นอินพุต และคาดเดาแท็กที่เหมาะสม ในกรณีนี้คือ Python

ชุดที่คุณจะทำงานร่วมกับมีหลายพันคำถามสกัดจากประชาชนชุดกองมากเกินขนาดใหญ่มากใน BigQuery ซึ่งมีมากกว่า 17 ล้านข้อความ

หลังจากดาวน์โหลดชุดข้อมูล คุณจะพบว่ามีโครงสร้างไดเรกทอรีที่คล้ายกับชุดข้อมูล IMDB ที่คุณเคยใช้งานก่อนหน้านี้:

train/
...python/
......0.txt
......1.txt
...javascript/
......0.txt
......1.txt
...csharp/
......0.txt
......1.txt
...java/
......0.txt
......1.txt

ในการทำแบบฝึกหัดนี้ คุณควรแก้ไขสมุดบันทึกนี้ให้ทำงานกับชุดข้อมูล Stack Overflow โดยทำการแก้ไขต่อไปนี้:

  1. ที่ด้านบนของโน้ตบุ๊คของคุณอัปเดตรหัสที่ดาวน์โหลดชุดข้อมูลที่ไอเอ็มที่มีรหัสเพื่อดาวน์โหลด ชุดกองมากเกิน ที่ได้รับการ prepreared เนื่องจากชุดข้อมูล Stack Overflow มีโครงสร้างไดเร็กทอรีที่คล้ายกัน คุณจึงไม่จำเป็นต้องทำการแก้ไขหลายอย่าง

  2. ปรับเปลี่ยนชั้นสุดท้ายของรูปแบบของคุณเพื่ออ่าน Dense(4) ที่มีอยู่ในขณะนี้สี่ชั้นเอาท์พุท

  3. เมื่อรวบรวมรูปแบบการเปลี่ยนแปลงการสูญเสีย tf.keras.losses.SparseCategoricalCrossentropy นี่คือการสูญเสียหน้าที่ถูกต้องเพื่อใช้สำหรับปัญหาการจัดหมวดหมู่หลายชั้นเมื่อป้ายชื่อสำหรับแต่ละชั้นเป็นจำนวนเต็ม (ในกรณีนี้พวกเขาสามารถเป็น 0, 1, 2 หรือ 3) นอกจากนี้การเปลี่ยนแปลงตัวชี้วัดที่จะ metrics=['accuracy'] ตั้งแต่นี้เป็นปัญหาที่การจัดหมวดหมู่หลายระดับ ( tf.metrics.BinaryAccuracy จะใช้สำหรับการจําแนก binary)

  4. เมื่อวางแผนความถูกต้องในช่วงเวลาการเปลี่ยนแปลง binary_accuracy และ val_binary_accuracy เพื่อ accuracy และ val_accuracy ตามลำดับ

  5. เมื่อการเปลี่ยนแปลงเหล่านี้เสร็จสมบูรณ์ คุณจะสามารถฝึกตัวแยกประเภทได้

เรียนรู้เพิ่มเติม

บทช่วยสอนนี้แนะนำการจัดประเภทข้อความตั้งแต่เริ่มต้น ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับขั้นตอนการจัดหมวดหมู่ข้อความทั่วไปตรวจสอบ คู่มือการจัดหมวดหมู่ข้อความ จาก Google พัฒนา

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.