495 lines
30 KiB
Plaintext
495 lines
30 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Mạng tạo sinh\n",
|
|
"\n",
|
|
"Mạng Nơ-ron Hồi quy (RNNs) và các biến thể tế bào có cổng của chúng như Tế bào Bộ nhớ Ngắn Dài (LSTMs) và Đơn vị Hồi quy Có cổng (GRUs) cung cấp một cơ chế để mô hình hóa ngôn ngữ, tức là chúng có thể học cách sắp xếp từ và đưa ra dự đoán cho từ tiếp theo trong một chuỗi. Điều này cho phép chúng ta sử dụng RNNs cho các **nhiệm vụ tạo sinh**, chẳng hạn như tạo văn bản thông thường, dịch máy, và thậm chí là chú thích hình ảnh.\n",
|
|
"\n",
|
|
"Trong kiến trúc RNN mà chúng ta đã thảo luận ở đơn vị trước, mỗi đơn vị RNN tạo ra trạng thái ẩn tiếp theo như một đầu ra. Tuy nhiên, chúng ta cũng có thể thêm một đầu ra khác vào mỗi đơn vị hồi quy, điều này cho phép chúng ta xuất ra một **chuỗi** (có độ dài bằng với chuỗi ban đầu). Hơn nữa, chúng ta có thể sử dụng các đơn vị RNN không nhận đầu vào ở mỗi bước, mà chỉ nhận một vector trạng thái ban đầu, sau đó tạo ra một chuỗi các đầu ra.\n",
|
|
"\n",
|
|
"Trong notebook này, chúng ta sẽ tập trung vào các mô hình tạo sinh đơn giản giúp chúng ta tạo văn bản. Để đơn giản, hãy xây dựng **mạng cấp độ ký tự**, mạng này tạo văn bản từng chữ cái một. Trong quá trình huấn luyện, chúng ta cần lấy một tập hợp văn bản và chia nó thành các chuỗi ký tự.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import tensorflow as tf\n",
|
|
"from tensorflow import keras\n",
|
|
"import tensorflow_datasets as tfds\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Xây dựng từ vựng ký tự\n",
|
|
"\n",
|
|
"Để xây dựng mạng sinh ở cấp độ ký tự, chúng ta cần chia văn bản thành các ký tự riêng lẻ thay vì các từ. Lớp `TextVectorization` mà chúng ta đã sử dụng trước đây không thể làm điều này, vì vậy chúng ta có hai lựa chọn:\n",
|
|
"\n",
|
|
"* Tự tải văn bản và thực hiện việc phân tách 'thủ công', như trong [ví dụ chính thức của Keras này](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
|
|
"* Sử dụng lớp `Tokenizer` để phân tách ở cấp độ ký tự.\n",
|
|
"\n",
|
|
"Chúng ta sẽ chọn phương án thứ hai. `Tokenizer` cũng có thể được sử dụng để phân tách thành từ, vì vậy bạn có thể dễ dàng chuyển đổi từ phân tách cấp ký tự sang cấp từ.\n",
|
|
"\n",
|
|
"Để thực hiện phân tách ở cấp độ ký tự, chúng ta cần truyền tham số `char_level=True`:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def extract_text(x):\n",
|
|
" return x['title']+' '+x['description']\n",
|
|
"\n",
|
|
"def tupelize(x):\n",
|
|
" return (extract_text(x),x['label'])\n",
|
|
"\n",
|
|
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
|
|
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Chúng tôi cũng muốn sử dụng một token đặc biệt để biểu thị **kết thúc chuỗi**, mà chúng tôi sẽ gọi là `<eos>`. Hãy thêm nó thủ công vào từ vựng:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"eos_token = len(tokenizer.word_index)+1\n",
|
|
"tokenizer.word_index['<eos>'] = eos_token\n",
|
|
"\n",
|
|
"vocab_size = eos_token + 1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"tokenizer.texts_to_sequences(['Hello, world!'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Huấn luyện RNN sinh để tạo tiêu đề\n",
|
|
"\n",
|
|
"Cách chúng ta sẽ huấn luyện RNN để tạo tiêu đề tin tức như sau. Ở mỗi bước, chúng ta sẽ lấy một tiêu đề, tiêu đề này sẽ được đưa vào RNN, và với mỗi ký tự đầu vào, chúng ta sẽ yêu cầu mạng tạo ra ký tự đầu ra tiếp theo:\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Đối với ký tự cuối cùng của chuỗi, chúng ta sẽ yêu cầu mạng tạo ra token `<eos>`.\n",
|
|
"\n",
|
|
"Điểm khác biệt chính của RNN sinh mà chúng ta sử dụng ở đây là chúng ta sẽ lấy đầu ra từ mỗi bước của RNN, chứ không chỉ từ ô cuối cùng. Điều này có thể thực hiện được bằng cách chỉ định tham số `return_sequences` cho ô RNN.\n",
|
|
"\n",
|
|
"Do đó, trong quá trình huấn luyện, đầu vào của mạng sẽ là một chuỗi các ký tự được mã hóa với độ dài nhất định, và đầu ra sẽ là một chuỗi có cùng độ dài, nhưng được dịch chuyển một phần tử và kết thúc bằng `<eos>`. Minibatch sẽ bao gồm một số chuỗi như vậy, và chúng ta sẽ cần sử dụng **padding** để căn chỉnh tất cả các chuỗi.\n",
|
|
"\n",
|
|
"Hãy tạo các hàm để chuyển đổi tập dữ liệu cho chúng ta. Vì chúng ta muốn thêm padding vào các chuỗi ở cấp độ minibatch, trước tiên chúng ta sẽ nhóm tập dữ liệu bằng cách gọi `.batch()`, và sau đó `map` nó để thực hiện chuyển đổi. Vì vậy, hàm chuyển đổi sẽ nhận toàn bộ minibatch làm tham số:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def title_batch(x):\n",
|
|
" x = [t.numpy().decode('utf-8') for t in x]\n",
|
|
" z = tokenizer.texts_to_sequences(x)\n",
|
|
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
|
|
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Một vài điều quan trọng mà chúng ta thực hiện ở đây:\n",
|
|
"* Đầu tiên, chúng ta trích xuất văn bản thực tế từ tensor chuỗi\n",
|
|
"* `text_to_sequences` chuyển đổi danh sách các chuỗi thành danh sách các tensor số nguyên\n",
|
|
"* `pad_sequences` thêm phần đệm vào các tensor đó để đạt độ dài tối đa\n",
|
|
"* Cuối cùng, chúng ta mã hóa one-hot tất cả các ký tự, đồng thời thực hiện việc dịch chuyển và thêm `<eos>`. Chúng ta sẽ sớm thấy lý do tại sao cần mã hóa one-hot các ký tự\n",
|
|
"\n",
|
|
"Tuy nhiên, hàm này mang tính chất **Pythonic**, nghĩa là nó không thể được tự động chuyển đổi thành đồ thị tính toán của Tensorflow. Chúng ta sẽ gặp lỗi nếu cố gắng sử dụng hàm này trực tiếp trong hàm `Dataset.map`. Chúng ta cần bao bọc lời gọi Pythonic này bằng cách sử dụng trình bao `py_function`:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def title_batch_fn(x):\n",
|
|
" x = x['title']\n",
|
|
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
|
|
" return a,b"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Note**: Việc phân biệt giữa các hàm chuyển đổi Pythonic và Tensorflow có thể hơi phức tạp, và bạn có thể thắc mắc tại sao chúng ta không chuyển đổi tập dữ liệu bằng các hàm Python tiêu chuẩn trước khi truyền nó vào `fit`. Mặc dù điều này hoàn toàn có thể thực hiện, việc sử dụng `Dataset.map` có một lợi thế lớn, vì pipeline chuyển đổi dữ liệu được thực thi bằng đồ thị tính toán của Tensorflow, tận dụng khả năng tính toán của GPU và giảm thiểu nhu cầu truyền dữ liệu giữa CPU/GPU.\n",
|
|
"\n",
|
|
"Bây giờ chúng ta có thể xây dựng mạng generator và bắt đầu huấn luyện. Nó có thể dựa trên bất kỳ cell hồi quy nào mà chúng ta đã thảo luận trong bài học trước (đơn giản, LSTM hoặc GRU). Trong ví dụ này, chúng ta sẽ sử dụng LSTM.\n",
|
|
"\n",
|
|
"Vì mạng nhận các ký tự làm đầu vào và kích thước từ vựng khá nhỏ, chúng ta không cần lớp embedding, đầu vào được mã hóa one-hot có thể trực tiếp đi vào cell LSTM. Lớp đầu ra sẽ là một bộ phân loại `Dense` chuyển đổi đầu ra của LSTM thành các số token được mã hóa one-hot.\n",
|
|
"\n",
|
|
"Ngoài ra, vì chúng ta đang xử lý các chuỗi có độ dài thay đổi, chúng ta có thể sử dụng lớp `Masking` để tạo một mặt nạ bỏ qua phần được đệm của chuỗi. Điều này không hoàn toàn cần thiết, vì chúng ta không quá quan tâm đến mọi thứ vượt quá token `<eos>`, nhưng chúng ta sẽ sử dụng nó để có thêm kinh nghiệm với loại lớp này. `input_shape` sẽ là `(None, vocab_size)`, trong đó `None` biểu thị chuỗi có độ dài thay đổi, và hình dạng đầu ra cũng là `(None, vocab_size)`, như bạn có thể thấy từ `summary`:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"sequential\"\n",
|
|
"_________________________________________________________________\n",
|
|
"Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
"masking (Masking) (None, None, 84) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"lstm (LSTM) (None, None, 128) 109056 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense (Dense) (None, None, 84) 10836 \n",
|
|
"=================================================================\n",
|
|
"Total params: 119,892\n",
|
|
"Trainable params: 119,892\n",
|
|
"Non-trainable params: 0\n",
|
|
"_________________________________________________________________\n",
|
|
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
|
|
]
|
|
},
|
|
"execution_count": 7,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"model = keras.models.Sequential([\n",
|
|
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
|
|
" keras.layers.LSTM(128,return_sequences=True),\n",
|
|
" keras.layers.Dense(vocab_size,activation='softmax')\n",
|
|
"])\n",
|
|
"\n",
|
|
"model.summary()\n",
|
|
"model.compile(loss='categorical_crossentropy')\n",
|
|
"\n",
|
|
"model.fit(ds_train.batch(8).map(title_batch_fn))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Tạo đầu ra\n",
|
|
"\n",
|
|
"Bây giờ chúng ta đã huấn luyện mô hình, chúng ta muốn sử dụng nó để tạo một số đầu ra. Trước tiên, chúng ta cần một cách để giải mã văn bản được biểu diễn bằng một chuỗi số token. Để làm điều này, chúng ta có thể sử dụng hàm `tokenizer.sequences_to_texts`; tuy nhiên, nó không hoạt động tốt với việc mã hóa token ở cấp độ ký tự. Vì vậy, chúng ta sẽ lấy một từ điển các token từ tokenizer (gọi là `word_index`), xây dựng một bản đồ ngược, và tự viết hàm giải mã của riêng mình:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
|
|
"\n",
|
|
"def decode(x):\n",
|
|
" return ''.join([reverse_map[t] for t in x])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Bây giờ, chúng ta sẽ bắt đầu với một chuỗi `start`, mã hóa nó thành một dãy `inp`, và sau đó ở mỗi bước, chúng ta sẽ gọi mạng để suy luận ký tự tiếp theo.\n",
|
|
"\n",
|
|
"Đầu ra của mạng `out` là một vector gồm `vocab_size` phần tử, đại diện cho xác suất của mỗi token, và chúng ta có thể tìm số token có xác suất cao nhất bằng cách sử dụng `argmax`. Sau đó, chúng ta thêm ký tự này vào danh sách các token đã được tạo, và tiếp tục quá trình tạo. Quá trình tạo một ký tự này được lặp lại `size` lần để tạo ra số lượng ký tự yêu cầu, và chúng ta sẽ kết thúc sớm khi gặp `eos_token`.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"def generate(model,size=100,start='Today '):\n",
|
|
" inp = tokenizer.texts_to_sequences([start])[0]\n",
|
|
" chars = inp\n",
|
|
" for i in range(size):\n",
|
|
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
|
|
" nc = tf.argmax(out)\n",
|
|
" if nc==eos_token:\n",
|
|
" break\n",
|
|
" chars.append(nc.numpy())\n",
|
|
" inp = inp+[nc]\n",
|
|
" return decode(chars)\n",
|
|
" \n",
|
|
"generate(model)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Lấy mẫu đầu ra trong quá trình huấn luyện\n",
|
|
"\n",
|
|
"Vì chúng ta không có bất kỳ chỉ số hữu ích nào như *độ chính xác*, cách duy nhất để thấy rằng mô hình của chúng ta đang cải thiện là bằng cách **lấy mẫu** chuỗi được tạo ra trong quá trình huấn luyện. Để làm điều này, chúng ta sẽ sử dụng **callbacks**, tức là các hàm mà chúng ta có thể truyền vào hàm `fit`, và chúng sẽ được gọi định kỳ trong quá trình huấn luyện.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Epoch 1/3\n",
|
|
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
|
|
"Today #39;s a lead in the company for the strike\n",
|
|
"Epoch 2/3\n",
|
|
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
|
|
"Today #39;s the Market Service on Security Start (AP)\n",
|
|
"Epoch 3/3\n",
|
|
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
|
|
"Today #39;s a line on the strike to start for the start\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
|
|
]
|
|
},
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"sampling_callback = keras.callbacks.LambdaCallback(\n",
|
|
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
|
|
")\n",
|
|
"\n",
|
|
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Ví dụ này đã tạo ra một văn bản khá tốt, nhưng vẫn có thể cải thiện thêm theo nhiều cách:\n",
|
|
"\n",
|
|
"* **Thêm nội dung**. Chúng ta chỉ sử dụng tiêu đề cho nhiệm vụ này, nhưng bạn có thể thử nghiệm với toàn bộ văn bản. Hãy nhớ rằng RNN không xử lý tốt các chuỗi dài, vì vậy sẽ hợp lý hơn nếu chia chúng thành các câu ngắn hơn hoặc luôn huấn luyện trên một độ dài chuỗi cố định với giá trị được định trước `num_chars` (ví dụ, 256). Bạn có thể thử thay đổi ví dụ trên thành kiến trúc như vậy, sử dụng [hướng dẫn chính thức của Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/) làm nguồn cảm hứng.\n",
|
|
"\n",
|
|
"* **LSTM nhiều lớp**. Sẽ hợp lý nếu thử nghiệm với 2 hoặc 3 lớp tế bào LSTM. Như đã đề cập trong bài học trước, mỗi lớp LSTM sẽ trích xuất các mẫu nhất định từ văn bản, và trong trường hợp trình tạo cấp độ ký tự, chúng ta có thể kỳ vọng lớp LSTM thấp hơn chịu trách nhiệm trích xuất âm tiết, và các lớp cao hơn - từ và tổ hợp từ. Điều này có thể được thực hiện đơn giản bằng cách truyền tham số số lượng lớp vào hàm khởi tạo LSTM.\n",
|
|
"\n",
|
|
"* Bạn cũng có thể muốn thử nghiệm với **đơn vị GRU** để xem loại nào hoạt động tốt hơn, và với **kích thước lớp ẩn khác nhau**. Lớp ẩn quá lớn có thể dẫn đến hiện tượng overfitting (ví dụ: mạng sẽ học chính xác văn bản), và kích thước nhỏ hơn có thể không tạo ra kết quả tốt.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Tạo văn bản mềm và nhiệt độ\n",
|
|
"\n",
|
|
"Trong định nghĩa trước của `generate`, chúng ta luôn chọn ký tự có xác suất cao nhất làm ký tự tiếp theo trong văn bản được tạo. Điều này dẫn đến việc văn bản thường \"lặp lại\" giữa các chuỗi ký tự giống nhau nhiều lần, như trong ví dụ sau:\n",
|
|
"```\n",
|
|
"today of the second the company and a second the company ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"Tuy nhiên, nếu chúng ta xem xét phân bố xác suất cho ký tự tiếp theo, có thể thấy rằng sự khác biệt giữa một vài xác suất cao nhất không lớn, ví dụ: một ký tự có xác suất là 0.2, ký tự khác là 0.19, v.v. Chẳng hạn, khi tìm ký tự tiếp theo trong chuỗi '*play*', ký tự tiếp theo có thể là khoảng trắng hoặc **e** (như trong từ *player*).\n",
|
|
"\n",
|
|
"Điều này dẫn đến kết luận rằng không phải lúc nào cũng \"công bằng\" khi chọn ký tự có xác suất cao nhất, vì việc chọn ký tự có xác suất cao thứ hai vẫn có thể dẫn đến văn bản có ý nghĩa. Sẽ hợp lý hơn nếu chúng ta **lấy mẫu** ký tự từ phân bố xác suất do đầu ra của mạng cung cấp.\n",
|
|
"\n",
|
|
"Việc lấy mẫu này có thể được thực hiện bằng hàm `np.multinomial`, hàm này triển khai cái gọi là **phân phối đa thức**. Một hàm thực hiện việc tạo văn bản **mềm** này được định nghĩa dưới đây:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 33,
|
|
"metadata": {
|
|
"scrolled": true
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"\n",
|
|
"--- Temperature = 0.3\n",
|
|
"Today #39;s strike #39; to start at the store return\n",
|
|
"On Sunday PO to Be Data Profit Up (Reuters)\n",
|
|
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
|
|
"President olding of the blast start for the strike to pay <b>...</b>\n",
|
|
"Little red riding hood ficed to the spam countered in European <b>...</b>\n",
|
|
"\n",
|
|
"--- Temperature = 0.8\n",
|
|
"Today countie strikes ryder missile faces food market blut\n",
|
|
"On Sunday collores lose-toppy of sale of Bullment in <b>...</b>\n",
|
|
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
|
|
"President Ol Luster for Profit Peaced Raised (AP)\n",
|
|
"Little red riding hood dace on depart talks #39; bank up\n",
|
|
"\n",
|
|
"--- Temperature = 1.0\n",
|
|
"Today wits House buiting debate fixes #39; supervice stake again\n",
|
|
"On Sunday arling digital poaching In for level\n",
|
|
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
|
|
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
|
|
"Little red riding hood signs on cash in Carter-youb\n",
|
|
"\n",
|
|
"--- Temperature = 1.3\n",
|
|
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
|
|
"On Sunday hround elitwing wint EU Powerburlinetien\n",
|
|
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
|
|
"President lost securitys from power Elections in Smiltrials\n",
|
|
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
|
|
"\n",
|
|
"--- Temperature = 1.8\n",
|
|
"Today #39;It: He deat: N.KA Asside\n",
|
|
"On Sunday i arry Par aldeup patient Wo stele1\n"
|
|
]
|
|
},
|
|
{
|
|
"ename": "KeyError",
|
|
"evalue": "0",
|
|
"output_type": "error",
|
|
"traceback": [
|
|
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
|
|
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
|
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|
"\u001b[0;31mKeyError\u001b[0m: 0"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
|
|
" inp = tokenizer.texts_to_sequences([start])[0]\n",
|
|
" chars = inp\n",
|
|
" for i in range(size):\n",
|
|
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
|
|
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
|
|
" probs = probs/np.sum(probs)\n",
|
|
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
|
|
" if nc==eos_token:\n",
|
|
" break\n",
|
|
" chars.append(nc)\n",
|
|
" inp = inp+[nc]\n",
|
|
" return decode(chars)\n",
|
|
"\n",
|
|
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
|
|
" \n",
|
|
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
|
|
" print(f\"\\n--- Temperature = {i}\")\n",
|
|
" for j in range(5):\n",
|
|
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Chúng tôi đã giới thiệu thêm một tham số gọi là **nhiệt độ**, được sử dụng để chỉ ra mức độ chúng ta nên tuân thủ xác suất cao nhất. Nếu nhiệt độ là 1.0, chúng ta thực hiện lấy mẫu đa thức công bằng, và khi nhiệt độ tiến tới vô cực - tất cả các xác suất trở nên bằng nhau, và chúng ta chọn ngẫu nhiên ký tự tiếp theo. Trong ví dụ dưới đây, chúng ta có thể quan sát rằng văn bản trở nên vô nghĩa khi chúng ta tăng nhiệt độ quá nhiều, và nó giống như văn bản được tạo cứng \"lặp lại\" khi nhiệt độ tiến gần đến 0.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Tuyên bố miễn trừ trách nhiệm**: \nTài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn tham khảo chính thức. Đối với các thông tin quan trọng, nên sử dụng dịch vụ dịch thuật chuyên nghiệp từ con người. Chúng tôi không chịu trách nhiệm cho bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"interpreter": {
|
|
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
|
|
},
|
|
"kernelspec": {
|
|
"display_name": "Python 3.8.12 ('py38')",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.12"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "9fbb7d5fda708537649f71f5f646fcde",
|
|
"translation_date": "2025-08-29T15:38:53+00:00",
|
|
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
|
|
"language_code": "vi"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |