I TRY TO ADAPT PENNYLANE QLSTM with my how data buut seems ta the QLSTM is very slow 100 more than classical lstm i just introduce my data frame for problem vlassifiication

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import qlstm_pennylane
import pandas as pd
import time


from importlib import reload
reload(qlstm_pennylane)
from qlstm_pennylane import QLSTM
#import of data
df = pd.read_csv('Data_csv.csv',sep=';',parse_dates=True)
df.head()
df.columns
for i in range(df.shape[0]):
    if df['satbility'][i]==0:
        df['satbility'][i]='stable'
    else :
        df['satbility'][i]='instable'
    
df.head()
tag_to_ix = {"stable": 0, "instable": 1}  # Assign each tag with a unique index
ix_to_tag = {i:k for k,i in tag_to_ix.items()}
print(ix_to_tag)
def prepare_sequence(seq, to_ix):
    idxs = [to_ix[w] for w in seq]
    return torch.tensor(idxs, dtype=torch.long)# convert an array of values into a dataset matrix
def create_dataset(dataset, look_back=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-look_back-1):
        a = dataset['W0'][i:(i+look_back)]
        b=dataset['satbility'][i:(i+look_back)]
        dataX.append(a)
        dataY.append(b)
    return dataX, dataY
X,Y = create_dataset(df, look_back=1)
#training_data1=list(zip(X,Y))
# Function to create a list of tuples
def create_list_of_tuples(lst1, lst2):
    result = []  # Empty list to store the tuples
    for i in range(len(lst1)):
        # Create a tuple from corresponding elements
        tuple_element = (lst1[i], lst2[i])
        result.append(tuple_element)  # Append the tuple to the list
    return result
training_data=create_list_of_tuples(X,Y)
print(training_data1[0])
print(type(training_data1))
word_to_ix = {}
#print(training_data)


# For each words-list (sentence) and tags-list in each tuple of training_data
for sent, tags in training_data:
    for word in sent:
        if word not in word_to_ix:  # word has not been assigned an index yet
            word_to_ix[word] = len(word_to_ix) # Assign each word with a unique index

print(f"Vocabulary: {word_to_ix}")
print(f"Entities: {ix_to_tag}")
class LSTMTagger(nn.Module):

    def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size, n_qubits=0):
        super(LSTMTagger, self).__init__()
        self.hidden_dim = hidden_dim

        self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)

        # The LSTM takes word embeddings as inputs, and outputs hidden states
        # with dimensionality hidden_dim.
        if n_qubits > 0:
            print("Tagger will use Quantum LSTM")
            self.lstm = QLSTM(embedding_dim, hidden_dim, n_qubits=n_qubits)
        else:
            print("Tagger will use Classical LSTM")
            self.lstm = nn.LSTM(embedding_dim, hidden_dim)

        # The linear layer that maps from hidden state space to tag space
        self.hidden2tag = nn.Linear(hidden_dim, tagset_size)

    def forward(self, sentence):
        embeds = self.word_embeddings(sentence)
        lstm_out, _ = self.lstm(embeds.view(len(sentence), 1, -1))
        tag_logits = self.hidden2tag(lstm_out.view(len(sentence), -1))
        tag_scores = F.log_softmax(tag_logits, dim=1)
        return tag_scores
embedding_dim = 8
hidden_dim = 6
n_epochs = 5model_classical = LSTMTagger(embedding_dim, 
                        hidden_dim, 
                        vocab_size=len(word_to_ix), 
                        tagset_size=len(tag_to_ix), 
                        n_qubits=0)
def train(model, n_epochs):
    loss_function = nn.NLLLoss()
    optimizer = optim.SGD(model.parameters(), lr=0.1)

    history = {
        'loss': [],
        'acc': []
    }
    for epoch in range(n_epochs):
        losses = []
        preds = []
        targets = []
        for sentence, tags in training_data:
            # Step 1. Remember that Pytorch accumulates gradients.
            # We need to clear them out before each instance
            model.zero_grad()

            # Step 2. Get our inputs ready for the network, that is, turn them into
            # Tensors of word indices.
            sentence_in = prepare_sequence(sentence, word_to_ix)
            labels = prepare_sequence(tags, tag_to_ix)

            # Step 3. Run our forward pass.
            tag_scores = model(sentence_in)

            # Step 4. Compute the loss, gradients, and update the parameters by
            #  calling optimizer.step()
            loss = loss_function(tag_scores, labels)
            loss.backward()
            optimizer.step()
            losses.append(float(loss))
            
            probs = torch.softmax(tag_scores, dim=-1)
            preds.append(probs.argmax(dim=-1))
            targets.append(labels)

        avg_loss = np.mean(losses)
        history['loss'].append(avg_loss)
        
        preds = torch.cat(preds)
        targets = torch.cat(targets)
        corrects = (preds == targets)
        accuracy = corrects.sum().float() / float(targets.size(0) )
        history['acc'].append(accuracy)

        print(f"Epoch {epoch+1} / {n_epochs}: Loss = {avg_loss:.3f} Acc = {accuracy:.2f}")

    return history
start = time.time()

history_classical = train(model_classical, n_epochs)
end = time.time()

print(end - start)
def print_result(model):
    with torch.no_grad():
        input_sentence = training_data[0][0]
        labels = training_data[0][1]
        inputs = prepare_sequence(input_sentence, word_to_ix)
        tag_scores = model(inputs)

        tag_ids = torch.argmax(tag_scores, dim=1).numpy()
        tag_labels = [ix_to_tag[k] for k in tag_ids]
        print(f"Sentence:  {input_sentence}")
        print(f"Labels:    {labels}")
        print(f"Predicted: {tag_labels}")
print_result(model_classical)
n_qubits = 3
model_quantum = LSTMTagger(embedding_dim, 
                        hidden_dim, 
                        vocab_size=len(word_to_ix), 
                        tagset_size=len(tag_to_ix), 
                        n_qubits=n_qubits)
start = time.time()

history_quantum = train(model_quantum, n_epochs)
end = time.time()

print(end - start)

i use last version of pennlane

Hey @lord_youn! Welcome to the forum :sunflower:

I assume you’re working off of / getting inspiration from this demo?

If I understand correctly, you’re observing a slow-down relative to a purely classical LSTM when you use your own data. It’s tough to say where that slow-down is occurring in your code as there’s quite a bit going on (I also don’t have access to your data that you’re using).

Is it actually a slow-down you’re seeing (i.e., one epoch with your QLSTM takes way longer than the analogous classical one)? Or is it that the model’s speed is comparable to the classical one but takes a lot longer (more training epochs) to reach the desired value of your loss function?

one epoch in qlstm take long time to exexute .in one seconde we have result of classical lstm but it can take 3 or for minute for QLSTM in one epoch.i try different cpu bakend that is same
for my dataset i have speed : int that is my feature and my target is satbility that is string

Thanks for clarifying :slight_smile:. I think the answer here isn’t as complicated as it might seem. The QLSTM is most likely taking longer because it’s a bigger network with more moving parts (I can’t see your code that you’re using — I’m not sure what is in the qlstm_pennylane import — but I’m assuming it’s similar to what’s in the demo). A more computationally-heavy forward pass can easily be the culprit here.

Let me know if that helps!

Hello,I also encountered the same confusion as you, but I think it is because our calculation is a simulation of quantum computing results, so it cannot be compared with the classic LSTM in terms of physical time. But I found that using the adjoint diff_method provided by PennyLane can help the model training faster.

Hi @quantum_accept, welcome to the Forum and thank you for this insight!

The adjoint diff_method can indeed help speed up the computation in many cases. I’m glad to hear that it worked for you!