414 lines
23 KiB
Plaintext
414 lines
23 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ỉ lấy 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": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Loading dataset...\n",
|
|
"Building vocab...\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"import torch\n",
|
|
"import torchtext\n",
|
|
"import numpy as np\n",
|
|
"from torchnlp import *\n",
|
|
"train_dataset,test_dataset,classes,vocab = load_dataset()"
|
|
]
|
|
},
|
|
{
|
|
"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ừ. Điều này có thể thực hiện bằng cách định nghĩa một bộ tách từ khác:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Vocabulary size = 82\n",
|
|
"Encoding of 'a' is 1\n",
|
|
"Character with code 13 is c\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"def char_tokenizer(words):\n",
|
|
" return list(words) #[word for word in words]\n",
|
|
"\n",
|
|
"counter = collections.Counter()\n",
|
|
"for (label, line) in train_dataset:\n",
|
|
" counter.update(char_tokenizer(line))\n",
|
|
"vocab = torchtext.vocab.vocab(counter)\n",
|
|
"\n",
|
|
"vocab_size = len(vocab)\n",
|
|
"print(f\"Vocabulary size = {vocab_size}\")\n",
|
|
"print(f\"Encoding of 'a' is {vocab.get_stoi()['a']}\")\n",
|
|
"print(f\"Character with code 13 is {vocab.get_itos()[13]}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Hãy xem ví dụ về cách chúng ta có thể mã hóa văn bản từ tập dữ liệu của mình:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"tensor([ 0, 1, 2, 2, 3, 4, 5, 6, 3, 7, 8, 1, 9, 10, 3, 11, 2, 1,\n",
|
|
" 12, 3, 7, 1, 13, 14, 3, 15, 16, 5, 17, 3, 5, 18, 8, 3, 7, 2,\n",
|
|
" 1, 13, 14, 3, 19, 20, 8, 21, 5, 8, 9, 10, 22, 3, 20, 8, 21, 5,\n",
|
|
" 8, 9, 10, 3, 23, 3, 4, 18, 17, 9, 5, 23, 10, 8, 2, 2, 8, 9,\n",
|
|
" 10, 24, 3, 0, 1, 2, 2, 3, 4, 5, 9, 8, 8, 5, 25, 10, 3, 26,\n",
|
|
" 12, 27, 16, 26, 2, 27, 16, 28, 29, 30, 1, 16, 26, 3, 17, 31, 3, 21,\n",
|
|
" 2, 5, 9, 1, 23, 13, 32, 16, 27, 13, 10, 24, 3, 1, 9, 8, 3, 10,\n",
|
|
" 8, 8, 27, 16, 28, 3, 28, 9, 8, 8, 16, 3, 1, 28, 1, 27, 16, 6])"
|
|
]
|
|
},
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"def enc(x):\n",
|
|
" return torch.LongTensor(encode(x,voc=vocab,tokenizer=char_tokenizer))\n",
|
|
"\n",
|
|
"enc(train_dataset[0][1])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Huấn luyện RNN tạo sinh\n",
|
|
"\n",
|
|
"Cách chúng ta sẽ huấn luyện RNN để tạo văn bản như sau. Ở mỗi bước, chúng ta sẽ lấy một chuỗi ký tự có độ dài `nchars`, và yêu cầu mạng tạo ra ký tự đầu ra tiếp theo cho mỗi ký tự đầu vào:\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Tùy thuộc vào tình huống thực tế, chúng ta cũng có thể muốn bao gồm một số ký tự đặc biệt, chẳng hạn như *kết thúc chuỗi* `<eos>`. Trong trường hợp của chúng ta, mục tiêu là huấn luyện mạng để tạo văn bản liên tục, vì vậy chúng ta sẽ cố định kích thước của mỗi chuỗi bằng số lượng token `nchars`. Do đó, mỗi ví dụ huấn luyện sẽ bao gồm `nchars` đầu vào và `nchars` đầu ra (là chuỗi đầu vào được dịch sang trái một ký tự). Minibatch sẽ bao gồm một số chuỗi như vậy.\n",
|
|
"\n",
|
|
"Cách chúng ta tạo minibatch là lấy mỗi văn bản tin tức có độ dài `l`, và tạo tất cả các kết hợp đầu vào-đầu ra có thể từ nó (sẽ có `l-nchars` kết hợp như vậy). Những kết hợp này sẽ tạo thành một minibatch, và kích thước của các minibatch sẽ khác nhau ở mỗi bước huấn luyện.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"(tensor([[ 0, 1, 2, ..., 28, 29, 30],\n",
|
|
" [ 1, 2, 2, ..., 29, 30, 1],\n",
|
|
" [ 2, 2, 3, ..., 30, 1, 16],\n",
|
|
" ...,\n",
|
|
" [20, 8, 21, ..., 1, 28, 1],\n",
|
|
" [ 8, 21, 5, ..., 28, 1, 27],\n",
|
|
" [21, 5, 8, ..., 1, 27, 16]]),\n",
|
|
" tensor([[ 1, 2, 2, ..., 29, 30, 1],\n",
|
|
" [ 2, 2, 3, ..., 30, 1, 16],\n",
|
|
" [ 2, 3, 4, ..., 1, 16, 26],\n",
|
|
" ...,\n",
|
|
" [ 8, 21, 5, ..., 28, 1, 27],\n",
|
|
" [21, 5, 8, ..., 1, 27, 16],\n",
|
|
" [ 5, 8, 9, ..., 27, 16, 6]]))"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"nchars = 100\n",
|
|
"\n",
|
|
"def get_batch(s,nchars=nchars):\n",
|
|
" ins = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
|
|
" outs = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
|
|
" for i in range(len(s)-nchars):\n",
|
|
" ins[i] = enc(s[i:i+nchars])\n",
|
|
" outs[i] = enc(s[i+1:i+nchars+1])\n",
|
|
" return ins,outs\n",
|
|
"\n",
|
|
"get_batch(train_dataset[0][1])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Bây giờ chúng ta sẽ định nghĩa mạng tạo. Nó có thể dựa trên bất kỳ tế bào hồi quy nào mà chúng ta đã thảo luận trong đơn vị trước (đơn giản, LSTM hoặc GRU). Trong ví dụ của chúng ta, 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 nhúng, đầu vào được mã hóa một-hot có thể trực tiếp đi vào tế bào LSTM. Tuy nhiên, vì chúng ta truyền số ký tự làm đầu vào, chúng ta cần mã hóa một-hot chúng trước khi truyền vào LSTM. Điều này được thực hiện bằng cách gọi hàm `one_hot` trong quá trình `forward`. Bộ mã hóa đầu ra sẽ là một lớp tuyến tính, lớp này sẽ chuyển trạng thái ẩn thành đầu ra được mã hóa một-hot.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"class LSTMGenerator(torch.nn.Module):\n",
|
|
" def __init__(self, vocab_size, hidden_dim):\n",
|
|
" super().__init__()\n",
|
|
" self.rnn = torch.nn.LSTM(vocab_size,hidden_dim,batch_first=True)\n",
|
|
" self.fc = torch.nn.Linear(hidden_dim, vocab_size)\n",
|
|
"\n",
|
|
" def forward(self, x, s=None):\n",
|
|
" x = torch.nn.functional.one_hot(x,vocab_size).to(torch.float32)\n",
|
|
" x,s = self.rnn(x,s)\n",
|
|
" return self.fc(x),s"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Trong quá trình huấn luyện, chúng ta muốn có khả năng lấy mẫu văn bản được tạo ra. Để làm điều đó, chúng ta sẽ định nghĩa hàm `generate`, hàm này sẽ tạo ra chuỗi đầu ra có độ dài `size`, bắt đầu từ chuỗi ban đầu `start`.\n",
|
|
"\n",
|
|
"Cách hoạt động như sau. Đầu tiên, chúng ta sẽ truyền toàn bộ chuỗi bắt đầu qua mạng, và lấy trạng thái đầu ra `s` cùng với ký tự dự đoán tiếp theo `out`. Vì `out` được mã hóa dưới dạng one-hot, chúng ta sử dụng `argmax` để lấy chỉ số của ký tự `nc` trong từ vựng, và dùng `itos` để xác định ký tự thực tế rồi thêm nó vào danh sách các ký tự kết quả `chars`. 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.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def generate(net,size=100,start='today '):\n",
|
|
" chars = list(start)\n",
|
|
" out, s = net(enc(chars).view(1,-1).to(device))\n",
|
|
" for i in range(size):\n",
|
|
" nc = torch.argmax(out[0][-1])\n",
|
|
" chars.append(vocab.get_itos()[nc])\n",
|
|
" out, s = net(nc.view(1,-1),s)\n",
|
|
" return ''.join(chars)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Bây giờ hãy bắt đầu huấn luyện! Vòng lặp huấn luyện gần như giống hệt với tất cả các ví dụ trước đây của chúng ta, nhưng thay vì in độ chính xác, chúng ta sẽ in văn bản được tạo mẫu sau mỗi 1000 epoch.\n",
|
|
"\n",
|
|
"Cần chú ý đặc biệt đến cách chúng ta tính toán loss. Chúng ta cần tính loss dựa trên đầu ra được mã hóa one-hot `out` và văn bản mong đợi `text_out`, là danh sách các chỉ số ký tự. May mắn thay, hàm `cross_entropy` yêu cầu đầu ra mạng chưa được chuẩn hóa làm đối số đầu tiên và số lớp làm đối số thứ hai, điều này hoàn toàn phù hợp với những gì chúng ta có. Nó cũng tự động thực hiện việc tính trung bình trên kích thước minibatch.\n",
|
|
"\n",
|
|
"Chúng ta cũng giới hạn việc huấn luyện bởi số mẫu `samples_to_train`, để không phải chờ quá lâu. Chúng tôi khuyến khích bạn thử nghiệm và thử huấn luyện lâu hơn, có thể trong vài epoch (trong trường hợp đó, bạn sẽ cần tạo một vòng lặp khác xung quanh đoạn mã này).\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Current loss = 4.398899078369141\n",
|
|
"today sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr s\n",
|
|
"Current loss = 2.161320447921753\n",
|
|
"today and to the tor to to the tor to to the tor to to the tor to to the tor to to the tor to to the tor t\n",
|
|
"Current loss = 1.6722588539123535\n",
|
|
"today and the court to the could to the could to the could to the could to the could to the could to the c\n",
|
|
"Current loss = 2.423795223236084\n",
|
|
"today and a second to the conternation of the conternation of the conternation of the conternation of the \n",
|
|
"Current loss = 1.702607274055481\n",
|
|
"today and the company to the company to the company to the company to the company to the company to the co\n",
|
|
"Current loss = 1.692358136177063\n",
|
|
"today and the company to the company to the company to the company to the company to the company to the co\n",
|
|
"Current loss = 1.9722288846969604\n",
|
|
"today and the control the control the control the control the control the control the control the control \n",
|
|
"Current loss = 1.8705692291259766\n",
|
|
"today and the second to the second to the second to the second to the second to the second to the second t\n",
|
|
"Current loss = 1.7626899480819702\n",
|
|
"today and a security and a security and a security and a security and a security and a security and a secu\n",
|
|
"Current loss = 1.5574463605880737\n",
|
|
"today and the company and the company and the company and the company and the company and the company and \n",
|
|
"Current loss = 1.5620026588439941\n",
|
|
"today and the be that the be the be that the be the be that the be the be that the be the be that the be t\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"net = LSTMGenerator(vocab_size,64).to(device)\n",
|
|
"\n",
|
|
"samples_to_train = 10000\n",
|
|
"optimizer = torch.optim.Adam(net.parameters(),0.01)\n",
|
|
"loss_fn = torch.nn.CrossEntropyLoss()\n",
|
|
"net.train()\n",
|
|
"for i,x in enumerate(train_dataset):\n",
|
|
" # x[0] is class label, x[1] is text\n",
|
|
" if len(x[1])-nchars<10:\n",
|
|
" continue\n",
|
|
" samples_to_train-=1\n",
|
|
" if not samples_to_train: break\n",
|
|
" text_in, text_out = get_batch(x[1])\n",
|
|
" optimizer.zero_grad()\n",
|
|
" out,s = net(text_in)\n",
|
|
" loss = torch.nn.functional.cross_entropy(out.view(-1,vocab_size),text_out.flatten()) #cross_entropy(out,labels)\n",
|
|
" loss.backward()\n",
|
|
" optimizer.step()\n",
|
|
" if i%1000==0:\n",
|
|
" print(f\"Current loss = {loss.item()}\")\n",
|
|
" print(generate(net))"
|
|
]
|
|
},
|
|
{
|
|
"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 một số cách:\n",
|
|
"\n",
|
|
"* **Cải thiện việc tạo minibatch**. Cách chúng ta chuẩn bị dữ liệu để huấn luyện là tạo một minibatch từ một mẫu duy nhất. Điều này không lý tưởng, vì các minibatch có kích thước khác nhau, và một số thậm chí không thể được tạo ra vì văn bản nhỏ hơn `nchars`. Ngoài ra, các minibatch nhỏ không tận dụng GPU đủ hiệu quả. Sẽ hợp lý hơn nếu lấy một đoạn văn bản lớn từ tất cả các mẫu, sau đó tạo tất cả các cặp đầu vào-đầu ra, xáo trộn chúng, và tạo các minibatch có kích thước bằng nhau.\n",
|
|
"\n",
|
|
"* **LSTM nhiều lớp**. Có lý do để thử 2 hoặc 3 lớp tế bào LSTM. Như đã đề cập trong phần trước, mỗi lớp của LSTM 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 - cho từ và các 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 **các đơn vị GRU** để xem loại nào hoạt động tốt hơn, và với **các kích thước lớp ẩn khác nhau**. Lớp ẩn quá lớn có thể dẫn đến 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 phối 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 chúng ta đế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 hơn, 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 **lấy mẫu** ký tự từ phân phối xác suất được cung cấp bởi đầu ra của mạng.\n",
|
|
"\n",
|
|
"Việc lấy mẫu này có thể được thực hiện bằng hàm `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": 10,
|
|
"metadata": {
|
|
"scrolled": true
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"--- Temperature = 0.3\n",
|
|
"Today and a company and complete an all the land the restrational the as a security and has provers the pay to and a report and the computer in the stand has filities and working the law the stations for a company and with the company and the final the first company and refight of the state and and workin\n",
|
|
"\n",
|
|
"--- Temperature = 0.8\n",
|
|
"Today he oniis its first to Aus bomblaties the marmation a to manan boogot that pirate assaid a relaid their that goverfin the the Cappets Ecrotional Assonia Cition targets it annight the w scyments Blamity #39;s TVeer Diercheg Reserals fran envyuil that of ster said access what succers of Dour-provelith\n",
|
|
"\n",
|
|
"--- Temperature = 1.0\n",
|
|
"Today holy they a 11 will meda a toket subsuaties, engins for Chanos, they's has stainger past to opening orital his thempting new Nattona was al innerforder advan-than #36;s night year his religuled talitatian what the but with Wednesday to Justment will wemen of Mark CCC Camp as Timed Nae wome a leaders\n",
|
|
"\n",
|
|
"--- Temperature = 1.3\n",
|
|
"Today gpone 2.5 fech atcusion poor cocles toparsdorM.cht Line Pamage put 43 his calt lowed to the book, that has authh-the silia rruch ailing to'ory andhes beutirsimi- Aefffive heading offil an auf eacklets is charged evis, Gunymy oy) Mony has it after-sloythyor loveId out filme, the Natabl -Najuntaxiggs \n",
|
|
"\n",
|
|
"--- Temperature = 1.8\n",
|
|
"Today plary, P.slan chly\\401 mardregationly #39;t 8.1Mide) closes ,filtcon alfly playin roven!\\grea.-QFBEP: Iss onfarchQ/itilia CCf Zivesigntwasta orce.-Peul-aw.uicrin of fuglinfsut aftaningwo, MIEX awayew Aice Woiduar Corvagiugge oppo esig ThusBratourid canthly-RyI.co lagitems\\eexciaishes.conBabntusmor I\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"def generate_soft(net,size=100,start='today ',temperature=1.0):\n",
|
|
" chars = list(start)\n",
|
|
" out, s = net(enc(chars).view(1,-1).to(device))\n",
|
|
" for i in range(size):\n",
|
|
" #nc = torch.argmax(out[0][-1])\n",
|
|
" out_dist = out[0][-1].div(temperature).exp()\n",
|
|
" nc = torch.multinomial(out_dist,1)[0]\n",
|
|
" chars.append(vocab.get_itos()[nc])\n",
|
|
" out, s = net(nc.view(1,-1),s)\n",
|
|
" return ''.join(chars)\n",
|
|
" \n",
|
|
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
|
|
" print(f\"--- Temperature = {i}\\n{generate_soft(net,size=300,start='Today ',temperature=i)}\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Chúng tôi đã giới thiệu một tham số mới 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 độ tăng lên vô hạn - 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 \"lặp lại\" được tạo cứng 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 thông tin chính thức. Đối với các thông tin quan trọng, khuyến nghị sử dụng dịch vụ dịch thuật chuyên nghiệp bởi 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": "7673cd150d96c74c6d6011460094efb4",
|
|
"translation_date": "2025-08-29T15:44:09+00:00",
|
|
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativePyTorch.ipynb",
|
|
"language_code": "vi"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |