Написание пользовательского слоя (пул 3D RoI) с использованием Keras в R - PullRequest
0 голосов
/ 17 июня 2020

Используя R, я хотел бы создать настраиваемый слой Keras, который выполняет объединение 3D областей интереса (RoI) Pooling. Моя функция 3D RoI Pooling работает, как ожидалось, за пределами KerasLayer R6Class, но у меня возникают проблемы с ее интеграцией в пользовательский слой. Я не уверен, правильно ли я использую автограф в приведенном ниже примере. Меня впечатляет, что для использования функций R (например, для l oop) в разделе «call» настраиваемого слоя мне необходимо обернуть функцию автографом.

Ниже пользовательский слой для применения 3D RoI Pooling (без обучающих весов), соответствующий синтекс для пользователя Keras R?

Входные данные для слоя 3d_RoI_Pool включают:

(i) выходной слой из VNet модель,

  • shape = (None, 16, 16, 40, 1)

(ii) тензор, определяющий «индекс» для обрезки входного слоя до экстент каждого RoI,

  - tf.Variable 'Variable:0' shape=(1, 1, 6) dtype=float64, numpy=array([[[ 5.,  5.,  4.,  5., 10., 20.]]])

(iii) выходное измерение для объединенных 3D RoI.

  • В данном случае это c (1, 1, 5, 5, 5, 1) для c (Batch_Size, RoI_Size, X, Y, Z, Channels)

Ниже приведены некоторые вопросы, которые мне неясны:

  • Сначала я применяю layer_cropping_3d для обрезки каждого RoI, но не уверен, разрешено ли настраиваемому слою использовать доступные слои R Keras ? По этой причине в коде я выполнил собственное кадрирование.

  • Правильно ли использовать автограф в настраиваемом слое?

  • Должен ли я вместо этого использовать layer_lambda () для такой функции (т.е. обертывать произвольное выражение как слой), учитывая, что у меня нет обучаемых весов в слое 3D_RoI_Pooling?

Ниже приведен код, выходной слой из V- Net CNN и подготавливает входные данные для настраиваемого слоя:

  # FINAL LAYERS OF V_Net
  Output_shortcut = up1_DeConv
  Final_Conv <- up1_Concat %>%
    # 1st
    layer_conv_3d(filters = Filter_Start, kernel_size = Kernel_Conv_Size, padding = "same", name = "Final_Conv") %>%
    layer_batch_normalization() %>%
    layer_activation("relu")

  Final_Conv <- layer_add(c(Final_Conv, Output_shortcut), name = "Final_Conv_ResNet")

  # PREPARE INPUT FOR CUSTOM LAYER
  n_RoI <- 1 
  Batch_Size <- 1 

  Table_RoI <- list(list(c(5, 5), c(4, 5), c(10, 20)))
  Table_RoI <- array_reshape(unlist(Table_RoI), c(Batch_Size,n_RoI,6), order="F")
  Table_RoI <- tf$Variable(Table_RoI, tf$int16)

  output_dim <- c(Batch_Size, n_RoI, 5,5,5, as.numeric(dim(Final_Conv)[5]))

  # FEED CUSTOM LAYER TO CNN
  Final_Conv2 <- Final_Conv %>% layer_3D_ROI_pooled(Table_RoI=Table_RoI, output_dim= output_dim)

Ниже приведен фактический настраиваемый слой 3D RoI Pooling, который генерирует ошибку:

# 3D ROIpooled_Layer (R KERAS )
ROIpooled_Layer <- R6::R6Class("KerasLayer",
                                inherit = KerasLayer,
                                public = list(
                                  Table_RoI = NULL,
                                  output_dim = NULL, 

                                  ###############
                                  # INITIALISE
                                  ###############

                                  initialize = function(Table_RoI, output_dim) {
                                    self$Table_RoI = Table_RoI
                                    self$output_dim = output_dim
                                    },

                                  ###############
                                  # CALL FUNCTION   ROIpooled_Function <-
                                  ###############
                                  call = autograph(function(x, mask = NULL,
                                                            Table_RoI,
                                                            output_dim) {

                                    ## Input_L ROI_Table 
                                    n_Batch <- output_dim[1]
                                    n_RoI <- output_dim[2]
                                    Channels <- output_dim[6]

                                    for(r in 1:n_RoI){


                                        # layer_cropping_3d(Input_L, cropping = list(list(as.numeric(Table_RoI[,r,1]), as.numeric(Table_RoI[,r,2])), 
                                        #                                                               list(as.numeric(Table_RoI[,r,3]), as.numeric(Table_RoI[,r,4])), 
                                        #                                                               list(as.numeric(Table_RoI[,r,5]), as.numeric(Table_RoI[,r,6]))))

                                      RoI_Cropped <-x[,(as.numeric(Table_RoI[,r,1])+1):(dim(feature_map_T)[2]-as.numeric(Table_RoI[,r,2])),
                                                                  (as.numeric(Table_RoI[,r,3])+1):(dim(feature_map_T)[3]-as.numeric(Table_RoI[,r,4])),
                                                                  (as.numeric(Table_RoI[,r,5])+1):(dim(feature_map_T)[4]-as.numeric(Table_RoI[,r,6])),]

                                      RoI_X_Res <- as.array(k_shape(RoI_Cropped)[2])
                                      RoI_Y_Res <- as.array(k_shape(RoI_Cropped)[3])
                                      RoI_Z_Res <- as.array(k_shape(RoI_Cropped)[4])

                                      New_X_Res <- as.array(output_dim[3])
                                      New_Y_Res <- as.array(output_dim[4])
                                      New_Z_Res <- as.array(output_dim[5])

                                      X_step = RoI_X_Res / New_X_Res    
                                      Y_step = RoI_Y_Res  / New_Y_Res  
                                      Z_step = RoI_Z_Res  / New_Z_Res  

                                      for(ch in 1:Channels) { 
                                        print(paste("ch", ch))
                                        for (k in 1:New_Z_Res) { 
                                          print(paste("k", k))
                                          for (j in 1:New_Y_Res) { 
                                            print(paste("j", j, "k", k))
                                            for (i in 1:New_X_Res) { 
                                              # INDEX X
                                              Index_Xstart <- floor((i-1)*X_step+1)
                                              if(i+1 <= RoI_X_Res){
                                                Index_Xend <- floor((i)*X_step)
                                              }else{
                                                Index_Xend <- RoI_X_Res
                                              }
                                              # INDEX Y
                                              Index_Ystart <-  floor((j-1)*Y_step+1) 
                                              if(j+1 <= RoI_Y_Res){
                                                Index_Yend <- floor((j)*Y_step)
                                              }else{
                                                Index_Yend <-RoI_Y_Res
                                              }
                                              # INDEX Z        
                                              Index_Zstart <-  floor((k-1)*Z_step+1) 
                                              if(k+1 <= RoI_Z_Res){
                                                Index_Zend <- floor((k)*Z_step)
                                              }else{
                                                Index_Zend <-RoI_Z_Res
                                              }
                                              Max_Pool_X_Value <- as.array(k_max(RoI_Cropped[n_Batch,Index_Xstart:Index_Xend, Index_Ystart:Index_Yend, Index_Zstart:Index_Zend,ch])) # ADD BATCH AND CHANNEL LAYERS
                                              RoI_Pooled_Array[,r,i,j,k,ch] <- Max_Pool_X_Value
                                            }# i LOOP
                                          } # j LOOP 
                                        } # k Loop
                                      } #Ch LOOP 
                                    } # r LOOP (ROI)
                                    feature_map_ROIpooled <- tf$Variable(RoI_Pooled_Array, tf$int16) # ??? NOT SURE IF RETURN NEEDS TO BE A VARIABLE

                                    return (feature_map_ROIpooled)

                                  }), # END OF AUTO, # END OF CALL ... AUTOGRAPH FUNCTION

                                  ##############
                                  # OUTPUT SHAPE
                                  ##############

                                  compute_output_shape = function(input_shape) { 
                                    list(self$output_dim) 
                                    }
                                )
                              )
# 
###############################
# Create layer wrapper function
###############################

layer_3D_ROI_pooled <- function(object, Table_RoI, output_dim, name = NULL, trainable = TRUE) {
  create_layer(ROIpooled_Layer, object, list(Table_RoI = Table_RoI, 
                                              output_dim = as.integer(output_dim), 
                                              name = name,
                                              trainable = FALSE
                                            ))
}

ОШИБКА:

Error in value[[3L]](cond) : 
   The R function's signature must not contains esoteric Python-incompatible constructs. Detailed traceback: SyntaxError: non-default argument follows default argument (<string>, line 3)

Любая помощь / понимание / ясность приветствуются.

С уважением, Дом

1 Ответ

0 голосов
/ 19 июня 2020

Я не уверен, что это правильный протокол для ответа на собственный вопрос, но я думаю, что у меня есть рабочий пользовательский слой для пула 3D RoI, которым я могу поделиться. В приведенном выше описании много ошибок, но наиболее заметное изменение касается l oop .... Я думаю, мне нужно было сначала сгенерировать список тензоров, которые представляют каждый объединенный RoI, а затем преобразовать его в желаемую форму вывода.

################################################################################################
# ROI_3D_pooled_Layer (Custom layer class)
##########################################
ROI_3D_pooled_Layer <- R6::R6Class("KerasLayer",

                                   inherit = KerasLayer,

                                   public = list(
                                     List_RoI = NULL,
                                     output_dim = NULL, 

                                     initialize = function(List_RoI, output_dim) {
                                       self$List_RoI = List_RoI
                                       self$output_dim = output_dim
                                     },

                                     call = function(x, mask = NULL) {   
                                       List_RoI <- self$List_RoI
                                       output_dim <- self$output_dim

                                       # EXTRACT INFORMATION ON OUTPUT DIMENSION
                                       n_Batch <- as.integer(output_dim[1])
                                       n_RoIs <- as.integer(output_dim[2])
                                       n_Channels <- as.integer(output_dim[6])

                                       New_X_Res <- as.numeric(output_dim[3])
                                       New_Y_Res <- as.numeric(output_dim[4])
                                       New_Z_Res <- as.numeric(output_dim[5])

                                       input_shape <- dim(x)

                                       # EMPTY LIST TO STORE TENSORS
                                       output_list = list()
                                       for(r in 1:n_RoIs){ # LOOP RoIs
                                         # GET one RoI AND CROP INPUT LAYER
                                         if(n_RoIs > 1){
                                           oneList_RoI <- List_RoI[[r]]
                                         }else{
                                           oneList_RoI <- List_RoI
                                         }

                                         RoI_Cropped <-x[,(oneList_RoI[[1]][1]+1):(as.numeric(input_shape[2])-oneList_RoI[[1]][2]),
                                                         (oneList_RoI[[2]][1]+1):(as.numeric(input_shape[3])-oneList_RoI[[2]][2]),
                                                         (oneList_RoI[[3]][1]+1):(as.numeric(input_shape[4])-oneList_RoI[[3]][1]),]

                                         # GET RoI Dimensions for XYZ
                                         RoI_X_Res <- as.numeric(dim(RoI_Cropped)[2])
                                         RoI_Y_Res <- as.numeric(dim(RoI_Cropped)[3])
                                         RoI_Z_Res <- as.numeric(dim(RoI_Cropped)[4])

                                         # CALCULATE STEPS IN ALL DIMENSIONS FOR POOLING
                                         X_step = RoI_X_Res / New_X_Res    
                                         Y_step = RoI_Y_Res  / New_Y_Res  
                                         Z_step = RoI_Z_Res  / New_Z_Res  

                                         for(ch in 1:n_Channels) { # LOOP CHANNEL
                                           for (k in 1:New_Z_Res) { # LOOP Z
                                             for (j in 1:New_Y_Res) { # LOOP Y
                                               for (i in 1:New_X_Res) { # LOOP X
                                                 # INDEX X
                                                 Index_Xstart <- floor((i-1)*X_step+1)
                                                 if(i+1 <= RoI_X_Res){
                                                   Index_Xend <- floor((i)*X_step)
                                                 }else{
                                                   Index_Xend <- RoI_X_Res
                                                 }
                                                 # INDEX Y
                                                 Index_Ystart <-  floor((j-1)*Y_step+1) 
                                                 if(j+1 <= RoI_Y_Res){
                                                   Index_Yend <- floor((j)*Y_step)
                                                 }else{
                                                   Index_Yend <-RoI_Y_Res
                                                 }
                                                 # INDEX Z        
                                                 Index_Zstart <-  floor((k-1)*Z_step+1) 
                                                 if(k+1 <= RoI_Z_Res){
                                                   Index_Zend <- floor((k)*Z_step)
                                                 }else{
                                                   Index_Zend <-RoI_Z_Res
                                                 }

                                                 # MAX POOL VOLUME FOR EACH ELEMENT IN FINAL LAYER AND PUT IN EMPTY ARRAY
                                                 Max_Pool_X_Value <-k_max(RoI_Cropped[,Index_Xstart:Index_Xend, Index_Ystart:Index_Yend, Index_Zstart:Index_Zend,ch])

                                                 # APPEND EACH RoI_Pooled element into a list
                                                 output_list <- list.append(output_list, Max_Pool_X_Value)
                                               }# i LOOP
                                             } # j LOOP 
                                           } # k Loop
                                         } #Ch LOOP 
                                       } # r LOOP (ROI)

                                       # STACK THE OUTPUT LIST AND RESHAPE TO THE DESIRED OUTPUT SIZE 
                                       output_Stack <- k_stack(output_list, axis = 1)
                                       feature_map_ROIpooled <- k_reshape(output_Stack, shape = c(n_Batch, n_RoIs, New_X_Res, New_Y_Res, New_Z_Res, n_Channels))
                                       return (feature_map_ROIpooled)
                                     },
                                     compute_output_shape = function(input_shape) {
                                       return(self$output_dim)
                                     }
                                   )
)

# Create layer wrapper function
layer_3D_ROI_pooled <- function(object, List_RoI, output_dim) {
  create_layer(ROI_3D_pooled_Layer, object, list(List_RoI = List_RoI, 
                                                 output_dim = as.integer(output_dim)
  ))
}

Это моя первая попытка использовать пользовательский слой Keras (с использованием R), поэтому, пожалуйста, внесите предложения по улучшению.

...