414 lines
22 KiB
Plaintext
414 lines
22 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Rețele generative\n",
|
|
"\n",
|
|
"Rețelele Neuronale Recurente (RNN) și variantele lor cu celule cu porți, cum ar fi Celulele cu Memorie pe Termen Lung (LSTM) și Unitățile Recurente cu Porți (GRU), au oferit un mecanism pentru modelarea limbajului, adică pot învăța ordonarea cuvintelor și pot oferi predicții pentru următorul cuvânt dintr-o secvență. Acest lucru ne permite să folosim RNN-urile pentru **sarcini generative**, cum ar fi generarea obișnuită de text, traducerea automată și chiar generarea de descrieri pentru imagini.\n",
|
|
"\n",
|
|
"În arhitectura RNN discutată în unitatea anterioară, fiecare unitate RNN producea următoarea stare ascunsă ca ieșire. Totuși, putem adăuga și o altă ieșire fiecărei unități recurente, ceea ce ne-ar permite să generăm o **secvență** (care este egală ca lungime cu secvența originală). Mai mult, putem folosi unități RNN care nu acceptă o intrare la fiecare pas, ci doar primesc un vector de stare inițială și apoi produc o secvență de ieșiri.\n",
|
|
"\n",
|
|
"În acest notebook, ne vom concentra pe modele generative simple care ne ajută să generăm text. Pentru simplitate, să construim o **rețea la nivel de caractere**, care generează text literă cu literă. În timpul antrenării, trebuie să luăm un corpus de text și să-l împărțim în secvențe de litere.\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": [
|
|
"## Construirea vocabularului de caractere\n",
|
|
"\n",
|
|
"Pentru a construi o rețea generativă la nivel de caractere, trebuie să împărțim textul în caractere individuale, în loc de cuvinte. Acest lucru poate fi realizat prin definirea unui tokenizator diferit:\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": [
|
|
"Să vedem exemplul de cum putem codifica textul din setul nostru de date:\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": [
|
|
"## Antrenarea unui RNN generativ\n",
|
|
"\n",
|
|
"Modul în care vom antrena RNN pentru a genera text este următorul. La fiecare pas, vom lua o secvență de caractere de lungime `nchars` și vom cere rețelei să genereze următorul caracter de ieșire pentru fiecare caracter de intrare:\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"În funcție de scenariul concret, este posibil să dorim să includem și câteva caractere speciale, cum ar fi *sfârșit-de-secvență* `<eos>`. În cazul nostru, dorim doar să antrenăm rețeaua pentru generarea continuă de text, așa că vom fixa dimensiunea fiecărei secvențe să fie egală cu `nchars` tokeni. Prin urmare, fiecare exemplu de antrenament va consta din `nchars` intrări și `nchars` ieșiri (care sunt secvența de intrare deplasată cu un simbol spre stânga). Un minibatch va consta din mai multe astfel de secvențe.\n",
|
|
"\n",
|
|
"Modul în care vom genera minibatch-uri este să luăm fiecare text de știri de lungime `l` și să generăm toate combinațiile posibile de intrare-ieșire din acesta (vor exista `l-nchars` astfel de combinații). Acestea vor forma un minibatch, iar dimensiunea minibatch-urilor va fi diferită la fiecare pas de antrenament.\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": [
|
|
"Acum să definim rețeaua generatorului. Aceasta poate fi bazată pe orice celulă recurentă despre care am discutat în unitatea anterioară (simplă, LSTM sau GRU). În exemplul nostru vom folosi LSTM.\n",
|
|
"\n",
|
|
"Deoarece rețeaua primește caractere ca intrare, iar dimensiunea vocabularului este destul de mică, nu avem nevoie de un strat de încorporare (embedding), intrarea codificată one-hot poate fi trimisă direct către celula LSTM. Totuși, deoarece transmitem numerele caracterelor ca intrare, trebuie să le codificăm one-hot înainte de a le trimite către LSTM. Acest lucru se face apelând funcția `one_hot` în timpul trecerii `forward`. Codificatorul de ieșire va fi un strat liniar care va converti starea ascunsă într-o ieșire codificată one-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": [
|
|
"În timpul antrenamentului, dorim să putem eșantiona text generat. Pentru a face acest lucru, vom defini funcția `generate`, care va produce un șir de caractere de lungime `size`, începând de la șirul inițial `start`.\n",
|
|
"\n",
|
|
"Modul în care funcționează este următorul. Mai întâi, vom trece întregul șir `start` prin rețea și vom obține starea de ieșire `s` și următorul caracter prezis `out`. Deoarece `out` este codificat one-hot, folosim `argmax` pentru a obține indexul caracterului `nc` din vocabular și utilizăm `itos` pentru a determina caracterul real, pe care îl adăugăm la lista rezultată de caractere `chars`. Acest proces de generare a unui caracter este repetat de `size` ori pentru a genera numărul necesar de caractere.\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": [
|
|
"Acum să trecem la antrenament! Bucla de antrenament este aproape aceeași ca în toate exemplele noastre anterioare, dar în loc să afișăm acuratețea, generăm și afișăm text eșantionat la fiecare 1000 de epoci.\n",
|
|
"\n",
|
|
"O atenție specială trebuie acordată modului în care calculăm pierderea. Trebuie să calculăm pierderea având ca intrare ieșirea codificată one-hot `out` și textul așteptat `text_out`, care este lista indicilor caracterelor. Din fericire, funcția `cross_entropy` așteaptă ca prim argument ieșirea ne-normalizată a rețelei și ca al doilea argument numărul clasei, ceea ce este exact ceea ce avem. De asemenea, efectuează automat media pe dimensiunea minibatch-ului.\n",
|
|
"\n",
|
|
"De asemenea, limităm antrenamentul la un număr de mostre definit de `samples_to_train`, pentru a nu aștepta prea mult. Vă încurajăm să experimentați și să încercați antrenamente mai lungi, posibil pentru mai multe epoci (în acest caz, ar trebui să creați o altă buclă în jurul acestui cod).\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": [
|
|
"Acest exemplu generează deja un text destul de bun, dar poate fi îmbunătățit în mai multe moduri:\n",
|
|
"\n",
|
|
"* **Generarea mai bună a minibatch-urilor**. Modul în care am pregătit datele pentru antrenament a fost să generăm un minibatch dintr-un singur eșantion. Acest lucru nu este ideal, deoarece minibatch-urile au dimensiuni diferite, iar unele dintre ele nici măcar nu pot fi generate, deoarece textul este mai mic decât `nchars`. De asemenea, minibatch-urile mici nu utilizează suficient GPU-ul. Ar fi mai înțelept să luăm un bloc mare de text din toate eșantioanele, să generăm toate perechile input-output, să le amestecăm și să generăm minibatch-uri de dimensiuni egale.\n",
|
|
"\n",
|
|
"* **LSTM multilayer**. Are sens să încercăm 2 sau 3 straturi de celule LSTM. Așa cum am menționat în unitatea anterioară, fiecare strat de LSTM extrage anumite tipare din text, iar în cazul unui generator la nivel de caractere, ne putem aștepta ca nivelul inferior al LSTM să fie responsabil pentru extragerea silabelor, iar nivelurile superioare - pentru cuvinte și combinații de cuvinte. Acest lucru poate fi implementat simplu prin transmiterea unui parametru pentru numărul de straturi către constructorul LSTM.\n",
|
|
"\n",
|
|
"* De asemenea, ai putea să experimentezi cu **unități GRU** și să vezi care dintre ele oferă performanțe mai bune, precum și cu **dimensiuni diferite ale straturilor ascunse**. Un strat ascuns prea mare poate duce la overfitting (de exemplu, rețeaua va învăța textul exact), iar o dimensiune mai mică s-ar putea să nu producă un rezultat bun.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Generarea textului moale și temperatura\n",
|
|
"\n",
|
|
"În definiția anterioară a funcției `generate`, alegeam întotdeauna caracterul cu cea mai mare probabilitate ca următorul caracter în textul generat. Acest lucru ducea adesea la faptul că textul \"cicla\" între aceleași secvențe de caractere din nou și din nou, ca în acest exemplu:\n",
|
|
"```\n",
|
|
"today of the second the company and a second the company ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"Totuși, dacă ne uităm la distribuția probabilităților pentru următorul caracter, este posibil ca diferența dintre câteva dintre cele mai mari probabilități să nu fie semnificativă, de exemplu, un caracter poate avea probabilitatea 0.2, iar altul 0.19, etc. De exemplu, când căutăm următorul caracter în secvența '*play*', următorul caracter poate fi la fel de bine un spațiu sau **e** (ca în cuvântul *player*).\n",
|
|
"\n",
|
|
"Acest lucru ne conduce la concluzia că nu este întotdeauna \"corect\" să selectăm caracterul cu probabilitatea cea mai mare, deoarece alegerea celui de-al doilea cel mai probabil caracter poate duce, de asemenea, la un text semnificativ. Este mai înțelept să **eșantionăm** caracterele din distribuția probabilităților oferită de rezultatul rețelei.\n",
|
|
"\n",
|
|
"Această eșantionare poate fi realizată folosind funcția `multinomial`, care implementează așa-numita **distribuție multinomială**. O funcție care implementează această generare de text **moale** este definită mai jos:\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": [
|
|
"Am introdus încă un parametru numit **temperatură**, care este utilizat pentru a indica cât de strict ar trebui să ne bazăm pe cea mai mare probabilitate. Dacă temperatura este 1.0, efectuăm o eșantionare multinomială echitabilă, iar când temperatura crește spre infinit - toate probabilitățile devin egale și selectăm aleator următorul caracter. În exemplul de mai jos putem observa că textul devine lipsit de sens atunci când creștem temperatura prea mult și seamănă cu un text \"ciclic\" generat rigid atunci când se apropie de 0.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Declinare de responsabilitate**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa natală ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\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-30T00:37:39+00:00",
|
|
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativePyTorch.ipynb",
|
|
"language_code": "ro"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |