import pandas as pd
import time
import numpy as np
import matplotlib.pyplot as plt
import os
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader
from collections import Counter
import torch.nn.functional
import pennylane as qml
from pennylane import numpy as np
from datasets import load_dataset
from tqdm import tqdm  # 添加进度条
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import re
from sklearn.model_selection import train_test_split
from qiskit import QuantumCircuit
from qiskit.visualization import circuit_drawer
from sklearn.metrics import f1_score, recall_score
from torch.optim.lr_scheduler import StepLR
import warnings
import random
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)


min_freq = 1

sequence_length = 10

embedding_dim = 100  # 词嵌入维度 与mat1有关

batch_size = 32

hidden_units = 64

n_qlayers = 1

dropout_rate = 0.5

lr = 0.001

epoch = 80

#weight_decay = 0.00001

# 读取数据文件
def load_data(file_path):
    data = []
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            text, label = line.strip().split('\t')
            data.append((text, int(label)))
    return pd.DataFrame(data, columns=['text', 'label'])

# 文本清洗函数
def clean_text(text):
    # 转换为小写
    text = text.lower()
    # 移除 HTML 标签
    text = re.sub(r'<.*?>', '', text)
    # 移除 URL
    text = re.sub(r'http\S+|www\S+|https\S+', '', text, flags=re.MULTILINE)
    # 移除标点符号和数字
    text = re.sub(r'\d+', '', text)
    text = re.sub(r'[^\w\s]', '', text)
    # 分词
    words = word_tokenize(text)
    # 移除停用词
    stop_words = set(stopwords.words('english'))- {'not', 'no', 'nor', 'but'}
    words = [word for word in words if word not in stop_words]
    return ' '.join(words)


# 加载数据
file_path = 'amazon_cells_labelled.txt'
dataset = load_data(file_path)

# 随机抽取一个新的训练集（800条）、验证集（100条）和测试集（100条）
train_val_set, test_set = train_test_split(dataset, train_size=900, test_size=100, random_state=42, stratify=dataset['label'])
train_set, val_set = train_test_split(train_val_set, train_size=800, test_size=100, random_state=42, stratify=train_val_set['label'])

# 清洗所有数据集的文本
train_set['text'] = train_set['text'].apply(clean_text)
val_set['text'] = val_set['text'].apply(clean_text)
test_set['text'] = test_set['text'].apply(clean_text)

# 定义一个函数来标记和编码句子
def tokenize_and_encode(sentences, vocab, seq_length):
    token_ids = [
        [vocab.get(token, vocab['<UNK>']) for token in sentence.split()]
        for sentence in sentences
    ]
    # 填充序列
    token_ids = [
        t_ids[:seq_length] if len(t_ids) > seq_length else t_ids + [vocab['<PAD>']] * (seq_length - len(t_ids))
        for t_ids in token_ids
    ]
    return token_ids

# 从训练数据集创建词汇表
all_train_tokens = [token for sentence in train_set['text'] for token in sentence.split()]

# 计算所有训练数据中单词的频率
word_counts = Counter(all_train_tokens)

# 打印词汇表中每个单词的频率，按照频率从高到低排序
for word, count in word_counts.most_common():
    print(f"{word}: {count}")

# 只保留出现次数大于等于阈值的单词

filtered_words = [word for word, count in word_counts.items() if count >= min_freq]
vocabulary = {word: i + 2 for i, word in enumerate(filtered_words)}
vocabulary['<UNK>'] = 1
vocabulary['<PAD>'] = 0

# 打印词汇表大小
print(f"真实Vocabulary size: {len(vocabulary)}")

# 对数据集进行标记和编码

train_token_ids = tokenize_and_encode(train_set['text'], vocabulary, sequence_length)
val_token_ids = tokenize_and_encode(val_set['text'], vocabulary, sequence_length)
#test_token_ids = tokenize_and_encode(test_set['text'], vocabulary, sequence_length)

# 创建自定义 PyTorch 数据集
class SentimentDataset(Dataset):
    def __init__(self, token_ids, labels):
        self.token_ids = token_ids
        self.labels = labels

    def __len__(self):
        return len(self.token_ids)

    def __getitem__(self, idx):
        return torch.tensor(self.token_ids[idx], dtype=torch.long), torch.tensor(self.labels[idx], dtype=torch.long)

# 创建自定义 Dataset 实例

train_dataset = SentimentDataset(train_token_ids, train_set['label'].tolist())
val_dataset = SentimentDataset(val_token_ids, val_set['label'].tolist())
#test_dataset = SentimentDataset(test_token_ids, test_set['label'].tolist())

# 打印标记和编码后的数据样本
print("\n标记和编码后的数据样本:")
for sample in train_token_ids[:500]:
     print(" ".join(map(str, sample)))



# 创建 DataLoader
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)
#test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)


# 打印训练集、验证集和测试集的标签统计信息
train_positive_count = train_set[train_set['label'] == 1].shape[0]
train_negative_count = train_set[train_set['label'] == 0].shape[0]
print(f"Train Positive count: {train_positive_count}")
print(f"Train Negative count: {train_negative_count}")

val_positive_count = val_set[val_set['label'] == 1].shape[0]
val_negative_count = val_set[val_set['label'] == 0].shape[0]
print(f"Validation Positive count: {val_positive_count}")
print(f"Validation Negative count: {val_negative_count}")

test_positive_count = test_set[test_set['label'] == 1].shape[0]
test_negative_count = test_set[test_set['label'] == 0].shape[0]
print(f"Test Positive count: {test_positive_count}")
print(f"Test Negative count: {test_negative_count}")

# 统计所有句子的长度
sentence_lengths = [len(sentence.split()) for sentence in train_set['text']]
# 绘制长度分布直方图
plt.hist(sentence_lengths, bins=50)
plt.xlabel('Sentence Length')
plt.ylabel('Frequency')
plt.title('Distribution of Sentence Lengths')
plt.show()

# 计算第95百分位数
percentile_90 = np.percentile(sentence_lengths, 90)
print(f"The 90th percentile of sentence lengths is: {int(percentile_90)}")
#自注意力类

# 量子LSTM
class QLSTM(nn.Module):
    def __init__(self,
                 input_size,
                 hidden_size,
                 n_qubits=4,
                 n_qlayers=n_qlayers,
                 n_vrotations=3,
                 batch_first=True,
                 return_sequences=False,
                 return_state=False,
                 backend="default.qubit",
                 dropout_rate=dropout_rate):
        super(QLSTM, self).__init__()
        self.n_inputs = input_size
        self.hidden_size = hidden_size
        self.concat_size = self.n_inputs + self.hidden_size
        self.n_qubits = n_qubits
        self.n_qlayers = n_qlayers
        self.n_vrotations = n_vrotations
        self.backend = backend

        self.batch_first = batch_first
        self.return_sequences = return_sequences
        self.return_state = return_state

        self.wires_forget = [f"wire_forget_{i}" for i in range(self.n_qubits)]
        self.wires_input = [f"wire_input_{i}" for i in range(self.n_qubits)]
        self.wires_update = [f"wire_update_{i}" for i in range(self.n_qubits)]
        self.wires_output = [f"wire_output_{i}" for i in range(self.n_qubits)]
        self.wires_output_h = [f"wire_output_h_{i}" for i in range(self.n_qubits)]
        # 定义线性层
        self.fc = nn.Linear(self.hidden_size, 2)
        # 初始化权重形状
        self.weight_shapes = {"weights": (self.n_qlayers, self.n_vrotations, self.n_qubits)}
        # 定义量子设备
        # self.dev = qml.device('default.qubit', wires=4)
        self.dev_forget = qml.device(self.backend, wires=self.wires_forget)
        self.dev_input = qml.device(self.backend, wires=self.wires_input)
        self.dev_update = qml.device(self.backend, wires=self.wires_update)
        self.dev_output = qml.device(self.backend, wires=self.wires_output)
        self.dev_output_h = qml.device(self.backend, wires=self.wires_output_h)
        # 定义 ansatz 方法
        self.ansatz = self.ansatz
        # 初始化dropout层
        self.dropout = nn.Dropout(dropout_rate)

        # QNode实例化
        self.qlayer_forget = qml.QNode(self._circuit_forget, self.dev_forget, interface="torch")
        self.qlayer_input = qml.QNode(self._circuit_input, self.dev_input, interface="torch")
        self.qlayer_update = qml.QNode(self._circuit_update, self.dev_update, interface="torch")
        self.qlayer_output = qml.QNode(self._circuit_output, self.dev_output, interface="torch")
        self.qlayer_output_h = qml.QNode(self._circuit_output_h, self.dev_output_h, interface="torch")
        # 定义权重形状
        weight_shapes = {"weights": (self.n_qlayers, self.n_vrotations, self.n_qubits)}

        # print(f"weight_shapes = (n_qlayers, n_vrotations, n_qubits) = ({self.n_qlayers}, {self.n_vrotations}, {self.n_qubits})")

        # 定义线性层
        self.clayer_in = nn.Linear(self.concat_size, self.n_qubits)
        self.clayer_out = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_f = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_i = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_g = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_o = nn.Linear(self.n_qubits, self.hidden_size)
        self.TorchLayers = {
            'forget': qml.qnn.TorchLayer(self.qlayer_forget, self.weight_shapes),
            'input': qml.qnn.TorchLayer(self.qlayer_input, self.weight_shapes),
            'update': qml.qnn.TorchLayer(self.qlayer_update, self.weight_shapes),
            'output': qml.qnn.TorchLayer(self.qlayer_output, self.weight_shapes),
            'output_h': qml.qnn.TorchLayer(self.qlayer_output_h, self.weight_shapes)
        }

    def ansatz(self, params, wires_type):

        # Entangling layer.
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i]])
                else:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i - self.n_qubits]])

            # Variational layer.
            for i in range(self.n_qubits):
                qml.RX(params[0][i], wires=wires_type[i])
                qml.RY(params[1][i], wires=wires_type[i])
                qml.RZ(params[2][i], wires=wires_type[i])

    def vqc(self, features, weights, wires_type):
        # 将features转换为PyTorch张量（如果它是一个NumPy数组）
        if isinstance(features, np.ndarray):
            features = torch.tensor(features, dtype=torch.float32)
        # 检查features是否为一维张量，如果是，则添加一个新的批次维度
        if features.dim() == 1:
            features = features.unsqueeze(0)  # 将其变为二维张量，形状为[1, 特征数]
        if not isinstance(features, torch.Tensor):
            features = torch.tensor(features, dtype=torch.float32)
        # print("features形状:", features.shape)
        # print("Weights shape:", weights.shape)

        # 确保 features 的长度等于量子位的数量
        features = features[:, :self.n_qubits]
        ry_params = torch.atan2(features, torch.ones_like(features))
        rz_params = torch.atan2(features ** 2, torch.ones_like(features))

        # ry_params = [torch.arctan(feature) for feature in features]
        # rz_params = [torch.arctan(feature ** 2) for feature in features]
        # 应用Hadamard门到每个量子位上
        for i in range(self.n_qubits):
            qml.Hadamard(wires=wires_type[i])

        # 对量子位进行RY和RZ旋转
        for i in range(self.n_qubits):
            qml.RY(ry_params[:, i], wires=wires_type[i])
            qml.RZ(rz_params[:, i], wires=wires_type[i])

        # 创建量子位之间的纠缠
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i]])
                else:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i - self.n_qubits]])

        # 再次对量子位进行RX、RY、RZ旋转
        for layer in range(self.n_qlayers):
            for i in range(self.n_qubits):
                qml.RX(weights[layer, 0, i], wires=wires_type[i])
                qml.RY(weights[layer, 1, i], wires=wires_type[i])
                qml.RZ(weights[layer, 2, i], wires=wires_type[i])
    # 定义量子电路，模拟LSTM中的门控机制
    def _circuit_forget(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_forget)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_forget]

    def _circuit_input(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_input)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_input]

    def _circuit_update(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_update)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_update]

    def _circuit_output(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_output)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_output]
    # 计算隐藏状态输出

    def _circuit_output_h(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_output_h)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_output_h]

    # 利用qiskit可视化电路图
    def to_qiskit_circuit(self, inputs, weights, wires_type):
        # 添加经典位用于存储测量结果
        circuit = QuantumCircuit(self.n_qubits, self.n_qubits)
        features = torch.tensor(inputs[:, :self.n_qubits], dtype=torch.float32)
        ry_params = torch.atan2(features, torch.ones_like(features))
        rz_params = torch.atan2(features ** 2, torch.ones_like(features))

        # 应用Hadamard门到每个量子位上
        for i in range(self.n_qubits):
            circuit.h(i)

        # 对量子位进行RY和RZ旋转
        for i in range(self.n_qubits):
            circuit.ry(ry_params[:, i].item(), i)
            circuit.rz(rz_params[:, i].item(), i)

        # 创建量子位之间的纠缠
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    circuit.cx(j, j + i)
                else:
                    circuit.cx(j, (j + i) % self.n_qubits)

        # 再次对量子位进行RX、RY、RZ旋转
        for layer in range(self.n_qlayers):
            for i in range(self.n_qubits):
                circuit.rx(weights[layer, 0, i].item(), i)
                circuit.ry(weights[layer, 1, i].item(), i)
                circuit.rz(weights[layer, 2, i].item(), i)

        # 对每个量子位进行测量，并将结果存储到对应的经典位中
        for i in range(self.n_qubits):
            circuit.measure(i, i)

        return circuit

    def visualize_qiskit_circuit(self):
        example_inputs = np.random.random((1, self.n_qubits))
        example_weights = np.random.random((self.n_qlayers, self.n_vrotations, self.n_qubits))
        qiskit_circuit = self.to_qiskit_circuit(example_inputs, example_weights, self.wires_forget)
        circuit_drawer(qiskit_circuit, output='mpl').show()

    def forward(self, x, init_states=None):

        batch_size, seq_length, _ = x.size()

        if init_states is None:
            h_t = torch.zeros(batch_size, self.hidden_size, dtype=torch.float32)  # hidden state (output)
            c_t = torch.zeros(batch_size, self.hidden_size, dtype=torch.float32)  # cell state
        else:
            h_t, c_t = init_states

            # 批处理整个序列
        for t in range(seq_length):
            x_t = x[:, t, :]  # 获取当前时间步的特征
            # 选择 h_t 的最后一层，以匹配 x_t 的维度
            h_t_last_layer = h_t[-1, :, :]  # 假设 h_t 的形状是 [num_layers, batch_size, hidden_size]

            # 现在 h_t_last_layer 的形状是 [batch_size, hidden_size]，可以和 x_t 连接
            combined = torch.cat((h_t_last_layer, x_t), dim=1)

            # 将拼接后的数据通过一个线性层以匹配量子位的维度
            combined = self.clayer_in(combined)

            # 用量子层处理整个批次的数据
            f_t_intermediate = self.TorchLayers['forget'](combined)
            i_t_intermediate = self.TorchLayers['input'](combined)
            g_t_intermediate = self.TorchLayers['update'](combined)
            o_t_intermediate = self.TorchLayers['output'](combined)

            # 将中间结果通过另一个线性层转换回隐藏状态的维度
            f_t = torch.sigmoid(self.clayer_out_f(f_t_intermediate))
            i_t = torch.sigmoid(self.clayer_out_i(i_t_intermediate))
            g_t = torch.tanh(self.clayer_out_g(g_t_intermediate))
            o_t = torch.sigmoid(self.clayer_out_o(o_t_intermediate))

            # 根据 LSTM 的更新规则更新隐藏状态和细胞状态
            c_t = f_t * c_t + i_t * g_t
            h_t = o_t * torch.tanh(c_t)
            # print("h_t shape:", h_t.shape)
            # 使用最后的隐藏状态通过一个线性层以得到最终输出
            h_t = self.dropout(h_t)  # 将dropout应用到隐藏状态

        output = self.fc(h_t)
        # print(f"Output shape: {output.shape}")
        return output

# 电路可视化实现
qlstm_instance = QLSTM(input_size=10, hidden_size=64, n_qubits=4, n_qlayers=1, n_vrotations=3, backend="default.qubit")
qlstm_instance.visualize_qiskit_circuit()
class QShallowClassificationLSTM(nn.Module):
    def __init__(self, num_sensors, embedding_dim, hidden_units, n_qubits=4, n_qlayers=1, num_classes=2, dropout_rate=dropout_rate):
        super().__init__()
        self.num_sensors = num_sensors
        self.hidden_units = hidden_units
        self.num_layers = 1
        self.num_classes = num_classes
        self.embedding = nn.Embedding(vocab_size, embedding_dim)

        # 添加自注意力层

        # 添加 Dropout 层
        self.dropout = nn.Dropout(dropout_rate)
        self.lstm = QLSTM(
            # input_size=num_sensors,
            # 使用embedding_dim 作为 LSTM 的输入维度
            input_size=embedding_dim,
            hidden_size=hidden_units,
            batch_first=True,
            n_qubits=n_qubits,
            n_qlayers=n_qlayers,

        )
        self.linear = nn.Linear(in_features=2, out_features=self.num_classes)


    def forward(self, x):
        batch_size = x.shape[0]

        x = self.embedding(x)
        # print(f"Embedding layer output shape: {x.shape}")
        # 应用自注意力层


        # 应用 Dropout
        x = self.dropout(x)

        h0 = torch.zeros(self.num_layers, batch_size, self.hidden_units)
        c0 = torch.zeros(self.num_layers, batch_size, self.hidden_units)

        # QLSTM 返回所有时间步的输出
        outputs = self.lstm(x, (h0, c0))

        # 选择最后一个时间步的隐藏状态，它的形状为 [batch_size, hidden_units]
        last_hidden_state = outputs.squeeze(0)

        # 将最后一个隐藏状态传递给线性层
        out = self.linear(last_hidden_state)

        return out

#  计算模型分类准确率
def calculate_accuracy_and_scores(data_loader, Qmodel):
    correct = 0
    total = 0
    true_positives = 0
    predicted_positives = 0
    true_negatives = 0
    predicted_negatives = 0
    all_labels = []
    all_predictions = []

    Qmodel.eval()
    with torch.no_grad():
        for X, y in data_loader:
            outputs = Qmodel(X)
            _, predicted = torch.max(outputs.data, 1)
            total += y.size(0)

            # 累积条件统计数据
            true_positives += (y == 1).sum().item()  # 真实正类
            predicted_positives += (predicted == 1).sum().item()  # 预测正类
            true_negatives += (y == 0).sum().item()  # 真实负类
            predicted_negatives += (predicted == 0).sum().item()  # 预测负类

            correct += (predicted == y).sum().item()

            # 收集所有标签和预测值
            all_labels.extend(y.cpu().numpy())
            all_predictions.extend(predicted.cpu().numpy())


    # 计算准确率
    accuracy = 100 * correct / total

    # 计算召回率
    recall = recall_score(y, predicted, pos_label=1)

    # 计算F1分数
    f1 = f1_score(y, predicted, pos_label=1)

    return accuracy, recall, f1

# 词汇表大小
vocab_size = len(vocabulary)




# 实例化分类模型和量子分类模型

Qmodel = QShallowClassificationLSTM(num_sensors=len(vocabulary),
                                    embedding_dim=embedding_dim,
                                    hidden_units=hidden_units,
                                    n_qubits=4,
                                    n_qlayers=1,
                                    num_classes=2)

# 定义损失函数和优化器
loss_function = nn.CrossEntropyLoss()  # 更新为分类任务的损失函数

Qoptimizer = torch.optim.Adam(Qmodel.parameters(), lr=lr)

# 定义学习率调度器
# scheduler = StepLR(Qoptimizer, step_size=34, gamma=0.2)

#  训练函数
def train_model(data_loader, Qmodel, loss_function, optimizer,  progress_bar):
    total_loss = 0
    Qmodel.train()

    for X, y in data_loader:
        output = Qmodel(X)
        loss = loss_function(output, y)

        # 添加L2正则化
        # reg_loss = weight_decay * sum(p.sum() for p in Qmodel.parameters() if p.requires_grad)
        # loss += reg_loss

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_loss += loss.item()
        progress_bar.update(1)  # 更新进度条

    avg_loss = total_loss / len(data_loader)
    return avg_loss

#  测试函数
def test_model(data_loader, Qmodel, loss_function, progress_bar):

    total_loss = 0
    Qmodel.eval()
    with torch.no_grad():
        for X, y in data_loader:
            output = Qmodel(X)
            total_loss += loss_function(output, y).item()
            progress_bar.update(1)  # 更新进度条

    avg_loss = total_loss / len(data_loader)
    return avg_loss

# 初始化训练、测试、验证损失，验证集准确率
quantum_loss_train = []
quantum_loss_test = []
quantum_loss_val = []
quantum_accuracy_val = []
print("Quantum Untrained test\n--------")

# 初始化存储准确率的列表
train_accuracy_list = []
train_recall_list = []
train_f1_list = []

val_accuracy_list = []
val_recall_list = []
val_f1_list = []

# test_accuracy_list = []
# test_recall_list = []
# test_f1_list = []

for ix_epoch in range(epoch):
    #  print(f"Epoch {ix_epoch+1}\n---------")
    total_steps = len(train_loader) + len(val_loader)
    progress_bar = tqdm(total=total_steps, desc=f"Epoch {ix_epoch + 1}")

    # 训练损失
    train_loss = train_model(train_loader, Qmodel, loss_function, Qoptimizer, progress_bar)

    # 测试损失
    # test_loss = test_model(test_loader, Qmodel, loss_function, progress_bar)

    # 验证损失
    val_loss = test_model(val_loader, Qmodel, loss_function, progress_bar)

    # 计算量子模型的准确率、召回率和F1分数
    quantum_train_accuracy, train_recall, train_f1 = calculate_accuracy_and_scores(train_loader, Qmodel)
    # quantum_test_accuracy, test_recall, test_f1 = calculate_accuracy_and_scores(test_loader, Qmodel)

    # 计算验证集准确率、召回率和F1分数
    val_accuracy, val_recall, val_f1 = calculate_accuracy_and_scores(val_loader, Qmodel)

    # 关闭进度条
    progress_bar.close()

    train_accuracy, train_recall, train_f1 = calculate_accuracy_and_scores(train_loader, Qmodel)
    val_accuracy, val_recall, val_f1 = calculate_accuracy_and_scores(val_loader, Qmodel)
    # test_accuracy = calculate_accuracy(test_loader, Qmodel)

    # 将准确率添加到相应的列表中
    train_accuracy_list.append(train_accuracy)
    train_recall_list.append(train_recall)
    train_f1_list.append(train_f1)

    val_accuracy_list.append(val_accuracy)
    val_recall_list.append(val_recall)
    val_f1_list.append(val_f1)

    # test_accuracy_list.append(test_accuracy)
    # test_recall_list.append(test_recall)
    # test_f1_list.append(test_f1)

    # 打印损失和评估指标信息
    print(f"\nTrain Loss: {train_loss:.4f}")
    # print(f"Test Loss: {test_loss:.4f}")
    print(f"Validation Loss: {val_loss:.4f}")

    print(f"Train Accuracy: {quantum_train_accuracy:.2f}%")
    # print(f"Test Accuracy: {quantum_test_accuracy:.2f}%")
    print(f"Validation Accuracy: {val_accuracy:.2f}%\n")

    print(f"Train Recall: {train_recall:.2f}")
    # print(f"Test Recall: {test_recall:.2f}")
    print(f"Train F1 Score: {train_f1:.2f}")

    print(f"Validation Recall: {val_recall:.2f}")
    # print(f"Test F1 Score: {test_f1:.2f}")
    print(f"Validation F1 Score: {val_f1:.2f}\n")

    # 记录训练、测试、验证损失
    quantum_loss_train.append(train_loss)
    # quantum_loss_test.append(test_loss)
    quantum_loss_val.append(val_loss)
    quantum_accuracy_val.append(val_accuracy)
train_eval_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)

这是我去除了自注意力层之后的代码，请你结合我的运行结果给出建议和参数组合来减轻我的模型的过拟合Epoch 1: 100%|██████████| 29/29 [00:46<00:00,  1.62s/it]
Epoch 2:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.7099
Validation Loss: 0.7025
Train Accuracy: 50.00%
Validation Accuracy: 50.00%

Train Recall: 1.00
Train F1 Score: 0.55
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 2: 100%|██████████| 29/29 [00:46<00:00,  1.61s/it]

Train Loss: 0.6951
Validation Loss: 0.6929
Train Accuracy: 49.75%
Validation Accuracy: 49.00%

Train Recall: 1.00
Train F1 Score: 0.64
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 3: 100%|██████████| 29/29 [00:47<00:00,  1.63s/it]
Epoch 4:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6962
Validation Loss: 0.6885
Train Accuracy: 50.50%
Validation Accuracy: 51.00%

Train Recall: 0.00
Train F1 Score: 0.00
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 4: 100%|██████████| 29/29 [00:48<00:00,  1.69s/it]

Train Loss: 0.6932
Validation Loss: 0.6888
Train Accuracy: 50.62%
Validation Accuracy: 51.00%

Train Recall: 0.00
Train F1 Score: 0.00
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 5: 100%|██████████| 29/29 [00:45<00:00,  1.56s/it]

Train Loss: 0.6954
Validation Loss: 0.6898
Train Accuracy: 51.25%
Validation Accuracy: 51.00%

Train Recall: 0.00
Train F1 Score: 0.00
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 6: 100%|██████████| 29/29 [00:45<00:00,  1.57s/it]

Train Loss: 0.6949
Validation Loss: 0.6928
Train Accuracy: 54.50%
Validation Accuracy: 55.00%

Train Recall: 0.70
Train F1 Score: 0.45
Validation Recall: 1.00
Validation F1 Score: 0.50

Epoch 7: 100%|██████████| 29/29 [00:44<00:00,  1.55s/it]
Epoch 8:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6935
Validation Loss: 0.6942
Train Accuracy: 51.62%
Validation Accuracy: 50.00%

Train Recall: 0.83
Train F1 Score: 0.50
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 8: 100%|██████████| 29/29 [00:44<00:00,  1.53s/it]
Epoch 9:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6925
Validation Loss: 0.6912
Train Accuracy: 50.00%
Validation Accuracy: 50.00%

Train Recall: 0.00
Train F1 Score: 0.00
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 9: 100%|██████████| 29/29 [00:44<00:00,  1.52s/it]
Epoch 10:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6936
Validation Loss: 0.6955
Train Accuracy: 51.62%
Validation Accuracy: 47.00%

Train Recall: 0.81
Train F1 Score: 0.67
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 10: 100%|██████████| 29/29 [00:44<00:00,  1.52s/it]
Epoch 11:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6938
Validation Loss: 0.6957
Train Accuracy: 51.00%
Validation Accuracy: 49.00%

Train Recall: 0.90
Train F1 Score: 0.78
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 11: 100%|██████████| 29/29 [00:43<00:00,  1.50s/it]
Epoch 12:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6922
Validation Loss: 0.6937
Train Accuracy: 53.88%
Validation Accuracy: 53.00%

Train Recall: 0.86
Train F1 Score: 0.69
Validation Recall: 1.00
Validation F1 Score: 0.50

Epoch 12: 100%|██████████| 29/29 [00:43<00:00,  1.50s/it]
Epoch 13:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6930
Validation Loss: 0.6963
Train Accuracy: 51.88%
Validation Accuracy: 50.00%

Train Recall: 0.64
Train F1 Score: 0.50
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 13: 100%|██████████| 29/29 [00:43<00:00,  1.50s/it]
Epoch 14:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6917
Validation Loss: 0.6938
Train Accuracy: 54.12%
Validation Accuracy: 53.00%

Train Recall: 0.88
Train F1 Score: 0.68
Validation Recall: 1.00
Validation F1 Score: 0.50

Epoch 14: 100%|██████████| 29/29 [00:43<00:00,  1.50s/it]
Epoch 15:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6929
Validation Loss: 0.6963
Train Accuracy: 52.38%
Validation Accuracy: 49.00%

Train Recall: 0.59
Train F1 Score: 0.51
Validation Recall: 1.00
Validation F1 Score: 0.40

Epoch 15: 100%|██████████| 29/29 [00:42<00:00,  1.48s/it]
Epoch 16:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6911
Validation Loss: 0.6932
Train Accuracy: 54.75%
Validation Accuracy: 52.00%

Train Recall: 0.54
Train F1 Score: 0.41
Validation Recall: 1.00
Validation F1 Score: 0.50

Epoch 16: 100%|██████████| 29/29 [00:42<00:00,  1.48s/it]
Epoch 17:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6921
Validation Loss: 0.6912
Train Accuracy: 54.25%
Validation Accuracy: 55.00%

Train Recall: 0.50
Train F1 Score: 0.49
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 17: 100%|██████████| 29/29 [00:43<00:00,  1.51s/it]
Epoch 18:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6896
Validation Loss: 0.6903
Train Accuracy: 56.25%
Validation Accuracy: 59.00%

Train Recall: 0.80
Train F1 Score: 0.73
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 18: 100%|██████████| 29/29 [00:43<00:00,  1.50s/it]
Epoch 19:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6932
Validation Loss: 0.6890
Train Accuracy: 59.50%
Validation Accuracy: 67.00%

Train Recall: 0.53
Train F1 Score: 0.60
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 19: 100%|██████████| 29/29 [00:43<00:00,  1.51s/it]
Epoch 20:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6917
Validation Loss: 0.6922
Train Accuracy: 55.38%
Validation Accuracy: 52.00%

Train Recall: 0.60
Train F1 Score: 0.65
Validation Recall: 1.00
Validation F1 Score: 0.50

Epoch 20: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.6858
Validation Loss: 0.6885
Train Accuracy: 57.62%
Validation Accuracy: 58.00%

Train Recall: 0.65
Train F1 Score: 0.65
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 21: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 22:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6929
Validation Loss: 0.6868
Train Accuracy: 58.62%
Validation Accuracy: 63.00%

Train Recall: 0.47
Train F1 Score: 0.54
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 22: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 23:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6831
Validation Loss: 0.6855
Train Accuracy: 58.62%
Validation Accuracy: 58.00%

Train Recall: 0.59
Train F1 Score: 0.65
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 23: 100%|██████████| 29/29 [00:42<00:00,  1.47s/it]

Train Loss: 0.6872
Validation Loss: 0.6809
Train Accuracy: 62.50%
Validation Accuracy: 67.00%

Train Recall: 0.67
Train F1 Score: 0.75
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 24: 100%|██████████| 29/29 [00:42<00:00,  1.47s/it]
Epoch 25:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6812
Validation Loss: 0.6738
Train Accuracy: 58.75%
Validation Accuracy: 62.00%

Train Recall: 0.12
Train F1 Score: 0.22
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 25: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.6813
Validation Loss: 0.6770
Train Accuracy: 61.00%
Validation Accuracy: 57.00%

Train Recall: 0.46
Train F1 Score: 0.43
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 26: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 27:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6727
Validation Loss: 0.6690
Train Accuracy: 62.00%
Validation Accuracy: 58.00%

Train Recall: 0.92
Train F1 Score: 0.67
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 27: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 28:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6536
Validation Loss: 0.6120
Train Accuracy: 72.00%
Validation Accuracy: 69.00%

Train Recall: 0.69
Train F1 Score: 0.81
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 28: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 29:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6252
Validation Loss: 0.6420
Train Accuracy: 77.38%
Validation Accuracy: 68.00%

Train Recall: 0.64
Train F1 Score: 0.78
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 29: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 30:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.5945
Validation Loss: 0.6179
Train Accuracy: 72.88%
Validation Accuracy: 65.00%

Train Recall: 1.00
Train F1 Score: 0.86
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 30: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 31:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.6010
Validation Loss: 0.5016
Train Accuracy: 82.38%
Validation Accuracy: 74.00%

Train Recall: 0.87
Train F1 Score: 0.93
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 31: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 32:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.5632
Validation Loss: 0.5351
Train Accuracy: 85.25%
Validation Accuracy: 74.00%

Train Recall: 1.00
Train F1 Score: 0.97
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 32: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]

Train Loss: 0.5852
Validation Loss: 0.5158
Train Accuracy: 86.12%
Validation Accuracy: 77.00%

Train Recall: 0.93
Train F1 Score: 0.93
Validation Recall: 1.00
Validation F1 Score: 0.67

Epoch 33: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.5446
Validation Loss: 0.6351
Train Accuracy: 77.50%
Validation Accuracy: 72.00%

Train Recall: 0.44
Train F1 Score: 0.58
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 34: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 35:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.5482
Validation Loss: 0.6744
Train Accuracy: 75.75%
Validation Accuracy: 69.00%

Train Recall: 0.40
Train F1 Score: 0.57
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 35: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 36:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.5288
Validation Loss: 0.5845
Train Accuracy: 81.00%
Validation Accuracy: 74.00%

Train Recall: 0.53
Train F1 Score: 0.69
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 36: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 37:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4769
Validation Loss: 0.6064
Train Accuracy: 79.38%
Validation Accuracy: 73.00%

Train Recall: 0.62
Train F1 Score: 0.76
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 37: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 38:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.5136
Validation Loss: 0.6083
Train Accuracy: 78.62%
Validation Accuracy: 71.00%

Train Recall: 0.46
Train F1 Score: 0.63
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 38: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.4697
Validation Loss: 0.5999
Train Accuracy: 81.50%
Validation Accuracy: 72.00%

Train Recall: 0.62
Train F1 Score: 0.77
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 39: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 40:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4724
Validation Loss: 0.6316
Train Accuracy: 86.50%
Validation Accuracy: 76.00%

Train Recall: 0.59
Train F1 Score: 0.74
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 40: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 41:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4854
Validation Loss: 0.5679
Train Accuracy: 81.00%
Validation Accuracy: 74.00%

Train Recall: 0.73
Train F1 Score: 0.85
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 41: 100%|██████████| 29/29 [00:42<00:00,  1.47s/it]
Epoch 42:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4815
Validation Loss: 0.6079
Train Accuracy: 79.12%
Validation Accuracy: 71.00%

Train Recall: 0.54
Train F1 Score: 0.70
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 42: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 43:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4759
Validation Loss: 0.5980
Train Accuracy: 80.12%
Validation Accuracy: 73.00%

Train Recall: 0.64
Train F1 Score: 0.78
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 43: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 44:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4342
Validation Loss: 0.4356
Train Accuracy: 85.50%
Validation Accuracy: 78.00%

Train Recall: 0.65
Train F1 Score: 0.79
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 44: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.4262
Validation Loss: 0.5747
Train Accuracy: 81.75%
Validation Accuracy: 74.00%

Train Recall: 0.38
Train F1 Score: 0.55
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 45: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 46:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4256
Validation Loss: 0.5875
Train Accuracy: 82.38%
Validation Accuracy: 75.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 46: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 47:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4243
Validation Loss: 0.5312
Train Accuracy: 85.12%
Validation Accuracy: 78.00%

Train Recall: 0.80
Train F1 Score: 0.89
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 47: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 48:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4283
Validation Loss: 0.5802
Train Accuracy: 83.62%
Validation Accuracy: 76.00%

Train Recall: 0.70
Train F1 Score: 0.82
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 48: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 49:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4341
Validation Loss: 0.6030
Train Accuracy: 85.25%
Validation Accuracy: 75.00%

Train Recall: 0.58
Train F1 Score: 0.74
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 49: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 50:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4387
Validation Loss: 0.5261
Train Accuracy: 86.25%
Validation Accuracy: 75.00%

Train Recall: 0.77
Train F1 Score: 0.87
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 50: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 51:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4590
Validation Loss: 0.4483
Train Accuracy: 89.00%
Validation Accuracy: 77.00%

Train Recall: 0.78
Train F1 Score: 0.88
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 51: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 52:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4499
Validation Loss: 0.5525
Train Accuracy: 85.62%
Validation Accuracy: 74.00%

Train Recall: 0.90
Train F1 Score: 0.95
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 52: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 53:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3902
Validation Loss: 0.4589
Train Accuracy: 89.25%
Validation Accuracy: 77.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 53: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 54:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4480
Validation Loss: 0.6264
Train Accuracy: 83.12%
Validation Accuracy: 74.00%

Train Recall: 0.63
Train F1 Score: 0.77
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 54: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 55:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3849
Validation Loss: 0.6070
Train Accuracy: 85.25%
Validation Accuracy: 74.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 55: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 56:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3920
Validation Loss: 0.4661
Train Accuracy: 90.50%
Validation Accuracy: 80.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 1.00
Validation F1 Score: 1.00

Epoch 56: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]

Train Loss: 0.3810
Validation Loss: 0.6580
Train Accuracy: 87.00%
Validation Accuracy: 75.00%

Train Recall: 0.85
Train F1 Score: 0.92
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 57: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 58:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3607
Validation Loss: 0.6122
Train Accuracy: 87.62%
Validation Accuracy: 75.00%

Train Recall: 0.62
Train F1 Score: 0.76
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 58: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 59:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3591
Validation Loss: 0.7660
Train Accuracy: 82.38%
Validation Accuracy: 72.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 59: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 60:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.4046
Validation Loss: 0.7167
Train Accuracy: 82.88%
Validation Accuracy: 72.00%

Train Recall: 0.62
Train F1 Score: 0.77
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 60: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 61:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3062
Validation Loss: 0.6540
Train Accuracy: 88.00%
Validation Accuracy: 76.00%

Train Recall: 0.71
Train F1 Score: 0.83
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 61: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 62:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3374
Validation Loss: 0.6520
Train Accuracy: 89.25%
Validation Accuracy: 77.00%

Train Recall: 0.80
Train F1 Score: 0.89
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 62: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 63:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3392
Validation Loss: 0.6419
Train Accuracy: 92.50%
Validation Accuracy: 77.00%

Train Recall: 0.84
Train F1 Score: 0.91
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 63: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.3426
Validation Loss: 0.6586
Train Accuracy: 89.38%
Validation Accuracy: 75.00%

Train Recall: 0.67
Train F1 Score: 0.80
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 64: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 65:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3348
Validation Loss: 0.6322
Train Accuracy: 89.25%
Validation Accuracy: 77.00%

Train Recall: 0.62
Train F1 Score: 0.77
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 65: 100%|██████████| 29/29 [00:42<00:00,  1.47s/it]
Epoch 66:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3255
Validation Loss: 0.6569
Train Accuracy: 88.62%
Validation Accuracy: 76.00%

Train Recall: 0.89
Train F1 Score: 0.94
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 66: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 67:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3180
Validation Loss: 0.6446
Train Accuracy: 92.12%
Validation Accuracy: 78.00%

Train Recall: 0.88
Train F1 Score: 0.94
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 67: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]
Epoch 68:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2695
Validation Loss: 0.7006
Train Accuracy: 92.25%
Validation Accuracy: 77.00%

Train Recall: 0.79
Train F1 Score: 0.88
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 68: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]
Epoch 69:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3440
Validation Loss: 0.6379
Train Accuracy: 93.00%
Validation Accuracy: 77.00%

Train Recall: 0.94
Train F1 Score: 0.97
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 69: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]

Train Loss: 0.3124
Validation Loss: 0.7002
Train Accuracy: 90.50%
Validation Accuracy: 75.00%

Train Recall: 0.92
Train F1 Score: 0.96
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 70: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]

Train Loss: 0.3278
Validation Loss: 0.7018
Train Accuracy: 91.62%
Validation Accuracy: 76.00%

Train Recall: 0.82
Train F1 Score: 0.90
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 71: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]

Train Loss: 0.2967
Validation Loss: 0.7321
Train Accuracy: 91.62%
Validation Accuracy: 75.00%

Train Recall: 0.78
Train F1 Score: 0.88
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 72: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 73:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2845
Validation Loss: 0.7169
Train Accuracy: 91.88%
Validation Accuracy: 76.00%

Train Recall: 0.73
Train F1 Score: 0.84
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 73: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]
Epoch 74:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2854
Validation Loss: 0.7367
Train Accuracy: 92.12%
Validation Accuracy: 77.00%

Train Recall: 0.90
Train F1 Score: 0.95
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 74: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]

Train Loss: 0.2926
Validation Loss: 0.7172
Train Accuracy: 94.62%
Validation Accuracy: 75.00%

Train Recall: 1.00
Train F1 Score: 1.00
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 75: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 76:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2787
Validation Loss: 0.7511
Train Accuracy: 93.88%
Validation Accuracy: 78.00%

Train Recall: 0.94
Train F1 Score: 0.97
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 76: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]
Epoch 77:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2907
Validation Loss: 0.7432
Train Accuracy: 94.25%
Validation Accuracy: 78.00%

Train Recall: 0.89
Train F1 Score: 0.94
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 77: 100%|██████████| 29/29 [00:42<00:00,  1.46s/it]
Epoch 78:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.3301
Validation Loss: 0.7091
Train Accuracy: 96.00%
Validation Accuracy: 77.00%

Train Recall: 0.94
Train F1 Score: 0.97
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 78: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]
Epoch 79:   0%|          | 0/29 [00:00<?, ?it/s]
Train Loss: 0.2868
Validation Loss: 0.7145
Train Accuracy: 95.00%
Validation Accuracy: 76.00%

Train Recall: 0.95
Train F1 Score: 0.97
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 79: 100%|██████████| 29/29 [00:42<00:00,  1.45s/it]

Train Loss: 0.3061
Validation Loss: 0.7243
Train Accuracy: 93.38%
Validation Accuracy: 77.00%

Train Recall: 0.75
Train F1 Score: 0.83
Validation Recall: 0.00
Validation F1 Score: 0.00

Epoch 80: 100%|██████████| 29/29 [00:41<00:00,  1.44s/it]

Train Loss: 0.3056
Validation Loss: 0.7419
Train Accuracy: 94.38%
Validation Accuracy: 75.00%

Train Recall: 0.77
Train F1 Score: 0.87
Validation Recall: 0.00
Validation F1 Score: 0.00