
ããã«ã¡ã¯ãHabrïŒ
RãŠãŒã¶ãŒã¯é·ãéããã£ãŒãã©ãŒãã³ã°ã«åå ããæ©äŒã奪ãããŠãããåäžã®ããã°ã©ãã³ã°èšèªã®ãã¬ãŒã ã¯ãŒã¯å
ã«ãšã©ãŸã£ãŠããŸãã
MXNetã®ãªãªãŒã¹ã«ããç¶æ³ã¯å€ããå§ããŸããããåŸæ¹äºææ§ãæãªãç¬ç¹ã®ããã¥ã¡ã³ããé »ç¹ãªå€æŽããã®ã©ã€ãã©ãªã®äººæ°ãå¶éããŠããŸãã
ããã«é
åçãªã®ã¯ã TensorFlowãšKerasã§Rã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããããã¯ãšã³ãïŒTensorFlowãTheanoãCNTKïŒããéžæã§ããããšã詳现ãªããã¥ã¡ã³ããããã³å€ãã®äŸã§ãã ãã®ã¡ãã»ãŒãžã§ã¯ã Carvana Image Masking Challenge ïŒ åè
ïŒãäŸãšããŠäœ¿çšããèæ¯ãã16ã®ç°ãªãè§åºŠããæ®åœ±ããè»ãåé¢ããæ¹æ³ãåŠç¿ããå¿
èŠãããç»åã»ã°ã¡ã³ããŒã·ã§ã³ã®åé¡ã®è§£æ±ºçãåæããŸãã ããã¥ãŒã©ã«ãããã¯ãŒã¯ãéšåã¯Kerasã«å®å
šã«å®è£
ããã magick ïŒ ImageMagickãžã®ã€ã³ã¿ãŒãã§ãŒã¹ïŒã¯ç»ååŠçãæ
åœãã䞊ååŠçã¯parallel + doParallel + foreach ïŒWindowsïŒãŸãã¯parallel + doMC + foreach ïŒLinuxïŒã«ãã£ãŠæäŸãããŸãã
å
容ïŒ
- å¿
èŠãªãã®ããã¹ãŠã€ã³ã¹ããŒã«ãã
- ç»åæäœïŒ OpenCVã®ä»£æ¿ãšããŠã®magick
- WindowsãšLinuxã§Rã³ãŒããåæã«å®è¡ãã
- 網ç¶ããã³å埩å
- ã»ã°ã¡ã³ããŒã·ã§ã³ã®åé¡ãšãã®æ倱é¢æ°
- U-Netã¢ãŒããã¯ãã£
- ã¢ãã«ãã¬ãŒãã³ã°
- ã¢ãã«ããŒã¹ã®äºæž¬
1.å¿
èŠãªãã®ãã¹ãŠãã€ã³ã¹ããŒã«ãã
ãªãŒããŒã«ã¯ãã§ã«4 GB以äžã®ã¡ã¢ãªãåããNvidia GPUãããïŒãããããã以äžã§ãããããã»ã©ããããããªãïŒãCUDAããã³cuDNNã©ã€ãã©ãªãã€ã³ã¹ããŒã«ãããŠãããšæ³å®ããŠããŸãã Linuxã®å ŽåãåŸè
ã®ã€ã³ã¹ããŒã«ã¯ç°¡åã§ïŒ å€ãã®ããã¥ã¢ã«ã®1〠ïŒãWindowsã®å Žåã¯ããã«ç°¡åã§ãïŒ ããã¥ã¢ã«ã®ãCUDAïŒcuDNNãã»ã¯ã·ã§ã³ãåç
§ïŒã
次ã«ãPython 3ã§Anacondaãã£ã¹ããªãã¥ãŒã·ã§ã³ãã€ã³ã¹ããŒã«ããããšããå§ãããŸãã ã¹ããŒã¹ãç¯çŽããããã«ãMinicondaã®æå°ãªãã·ã§ã³ãéžæã§ããŸãã ãã£ã¹ããªãã¥ãŒã·ã§ã³ã®PythonããŒãžã§ã³ãconda install python=3.6
ãµããŒããããŠããæåŸã®ããŒãžã§ã³ãããå
ã«ããå Žåã conda install python=3.6
ãšãã圢åŒã®ã³ãã³ãã§çœ®ãæããããšãã§ããŸãã ãŸãããã¹ãŠãéåžžã®Pythonããã³ä»®æ³ç°å¢ã§åäœããŸãã
䜿çšãããRããã±ãŒãžã®ãªã¹ãã¯æ¬¡ã®ãšããã§ãã
Windowsããã±ãŒãžãªã¹ã library(keras) library(magick) library(abind) library(reticulate) library(parallel) library(doParallel) library(foreach)
Linuxããã±ãŒãžãªã¹ã library(keras) library(magick) library(abind) library(reticulate) library(parallel) library(doMC) library(foreach)
ãããã¯ãã¹ãŠCRANã§ã€ã³ã¹ããŒã«ãããŸããã devtools::install_github("rstudio/keras")
ã¯Githubã§äœ¿çšããã®ãæé©ã§ãïŒ devtools::install_github("rstudio/keras")
ã ç¶ããŠinstall_keras()
ã³ãã³ããå®è¡ãããšãcondaç°å¢ãäœæãããTensorflowãšKerasã®æ£ããPythonããŒãžã§ã³ãã€ã³ã¹ããŒã«ãããŸã ã äœããã®çç±ã§ãã®ã³ãã³ããæ£ããæ©èœããªãå ŽåïŒããšãã°ãå¿
èŠãªPythonãã£ã¹ããªãã¥ãŒã·ã§ã³ãèŠã€ãããªãã£ãå ŽåïŒããŸãã¯äœ¿çšããã©ã€ãã©ãªã®ç¹å®ã®ããŒãžã§ã³ãå¿
èŠãªå Žåã¯ã condaç°å¢ãèªåã§äœæã ãå¿
èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ããŠãããRã§ã¬ãã¯ã«ããã±ãŒãžãæå®ããå¿
èŠããããŸããã®ç°å¢ã¯use_condaenv()
ã³ãã³ãã䜿çšããŠããŸãã
以äžã§äœ¿çšããããã©ã¡ãŒã¿ãŒã®ãªã¹ãïŒ
input_size <- 128 # , epochs <- 30 # batch_size <- 16 # orig_width <- 1918 # orig_height <- 1280 # train_samples <- 5088 # train_index <- sample(1:train_samples, round(train_samples * 0.8)) # 80% val_index <- c(1:train_samples)[-train_index] # images_dir <- "input/train/" masks_dir <- "input/train_masks/"
2.ç»åââæäœïŒ OpenCVã®ä»£æ¿ãšããŠã®magick
ã°ã©ãã£ãã¯ããŒã¿ã§æ©æ¢°åŠç¿ã®åé¡ã解決ããå Žåãå°ãªããšããã£ã¹ã¯ããç»åãèªã¿åããé
åã®åœ¢ã§ãã¥ãŒã©ã«ãããã¯ãŒã¯ã«è»¢éã§ããå¿
èŠããããŸãã éåžžãããããæ¡åŒµãå®è£
ããããã«ãããŸããŸãªç»åå€æãå®è¡ã§ããå¿
èŠããããŸãããã¬ãŒãã³ã°ã»ããã«ããã¬ãŒãã³ã°ã»ããèªäœã«å®éã«ååšãããµã³ãã«ããäœæããã人工çãªãµã³ãã«ãè¿œå ããŸãã æ¡åŒµã¯ãïŒã»ãšãã©ïŒã¢ãã«ã®å質ãåžžã«åäžãããããšãã§ããŸã ãããšãã°ã ãã®ã¡ãã»ãŒãžããåºæ¬çãªç解ãåŸãããšãã§ããŸã ã ä»åŸã¯ãããããã¹ãŠãè¿
éãã€ãã«ãã¹ã¬ããã§å®è¡ããå¿
èŠãããããšã«æ³šæããŠãã ãããæ¯èŒçé«éãªCPUãæ¯èŒçäœéã®ãããªã«ãŒãã§ãã£ãŠããæºå段éã¯ãã¥ãŒã©ã«ãããã¯ãŒã¯èªäœããã¬ãŒãã³ã°ãããããå€ãã®ãªãœãŒã¹ãæ¶è²»ããŸãã
Pythonã¯äŒçµ±çã«OpenCVã䜿çšããŠç»åãåŠçããŸãã Rçšã®ãã®ã¡ã¬ãã€ãã©ã€ãã©ãªã®ããŒãžã§ã³ã¯ãŸã äœæãããŠãããããã®é¢æ°ãã¬ãã¯ã«çµç±ã§åŒã³åºãããšã¯ã¹ããŒããã³ããããªããœãªã¥ãŒã·ã§ã³ã®ããã«èŠãããããå©çšå¯èœãªä»£æ¿æ¡ããéžæããŸãã
æã匷åãªäžäœ3ã€ã®ã°ã©ãã£ãã¯ããã±ãŒãžã¯æ¬¡ã®ãšããã§ãã
EBImage-ããã±ãŒãžã¯S4ã¯ã©ã¹ã䜿çšããŠäœæãããBioconductoraãªããžããªã«é
眮ãããŸãããããã¯ãããã±ãŒãžèªäœãšãã®ããã¥ã¡ã³ãã®äž¡æ¹ã®å質ã«å¯Ÿããæé«ã®èŠä»¶ãæå³ããŸãã æ®å¿µãªããããã®ãœãããŠã§ã¢è£œåã®èšå€§ãªæ©èœã楜ããããšã¯ããã®éåžžã«é
ãé床ã«ãã£ãŠåŠšããããŠããŸãã
imager-ãã®ããã±ãŒãžã®äž»ãªäœæ¥ã¯CImgã©ã€ãã©ãªã«é¢ããã³ã³ãã€ã«ãããã³ãŒãã«ãã£ãŠå®è¡ãããããããã®ããã±ãŒãžã¯ããã©ãŒãã³ã¹ã®é¢ã§ããèå³æ·±ãããã«èŠããŸãã å©ç¹ã®äžã§ããããã€ãã©ã€ã³ãæŒç®å%>%
ïŒããã³magrittrã®ä»ã®æŒç®åïŒã®ãµããŒã ãããããããã±ãŒãžãšã®ç·å¯ãªçµ±åã«æ³šç®ã§ããŸãã tigpverseïŒggplot2ãå«ãïŒ ãããã³split-apply-combineã€ããªãã®ãŒã®ãµããŒãã ãŸããäžéšã®PCã§ç»åãèªã¿åãããã®æ©èœãåäœäžèœã«ãªã£ãäžå¯è§£ãªãã°ã ããããã®ã¡ãã»ãŒãžã®äœæè
ããã®ããã±ãŒãžãéžæã§ããªãããã«ããŸããã
- magickã¯ã ImageMagickã®ã©ãããŒããã±ãŒãžã§ããã rOpenSciã³ãã¥ããã£ã®ã¡ã³ããŒã«ãã£ãŠéçºãããç©æ¥µçã«éçºãããŠããŸãã Tesseract OCRã©ã€ãã©ãªãŒãšã®çµ±åãšãã圢ã§ã以åã®ããã±ãŒãžã®ãã¹ãŠã®å©ç¹ãå®å®æ§ããã°ã®ãªãããšãããã³ãã©ãŒæ©èœïŒã¿ã¹ã¯ã®äžéšãšããŠã¯åœ¹ã«ç«ããªãïŒãçµã¿åãããŠããŸãã ç°ãªãã³ã¢æ°ã§ç»åãèªã¿åã£ãŠå€æãããšãã®é床ã®æž¬å®å€ã以äžã«ç€ºããŸãã ãã€ãã¹èšå·ã®ãã¡ãé£è§£ãªæ§æã¯å Žæã«æ³šæããããšãã§ããŸããããšãã°ãåãåãããµã€ãºå€æŽãè¡ãã«ã¯ãé¢æ°ã®
height
ãšwidth
ã®åã®éåžžã®åŒæ°ã®ä»£ããã«"100x150+50"
ãšãã圢åŒã®æååãæž¡ãå¿
èŠããããŸãã ååŠçã®è£å©é¢æ°ã¯ãããã®å€ã«ãã£ãŠæ£ç¢ºã«ãã©ã¡ãŒã¿ãŒåãããããã paste0(...)
æ§é paste0(...)
ãŸãã¯sprintf(...)
ã䜿çšããå¿
èŠããããŸãã
以äžãPeter Giannakopoulosã®Kerasã«ããKaggle Carvana Image Masking Challengeãœãªã¥ãŒã·ã§ã³ã®æŠèŠã説æããŸãã
ãã¡ã€ã«ããã¢ã§èªã¿åãå¿
èŠããããŸã-ç»åãšããã«å¯Ÿå¿ãããã¹ã¯ããŸããæ¡åŒµã䜿çšããå Žåã¯åãå€æïŒå転ãã·ãããåå°ããºãŒã ïŒãç»åãšãã¹ã¯ã«é©çšããå¿
èŠããããŸãã 1ã€ã®é¢æ°ã®åœ¢åŒã§èªã¿åããå®çŸããŸããããã«ãããåçãããã«ç®çã®ãµã€ãºã«çž®å°ãããŸãã
imagesRead <- function(image_file, mask_file, target_width = 128, target_height = 128) { img <- image_read(image_file) img <- image_scale(img, paste0(target_width, "x", target_height, "!")) mask <- image_read(mask_file) mask <- image_scale(mask, paste0(target_width, "x", target_height, "!")) list(img = img, mask = mask) }
ç»åããã¹ã¯ããé¢æ°ã®çµæïŒ
img <- "input/train/0cdf5b5d0ce1_01.jpg" mask <- "input/train_masks/0cdf5b5d0ce1_01_mask.png" x_y_imgs <- imagesRead(img, mask, target_width = 400, target_height = 400) image_composite(x_y_imgs$img, x_y_imgs$mask, operator = "blend", compose_args = "60") %>% image_write(path = "pics/pic1.jpg", format = "jpg")

å¢åŒ·ã®æåã®çš®é¡ã¯ãæããã圩床ãè²çžã®å€åã§ãã æãããªçç±ãããã«ã©ãŒç»åã«é©çšãããŸãããçœé»ãã¹ã¯ã«ã¯é©çšãããŸããã
randomBSH <- function(img, u = 0, brightness_shift_lim = c(90, 110), # percentage saturation_shift_lim = c(95, 105), # of current value hue_shift_lim = c(80, 120)) { if (rnorm(1) < u) return(img) brightness_shift <- runif(1, brightness_shift_lim[1], brightness_shift_lim[2]) saturation_shift <- runif(1, saturation_shift_lim[1], saturation_shift_lim[2]) hue_shift <- runif(1, hue_shift_lim[1], hue_shift_lim[2]) img <- image_modulate(img, brightness = brightness_shift, saturation = saturation_shift, hue = hue_shift) img }
ãã®å€æã¯50ïŒ
ã®ç¢ºçã§é©çšãããŸãïŒååã®å Žåãå
ã®ç»åãè¿ãããŸãïŒ if (rnorm(1) < u) return(img)
ïŒã3ã€ã®ãã©ã¡ãŒã¿ãŒã®ããããã®å€æŽå€ã¯ãå
ã®å²åãšããŠæå®ãããå€ã®ç¯å²å
ã§ã©ã³ãã ã«éžæãããŸãæ°éã
ãŸãã50ïŒ
ã®ç¢ºçã§ãç»åãšãã¹ã¯ã®æ°Žå¹³åå°ã䜿çšããŸãã
randomHorizontalFlip <- function(img, mask, u = 0) { if (rnorm(1) < u) return(list(img = img, mask = mask)) list(img = image_flop(img), mask = image_flop(mask)) }
çµæïŒ
img <- "input/train/0cdf5b5d0ce1_01.jpg" mask <- "input/train_masks/0cdf5b5d0ce1_01_mask.png" x_y_imgs <- imagesRead(img, mask, target_width = 400, target_height = 400) x_y_imgs$img <- randomBSH(x_y_imgs$img) x_y_imgs <- randomHorizontalFlip(x_y_imgs$img, x_y_imgs$mask) image_composite(x_y_imgs$img, x_y_imgs$mask, operator = "blend", compose_args = "60") %>% image_write(path = "pics/pic2.jpg", format = "jpg")

ããã«è¡šç€ºããããã®æ®ãã®å€æã¯åºæ¬çãªãã®ã§ã¯ãªãããããããã«ã€ããŠã¯èª¬æããŸããã
æåŸã®æ®µéã§ã¯ãåçãé
åã«å€æããŸãã
img2arr <- function(image, target_width = 128, target_height = 128) { result <- aperm(as.numeric(image[[1]])[, , 1:3], c(2, 1, 3)) # transpose dim(result) <- c(1, target_width, target_height, 3) return(result) } mask2arr <- function(mask, target_width = 128, target_height = 128) { result <- t(as.numeric(mask[[1]])[, , 1]) # transpose dim(result) <- c(1, target_width, target_height, 1) return(result) }
ç»åã®è¡ãè¡åã®è¡ã®ãŸãŸã«ãªãããã«è»¢çœ®ãå¿
èŠã§ãïŒç»åã¯è¡ããšã«åœ¢æãããŸãïŒããã¹ã³ãŒãã§èµ°æ»ããŒã ã移åããããïŒãRã®è¡åã¯åã§åããããŸãïŒååªå
ããŸãã¯Fortranã¹ã¿ã€ã«ãæ¯èŒã®ããã numpyã§ïŒååªå
圢åŒãšè¡åªå
圢åŒãåãæ¿ããããšãã§ããŸãïŒã ãããªãã§ãã§ããŸãããããç解ããããã§ãã
3. Windowsããã³Linuxã§ã®Rã³ãŒãã®äžŠåå®è¡
Rã§ã®äžŠåèšç®ã®äžè¬çãªç解ã¯ããã¥ãŒããªã¢ã«ããã±ãŒãž 'parallel' ã doParallelãšforeachã® å
¥é ãããã³doMCãšforeachã® å
¥éã«ãããŸãã æäœã¢ã«ãŽãªãºã ã¯æ¬¡ã®ãšããã§ãã
å¿
èŠãªã³ã¢æ°ã§ã¯ã©ã¹ã¿ãŒãéå§ããŸãã
cl <- makePSOCKcluster(4)
SOCKã¯ã©ã¹ã¿ãŒã¯ãè€æ°ã®PCã®CPUã䜿çšããæ©èœãå«ãããŠãããŒãµã«ãœãªã¥ãŒã·ã§ã³ã§ãã æ®å¿µãªãããã€ãã¬ãŒã¿ãšãã¥ãŒã©ã«ãããã¯ãŒã¯ãã¬ãŒãã³ã°ã䜿çšãããã®äŸã¯Windowsã§æ©èœããŸãããLinuxã§ã¯æ©èœããŸããã Linuxã§ã¯ã代æ¿ã®doMCããã±ãŒãžã䜿çšã§ããŸããããã¯ãå
ã®ããã»ã¹ã®ãã©ãŒã¯ã䜿çšããŠã¯ã©ã¹ã¿ãŒãäœæããŸãã æ®ãã®æé ãå®è¡ããå¿
èŠã¯ãããŸããã
registerDoMC(4) # doMC
doParallelãšdoMCã®äž¡æ¹ãã 䞊åæ©èœãšforeachæ©èœã仲ä»ããŸãã
makePSOCKcluster()
ã䜿çšããå Žåãå¿
èŠãªããã±ãŒãžãšæ©èœãã¯ã©ã¹ã¿ãŒã«ããŒãããå¿
èŠããããŸãã
ããã±ãŒãžãšæ©èœãããŠã³ããŒããã clusterEvalQ(cl, { library(magick) library(abind) library(reticulate) imagesRead <- function(image_file, mask_file, target_width = 128, target_height = 128) { img <- image_read(image_file) img <- image_scale(img, paste0(target_width, "x", target_height, "!")) mask <- image_read(mask_file) mask <- image_scale(mask, paste0(target_width, "x", target_height, "!")) return(list(img = img, mask = mask)) } randomBSH <- function(img, u = 0, brightness_shift_lim = c(90, 110), # percentage saturation_shift_lim = c(95, 105), # of current value hue_shift_lim = c(80, 120)) { if (rnorm(1) < u) return(img) brightness_shift <- runif(1, brightness_shift_lim[1], brightness_shift_lim[2]) saturation_shift <- runif(1, saturation_shift_lim[1], saturation_shift_lim[2]) hue_shift <- runif(1, hue_shift_lim[1], hue_shift_lim[2]) img <- image_modulate(img, brightness = brightness_shift, saturation = saturation_shift, hue = hue_shift) img } randomHorizontalFlip <- function(img, mask, u = 0) { if (rnorm(1) < u) return(list(img = img, mask = mask)) list(img = image_flop(img), mask = image_flop(mask)) } img2arr <- function(image, target_width = 128, target_height = 128) { result <- aperm(as.numeric(image[[1]])[, , 1:3], c(2, 1, 3)) # transpose dim(result) <- c(1, target_width, target_height, 3) return(result) } mask2arr <- function(mask, target_width = 128, target_height = 128) { result <- t(as.numeric(mask[[1]])[, , 1]) # transpose dim(result) <- c(1, target_width, target_height, 1) return(result) } })
foreachã®äžŠåããã¯ãšã³ããšããŠã¯ã©ã¹ã¿ãŒãç»é²ããŸãã
registerDoParallel(cl)
ãã®åŸãã³ãŒãã䞊åã¢ãŒãã§å®è¡ã§ããŸãã
imgs <- list.files(, pattern = , full.names = TRUE)[1:16] masks <- list.files(, pattern = , full.names = TRUE)[1:16] x_y_batch <- foreach(i = 1:16) %dopar% { x_y_imgs <- imagesRead(image_file = batch_images_list[i], mask_file = batch_masks_list[i]) # augmentation x_y_imgs$img <- randomBSH(x_y_imgs$img) x_y_imgs <- randomHorizontalFlip(x_y_imgs$img, x_y_imgs$mask) # return as arrays x_y_arr <- list(x = img2arr(x_y_imgs$img), y = mask2arr(x_y_imgs$mask)) } str(x_y_batch) # List of 16 # $ :List of 2 # ..$ x: num [1, 1:128, 1:128, 1:3] 0.953 0.957 0.953 0.949 0.949 ... # ..$ y: num [1, 1:128, 1:128, 1] 0 0 0 0 0 0 0 0 0 0 ... # $ :List of 2 # ..$ x: num [1, 1:128, 1:128, 1:3] 0.949 0.957 0.953 0.949 0.949 ... # ..$ y: num [1, 1:128, 1:128, 1] 0 0 0 0 0 0 0 0 0 0 ... # ....
æåŸã«ãã¯ã©ã¹ã¿ãŒãåæ¢ããããšãå¿ããªãã§ãã ããã
stopCluster(cl)
ãã€ã¯ããã³ãããŒã¯ããã±ãŒãžã䜿çšããŠãè€æ°ã®ã³ã¢/ã¹ã¬ããã䜿çšããå©ç¹ã確èªããŸãã 4 GBã®ã¡ã¢ãªãæèŒããGPUã§ã¯ã16ãã¢ã®ã€ã¡ãŒãžã®ããããæäœã§ããŸããã€ãŸãã2ã4ã8ããŸãã¯16ã¹ã¬ããã䜿çšããããšããå§ãããŸãïŒæéã¯ç§åäœã§ç€ºãããŸãïŒã

16ã¹ã¬ããããã§ãã¯ããããšã¯ã§ããŸããã§ãããã1ã¹ã¬ãããã4ã¹ã¬ããã«åãæ¿ãããšãé床ãçŽ3åã«ãªããéåžžã«æ¥œããããšã¯æããã§ãã
4. 網ç¶ããã³å埩å
ã¡ã¢ãªã«åãŸããªãããŒã¿ãåŠçããã«ã¯ã reticulateããã±ãŒãžã®å埩åã䜿çšããŸãã åºæ¬ã¯ãéåžžã®ã¯ããŒãžã£ãŒé¢æ°ãã€ãŸãåŒã³åºããããšãåŒã³åºãç°å¢ãšãšãã«å¥ã®é¢æ°ãè¿ãé¢æ°ã§ãã
train_generator train_generator <- function(images_dir, samples_index, masks_dir, batch_size) { images_iter <- list.files(images_dir, pattern = ".jpg", full.names = TRUE)[samples_index] # for current epoch images_all <- list.files(images_dir, pattern = ".jpg", full.names = TRUE)[samples_index] # for next epoch masks_iter <- list.files(masks_dir, pattern = ".gif", full.names = TRUE)[samples_index] # for current epoch masks_all <- list.files(masks_dir, pattern = ".gif", full.names = TRUE)[samples_index] # for next epoch function() { # start new epoch if (length(images_iter) < batch_size) { images_iter <<- images_all masks_iter <<- masks_all } batch_ind <- sample(1:length(images_iter), batch_size) batch_images_list <- images_iter[batch_ind] images_iter <<- images_iter[-batch_ind] batch_masks_list <- masks_iter[batch_ind] masks_iter <<- masks_iter[-batch_ind] x_y_batch <- foreach(i = 1:batch_size) %dopar% { x_y_imgs <- imagesRead(image_file = batch_images_list[i], mask_file = batch_masks_list[i]) # augmentation x_y_imgs$img <- randomBSH(x_y_imgs$img) x_y_imgs <- randomHorizontalFlip(x_y_imgs$img, x_y_imgs$mask) # return as arrays x_y_arr <- list(x = img2arr(x_y_imgs$img), y = mask2arr(x_y_imgs$mask)) } x_y_batch <- purrr::transpose(x_y_batch) x_batch <- do.call(abind, c(x_y_batch$x, list(along = 1))) y_batch <- do.call(abind, c(x_y_batch$y, list(along = 1))) result <- list(keras_array(x_batch), keras_array(y_batch)) return(result) } }
val_generator val_generator <- function(images_dir, samples_index, masks_dir, batch_size) { images_iter <- list.files(images_dir, pattern = ".jpg", full.names = TRUE)[samples_index] # for current epoch images_all <- list.files(images_dir, pattern = ".jpg", full.names = TRUE)[samples_index] # for next epoch masks_iter <- list.files(masks_dir, pattern = ".gif", full.names = TRUE)[samples_index] # for current epoch masks_all <- list.files(masks_dir, pattern = "gif", full.names = TRUE)[samples_index] # for next epoch function() { # start new epoch if (length(images_iter) < batch_size) { images_iter <<- images_all masks_iter <<- masks_all } batch_ind <- sample(1:length(images_iter), batch_size) batch_images_list <- images_iter[batch_ind] images_iter <<- images_iter[-batch_ind] batch_masks_list <- masks_iter[batch_ind] masks_iter <<- masks_iter[-batch_ind] x_y_batch <- foreach(i = 1:batch_size) %dopar% { x_y_imgs <- imagesRead(image_file = batch_images_list[i], mask_file = batch_masks_list[i]) # without augmentation # return as arrays x_y_arr <- list(x = img2arr(x_y_imgs$img), y = mask2arr(x_y_imgs$mask)) } x_y_batch <- purrr::transpose(x_y_batch) x_batch <- do.call(abind, c(x_y_batch$x, list(along = 1))) y_batch <- do.call(abind, c(x_y_batch$y, list(along = 1))) result <- list(keras_array(x_batch), keras_array(y_batch)) return(result) } }
ããã§ãã³ãŒã«ç°å¢ã§ã¯ãåæ代ã«æžå°ããåŠçæžã¿ãã¡ã€ã«ã®ãªã¹ããšã次ã®åæ代ã®åãã«äœ¿çšãããå®å
šãªãªã¹ãã®ã³ããŒãä¿åãããŸãã ãã®å®è£
ã§ã¯ãã©ã³ãã ãªãã¡ã€ã«ã®ã·ã£ããã«ã«ã€ããŠå¿é
ããå¿
èŠã¯ãããŸãã-åãããã¯ã©ã³ãã ãªãµã³ããªã³ã°ã«ãã£ãŠååŸãããŸãã
äžèšã®ããã«ã x_y_batch
ã¯16åã®ãªã¹ãã®ãªã¹ãã§ãããåãªã¹ãã¯2ã€ã®é
åã®ãªã¹ãã§ãã purrr::transpose()
é¢æ°ã¯ãã¹ãããããªã¹ããè£è¿ãã«ããããããã16é
åã®ãªã¹ãã§ãã2ã€ã®ãªã¹ãã®ãªã¹ããååŸããŸãã abind()
ã¯æå®ããã次å
ã«æ²¿ã£ãŠé
åãçµåãã do.call()
ã¯ä»»æã®æ°ã®åŒæ°ãå
éšé¢æ°ã«æž¡ããŸãã è¿œå ã®åŒæ°ïŒ along = 1
ïŒã¯éåžžã«å¥åŠãªæ¹æ³ã§äžããããŸãïŒ do.call(abind, c(x_y_batch$x, list(along = 1)))
ã
ãããã®é¢æ°ãpy_iterator()
ç解ãããªããžã§ã¯ãã«å€ããããšã¯æ®ã£ãŠããŸãïŒ
train_iterator <- py_iterator(train_generator(images_dir = images_dir, masks_dir = masks_dir, samples_index = train_index, batch_size = batch_size)) val_iterator <- py_iterator(val_generator(images_dir = images_dir, masks_dir = masks_dir, samples_index = val_index, batch_size = batch_size))
iter_next(train_iterator)
ãåŒã³åºããšã1ã€ã®å埩ã®çµæãè¿ãããŸããããã¯ããããã°ãã§ãŒãºã§åœ¹ç«ã¡ãŸãã
5.ã»ã°ã¡ã³ããŒã·ã§ã³ã®åé¡ãšãã®æ倱é¢æ°
ã»ã°ã¡ã³ããŒã·ã§ã³ã®åé¡ã¯ããã¯ã»ã«ããšã®åé¡ãšèŠãªãããšãã§ããŸããåãã¯ã»ã«ã¯ç¹å®ã®ã¯ã©ã¹ã«å±ãããšäºæž¬ãããŸãã 2ã€ã®ã¯ã©ã¹ã®å Žåãçµæã¯ãã¹ã¯ã«ãªããŸãã ã¯ã©ã¹ã3ã€ä»¥äžããå Žåããã¹ã¯ã®æ°ã¯ãã¯ã©ã¹ã®æ°ãã1ãåŒãããã®ã«çãããªããŸãïŒã¯ã³ããããšã³ã³ãŒãã®ã¢ããã°ïŒã ç§ãã¡ã®ç«¶äºã§ã¯ã2ã€ã®ã¯ã©ã¹ïŒè»ãšèæ¯ïŒã®ã¿ããããå質ã¡ããªãã¯ã¯ãµã€ã³ãä¿æ°ã§ãã 圌ã¯ãã®æ¹æ³ã§èšç®ããŸãïŒ
K <- backend() dice_coef <- function(y_true, y_pred, smooth = 1.0) { y_true_f <- K$flatten(y_true) y_pred_f <- K$flatten(y_pred) intersection <- K$sum(y_true_f * y_pred_f) result <- (2 * intersection + smooth) / (K$sum(y_true_f) + K$sum(y_pred_f) + smooth) return(result) }
æ倱é¢æ°ãæé©åããŸããããã¯ãã¯ãã¹ãšã³ããããŒãš1 - dice_coef
ã§ãã
bce_dice_loss <- function(y_true, y_pred) { result <- loss_binary_crossentropy(y_true, y_pred) + (1 - dice_coef(y_true, y_pred)) return(result) }
6. U-Netã¢ãŒããã¯ãã£
U-Netã¯ã»ã°ã¡ã³ããŒã·ã§ã³ã®åé¡ã解決ããããã®å€å
žçãªã¢ãŒããã¯ãã£ã§ãã åè·¯å³ïŒ

ãœãŒã¹ïŒ https : //www.researchgate.net/figure/311715357_fig3_Fig-3-U-NET-Architecture
åç128x128ã®å®è£
ïŒ
U-Net 128 get_unet_128 <- function(input_shape = c(128, 128, 3), num_classes = 1) { inputs <- layer_input(shape = input_shape) # 128 down1 <- inputs %>% layer_conv_2d(filters = 64, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 64, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") down1_pool <- down1 %>% layer_max_pooling_2d(pool_size = c(2, 2), strides = c(2, 2)) # 64 down2 <- down1_pool %>% layer_conv_2d(filters = 128, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 128, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") down2_pool <- down2 %>% layer_max_pooling_2d(pool_size = c(2, 2), strides = c(2, 2)) # 32 down3 <- down2_pool %>% layer_conv_2d(filters = 256, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 256, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") down3_pool <- down3 %>% layer_max_pooling_2d(pool_size = c(2, 2), strides = c(2, 2)) # 16 down4 <- down3_pool %>% layer_conv_2d(filters = 512, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 512, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") down4_pool <- down4 %>% layer_max_pooling_2d(pool_size = c(2, 2), strides = c(2, 2)) # 8 center <- down4_pool %>% layer_conv_2d(filters = 1024, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 1024, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") # center up4 <- center %>% layer_upsampling_2d(size = c(2, 2)) %>% {layer_concatenate(inputs = list(down4, .), axis = 3)} %>% layer_conv_2d(filters = 512, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 512, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 512, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") # 16 up3 <- up4 %>% layer_upsampling_2d(size = c(2, 2)) %>% {layer_concatenate(inputs = list(down3, .), axis = 3)} %>% layer_conv_2d(filters = 256, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 256, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 256, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") # 32 up2 <- up3 %>% layer_upsampling_2d(size = c(2, 2)) %>% {layer_concatenate(inputs = list(down2, .), axis = 3)} %>% layer_conv_2d(filters = 128, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 128, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 128, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") # 64 up1 <- up2 %>% layer_upsampling_2d(size = c(2, 2)) %>% {layer_concatenate(inputs = list(down1, .), axis = 3)} %>% layer_conv_2d(filters = 64, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 64, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") %>% layer_conv_2d(filters = 64, kernel_size = c(3, 3), padding = "same") %>% layer_batch_normalization() %>% layer_activation("relu") # 128 classify <- layer_conv_2d(up1, filters = num_classes, kernel_size = c(1, 1), activation = "sigmoid") model <- keras_model( inputs = inputs, outputs = classify ) model %>% compile( optimizer = optimizer_rmsprop(lr = 0.0001), loss = bce_dice_loss, metrics = c(dice_coef) ) return(model) } model <- get_unet_128()
{layer_concatenate(inputs = list(down4, .), axis = 3)}
ã®äžæ¬åŒ§ã¯ã %>%
æŒç®åã®ããã«æåã®ãªããžã§ã¯ããšããŠã§ã¯ãªããå¿
èŠãªåŒæ°ãšããŠãªããžã§ã¯ãã眮ãæããããã«å¿
èŠã§ãã ãã®ã¢ãŒããã¯ãã£ã®å€ãã®å€æŽãæäŸã§ããŸãïŒ layer_conv_2d_transpose
代ããã«layer_upsampling_2d
䜿çšããéåžžã®layer_separable_conv_2d
代ããã«layer_separable_conv_2d
åå¥ã®ç³ã¿èŸŒã¿ãé©çšãããã£ã«ã¿ãŒçªå·ãšãªããã£ãã€ã¶ãŒèšå®ãè©ŠããŸãã Kerasãªã³ã¯ä»ãã®Kaggle Carvana Image Masking Challengeãœãªã¥ãŒã·ã§ã³ã«ã¯ ã1024x1024ãŸã§ã®è§£å床ã®ãªãã·ã§ã³ãããããããRã«ç°¡åã«ç§»æ€ã§ããŸãã
ãã®ã¢ãã«ã«ã¯å€ãã®ãã©ã¡ãŒã¿ãŒããããŸãã
# Total params: 34,540,737 # Trainable params: 34,527,041 # Non-trainable params: 13,696
7.ã¢ãã«ãã¬ãŒãã³ã°
ããã§ã¯ãã¹ãŠãç°¡åã§ãã Tensorboardãèµ·åããŸãã
tensorboard("logs_r")
å¥ã®æ¹æ³ãšããŠã tfrunsããã±ãŒãžã䜿çšã§ããŸã ãããã«ãããTensorboardã¢ããã°ãRStudio IDEã«è¿œå ããããã¥ãŒã©ã«ãããã¯ãŒã¯ã®ãã¬ãŒãã³ã°äœæ¥ãåçåã§ããŸãã
ã³ãŒã«ããã¯ãæå®ããŸãã æ©æåæ¢ã䜿çšãããã©ããŒã«éãããšãã®ãã¬ãŒãã³ã°ã®é床ãäœäžãããæé©ãªã¢ãã«ã®ééãç¶æããŸãã
callbacks_list <- list( callback_tensorboard("logs_r"), callback_early_stopping(monitor = "val_python_function", min_delta = 1e-4, patience = 8, verbose = 1, mode = "max"), callback_reduce_lr_on_plateau(monitor = "val_python_function", factor = 0.1, patience = 4, verbose = 1, epsilon = 1e-4, mode = "max"), callback_model_checkpoint(filepath = "weights_r/unet128_{epoch:02d}.h5", monitor = "val_python_function", save_best_only = TRUE, save_weights_only = TRUE, mode = "max" ) )
ãã¬ãŒãã³ã°ãéå§ããŠåŸ
æ©ããŸãã GTX 1050tiã§ã¯ã1ã€ã®æ代ã«çŽ10åããããŸãã
model %>% fit_generator( train_iterator, steps_per_epoch = as.integer(length(train_index) / batch_size), epochs = epochs, validation_data = val_iterator, validation_steps = as.integer(length(val_index) / batch_size), verbose = 1, callbacks = callbacks_list )
8.ã¢ãã«ããŒã¹ã®äºæž¬
- run-length encoding.
test_dir <- "input/test/" test_samples <- 100064 test_index <- sample(1:test_samples, 1000) load_model_weights_hdf5(model, "weights_r/unet128_08.h5") # best model imageRead <- function(image_file, target_width = 128, target_height = 128) { img <- image_read(image_file) img <- image_scale(img, paste0(target_width, "x", target_height, "!")) } img2arr <- function(image, target_width = 128, target_height = 128) { result <- aperm(as.numeric(image[[1]])[, , 1:3], c(2, 1, 3)) # transpose dim(result) <- c(1, target_width, target_height, 3) return(result) } arr2img <- function(arr, target_width = 1918, target_height = 1280) { img <- image_read(arr) img <- image_scale(img, paste0(target_width, "x", target_height, "!")) } qrle <- function(mask) { img <- t(mask) dim(img) <- c(128, 128, 1) img <- arr2img(img) arr <- as.numeric(img[[1]])[, , 2] vect <- ifelse(as.vector(arr) >= 0.5, 1, 0) turnpoints <- c(vect, 0) - c(0, vect) starts <- which(turnpoints == 1) ends <- which(turnpoints == -1) paste(c(rbind(starts, ends - starts)), collapse = " ") } cl <- makePSOCKcluster(4) clusterEvalQ(cl, { library(magick) library(abind) library(reticulate) imageRead <- function(image_file, target_width = 128, target_height = 128) { img <- image_read(image_file) img <- image_scale(img, paste0(target_width, "x", target_height, "!")) } img2arr <- function(image, target_width = 128, target_height = 128) { result <- aperm(as.numeric(image[[1]])[, , 1:3], c(2, 1, 3)) # transpose dim(result) <- c(1, target_width, target_height, 3) return(result) } qrle <- function(mask) { img <- t(mask) dim(img) <- c(128, 128, 1) img <- arr2img(img) arr <- as.numeric(img[[1]])[, , 2] vect <- ifelse(as.vector(arr) >= 0.5, 1, 0) turnpoints <- c(vect, 0) - c(0, vect) starts <- which(turnpoints == 1) ends <- which(turnpoints == -1) paste(c(rbind(starts, ends - starts)), collapse = " ") } }) registerDoParallel(cl) test_generator <- function(images_dir, samples_index, batch_size) { images_iter <- list.files(images_dir, pattern = ".jpg", full.names = TRUE)[samples_index] function() { batch_ind <- sample(1:length(images_iter), batch_size) batch_images_list <- images_iter[batch_ind] images_iter <<- images_iter[-batch_ind] x_batch <- foreach(i = 1:batch_size) %dopar% { img <- imageRead(image_file = batch_images_list[i]) # return as array arr <- img2arr(img) } x_batch <- do.call(abind, c(x_batch, list(along = 1))) result <- list(keras_array(x_batch)) } } test_iterator <- py_iterator(test_generator(images_dir = test_dir, samples_index = test_index, batch_size = batch_size)) preds <- predict_generator(model, test_iterator, steps = 10) preds <- foreach(i = 1:160) %dopar% { result <- qrle(preds[i, , , ]) } preds <- do.call(rbind, preds)
, qrle
, ( skoffer -):
:

â 128128. , , .
, .
åèš
ãã®ã¡ãã»ãŒãžã§ã¯ãRã®äžã«åº§ã£ãŠãã¡ãã·ã§ã³ã®ãã¬ã³ãã«é
ããã«ã€ããŠããããšãã§ãããã£ãŒããã¥ãŒã©ã«ãããã¯ãŒã¯ãããŸããã¬ãŒãã³ã°ã§ããããšã瀺ãããŸãããããã«ãWindowsã§ãããããé²ãããšã¯ã§ããŸããã
ç¶ç¶ããã«ã¯ãéåžžã©ããã次ã®ããã«ããŸãã