在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是给起始标记的 补码尽量不使用,也就是说序列长度基本接近于 序列的最大长度 - 如果补码过多,就会出现一个个补码相连的情况,这会让模型认为补码后就是补码,因为模型算的是概率 |
|
|
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维的 ,稍微有些不同 但仔细想想,序列中真实表达的意思,对世界的描述,是多维的,复杂结构的 |
|
|
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]))
for X,y in trainDataLoader:
print(X.shape,y.shape) #torch.Size([64, 100, 3]) torch.Size([64, 100, 1])
break
这是个回归问题,每个数据元素映射到一个数值
|
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)
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维度的数值上,也就是回归问题
|
|
|
|
|
|
|