tcn-attention-lstm 等深度神经网络 训练的结果是0 怎么解决 是什么原因导致的
训练结果都是 0 可能是由于数据问题、模型结构问题、训练过程问题或代码实现问题导致的。建议从数据预处理、模型结构调整、训练参数优化和代码调试等方面逐步排查问题。希望这些建议对你有所帮助!
第一步:
调整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_train
和y_train
没有正确归一化或标准化,可能会导致模型学习效果不佳。-
解决方法:确保输入数据的特征值在合理范围内(如 [0, 1] 或 [-1, 1]),并检查标签数据是否正确。
-
2. 模型结构问题
-
激活函数选择不当:在你的代码中,使用了
LeakyReLU
和Softmax
。如果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_train
和y_train
的设备问题:在代码中,你将x_train
和y_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-05
和 0.0001
),而标准差(std)接近 1。这表明 Attention 层的输出值几乎为 0,导致后续层的输入几乎为 0,最终影响了模型的输出。
可能的原因:
-
Attention 层的实现问题:
MultiHeadAttention
的实现可能存在问题,导致输出值过小。例如,注意力权重的计算可能不正确,或者缩放因子设置不合理。 -
输入特征的尺度问题:如果输入特征的尺度不合适(如数值范围过大或过小),可能会导致注意力机制无法正常工作。
-
num_heads
和num_channels
的设置问题:num_heads
必须是num_channels[-1]
的因数,但如果设置不合理,可能会导致注意力机制的计算出现问题。
解决方法:
-
检查
MultiHeadAttention
的实现:-
确保
MultiHeadAttention
的实现是正确的。可以参考 PyTorch 的官方实现(torch.nn.MultiheadAttention
)来对比和调试。 -
确保注意力权重的计算公式正确,特别是缩放因子(
scale
)的设置。通常,缩放因子为sqrt(d_k)
,其中d_k
是每个注意力头的维度。
-
-
调整输入特征的尺度:
-
确保输入特征的数值范围在合理范围内(如 [0, 1] 或 [-1, 1])。如果输入特征的数值范围过大,可以尝试进行归一化或标准化处理。
-
-
重新设置
num_heads
和num_channels
:-
确保
num_heads
是num_channels[-1]
的因数。例如,如果num_channels[-1] = 256
,num_heads
可以设置为 8、16 或 32。 -
尝试调整
num_heads
的值,观察对输出的影响。
-
2. LSTM 层的输出值较小
在 LSTM1
和 LSTM2
的输出中,均值(mean)较小(如 0.0121
和 0.0143
),这表明 LSTM 层的输出值也较小。这可能是由于以下原因导致的:
可能的原因:
-
LSTM 的隐藏状态初始化问题:在
forward
方法中,你手动初始化了 LSTM 的隐藏状态和细胞状态,但这些初始化值可能不合理,导致 LSTM 的输出值较小。 -
LSTM 的输入值过小:由于
Attention
层的输出值过小,导致 LSTM 的输入值也过小,进而影响了 LSTM 的输出。
解决方法:
-
调整 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)
-
-
调整 LSTM 的输入值:
-
确保 LSTM 的输入值(即
Attention
层的输出)在合理范围内。如果Attention
层的输出值过小,可以尝试调整Attention
层的实现或输入特征的尺度。
-
3. 最终输出值过小
在最终输出中,均值(mean)为 0.0007
,标准差(std)为 3.4623e-07
,这表明输出值几乎为 0。这可能是由于以下原因导致的:
可能的原因:
-
输出层的激活函数问题:
Softmax
层的输入值(即fc
层的输出)可能过小,导致经过Softmax
后,所有类别的概率都非常接近 0。 -
模型的训练不足:模型可能没有充分学习到数据的特征,导致输出值过小。
解决方法:
-
调整输出层的激活函数:
-
如果任务是多分类任务,可以尝试去掉
Softmax
层,直接使用fc
层的输出进行训练,并在损失函数中使用CrossEntropyLoss
(它内部已经包含了Softmax
):Python复制
self.fc = nn.Linear(hidden_size, output_size) # 去掉 Softmax 层
-
-
调整训练参数:
-
增加训练的迭代次数(epoch)。
-
调整学习率(如使用更高的学习率或学习率调度器)。
-
使用更合适的优化器(如
Adam
)。
-
总结
从中间输出结果来看,主要问题是 Attention
层的输出值过小,导致后续层的输入值也过小,最终影响了模型的输出。建议从以下方面进行调整:
-
检查和调整
MultiHeadAttention
的实现。 -
调整输入特征的尺度。
-
重新设置
num_heads
和num_channels
。 -
调整 LSTM 的隐藏状态初始化。
-
调整输出层的激活函数和训练参数。
希望这些建议能帮助你解决问题!
更多推荐
所有评论(0)