【需求实现】Tensorflow2的曲线拟合(三):Embedding层

news2024/11/23 20:49:01

文章目录

  • 导读
  • Embedding的维度问题
  • Embedding的输入输出
  • 比较容易踩的坑
    • input_shape与input_length的对应关系
    • built属性

导读

这是填曲线拟合第一篇的坑,有关Embedding层的问题。

Embedding的维度问题

首先是上次我们提到的Embedding层,他确实能够做到将数据一一对应着输出的功能。但是实际上,在曲线拟合中还是存在一个严重的问题:降维问题。

在自然语言中,Embedding层的目的就是为了把高维的、稀疏的矩阵,变为低维的、稠密的矩阵。

Embedding Layer可以被认为是one-hot编码和降维的替代方法。

——摘自Understanding Embedding Layer in Keras

这也就意味着Embedding能够在我们拟合的过程中将已经整成维度为 ( TRAIN _ SIZE , COL _ SIZE , ROW _ SIZE ) (\text{TRAIN}\_\text{SIZE}, \text{COL}\_\text{SIZE}, \text{ROW}\_\text{SIZE}) (TRAIN_SIZE,COL_SIZE,ROW_SIZE)的数据集,直接降低一个维度,从而直接导致在训练的过程中丢失一个维度,进而造成曲线峰值不会变化的bug。

只是我们所使用的案例刚好采用的是峰值不会变化的三角函数曲线,如果产生这个bug大概就是这种样子:

在这里插入图片描述

可以看到无论测试集长什么花样,预测值都是不会变动的。这就完全不正确了。

Embedding的输入输出

我们不妨再看看官方GitHub中会不会有什么提示。

P.S.:GitHub这里有个比较方便的就是,在最末尾加上【#L382-L890】,就会把这个代码文件中第 382 382 382行到第 890 890 890行中间的所有代码高亮显示。这个链接点进去就是LSTM整个类给高亮显示的链接。

我们先按照官方教程构建一个简单的Embedding Layer

import tensorflow as tf
model = tf.keras.Sequential([
  tf.keras.layers.Embedding(input_dim = 1000, output_dim = 64, input_length = 10)
])
model.summary()

这个Embedding Layer给了一个input_dim作为输入维度,output_dim作为输出维度,input_length作为输出长度,这也就为输入的数据基本确定了一个样本。

其中,input_dim本身实际上是一个限制,也就是说输入最多不能超过 999 999 999,如果是自然语言的话那就是句子长度最高不能超过 999 999 999个字词。

在官方GitHub源码中也有这方面的逻辑:

if "input_shape" not in kwargs:
    if input_length:
        kwargs["input_shape"] = (input_length,)
    else:
        kwargs["input_shape"] = (None,)

也就是说,当input_shape没有指定的时候,就默认按照input_length创建input_shape。如果连input_length也没有的话,那就是规定这一个维度没东西。举个例子,我们所构建的这个网络将形成输入为 ( 10 , ) (10,) (10,)的数据。同时由于转型为Tensor的过程中又会再增加一个维度,也就构成了 ( None , 10 , ) (\text{None},10,) (None,10,)的输入。 None \text{None} None batch _ size \text{batch}\_\text{size} batch_size的一种取值,取 None \text{None} None表示每次开始使用之前可以根据当前数据量自定义,但每次开始使用之后必须一直使用到测试结束都不能有变化。

同样的,输入变成了 ( None , 10 , ) (\text{None},10,) (None,10,),那么输出也就是在后面再加上一个output_dim,也就是 ( None , 10 , 64 ) (\text{None},10,64) (None,10,64)

于是,我们尝试一下:

import numpy as np
input_array = np.random.randint(1000, size=(32, 10))
model.compile(optimizer = 'rmsprop', loss = 'mse')
output_array = model.predict(input_array)

首先,我们使用numpyrandom库随机生成一组数据,这组数据是 0 ∼ 1000 0\sim1000 01000之间的随机数,一共有 32 32 32行、 10 10 10列。

然后确定模型的优化器与需要优化的损失函数,这里选取均方差mean squard error作为损失函数,也就是我们所熟悉的MSE

l ( x ) = ∑ i = 1 N ( x i − x ˉ ) 2 N l(x)=\frac{\sum_{i=1}^N(x_i-\bar{x})^2}{N} l(x)=Ni=1N(xixˉ)2

优化器则是RMSprop,特点就是类似强化学习中DDPG里的软更新一样,是从一个随机起始位置逐步逼近目标,然后每次更新都只接收更新的一部分,而不是彻底覆盖。也就是

θ ′ = τ θ + ( 1 − τ ) θ ′ \theta'=\tau\theta+(1-\tau)\theta' θ=τθ+(1τ)θ

从而使得 f ( x ) f(x) f(x)能够产生下列变化

f 0 ( x ) = g 0 ( x ) f 1 ( x ) = g 0 ( x ) + g 1 ( x ) f 2 ( x ) = g 0 ( x ) + g 1 ( x ) + g 2 ( x ) … \begin{matrix}f_0(x)&=&g_0(x)\\f_1(x)&=&g_0(x)&+&g_1(x)\\f_2(x)&=&g_0(x)&+&g_1(x)&+&g_2(x)\\\ldots\end{matrix} f0(x)f1(x)f2(x)===g0(x)g0(x)g0(x)++g1(x)g1(x)+g2(x)

最终,我们的output_array最终输出的shape也是 ( 32 , 10 , 64 ) (32,10,64) (32,10,64)

所以,对于Embedding层,输入设置了input_length,输入数据的时候只需要保证第 2 2 2个维度为input_length,最终输出的时候就会输出 ( batch _ size , input _ length , output _ dim ) (\text{batch}\_\text{size},\text{input}\_\text{length},\text{output}\_\text{dim}) (batch_size,input_length,output_dim)

在官方GitHub源码中当然也有这个逻辑:

@tf_utils.shape_type_conversion
def compute_output_shape(self, input_shape):
    if self.input_length is None:
        return input_shape + (self.output_dim,)
    else:
        # input_length can be tuple if input is 3D or higher
        if isinstance(self.input_length, (list, tuple)):
            in_lens = list(self.input_length)
        else:
            in_lens = [self.input_length]
        if len(in_lens) != len(input_shape) - 1:
            raise ValueError(
                f'"input_length" is {self.input_length}, but received '
                f"input has shape {input_shape}"
            )
        else:
            for i, (s1, s2) in enumerate(zip(in_lens, input_shape[1:])):
                if s1 is not None and s2 is not None and s1 != s2:
                    raise ValueError(
                        f'"input_length" is {self.input_length}, but '
                        f"received input has shape {input_shape}"
                    )
                elif s1 is None:
                    in_lens[i] = s2
        return (input_shape[0],) + tuple(in_lens) + (self.output_dim,)

这段代码包含以下几个关键分支:

  • input_length不存在的时候,就把output_dim拼在input_shape后面,形成一个三元组
  • input_length存在的时候,需要保证input_length是比input_shape少一个维度,从而保证自定义的input_shapeinput_length能够有可能存在对应关系。
  • 然后在input_shape中,需要检查input_lengthinput_shape中除开第一个元素以外的元素是否存在对应关系,如果对应不上,那就需要返回去重新检查;如果input_length为空,那么就是按照input_shape去完善input_length
  • 最后就是元组拼接,首先是input_shape的第一个元素,也就是刚刚所说的 None \text{None} None或者指定的 batch _ size \text{batch}\_\text{size} batch_size,再就是input_length,最后是output_dim,最终输出也就是 ( None , 10 , 64 ) (\text{None},10,64) (None,10,64)。而如果我们不管这个 None \text{None} None,就只在最后输入数据的时候给入一个确定维度的数据,这个时候神经网络也会自己进行适配。

比较容易踩的坑

input_shape与input_length的对应关系

而如果我指定input_shape呢?这个时候如果没有阅读源码的话反而很容易乱掉。

一般情况下,在构建Tensor的时候,往往需要三维数据,这个时候极大可能就会采用三维数据作为输入:input_shape=(None,10,64)

这个时候就会因为上面的一系列操作,最终输出 ( None , None , None , 10 , 64 ) (\text{None},\text{None},\text{None},10,64) (None,None,None,10,64)

反而不如不指定input_shape了。

built属性

在官方GitHub源码中有这么一段:

@tf_utils.shape_type_conversion
def build(self, input_shape=None):
    self.embeddings = self.add_weight(
        shape=(self.input_dim, self.output_dim),
        initializer=self.embeddings_initializer,
        name="embeddings",
        regularizer=self.embeddings_regularizer,
        constraint=self.embeddings_constraint,
        experimental_autocast=False,
    )
    self.built = True

最后一句话有个self.built = True,也就是说调用这个,整个模型就是【已构建】的状态,不需要再显式调用Sequentialbuild方法保证模型的构建完成。
当然,并不是所有的layer都有这个属性。目前已知的就包括LSTMGRU等模型,都是不会自动调用build方法,而是需要自行显式调用。

显式调用的目的也很明确,就是为了给网络一个相当确切的输入。因为包括LSTMGRU等模型的参数只有一个最关键的units,而不包含input_lengthinput_shape等属性,所以需要额外使用build方法显式声明:

import tensorflow as tf
HIDDEN_OUTPUT = int(SEQUE_SIZE / 10) + 1
model = tf.keras.models.Sequential([
    tf.keras.layers.LSTM(units = 10, activation = 'relu'),
])
model.compile(optimizer = 'adam', loss = tf.keras.losses.mean_squared_error)
model.build(input_shape = (1000, 64))
model.summary()

其中,build方法中所包含的input_shape属性需要使用 ( input _ dim , output _ dim ) (\text{input}\_\text{dim}, \text{output}\_\text{dim}) (input_dim,output_dim)输入。

同样的,input_dim并不重要。这里不是说输入的维度不重要,而是input_shape本身第一个值就是不重要,可以用 None \text{None} None代替,也就是input_shape = (None, 64)

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

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

相关文章

预约Oracle OCP认证考试的保姆式流程

Oracle OCP认证考试的预约流程涉及到Oracle的SLS培训记录,因此相当复杂。本文进行了详细地说明,每一步都有截图,有需要的同学建议收藏。 关于号主,姚远 Oracle ACE(Oracle和MySQL数据库方向)。Oracle MAA…

智能体重秤方案PCBA方案设计

智能体重秤是一款高精度、便捷、多功能的健康管理工具,旨在帮助用户监测和控制体重,达到健康管理与减肥的目的。该产品融合了先进的科技技术,结合了人体工程学设计,具有美观、易用的特点。以下将从结构、参数、原理和应用方面为大…

电涌(浪涌)保护器防雷保护级别

浪涌保护器实际就是压敏电阻,具有高通低阻的特性。当电网在不超过最大持续运行电压的情况下运行时,两个电极之间呈高阻状态。由于雷击的能量是非常巨大的,需要通过分级泄放的方法,将雷击能量逐步泄放到大地。 第一级防雷器可以对…

mmyolo框架实现在VOC数据集上复现Yolov6教程(详细)

写在开头,最近学习mmyolo的框架,想着它能将所有配置都写在一个config文件里,只需要改配置文件就可以改动模型,感觉挺方便的。 就想着Yolov6用mmyolo框架来实现,但mmyolo并没有提供v6的voc实现配置,v5是有的(看下图)&am…

软件测试技能,JMeter压力测试教程,取样器之测试活动(十八)

目录 前言 一、测试活动(Test Action) 二、Pause 设置暂停 三、Stop 停止 四、循环设置 五、跨线程组使用 前言 如果想在请求之后加等待时间如何做呢? 如果希望在 sampler 执行完之后再等待,则可使用取样器里面的测试活动 (Test Action) 一、测…

10个Salesforce集成项目最佳实践,助力成为专家!

随着企业越来越关注数据驱动的决策方法,集成多个系统成为了Salesforce 实施不可或缺的一部分。无论该项目是Salesforce的传统CRM迁移还是新的CRM实施,Salesforce CRM与ERP以及其他业务关键系统的集成都是需要考虑的重要策略。 集成项目的成功很大程度上…

Vue-pdf踩坑记录

最近在公司的一个项目中,需要在线预览PDF文件。基于vue-admin-electron的模板中开发。开发机系统为Windows,使用的框架为electron-vue。 坑1:在通过vue-router路由到含有vue-pdf组件的页面时报:“syntaxError: Unexpected token …

《移动互联网技术》 第十章 系统与通信: 掌握Android系统的分层架构设计思想和基于组件的设计模式

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

玩转代码|三个惊艳的黑科技代码,每一行代码都有惊讶的效果

目录 显示忘记密码 解除网页限制 去除视频logo 今日优质代码推荐 实现效果 实现过程 1. 简单的 Html 和 CSS 2. 创建 canvas画布 3. 获取鼠标点击位置 4. 实现鼠标点击产生烟花的初级形态 5. 实现烟花散开 6. 实现拖尾效果以及随机颜色 7. 实现烟花重力下坠 8. 实…

深度学习模型训练的全流程

目标是使用Pytorch来完成CNN的训练和验证过程,CNN网络结构。需要完成的逻辑结构如下: 构造训练集和验证集; 每轮进行训练和验证,并根据最优验证集精度保存模型。 # 将自定义的Dataset封装成一个Batch Size大小的Tensor&#xf…

threejs后期处理

个人博客地址: https://cxx001.gitee.io 1. 如何使用Threejs的后期处理 后期处理就是在场景渲染完后,最后对场景显示效果调整的手段。 使用后期处理步骤: (1)创建THREE.EffectComposer对象。(效果组合器) (2&#x…

指定某个时间,计算和当前时间间隔几天几时几分

dateDiff(startTime,endTime) {let t1 new Date(startTime).getTime()*1000; //开始时间 2023-06-29 10:00:00let t2 new Date(endTime).getTime()*1000; //结束时间 1688090400000000 2023-06-30 10:00:00 1688092230000000 2023-06-30 10:30:30let dateTime 1000 *…

小程序反编译

第一步:下载软件 根据把博客下载好三个软件 夜神模拟器 RE文件管理器 Node.js 第二步:打开模拟器中的 “微信” 第三步:点击要下载的小程序 并 记录当时的时间 方便一会查找pkg文件 第四步:打开文件资源管理器 第五步&#xff1a…

PyTorch的ONNX结合MNIST手写数字数据集的应用(.pth和.onnx的转换与onnx运行时)

在PyTorch以前的模型都是.pth格式,后面Meta跟微软一起做了一个.onnx的通用格式。这里对这两种格式文件,分别做一个介绍,依然使用MNIST数据集来做示例 1、CUDA下的pth文件 那pth文件里面是什么结构呢?其实在以前的文章就有介绍过…

0基础学习VR全景平台篇 第50篇:高级功能-自定义右键

本期为大家带来蛙色VR平台,高级功能—自定义右键功能操作。 功能位置示意 一、本功能将用在哪里? 自定义右键功能,观看者可通过电脑端右键和手机端长按屏幕,出现作者配置的自定义内容,使VR全景玩法变得多样化。 二、…

欧科云链2023年报:毛利达1.55亿港元,数字资产业务成最大增长点

据香港商报报道,2023年6月28日,欧科云链控股有限公司(以下简称“欧科云链”)及其附属公司(股份代号:1499.HK,以下简称“集团”)发布了截至2023年3月31日的年度报告。报告期内&#x…

工业读码器的选择和使用注意事项有哪些?

工业读码器是一种能够读取条形码、二维码等信息的设备,广泛应用于物流、生产制造、零售等行业。如何选择和使用工业读码器呢?下面是一些注意事项。 选择工业读码器 要根据应用场景选择合适的读码器类型,如手持式、固定式、手动旋转式等。 要考虑读取码的…

【C++】详解多态

目录 一、多态的概念二、多态的定义及实现1、多态的构成条件2、虚函数3、虚函数的重写1、虚函数重写的两个例外 4、C11 override 和 final5、重载、覆盖(重写)、隐藏(重定义)的对比 三、抽象类1、概念2、接口继承和实现继承 四、多态的原理1、虚函数表2、多态的原理3、动态绑定…

Mysql架构篇--Mysql(M-S) 主从同步

文章目录 前言:一、主从同步是什么?二、主从同步实现:1.准备工作:2.开启主从复制:2.1 mysql 服务端配置文件修改:2.2 mysql master 节点用户创建:2.3 mysql slave 节点开启数据复制:…