下載資料

– 與之前所有任務相同,這個任務的資料下載是需要經過申請的,請你找助教申請帳號。

讀取資料

library(data.table)

train_dat <- fread('train.csv', data.table = FALSE)
test_dat <- fread('test.csv', data.table = FALSE)
submit_dat <- fread('sample_submission.csv', data.table = FALSE)

檔案格式

F02

F01

library(OpenImageR)
library(imager)

img_dir <- 'image/'
img_pos <- 10L

img_path <- paste0(img_dir, train_dat[img_pos, 'PID'], '/', train_dat[img_pos, 'UID'], '.png')
img <- readImage(img_path)
par(mar = rep(0, 4))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(img, 0, 1, 1, 0, interpolate=FALSE)

標籤格式

– 它的檔案格式有點複雜,但如果你想要在原來那張圖上面做堆疊,你可以透過這種方式做到:

library(jsonlite)

# Settings

label_dir <- 'label/'
img_pos <- 10L

# Read data

label_dat <- fread('label/label_list.csv', data.table = FALSE)

json_path <- paste0(label_dir, train_dat[img_pos, 'PID'], '/', train_dat[img_pos, 'UID'], '.json')
anno_list <- fromJSON(json_path)

# Show image

par(mar = rep(0, 4))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(img, 0, 1, 1, 0, interpolate=FALSE)

# Show annotations

for (m in 1:length(anno_list[['shapes']][['tagAnno']])) {
  
  # Processing
  
  seg_data <- anno_list[['shapes']][['segments']][[m]]
  
  x_seq <- t(seg_data[,c(1,3)]) %>% as.numeric()
  x_seq <- x_seq / anno_list[['size']][1]
  
  y_seq <- t(seg_data[,c(2,4)]) %>% as.numeric()
  y_seq <- y_seq / anno_list[['size']][2]    
  
  poly_col <- label_dat[label_dat[,'structure'] %in% anno_list[['shapes']][['tagAnno']][m], 'color']
  poly_col <- paste0(poly_col, 'A0')
  polygon(x = x_seq, y = y_seq, col = poly_col, border = poly_col)
  
}

library(jsonlite)
library(tiff)

# Settings

label_dir <- 'label/'
img_pos <- 10L

# Read data

json_path <- paste0(label_dir, train_dat[img_pos, 'PID'], '/', train_dat[img_pos, 'UID'], '.json')
anno_list <- fromJSON(json_path)

# Get info

current_dir <- paste0(label_dir, train_dat[img_pos,'PID'], '/', train_dat[img_pos,'UID'], '/')
if (!dir.exists(current_dir)) {dir.create(current_dir, recursive = TRUE)}

obj_names <- unique(anno_list[['shapes']][['tagAnno']])

for (m in 1:length(obj_names)) {
  
  # Plotting
  
  tiff(filename = paste0(current_dir, obj_names[m], '.tiff'), width = 256, height = 256)
  
  par(mar = rep(0, 4))
  plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
  
  # Processing
  
  used_id <- which(anno_list[['shapes']][['tagAnno']] %in% obj_names[m])
  if (length(used_id) > 1) {message(original_data[img_pos,'PID'], '/', original_data[img_pos,'UID'], ':', obj_names[m])}
  
  for (q in used_id) {
    
    seg_data <- anno_list[['shapes']][['segments']][[q]]
    
    x_seq <- t(seg_data[,c(1,3)]) %>% as.numeric()
    x_seq <- x_seq / anno_list[['size']][1]
    
    y_seq <- t(seg_data[,c(2,4)]) %>% as.numeric()
    y_seq <- y_seq / anno_list[['size']][2]    
    
    polygon(x = x_seq, y = y_seq, col = '#000000', border = '#000000')
    
  }
  
  dev.off()
  
  # Binarization
  
  seg_img <- readImage(paste0(current_dir, obj_names[m], '.tiff'))
  if (dim(seg_img)[3] %in% 3) {seg_img <- seg_img %>% rgb_2gray()}
  if (prop.table(table(seg_img))['1'] > 0.5) {seg_img <- 1 - (seg_img > 0.5)} else {seg_img <- (seg_img > 0.5) + 0}
  seg_img <- matrix(seg_img, nrow = 256, ncol = 256)
    
  writeTIFF(what = seg_img, where = paste0(current_dir, obj_names[m], '.tiff'), compression = 'none')
  
}
library(magrittr)

# Settings

label_dir <- 'label/'
img_dir <- 'image/'

img_pos <- 10L

# Read data

label_dat <- fread('label/label_list.csv', data.table = FALSE)

# Show image

img_path <- paste0(img_dir, train_dat[img_pos, 'PID'], '/', train_dat[img_pos, 'UID'], '.png')
img <- readImage(img_path)

par(mar = rep(0, 4))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(img, 0, 1, 1, 0, interpolate = FALSE)

# Read annotations

current_dir <- paste0(label_dir, train_dat[img_pos, 'PID'], '/', train_dat[img_pos, 'UID'], '/')
anno_files <- list.files(current_dir) %>% gsub('\\.tiff', '', .)

# Show annotations

for (m in 1:length(anno_files)) {
  
  anno_img <- readImage(paste0(current_dir, anno_files[m], '.tiff'))
  anno_img <- (anno_img > 0.5)
  
  poly_col <- label_dat[label_dat[,'structure'] %in% anno_files[m], 'color']
  poly_col <- paste0(poly_col, 'A0')  
  
  anno_raster <- c('#00000000', poly_col)[anno_img + 1L] %>% array(., dim = dim(anno_img))
  rasterImage(anno_raster, 0, 1, 1, 0, interpolate = FALSE)
  
}

標籤編碼

library(data.table)
library(OpenImageR)
library(magrittr)

# Settings

img_dir <- 'image/'
label_dir <- 'label/'
process_dir <- 'processed/'

# Read data

label_dat <- fread('label/label_list.csv', data.table = FALSE)

# Patient based processing

if (!dir.exists(process_dir)) {dir.create(process_dir)}
PIDs <- unique(train_dat[,'PID'])

tab_list <- list()

pb <- txtProgressBar(max = length(PIDs), style = 3)

for (i in 1:length(PIDs)) {
  
  current_path <- paste0(process_dir, PIDs[i], '.RData')
  sub_train_dat <- train_dat[train_dat[,'PID'] %in% PIDs[i],]
  
  x_array <- array(0, dim = c(256, 256, nrow(sub_train_dat), 3))
  y_array <- array(0L, dim = c(256, 256, nrow(sub_train_dat), nrow(label_dat)))
  
  for (j in 1:nrow(sub_train_dat)) {
    
    img_path <- paste0(img_dir, PIDs[i], '/', sub_train_dat[j, 'UID'], '.png')
    x_array[,,j,] <- readImage(img_path)
    
    current_label_dir <- paste0(label_dir, PIDs[i], '/', sub_train_dat[j, 'UID'], '/')
    label_files <- list.files(current_label_dir) %>% gsub('.tiff', '', .)
    
    if (length(label_files) > 0) {
      
      for (k in 1:length(label_files)) {
        
        label_path <- paste0(label_dir, PIDs[i], '/', sub_train_dat[j, 'UID'], '/', label_files[k], '.tiff')
        label_img <- readImage(label_path)
        pos_id <- which(label_dat[,'structure'] %in% label_files[k])
        if (dim(label_img)[3] %in% 3) {label_img <- label_img %>% rgb_2gray()}
        y_array[,,j,pos_id] <- (label_img > 0.5) + 0L
        
      }
      
    }
    
  }
  
  tab_list[[i]] <- apply(y_array, 3:4, sum)
  save(x_array, y_array, file = current_path)
  setTxtProgressBar(pb, i)
  
}

close(pb)
library(mxnet)
library(abind)

# Settings

fold_pos <- 50L

img_dir <- 'image/'
process_dir <- 'processed/'
PIDs <- unique(train_dat[,'PID'])

neg_pixel <- c(461, 465, 238, 241, 51, 54, 29, 89, 133)
neg_pixel <- neg_pixel * fold_pos

# Read data

my_iterator_core <- function (batch_size, random_crop = 224) {
  
  batch <- 0
  batch_per_epoch <- nrow(train_dat) / batch_size
  
  reset <- function() {batch <<- 0}
  
  iter.next <- function() {
    batch <<- batch+1
    if (batch > batch_per_epoch) {return(FALSE)} else {return(TRUE)}
  }
  
  value <- function() {
    batch_PID <- sample(PIDs, 1, replace = TRUE)
    load(paste0(process_dir, batch_PID, '.RData'))
    batch_idxID <- sample(1:dim(x_array)[3], batch_size, replace = TRUE)
    batch_x_list <- list()
    batch_y_list <- list()
    batch_mask_list <- list()
    for (j in 1:batch_size) {
      random_row <- sample(0:(dim(x_array)[1] - random_crop), 1)
      random_col <- sample(0:(dim(x_array)[2] - random_crop), 1)
      batch_x_list[[j]] <- x_array[random_row+1:random_crop,random_col+1:random_crop,batch_idxID[j],]
      batch_y_list[[j]] <- y_array[random_row+1:random_crop,random_col+1:random_crop,batch_idxID[j],]
      sample_mask_list <- list()
      for (k in 1:length(neg_pixel)) {
        sub_mask_array <- array(0L, dim = c(random_crop, random_crop))
        neg_mask_pos <- sample(1:length(sub_mask_array), neg_pixel[k])
        sub_mask_array[neg_mask_pos] <- 1L
        pos_mask_pos <- which(y_array[random_row+1:random_crop,random_col+1:random_crop,batch_idxID[j],k] == 1)
        sub_mask_array[pos_mask_pos] <- fold_pos
        mirror_mask_pos <- which(y_array[random_row+1:random_crop,(dim(y_array)[2] + 1) - (random_col+1:random_crop),batch_idxID[j],k] == 1)
        sub_mask_array[mirror_mask_pos] <- fold_pos
        sample_mask_list[[k]] <- sub_mask_array
      }
      batch_mask_list[[j]] <- abind(sample_mask_list, along = 3)
    }
    batch_x <- abind(batch_x_list, along = 4)
    batch_y <- abind(batch_y_list, along = 4)
    batch_mask <- abind(batch_mask_list, along = 4)
    data <- mx.nd.array(batch_x)
    label <- mx.nd.array(batch_y)
    mask <- mx.nd.array(batch_mask)
    return(list(data = data, label = label, mask = mask))
  }
  
  return(list(reset = reset, iter.next = iter.next, value = value, batch_size = batch_size, batch = batch))
}

my_iterator_func <- setRefClass("Custom_Iter",
                                fields = c("iter", "batch_size", "random_crop"),
                                contains = "Rcpp_MXArrayDataIter",
                                methods = list(
                                  initialize = function (iter, batch_size = 8, random_crop = 224){
                                    .self$iter <- my_iterator_core(batch_size = batch_size, random_crop = random_crop)
                                    .self
                                  },
                                  value = function () {
                                    .self$iter$value()
                                  },
                                  iter.next = function () {
                                    .self$iter$iter.next()
                                  },
                                  reset = function () {
                                    .self$iter$reset()
                                  },
                                  finalize = function () {
                                  }
                                )
)

my_iter <- my_iterator_func(iter = NULL, batch_size = 16, random_crop = 224)
label_dat <- fread('label/label_list.csv', data.table = FALSE)

my_iter$reset()
my_iter$iter.next()
## [1] TRUE
batch_data <- my_iter$value()

par(mar = rep(0, 4), mfrow = c(1, 1))

plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(as.raster(as.array(batch_data$data)[,,,1]), 0, 1, 1, 0, interpolate=FALSE)
for (k in 1:nrow(label_dat)) {
  current_col <- paste0(label_dat[k,'color'], 'A0')
  current_img <- as.array(batch_data$label)[,,k,1]
  if (!table(current_img)['1'] %in% NA) {
    current_img <- c('#00000000', current_col)[current_img + 1]
    current_img <- array(current_img, dim = c(224, 224))
    rasterImage(current_img, 0, 1, 1, 0, interpolate=FALSE)
  }
}

par(mar = rep(0, 4), mfcol = c(3, 6))

for (k in 1:nrow(label_dat)) {
  plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
  rasterImage(as.raster(as.array(batch_data$data)[,,,1]), 0, 1, 1, 0, interpolate=FALSE)
  current_col <- paste0(label_dat[k,'color'], 'A0')
  current_img <- as.array(batch_data$label)[,,k,1]
  current_img[current_img > 1] <- 1
  if (!table(current_img)['1'] %in% NA) {
    current_img <- c('#00000000', current_col)[current_img + 1]
    current_img <- array(current_img, dim = c(224, 224))
    rasterImage(current_img, 0, 1, 1, 0, interpolate = FALSE)
  }
}

for (k in 1:nrow(label_dat)) {
  plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
  rasterImage(as.raster(as.array(batch_data$data)[,,,1]), 0, 1, 1, 0, interpolate=FALSE)
  current_col <- paste0(label_dat[k,'color'], 'A0')
  current_img <- as.array(batch_data$mask)[,,k,1]
  current_img[current_img > 1] <- 1
  if (!table(current_img)['1'] %in% NA) {
    current_img <- c('#00000000', current_col)[current_img + 1]
    current_img <- array(current_img, dim = c(224, 224))
    rasterImage(current_img, 0, 1, 1, 0, interpolate = FALSE)
  }
}

模型訓練

library(mxnet)

data <- mx.symbol.Variable('data')
bn_data <- mx.symbol.BatchNorm(data = data, fix.gamma = TRUE, name = 'bn_data')

down_conv1 <- mx.symbol.Convolution(data = bn_data, kernel = c(7, 7), pad = c(3, 3), num_filter = 32, no.bias = TRUE, name = 'down_conv1')
down_convbn1 <- mx.symbol.BatchNorm(data = down_conv1, fix.gamma = FALSE, name = 'down_convbn1')
down_convrelu1 <- mx.symbol.Activation(data = down_convbn1, act_type = "relu", name = 'down_convrelu1')
down_convpool1 <- mx.symbol.Pooling(data = down_convrelu1, pool_type = "avg", kernel = c(2, 2), stride = c(2, 2), name = 'down_convpool1')

down_conv2 <- mx.symbol.Convolution(data = down_convpool1, kernel = c(5, 5), pad = c(2, 2), num_filter = 64, no.bias = TRUE, name = 'down_conv2')
down_convbn2 <- mx.symbol.BatchNorm(data = down_conv2, fix.gamma = FALSE, name = 'down_convbn2')
down_convrelu2 <- mx.symbol.Activation(data = down_convbn2, act_type = "relu", name = 'down_convrelu2')
down_convpool2 <- mx.symbol.Pooling(data = down_convrelu2, pool_type = "avg", kernel = c(2, 2), stride = c(2, 2), name = 'down_convpool2')

down_conv3 <- mx.symbol.Convolution(data = down_convpool2, kernel = c(3, 3), pad = c(1, 1), num_filter = 128, no.bias = TRUE, name = 'down_conv3')
down_convbn3 <- mx.symbol.BatchNorm(data = down_conv3, fix.gamma = FALSE, name = 'down_convbn3')
down_convrelu3 <- mx.symbol.Activation(data = down_convbn3, act_type = "relu", name = 'down_convrelu3')
down_convpool3 <- mx.symbol.Pooling(data = down_convrelu3, pool_type = "avg", kernel = c(2, 2), stride = c(2, 2), name = 'down_convpool3')

down_conv4 <- mx.symbol.Convolution(data = down_convpool3, kernel = c(3, 3), pad = c(1, 1), num_filter = 256, no.bias = TRUE, name = 'down_conv4')
down_convbn4 <- mx.symbol.BatchNorm(data = down_conv4, fix.gamma = FALSE, name = 'down_convbn4')
down_convrelu4 <- mx.symbol.Activation(data = down_convbn4, act_type = "relu", name = 'down_convrelu4')
down_convpool4 <- mx.symbol.Pooling(data = down_convrelu4, pool_type = "avg", kernel = c(2, 2), stride = c(2, 2), name = 'down_convpool4')

down_conv5 <- mx.symbol.Convolution(data = down_convpool4, kernel = c(3, 3), pad = c(1, 1), num_filter = 512, no.bias = TRUE, name = 'down_conv5')
down_convbn5 <- mx.symbol.BatchNorm(data = down_conv5, fix.gamma = FALSE, name = 'down_convbn5')
down_convrelu5 <- mx.symbol.Activation(data = down_convbn5, act_type = "relu", name = 'down_convrelu5')
down_convpool5 <- mx.symbol.Pooling(data = down_convrelu5, pool_type = "avg", kernel = c(2, 2), stride = c(2, 2), name = 'down_convpool5')

down_conv6 <- mx.symbol.Convolution(data = down_convpool5, kernel = c(3, 3), pad = c(1, 1), num_filter = 512, no.bias = TRUE, name = 'down_conv6')
down_convbn6 <- mx.symbol.BatchNorm(data = down_conv6, fix.gamma = FALSE, name = 'down_convbn6')
down_convrelu6 <- mx.symbol.Activation(data = down_convbn6, act_type = "relu", name = 'down_convrelu6')

up_deconv1 <- mx.symbol.Deconvolution(data = down_convrelu6, kernel = c(2, 2), stride = c(2, 2), num_filter = 512, name = 'up_deconv1')
up_deconvbn1 <- mx.symbol.BatchNorm(data = up_deconv1, fix.gamma = FALSE, name = 'up_deconvbn1')
up_deconvrelu1 <- mx.symbol.Activation(data = up_deconvbn1, act_type = "relu", name = 'up_deconvrelu1')
up_conv1 <- mx.symbol.Convolution(data = up_deconvrelu1, kernel = c(3, 3), pad = c(1, 1), num_filter = 512, no.bias = TRUE, name = 'up_conv1')
up_convbn1 <- mx.symbol.BatchNorm(data = up_conv1, fix.gamma = FALSE, name = 'up_convbn1')
up_convrelu1 <- mx.symbol.Activation(data = up_convbn1, act_type = "relu", name = 'up_convrelu1')

up_concat2 <- mx.symbol.concat(data = list(up_convrelu1, down_convrelu5), num.args = 2, dim = 1, name = 'up_concat2')
up_deconv2 <- mx.symbol.Deconvolution(data = up_concat2, kernel = c(2, 2), stride = c(2, 2), num_filter = 256, name = 'up_deconv2')
up_deconvbn2 <- mx.symbol.BatchNorm(data = up_deconv2, fix.gamma = FALSE, name = 'up_deconvbn2')
up_deconvrelu2 <- mx.symbol.Activation(data = up_deconvbn2, act_type = "relu", name = 'up_deconvrelu2')
up_conv2 <- mx.symbol.Convolution(data = up_deconvrelu2, kernel = c(3, 3), pad = c(1, 1), num_filter = 256, no.bias = TRUE, name = 'up_conv2')
up_convbn2 <- mx.symbol.BatchNorm(data = up_conv2, fix.gamma = FALSE, name = 'up_convbn2')
up_convrelu2 <- mx.symbol.Activation(data = up_convbn2, act_type = "relu", name = 'up_convrelu2')

up_concat3 <- mx.symbol.concat(data = list(up_convrelu2, down_convrelu4), num.args = 2, dim = 1, name = 'up_concat3')
up_deconv3 <- mx.symbol.Deconvolution(data = up_concat3, kernel = c(2, 2), stride = c(2, 2), num_filter = 256, name = 'up_deconv3')
up_deconvbn3 <- mx.symbol.BatchNorm(data = up_deconv3, fix.gamma = FALSE, name = 'up_deconvbn3')
up_deconvrelu3 <- mx.symbol.Activation(data = up_deconvbn3, act_type = "relu", name = 'up_deconvrelu3')
up_conv3 <- mx.symbol.Convolution(data = up_deconvrelu3, kernel = c(3, 3), pad = c(1, 1), num_filter = 256, no.bias = TRUE, name = 'up_conv3')
up_convbn3 <- mx.symbol.BatchNorm(data = up_conv3, fix.gamma = FALSE, name = 'up_convbn3')
up_convrelu3 <- mx.symbol.Activation(data = up_convbn3, act_type = "relu", name = 'up_convrelu3')

up_concat4 <- mx.symbol.concat(data = list(up_convrelu3, down_convrelu3), num.args = 2, dim = 1, name = 'up_concat4')
up_deconv4 <- mx.symbol.Deconvolution(data = up_concat4, kernel = c(2, 2), stride = c(2, 2), num_filter = 256, name = 'up_deconv4')
up_deconvbn4 <- mx.symbol.BatchNorm(data = up_deconv4, fix.gamma = FALSE, name = 'up_deconvbn4')
up_deconvrelu4 <- mx.symbol.Activation(data = up_deconvbn4, act_type = "relu", name = 'up_deconvrelu4')
up_conv4 <- mx.symbol.Convolution(data = up_deconvrelu4, kernel = c(3, 3), pad = c(1, 1), num_filter = 288, no.bias = TRUE, name = 'up_conv4')
up_convbn4 <- mx.symbol.BatchNorm(data = up_conv4, fix.gamma = FALSE, name = 'up_convbn4')
up_convrelu4 <- mx.symbol.Activation(data = up_convbn4, act_type = "relu", name = 'up_convrelu4')

up_deconv5 <- mx.symbol.Deconvolution(data = up_convrelu4, kernel = c(2, 2), stride = c(2, 2), num_filter = 288, num_group = 9, name = 'up_deconv5')
up_deconvbn5 <- mx.symbol.BatchNorm(data = up_deconv5, fix.gamma = FALSE, name = 'up_deconvbn5')
up_deconvrelu5 <- mx.symbol.Activation(data = up_deconvbn5, act_type = "relu", name = 'up_deconvrelu5')
up_conv5 <- mx.symbol.Convolution(data = up_deconvrelu5, kernel = c(3, 3), pad = c(1, 1), num_filter = 288, num_group = 9, no.bias = TRUE, name = 'up_conv5')
up_convbn5 <- mx.symbol.BatchNorm(data = up_conv5, fix.gamma = FALSE, name = 'up_convbn5')
up_convrelu5 <- mx.symbol.Activation(data = up_convbn5, act_type = "relu", name = 'up_convrelu5')

linear_pred <- mx.symbol.Convolution(data = up_convrelu5, kernel = c(3, 3), pad = c(1, 1), num_filter = 9, name = 'linear_pred')
logistic_pred <- mx.symbol.Activation(data = linear_pred, act.type = 'sigmoid', name = 'logistic_pred')

# CE loss

label <- mx.symbol.Variable(name = 'label')
mask <- mx.symbol.Variable(name = 'mask')

eps <- 1e-8
ce_loss_pos <- mx.symbol.broadcast_mul(mx.symbol.log(logistic_pred + eps), label)
ce_loss_neg <- mx.symbol.broadcast_mul(mx.symbol.log(1 - logistic_pred + eps), 1 - label)
ce_loss_sum <- mx.symbol.broadcast_add(ce_loss_pos, ce_loss_neg)
ce_loss_weight <- mx.symbol.broadcast_mul(ce_loss_sum, mask)
sum_mask <- mx.symbol.sum(mask, axis = 0:3)
sum_ce_loss <- mx.symbol.sum(ce_loss_weight, axis = 0:3)
mean_ce_loss <- mx.symbol.broadcast_div(sum_ce_loss, sum_mask)
ce_loss <- mx.symbol.MakeLoss(0 - mean_ce_loss, name = 'ce_loss')
my_optimizer <- mx.opt.create(name = "sgd", learning.rate = 0.005, momentum = 0.9, wd = 1e-4)

my.eval.metric.loss <- mx.metric.custom(
  name = "ce-loss", 
  function(real, pred) {
    return(as.array(pred))
  }
)

mx.set.seed(0)

model <- mx.model.FeedForward.create(symbol = ce_loss, X = my_iter, optimizer = my_optimizer,
                                     eval.metric = my.eval.metric.loss,
                                     input.names = c('data'), output.names = c('label', 'mask'),
                                     array.batch.size = 16, ctx = mx.gpu(), num.round = 100)

model$symbol <- logistic_pred

輸出預測

# Generate image array

test_x_array <- array(0, dim = c(256, 256, 3, 1))
img_path <- paste0(img_dir, test_dat[4, 'PID'], '/', test_dat[4, 'UID'], '.png')
test_x_array[,,,1] <- readImage(img_path)

# Predicting

test_y_array <- predict(model, test_x_array, ctx = mx.gpu())

# Show image

par(mar = rep(0, 4))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(test_x_array[,,,1], 0, 1, 1, 0, interpolate=FALSE)

# Show annotation

for (k in 1:nrow(label_dat)) {
  current_col <- paste0(label_dat[k,'color'], 'A0')
  current_img <- (test_y_array[,,k,1] > 0.5) + 0L
  if (!table(current_img)['1'] %in% NA) {
    current_img <- c('#00000000', current_col)[current_img + 1]
    current_img <- array(current_img, dim = c(256, 256))
    rasterImage(current_img, 0, 1, 1, 0, interpolate=FALSE)
  }
}

head(submit_dat)
##    PID  UID row col   label
## 1 P012 U004 149 128 medulla
## 2 P012 U004 150 128 medulla
## 3 P012 U004 151 128 medulla
## 4 P012 U004 147 129 medulla
## 5 P012 U004 148 129 medulla
## 6 P012 U004 149 129 medulla
library(OpenImageR)
library(imager)

# Settings

img_dir <- 'image/'

# Read data

label_dat <- fread('label/label_list.csv', data.table = FALSE)
img_path <- paste0(img_dir, 'P012/U004.png')
img <- readImage(img_path)

# Show image

par(mar = rep(0, 4))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(img, 0, 1, 1, 0, interpolate=FALSE)

# Show annotation

obj_names <- unique(submit_dat[,'label'])

for (k in 1:length(obj_names)) {
  current_col <- paste0(label_dat[label_dat[,'structure'] %in% obj_names[k],'color'], 'A0')
  current_img <- matrix('#00000000', nrow = 256, ncol = 256)
  pos_matrix <- submit_dat[submit_dat[,'label'] %in% obj_names[k], c('row', 'col')] %>% as.matrix()
  current_img[pos_matrix] <- current_col
  rasterImage(current_img, 0, 1, 1, 0, interpolate=FALSE)
}

# Generate image array

test_x_array <- array(0, dim = c(256, 256, 3, nrow(test_dat)))

for (i in 1:nrow(test_dat)) {
  img_path <- paste0(img_dir, test_dat[i, 'PID'], '/', test_dat[i, 'UID'], '.png')
  test_x_array[,,,i] <- readImage(img_path)
}

# Predicting

test_y_array <- predict(model, test_x_array, ctx = mx.gpu())

# Processing

cut_p <- 0.5

submit_dat_list <- list()

for (i in 1:nrow(test_dat)) {
  
  for (j in 1:nrow(label_dat)) {
    
    sub_y_array <- test_y_array[,,j,i]
    pos_info <- which(sub_y_array > cut_p, arr.ind = TRUE)
    
    if (nrow(pos_info) > 0) {
      
      sub_submit_dat <- data.frame(PID = test_dat[i,'PID'],
                                   UID = test_dat[i,'UID'],
                                   row = pos_info[,'row'],
                                   col = pos_info[,'col'],
                                   label = label_dat[j,'structure'],
                                   stringsAsFactors = FALSE)
      
      submit_dat_list[[length(submit_dat_list) + 1]] <- sub_submit_dat
      
    }
    
  }
  
}

my_submit_dat <- do.call('rbind', submit_dat_list)
write.csv(my_submit_dat, file = 'my_submission.csv', na = '', row.names = FALSE, quote = FALSE)

3D卷積

  1. 更複雜的資料擴增(翻轉)

  2. 適當的切點

  3. 使用「驗證組」對訓練過程做出指引

  4. 交叉驗證

  5. 網路結構的修正,更深的網路等

  6. 多階段的學習率修正策略

library(mxnet)
library(abind)

# Settings

fold_pos <- 50L

img_dir <- 'image/'
process_dir <- 'processed/'
PIDs <- unique(train_dat[,'PID'])

neg_pixel <- c(461, 465, 238, 241, 51, 54, 29, 89, 133)
neg_pixel <- neg_pixel * fold_pos

# Read data

my_iterator_core <- function (batch_size, random_crop = 224, z_crop = 20) {
  
  batch <- 0
  batch_per_epoch <- ceiling(length(PIDs) / batch_size * 30 / z_crop)
  
  reset <- function() {batch <<- 0}
  
  iter.next <- function() {
    batch <<- batch+1
    if (batch > batch_per_epoch) {return(FALSE)} else {return(TRUE)}
  }
  
  value <- function() {
    batch_PID <- sample(PIDs, batch_size, replace = TRUE)
    batch_x_list <- list()
    batch_y_list <- list()
    batch_mask_list <- list()
    for (j in 1:batch_size) {
      load(paste0(process_dir, batch_PID[j], '.RData'))
      random_row <- sample(0:(dim(x_array)[1] - random_crop), 1)
      random_col <- sample(0:(dim(x_array)[2] - random_crop), 1)
      random_z <- sample(0:(dim(x_array)[3] - z_crop), 1)
      batch_x_list[[j]] <- x_array[random_row+1:random_crop,random_col+1:random_crop,random_z+1:z_crop,]
      batch_y_list[[j]] <- y_array[random_row+1:random_crop,random_col+1:random_crop,random_z+1:z_crop,]
      sample_mask_list <- list()
      for (k in 1:length(neg_pixel)) {
        sub_mask_array <- array(0L, dim = c(random_crop, random_crop, z_crop))
        neg_mask_pos <- sample(1:length(sub_mask_array), neg_pixel[k] * z_crop)
        sub_mask_array[neg_mask_pos] <- 1L
        pos_mask_pos <- which(y_array[random_row+1:random_crop,random_col+1:random_crop,random_z + 1:z_crop,k] == 1)
        sub_mask_array[pos_mask_pos] <- fold_pos
        mirror_mask_pos <- which(y_array[random_row+1:random_crop, (dim(y_array)[2] + 1) - (random_col+1:random_crop),random_z + 1:z_crop,k] == 1)
        sub_mask_array[mirror_mask_pos] <- fold_pos
        sample_mask_list[[k]] <- sub_mask_array
      }
      batch_mask_list[[j]] <- abind(sample_mask_list, along = 4)
    }
    batch_x <- abind(batch_x_list, along = 5)
    batch_y <- abind(batch_y_list, along = 5)
    batch_mask <- abind(batch_mask_list, along = 5)
    data <- mx.nd.array(batch_x)
    label <- mx.nd.array(batch_y)
    mask <- mx.nd.array(batch_mask)
    return(list(data = data, label = label, mask = mask))
  }
  
  return(list(reset = reset, iter.next = iter.next, value = value, batch_size = batch_size, batch = batch))
}

my_iterator_func <- setRefClass("Custom_Iter",
                                fields = c("iter", "batch_size", "random_crop", "z_crop"),
                                contains = "Rcpp_MXArrayDataIter",
                                methods = list(
                                  initialize = function (iter, batch_size = 8, random_crop = 224, z_crop = 20){
                                    .self$iter <- my_iterator_core(batch_size = batch_size, random_crop = random_crop, z_crop = z_crop)
                                    .self
                                  },
                                  value = function () {
                                    .self$iter$value()
                                  },
                                  iter.next = function () {
                                    .self$iter$iter.next()
                                  },
                                  reset = function () {
                                    .self$iter$reset()
                                  },
                                  finalize = function () {
                                  }
                                )
)

my_iter <- my_iterator_func(iter = NULL, batch_size = 1, random_crop = 224, z_crop = 20)
library(mxnet)

data <- mx.symbol.Variable('data')
bn_data <- mx.symbol.BatchNorm(data = data, fix.gamma = TRUE, name = 'bn_data')

down_conv1 <- mx.symbol.Convolution(data = bn_data, kernel = c(7, 7, 1), pad = c(3, 3, 0), num_filter = 32, no.bias = TRUE, name = 'down_conv1')
down_convbn1 <- mx.symbol.BatchNorm(data = down_conv1, fix.gamma = FALSE, name = 'down_convbn1')
down_convrelu1 <- mx.symbol.Activation(data = down_convbn1, act_type = "relu", name = 'down_convrelu1')
down_convpool1 <- mx.symbol.Pooling(data = down_convrelu1, pool_type = "avg", kernel = c(2, 2, 1), stride = c(2, 2, 1), name = 'down_convpool1')

down_conv2 <- mx.symbol.Convolution(data = down_convpool1, kernel = c(5, 5, 1), pad = c(2, 2, 0), num_filter = 64, no.bias = TRUE, name = 'down_conv2')
down_convbn2 <- mx.symbol.BatchNorm(data = down_conv2, fix.gamma = FALSE, name = 'down_convbn2')
down_convrelu2 <- mx.symbol.Activation(data = down_convbn2, act_type = "relu", name = 'down_convrelu2')
down_convpool2 <- mx.symbol.Pooling(data = down_convrelu2, pool_type = "avg", kernel = c(2, 2, 1), stride = c(2, 2, 1), name = 'down_convpool2')

down_conv3 <- mx.symbol.Convolution(data = down_convpool2, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 128, no.bias = TRUE, name = 'down_conv3')
down_convbn3 <- mx.symbol.BatchNorm(data = down_conv3, fix.gamma = FALSE, name = 'down_convbn3')
down_convrelu3 <- mx.symbol.Activation(data = down_convbn3, act_type = "relu", name = 'down_convrelu3')
down_convpool3 <- mx.symbol.Pooling(data = down_convrelu3, pool_type = "avg", kernel = c(2, 2, 1), stride = c(2, 2, 1), name = 'down_convpool3')

down_conv4 <- mx.symbol.Convolution(data = down_convpool3, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 256, no.bias = TRUE, name = 'down_conv4')
down_convbn4 <- mx.symbol.BatchNorm(data = down_conv4, fix.gamma = FALSE, name = 'down_convbn4')
down_convrelu4 <- mx.symbol.Activation(data = down_convbn4, act_type = "relu", name = 'down_convrelu4')
down_convpool4 <- mx.symbol.Pooling(data = down_convrelu4, pool_type = "avg", kernel = c(2, 2, 1), stride = c(2, 2, 1), name = 'down_convpool4')

down_conv5 <- mx.symbol.Convolution(data = down_convpool4, kernel = c(3, 3, 3), pad = c(1, 1, 1), num_filter = 512, no.bias = TRUE, name = 'down_conv5')
down_convbn5 <- mx.symbol.BatchNorm(data = down_conv5, fix.gamma = FALSE, name = 'down_convbn5')
down_convrelu5 <- mx.symbol.Activation(data = down_convbn5, act_type = "relu", name = 'down_convrelu5')
down_convpool5 <- mx.symbol.Pooling(data = down_convrelu5, pool_type = "avg", kernel = c(2, 2, 1), stride = c(2, 2, 1), name = 'down_convpool5')

down_conv6 <- mx.symbol.Convolution(data = down_convpool5, kernel = c(3, 3, 3), pad = c(1, 1, 1), num_filter = 512, no.bias = TRUE, name = 'down_conv6')
down_convbn6 <- mx.symbol.BatchNorm(data = down_conv6, fix.gamma = FALSE, name = 'down_convbn6')
down_convrelu6 <- mx.symbol.Activation(data = down_convbn6, act_type = "relu", name = 'down_convrelu6')

up_deconv1 <- mx.symbol.Deconvolution(data = down_convrelu6, kernel = c(2, 2, 1), stride = c(2, 2, 1), num_filter = 512, name = 'up_deconv1')
up_deconvbn1 <- mx.symbol.BatchNorm(data = up_deconv1, fix.gamma = FALSE, name = 'up_deconvbn1')
up_deconvrelu1 <- mx.symbol.Activation(data = up_deconvbn1, act_type = "relu", name = 'up_deconvrelu1')
up_conv1 <- mx.symbol.Convolution(data = up_deconvrelu1, kernel = c(3, 3, 3), pad = c(1, 1, 1), num_filter = 512, no.bias = TRUE, name = 'up_conv1')
up_convbn1 <- mx.symbol.BatchNorm(data = up_conv1, fix.gamma = FALSE, name = 'up_convbn1')
up_convrelu1 <- mx.symbol.Activation(data = up_convbn1, act_type = "relu", name = 'up_convrelu1')

up_concat2 <- mx.symbol.concat(data = list(up_convrelu1, down_convrelu5), num.args = 2, dim = 1, name = 'up_concat2')
up_deconv2 <- mx.symbol.Deconvolution(data = up_concat2, kernel = c(2, 2, 1), stride = c(2, 2, 1), num_filter = 256, name = 'up_deconv2')
up_deconvbn2 <- mx.symbol.BatchNorm(data = up_deconv2, fix.gamma = FALSE, name = 'up_deconvbn2')
up_deconvrelu2 <- mx.symbol.Activation(data = up_deconvbn2, act_type = "relu", name = 'up_deconvrelu2')
up_conv2 <- mx.symbol.Convolution(data = up_deconvrelu2, kernel = c(3, 3, 3), pad = c(1, 1, 1), num_filter = 256, no.bias = TRUE, name = 'up_conv2')
up_convbn2 <- mx.symbol.BatchNorm(data = up_conv2, fix.gamma = FALSE, name = 'up_convbn2')
up_convrelu2 <- mx.symbol.Activation(data = up_convbn2, act_type = "relu", name = 'up_convrelu2')

up_concat3 <- mx.symbol.concat(data = list(up_convrelu2, down_convrelu4), num.args = 2, dim = 1, name = 'up_concat3')
up_deconv3 <- mx.symbol.Deconvolution(data = up_concat3, kernel = c(2, 2, 1), stride = c(2, 2, 1), num_filter = 256, name = 'up_deconv3')
up_deconvbn3 <- mx.symbol.BatchNorm(data = up_deconv3, fix.gamma = FALSE, name = 'up_deconvbn3')
up_deconvrelu3 <- mx.symbol.Activation(data = up_deconvbn3, act_type = "relu", name = 'up_deconvrelu3')
up_conv3 <- mx.symbol.Convolution(data = up_deconvrelu3, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 256, no.bias = TRUE, name = 'up_conv3')
up_convbn3 <- mx.symbol.BatchNorm(data = up_conv3, fix.gamma = FALSE, name = 'up_convbn3')
up_convrelu3 <- mx.symbol.Activation(data = up_convbn3, act_type = "relu", name = 'up_convrelu3')

up_concat4 <- mx.symbol.concat(data = list(up_convrelu3, down_convrelu3), num.args = 2, dim = 1, name = 'up_concat4')
up_deconv4 <- mx.symbol.Deconvolution(data = up_concat4, kernel = c(2, 2, 1), stride = c(2, 2, 1), num_filter = 256, name = 'up_deconv4')
up_deconvbn4 <- mx.symbol.BatchNorm(data = up_deconv4, fix.gamma = FALSE, name = 'up_deconvbn4')
up_deconvrelu4 <- mx.symbol.Activation(data = up_deconvbn4, act_type = "relu", name = 'up_deconvrelu4')
up_conv4 <- mx.symbol.Convolution(data = up_deconvrelu4, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 288, no.bias = TRUE, name = 'up_conv4')
up_convbn4 <- mx.symbol.BatchNorm(data = up_conv4, fix.gamma = FALSE, name = 'up_convbn4')
up_convrelu4 <- mx.symbol.Activation(data = up_convbn4, act_type = "relu", name = 'up_convrelu4')

up_deconv5 <- mx.symbol.Deconvolution(data = up_convrelu4, kernel = c(2, 2, 1), stride = c(2, 2, 1), num_filter = 288, num_group = 9, name = 'up_deconv5')
up_deconvbn5 <- mx.symbol.BatchNorm(data = up_deconv5, fix.gamma = FALSE, name = 'up_deconvbn5')
up_deconvrelu5 <- mx.symbol.Activation(data = up_deconvbn5, act_type = "relu", name = 'up_deconvrelu5')
up_conv5 <- mx.symbol.Convolution(data = up_deconvrelu5, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 288, num_group = 9, no.bias = TRUE, name = 'up_conv5')
up_convbn5 <- mx.symbol.BatchNorm(data = up_conv5, fix.gamma = FALSE, name = 'up_convbn5')
up_convrelu5 <- mx.symbol.Activation(data = up_convbn5, act_type = "relu", name = 'up_convrelu5')

linear_pred <- mx.symbol.Convolution(data = up_convrelu5, kernel = c(3, 3, 1), pad = c(1, 1, 0), num_filter = 9, name = 'linear_pred')
logistic_pred <- mx.symbol.Activation(data = linear_pred, act.type = 'sigmoid', name = 'logistic_pred')

# CE loss

label <- mx.symbol.Variable(name = 'label')
mask <- mx.symbol.Variable(name = 'mask')

eps <- 1e-8
ce_loss_pos <- mx.symbol.broadcast_mul(mx.symbol.log(logistic_pred + eps), label)
ce_loss_neg <- mx.symbol.broadcast_mul(mx.symbol.log(1 - logistic_pred + eps), 1 - label)
ce_loss_sum <- mx.symbol.broadcast_add(ce_loss_pos, ce_loss_neg)
ce_loss_weight <- mx.symbol.broadcast_mul(ce_loss_sum, mask)
sum_mask <- mx.symbol.sum(mask, axis = 0:4)
sum_ce_loss <- mx.symbol.sum(ce_loss_weight, axis = 0:4)
mean_ce_loss <- mx.symbol.broadcast_div(sum_ce_loss, sum_mask)
ce_loss <- mx.symbol.MakeLoss(0 - mean_ce_loss, name = 'ce_loss')
my_optimizer <- mx.opt.create(name = "sgd", learning.rate = 0.005, momentum = 0.9, wd = 1e-4)

my.eval.metric.loss <- mx.metric.custom(
  name = "ce-loss", 
  function(real, pred) {
    return(as.array(pred))
  }
)

mx.set.seed(0)

model <- mx.model.FeedForward.create(symbol = ce_loss, X = my_iter, optimizer = my_optimizer,
                                     eval.metric = my.eval.metric.loss,
                                     input.names = c('data'), output.names = c('label', 'mask'),
                                     array.batch.size = 1, ctx = mx.gpu(), num.round = 100)

model$symbol <- logistic_pred
# Generate image array

test_PIDs <- unique(test_dat[,'PID'])

use_Patient <- 1

sub_test_dat <- test_dat[test_dat[,'PID'] %in% test_PIDs[use_Patient],]
test_x_array <- array(0, dim = c(256, 256, nrow(sub_test_dat), 3, 1))

for (j in 1:nrow(sub_test_dat)) {

  img_path <- paste0(img_dir, test_PIDs[use_Patient], '/', sub_test_dat[j, 'UID'], '.png')
  test_x_array[,,j,,] <- readImage(img_path)

}

# Predicting

test_y_array <- predict(model, test_x_array, ctx = mx.gpu())

# Show image

use_cut <- 4

par(mar = rep(0, 4), mfrow = c(1, 1))
plot(NA, xlim = c(0.04, 0.96), ylim = c(0.96, 0.04), axes = FALSE)
rasterImage(test_x_array[,,use_cut,,1], 0, 1, 1, 0, interpolate=FALSE)

# Show annotation

for (k in 1:nrow(label_dat)) {
  current_col <- paste0(label_dat[k,'color'], 'A0')
  current_img <- (test_y_array[,,use_cut,k,1] > 0.5) + 0L
  if (!table(current_img)['1'] %in% NA) {
    current_img <- c('#00000000', current_col)[current_img + 1]
    current_img <- array(current_img, dim = c(256, 256))
    rasterImage(current_img, 0, 1, 1, 0, interpolate=FALSE)
  }
}

# Get predictions

cut_p <- 0.5
test_PIDs <- unique(test_dat[,'PID'])

submit_dat_list <- list()

for (i in 1:length(test_PIDs)) {

  # Generate image array

  sub_test_dat <- test_dat[test_dat[,'PID'] %in% test_PIDs[i],]
  test_x_array <- array(0, dim = c(256, 256, nrow(sub_test_dat), 3, 1))

  for (j in 1:nrow(sub_test_dat)) {

    img_path <- paste0(img_dir, test_PIDs[i], '/', sub_test_dat[j,'UID'], '.png')
    test_x_array[,,j,,] <- readImage(img_path)

  }

  # Predicting

  test_y_array <- predict(model, test_x_array, ctx = mx.gpu())

  # Processing

  for (j in 1:nrow(sub_test_dat)) {

    for (k in 1:nrow(label_dat)) {

      sub_y_array <- test_y_array[,,j,k,1]
      pos_info <- which(sub_y_array > cut_p, arr.ind = TRUE)

      if (nrow(pos_info) > 0) {

        sub_submit_dat <- data.frame(PID = sub_test_dat[1,'PID'],
                                     UID = sub_test_dat[j,'UID'],
                                     row = pos_info[,'row'],
                                     col = pos_info[,'col'],
                                     label = label_dat[k,'structure'],
                                     stringsAsFactors = FALSE)

        submit_dat_list[[length(submit_dat_list) + 1]] <- sub_submit_dat

      }

    }

  }

}

# Write out

my_submit_dat <- do.call('rbind', submit_dat_list)
write.csv(my_submit_dat, file = 'my_submission.csv', na = '', row.names = FALSE, quote = FALSE)