Introducció

En aquest tema, explorarem com utilitzar Xarxes Neuronals Recurrentes (RNN) per a la generació de text. Les RNN són especialment útils per a tasques seqüencials com el processament del llenguatge natural (PLN), ja que poden mantenir informació sobre contextos anteriors en una seqüència. Aprendrem els conceptes bàsics, veurem exemples pràctics i realitzarem exercicis per consolidar els nostres coneixements.

Conceptes Clau

  1. Xarxes Neuronals Recurrentes (RNN):

    • Les RNN són un tipus de xarxa neuronal dissenyada per treballar amb dades seqüencials.
    • Cada unitat de la xarxa té una connexió recurrent que permet mantenir informació sobre els estats anteriors.
  2. LSTM (Long Short-Term Memory):

    • Una variant de les RNN que aborda el problema del gradient que desapareix.
    • Utilitza cel·les de memòria per mantenir informació durant períodes de temps més llargs.
  3. GRU (Gated Recurrent Unit):

    • Una altra variant de les RNN que simplifica les cel·les de memòria de les LSTM.
    • Té menys paràmetres que les LSTM, cosa que pot fer-les més eficients.
  4. Embedding:

    • Una representació vectorial d'elements de text (paraules, caràcters) en un espai de dimensions més baixes.
    • Facilita l'aprenentatge de relacions semàntiques entre paraules.

Exemples Pràctics

Exemple 1: Generació de text amb una RNN bàsica

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, SimpleRNN, Dense

# Dades d'exemple
text = "Hola, benvingut al curs de Deep Learning. Aprendrem moltes coses interessants."

# Preprocessament del text
chars = sorted(list(set(text)))
char_to_index = {c: i for i, c in enumerate(chars)}
index_to_char = {i: c for i, c in enumerate(chars)}

# Paràmetres
maxlen = 40
step = 3

# Preparar les seqüències d'entrada i sortida
sentences = []
next_chars = []
for i in range(0, len(text) - maxlen, step):
    sentences.append(text[i: i + maxlen])
    next_chars.append(text[i + maxlen])
    
X = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)

for i, sentence in enumerate(sentences):
    for t, char in enumerate(sentence):
        X[i, t, char_to_index[char]] = 1
    y[i, char_to_index[next_chars[i]]] = 1

# Construir el model
model = Sequential()
model.add(SimpleRNN(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars), activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam')

# Entrenar el model
model.fit(X, y, batch_size=128, epochs=20)

# Generar text
def sample(preds, temperature=1.0):
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

generated_text = text[:maxlen]
print('--- Generating with seed: "' + generated_text + '"')

for i in range(400):
    sampled = np.zeros((1, maxlen, len(chars)))
    for t, char in enumerate(generated_text):
        sampled[0, t, char_to_index[char]] = 1

    preds = model.predict(sampled, verbose=0)[0]
    next_index = sample(preds, 0.5)
    next_char = index_to_char[next_index]

    generated_text += next_char
    generated_text = generated_text[1:]

    print(next_char, end='')
print()

Explicació del Codi

  1. Preprocessament del text:

    • Convertim el text en una seqüència de caràcters únics.
    • Creem diccionaris per mapar caràcters a índexs i viceversa.
  2. Preparació de les seqüències d'entrada i sortida:

    • Dividim el text en seqüències de longitud fixa (maxlen).
    • Preparem les dades d'entrada (X) i les etiquetes (y).
  3. Construcció del model:

    • Utilitzem una capa SimpleRNN amb 128 unitats.
    • Afegim una capa Dense amb activació softmax per predir el següent caràcter.
  4. Entrenament del model:

    • Compilem el model amb la pèrdua categorical_crossentropy i l'optimitzador adam.
    • Entrenem el model durant 20 èpoques.
  5. Generació de text:

    • Utilitzem la funció sample per generar el següent caràcter basat en les prediccions del model.
    • Generem text de manera iterativa, afegint el nou caràcter a la seqüència generada.

Exercicis Pràctics

Exercici 1: Millorar la Generació de Text amb LSTM

Modifica l'exemple anterior per utilitzar una capa LSTM en lloc de SimpleRNN. Compara els resultats obtinguts.

Solució

from tensorflow.keras.layers import LSTM

# Construir el model amb LSTM
model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars), activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam')

# Entrenar el model
model.fit(X, y, batch_size=128, epochs=20)

# Generar text
generated_text = text[:maxlen]
print('--- Generating with seed: "' + generated_text + '"')

for i in range(400):
    sampled = np.zeros((1, maxlen, len(chars)))
    for t, char in enumerate(generated_text):
        sampled[0, t, char_to_index[char]] = 1

    preds = model.predict(sampled, verbose=0)[0]
    next_index = sample(preds, 0.5)
    next_char = index_to_char[next_index]

    generated_text += next_char
    generated_text = generated_text[1:]

    print(next_char, end='')
print()

Exercici 2: Ajustar la Temperatura de la Funció de Mostreig

Experimenta amb diferents valors de temperatura en la funció sample. Observa com afecta la diversitat del text generat.

Solució

# Funció de mostreig amb diferents temperatures
def sample(preds, temperature=1.0):
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

# Generar text amb diferents temperatures
for temp in [0.2, 0.5, 1.0, 1.2]:
    print('--- Temperature:', temp)
    generated_text = text[:maxlen]
    print('--- Generating with seed: "' + generated_text + '"')

    for i in range(400):
        sampled = np.zeros((1, maxlen, len(chars)))
        for t, char in enumerate(generated_text):
            sampled[0, t, char_to_index[char]] = 1

        preds = model.predict(sampled, verbose=0)[0]
        next_index = sample(preds, temp)
        next_char = index_to_char[next_index]

        generated_text += next_char
        generated_text = generated_text[1:]

        print(next_char, end='')
    print()

Resum

En aquest tema, hem après com utilitzar RNN per a la generació de text. Hem vist com construir i entrenar un model bàsic de RNN i com millorar-lo utilitzant LSTM. També hem explorat com ajustar la temperatura de la funció de mostreig per controlar la diversitat del text generat. Aquests coneixements són fonamentals per a tasques avançades de processament del llenguatge natural i obren la porta a aplicacions més complexes com la traducció automàtica i la síntesi de text.

© Copyright 2024. Tots els drets reservats