Trang này được dịch bởi Cloud Translation API.
Switch to English

phân loại văn bản cơ bản

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải về máy tính xách tay

Hướng dẫn này cho thấy phân loại văn bản bắt đầu từ các tập tin văn bản đơn giản được lưu trữ trên đĩa. Bạn sẽ đào tạo một phân loại nhị phân để thực hiện phân tích tình cảm trên một tập dữ liệu IMDB. Vào cuối của máy tính xách tay, có một bài tập để bạn có thể thử, trong đó bạn sẽ đào tạo một phân loại nhiều lớp để dự đoán từ khóa cho một câu hỏi lập trình trên 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.3.0

phân tích tình cảm

Máy tính xách tay này huấn luyện một mô hình phân tích tình cảm để đánh giá phim classify như tích cực hay tiêu cực, dựa trên văn bản của tổng quan. Đây là một ví dụ về nhị phân -Hoặc hai đẳng cấp phân loại, một loại quan trọng và được áp dụng rộng rãi của máy có vấn đề học tập.

Bạn sẽ sử dụng lớn Movie Review Dataset có chứa nội dung của 50.000 đánh giá phim từ Internet Movie Database . Đây là những chia thành 25.000 ý kiến ​​cho đào tạo và 25.000 ý kiến ​​cho thử nghiệm. Việc đào tạo và thử nghiệm bộ được cân bằng, nghĩa là chúng có chứa một số lượng tương đương đánh giá tích cực và tiêu cực.

Tải về và khám phá những bộ dữ liệu IMDB

Hãy tải về và giải nén dữ liệu, sau đó khám phá cấu trúc thư mục.

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

dataset = tf.keras.utils.get_file("aclImdb_v1.tar.gz", 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)
 
['imdb.vocab', 'train', 'test', 'README', 'imdbEr.txt']
 train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
 
['urls_pos.txt',
 'neg',
 'labeledBow.feat',
 'pos',
 'urls_neg.txt',
 'unsup',
 'unsupBow.feat',
 'urls_unsup.txt']

Các aclImdb/train/posaclImdb/train/neg thư mục chứa nhiều tập tin văn bản, mỗi trong số đó là một bài đánh giá bộ phim duy nhất. Chúng ta hãy nhìn vào một trong số họ.

 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.

Tải dữ liệu

Tiếp theo, bạn sẽ được tải các dữ liệu ra đĩa và chuẩn bị nó sang một định dạng phù hợp cho đào tạo. Để làm như vậy, bạn sẽ sử dụng hữu ích text_dataset_from_directory tiện ích, mà hy vọng một cấu trúc thư mục như sau.

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

Để chuẩn bị một tập dữ liệu để phân loại nhị phân, bạn sẽ cần hai thư mục trên đĩa, tương ứng với class_aclass_b . Đây sẽ là đánh giá phim tích cực và tiêu cực, có thể được tìm thấy trong aclImdb/train/posaclImdb/train/neg . Như số liệu IMDB chứa thư mục bổ sung, bạn sẽ loại bỏ chúng trước khi sử dụng tiện ích này.

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

Tiếp theo, bạn sẽ sử dụng text_dataset_from_directory tiện ích để tạo ra một nhãn tf.data.Dataset . tf.data là một bộ sưu tập công cụ mạnh mẽ để làm việc với dữ liệu.

Khi chạy thử nghiệm máy học, nó là một thực hành tốt nhất để phân chia tập dữ liệu của bạn thành ba chia rẽ: đào tạo , xác nhậnkiểm tra .

Bộ dữ liệu IMDB đã được chia thành tàu và kiểm tra, nhưng nó thiếu một bộ xác nhận. Hãy tạo ra một tập hợp kiểm chứng bằng một tách 80:20 của dữ liệu huấn luyện bằng công validation_split luận dưới đây.

 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.

Như bạn thấy ở trên, có 25.000 ví dụ trong thư mục đào tạo, trong đó bạn sẽ sử dụng 80% (hoặc 20.000) cho việc đào tạo. Như bạn sẽ thấy trong một khoảnh khắc, bạn có thể đào tạo một mô hình bằng cách thông qua một tập dữ liệu trực tiếp đến model.fit . Nếu bạn là người mới đến tf.data , bạn cũng có thể lặp qua tập dữ liệu và in ra một vài ví dụ như sau.

 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

Chú ý đánh giá chứa văn bản thô (với dấu chấm câu và các thẻ HTML thỉnh thoảng như <br/> ). Bạn sẽ thấy làm thế nào để xử lý những trong phần sau.

Các nhãn là 0 hoặc 1. Để xem các tương ứng với đánh giá phim tích cực và tiêu cực, bạn có thể kiểm tra class_names tài sản trên các tập dữ liệu.

 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

Tiếp theo, bạn sẽ tạo ra một xác nhận và kiểm tra dữ liệu. Bạn sẽ sử dụng 5.000 đánh giá còn lại từ tập huấn luyện để xác nhận.

 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.

Chuẩn bị dữ liệu cho đào tạo

Tiếp theo, bạn sẽ chuẩn hóa, tokenize, và vectorize dữ liệu bằng cách sử dụng hữu ích preprocessing.TextVectorization lớp.

Tiêu chuẩn đề cập đến tiền xử lý văn bản, thường để loại bỏ dấu chấm câu hoặc HTML yếu tố để đơn giản hóa các tập dữ liệu. Tokenization đề cập đến chuỗi tách vào thẻ (ví dụ, tách một câu vào từ riêng lẻ, bằng cách chia tách vào khoảng trắng). Số hóa bản vẽ liên quan đến chuyển đổi thẻ vào số để họ có thể được đưa vào một mạng lưới thần kinh. Tất cả những công việc này có thể được thực hiện với lớp này.

Như bạn đã thấy ở trên, đánh giá chứa các thẻ HTML khác nhau như <br /> . Những thẻ này sẽ không được gỡ bỏ bởi các standardizer mặc định trong TextVectorization lớp (trong đó chuyển đổi văn bản để lowecase và dải chấm câu theo mặc định, nhưng không tước HTML). Bạn sẽ viết một chức năng tùy chỉnh tiêu chuẩn để loại bỏ các 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),
                                  '')
 

Tiếp theo, bạn sẽ tạo ra một TextVectorization lớp. bạn sẽ sử dụng lớp này để tiêu chuẩn hóa, tokenize, và vectorize dữ liệu của chúng tôi. Bạn đặt output_mode để int để tạo ra các chỉ số số nguyên duy nhất cho mỗi thẻ.

Lưu ý rằng bạn đang sử dụng chức năng chia mặc định, và các chức năng tùy chỉnh tiêu chuẩn bạn đã định nghĩa ở trên. Bạn cũng sẽ xác định một số hằng số cho mô hình, giống như một cực đại rõ ràng sequence_length , mà sẽ làm cho lớp để chuỗi pad hoặc truncate chính xác sequence_length giá trị.

 max_features = 10000
sequence_length = 250

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

Tiếp theo, bạn sẽ gọi adapt để phù hợp với tình trạng của lớp tiền xử lý để các tập dữ liệu. Điều này sẽ gây ra các mô hình để xây dựng một chỉ số của chuỗi để nguyên.

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

Hãy tạo một hàm để xem kết quả của việc sử dụng lớp này để preprocess một số dữ liệu.

 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'Silent Night, Deadly Night 5 is the very last of the series, and like part 4, it\'s unrelated to the first three except by title and the fact that it\'s a Christmas-themed horror flick.<br /><br />Except to the oblivious, there\'s some obvious things going on here...Mickey Rooney plays a toymaker named Joe Petto and his creepy son\'s name is Pino. Ring a bell, anyone? Now, a little boy named Derek heard a knock at the door one evening, and opened it to find a present on the doorstep for him. Even though it said "don\'t open till Christmas", he begins to open it anyway but is stopped by his dad, who scolds him and sends him to bed, and opens the gift himself. Inside is a little red ball that sprouts Santa arms and a head, and proceeds to kill dad. Oops, maybe he should have left well-enough alone. Of course Derek is then traumatized by the incident since he watched it from the stairs, but he doesn\'t grow up to be some killer Santa, he just stops talking.<br /><br />There\'s a mysterious stranger lurking around, who seems very interested in the toys that Joe Petto makes. We even see him buying a bunch when Derek\'s mom takes him to the store to find a gift for him to bring him out of his trauma. And what exactly is this guy doing? Well, we\'re not sure but he does seem to be taking these toys apart to see what makes them tick. He does keep his landlord from evicting him by promising him to pay him in cash the next day and presents him with a "Larry the Larvae" toy for his kid, but of course "Larry" is not a good toy and gets out of the box in the car and of course, well, things aren\'t pretty.<br /><br />Anyway, eventually what\'s going on with Joe Petto and Pino is of course revealed, and as with the old story, Pino is not a "real boy". Pino is probably even more agitated and naughty because he suffers from "Kenitalia" (a smooth plastic crotch) so that could account for his evil ways. And the identity of the lurking stranger is revealed too, and there\'s even kind of a happy ending of sorts. Whee.<br /><br />A step up from part 4, but not much of one. Again, Brian Yuzna is involved, and Screaming Mad George, so some decent special effects, but not enough to make this great. A few leftovers from part 4 are hanging around too, like Clint Howard and Neith Hunter, but that doesn\'t really make any difference. Anyway, I now have seeing the whole series out of my system. Now if I could get some of it out of my brain. 4 out of 5.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[1287,  313, 2380,  313,  661,    7,    2,   52,  229,    5,    2,
         200,    3,   38,  170,  669,   29, 5492,    6,    2,   83,  297,
         549,   32,  410,    3,    2,  186,   12,   29,    4,    1,  191,
         510,  549,    6,    2, 8229,  212,   46,  576,  175,  168,   20,
           1, 5361,  290,    4,    1,  761,  969,    1,    3,   24,  935,
        2271,  393,    7,    1, 1675,    4, 3747,  250,  148,    4,  112,
         436,  761, 3529,  548,    4, 3633,   31,    2, 1331,   28, 2096,
           3, 2912,    9,    6,  163,    4, 1006,   20,    2,    1,   15,
          85,   53,  147,    9,  292,   89,  959, 2314,  984,   27,  762,
           6,  959,    9,  564,   18,    7, 2140,   32,   24, 1254,   36,
           1,   85,    3, 3298,   85,    6, 1410,    3, 1936,    2, 3408,
         301,  965,    7,    4,  112,  740, 1977,   12,    1, 2014, 2772,
           3,    4,  428,    3, 5177,    6,  512, 1254,    1,  278,   27,
         139,   25,  308,    1,  579,    5,  259, 3529,    7,   92, 8981,
          32,    2, 3842,  230,   27,  289,    9,   35,    2, 5712,   18,
          27,  144, 2166,   56,    6,   26,   46,  466, 2014,   27,   40,
        2745,  657,  212,    4, 1376, 3002, 7080,  183,   36,  180,   52,
         920,    8,    2, 4028,   12,  969,    1,  158,   71,   53,   67,
          85, 2754,    4,  734,   51,    1, 1611,  294,   85,    6,    2,
        1164,    6,  163,    4, 3408,   15,   85,    6,  717,   85,   44,
           5,   24, 7158,    3,   48,  604,    7,   11,  225,  384,   73,
          65,   21,  242,   18,   27,  120,  295,    6,   26,  667,  129,
        4028,  948,    6,   67,   48,  158,   93,    1]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

Như bạn thấy ở trên, mỗi mã thông báo đã được thay thế bằng một số nguyên. Bạn có thể tra cứu các token (string) mà mỗi số nguyên tương ứng với bằng cách gọi .get_vocabulary() trên lớp.

 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

Bạn đang gần sẵn sàng để đào tạo mô hình của bạn. Là một bước tiền xử lý cuối cùng, bạn sẽ áp dụng các lớp TextVectorization bạn đã tạo trước đó để tàu, xác nhận, và dữ liệu thử nghiệm.

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

Cấu hình dữ liệu cho hiệu suất

Đây là hai phương pháp quan trọng bạn nên sử dụng khi tải dữ liệu để đảm bảo rằng I / O không trở thành chặn.

.cache() giữ dữ liệu trong bộ nhớ sau khi nó được nạp khỏi đĩa. Điều này sẽ đảm bảo dữ liệu không trở thành một nút cổ chai trong khi đào tạo mô hình của bạn. Nếu dữ liệu của bạn quá lớn để phù hợp với bộ nhớ, bạn cũng có thể sử dụng phương pháp này để tạo ra một performant on-disk cache, đó là hiệu quả hơn để đọc hơn nhiều file nhỏ.

.prefetch() trùng lặp dữ liệu tiền xử lý và mô hình thực hiện trong khi đào tạo.

Bạn có thể tìm hiểu thêm về cả hai phương pháp, cũng như làm thế nào để dữ liệu bộ nhớ cache vào đĩa trong hướng dẫn thực hiện dữ liệu .

 AUTOTUNE = tf.data.experimental.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)
 

Tạo mô hình

Đó là thời gian để tạo ra mạng lưới thần kinh của chúng tôi:

 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
_________________________________________________________________

Các lớp được xếp chồng lên nhau liên tục để xây dựng phân loại:

  1. Lớp đầu tiên là một Embedding lớp. lớp này có các đánh giá nguyên-mã hoá và nhìn lên một vector nhúng cho mỗi từ-index. Những vectơ được học như mô hình xe lửa. Các vectơ thêm tham số vào mảng đầu ra. Các kích thước kết quả là: (batch, sequence, embedding) . Để tìm hiểu thêm về embeddings, xem chữ nhúng hướng dẫn .
  2. Tiếp theo, một GlobalAveragePooling1D lớp trả về một vector đầu ra chiều dài cố định cho mỗi ví dụ bằng cách lấy trung bình so với chiều thứ tự. Điều này cho phép các mô hình để xử lý đầu vào của chiều dài thay đổi, theo cách đơn giản nhất có thể.
  3. Vector đầu ra cố định thời lượng này được dẫn qua một đầy đủ kết nối ( Dense ) lớp với 16 đơn vị ẩn.
  4. Lớp cuối cùng được đông kết nối với một nút đầu ra duy nhất.

Chức năng mất mát và tối ưu hóa

Một mô hình cần có một chức năng mất mát và một ưu cho việc đào tạo. Do đây là một vấn đề phân loại nhị phân và mô hình đầu ra một xác suất (một lớp duy nhất đơn vị với một kích hoạt sigmoid), bạn sẽ sử dụng losses.BinaryCrossentropy chức năng thua lỗ.

Bây giờ, cấu hình các mô hình sử dụng một ưu và chức năng bị mất:

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

Đào tạo mô hình

Bạn sẽ đào tạo các mô hình bằng cách truyền dataset đối tượng với phương pháp phù hợp.

 epochs = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs)
 
Epoch 1/10
625/625 [==============================] - 3s 5ms/step - loss: 0.6632 - binary_accuracy: 0.6931 - val_loss: 0.6135 - val_binary_accuracy: 0.7752
Epoch 2/10
625/625 [==============================] - 3s 4ms/step - loss: 0.5472 - binary_accuracy: 0.8003 - val_loss: 0.4968 - val_binary_accuracy: 0.8220
Epoch 3/10
625/625 [==============================] - 3s 4ms/step - loss: 0.4434 - binary_accuracy: 0.8459 - val_loss: 0.4187 - val_binary_accuracy: 0.8486
Epoch 4/10
625/625 [==============================] - 3s 4ms/step - loss: 0.3770 - binary_accuracy: 0.8660 - val_loss: 0.3726 - val_binary_accuracy: 0.8622
Epoch 5/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3349 - binary_accuracy: 0.8786 - val_loss: 0.3442 - val_binary_accuracy: 0.8678
Epoch 6/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3046 - binary_accuracy: 0.8889 - val_loss: 0.3253 - val_binary_accuracy: 0.8722
Epoch 7/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2807 - binary_accuracy: 0.8977 - val_loss: 0.3118 - val_binary_accuracy: 0.8726
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2609 - binary_accuracy: 0.9046 - val_loss: 0.3026 - val_binary_accuracy: 0.8762
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2443 - binary_accuracy: 0.9123 - val_loss: 0.2961 - val_binary_accuracy: 0.8774
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2309 - binary_accuracy: 0.9163 - val_loss: 0.2915 - val_binary_accuracy: 0.8804

Đánh giá mô hình

Hãy xem cách này thực hiện mô hình. Hai giá trị này sẽ được trả lại. Mất (một số đại diện cho lỗi của chúng tôi, giá trị thấp hơn là tốt hơn), và độ chính xác.

 loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
 
782/782 [==============================] - 2s 3ms/step - loss: 0.3097 - binary_accuracy: 0.8740
Loss:  0.30967268347740173
Accuracy:  0.8740400075912476

cách tiếp cận khá ngây thơ này đạt được độ chính xác khoảng 86%.

Tạo một âm mưu chính xác và mất theo thời gian

model.fit() trả về một History đối tượng có chứa một từ điển với tất cả mọi thứ đã xảy ra trong đào tạo:

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

Có bốn mục: một cho mỗi theo dõi số liệu trong đào tạo và xác nhận. Bạn có thể sử dụng những âm mưu đào tạo và xác nhận mất để so sánh, cũng như công tác đào tạo và xác nhận độ chính xác:

 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

Trong cốt truyện này, các dấu chấm đại diện cho sự mất mát đào tạo và chính xác, và các dòng rắn là mất xác và độ chính xác.

Chú ý sự mất mát đào tạo giảm theo từng thời đại và tính chính xác đào tạo tăng lên theo từng thời đại. Này được mong đợi khi sử dụng một gradient descent tối ưu hóa-nó nên giảm thiểu số lượng mong muốn trên mỗi lần lặp.

Đây không phải là trường hợp đối với sự mất mát thẩm định và độ chính xác-họ dường như đỉnh trước khi tính chính xác đào tạo. Đây là một ví dụ về overfitting: này thực hiện mô hình tốt hơn trên các dữ liệu đào tạo hơn là trên dữ liệu mà nó chưa bao giờ thấy trước đây. Sau thời điểm này, mô hình quá tối ưu và nghe tin cơ quan đại diện cụ thể cho các dữ liệu huấn luyện mà không khái quát để kiểm tra dữ liệu.

Đối với trường hợp đặc biệt này, bạn có thể ngăn chặn overfitting bằng cách đơn giản ngăn chặn việc đào tạo khi độ chính xác xác nhận không còn tăng. Một cách để làm điều đó là sử dụng callback EarlyStopping .

Xuất khẩu mô hình

Trong đoạn mã trên, bạn áp dụng TextVectorization lớp để các dữ liệu trước khi ăn văn bản cho mô hình. Nếu bạn muốn thực hiện mô hình của bạn khả năng xử lý chuỗi thô (ví dụ, để đơn giản hóa việc triển khai nó), bạn có thể bao gồm các TextVectorization lớp bên trong mô hình của bạn. Để làm như vậy, bạn có thể tạo ra một mô hình mới sử dụng các trọng bạn chỉ được đào tạo.

 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.3097 - accuracy: 0.8740
0.8740400075912476

Bao gồm các văn bản tiền xử lý logic bên trong mô hình của bạn cho phép bạn xuất một mô hình phục vụ sản xuất mà đơn giản hoá việc triển khai, và làm giảm khả năng đào tạo / kiểm tra nghiêng .

Có sự khác biệt hiệu suất cần lưu ý khi lựa chọn nơi nộp hồ sơ lớp TextVectorization của bạn. Sử dụng nó bên ngoài của mô hình của bạn cho phép bạn làm CPU xử lý không đồng bộ và đệm dữ liệu của bạn khi huấn luyện trên GPU. Vì vậy, nếu bạn đang đào tạo mô hình của bạn trên GPU, bạn có thể muốn đi với tùy chọn này để có được hiệu suất tốt nhất khi phát triển mô hình của bạn, sau đó chuyển sang bao gồm các lớp TextVectorization bên trong mô hình của bạn khi bạn đã sẵn sàng để chuẩn bị cho việc triển khai .

Ghé thăm này hướng dẫn để tìm hiểu thêm về tiết kiệm các mô hình.

Tập thể dục: phân loại nhiều lớp về các vấn đề Stack Overflow

Hướng dẫn này cho thấy làm thế nào để đào tạo một phân loại nhị phân từ đầu trên tập dữ liệu IMDB. Là một tập thể dục, bạn có thể sửa máy tính xách tay này để đào tạo một phân loại nhiều lớp để dự đoán thẻ của một câu hỏi lập trình trên Stack Overflow .

Chúng tôi đã chuẩn bị một bộ dữ liệu để bạn có thể sử dụng chứa cơ thể của hàng ngàn câu hỏi lập trình (ví dụ, "Làm thế nào có thể sắp xếp một cuốn từ điển bằng giá trị bằng Python?") Được đưa lên Stack Overflow. Mỗi được dán nhãn với chính xác một thẻ (hoặc Python, CSharp, JavaScript, hoặc Java). Nhiệm vụ của bạn là để có một câu hỏi như đầu vào, và dự đoán từ khóa thích hợp, trong trường hợp này, Python.

Bộ dữ liệu bạn sẽ làm việc với chứa vài ngàn câu hỏi được chiết xuất từ công chúng lớn hơn nhiều Stack Overflow bộ dữ liệu trên BigQuery , trong đó có hơn 17 triệu bài đăng nào.

Sau khi tải về các tập dữ liệu, bạn sẽ thấy nó có một cấu trúc thư mục tương tự như các tập dữ liệu IMDB bạn làm việc với trước đây:

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

Để hoàn thành bài tập này, bạn nên thay đổi máy tính xách tay này để làm việc với các tập dữ liệu Stack Overflow bằng cách làm cho những sửa đổi như sau:

  1. Ở phía trên cùng của máy tính xách tay của bạn, cập nhật mã rằng việc tải các tập dữ liệu IMDB với mã để tải về các tập dữ liệu Stack Overflow chúng tôi đã prepreared. Khi bộ dữ liệu Stack Overflow có một cấu trúc thư mục tương tự, bạn sẽ không cần phải thực hiện nhiều thay đổi.

  2. Sửa đổi các lớp cuối cùng của mô hình của bạn để đọc Dense(4) , như bây giờ có bốn lớp đầu ra.

  3. Khi bạn biên dịch mô hình của bạn, thay đổi sự mất mát để SparseCategoricalCrossentropy . Đây là chức năng mất đúng để sử dụng cho một vấn đề phân loại nhiều lớp, khi nhãn cho mỗi lớp học là các số nguyên (trong trường hợp của chúng tôi, họ có thể là 0, 1, 2, hoặc 3).

  4. Một khi những thay đổi này hoàn tất, bạn sẽ có thể đào tạo một phân loại nhiều lớp.

Nếu bạn gặp khó khăn, bạn có thể tìm một giải pháp ở đây .

Học nhiều hơn nữa

Hướng dẫn này giới thiệu phân loại văn bản từ đầu. Để tìm hiểu thêm về công việc phân loại văn bản nói chung, chúng tôi khuyên bạn nên đọc hướng dẫn này từ Google phát triển.

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