오늘 현지 TensorFlow Everywhere 이벤트에 참석하세요!

TF-Hub를 사용한 Bangla 문서 분류

TensorFlow.org에서 보기 Google Colab에서 실행하기 GitHub에서 소스 보기 노트북 다운로드하기

주의: pip로 python 패키지를 설치하는 외에도 이 노트북에서는 sudo apt install을 사용하여 시스템 패키지unzip을 설치합니다.

이 colab은 비 영어/현지어로 텍스트를 분류하기 위해 Tensorflow Hub를 사용하는 데모입니다. 여기에서는 Bangla를 현지어로 선택하고 사전 훈련된 단어 임베딩을 사용하여 Bangla 뉴스 기사를 5가지 범주로 분류하는 다중 클래스 분류 작업을 해결합니다. Bangla용 사전 훈련 임베딩은 157개 언어에 대해 사전 훈련된 단어 벡터를 게시한 Facebook 라이브러리인 fastText에서 가져옵니다.

먼저 TF-Hub의 사전 훈련된 임베딩 exporter를 사용하여 단어 임베딩을 텍스트 임베딩 모듈로 변환한 다음, Tensorflow의 사용자 친화적인 상위 수준 API인 tf.keras로 분류자를 훈련하는 모듈을 사용하여 딥 러닝 모델을 빌드합니다. 여기에서 fastText 임베딩을 사용하더라도 다른 작업에서 사전 훈련된 다른 임베딩을 내보내고 Tensorflow Hub를 사용하여 신속하게 결과를 얻을 수 있습니다.

설정

# https://github.com/pypa/setuptools/issues/1694#issuecomment-466010982
pip install -q gdown --no-use-pep517
sudo apt-get install -y unzip
Reading package lists...
Building dependency tree...
Reading state information...
unzip is already the newest version (6.0-21ubuntu1).
The following packages were automatically installed and are no longer required:
  dconf-gsettings-backend dconf-service dkms freeglut3 freeglut3-dev
  glib-networking glib-networking-common glib-networking-services
  gsettings-desktop-schemas libcairo-gobject2 libcolord2 libdconf1
  libegl1-mesa libepoxy0 libglu1-mesa libglu1-mesa-dev libgtk-3-0
  libgtk-3-common libice-dev libjansson4 libjson-glib-1.0-0
  libjson-glib-1.0-common libproxy1v5 librest-0.7-0 libsm-dev
  libsoup-gnome2.4-1 libsoup2.4-1 libxi-dev libxmu-dev libxmu-headers
  libxnvctrl0 libxt-dev linux-gcp-headers-5.0.0-1026
  linux-headers-5.0.0-1026-gcp linux-image-5.0.0-1026-gcp
  linux-modules-5.0.0-1026-gcp pkg-config policykit-1-gnome python3-xkit
  screen-resolution-extra xserver-xorg-core-hwe-18.04
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 94 not upgraded.

import os

import tensorflow as tf
import tensorflow_hub as hub

import gdown
import numpy as np
from sklearn.metrics import classification_report
import matplotlib.pyplot as plt
import seaborn as sns

데이터세트

다양한 Bangla 뉴스 포털에서 수집한 약 3,76,226개의 기사가 있고 경제, 국내, 국제, 스포츠 및 엔터테인먼트의 5가지 범주로 분류된 BARD(Bangla Article Dataset)를 사용합니다. 이 (bit.ly/BARD_DATASET) 링크가 가리키는 Google 드라이브 파일을 GitHub 리포지토리에서 다운로드합니다.

gdown.download(
    url='https://drive.google.com/uc?id=1Ag0jd21oRwJhVFIBohmX_ogeojVtapLy',
    output='bard.zip',
    quiet=True
)
'bard.zip'
unzip -qo bard.zip

사전 훈련된 단어 벡터를 TF-Hub 모듈로 내보내기

TF-Hub는 여기에서 단어 임베딩을 TF-Hub 텍스트 임베딩 모듈로 변환하기 위한 몇 가지 편리한 스크립트를 제공합니다. Bangla 또는 다른 언어 모듈을 만들려면 .txt 또는 .vec 파일을 포함하는 단어를 export_v2.py와 동일한 디렉토리로 다운로드하고 스크립트를 실행하기만 하면 됩니다.

Exporter는 임베딩 벡터를 읽고 Tensorflow SavedModel로 내보냅니다. SavedModel에는 가중치와 그래프를 포함한 완전한 TensorFlow 프로그램이 포함되어 있습니다. TF-Hub는 SavedModel을 텍스트 분류를 위한 모델을 빌드하는 데 사용할 모듈로 로드할 수 있습니다. 모델을 빌드하기 위해 tf.keras를 사용하므로 Hub 모듈이 Keras 레이어로 사용할 래퍼를 제공하는 hub.KerasLayer를 사용할 것입니다.

먼저 fastText에서 단어 임베딩을 가져오고 TF-Hub 리포지토리에서 임베딩 exporter를 가져옵니다.

curl -O https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.bn.300.vec.gz
curl -O https://raw.githubusercontent.com/tensorflow/hub/master/examples/text_embeddings_v2/export_v2.py
gunzip -qf cc.bn.300.vec.gz --k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  840M  100  840M    0     0  16.5M      0  0:00:50  0:00:50 --:--:-- 16.6M
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7493  100  7493    0     0  17466      0 --:--:-- --:--:-- --:--:-- 17466

그런 다음 임베딩 파일에서 exporter 스크립트를 실행합니다. fastText 임베딩에는 헤더 행이 있고 크기가 매우 크기 때문에(모듈로 변환한 후 bangla의 경우 약 3.3GB) 첫 번째 행을 무시하고 처음 100,000개의 토큰만 텍스트 임베딩 모듈로 내보냅니다.

python export_v2.py --embedding_file=cc.bn.300.vec --export_path=text_module --num_lines_to_ignore=1 --num_lines_to_use=100000
2020-11-12 01:43:22.242268: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
2020-11-12 01:43:37.161418: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcuda.so.1
2020-11-12 01:43:37.869488: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.870275: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1716] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-11-12 01:43:37.870330: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
2020-11-12 01:43:37.872254: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcublas.so.10
2020-11-12 01:43:37.874073: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcufft.so.10
2020-11-12 01:43:37.874479: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcurand.so.10
2020-11-12 01:43:37.876363: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcusolver.so.10
2020-11-12 01:43:37.877221: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcusparse.so.10
2020-11-12 01:43:37.880938: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudnn.so.7
2020-11-12 01:43:37.881083: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.881815: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.882475: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1858] Adding visible gpu devices: 0
2020-11-12 01:43:37.882882: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN)to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2020-11-12 01:43:37.889624: I tensorflow/core/platform/profile_utils/cpu_utils.cc:104] CPU Frequency: 2000185000 Hz
2020-11-12 01:43:37.890060: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x4d07b50 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-11-12 01:43:37.890114: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2020-11-12 01:43:37.983513: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.984337: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x96f9bb0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:
2020-11-12 01:43:37.984397: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Tesla V100-SXM2-16GB, Compute Capability 7.0
2020-11-12 01:43:37.984648: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.985319: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1716] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-11-12 01:43:37.985370: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
2020-11-12 01:43:37.985429: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcublas.so.10
2020-11-12 01:43:37.985455: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcufft.so.10
2020-11-12 01:43:37.985466: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcurand.so.10
2020-11-12 01:43:37.985479: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcusolver.so.10
2020-11-12 01:43:37.985490: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcusparse.so.10
2020-11-12 01:43:37.985502: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudnn.so.7
2020-11-12 01:43:37.985588: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.986296: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:37.986940: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1858] Adding visible gpu devices: 0
2020-11-12 01:43:37.986988: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
2020-11-12 01:43:38.425119: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1257] Device interconnect StreamExecutor with strength 1 edge matrix:
2020-11-12 01:43:38.425177: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1263]      0 
2020-11-12 01:43:38.425187: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1276] 0:   N 
2020-11-12 01:43:38.425425: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:38.426210: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-11-12 01:43:38.426880: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1402] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14764 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)
INFO:tensorflow:Assets written to: text_module/assets
I1112 01:43:39.961149 140651856697152 builder_impl.py:775] Assets written to: text_module/assets

module_path = "text_module"
embedding_layer = hub.KerasLayer(module_path, trainable=False)

텍스트 임베딩 모듈은 문자열의 1D 텐서에 있는 문장 배치를 입력으로 받아 문장에 해당하는 형상의 임베딩 벡터(batch_size, embedding_dim)를 출력합니다. 공백으로 분할하여 입력을 전처리합니다. 단어 임베딩은 sqrtn sqrtn combiner를 사용하여 문장 임베딩에 결합됩니다(여기 참조). 데모를 위해 Bangla 단어 목록을 입력으로 전달하고 해당 임베딩 벡터를 얻습니다.

embedding_layer(['বাস', 'বসবাস', 'ট্রেন', 'যাত্রী', 'ট্রাক'])
<tf.Tensor: shape=(5, 300), dtype=float64, numpy=
array([[ 0.0462, -0.0355,  0.0129, ...,  0.0025, -0.0966,  0.0216],
       [-0.0631, -0.0051,  0.085 , ...,  0.0249, -0.0149,  0.0203],
       [ 0.1371, -0.069 , -0.1176, ...,  0.029 ,  0.0508, -0.026 ],
       [ 0.0532, -0.0465, -0.0504, ...,  0.02  , -0.0023,  0.0011],
       [ 0.0908, -0.0404, -0.0536, ..., -0.0275,  0.0528,  0.0253]])>

Tensorflow 데이터세트로 변환하기

데이터세트가 정말 크기 때문에 메모리에 전체 데이터세트를 로드하는 대신 Tensorflow 데이터세트 기능을 사용하여 일괄적으로 런타임에 샘플을 생성하는 데 생성기를 사용합니다. 데이터세트는 또한 매우 불균형적이므로 생성기를 사용하기 전에 데이터세트를 셔플합니다.

dir_names = ['economy', 'sports', 'entertainment', 'state', 'international']

file_paths = []
labels = []
for i, dir in enumerate(dir_names):
  file_names = ["/".join([dir, name]) for name in os.listdir(dir)]
  file_paths += file_names
  labels += [i] * len(os.listdir(dir))

np.random.seed(42)
permutation = np.random.permutation(len(file_paths))

file_paths = np.array(file_paths)[permutation]
labels = np.array(labels)[permutation]

셔플한 후 훈련 및 검증 예제에서 레이블 분포를 확인할 수 있습니다.

train_frac = 0.8
train_size = int(len(file_paths) * train_frac)
# plot training vs validation distribution
plt.subplot(1, 2, 1)
plt.hist(labels[0:train_size])
plt.title("Train labels")
plt.subplot(1, 2, 2)
plt.hist(labels[train_size:])
plt.title("Validation labels")
plt.tight_layout()

png

생성기를 사용하여 데이터세트를 생성하려면 먼저 file_paths에서 각 기사를 읽고 레이블 배열에서 레이블을 읽어 각 스텝에서 하나의 훈련 예제를 생성하는 생성기 함수를 작성합니다. 이 생성기 함수를 tf.data.Dataset.from_generator 메서드에 전달하고 출력 유형을 지정합니다. 각 훈련 예제는 tf.string 데이터 형식의 기사와 원-핫 인코딩된 레이블을 포함하는 튜플입니다. skiptake 메서드를 사용하여 80-20의 훈련-검증 분할로 데이터세트를 분할합니다.

def load_file(path, label):
    return tf.io.read_file(path), label
def make_datasets(train_size):
  batch_size = 256

  train_files = file_paths[:train_size]
  train_labels = labels[:train_size]
  train_ds = tf.data.Dataset.from_tensor_slices((train_files, train_labels))
  train_ds = train_ds.map(load_file).shuffle(5000)
  train_ds = train_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)

  test_files = file_paths[train_size:]
  test_labels = labels[train_size:]
  test_ds = tf.data.Dataset.from_tensor_slices((test_files, test_labels))
  test_ds = test_ds.map(load_file)
  test_ds = test_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)


  return train_ds, test_ds
train_data, validation_data = make_datasets(train_size)

모델 훈련 및 평가

keras에서 다른 레이어로 사용하기 위해 모듈 주위에 래퍼를 이미 추가했으므로 레이어의 선형 스택인 작은 순차 모델을 만들 수 있습니다. 다른 레이어와 마찬가지로 model.add로 텍스트 임베딩 모듈을 추가할 수 있습니다. 손실과 옵티마이저를 지정하여 모델을 컴파일하고 10개 epoch 동안 훈련합니다. tf.keras API는 tensorflow 데이터세트를 입력으로 처리할 수 있으므로 모델 훈련을 위해 데이터세트 인스턴스를 fit 메서드로 전달할 수 있습니다. 생성기 함수를 사용하기 때문에 tf.data가 샘플을 생성하고 배치 처리하여 모델에 공급하는 작업을 처리합니다.

모델

def create_model():
  model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=[], dtype=tf.string),
    embedding_layer,
    tf.keras.layers.Dense(64, activation="relu"),
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(5),
  ])
  model.compile(loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
      optimizer="adam", metrics=['accuracy'])
  return model
model = create_model()
# Create earlystopping callback
early_stopping_callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=3)
WARNING:tensorflow:Layer dense is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because its dtype defaults to floatx.

If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.

To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.


WARNING:tensorflow:Layer dense is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because its dtype defaults to floatx.

If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.

To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.


훈련

history = model.fit(train_data, 
                    validation_data=validation_data, 
                    epochs=5, 
                    callbacks=[early_stopping_callback])
Epoch 1/5
1176/1176 [==============================] - 56s 48ms/step - loss: 0.2187 - accuracy: 0.9277 - val_loss: 0.1436 - val_accuracy: 0.9515
Epoch 2/5
1176/1176 [==============================] - 55s 47ms/step - loss: 0.1390 - accuracy: 0.9512 - val_loss: 0.1327 - val_accuracy: 0.9533
Epoch 3/5
1176/1176 [==============================] - 55s 47ms/step - loss: 0.1276 - accuracy: 0.9547 - val_loss: 0.1226 - val_accuracy: 0.9574
Epoch 4/5
1176/1176 [==============================] - 55s 47ms/step - loss: 0.1211 - accuracy: 0.9564 - val_loss: 0.1209 - val_accuracy: 0.9568
Epoch 5/5
1176/1176 [==============================] - 56s 47ms/step - loss: 0.1160 - accuracy: 0.9580 - val_loss: 0.1154 - val_accuracy: 0.9585

평가

각 epoch에 대한 손실 및 정확성 값을 포함하는 fit 메서드에서 반환된 history 객체를 사용하여 훈련 및 검증 데이터에 대한 정확성과 손실 곡선을 시각화할 수 있습니다.

# Plot training & validation accuracy values
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

# Plot training & validation loss values
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

png

png

예측

검증 데이터에 대한 예측값을 얻고 혼동 행렬을 확인하여 5개 클래스 각각에 대한 모델의 성능을 확인할 수 있습니다. predict 메서드는 np.argmax를 사용하여 클래스 레이블로 변환하는 각 클래스의 확률에 대한 n-d 배열을 반환합니다.

y_pred = model.predict(validation_data)
y_pred = np.argmax(y_pred, axis=1)
samples = file_paths[0:3]
for i, sample in enumerate(samples):
  f = open(sample)
  text = f.read()
  print(text[0:100])
  print("True Class: ", sample.split("/")[0])
  print("Predicted Class: ", dir_names[y_pred[i]])
  f.close()

বেঙ্গল চলচ্চিত্র উন্নয়ন ফোরামের অনুদানে চলচ্চিত্র নির্মাণ করছেন আশুতোষ সুজন। ছবির নাম আমার বাবা। 
True Class:  entertainment
Predicted Class:  state

জঙ্গিবাদের বর্তমান উত্থানের পেছনে রাজনীতির চরম ব্যর্থতা রয়েছে বলে মন্তব্য করেছেন চট্টগ্রাম সিটি করপ
True Class:  state
Predicted Class:  state

খুদে সদস্য
এখনো দুই সপ্তাহও হয়নি বয়স। কিন্তু এর মধ্যেই রিয়াল মাদ্রিদের সদস্য হয়ে গেছে মার্টিন ক্যাস
True Class:  sports
Predicted Class:  state

성능 비교

이제 labels에서 검증 데이터의 올바른 레이블을 가져와 예측값과 비교하고 classification_report를 생성합니다.

y_true = np.array(labels[train_size:])
print(classification_report(y_true, y_pred, target_names=dir_names))
               precision    recall  f1-score   support

      economy       0.81      0.81      0.81      3897
       sports       0.98      0.99      0.99     10204
entertainment       0.92      0.94      0.93      6256
        state       0.98      0.97      0.97     48512
international       0.91      0.94      0.93      6377

     accuracy                           0.96     75246
    macro avg       0.92      0.93      0.93     75246
 weighted avg       0.96      0.96      0.96     75246


또한 모델의 성능을 0.96 정밀도를 보고하는 원본 논문에서 얻은 결과와 비교할 수 있습니다. 원래 저자는 구두점 및 숫자를 삭제하고 가장 빈번한 25개의 제외어를 제거하는 등 데이터세트에 수행된 많은 전처리 스텝을 설명했습니다. classification_report에서 볼 수 있듯이 전처리 없이 5개 epoch 동안만 훈련한 후에도 0.96의 정밀도와 정확성이 얻어집니다!

이 예제에서는 임베딩 모듈에서 Keras 레이어를 만들 때 trainable=False를 설정했습니다. 이것은 임베딩 가중치가 훈련 중에 업데이트되지 않음을 의미합니다. 이 데이터세트에서 단 두 번의 epoch로 97% 정확성에 도달하려면 True로 설정해 보세요.