基于Transformer的多变量风电功率预测TF2

news2024/11/15 7:59:36

        Transformer目前大火,作为一个合格的算法搬运工自然要跟上潮流,本文基于tensorflow2框架,构建transformer模型,并将其用于多变量的风电功率负荷预测。  实验结果表明,相比与传统的LSTM,该方法精度更高,缺点也很明显,该方法需要更多的数据训练效果才能超过传统方法,而且占用很高的gpu资源(测试阶段,一次性输入所有测试集数据直接会OOM,需要分批输入),cpu就更慢了。

        今天是2023年的第一天,首先总结一下2022的收获:

         接着进入正题

1 Transformer网络结构

        原始的transformer网络是用来的处理文本翻译这样的任务,输入=输出(输出是另一种形式的输出),所以原始的网络是先编码再解码的结构,数据进入网络进行编码器,得到隐含特征,然后利用解码器,将其还原成另外一种表达。而我们进行风电功率预测,由于我们的输入与输出不是同一个东西,所以我在网络中去掉了解码器,直接将编码器的输出作为提取的特征,然后接一个全连接层作为输出层,输出功率值。具体理解包括:输入层→编码器→输出层。

1.1 输入输出层

        本文采用的数据形式如图1所示,数据含有6个特征,采用滚动序列建模的方法,生成输入数据与输出数据。具体为:设定输入时间步m与输出时间步n,然后取第1到m时刻的所有数据作为输入,取第m+1到第m+n时刻的实际发电功率作为输出,作为第一个样本;然后取第2到m+1时刻的所有数据作为输入,取第m+2到第m+n+1时刻的实际发电功率作为输出,作为第二个样本。。。依次类推,通过这种滚动的方法获得输入输出数据。当m取10,n取3时,则输入层的维度为[None,10,6],输出层的维度为[None,3],模型训练好后,只需要输入过去10个时刻的所有数据,就能预测得到未来3个时刻的发电功率预测值。

图1
图1 数据结构

1.2 编码器 

1.2.1 嵌入层

        嵌入层实际上只是一个简单的全连接层,将原本维度变换到d_model,其目的有两个:1)对原始数据进行特征变换,原始只有6个特征,假设这些特征之间是有联系的,采用一个全连接层可以让特征之间进行交互,起到变换特征的作用;2)其次的是增加网络复杂度,为了后续使用多头自注意力机制,多头的数量必须与能被特征整除,打个比方,假如原始的6个特征变换到64个,然后就能用1、2、4、8、16、32、64头数,可选择性较高,如果只是6的话,就只能设置1、2、3,采用更多的头数可以增加网络复杂度,如果风电数据有几万条,网络过于简单无法有效的学习到这么长的序列的特征。

        在程序中我将d_model设成16,则经过嵌入层之后的数据为:

d_model=16
embedding = tf.keras.layers.Dense(d_model)
x=np.random.rand(64,10,6)#64是batchsize 10是输入时间步 6是6个特征
y=embedding (x) #y的shape变成 64,10,16

1.2.2 位置编码

        Transformer使用的是正余弦位置编码。位置编码通过使用不同频率的正弦、余弦函数生成,然后和对应的位置的输入向量(嵌入层的输出数据)相加,位置向量维度必须和词向量的维度一致

def get_angles(pos, i, d_model):
    # 这里的i等价与公式中的2i和2i+1
    angle_rates = 1 / np.power(10000, (2 * (i//2)) / np.float32(d_model))
    return pos * angle_rates

def positional_encoding(maximum_position_encoding, d_model):
    
    angle_rads = get_angles(np.arange(maximum_position_encoding)[:, np.newaxis], np.arange(d_model)[np.newaxis, :],d_model)
    # apply sin to even indices in the array; 2i
    angle_rads[:, 0::2] = np.sin(angle_rads[:, 0::2])
    # apply cos to odd indices in the array; 2i+1
    angle_rads[:, 1::2] = np.cos(angle_rads[:, 1::2])
    pos_encoding = angle_rads[np.newaxis, ...]
    return tf.cast(pos_encoding, dtype=tf.float32)
x=np.random.rand(64,10,16)
pos_enc=positional_encoding(5000, 16)
x +=pos_enc[:,x.shape[1],:] #x的shape还是[64,10,16]

 1.2.3 self-attention自注意力机制

        自注意力网络上很多解释,这里我们简单的理解一下计算步骤:通过嵌入层与位置编码后,我们的数据是64 x 10 x 16 其中64表示batchsize 10表示时间步  16为特征维度。如果我们想要获得第i个样本的input-1(每一个样本含10个input,每个input的维度是16)的输出,那么我们进行如下几步:

1、构建3个全连接层,每个维度都是d_model,输入input-1,分别得到3个变量,即Q、K、V,可以将QKV就理解成input-1的另一种表达
1、利用input-1的Q,分别乘上input-1、input-2、....、input-16的K',此时我们获得了16个score。这个score,这就是相较于input-1、input-2、....、input-16,input-1的重要程度

        这里你会很奇怪为啥score就是input-1相较于其他input的重要程度。我的理解是:Q乘K'是点积。啥时点积?点积就是余弦相似度的分子,QK'近似等于余弦相似度,如果两个变量越相似,QK‘就越大;可推,如果一个变量最重要,那他可以近似代替其他变量,那他与其他变量的点积就会很大。(也可以理解成相关性,一样的推理)

2、然后对这些score取softmax,归一化重要程度。
3、然后将这个重要程度乘上input-1、input-2、....、input-16的值向量,求和。
4、此时我们获得了input-1的输出。

1.2.4 多头注意力

        多头注意力,可以理解为我们每个头只计算部分特征,比如第一个头只计算input-1到input-4,第二个头计算input-5到input-8,16个特征就是4个头。

1.2.5 编码器

        编码器就是输入经嵌入层+位置编码+多头注意力层+多头注意力层+多头注意力层+...+多头注意力层,得到输出特征,然后输入一个全连接层,就能得到我们的输出

def scaled_dot_product_attention(q, k, v, mask):
    """Calculate the attention weights.
    q, k, v must have matching leading dimensions.
    k, v must have matching penultimate dimension, i.e.: seq_len_k = seq_len_v.
    The mask has different shapes depending on its type(padding or look ahead) 
    but it must be broadcastable for addition.
    Args:
    q: query shape == (..., seq_len_q, depth)
    k: key shape == (..., seq_len_k, depth)
    v: value shape == (..., seq_len_v, depth_v)
    mask: Float tensor with shape broadcastable to (..., seq_len_q, seq_len_k). Defaults to None.
    
    Returns:
      output, attention_weights
    """
    matmul_qk = tf.matmul(q, k, transpose_b=True)  # (..., seq_len_q, seq_len_k)
    # scale matmul_qk
    dk = tf.cast(tf.shape(k)[-1], tf.float32)   ## 64
    scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)
    # add the mask to the scaled tensor.
    if mask is not None:
        scaled_attention_logits = scaled_attention_logits + (mask * -1e9)  
    # softmax is normalized on the last axis (seq_len_k) so that the scores
    # add up to 1.
    attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1)  # (..., seq_len_q, seq_len_k)
    output = tf.matmul(attention_weights, v)  # (..., seq_len_q, depth_v)
    return output, attention_weights

class MultiHeadAttention(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads):
    super(MultiHeadAttention, self).__init__()
    self.num_heads = num_heads
    self.d_model = d_model
    assert d_model % self.num_heads == 0# d_model self.num_heads 要能够整除
    self.depth = d_model // self.num_heads
    self.wq = tf.keras.layers.Dense(d_model)
    self.wk = tf.keras.layers.Dense(d_model)
    self.wv = tf.keras.layers.Dense(d_model)
    self.dense = tf.keras.layers.Dense(d_model)
  def split_heads(self, x, batch_size):
    """Split the last dimension into (num_heads, depth).
    Transpose the result such that the shape is (batch_size, num_heads, seq_len, depth)
    """
    x = tf.reshape(x, (batch_size, -1, self.num_heads, self.depth))
    return tf.transpose(x, perm=[0, 2, 1, 3])
  def call(self, v, k, q, mask):
    batch_size = tf.shape(q)[0]
    q = self.wq(q)  # (batch_size, seq_len, d_model)
    k = self.wk(k)  # (batch_size, seq_len, d_model)
    v = self.wv(v)  # (batch_size, seq_len, d_model)
    q = self.split_heads(q, batch_size)  # (batch_size, num_heads, seq_len_q, depth)
    k = self.split_heads(k, batch_size)  # (batch_size, num_heads, seq_len_k, depth)
    v = self.split_heads(v, batch_size)  # (batch_size, num_heads, seq_len_v, depth)
    # scaled_attention.shape == (batch_size, num_heads, seq_len_q, depth)
    # attention_weights.shape == (batch_size, num_heads, seq_len_q, seq_len_k)
    scaled_attention, attention_weights = scaled_dot_product_attention(q, k, v, mask)
    scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3])  # (batch_size, seq_len_q, num_heads, depth)
    concat_attention = tf.reshape(scaled_attention, 
                                  (batch_size, -1, self.d_model))  # (batch_size, seq_len_q, d_model)
    output = self.dense(concat_attention)  # (batch_size, seq_len_q, d_model)
    return output, attention_weights

def point_wise_feed_forward_network(d_model, dff):
  return tf.keras.Sequential([
      tf.keras.layers.Dense(dff, activation='relu'),  # (batch_size, seq_len, dff)
      tf.keras.layers.Dense(d_model)                  # (batch_size, seq_len, d_model)
  ])

class EncoderLayer(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads, dff, rate=0.1):
    super(EncoderLayer, self).__init__()
    self.mha = MultiHeadAttention(d_model, num_heads)
    self.ffn = point_wise_feed_forward_network(d_model, dff)
    self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.dropout1 = tf.keras.layers.Dropout(rate)
    self.dropout2 = tf.keras.layers.Dropout(rate)
  def call(self, x, training, mask):
    attn_output, _ = self.mha(x, x, x, mask)  # (batch_size, input_seq_len, d_model)
    attn_output = self.dropout1(attn_output, training=training)
    out1 = self.layernorm1(x + attn_output)  # (batch_size, input_seq_len, d_model)
    ffn_output = self.ffn(out1)  # (batch_size, input_seq_len, d_model)
    ffn_output = self.dropout2(ffn_output, training=training)
    out2 = self.layernorm2(out1 + ffn_output)  # (batch_size, input_seq_len, d_model)
    return out2

class Encoder(tf.keras.layers.Layer):
  def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
               maximum_position_encoding, rate=0.1):
    super(Encoder, self).__init__()
    self.d_model = d_model
    self.num_layers = num_layers
    self.embedding = tf.keras.layers.Dense(d_model)
    self.pos_encoding = positional_encoding(maximum_position_encoding, self.d_model)
    self.enc_layers = [ EncoderLayer(d_model, num_heads, dff, rate) for _ in range(num_layers) ]
    self.dropout = tf.keras.layers.Dropout(rate)
  def call(self, x, training, mask):
    seq_len = tf.shape(x)[1]
    # adding embedding and position encoding.
    x = self.embedding(x)  # (batch_size, input_seq_len, d_model)
    # print('------------------\n',seq_len)
#    x=tf.tile(tf.expand_dims(x,2),self.d_model)
    x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))
    # print(x.shape)
    x += self.pos_encoding[:, :seq_len, :]
    x = self.dropout(x, training=training)
    # print(x.shape)
    # print(mask.shape)
    for i in range(self.num_layers):
      x = self.enc_layers[i](x, training, mask)
    return x  # (batch_size, input_seq_len, d_model)

2 实战

        经过全面的分析,现在就可以训练网络了。

2.1 BP网

目录

1 Transformer网络结构

1.1 输入输出层

1.2.1 嵌入层

1.2.2 位置编码

 1.2.3 self-attention自注意力机制

1.2.4 多头注意力

1.2.5 编码器

2 实战

2.1 BP网络

2.2 LSTM网络

2.3 Transformer模型

2.4 对比

3 代码


        训练一个BP来做对比

2.2 LSTM网络

        训练一个LSTM来做对比

 

2.3 Transformer模型

 

 

2.4 对比

        就取1000个点来画图对比

 

3 代码

        详细代码数据见评论区 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141403.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

干货 | 背熟这些 Docker 命令,面试再也不怕啦~

我们下载 Docker 镜像的时候,默认会访问 Docker 网站,而 Docker 网站是在国外部署的,距离比较远下载速度特别慢。我们可以通过设置加速器的方式来加速 Docker 镜像下载的速度。下面将描述一下使用加速器的步骤:1.我们这里选择的是…

ORB-SLAM2 --- MapPoint::Replace函数

目录 1.函数作用 2.code 3.函数解析 1.函数作用 替换地图点,更新观测关系。 2.code void MapPoint::Replace(MapPoint* pMP) {// 同一个地图点则跳过if(pMP->mnIdthis->mnId)return;//要替换当前地图点,有两个工作:// 1. 将当前地图点的观测数据等其他数…

数据报告:[数字健康]如何引发美国医疗深度变革

本文由前嗅数据研究院出品 在美国,全球疫情的不断发展扩大,促进了其医疗行业的变革与创新,以“Digital Health”(数字健康)为关键词的医疗领域正在发⽣⾰命性的变化。本文着重介绍“Digital Health”的特点及其在各领域…

【博学谷学习记录】超强总结,用心分享|kafka如何保证数据不丢失

文章目录数据在Kafka中的流转阶段一:生产者如何保证数据不丢失ACK机制阶段二:Broker端如何保证数据不丢失磁盘副本阶段三:消费者如何保证数据不丢失消费者提交偏移量数据在Kafka中的流转 阶段一:生产者如何保证数据不丢失 ACK机制 生产者将数据生产到Broker后,Broker需要给一个…

学习python之——python入门

欢迎来到 Python 入门的学习之旅! Python 是一种高级编程语言,它是一种解释型语言,有着丰富的库和大量的第三方模块,能够用于许多不同的编程任务。无论你是想要学习 Python 进行 Web 开发,还是想用它来进行数据分析和…

Windows 远程桌面 Ubuntu

参考 Windows远程桌面工具连接Ubuntu系统使用总结_CHH3213的博客-CSDN博客_远程连接ubuntu 开启ssh服务(非必须 查看ssh是否已经开启 sudo ps -e | grep ssh 如果最后返回是sshd,证明ssh已经开启,跳到第四步 第二步,如果没有…

excel处理时间数据

目录excel中的日期中同时提取年月,可使用YEAR函数提取年份,MONTH函数提取月份,然后使用合并函数“&”将年月合并即可。方法步骤如下: 1、打开需要操作的EXCEL表格,在任意空白单元格上面的函数编辑框中输入“YEAR&…

自动化 HR 流程,实现人力资源部门无纸化

自动化 HR 流程,实现人力资源部门无纸化 如果公司使用手动流程,人力资源部门则可能是纸张最密集的部门之一。使用像Google Docs或Dropbox这样的免费文件共享应用程序可能会感觉比使用纸张更上一层楼。但是,这些应用程序旨在在某个时间点启用…

python居然还能画出这么精美的魔法少女,惊我一整年

前言 大家早好、午好、晚好吖 ❤ ~ 对于上面漫小姐姐图,大家觉得好不好看呢 这种极简的线条画出超具魅力的小姐姐图 简直不要太击中小心脏 接下来,我们就用python来实现一下,画出一个好看的少女~ 代码展示 导入模块 import turtle as te…

VIVADO异步时钟域约束(groups)

异步时钟域约束 VIVADO异步时钟约束之实例演示 操作方法: 1、先在synthesis 中打开 report clock interaction ,可以看到没有约束的异步时钟之间用红色标记; 2、在synthesis中打开edit timing constraints 设置异步时钟; 3、异…

QGroundControl 添加自定义FactGroup

基于QGC4.1.2版本进行添加,首先由于QGC的原来对FactGroup定义均写在Vehicle.h和Vehicle.cc两个文件中,个人感觉都写在Vehicle文件下回导致文件过大,所以将FactGroup定义进行分离,写在各自的.h和.cc文件下,然后在Vehicl…

运动无线耳机哪个品牌比较好、运动效果最好的运动耳机推荐

近几年,运动耳机愈发获得消费者的认可。它拥有着更牢固的佩戴方式,即便是长时间佩戴、也拥有更舒适的体验。因此,运动耳机也受到运动、健身人群的喜爱。但是不少小伙伴跟我反映如何选择一款体验出色的运动耳机,也成为了当前不少运…

计算机sci期刊拒稿两次,重新投稿接受的概率大吗? - 易智编译EaseEditing

重新投稿需要修改的幅度很大,而且就算能接受,时间也会非常久。 要是不着急用可以试试: 根据审稿意见一条条的来修改; 增加新的参考文献; 如果是“修改后重投”,可能需要注意以下问题: 1. 与…

数据可视化,2022A股正式收官,这么特别的一年,你挣钱了吗?

“A股年线止步三连阳!深成指全年累计下跌25.85%;创业板指全年累计下跌累计29.37%;上证50指数累计下跌19.52%;科创50指数累计下跌31.35%。其中,创业板指、深成指仅跑赢俄罗…

循环神经网络-高级篇RNN Classifier

循环神经网络-高级篇RNN Classifier 本篇实现一个循环神经网络的分类器RNN Classifier 我们使用一个数据集包含Name,Country,其中名字有几千个,来自18个不同的国家,我们的目标是训练一个模型,可以实现输入一个名字&a…

cad绘图:AutoCAD 2023 中文

Autodesk AutoCAD 2023是计算机辅助设计(CAD)软件,是世界领先的2D和3D CAD工具。它将允许您使用其强大而灵活的功能来设计和塑造您周围的世界。在3D中加速文档制作,无缝地分享想法,更直观地探索想法。AutoCAD使用户能够从桌面、Web和移动设备…

http 模块

1、什么是 http 模块 http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的http.createServer() 方法,就能方便的把一台普通的电脑,变成一台 Web 服务器,从而对外提供Web 资源服务。 如果要希望使用 http 模块…

Centos8/linux下载、安装、配置、连接MySQL5.7(rpm方式)

目录 问题现象: 问题分析: 解决方法: 下载: 安装: 配置: 连接: 拓展 问题现象: 今天在使用Centos8 安装MySQL5.7的rpm包时,出现如下报错: 仓库 "…

【ROS】—— ROS运行管理 ——元功能包与launch文件(八)

文章目录前言1. 元功能包1.1 应用场景1.2 概念1.3 实现2. ROS节点运行管理launch文件2.1 launch文件标签之launch2.2 launch文件标签之node2.3 launch文件标签之include2.4 launch文件标签之remap2.5 launch文件标签之param2.6 launch文件标签之rosparam2.7 launch文件标签之gr…

2023年伊凡最新整理简单方法之为hbuilderx配置node环境实现可npm install

本文优雅草伊凡投稿一颗优雅草科技,欢迎其他朋友们来投稿(一定会详细署名),好直接开始,由于伊凡的电脑实在太卡了因此重装了一下系统所有环境全没了可能要一步步做环境了,后续可能会发关于flutter&#xff…