第一步:

调整seq_len ,可以用经验数值,或者呢,用acf ,自相关学习

# sys.path.append('/home/aistudio/external-libraries')
# pip install -U imbalanced-learn -t /home/aistudio/external-libraries

# pip install statsmodels  -t /home/aistudio/external-libraries

# pip install statsmodels

# CF(Autocorrelation Function,自相关函数)图是一种用于分析时间序列数据的工具。自相关函数衡量了时间序列数据与其自身滞后版本之间的相关性。ACF图可以帮助我们识别时间序列数据中的季节性和周期性模式。
#
# 在ACF图中,横轴表示滞后期数,纵轴表示相关系数的值。每个点代表了对应滞后期的相关系数。相关系数的取值范围在-1到1之间,值越接近1表示正相关,值越接近-1表示负相关,值接近0表示无相关性。
# ————————————————
#
#                             版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
#
# 原文链接:https://blog.csdn.net/qq_49232127/article/details/133626939

import os
import sys

from sklearn.preprocessing import MinMaxScaler, LabelEncoder

sys.path.append('/home/aistudio/external-libraries')

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import torch
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import statsmodels.api as sm

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

df = pd.read_csv('data_lf/bet_records_250201.csv')


df.sort_values(by='scene', ascending=True, inplace=True)
# 读取 CSV 文件


def readFso(file_path):
    # 读取文本文件,每行一个值
    with open(file_path, 'r') as file:
        lines = file.readlines()

    # 将每行的值转换为浮点数,并创建一个列表
    data_list = [float(line.strip()) for line in lines]
    # data_list = data_list[2024:2280]
    df = pd.DataFrame(data_list, columns=['column'])
    # 最小-最大标准化
    # 每一个批次内部标准,防止每次批次关联
    # scaler = MinMaxScaler()
    # df['column'] = scaler.fit_transform(df[['column']])
    data_list = df['column'].tolist()
    return data_list


# 读取 fso输入数据   fso输出数据
# 并规则化
# xdata = readFso('data_fso/data/datax_2_16.txt')
# ydata = readFso('data_fso/data/datay_2_16.txt')




# 定义类别顺序

# # 创建 LabelEncoder 对象
le = LabelEncoder()
#
# # 使用 fit 方法对类别顺序进行编码
# le.fit(categories)






# 提取 ydata 并数值化
# label_encoder = LabelEncoder()
ydata = le.fit_transform(df['rewardName'])

# 提取 xdata 和 ydata
# xdata = df.drop(columns=['rewardName'])  # 删除 rewardName 列,保留其他所有列





# 假设df是你的DataFrame
# df['create_at'] = pd.to_datetime(df['create_at'], unit='s')
# 提取出时间周期性特征(如小时的正弦/余弦值)
df['hour_sin'] = np.sin(2 * np.pi * df['hour'] / 24)
df['hour_cos'] = np.cos(2 * np.pi * df['hour'] / 24)
df['minute_sin'] = np.sin(2 * np.pi * df['minute'] / 60)
df['minute_cos'] = np.cos(2 * np.pi * df['minute'] / 60)
df['dayOfWeek_sin'] = np.sin(2 * np.pi * df['dayOfWeek'] / 7)
df['dayOfWeek_cos'] = np.cos(2 * np.pi * df['dayOfWeek'] / 7)

# 删除不需要的字段
df = df.drop(columns=['id', 'mrpStatus', 'scene', 'create_at', 'year',
                      'winRate', 'hour', 'minute', 'dayOfWeek'])

# # 对 rewardName 进行 One-Hot 编码
df = pd.get_dummies(df, columns=['rewardName'], prefix='rewardName')
# # 打印 One-Hot 编码后的数据行数
# print("One-Hot 编码后的数据行数:", len(df))
# 提取需要归一化的字段(除了 One-Hot 编码后的 rewardName 列之外的所有列)
# columns_to_normalize = df.columns.difference([col for col in df.columns if col.startswith('rewardName')])
# 创建归一化器
scaler = MinMaxScaler()
# 定义需要归一化的字段
columns_to_normalize = [
    'totalRewardAmount', 'singleRewardAmount', 'totalBetAmount', 'betCount',
    'maxRewardAmount', 'minRewardAmount', 'stdDevRewardAmount',
    'totalRewardUsers', 'totalBetUsers', 'averageBetAmount'
]
# 对指定字段进行归一化
df[columns_to_normalize] = scaler.fit_transform(df[columns_to_normalize])

# 输出处理后的数据
# print(df)
xdata = df

xdata = np.array(xdata)
ydata = np.array(ydata)
# 如果代码卡住且长时间没有结果,可能是因为数据量过大或者某些操作导致计算复杂度过高。以下是一些可能的原因和解决方法:
# 1. 数据量过大
# 示例数据
data = xdata.flatten()[:10000]  # 只取前1000个数据点 # 生成随机时间序列
# 由于 PyTorch 张量在 GPU 上,而 Pandas 的 Series 无法直接处理 GPU 上的数据,因此会报错。
ts = pd.Series(data)
save_path = f'./'
figure_name = 'zixuexi_acf.png'
figure_name2 = 'zixuexi_pacf.png'
# # 绘制自相关图
# plot_acf(ts, lags=40)  # 设置横轴范围
# plt.xlabel('Lag')
# plt.ylabel('Autocorrelation')
# plt.title('Autocorrelation Function')
# plt.savefig(os.path.join(save_path, figure_name))
# # plt.show()
#  绘制自相关图(ACF)
fig, ax = plt.subplots(figsize=(12, 6))
sm.graphics.tsa.plot_acf(ts, lags=200, ax=ax)

# 设置横轴刻度标签
ax.set_xlabel('Lag')
ax.set_ylabel('Autocorrelation')
ax.set_title('Autocorrelation Function')

# 设置横轴刻度范围和间隔
ax.set_xlim(0, 54)  # 设置横轴范围
ax.set_xticks(range(0, 55, 1))  # 设置横轴刻度,每隔10个单位显示一个刻度
ax.set_xticklabels(range(0, 55, 1))  # 设置横轴刻度标签
# 保存图像
plt.savefig(os.path.join(save_path, figure_name))

# 显示图像
plt.show()

plot_pacf(ts, lags=200)
plt.xlabel('Lag')
plt.ylabel('Autocorrelation')
plt.title('Autocorrelation Function')
plt.savefig(os.path.join(save_path, figure_name2))
# plt.show()

供的代码和描述来看,训练结果都是 0 可能由多种原因导致。以下是一些可能的原因和解决方法:

1. 数据问题

  • 数据不平衡:如果数据集中某一类别的样本占主导地位,模型可能会倾向于预测该类别,从而导致输出结果偏向于 0(假设 0 是多数类)。

    • 解决方法:检查数据分布,使用数据增强、过采样或欠采样等方法来平衡数据。

  • 数据预处理问题:如果输入数据 x_trainy_train 没有正确归一化或标准化,可能会导致模型学习效果不佳。

    • 解决方法:确保输入数据的特征值在合理范围内(如 [0, 1] 或 [-1, 1]),并检查标签数据是否正确。

2. 模型结构问题

  • 激活函数选择不当:在你的代码中,使用了 LeakyReLUSoftmax。如果 LeakyReLU 的负斜率设置过小,可能会导致梯度消失问题,进而影响模型的学习能力。

    • 解决方法:尝试调整 LeakyReLU 的负斜率参数(如设置为 0.01 或 0.1),或者改用其他激活函数(如 ReLU)。

  • Softmax 层的使用问题Softmax 层通常用于多分类任务,它会将输出归一化为概率分布。如果输出层的输入值(即 fc 层的输出)都接近 0,经过 Softmax 后,所有类别的概率可能都会非常接近,导致最终预测结果偏向于 0。

    • 解决方法:检查 fc 层的输出值范围,确保其能够提供足够的区分度。如果问题仍然存在,可以尝试去掉 Softmax 层,直接使用 fc 层的输出进行训练,并在损失函数中使用 CrossEntropyLoss(它内部已经包含了 Softmax)。

  • 模型容量不足:模型的隐藏层大小、层数等参数可能设置得过小,导致模型无法学习到复杂的特征。

    • 解决方法:尝试增加隐藏层大小(如将 hidden_size 设置为 512 或更大)或增加 LSTM 和 TCN 的层数。

3. 训练过程问题

  • 学习率过低:学习率 learn_rate = 0.0001 可能过低,导致模型学习速度过慢,甚至无法收敛。

    • 解决方法:尝试使用更高的学习率(如 0.001 或 0.01),或者使用学习率调度器(如 torch.optim.lr_scheduler.StepLR)动态调整学习率。

  • 优化器选择不当:默认情况下,PyTorch 使用的是 SGD 优化器,它可能不适合某些复杂的模型。

    • 解决方法:尝试使用 Adam 优化器,它通常在训练深度学习模型时表现更好。

  • 损失函数选择不当:如果任务是多分类任务,但损失函数选择不正确(如使用了均方误差损失 MSELoss),可能会导致模型无法正确学习。

    • 解决方法:对于多分类任务,使用 CrossEntropyLoss;对于回归任务,使用 MSELoss 或其他适合的损失函数。

  • 权重初始化问题:在 forward 方法中,你手动初始化了 LSTM 的隐藏状态和细胞状态,但这些初始化值可能不合理,导致模型无法正常学习。

    • 解决方法:可以尝试使用 PyTorch 提供的默认初始化方法,或者使用更合适的初始化策略(如 Xavier 初始化或 Kaiming 初始化)。

4. 代码实现问题

  • pin_memory=False:在 DataLoader 中,pin_memory 设置为 False 可能会影响数据传输效率,尤其是在使用 GPU 训练时。

    • 解决方法:如果使用 GPU 训练,建议将 pin_memory 设置为 True

  • x_trainy_train 的设备问题:在代码中,你将 x_trainy_train 移动到了 CPU,但模型可能在 GPU 上运行。这会导致设备不匹配问题。

    • 解决方法:确保数据和模型在同一设备上。如果使用 GPU,可以将数据和模型都移动到 GPU 上:

      Python复制

      device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      x_train = x_train.to(device)
      y_train = y_train.to(device)
      model = model.to(device)

5. 调试建议

  • 检查中间输出:在模型的每一层添加打印语句,检查中间输出的值范围和形状。例如:

    Python复制

    print("TCN output:", x.shape, x.mean(), x.std())
    print("Attention1 output:", x.shape, x.mean(), x.std())
    print("LSTM1 output:", x.shape, x.mean(), x.std())

    通过这种方式,可以快速定位问题所在。

  • 简化模型:先从一个简单的模型(如单层 LSTM 或 TCN)开始训练,逐步增加复杂度。这样可以更容易地发现潜在问题。

 
TCN output: torch.Size([1511, 27, 256]) 
tensor(0.0414, device='cuda:0') 
tensor(0.0583, device='cuda:0')
Attention1 output: torch.Size([1511, 27, 256]) 
tensor(8.0837e-05, device='cuda:0') 
tensor(1.0003, device='cuda:0')
LSTM1 output: torch.Size([1511, 27, 256]) 
tensor(0.0121, device='cuda:0')
tensor(0.1156, device='cuda:0')
Attention1 output: torch.Size([1511, 27, 256]) 
tensor(0.0001, device='cuda:0') 
tensor(1.0008, device='cuda:0')
LSTM2 output: torch.Size([1511, 27, 256]) 
tensor(0.0143, device='cuda:0') 
tensor(0.1078, device='cuda:0')
output: torch.Size([1511, 8]) 
tensor(0.0007, device='cuda:0')
tensor(3.4623e-07, device='cuda:0') 

总结

训练结果都是 0 可能是由于数据问题、模型结构问题、训练过程问题或代码实现问题导致的。建议从数据预处理、模型结构调整、训练参数优化和代码调试等方面逐步排查问题。希望这些建议对你有所帮助!

从你提供的中间输出结果来看,问题主要集中在 Attention 层的输出值过小,这可能是导致最终输出结果接近 0 的主要原因。以下是具体的分析和可能的原因:

1. Attention 层输出值过小

Attention1 和第二次 Attention1 的输出中,均值(mean)非常小(如 8.0837e-050.0001),而标准差(std)接近 1。这表明 Attention 层的输出值几乎为 0,导致后续层的输入几乎为 0,最终影响了模型的输出。

可能的原因:
  • Attention 层的实现问题MultiHeadAttention 的实现可能存在问题,导致输出值过小。例如,注意力权重的计算可能不正确,或者缩放因子设置不合理。

  • 输入特征的尺度问题:如果输入特征的尺度不合适(如数值范围过大或过小),可能会导致注意力机制无法正常工作。

  • num_headsnum_channels 的设置问题num_heads 必须是 num_channels[-1] 的因数,但如果设置不合理,可能会导致注意力机制的计算出现问题。

解决方法:
  1. 检查 MultiHeadAttention 的实现

    • 确保 MultiHeadAttention 的实现是正确的。可以参考 PyTorch 的官方实现(torch.nn.MultiheadAttention)来对比和调试。

    • 确保注意力权重的计算公式正确,特别是缩放因子(scale)的设置。通常,缩放因子为 sqrt(d_k),其中 d_k 是每个注意力头的维度。

  2. 调整输入特征的尺度

    • 确保输入特征的数值范围在合理范围内(如 [0, 1] 或 [-1, 1])。如果输入特征的数值范围过大,可以尝试进行归一化或标准化处理。

  3. 重新设置 num_headsnum_channels

    • 确保 num_headsnum_channels[-1] 的因数。例如,如果 num_channels[-1] = 256num_heads 可以设置为 8、16 或 32。

    • 尝试调整 num_heads 的值,观察对输出的影响。

2. LSTM 层的输出值较小

LSTM1LSTM2 的输出中,均值(mean)较小(如 0.01210.0143),这表明 LSTM 层的输出值也较小。这可能是由于以下原因导致的:

可能的原因:
  • LSTM 的隐藏状态初始化问题:在 forward 方法中,你手动初始化了 LSTM 的隐藏状态和细胞状态,但这些初始化值可能不合理,导致 LSTM 的输出值较小。

  • LSTM 的输入值过小:由于 Attention 层的输出值过小,导致 LSTM 的输入值也过小,进而影响了 LSTM 的输出。

解决方法:
  1. 调整 LSTM 的隐藏状态初始化

    • 尝试使用 PyTorch 的默认初始化方法,而不是手动初始化隐藏状态和细胞状态。例如:

      Python复制

      h_01 = None
      c_01 = None
      h_02 = None
      c_02 = None

      或者使用更合理的初始化值,如:

      Python复制

      h_01 = torch.zeros(2, x.size(0), self.hidden_size).to(device)
      c_01 = torch.zeros(2, x.size(0), self.hidden_size).to(device)
      h_02 = torch.zeros(2, x.size(0), self.hidden_size).to(device)
      c_02 = torch.zeros(2, x.size(0), self.hidden_size).to(device)
  2. 调整 LSTM 的输入值

    • 确保 LSTM 的输入值(即 Attention 层的输出)在合理范围内。如果 Attention 层的输出值过小,可以尝试调整 Attention 层的实现或输入特征的尺度。

3. 最终输出值过小

在最终输出中,均值(mean)为 0.0007,标准差(std)为 3.4623e-07,这表明输出值几乎为 0。这可能是由于以下原因导致的:

可能的原因:
  • 输出层的激活函数问题Softmax 层的输入值(即 fc 层的输出)可能过小,导致经过 Softmax 后,所有类别的概率都非常接近 0。

  • 模型的训练不足:模型可能没有充分学习到数据的特征,导致输出值过小。

解决方法:
  1. 调整输出层的激活函数

    • 如果任务是多分类任务,可以尝试去掉 Softmax 层,直接使用 fc 层的输出进行训练,并在损失函数中使用 CrossEntropyLoss(它内部已经包含了 Softmax):

      Python复制

      self.fc = nn.Linear(hidden_size, output_size)
      # 去掉 Softmax 层
  2. 调整训练参数

    • 增加训练的迭代次数(epoch)。

    • 调整学习率(如使用更高的学习率或学习率调度器)。

    • 使用更合适的优化器(如 Adam)。

总结

从中间输出结果来看,主要问题是 Attention 层的输出值过小,导致后续层的输入值也过小,最终影响了模型的输出。建议从以下方面进行调整:

  1. 检查和调整 MultiHeadAttention 的实现。

  2. 调整输入特征的尺度。

  3. 重新设置 num_headsnum_channels

  4. 调整 LSTM 的隐藏状态初始化。

  5. 调整输出层的激活函数和训练参数。

希望这些建议能帮助你解决问题!

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐