transformer·注意力
在seq2seq2中使用RNN提取序列特征 - RNN是有前后依赖关系的,因此不能并行运算 - 注意力替换RNN后可以并行运算了,但不再有前后依赖关系了
解决办法是 通过位置编码 加入 位置信息 - 因为有了位置信息,相同的单词处于不同的位置上时,信息是不一样的 - 位置编码数的数值不能太大,毕竟向量的值的范围为[-1,1]
在resnet中, 做了一个k=1的卷积才做为短接的主线 在transformer中,直接对原始数据做深度clone,做为短接的主线 - 这意味着,梯度几乎没有消失 - 意味着,神经网络可以有很多层 辅助线有两个 - 一个是注意力计算,直接将注意力计算的结果+主线 - 一个是全连接,直接将全连接的计算结果+主线
层归一化放在了主线的clone之后 - 随着层数增加,主线的变化只有一个 - 就是将辅线的计算结果加上主线上 - 这可能导致主线变化较大,所以辅线计算时,先做一个层归一化 - 如此,辅线的起点近似相同,处理后的结果也都在0附近,[-1,1]
``` ------------------------------------------------------------------------------- ```
时序数据
**天 import pandas as pd import numpy as np import torch import torch.nn as nn from sklearn.preprocessing import MinMaxScaler # 生成模拟时序数据 def generate_time_series(start_date, num_steps, freq='D'): timestamp = pd.date_range(start=start_date, periods=num_steps, freq=freq) trend = np.linspace(0, 5, num_steps) seasonality = 10 * np.sin(np.linspace(0, 10*np.pi, num_steps)) noise = np.random.normal(0, 1, num_steps) value = trend + seasonality + noise return pd.DataFrame({ 'timestamp': timestamp, 'value': value.astype(np.float32), 'feature1': np.random.uniform(0, 10, num_steps), # 附加随机特征 'feature2': np.random.randint(0, 5, num_steps) }).set_index('timestamp') # 参数配置 SEQ_LENGTH = 100 # 滑动窗口长度 BATCH_SIZE = 64 HIDDEN_SIZE = 32 EPOCHS = 50 # 生成数据 df = generate_time_series('2025-01-01', 100) scaler = MinMaxScaler() scaled_data = scaler.fit_transform(df.values) 分钟 import pandas as pd # 示例1:指定起止时间生成分钟序列 time_index_1 = pd.date_range( start='2023-01-01 08:00', end='2024-01-01 08:05', freq='T' ) # 示例2:通过起始时间+数量生成序列 time_index_2 = pd.date_range( start='2023-01-01 09:00', periods=120, # 生成120个时间点(120分钟) freq='T' ) # 示例3:生成15分钟间隔序列 time_index_3 = pd.date_range( start='2023-01-01 10:00', periods=4, freq='15T' # 输出为10:00, 10:15, 10:30, 10:45 ) # 转换为DataFrame df = pd.DataFrame(index=time_index_1) df.shape #(525606, 0) df[:7] 2023-01-01 08:00:00 2023-01-01 08:01:00 2023-01-01 08:02:00 2023-01-01 08:03:00 2023-01-01 08:04:00 2023-01-01 08:05:00 2023-01-01 08:06:00 秒级 import pandas as pd timestamps = pd.date_range( start='2024-04-12 13:57:32', end='2025-04-12 13:57:42', freq='S' ) timestamps.shape #(31536011,) import pandas as pd timestamps = pd.date_range( start='2024-04-12 13:57:32', end='2025-04-12 13:57:42', freq='10S' ) timestamps.shape #(3153602,) import pandas as pd import numpy as np # 生成模拟时序数据 def generate_time_series(): time_index_1 = pd.date_range( start='2023-01-01 08:00', end='2024-01-01 08:05', freq='min' ) num_steps = time_index_1.shape[0] trend = np.linspace(0, 5, num_steps) seasonality = 10 * np.sin(np.linspace(0, 10*np.pi, num_steps)) noise = np.random.normal(0, 1, num_steps) #将多个特征合并为一个时序 value = trend + seasonality + noise return pd.DataFrame({ 'timestamp': time_index_1, 'value': value.astype(np.float32), 'feature1': np.random.uniform(0, 10, num_steps), # 附加随机特征 'feature2': np.random.randint(0, 5, num_steps) }).set_index('timestamp') # 生成数据 df = generate_time_series() df 多个维度的数据相加合并为一列,再融入一些噪声 多个维度的数据合并,同时融合了target, 目标是将target中分离出来 从序列中分离出另外一个序列 import torch import pandas as pd import numpy as np # 生成模拟时序数据 def generate_time_series11(): time_index_1 = pd.date_range( start='2023-01-01 08:00', end='2024-01-01 08:05', freq='min' ) num_steps = time_index_1.shape[0] trend = np.linspace(0, 5, num_steps) seasonality = 10 * np.sin(np.linspace(0, 10*np.pi, num_steps)) noise = np.random.normal(0, 1, num_steps) #[low,high) #这里一个交易对应一个类别,一个序列中有seq_len条交易,这个类别也形成一个序列 target = 3 * np.sin(np.linspace(0, 7*np.pi, num_steps)) #将多个特征合并为一个时序 value = trend + seasonality + noise + target return pd.DataFrame({ 'timestamp': time_index_1, 'value': value.astype(np.float32), 'feature1': np.random.uniform(0, 10, num_steps), # 附加随机特征 'feature2': np.random.randint(0, 5, num_steps) }).set_index('timestamp'),pd.DataFrame(target,columns=['target']) # 生成数据 df_X,df_y = generate_time_series11() df = df_X from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaled_data = scaler.fit_transform(df.values) # 参数配置 SEQ_LENGTH = 100 # 滑动窗口长度 BATCH_SIZE = 64 HIDDEN_SIZE = 32 EPOCHS = 50 import torch # 构建训练集 def create_sequences11(data,label_seq, seq_length): sequences = [] targets = [] iv = seq_length//10 for i in range(0,len(data)-seq_length,iv): sequences.append(data[i:i+seq_length]) targets.append(label_seq[i:i+seq_length]) # 预测主特征 return torch.FloatTensor(sequences), torch.FloatTensor(targets) label_seq = np.array(df_y) X, y = create_sequences11(scaled_data, label_seq, SEQ_LENGTH) X.shape,y.shape (torch.Size([52551, 100, 3]), torch.Size([52551, 100, 1])) 序列的长度 LSTM 通常处理20个长度的序列 Transformer没有此限制,但通常不超过50, 实际上是大模型无限制,但小模型序列长了准备率仍不高 编码字典 原项目 X一套字典,y一套字典, 即编码序列一套字典,解码序列一套字典 原项目是一对一转换之后又做了逆序处理, 个人没有做逆序处理,在一一对应的情况下分别编码,导致a与A的编码一致 - 这使得转化后的数据序列字母本就一致,进而让模型参数还没有学习损失函数的值就非常低 - 损失函数低完全是编码巧合导致的,并不是模型具备了很好的预测能力 补码 n = random.randint(pc.min_len_seq, pc.max_len_seq-2) #减的2是给起始标记的 补码尽量不使用,也就是说序列长度基本接近于 序列的最大长度 - 如果补码过多,就会出现一个个补码相连的情况,这会让模型认为补码后就是补码,因为模型算的是概率 mytab('ultsf_sxdtat', 'tbtsf_sxdtat'); 时序·Xy31 封装调用 序列数据 交易·序列 频率·序列 图像·序列 from tpf.datasets import SeqXy31 from torch.utils.data import DataLoader dataset = SeqXy31(seq_len=100) trainDataLoader = DataLoader(dataset=dataset,batch_size=64,shuffle=True,drop_last=True) for X,y in trainDataLoader: print(X.shape,y.shape) #torch.Size([64, 100, 3]) torch.Size([64, 100, 1]) break X,y皆序列:从多组序列中分解出一个序列 import torch import pandas as pd import numpy as np from tpf.datasets import sd X,y = sd.getXy31(seq_len=100) X.shape,y.shape #(torch.Size([52551, 100, 3]), torch.Size([52551, 100, 1])) sd:seq data,序列数据** 正弦时序数据 - X:主特征value:三个特征+一个随机噪声;两个随机特征,feature1,feature2;做了归一化处理 - y:主特征value中的一个正弦时序
一个seq元素[seq_len, col_nums],即一个X[i] 由一个3维的向量表示,即用3个元素表示一条数据 [batch_size, seq_len, col_nums] -- [64, 100, 1] - 将X[i] 变换到 1维度的数值上,也就是回归问题
如果是交易,那么就是seq len个交易组合成一个序列,将这个序列看作一个元素 - Xy31的y也是一个序列,其元素与X中的元素按索引一一对应 - 本质上还是X[i] -- y[i]的映射 - [batch_size,xi] -- [batch_size, yi]的映射 xi与xj之间是相互独立的 [batch_size, seq_len, col_nums] -- [64, seq_len, 1] - 将[seq_len, col_nums]看作一个元素时,每个X[i] -- y[i]的映射是结合了整个seq的信息的 - 是X[i]结合了X[0]...X[i-1],X[i+1]...X[n-1]的信息映射到y[i]的
Xy31实际上是由正弦函数+线性函数生成的数据 每个X[i] 都可以对应一个时间函数t(i) 这实际上是一个时序数据,有多个维度,每个维度有自己的频率
从频率的角度看交易 - 在时间函数t(i)上产生一条交易数据 - 每个交易有多个频率的信号组合而成 - 即将频率与列对应起来,一个列可看作是相同频率的函数在时间上的展开
Xy31一个元素X[i]有3个特征组成,这与图像的像素相似 - 图像中一个像素就是3个元素,然后多个像素组成一张图片,就是一个元素 - 这里一条交易就是一个元素,多个元素组成一个序列 - 不同的是图像是2维的,序列是1维的 ,稍微有些不同
但仔细想想,序列中真实表达的意思,对世界的描述,是多维的,复杂结构的
时序·模型
```python import pandas as pd import numpy as np import torch from torch import nn from tpf.datasets import SeqXy31 from torch.utils.data import DataLoader class pc: batch_size = 64 seq_len=100 col_nums = 3 embedding_dim=128 class_nums = 1 dataset = SeqXy31(seq_len=100) trainDataLoader = DataLoader(dataset=dataset,batch_size=pc.batch_size,shuffle=True,drop_last=True) dataset[0][0][0],dataset[1][0][0] ```
``` (tensor([0.3810, 0.4219, 1.0000]), tensor([0.4002, 0.0629, 1.0000])) ```
```python for X,y in trainDataLoader: print(X.shape,y.shape) #torch.Size([64, 100, 3]) torch.Size([64, 100, 1]) break ```
这是个回归问题,每个数据元素映射到一个数值
```python from tpf.nlp.ts13 import SeqTrans #每个元素由seq_len个特征组成,每个特征的维度输入时为in_feature_dim,输出为out_feature_dim,在embedding_dim上变换 model = SeqTrans(seq_len=pc.seq_len, in_feature_dim=pc.col_nums, out_feature_dim=pc.class_nums, embedding_dim=pc.embedding_dim) loss_fn = nn.MSELoss() optim = torch.optim.Adam(params= model.parameters(),lr=1e-4) ```
```python for X,y in trainDataLoader: y_out = model(X) print(y_out.shape,y.shape) # torch.Size([64, 100, 1]) torch.Size([64, 100, 1]) loss = loss_fn(y_out,y) loss.backward() #求参数导 optim.step() #参数调整 optim.zero_grad() #清空参数梯度 print(round(loss.item(),5)) #5.5041 break ```
一个seq元素,即一个X[i] 由一个3维的向量表示,即用3个元素表示一条数据 [batch_size, seq_len, col_nums] -- [64, 100, 1] - 将X[i] 变换到 1维度的数值上,也就是回归问题
参考