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 相关文章推荐
pyqt4教程之实现windows窗口小示例分享
Mar 07 Python
python实现批量修改文件名代码
Sep 10 Python
Python实现mysql数据库更新表数据接口的功能
Nov 19 Python
Python wxpython模块响应鼠标拖动事件操作示例
Aug 23 Python
使用WingPro 7 设置Python路径的方法
Jul 24 Python
PyQt5使用QTimer实现电子时钟
Jul 29 Python
详解Python中的正斜杠与反斜杠
Aug 09 Python
python获取依赖包和安装依赖包教程
Feb 13 Python
Python 找出出现次数超过数组长度一半的元素实例
May 11 Python
Python pip 常用命令汇总
Oct 19 Python
scrapy头部修改的方法详解
Dec 06 Python
Python数组变形的几种实现方法
May 30 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扩展vld查看PHP opcode操作步骤
2013/03/04 PHP
使用php判断网页是否gzip压缩
2013/06/25 PHP
ThinkPHP的L方法使用简介
2014/06/18 PHP
Swoole 5将移除自动添加Event::wait()特性详解
2019/07/10 PHP
laravel5.5安装jwt-auth 生成token令牌的示例
2019/10/24 PHP
tp5.1 框架数据库-数据集操作实例分析
2020/05/26 PHP
JScript中使用ADODB.Stream判断文件编码的代码
2008/06/09 Javascript
document.documentElement的一些使用技巧
2013/04/18 Javascript
Jquery遍历节点的方法小集
2014/01/22 Javascript
JS关闭窗口时产生的事件及用法示例
2016/08/20 Javascript
js中动态创建json,动态为json添加属性、属性值的实例
2016/12/02 Javascript
微信小程序 textarea 详解及简单使用方法
2016/12/05 Javascript
js按条件生成随机json:randomjson实现方法
2017/04/07 Javascript
基于vue实现swipe轮播组件实例代码
2017/05/24 Javascript
js+html制作简单日历的方法
2017/06/27 Javascript
get  post jsonp三种数据交互形式实例详解
2017/08/25 Javascript
基于vue和react的spa进行按需加载的实现方法
2018/09/29 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
2019/10/28 Javascript
Python3基础之函数用法
2014/08/13 Python
星球大战与Python之间的那些事
2016/01/07 Python
对python append 与浅拷贝的实例讲解
2018/05/04 Python
Python中shapefile转换geojson的示例
2019/01/03 Python
Python参数类型以及常见的坑详解
2019/07/08 Python
django 实现将本地图片存入数据库,并能显示在web上的示例
2019/08/07 Python
PIL包中Image模块的convert()函数的具体使用
2020/02/26 Python
OpenCV+Python3.5 简易手势识别的实现
2020/12/21 Python
Python3利用scapy局域网实现自动多线程arp扫描功能
2021/01/21 Python
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
罗兰·穆雷官网:Roland Mouret
2018/09/28 全球购物
建材投资建议书
2014/05/16 职场文书
全国文明单位申报材料
2014/05/31 职场文书
中学生综合素质自我评价
2015/03/06 职场文书
大学毕业论文致谢词
2015/05/14 职场文书
为自己工作观后感
2015/06/11 职场文书
解决MySQL添加新用户-ERROR 1045 (28000)的问题
2022/03/03 MySQL
nginx之queue的具体使用
2022/06/28 Servers