Bước 3: Chuẩn bị dữ liệu

Trước khi có thể cấp dữ liệu cho một mô hình, dữ liệu đó cần được chuyển đổi sang một định dạng mà mô hình đó có thể hiểu được.

Trước tiên, các mẫu dữ liệu mà chúng tôi đã thu thập có thể được sắp xếp theo một thứ tự cụ thể. Chúng tôi không muốn thông tin nào liên quan đến thứ tự các mẫu ảnh hưởng đến mối quan hệ giữa văn bản và nhãn. Ví dụ: nếu một tập dữ liệu được sắp xếp theo lớp và sau đó được chia thành các tập huấn luyện/xác thực, thì các tập hợp này sẽ không đại diện cho sự phân phối dữ liệu tổng thể.

Phương pháp hay nhất đơn giản để đảm bảo mô hình không bị ảnh hưởng bởi thứ tự dữ liệu là luôn phát ngẫu nhiên dữ liệu trước khi làm bất cứ điều gì khác. Nếu dữ liệu của bạn đã được chia thành các tập huấn luyện và xác thực, hãy đảm bảo chuyển đổi dữ liệu xác thực giống như cách chuyển đổi dữ liệu huấn luyện. Nếu chưa có bộ bài tập huấn luyện và xác thực riêng, bạn có thể chia nhỏ các mẫu sau khi tách nhỏ; thông thường, bạn nên sử dụng 80% mẫu để huấn luyện và 20% để xác thực.

Thứ hai, thuật toán của công nghệ máy học sẽ lấy số làm dữ liệu đầu vào. Điều này có nghĩa là chúng ta sẽ cần chuyển đổi văn bản thành vectơ số. Quá trình này có hai bước:

  1. Mã hoá: Chia văn bản thành các từ hoặc văn bản phụ nhỏ hơn để có thể khái quát hoá mối quan hệ giữa văn bản và nhãn. Điều này xác định “từ vựng” của tập dữ liệu (tập hợp mã thông báo duy nhất có trong dữ liệu).

  2. Vectơ hóa: Xác định một số đo tốt để thể hiện đặc điểm của các văn bản này.

Hãy xem cách thực hiện hai bước này cho cả vectơ n gam và vectơ trình tự, cũng như cách tối ưu hoá cách biểu diễn vectơ bằng cách sử dụng các kỹ thuật lựa chọn tính năng và chuẩn hoá.

Vectơ gam [Tùy chọn A]

Trong các đoạn tiếp theo, chúng ta sẽ xem cách thực hiện mã hoá và vectơ hoá cho các mô hình n-gam. Chúng tôi cũng sẽ trình bày cách chúng tôi có thể tối ưu hoá cách trình bày n-gam bằng các kỹ thuật chọn tính năng và chuẩn hoá.

Trong vectơ n gam, văn bản được biểu thị dưới dạng một tập hợp các n gam duy nhất: các nhóm mã thông báo n liền kề (thường là các từ). Xem xét văn bản The mouse ran up the clock. Ở đây, từ unigam (n = 1) là ['the', 'mouse', 'ran', 'up', 'clock'], từ Bigram (n = 2) là ['the mouse', 'mouse ran', 'ran up', 'up the', 'the clock'], v.v.

Mã hoá

Chúng tôi nhận thấy rằng việc mã hoá thành từ unigram và Bigrams cung cấp độ chính xác tốt, đồng thời tốn ít thời gian tính toán hơn.

Vectơ hoá

Sau khi chia mẫu văn bản thành n gam, chúng ta sẽ cần chuyển các n gam này thành vectơ số mà mô hình máy học có thể xử lý. Ví dụ dưới đây cho thấy các chỉ mục được chỉ định cho các uni hiểu và phần lớn được tạo cho hai văn bản.

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'the': 7, 'mouse': 2, 'ran': 4, 'up': 10,
  'clock': 0, 'the mouse': 9, 'mouse ran': 3, 'ran up': 6, 'up the': 11, 'the
clock': 8, 'down': 1, 'ran down': 5}

Sau khi được chỉ định cho ngam, chúng tôi thường vectơ hoá bằng cách sử dụng một trong các tuỳ chọn sau.

Mã hoá một lần: Mọi văn bản mẫu được biểu thị dưới dạng một vectơ cho biết có hoặc không có mã thông báo trong văn bản.

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]

Số lượng mã hóa: Mọi văn bản mẫu được biểu thị dưới dạng một vectơ cho biết số lượng mã thông báo trong văn bản. Xin lưu ý rằng phần tử tương ứng với unigram ' ' (được in đậm bên dưới) hiện được biểu thị là 2 vì từ "the" xuất hiện hai lần trong văn bản.

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1]

Mã hoá ff-idf: Vấn đề với hai phương pháp trên là những từ phổ biến xảy ra theo tần suất tương tự trong tất cả tài liệu (tức là các từ không phải là duy nhất đối với mẫu văn bản trong tập dữ liệu) sẽ không bị phạt. Ví dụ: các từ như “a” sẽ xuất hiện rất thường xuyên trong tất cả các văn bản. Vì vậy, số lượng mã thông báo cao hơn cho từ “the” so với các từ có ý nghĩa khác sẽ không hữu ích lắm.

'The mouse ran up the clock' = [0.33, 0, 0.23, 0.23, 0.23, 0, 0.33, 0.47, 0.33,
0.23, 0.33, 0.33] (See Scikit-learn TfidfTransformer)

Có nhiều vectơ biểu diễn khác, nhưng ba vectơ được sử dụng phổ biến nhất ở trên.

Chúng tôi quan sát thấy rằng mã hóa tf-idf tốt hơn một chút so với hai loại còn lại về độ chính xác (trung bình: cao hơn 0,25 – 15%), và bạn nên sử dụng phương pháp này để vectơ hoá n gam. Tuy nhiên, hãy lưu ý rằng tính năng này chiếm nhiều bộ nhớ hơn (vì sử dụng biểu diễn dấu phẩy động) và mất nhiều thời gian hơn để tính toán, đặc biệt là đối với các tập dữ liệu lớn (có thể mất gấp đôi thời gian trong một số trường hợp).

Lựa chọn tính năng

Khi chuyển đổi tất cả văn bản trong một tập dữ liệu thành mã thông báo uni+bigram, chúng tôi có thể sẽ có hàng chục nghìn mã thông báo. Không phải tất cả mã thông báo/tính năng này đều góp phần dự đoán nhãn. Vì vậy, chúng ta có thể thả một số mã thông báo nhất định, chẳng hạn như các mã thông báo xảy ra cực kỳ hiếm khi xảy ra trên tập dữ liệu. Chúng tôi cũng có thể đo lường mức độ quan trọng của tính năng (mức độ đóng góp của mỗi mã thông báo cho các thông tin dự đoán về nhãn) và chỉ bao gồm các mã thông báo có nhiều thông tin nhất.

Có nhiều hàm thống kê sử dụng các tính năng và nhãn tương ứng, đồng thời tạo ra điểm mức độ quan trọng của tính năng. Hai hàm được dùng phổ biến là f_classifchi2. Thử nghiệm của chúng tôi cho thấy cả hai hàm này đều hoạt động hiệu quả như nhau.

Quan trọng hơn, chúng tôi thấy rằng mức độ chính xác cao nhất vào khoảng 20.000 tính năng cho nhiều tập dữ liệu (Xem Hình 6). Việc thêm nhiều tính năng hơn ngưỡng này sẽ đóng góp rất ít và thậm chí đôi khi dẫn đến việc cung cấp quá nhiều và giảm hiệu suất.

So với K và độ chính xác

Hình 6: Các tính năng K hàng đầu so với Độ chính xác. Trong các tập dữ liệu, độ chính xác của khoảng 20 nghìn tính năng hàng đầu.

Chuẩn hoá

Chuẩn hoá sẽ chuyển đổi tất cả giá trị tính năng/mẫu thành giá trị nhỏ và tương tự. Việc này giúp đơn giản hoá quá trình hội tụ độ dốc trong thuật toán học. Theo những gì chúng tôi thấy, việc chuẩn hoá trong quá trình xử lý trước dữ liệu dường như không làm tăng thêm nhiều giá trị trong các vấn đề về phân loại văn bản; bạn nên bỏ qua bước này.

Mã sau đây tổng hợp tất cả các bước nêu trên:

  • Mã hoá mẫu văn bản thành từ uni+sơ đồ từ,
  • Minh họa bằng cách sử dụng mã hóa tf-idf,
  • Chỉ chọn 20.000 tính năng hàng đầu từ vectơ mã thông báo bằng cách loại bỏ các mã thông báo xuất hiện ít hơn 2 lần và sử dụng f_classif để tính toán mức độ quan trọng của tính năng.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif

# Vectorization parameters
# Range (inclusive) of n-gram sizes for tokenizing text.
NGRAM_RANGE = (1, 2)

# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Whether text should be split into word or character n-grams.
# One of 'word', 'char'.
TOKEN_MODE = 'word'

# Minimum document/corpus frequency below which a token will be discarded.
MIN_DOCUMENT_FREQUENCY = 2

def ngram_vectorize(train_texts, train_labels, val_texts):
    """Vectorizes texts as n-gram vectors.

    1 text = 1 tf-idf vector the length of vocabulary of unigrams + bigrams.

    # Arguments
        train_texts: list, training text strings.
        train_labels: np.ndarray, training labels.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val: vectorized training and validation texts
    """
    # Create keyword arguments to pass to the 'tf-idf' vectorizer.
    kwargs = {
            'ngram_range': NGRAM_RANGE,  # Use 1-grams + 2-grams.
            'dtype': 'int32',
            'strip_accents': 'unicode',
            'decode_error': 'replace',
            'analyzer': TOKEN_MODE,  # Split text into word tokens.
            'min_df': MIN_DOCUMENT_FREQUENCY,
    }
    vectorizer = TfidfVectorizer(**kwargs)

    # Learn vocabulary from training texts and vectorize training texts.
    x_train = vectorizer.fit_transform(train_texts)

    # Vectorize validation texts.
    x_val = vectorizer.transform(val_texts)

    # Select top 'k' of the vectorized features.
    selector = SelectKBest(f_classif, k=min(TOP_K, x_train.shape[1]))
    selector.fit(x_train, train_labels)
    x_train = selector.transform(x_train).astype('float32')
    x_val = selector.transform(x_val).astype('float32')
    return x_train, x_val

Với cách biểu diễn vectơ n gam, chúng ta loại bỏ rất nhiều thông tin về thứ tự từ và ngữ pháp (tốt nhất, chúng ta có thể duy trì một số thông tin về thứ tự một phần khi n > 1). Đây được gọi là phương pháp truyền miệng. Cách biểu diễn này được dùng kết hợp với các mô hình không tính đến thứ tự, chẳng hạn như hồi quy logistic, các lớp perceptron nhiều lớp, máy tăng cường độ dốc, hỗ trợ máy vectơ.

Vectơ trình tự [Tuỳ chọn B]

Trong các đoạn tiếp theo, chúng ta sẽ xem cách tiến hành mã hoá và đưa vectơ thành công cho các mô hình trình tự. Ngoài ra, chúng tôi cũng sẽ trình bày cách tối ưu hoá cách trình bày trình tự bằng cách sử dụng kỹ thuật lựa chọn tính năng và chuẩn hoá.

Đối với một số mẫu văn bản, thứ tự từ rất quan trọng đối với ý nghĩa của văn bản. Ví dụ: Câu "Tôi từng ghét bỏ đường đi làm của mình". Chiếc xe đạp mới của tôi đã thay đổi hoàn toàn” chỉ có thể hiểu được khi đọc theo thứ tự. Các mô hình như CNN/RNN có thể dự đoán thứ tự của các từ trong mẫu. Đối với những mô hình này, chúng tôi biểu thị văn bản dưới dạng chuỗi mã thông báo.

Mã hoá

Văn bản có thể được biểu thị dưới dạng một chuỗi ký tự hoặc một chuỗi từ. Chúng tôi nhận thấy rằng việc sử dụng cách trình bày ở cấp từ cung cấp hiệu suất tốt hơn so với mã thông báo ký tự. Đây cũng là tiêu chuẩn chung tuân theo ngành. Việc sử dụng mã thông báo ký tự chỉ hợp lý nếu văn bản có nhiều lỗi chính tả, điều này thường không đúng.

Vectơ hoá

Khi đã chuyển đổi mẫu văn bản thành trình tự từ, chúng ta cần chuyển các trình tự này thành vectơ số. Ví dụ bên dưới cho thấy các chỉ mục được chỉ định cho các biểu đồ đã tạo cho hai văn bản, sau đó là trình tự các chỉ mục mã thông báo mà văn bản đầu tiên được chuyển đổi.

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'clock': 5, 'ran': 3, 'up': 4, 'down': 6, 'the': 1, 'mouse': 2}.
NOTE: 'the' occurs most frequently, so the index value of 1 is assigned to it.
Some libraries reserve index 0 for unknown tokens, as is the case here.
Sequence of token indexes: 'The mouse ran up the clock' = [1, 2, 3, 4, 1, 5]

Có hai tuỳ chọn để vectơ hoá trình tự mã thông báo:

Mã hoá một lần: Trình tự được biểu thị bằng cách sử dụng các vectơ từ trong không gian n-n, trong đó n = kích thước của từ vựng. Nội dung trình bày này rất phù hợp khi chúng tôi mã hoá dưới dạng ký tự và do đó, từ vựng rất nhỏ. Khi chúng ta mã hoá dưới dạng từ, từ vựng thường sẽ có hàng chục nghìn mã thông báo, khiến các vectơ nóng trở nên rất thưa thớt và không hiệu quả. Ví dụ:

'The mouse ran up the clock' = [
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 0]
]

Nhúng từ: Các từ có liên quan đến nghĩa. Kết quả là, chúng ta có thể biểu thị mã thông báo từ trong một không gian vectơ dày đặc (~ vài trăm số thực), trong đó vị trí và khoảng cách giữa các từ cho biết mức độ tương tự của chúng về mặt ngữ nghĩa (Xem Hình 7). Cách trình bày này được gọi là tính năng nhúng từ.

Nhúng từ

Hình 7: Nhúng từ

Mô hình trình tự thường có một lớp nhúng như lớp đầu tiên. Lớp này tìm hiểu cách biến trình tự chỉ mục từ thành vectơ nhúng từ trong quá trình huấn luyện, sao cho mỗi chỉ mục từ được liên kết với một vectơ dày đặc gồm các giá trị thực đại diện cho vị trí của từ đó trong không gian ngữ nghĩa (Xem Hình 8).

Lớp nhúng

Hình 8: Lớp nhúng

Lựa chọn tính năng

Không phải tất cả các từ trong dữ liệu của chúng tôi đều góp phần gợi ý nhãn. Chúng tôi có thể tối ưu hoá quá trình học tập bằng cách loại bỏ các từ hiếm hoặc không liên quan khỏi từ vựng. Trên thực tế, chúng tôi nhận thấy rằng việc sử dụng 20.000 tính năng thường xuyên nhất là đủ. Điều này cũng đúng đối với các mô hình n gam (Xem Hình 6).

Hãy cùng nhau thực hiện tất cả các bước nêu trên trong quá trình vectơ hoá trình tự. Mã sau đây thực hiện những việc này:

  • Mã hoá văn bản thành các từ
  • Tạo từ vựng bằng cách sử dụng 20.000 mã thông báo hàng đầu
  • Chuyển đổi mã thông báo thành vectơ trình tự
  • Gắn chuỗi theo trình tự với độ dài cố định
from tensorflow.python.keras.preprocessing import sequence
from tensorflow.python.keras.preprocessing import text

# Vectorization parameters
# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Limit on the length of text sequences. Sequences longer than this
# will be truncated.
MAX_SEQUENCE_LENGTH = 500

def sequence_vectorize(train_texts, val_texts):
    """Vectorizes texts as sequence vectors.

    1 text = 1 sequence vector with fixed length.

    # Arguments
        train_texts: list, training text strings.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val, word_index: vectorized training and validation
            texts and word index dictionary.
    """
    # Create vocabulary with training texts.
    tokenizer = text.Tokenizer(num_words=TOP_K)
    tokenizer.fit_on_texts(train_texts)

    # Vectorize training and validation texts.
    x_train = tokenizer.texts_to_sequences(train_texts)
    x_val = tokenizer.texts_to_sequences(val_texts)

    # Get max sequence length.
    max_length = len(max(x_train, key=len))
    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH

    # Fix sequence length to max value. Sequences shorter than the length are
    # padded in the beginning and sequences longer are truncated
    # at the beginning.
    x_train = sequence.pad_sequences(x_train, maxlen=max_length)
    x_val = sequence.pad_sequences(x_val, maxlen=max_length)
    return x_train, x_val, tokenizer.word_index

Vectơ nhãn

Chúng ta đã biết cách chuyển đổi dữ liệu văn bản mẫu thành vectơ số. Quy trình tương tự phải được áp dụng cho các nhãn. Chúng ta chỉ cần chuyển đổi các nhãn thành các giá trị trong dải ô [0, num_classes - 1]. Ví dụ: nếu có 3 lớp, chúng ta chỉ có thể sử dụng các giá trị 0, 1 và 2 để biểu thị các giá trị đó. Trong nội bộ, mạng sẽ sử dụng các vectơ nóng để biểu thị các giá trị này (để tránh suy ra mối quan hệ không chính xác giữa các nhãn). Cách trình bày này phụ thuộc vào hàm mất mát và hàm kích hoạt lớp cuối cùng mà chúng ta sử dụng trong mạng nơron. Chúng ta sẽ tìm hiểu thêm về những điều này trong phần tiếp theo.