【问题标题】:Implementing custom layer in Keras (RStudio Interface)在 Keras 中实现自定义层(RStudio 界面)
【发布时间】:2018-08-01 12:52:08
【问题描述】:

我在使用 R 的 Keras 接口在词嵌入模型中实现自定义层时遇到了一些麻烦。下面是我的代码的玩具版本,它将重现错误:

rm(list = ls())
library(keras)
library(tensorflow)

# ================================
# inputs
# ================================

input_target <- layer_input(shape = 1)
input_context <- layer_input(shape = 1)

# embedding matrix for mean vectors
embedding_mu <- layer_embedding(
  input_dim = 1000, 
  output_dim = 50, 
  embeddings_initializer = initializer_random_uniform(),
  input_length = 1, 
  name = "embedding_mu"
)

# embedding matrix for sigma vectors
embedding_sigma <- layer_embedding(
  input_dim = 1000, 
  output_dim = 50, 
  embeddings_initializer = initializer_random_uniform(),
  input_length = 1, 
  name = "embedding_sigma"
)

# select target mu from the mu embedding matrix
target_vector_mu <- input_target %>%
  embedding_mu() %>% 
  layer_flatten()

# select context mu from the mu embedding matrix
context_vector_mu <- input_context %>%
  embedding_mu() %>%
  layer_flatten()

# select target sigma from the sigma embedding matrix
target_vector_sigma <- input_target %>%
  embedding_sigma() %>% 
  layer_flatten()

# select context sigma from the sigma embedding matrix
context_vector_sigma <- input_context %>%
  embedding_sigma() %>%
  layer_flatten()

# ================================
# custom layer
# ================================
KLenergy <- function(args){ # args <- list(mu_w, mu_c, sigma_w, sigma_c)
  comp1 <- tf$reduce_sum(tf$div(args[[4]], args[[3]]), axis = integer(1))
  comp2 <- tf$reduce_sum(tf$div(tf$square(tf$subtract(args[[1]], args[[2]])), args[[3]]), axis = integer(1))
  comp3 <- tf$subtract(tf$log(tf$reduce_prod(args[[4]], axis = integer(1))), tf$log(tf$reduce_prod(args[[3]], axis = integer(1))))
  energy <- 0.5*(comp1 + comp2 - comp3)
  return(energy)
}

kl_energy <- layer_lambda(list(target_vector_mu, 
                                 context_vector_mu, 
                                 target_vector_sigma, 
                                 context_vector_sigma),
                            KLenergy)


output <- layer_dense(kl_energy, units = 1, activation = "relu")

# ================================
# model compile
# ================================
model <- keras_model(list(input_target, input_context), output)
model %>% compile(
  loss = "binary_crossentropy", 
  optimizer = "Adagrad")

summary(model)

执行“输出”层后出现如下错误:

Error in py_call_impl(callable, dots$args, dots$keywords) : 
ValueError: Input 0 is incompatible with layer dense_2: expected min_ndim=2, found ndim=1

Detailed traceback: 
  File "/anaconda3/envs/r-tensorflow/lib/python3.6/site-packages/keras/engine/base_layer.py", line 414, in __call__
self.assert_input_compatibility(inputs)
  File "/anaconda3/envs/r-tensorflow/lib/python3.6/site-packages/keras/engine/base_layer.py", line 327, in assert_input_compatibility
str(K.ndim(x)))

我希望 kl_energy 层具有形状 (None, 1) 但我得到的是 (None,)。

kl_energy
Tensor("lambda_5/Mul:0", shape=(?,), dtype=float32)

我在定义自定义层时是否缺少参数?我尝试设置“keepdims = TRUE”:

KLenergy <- function(args){ # args <- list(mu_w, mu_c, sigma_w, sigma_c)
  comp1 <- tf$reduce_sum(tf$div(args[[4]], args[[3]]), axis = as.integer(1), keepdims = TRUE)
  comp2 <- tf$reduce_sum(tf$div(tf$square(tf$subtract(args[[1]], args[[2]])), args[[3]]), axis = as.integer(1), keepdims = TRUE)
  comp3 <- tf$subtract(tf$log(tf$reduce_prod(args[[4]], axis = as.integer(1), keepdims = TRUE)), tf$log(tf$reduce_prod(args[[3]], axis = as.integer(1), keepdims = TRUE)))
  energy <- 0.5*(comp1 + comp2 - comp3)
  return(energy)
}

但这给了我一个形状为 (1, None) 的 kl_energy 层,这不是我想要的。最终,该层的输出应与原始 word2vec 模型(使用 layer_dot - see here)中的形状相同,但使用此自定义层:

kl_energy
Tensor("lambda_7/Mul:0", shape=(1, ?), dtype=float32)

任何指导将不胜感激。

工作代码(以下归功于 Daniel):

# ================================
# inputs
# ================================

input_target <- layer_input(shape = 1)
input_context <- layer_input(shape = 1)

# embedding matrix for mean vectors
embedding_mu <- layer_embedding(
  input_dim = 1000, 
  output_dim = 50, 
  embeddings_initializer = initializer_random_uniform(),
  input_length = 1, 
  name = "embedding_mu"
)

# embedding matrix for sigma vectors
embedding_sigma <- layer_embedding(
  input_dim = 1000, 
  output_dim = 50, 
  embeddings_initializer = initializer_random_uniform(),
  input_length = 1, 
  name = "embedding_sigma"
)

# select target mu from the mu embedding matrix
target_vector_mu <- input_target %>%
  embedding_mu() %>% 
  layer_flatten()

# select context mu from the mu embedding matrix
context_vector_mu <- input_context %>%
  embedding_mu() %>%
  layer_flatten()

# select target sigma from the sigma embedding matrix
target_vector_sigma <- input_target %>%
  embedding_sigma() %>% 
  layer_flatten()

# select context sigma from the sigma embedding matrix
context_vector_sigma <- input_context %>%
  embedding_sigma() %>%
  layer_flatten()

# ================================
# custom layer
# ================================
KLenergy <- function(args){ # args <- list(mu_w, mu_c, sigma_w, sigma_c)
  comp1 <- tf$reduce_sum(tf$div(args[[4]], args[[3]]), axis = as.integer(1), keepdims = TRUE)
  comp2 <- tf$reduce_sum(tf$div(tf$square(tf$subtract(args[[1]], args[[2]])), args[[3]]), axis = as.integer(1), keepdims = TRUE)
  comp3 <- tf$subtract(tf$log(tf$reduce_prod(args[[4]], axis = as.integer(1), keepdims = TRUE)), tf$log(tf$reduce_prod(args[[3]], axis = as.integer(1), keepdims = TRUE)))
  energy <- 0.5*(comp1 + comp2 - comp3)
  return(energy)
}

kl_energy <- layer_lambda(list(target_vector_mu, 
                               context_vector_mu, 
                               target_vector_sigma, 
                               context_vector_sigma),
                          KLenergy)


output <- layer_dense(kl_energy, units = 1, activation = "relu")

# ================================
# model compile
# ================================
model <- keras_model(list(input_target, input_context), output)
model %>% compile(
   loss = "binary_crossentropy", 
  optimizer = "Adagrad")

summary(model)

【问题讨论】:

  • integer(1) 有什么特别之处吗?你能试试axis=1吗? --- 那么,R 中的轴是按 first = 0 还是 first = 1 计算的?根据您的代码,似乎 1 是第一个轴?如果尝试axis=2或axis=integer(2)会不会报错?
  • 不指定整数,你会得到一个类型错误(这是特定于通过 RStudio 使用 Keras)。它将“axis = 1”中的 1 读取为浮点数,但它需要整数。至于使用“axis = integer(2)”,我仍然得到一个 kl_energy 层,shape = (None, )。
  • 真的吗?但是integer(1) 不是在创建一个带零的向量吗? rdocumentation.org/packages/base/versions/3.5.0/topics/integer
  • 您在其他任何地方都只使用数字,为什么只是在那个地方出现错误?如果这需要一个数组,那么您应该创建一个包含 1 的数组。
  • 你完全正确,愚蠢的错误,应该是 as.integer(1)。我仍然得到同样的错误(即形状仍然是 (None,) 并且执行输出给出了相同的错误消息。

标签: r tensorflow keras


【解决方案1】:

不要忘记使用keepdims=TRUE 来返回(None,1)。

如前所述,您应该在 R 表示法中使用 as.integer(1) 或 1L。

【讨论】:

  • 就是这样!感谢您抓住丹尼尔,只是需要一双额外的眼睛。
  • 注意as.integer(1)可以写成1L
猜你喜欢
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 2011-06-25
  • 2016-10-06
  • 1970-01-01
相关资源
最近更新 更多