Keras—embedding嵌入层的用法详解


Posted in Python onJune 10, 2020

最近在工作中进行了NLP的内容,使用的还是Keras中embedding的词嵌入来做的。

Keras中embedding层做一下介绍。

中文文档地址:https://keras.io/zh/layers/embeddings/

参数如下:

Keras—embedding嵌入层的用法详解

其中参数重点有input_dim,output_dim,非必选参数input_length.

初始化方法参数设置后面会单独总结一下。

demo使用预训练(使用百度百科(word2vec)的语料库)参考

embedding使用的demo参考:

def create_embedding(word_index, num_words, word2vec_model):
 embedding_matrix = np.zeros((num_words, EMBEDDING_DIM))
 for word, i in word_index.items():
  try:
   embedding_vector = word2vec_model[word]
   embedding_matrix[i] = embedding_vector
  except:
   continue
 return embedding_matrix
 
#word_index:词典(统计词转换为索引)
#num_word:词典长度+1
#word2vec_model:词向量的model

加载词向量model的方法:

def pre_load_embedding_model(model_file):
 # model = gensim.models.Word2Vec.load(model_file)
 # model = gensim.models.Word2Vec.load(model_file,binary=True)
 model = gensim.models.KeyedVectors.load_word2vec_format(model_file)
 return model

model中Embedding层的设置(注意参数,Input层的输入,初始化方法):

embedding_matrix = create_embedding(word_index, num_words, word2vec_model)
 
 embedding_layer = Embedding(num_words,
        EMBEDDING_DIM,
        embeddings_initializer=Constant(embedding_matrix),
        input_length=MAX_SEQUENCE_LENGTH,
        trainable=False)
 sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
 embedded_sequences = embedding_layer(sequence_input)

embedding层的初始化设置

keras embeding设置初始值的两种方式

随机初始化Embedding

from keras.models import Sequential
from keras.layers import Embedding
import numpy as np
 
model = Sequential()
model.add(Embedding(1000, 64, input_length=10))
# the model will take as input an integer matrix of size (batch, input_length).
# the largest integer (i.e. word index) in the input should be no larger than 999 (vocabulary size).
# now model.output_shape == (None, 10, 64), where None is the batch dimension.
 
input_array = np.random.randint(1000, size=(32, 10))
 
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
print(output_array)
assert output_array.shape == (32, 10, 64)

使用weights参数指明embedding初始值

import numpy as np
import keras
 
m = keras.models.Sequential()
"""
可以通过weights参数指定初始的weights参数
因为Embedding层是不可导的 
梯度东流至此回,所以把embedding放在中间层是没有意义的,emebedding只能作为第一层
注意weights到embeddings的绑定过程很复杂,weights是一个列表
"""
embedding = keras.layers.Embedding(input_dim=3, output_dim=2, input_length=1, weights=[np.arange(3 * 2).reshape((3, 2))], mask_zero=True)
m.add(embedding) # 一旦add,就会自动调用embedding的build函数,
print(keras.backend.get_value(embedding.embeddings))
m.compile(keras.optimizers.RMSprop(), keras.losses.mse)
print(m.predict([1, 2, 2, 1, 2, 0]))
print(m.get_layer(index=0).get_weights())
print(keras.backend.get_value(embedding.embeddings))

给embedding设置初始值的第二种方式:使用initializer

import numpy as np
import keras
 
m = keras.models.Sequential()
"""
可以通过weights参数指定初始的weights参数
因为Embedding层是不可导的 
梯度东流至此回,所以把embedding放在中间层是没有意义的,emebedding只能作为第一层
给embedding设置权值的第二种方式,使用constant_initializer 
"""
embedding = keras.layers.Embedding(input_dim=3, output_dim=2, input_length=1, embeddings_initializer=keras.initializers.constant(np.arange(3 * 2, dtype=np.float32).reshape((3, 2))))
m.add(embedding)
print(keras.backend.get_value(embedding.embeddings))
m.compile(keras.optimizers.RMSprop(), keras.losses.mse)
print(m.predict([1, 2, 2, 1, 2]))
print(m.get_layer(index=0).get_weights())
print(keras.backend.get_value(embedding.embeddings))

关键的难点在于理清weights是怎么传入到embedding.embeddings张量里面去的。

Embedding是一个层,继承自Layer,Layer有weights参数,weights参数是一个list,里面的元素都是numpy数组。在调用Layer的构造函数的时候,weights参数就被存储到了_initial_weights变量

basic_layer.py 之Layer类

if 'weights' in kwargs:
   self._initial_weights = kwargs['weights']
  else:
   self._initial_weights = None

当把Embedding层添加到模型中、跟模型的上一层进行拼接的时候,会调用layer(上一层)函数,此处layer是Embedding实例,Embedding是一个继承了Layer的类,Embedding类没有重写__call__()方法,Layer实现了__call__()方法。

父类Layer的__call__方法调用子类的call()方法来获取结果。

所以最终调用的是Layer.__call__()。在这个方法中,会自动检测该层是否build过(根据self.built布尔变量)。

Layer.__call__函数非常重要。

def __call__(self, inputs, **kwargs):
  """Wrapper around self.call(), for handling internal references.
  If a Keras tensor is passed:
   - We call self._add_inbound_node().
   - If necessary, we `build` the layer to match
    the _keras_shape of the input(s).
   - We update the _keras_shape of every input tensor with
    its new shape (obtained via self.compute_output_shape).
    This is done as part of _add_inbound_node().
   - We update the _keras_history of the output tensor(s)
    with the current layer.
    This is done as part of _add_inbound_node().
  # Arguments
   inputs: Can be a tensor or list/tuple of tensors.
   **kwargs: Additional keyword arguments to be passed to `call()`.
  # Returns
   Output of the layer's `call` method.
  # Raises
   ValueError: in case the layer is missing shape information
    for its `build` call.
  """
  if isinstance(inputs, list):
   inputs = inputs[:]
  with K.name_scope(self.name):
   # Handle laying building (weight creating, input spec locking).
   if not self.built:#如果未曾build,那就要先执行build再调用call函数
    # Raise exceptions in case the input is not compatible
    # with the input_spec specified in the layer constructor.
    self.assert_input_compatibility(inputs)
 
    # Collect input shapes to build layer.
    input_shapes = []
    for x_elem in to_list(inputs):
     if hasattr(x_elem, '_keras_shape'):
      input_shapes.append(x_elem._keras_shape)
     elif hasattr(K, 'int_shape'):
      input_shapes.append(K.int_shape(x_elem))
     else:
      raise ValueError('You tried to call layer "' +
           self.name +
           '". This layer has no information'
           ' about its expected input shape, '
           'and thus cannot be built. '
           'You can build it manually via: '
           '`layer.build(batch_input_shape)`')
    self.build(unpack_singleton(input_shapes))
    self.built = True#这句话其实有些多余,因为self.build函数已经把built置为True了
 
    # Load weights that were specified at layer instantiation.
    if self._initial_weights is not None:#如果传入了weights,把weights参数赋值到每个变量,此处会覆盖上面的self.build函数中的赋值。
     self.set_weights(self._initial_weights)
 
   # Raise exceptions in case the input is not compatible
   # with the input_spec set at build time.
   self.assert_input_compatibility(inputs)
 
   # Handle mask propagation.
   previous_mask = _collect_previous_mask(inputs)
   user_kwargs = copy.copy(kwargs)
   if not is_all_none(previous_mask):
    # The previous layer generated a mask.
    if has_arg(self.call, 'mask'):
     if 'mask' not in kwargs:
      # If mask is explicitly passed to __call__,
      # we should override the default mask.
      kwargs['mask'] = previous_mask
   # Handle automatic shape inference (only useful for Theano).
   input_shape = _collect_input_shape(inputs)
 
   # Actually call the layer,
   # collecting output(s), mask(s), and shape(s).
   output = self.call(inputs, **kwargs)
   output_mask = self.compute_mask(inputs, previous_mask)
 
   # If the layer returns tensors from its inputs, unmodified,
   # we copy them to avoid loss of tensor metadata.
   output_ls = to_list(output)
   inputs_ls = to_list(inputs)
   output_ls_copy = []
   for x in output_ls:
    if x in inputs_ls:
     x = K.identity(x)
    output_ls_copy.append(x)
   output = unpack_singleton(output_ls_copy)
 
   # Inferring the output shape is only relevant for Theano.
   if all([s is not None
     for s in to_list(input_shape)]):
    output_shape = self.compute_output_shape(input_shape)
   else:
    if isinstance(input_shape, list):
     output_shape = [None for _ in input_shape]
    else:
     output_shape = None
 
   if (not isinstance(output_mask, (list, tuple)) and
     len(output_ls) > 1):
    # Augment the mask to match the length of the output.
    output_mask = [output_mask] * len(output_ls)
 
   # Add an inbound node to the layer, so that it keeps track
   # of the call and of all new variables created during the call.
   # This also updates the layer history of the output tensor(s).
   # If the input tensor(s) had not previous Keras history,
   # this does nothing.
   self._add_inbound_node(input_tensors=inputs,
         output_tensors=output,
         input_masks=previous_mask,
         output_masks=output_mask,
         input_shapes=input_shape,
         output_shapes=output_shape,
         arguments=user_kwargs)
 
   # Apply activity regularizer if any:
   if (hasattr(self, 'activity_regularizer') and
     self.activity_regularizer is not None):
    with K.name_scope('activity_regularizer'):
     regularization_losses = [
      self.activity_regularizer(x)
      for x in to_list(output)]
    self.add_loss(regularization_losses,
        inputs=to_list(inputs))
  return output

如果没有build过,会自动调用Embedding类的build()函数。Embedding.build()这个函数并不会去管weights,如果它使用的initializer没有传入,self.embeddings_initializer会变成随机初始化。

如果传入了,那么在这一步就能够把weights初始化好。

如果同时传入embeddings_initializer和weights参数,那么weights参数稍后会把Embedding#embeddings覆盖掉。

embedding.py Embedding类的build函数

def build(self, input_shape):
  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,
   dtype=self.dtype)
  self.built = True

综上,在keras中,使用weights给Layer的变量赋值是一个比较通用的方法,但是不够直观。keras鼓励多多使用明确的initializer,而尽量不要触碰weights。

以上这篇Keras—embedding嵌入层的用法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用实例详解Python中的Django框架中prefetch_related()函数对数据库查询的优化
Apr 01 Python
python内存管理分析
Apr 08 Python
Python教程之全局变量用法
Jun 27 Python
浅析Python中return和finally共同挖的坑
Aug 18 Python
Python分析学校四六级过关情况
Nov 22 Python
python机器学习实战之最近邻kNN分类器
Dec 20 Python
微信跳一跳python代码实现
Jan 05 Python
Python使用requests提交HTTP表单的方法
Dec 26 Python
python ipset管理 增删白名单的方法
Jan 14 Python
Python面向对象程序设计多继承和多态用法示例
Apr 08 Python
浅谈Python3中strip()、lstrip()、rstrip()用法详解
Apr 29 Python
pip指定python位置安装软件包的方法
Jul 12 Python
Keras框架中的epoch、bacth、batch size、iteration使用介绍
Jun 10 #Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
Jun 10 #Python
JAVA及PYTHON质数计算代码对比解析
Jun 10 #Python
keras 使用Lambda 快速新建层 添加多个参数操作
Jun 10 #Python
matplotlib 生成的图像中无法显示中文字符的解决方法
Jun 10 #Python
Tensorflow中k.gradients()和tf.stop_gradient()用法说明
Jun 10 #Python
PySide2出现“ImportError: DLL load failed: 找不到指定的模块”的问题及解决方法
Jun 10 #Python
You might like
php基础知识:类与对象(2) 自动加载对象
2006/12/13 PHP
带密匙的php加密解密示例分享
2014/01/29 PHP
ThinkPHP上使用多说评论插件的方法
2014/10/31 PHP
Yii2框架实现数据库常用操作总结
2017/02/08 PHP
PHP接口类(interface)的定义、特点和应用示例
2020/05/18 PHP
Thinkphp极验滑动验证码实现步骤解析
2020/11/24 PHP
javascript HTMLEncode HTMLDecode的完整实例(兼容ie和火狐)
2009/06/02 Javascript
jquery插件之easing 动态菜单
2010/08/21 Javascript
ModelDialog JavaScript模态对话框类代码
2011/04/17 Javascript
用JS实现3D球状标签云示例代码
2013/12/01 Javascript
Javascript实现带关闭按钮的网页漂浮广告代码
2014/01/12 Javascript
js获取指定的cookie的具体实现
2014/02/20 Javascript
归纳下js面向对象的几种常见写法总结
2016/08/24 Javascript
浅谈JS使用[ ]来访问对象属性
2016/09/21 Javascript
Ionic学习日记实现验证码倒计时
2018/02/08 Javascript
详解用场景去理解函数柯里化(入门篇)
2019/04/11 Javascript
微信小程序实现授权登录
2019/05/15 Javascript
VUE单页面切换动画代码(全网最好的切换效果)
2019/10/31 Javascript
node.js express捕获全局异常的三种方法实例分析
2019/12/27 Javascript
JavaScript之scrollTop、scrollHeight、offsetTop、offsetHeight等属性学习笔记
2020/07/15 Javascript
Vue使用CDN引用项目组件,减少项目体积的步骤
2020/10/30 Javascript
浅析Python中的join()方法的使用
2015/05/19 Python
python和bash统计CPU利用率的方法
2015/07/10 Python
python生成二维码的实例详解
2017/10/29 Python
Pycharm代码无法复制,无法选中删除,无法编辑的解决方法
2018/10/22 Python
Python中一般处理中文的几种方法
2019/03/06 Python
Python flask框架实现查询数据库并显示数据
2020/06/04 Python
python实现scrapy爬虫每天定时抓取数据的示例代码
2021/01/27 Python
函授毕业自我鉴定
2014/02/04 职场文书
经典婚礼主持词
2014/03/13 职场文书
学习演讲稿范文
2014/05/10 职场文书
小学教师年度个人总结
2015/02/05 职场文书
运动会运动员赞词
2015/07/22 职场文书
小学班主任教育随笔
2015/08/15 职场文书
2016年大学生暑期社会实践方案
2015/11/26 职场文书
学习党章心得体会2016
2016/01/15 职场文书