rm(list=ls(all=T))
options(digits=4, scipen=40)
library(dplyr)
library(keras)



0. Preparing Data

0.1 Images File Directories

Trainm Test and Validation Images files were organized under directories:

4000/
    train/ : training data
        cat/ : cat.1.jpg ~ cat.1000.jpg
        dog/ : dog.1.jpg ~ dog.1000.jpg
    validation/ : validation data
        cat/ : cat.1001.jpg ~ cat.1500.jpg
        dog/ : dog.1001.jpg ~ dog.1500.jpg
    test/ : test data
        cat/ : cat.1501.jpg ~ cat.2000.jpg
        dog/ : dog.1501.jpg ~ dog.2000.jpg

## Sample Images
par(mfrow = c(6, 12), pty = "s", mar = c(0.2, 0.2, 0, 0))
for(x in c("cat","dog")) for(i in 1:36)
  sprintf("4000/train/%s/%s.%d.jpg", x, x, i) %>% 
  image_load(target_size=c(150,150)) %>% 
  image_to_array %>% as.raster(255) %>% plot


0.2 Image Flows from Data Directries

Image dataset might be very large. Instead of reading in the entire dataset, we can generate image flows on the fly by flow_images_from_directory.

img255 = image_data_generator(rescale = 1/255)
Generate = function(x, gen=img255, sz=20) flow_images_from_directory(
  x, gen, 
  target_size = c(150, 150),              # re-size 
  batch_size = sz,                        # batch
  class_mode = "binary"                   # binary labels
  )



1. CNN Model 1: Convolutional Neural Network

1.1 Model Spec.

cnn1 <- keras_model_sequential() %>% 
  layer_conv_2d(filters = 32, kernel_size = c(3, 3), activation = "relu",
                input_shape = c(150, 150, 3)) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 64, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_flatten() %>% 
  layer_dense(units = 512, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")
summary(cnn1)
____________________________________________________________________________________________________________________
Layer (type)                                        Output Shape                                  Param #           
====================================================================================================================
conv2d_1 (Conv2D)                                   (None, 148, 148, 32)                          896               
____________________________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)                      (None, 74, 74, 32)                            0                 
____________________________________________________________________________________________________________________
conv2d_2 (Conv2D)                                   (None, 72, 72, 64)                            18496             
____________________________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)                      (None, 36, 36, 64)                            0                 
____________________________________________________________________________________________________________________
conv2d_3 (Conv2D)                                   (None, 34, 34, 128)                           73856             
____________________________________________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D)                      (None, 17, 17, 128)                           0                 
____________________________________________________________________________________________________________________
conv2d_4 (Conv2D)                                   (None, 15, 15, 128)                           147584            
____________________________________________________________________________________________________________________
max_pooling2d_4 (MaxPooling2D)                      (None, 7, 7, 128)                             0                 
____________________________________________________________________________________________________________________
flatten_1 (Flatten)                                 (None, 6272)                                  0                 
____________________________________________________________________________________________________________________
dense_1 (Dense)                                     (None, 512)                                   3211776           
____________________________________________________________________________________________________________________
dense_2 (Dense)                                     (None, 1)                                     513               
====================================================================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
____________________________________________________________________________________________________________________

No. Coefficient (Param #) in Each Layer

  • conv2d_1: (3 * 3 * 3 + 1) * 32 = 896
  • conv2d_2: (3 * 3 * 32 + 1) * 64 = 18,469

1.2 Training Parameters

cnn1 %>% compile(
  loss = "binary_crossentropy",               #
  optimizer = optimizer_rmsprop(lr = 1e-4),   #
  metrics = c("acc")                          #
  )

1.3 Fitting Model

fit1 <- cnn1 %>% fit_generator(
  Generate("4000/train"),
  steps_per_epoch = 100,
  epochs = 20,
  validation_data = Generate("4000/validation"),
  validation_steps = 50,
  verbose = 2
  )
2018-10-25 23:49:49.546436: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2018-10-25 23:49:49.630987: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:898] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2018-10-25 23:49:49.631354: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1356] Found device 0 with properties: 
name: Tesla K80 major: 3 minor: 7 memoryClockRate(GHz): 0.8235
pciBusID: 0000:00:04.0
totalMemory: 11.17GiB freeMemory: 11.09GiB
2018-10-25 23:49:49.631387: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1435] Adding visible gpu devices: 0
2018-10-25 23:49:49.913681: I tensorflow/core/common_runtime/gpu/gpu_device.cc:923] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-10-25 23:49:49.913742: I tensorflow/core/common_runtime/gpu/gpu_device.cc:929]      0 
2018-10-25 23:49:49.913754: I tensorflow/core/common_runtime/gpu/gpu_device.cc:942] 0:   N 
2018-10-25 23:49:49.914024: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1053] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 10751 MB memory) -> physical GPU (device: 0, name: Tesla K80, pci bus id: 0000:00:04.0, compute capability: 3.7)
Found 1000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/20
 - 18s - loss: 0.6910 - acc: 0.5200 - val_loss: 0.6851 - val_acc: 0.5310
Epoch 2/20
 - 8s - loss: 0.6539 - acc: 0.6250 - val_loss: 0.6552 - val_acc: 0.5900
Epoch 3/20
 - 8s - loss: 0.6134 - acc: 0.6620 - val_loss: 0.6063 - val_acc: 0.6670
Epoch 4/20
 - 8s - loss: 0.5670 - acc: 0.7055 - val_loss: 0.6028 - val_acc: 0.6570
Epoch 5/20
 - 8s - loss: 0.5330 - acc: 0.7300 - val_loss: 0.5919 - val_acc: 0.6730
Epoch 6/20
 - 8s - loss: 0.5055 - acc: 0.7555 - val_loss: 0.6384 - val_acc: 0.6560
Epoch 7/20
 - 8s - loss: 0.4840 - acc: 0.7615 - val_loss: 0.5521 - val_acc: 0.7070
Epoch 8/20
 - 8s - loss: 0.4529 - acc: 0.7825 - val_loss: 0.6371 - val_acc: 0.6780
Epoch 9/20
 - 8s - loss: 0.4364 - acc: 0.7870 - val_loss: 0.5548 - val_acc: 0.7080
Epoch 10/20
 - 8s - loss: 0.4011 - acc: 0.8080 - val_loss: 0.5507 - val_acc: 0.7150
Epoch 11/20
 - 8s - loss: 0.3758 - acc: 0.8335 - val_loss: 0.6531 - val_acc: 0.6910
Epoch 12/20
 - 8s - loss: 0.3608 - acc: 0.8405 - val_loss: 0.5951 - val_acc: 0.7110
Epoch 13/20
 - 8s - loss: 0.3369 - acc: 0.8490 - val_loss: 0.5756 - val_acc: 0.7240
Epoch 14/20
 - 8s - loss: 0.3117 - acc: 0.8675 - val_loss: 0.5579 - val_acc: 0.7250
Epoch 15/20
 - 8s - loss: 0.2893 - acc: 0.8780 - val_loss: 0.5992 - val_acc: 0.7240
Epoch 16/20
 - 8s - loss: 0.2665 - acc: 0.8940 - val_loss: 0.6274 - val_acc: 0.7200
Epoch 17/20
 - 8s - loss: 0.2478 - acc: 0.9020 - val_loss: 0.5875 - val_acc: 0.7250
Epoch 18/20
 - 8s - loss: 0.2151 - acc: 0.9180 - val_loss: 0.6622 - val_acc: 0.7250
Epoch 19/20
 - 8s - loss: 0.1960 - acc: 0.9255 - val_loss: 0.6901 - val_acc: 0.7190
Epoch 20/20
 - 8s - loss: 0.1837 - acc: 0.9310 - val_loss: 0.6334 - val_acc: 0.7350
plot(fit1)



2. CNN Model 2: Data Augmentation

2.1 Create and Test Augmentation Generator

Augment = image_data_generator(
  rescale = 1/255,
  rotation_range = 40,
  width_shift_range = 0.2,
  height_shift_range = 0.2,
  shear_range = 0.2,
  zoom_range = 0.2,
  horizontal_flip = TRUE,
  fill_mode = "nearest"
  )
# Load and Reshape an image for testing
img = image_load("4000/train/cat/cat.28.jpg", target_size=c(150,150)) %>% 
  image_to_array %>% array_reshape(c(1,150,150,3))
# Test the Aug. Generator 
aug = flow_images_from_data(img, generator=Augment, batch_size=1)
par(mfrow = c(2, 6), pty = "s", mar = c(0.5, 0.5, 0, 0))
for (i in 1:12) generator_next(aug)[1,,,] %>% as.raster %>% plot


2.2 Model Spec. & Training Parameters

cnn2 <- keras_model_sequential() %>% 
  layer_conv_2d(filters = 32, kernel_size = c(3, 3), activation = "relu",
                input_shape = c(150, 150, 3)) %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 64, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_conv_2d(filters = 128, kernel_size = c(3, 3), activation = "relu") %>% 
  layer_max_pooling_2d(pool_size = c(2, 2)) %>% 
  layer_flatten() %>% 
  layer_dropout(rate = 0.5) %>%     # add a dropout layer to mitigate OF
  layer_dense(units = 512, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")  
cnn2 %>% compile(
  loss = "binary_crossentropy",
  optimizer = optimizer_rmsprop(lr = 1e-4),
  metrics = c("acc")
)
summary(cnn2)
____________________________________________________________________________________________________________________
Layer (type)                                        Output Shape                                  Param #           
====================================================================================================================
conv2d_5 (Conv2D)                                   (None, 148, 148, 32)                          896               
____________________________________________________________________________________________________________________
max_pooling2d_5 (MaxPooling2D)                      (None, 74, 74, 32)                            0                 
____________________________________________________________________________________________________________________
conv2d_6 (Conv2D)                                   (None, 72, 72, 64)                            18496             
____________________________________________________________________________________________________________________
max_pooling2d_6 (MaxPooling2D)                      (None, 36, 36, 64)                            0                 
____________________________________________________________________________________________________________________
conv2d_7 (Conv2D)                                   (None, 34, 34, 128)                           73856             
____________________________________________________________________________________________________________________
max_pooling2d_7 (MaxPooling2D)                      (None, 17, 17, 128)                           0                 
____________________________________________________________________________________________________________________
conv2d_8 (Conv2D)                                   (None, 15, 15, 128)                           147584            
____________________________________________________________________________________________________________________
max_pooling2d_8 (MaxPooling2D)                      (None, 7, 7, 128)                             0                 
____________________________________________________________________________________________________________________
flatten_2 (Flatten)                                 (None, 6272)                                  0                 
____________________________________________________________________________________________________________________
dropout_1 (Dropout)                                 (None, 6272)                                  0                 
____________________________________________________________________________________________________________________
dense_3 (Dense)                                     (None, 512)                                   3211776           
____________________________________________________________________________________________________________________
dense_4 (Dense)                                     (None, 1)                                     513               
====================================================================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
____________________________________________________________________________________________________________________

3.3 Fitting Model

fit2 <- cnn2 %>% fit_generator(
  Generate("4000/train", Augment, 40),
  steps_per_epoch = 100,
  epochs = 50,
  validation_data = Generate("4000/validation"),
  validation_steps = 50,
  verbose=2
  )
Found 1000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/50
 - 33s - loss: 0.6917 - acc: 0.5195 - val_loss: 0.6852 - val_acc: 0.5010
Epoch 2/50
 - 30s - loss: 0.6809 - acc: 0.5720 - val_loss: 0.6618 - val_acc: 0.5930
Epoch 3/50
 - 30s - loss: 0.6675 - acc: 0.5998 - val_loss: 0.6355 - val_acc: 0.6420
Epoch 4/50
 - 30s - loss: 0.6583 - acc: 0.6148 - val_loss: 0.6224 - val_acc: 0.6740
Epoch 5/50
 - 30s - loss: 0.6416 - acc: 0.6288 - val_loss: 0.6051 - val_acc: 0.6740
Epoch 6/50
 - 30s - loss: 0.6356 - acc: 0.6452 - val_loss: 0.6144 - val_acc: 0.6560
Epoch 7/50
 - 30s - loss: 0.6212 - acc: 0.6655 - val_loss: 0.5652 - val_acc: 0.7070
Epoch 8/50
 - 30s - loss: 0.6091 - acc: 0.6690 - val_loss: 0.5504 - val_acc: 0.7280
Epoch 9/50
 - 30s - loss: 0.5997 - acc: 0.6768 - val_loss: 0.5690 - val_acc: 0.7030
Epoch 10/50
 - 30s - loss: 0.5950 - acc: 0.6757 - val_loss: 0.5582 - val_acc: 0.7160
Epoch 11/50
 - 30s - loss: 0.5812 - acc: 0.6942 - val_loss: 0.5195 - val_acc: 0.7540
Epoch 12/50
 - 30s - loss: 0.5718 - acc: 0.7030 - val_loss: 0.5290 - val_acc: 0.7420
Epoch 13/50
 - 31s - loss: 0.5621 - acc: 0.7098 - val_loss: 0.5624 - val_acc: 0.7000
Epoch 14/50
 - 30s - loss: 0.5561 - acc: 0.7135 - val_loss: 0.5291 - val_acc: 0.7260
Epoch 15/50
 - 31s - loss: 0.5486 - acc: 0.7240 - val_loss: 0.5103 - val_acc: 0.7410
Epoch 16/50
 - 30s - loss: 0.5536 - acc: 0.7170 - val_loss: 0.5348 - val_acc: 0.7150
Epoch 17/50
 - 30s - loss: 0.5428 - acc: 0.7265 - val_loss: 0.5641 - val_acc: 0.7130
Epoch 18/50
 - 30s - loss: 0.5329 - acc: 0.7337 - val_loss: 0.5783 - val_acc: 0.7000
Epoch 19/50
 - 30s - loss: 0.5364 - acc: 0.7315 - val_loss: 0.5178 - val_acc: 0.7470
Epoch 20/50
 - 30s - loss: 0.5293 - acc: 0.7245 - val_loss: 0.4966 - val_acc: 0.7510
Epoch 21/50
 - 30s - loss: 0.5241 - acc: 0.7390 - val_loss: 0.4988 - val_acc: 0.7480
Epoch 22/50
 - 30s - loss: 0.5191 - acc: 0.7398 - val_loss: 0.4853 - val_acc: 0.7690
Epoch 23/50
 - 30s - loss: 0.5105 - acc: 0.7488 - val_loss: 0.4788 - val_acc: 0.7550
Epoch 24/50
 - 30s - loss: 0.5164 - acc: 0.7405 - val_loss: 0.4660 - val_acc: 0.7770
Epoch 25/50
 - 31s - loss: 0.5057 - acc: 0.7505 - val_loss: 0.4684 - val_acc: 0.7840
Epoch 26/50
 - 30s - loss: 0.4958 - acc: 0.7525 - val_loss: 0.4927 - val_acc: 0.7580
Epoch 27/50
 - 30s - loss: 0.5007 - acc: 0.7523 - val_loss: 0.4685 - val_acc: 0.7820
Epoch 28/50
 - 31s - loss: 0.4929 - acc: 0.7582 - val_loss: 0.4691 - val_acc: 0.7860
Epoch 29/50
 - 30s - loss: 0.4904 - acc: 0.7573 - val_loss: 0.4594 - val_acc: 0.7860
Epoch 30/50
 - 30s - loss: 0.4844 - acc: 0.7582 - val_loss: 0.4599 - val_acc: 0.7950
Epoch 31/50
 - 31s - loss: 0.4859 - acc: 0.7660 - val_loss: 0.4592 - val_acc: 0.7780
Epoch 32/50
 - 30s - loss: 0.4887 - acc: 0.7640 - val_loss: 0.4513 - val_acc: 0.7840
Epoch 33/50
 - 30s - loss: 0.4801 - acc: 0.7647 - val_loss: 0.5167 - val_acc: 0.7430
Epoch 34/50
 - 30s - loss: 0.4735 - acc: 0.7717 - val_loss: 0.4582 - val_acc: 0.7790
Epoch 35/50
 - 30s - loss: 0.4720 - acc: 0.7670 - val_loss: 0.4754 - val_acc: 0.7600
Epoch 36/50
 - 30s - loss: 0.4619 - acc: 0.7793 - val_loss: 0.4559 - val_acc: 0.7910
Epoch 37/50
 - 30s - loss: 0.4595 - acc: 0.7815 - val_loss: 0.4634 - val_acc: 0.7860
Epoch 38/50
 - 30s - loss: 0.4683 - acc: 0.7765 - val_loss: 0.4491 - val_acc: 0.7840
Epoch 39/50
 - 30s - loss: 0.4627 - acc: 0.7823 - val_loss: 0.4755 - val_acc: 0.7730
Epoch 40/50
 - 30s - loss: 0.4587 - acc: 0.7790 - val_loss: 0.4488 - val_acc: 0.7800
Epoch 41/50
 - 30s - loss: 0.4535 - acc: 0.7902 - val_loss: 0.4487 - val_acc: 0.7900
Epoch 42/50
 - 30s - loss: 0.4491 - acc: 0.7945 - val_loss: 0.4191 - val_acc: 0.8110
Epoch 43/50
 - 30s - loss: 0.4378 - acc: 0.7968 - val_loss: 0.4702 - val_acc: 0.7790
Epoch 44/50
 - 30s - loss: 0.4455 - acc: 0.7910 - val_loss: 0.4231 - val_acc: 0.8070
Epoch 45/50
 - 30s - loss: 0.4489 - acc: 0.7847 - val_loss: 0.4677 - val_acc: 0.7660
Epoch 46/50
 - 30s - loss: 0.4449 - acc: 0.7915 - val_loss: 0.4236 - val_acc: 0.8030
Epoch 47/50
 - 30s - loss: 0.4423 - acc: 0.7940 - val_loss: 0.4477 - val_acc: 0.7790
Epoch 48/50
 - 30s - loss: 0.4368 - acc: 0.8067 - val_loss: 0.4407 - val_acc: 0.7770
Epoch 49/50
 - 30s - loss: 0.4310 - acc: 0.7960 - val_loss: 0.4329 - val_acc: 0.7950
Epoch 50/50
 - 30s - loss: 0.4319 - acc: 0.7988 - val_loss: 0.4294 - val_acc: 0.8010
plot(fit2)



3. CNN Model 3: PreTrain CNN with Data Aug.

3.1 Load VGG16 Pretrained Model

conv_base <- application_vgg16(
  weights = "imagenet",
  include_top = FALSE,
  input_shape = c(150, 150, 3))
summary(conv_base)
____________________________________________________________________________________________________________________
Layer (type)                                        Output Shape                                  Param #           
====================================================================================================================
input_1 (InputLayer)                                (None, 150, 150, 3)                           0                 
____________________________________________________________________________________________________________________
block1_conv1 (Conv2D)                               (None, 150, 150, 64)                          1792              
____________________________________________________________________________________________________________________
block1_conv2 (Conv2D)                               (None, 150, 150, 64)                          36928             
____________________________________________________________________________________________________________________
block1_pool (MaxPooling2D)                          (None, 75, 75, 64)                            0                 
____________________________________________________________________________________________________________________
block2_conv1 (Conv2D)                               (None, 75, 75, 128)                           73856             
____________________________________________________________________________________________________________________
block2_conv2 (Conv2D)                               (None, 75, 75, 128)                           147584            
____________________________________________________________________________________________________________________
block2_pool (MaxPooling2D)                          (None, 37, 37, 128)                           0                 
____________________________________________________________________________________________________________________
block3_conv1 (Conv2D)                               (None, 37, 37, 256)                           295168            
____________________________________________________________________________________________________________________
block3_conv2 (Conv2D)                               (None, 37, 37, 256)                           590080            
____________________________________________________________________________________________________________________
block3_conv3 (Conv2D)                               (None, 37, 37, 256)                           590080            
____________________________________________________________________________________________________________________
block3_pool (MaxPooling2D)                          (None, 18, 18, 256)                           0                 
____________________________________________________________________________________________________________________
block4_conv1 (Conv2D)                               (None, 18, 18, 512)                           1180160           
____________________________________________________________________________________________________________________
block4_conv2 (Conv2D)                               (None, 18, 18, 512)                           2359808           
____________________________________________________________________________________________________________________
block4_conv3 (Conv2D)                               (None, 18, 18, 512)                           2359808           
____________________________________________________________________________________________________________________
block4_pool (MaxPooling2D)                          (None, 9, 9, 512)                             0                 
____________________________________________________________________________________________________________________
block5_conv1 (Conv2D)                               (None, 9, 9, 512)                             2359808           
____________________________________________________________________________________________________________________
block5_conv2 (Conv2D)                               (None, 9, 9, 512)                             2359808           
____________________________________________________________________________________________________________________
block5_conv3 (Conv2D)                               (None, 9, 9, 512)                             2359808           
____________________________________________________________________________________________________________________
block5_pool (MaxPooling2D)                          (None, 4, 4, 512)                             0                 
====================================================================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
____________________________________________________________________________________________________________________

3.2 Combine VGG16 with Output Layers

cnn3 <- keras_model_sequential() %>% 
  conv_base %>% 
  layer_flatten() %>% 
  layer_dense(units = 256, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")  
summary(cnn3)
____________________________________________________________________________________________________________________
Layer (type)                                        Output Shape                                  Param #           
====================================================================================================================
vgg16 (Model)                                       (None, 4, 4, 512)                             14714688          
____________________________________________________________________________________________________________________
flatten_3 (Flatten)                                 (None, 8192)                                  0                 
____________________________________________________________________________________________________________________
dense_5 (Dense)                                     (None, 256)                                   2097408           
____________________________________________________________________________________________________________________
dense_6 (Dense)                                     (None, 1)                                     257               
====================================================================================================================
Total params: 16,812,353
Trainable params: 16,812,353
Non-trainable params: 0
____________________________________________________________________________________________________________________

3.3 Freeze the VGG16 Layers

length(cnn3$trainable_weights)  # 30
[1] 30
freeze_weights(conv_base)
length(cnn3$trainable_weights)  # 4
[1] 4

3.4 Compile the Modle with Training Parameters

cnn3 %>% compile(
  loss = "binary_crossentropy",
  optimizer = optimizer_rmsprop(lr = 2e-5),
  metrics = c("accuracy"))

3.5 First Stage Fitting

fit3 <- cnn3 %>% fit_generator(
  Generate("4000/train",Augment,40),
  steps_per_epoch = 100,
  epochs = 30,
  validation_data = Generate("4000/validation"),
  validation_steps = 50,
  verbose = 2
  )
Found 1000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/30
 - 39s - loss: 0.5919 - acc: 0.6877 - val_loss: 0.4274 - val_acc: 0.8340
Epoch 2/30
 - 34s - loss: 0.4684 - acc: 0.7950 - val_loss: 0.3471 - val_acc: 0.8680
Epoch 3/30
 - 35s - loss: 0.4074 - acc: 0.8237 - val_loss: 0.3072 - val_acc: 0.8780
Epoch 4/30
 - 35s - loss: 0.3787 - acc: 0.8337 - val_loss: 0.2923 - val_acc: 0.8830
Epoch 5/30
 - 35s - loss: 0.3662 - acc: 0.8437 - val_loss: 0.2759 - val_acc: 0.8890
Epoch 6/30
 - 35s - loss: 0.3465 - acc: 0.8505 - val_loss: 0.2683 - val_acc: 0.8870
Epoch 7/30
 - 36s - loss: 0.3456 - acc: 0.8543 - val_loss: 0.2650 - val_acc: 0.8920
Epoch 8/30
 - 35s - loss: 0.3303 - acc: 0.8555 - val_loss: 0.2571 - val_acc: 0.8980
Epoch 9/30
 - 34s - loss: 0.3213 - acc: 0.8610 - val_loss: 0.2498 - val_acc: 0.8930
Epoch 10/30
 - 35s - loss: 0.3214 - acc: 0.8605 - val_loss: 0.2485 - val_acc: 0.8980
Epoch 11/30
 - 36s - loss: 0.3149 - acc: 0.8632 - val_loss: 0.2513 - val_acc: 0.8970
Epoch 12/30
 - 35s - loss: 0.2986 - acc: 0.8728 - val_loss: 0.2410 - val_acc: 0.9050
Epoch 13/30
 - 36s - loss: 0.3053 - acc: 0.8678 - val_loss: 0.2388 - val_acc: 0.9040
Epoch 14/30
 - 35s - loss: 0.2975 - acc: 0.8698 - val_loss: 0.2377 - val_acc: 0.9030
Epoch 15/30
 - 35s - loss: 0.2954 - acc: 0.8725 - val_loss: 0.2373 - val_acc: 0.9000
Epoch 16/30
 - 36s - loss: 0.3016 - acc: 0.8695 - val_loss: 0.2353 - val_acc: 0.9020
Epoch 17/30
 - 35s - loss: 0.2919 - acc: 0.8735 - val_loss: 0.2337 - val_acc: 0.9100
Epoch 18/30
 - 35s - loss: 0.2811 - acc: 0.8765 - val_loss: 0.2350 - val_acc: 0.9040
Epoch 19/30
 - 34s - loss: 0.2863 - acc: 0.8793 - val_loss: 0.2477 - val_acc: 0.8980
Epoch 20/30
 - 35s - loss: 0.2795 - acc: 0.8810 - val_loss: 0.2342 - val_acc: 0.9050
Epoch 21/30
 - 35s - loss: 0.2832 - acc: 0.8765 - val_loss: 0.2385 - val_acc: 0.9060
Epoch 22/30
 - 36s - loss: 0.2813 - acc: 0.8710 - val_loss: 0.2361 - val_acc: 0.9050
Epoch 23/30
 - 34s - loss: 0.2823 - acc: 0.8775 - val_loss: 0.2402 - val_acc: 0.9060
Epoch 24/30
 - 35s - loss: 0.2852 - acc: 0.8697 - val_loss: 0.2349 - val_acc: 0.9100
Epoch 25/30
 - 35s - loss: 0.2712 - acc: 0.8830 - val_loss: 0.2300 - val_acc: 0.9030
Epoch 26/30
 - 35s - loss: 0.2695 - acc: 0.8860 - val_loss: 0.2371 - val_acc: 0.9030
Epoch 27/30
 - 34s - loss: 0.2694 - acc: 0.8830 - val_loss: 0.2382 - val_acc: 0.9060
Epoch 28/30
 - 35s - loss: 0.2656 - acc: 0.8845 - val_loss: 0.2340 - val_acc: 0.9020
Epoch 29/30
 - 35s - loss: 0.2661 - acc: 0.8870 - val_loss: 0.2330 - val_acc: 0.9050
Epoch 30/30
 - 35s - loss: 0.2748 - acc: 0.8910 - val_loss: 0.2318 - val_acc: 0.9030
plot(fit3)

3.6 Unfreeze the Lower Layers

unfreeze_weights(conv_base, from = "block5_conv1")
length(cnn3$trainable_weights)  # 10
[1] 10

3.7 Re-Compile with Adjusted Training Parameters

cnn3 %>% compile(
  loss = "binary_crossentropy",
  optimizer = optimizer_rmsprop(lr = 1e-5),
  metrics = c("accuracy")
  )

3.8 Second Stage Fitting

fit3a = cnn3 %>% fit_generator(
  Generate("4000/train",Augment,40),
  steps_per_epoch = 100,
  epochs = 50,
  validation_data = Generate("4000/validation"),
  validation_steps = 50,
  verbose = 2
  )
Found 1000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/50
 - 38s - loss: 0.2642 - acc: 0.8850 - val_loss: 0.2159 - val_acc: 0.9160
Epoch 2/50
 - 36s - loss: 0.2348 - acc: 0.9030 - val_loss: 0.2232 - val_acc: 0.9130
Epoch 3/50
 - 36s - loss: 0.1975 - acc: 0.9165 - val_loss: 0.2083 - val_acc: 0.9170
Epoch 4/50
 - 35s - loss: 0.1805 - acc: 0.9253 - val_loss: 0.2018 - val_acc: 0.9230
Epoch 5/50
 - 36s - loss: 0.1618 - acc: 0.9318 - val_loss: 0.1920 - val_acc: 0.9270
Epoch 6/50
 - 35s - loss: 0.1427 - acc: 0.9450 - val_loss: 0.1912 - val_acc: 0.9270
Epoch 7/50
 - 36s - loss: 0.1480 - acc: 0.9390 - val_loss: 0.2209 - val_acc: 0.9210
Epoch 8/50
 - 36s - loss: 0.1398 - acc: 0.9400 - val_loss: 0.1887 - val_acc: 0.9230
Epoch 9/50
 - 35s - loss: 0.1303 - acc: 0.9485 - val_loss: 0.1914 - val_acc: 0.9290
Epoch 10/50
 - 36s - loss: 0.1182 - acc: 0.9510 - val_loss: 0.1847 - val_acc: 0.9340
Epoch 11/50
 - 35s - loss: 0.1004 - acc: 0.9588 - val_loss: 0.2247 - val_acc: 0.9310
Epoch 12/50
 - 35s - loss: 0.1006 - acc: 0.9588 - val_loss: 0.2071 - val_acc: 0.9260
Epoch 13/50
 - 36s - loss: 0.1000 - acc: 0.9615 - val_loss: 0.1759 - val_acc: 0.9330
Epoch 14/50
 - 35s - loss: 0.0833 - acc: 0.9653 - val_loss: 0.2062 - val_acc: 0.9290
Epoch 15/50
 - 36s - loss: 0.0796 - acc: 0.9710 - val_loss: 0.2063 - val_acc: 0.9280
Epoch 16/50
 - 36s - loss: 0.0722 - acc: 0.9730 - val_loss: 0.1964 - val_acc: 0.9230
Epoch 17/50
 - 36s - loss: 0.0653 - acc: 0.9763 - val_loss: 0.2214 - val_acc: 0.9240
Epoch 18/50
 - 36s - loss: 0.0701 - acc: 0.9738 - val_loss: 0.1895 - val_acc: 0.9330
Epoch 19/50
 - 36s - loss: 0.0680 - acc: 0.9748 - val_loss: 0.2099 - val_acc: 0.9330
Epoch 20/50
 - 36s - loss: 0.0653 - acc: 0.9753 - val_loss: 0.2050 - val_acc: 0.9340
Epoch 21/50
 - 36s - loss: 0.0636 - acc: 0.9768 - val_loss: 0.2192 - val_acc: 0.9310
Epoch 22/50
 - 36s - loss: 0.0655 - acc: 0.9738 - val_loss: 0.2239 - val_acc: 0.9290
Epoch 23/50
 - 36s - loss: 0.0464 - acc: 0.9843 - val_loss: 0.3727 - val_acc: 0.9050
Epoch 24/50
 - 36s - loss: 0.0559 - acc: 0.9798 - val_loss: 0.2330 - val_acc: 0.9310
Epoch 25/50
 - 36s - loss: 0.0474 - acc: 0.9830 - val_loss: 0.2382 - val_acc: 0.9320
Epoch 26/50
 - 37s - loss: 0.0450 - acc: 0.9848 - val_loss: 0.2350 - val_acc: 0.9310
Epoch 27/50
 - 37s - loss: 0.0381 - acc: 0.9868 - val_loss: 0.2185 - val_acc: 0.9360
Epoch 28/50
 - 36s - loss: 0.0471 - acc: 0.9818 - val_loss: 0.2467 - val_acc: 0.9310
Epoch 29/50
 - 36s - loss: 0.0397 - acc: 0.9855 - val_loss: 0.2293 - val_acc: 0.9370
Epoch 30/50
 - 36s - loss: 0.0395 - acc: 0.9848 - val_loss: 0.2118 - val_acc: 0.9390
Epoch 31/50
 - 37s - loss: 0.0350 - acc: 0.9890 - val_loss: 0.2448 - val_acc: 0.9290
Epoch 32/50
 - 36s - loss: 0.0377 - acc: 0.9870 - val_loss: 0.2566 - val_acc: 0.9300
Epoch 33/50
 - 36s - loss: 0.0364 - acc: 0.9885 - val_loss: 0.2254 - val_acc: 0.9330
Epoch 34/50
 - 36s - loss: 0.0369 - acc: 0.9863 - val_loss: 0.2454 - val_acc: 0.9330
Epoch 35/50
 - 36s - loss: 0.0374 - acc: 0.9865 - val_loss: 0.2738 - val_acc: 0.9260
Epoch 36/50
 - 36s - loss: 0.0290 - acc: 0.9898 - val_loss: 0.2836 - val_acc: 0.9270
Epoch 37/50
 - 36s - loss: 0.0309 - acc: 0.9883 - val_loss: 0.5626 - val_acc: 0.8870
Epoch 38/50
 - 37s - loss: 0.0310 - acc: 0.9875 - val_loss: 0.2399 - val_acc: 0.9410
Epoch 39/50
 - 35s - loss: 0.0315 - acc: 0.9870 - val_loss: 0.2459 - val_acc: 0.9360
Epoch 40/50
 - 36s - loss: 0.0268 - acc: 0.9918 - val_loss: 0.2156 - val_acc: 0.9390
Epoch 41/50
 - 36s - loss: 0.0336 - acc: 0.9885 - val_loss: 0.2183 - val_acc: 0.9400
Epoch 42/50
 - 37s - loss: 0.0225 - acc: 0.9930 - val_loss: 0.2226 - val_acc: 0.9420
Epoch 43/50
 - 35s - loss: 0.0266 - acc: 0.9923 - val_loss: 0.2205 - val_acc: 0.9340
Epoch 44/50
 - 35s - loss: 0.0250 - acc: 0.9930 - val_loss: 0.2575 - val_acc: 0.9340
Epoch 45/50
 - 35s - loss: 0.0305 - acc: 0.9898 - val_loss: 0.2319 - val_acc: 0.9370
Epoch 46/50
 - 35s - loss: 0.0202 - acc: 0.9930 - val_loss: 0.2753 - val_acc: 0.9250
Epoch 47/50
 - 36s - loss: 0.0256 - acc: 0.9905 - val_loss: 0.2250 - val_acc: 0.9350
Epoch 48/50
 - 35s - loss: 0.0253 - acc: 0.9925 - val_loss: 0.2282 - val_acc: 0.9410
Epoch 49/50
 - 35s - loss: 0.0199 - acc: 0.9945 - val_loss: 0.2735 - val_acc: 0.9350
Epoch 50/50
 - 35s - loss: 0.0253 - acc: 0.9915 - val_loss: 0.2394 - val_acc: 0.9400
plot(fit3a)

3.9 Test Accuracy

cnn3 %>% evaluate_generator(Generate("4000/test"), steps = 50) # acc = 0.933
$loss
[1] 0.2751

$acc
[1] 0.938





LS0tCnRpdGxlOiAiRG9nIGFuZCBDYXQ6IEltYWdlIFJlY29uZ25pdGlvbiIKYXV0aG9yOiAidG9ueWNodW9AbWFpbC5uc3lzdS5lZHUudHciCmRhdGU6ICJgciBTeXMudGltZSgpYCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKPGJyPgpgYGB7ciBzZXQtb3B0aW9ucywgZWNobz1GQUxTRSwgY2FjaGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCm9wdGlvbnMod2lkdGg9MTAwKQpvcHRzX2NodW5rJHNldChjb21tZW50ID0gTkEpCmBgYAoKYGBge3IgIHdhcm5pbmc9RiwgbWVzc2FnZT1GLCBjYWNoZT1GLCBlcnJvcj1GfQpybShsaXN0PWxzKGFsbD1UKSkKb3B0aW9ucyhkaWdpdHM9NCwgc2NpcGVuPTQwKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGtlcmFzKQpgYGAKPGJyPgoKLSAtIC0KCiMjIyAwLiBQcmVwYXJpbmcgRGF0YQoKIyMjIyAwLjEgSW1hZ2VzIEZpbGUgRGlyZWN0b3JpZXMKVHJhaW5tIFRlc3QgYW5kIFZhbGlkYXRpb24gSW1hZ2VzIGZpbGVzIHdlcmUgb3JnYW5pemVkIHVuZGVyIGRpcmVjdG9yaWVzOiA8YnI+Cgo8cD4KJmVtc3A7IGA0MDAwL2AgPGJyPgomZW1zcDsgJmVtc3A7IGB0cmFpbi9gIDogdHJhaW5pbmcgZGF0YSA8YnI+CiZlbXNwOyAmZW1zcDsgJmVtc3A7ICZlbXNwOyBgY2F0L2AgOiBgY2F0LjEuanBnYCB+IGBjYXQuMTAwMC5qcGdgIDxicj4KJmVtc3A7ICZlbXNwOyAmZW1zcDsgJmVtc3A7IGBkb2cvYCA6IGBkb2cuMS5qcGdgIH4gYGRvZy4xMDAwLmpwZ2AgPGJyPgomZW1zcDsgJmVtc3A7IGB2YWxpZGF0aW9uL2AgOiB2YWxpZGF0aW9uIGRhdGEgPGJyPgomZW1zcDsgJmVtc3A7ICZlbXNwOyAmZW1zcDsgYGNhdC9gIDogYGNhdC4xMDAxLmpwZ2AgfiBgY2F0LjE1MDAuanBnYCA8YnI+CiZlbXNwOyAmZW1zcDsgJmVtc3A7ICZlbXNwOyBgZG9nL2AgOiBgZG9nLjEwMDEuanBnYCB+IGBkb2cuMTUwMC5qcGdgIDxicj4KJmVtc3A7ICZlbXNwOyBgdGVzdC9gIDogdGVzdCBkYXRhIDxicj4KJmVtc3A7ICZlbXNwOyAmZW1zcDsgJmVtc3A7IGBjYXQvYCA6IGBjYXQuMTUwMS5qcGdgIH4gYGNhdC4yMDAwLmpwZ2AgPGJyPgomZW1zcDsgJmVtc3A7ICZlbXNwOyAmZW1zcDsgYGRvZy9gIDogYGRvZy4xNTAxLmpwZ2AgfiBgZG9nLjIwMDAuanBnYCA8YnI+CjwvcD4KCmBgYHtyIGZpZy5oZWlnaHQ9NC41LCBmaWcud2lkdGg9OX0KIyMgU2FtcGxlIEltYWdlcwpwYXIobWZyb3cgPSBjKDYsIDEyKSwgcHR5ID0gInMiLCBtYXIgPSBjKDAuMiwgMC4yLCAwLCAwKSkKZm9yKHggaW4gYygiY2F0IiwiZG9nIikpIGZvcihpIGluIDE6MzYpCiAgc3ByaW50ZigiNDAwMC90cmFpbi8lcy8lcy4lZC5qcGciLCB4LCB4LCBpKSAlPiUgCiAgaW1hZ2VfbG9hZCh0YXJnZXRfc2l6ZT1jKDE1MCwxNTApKSAlPiUgCiAgaW1hZ2VfdG9fYXJyYXkgJT4lIGFzLnJhc3RlcigyNTUpICU+JSBwbG90CmBgYAo8YnI+CgojIyMjIDAuMiBJbWFnZSBGbG93cyBmcm9tIERhdGEgRGlyZWN0cmllcwpJbWFnZSBkYXRhc2V0IG1pZ2h0IGJlIHZlcnkgbGFyZ2UuIEluc3RlYWQgb2YgcmVhZGluZyBpbiB0aGUgZW50aXJlIGRhdGFzZXQsIHdlIGNhbiBnZW5lcmF0ZSBpbWFnZSBmbG93cyBvbiB0aGUgZmx5IGJ5IGBmbG93X2ltYWdlc19mcm9tX2RpcmVjdG9yeWAuCmBgYHtyfQppbWcyNTUgPSBpbWFnZV9kYXRhX2dlbmVyYXRvcihyZXNjYWxlID0gMS8yNTUpCkdlbmVyYXRlID0gZnVuY3Rpb24oeCwgZ2VuPWltZzI1NSwgc3o9MjApIGZsb3dfaW1hZ2VzX2Zyb21fZGlyZWN0b3J5KAogIHgsIGdlbiwgCiAgdGFyZ2V0X3NpemUgPSBjKDE1MCwgMTUwKSwgICAgICAgICAgICAgICMgcmUtc2l6ZSAKICBiYXRjaF9zaXplID0gc3osICAgICAgICAgICAgICAgICAgICAgICAgIyBiYXRjaCBzaXplICgnc3onKQogIGNsYXNzX21vZGUgPSAiYmluYXJ5IiAgICAgICAgICAgICAgICAgICAjIGJpbmFyeSBsYWJlbHMKICApCmBgYAo8YnI+CgotIC0gLQoKIyMjIDEuIENOTiBNb2RlbCAxOiBDb252b2x1dGlvbmFsIE5ldXJhbCBOZXR3b3JrCgojIyMjIDEuMSBNb2RlbCBTcGVjLgpgYGB7cn0KY25uMSA8LSBrZXJhc19tb2RlbF9zZXF1ZW50aWFsKCkgJT4lIAogIGxheWVyX2NvbnZfMmQoZmlsdGVycyA9IDMyLCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIsCiAgICAgICAgICAgICAgICBpbnB1dF9zaGFwZSA9IGMoMTUwLCAxNTAsIDMpKSAlPiUgCiAgbGF5ZXJfbWF4X3Bvb2xpbmdfMmQocG9vbF9zaXplID0gYygyLCAyKSkgJT4lIAogIGxheWVyX2NvbnZfMmQoZmlsdGVycyA9IDY0LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfY29udl8yZChmaWx0ZXJzID0gMTI4LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfY29udl8yZChmaWx0ZXJzID0gMTI4LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfZmxhdHRlbigpICU+JSAKICBsYXllcl9kZW5zZSh1bml0cyA9IDUxMiwgYWN0aXZhdGlvbiA9ICJyZWx1IikgJT4lIAogIGxheWVyX2RlbnNlKHVuaXRzID0gMSwgYWN0aXZhdGlvbiA9ICJzaWdtb2lkIikKCnN1bW1hcnkoY25uMSkKYGBgCgpOby4gQ29lZmZpY2llbnQgKGBQYXJhbSAjYCkgaW4gRWFjaCBMYXllcgoKKyBgY29udjJkXzE6ICgzICogMyAqIDMgKyAxKSAgICogMzIgPSA4OTZgIAorIGBjb252MmRfMjogKDMgKiAzICogMzIgICsgMSkgKiA2NCA9IDE4LDQ2OWAgCjxicj4KCgoKIyMjIyAxLjIgVHJhaW5pbmcgUGFyYW1ldGVycwpgYGB7cn0KY25uMSAlPiUgY29tcGlsZSgKICBsb3NzID0gImJpbmFyeV9jcm9zc2VudHJvcHkiLCAgICAgICAgICAgICAgICMKICBvcHRpbWl6ZXIgPSBvcHRpbWl6ZXJfcm1zcHJvcChsciA9IDFlLTQpLCAgICMKICBtZXRyaWNzID0gYygiYWNjIikgICAgICAgICAgICAgICAgICAgICAgICAgICMKICApCmBgYAoKIyMjIyAxLjMgRml0dGluZyBNb2RlbApgYGB7cn0KZml0MSA8LSBjbm4xICU+JSBmaXRfZ2VuZXJhdG9yKAogIEdlbmVyYXRlKCI0MDAwL3RyYWluIiksCiAgc3RlcHNfcGVyX2Vwb2NoID0gMTAwLAogIGVwb2NocyA9IDIwLAogIHZhbGlkYXRpb25fZGF0YSA9IEdlbmVyYXRlKCI0MDAwL3ZhbGlkYXRpb24iKSwKICB2YWxpZGF0aW9uX3N0ZXBzID0gNTAsCiAgdmVyYm9zZSA9IDIKICApCmBgYAoKYGBge3J9CnBsb3QoZml0MSkKYGBgCjxicj4KCi0gLSAtCgojIyMgMi4gQ05OIE1vZGVsIDI6IERhdGEgQXVnbWVudGF0aW9uCgojIyMjIDIuMSBDcmVhdGUgYW5kIFRlc3QgQXVnbWVudGF0aW9uIEdlbmVyYXRvcgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD05fQpBdWdtZW50ID0gaW1hZ2VfZGF0YV9nZW5lcmF0b3IoCiAgcmVzY2FsZSA9IDEvMjU1LAogIHJvdGF0aW9uX3JhbmdlID0gNDAsCiAgd2lkdGhfc2hpZnRfcmFuZ2UgPSAwLjIsCiAgaGVpZ2h0X3NoaWZ0X3JhbmdlID0gMC4yLAogIHNoZWFyX3JhbmdlID0gMC4yLAogIHpvb21fcmFuZ2UgPSAwLjIsCiAgaG9yaXpvbnRhbF9mbGlwID0gVFJVRSwKICBmaWxsX21vZGUgPSAibmVhcmVzdCIKICApCgojIExvYWQgYW5kIFJlc2hhcGUgYW4gaW1hZ2UgZm9yIHRlc3RpbmcKaW1nID0gaW1hZ2VfbG9hZCgiNDAwMC90cmFpbi9jYXQvY2F0LjI4LmpwZyIsIHRhcmdldF9zaXplPWMoMTUwLDE1MCkpICU+JSAKICBpbWFnZV90b19hcnJheSAlPiUgYXJyYXlfcmVzaGFwZShjKDEsMTUwLDE1MCwzKSkKCiMgVGVzdCB0aGUgQXVnLiBHZW5lcmF0b3IgCmF1ZyA9IGZsb3dfaW1hZ2VzX2Zyb21fZGF0YShpbWcsIGdlbmVyYXRvcj1BdWdtZW50LCBiYXRjaF9zaXplPTEpCnBhcihtZnJvdyA9IGMoMiwgNiksIHB0eSA9ICJzIiwgbWFyID0gYygwLjUsIDAuNSwgMCwgMCkpCmZvciAoaSBpbiAxOjEyKSBnZW5lcmF0b3JfbmV4dChhdWcpWzEsLCxdICU+JSBhcy5yYXN0ZXIgJT4lIHBsb3QKYGBgCjxicj4KCiMjIyMgMi4yIE1vZGVsIFNwZWMuICYgVHJhaW5pbmcgUGFyYW1ldGVycwpgYGB7cn0KY25uMiA8LSBrZXJhc19tb2RlbF9zZXF1ZW50aWFsKCkgJT4lIAogIGxheWVyX2NvbnZfMmQoZmlsdGVycyA9IDMyLCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIsCiAgICAgICAgICAgICAgICBpbnB1dF9zaGFwZSA9IGMoMTUwLCAxNTAsIDMpKSAlPiUgCiAgbGF5ZXJfbWF4X3Bvb2xpbmdfMmQocG9vbF9zaXplID0gYygyLCAyKSkgJT4lIAogIGxheWVyX2NvbnZfMmQoZmlsdGVycyA9IDY0LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfY29udl8yZChmaWx0ZXJzID0gMTI4LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfY29udl8yZChmaWx0ZXJzID0gMTI4LCBrZXJuZWxfc2l6ZSA9IGMoMywgMyksIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9tYXhfcG9vbGluZ18yZChwb29sX3NpemUgPSBjKDIsIDIpKSAlPiUgCiAgbGF5ZXJfZmxhdHRlbigpICU+JSAKICBsYXllcl9kcm9wb3V0KHJhdGUgPSAwLjUpICU+JSAgICAgIyBhZGQgYSBkcm9wb3V0IGxheWVyIHRvIG1pdGlnYXRlIE9GCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSA1MTIsIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9kZW5zZSh1bml0cyA9IDEsIGFjdGl2YXRpb24gPSAic2lnbW9pZCIpICAKCmNubjIgJT4lIGNvbXBpbGUoCiAgbG9zcyA9ICJiaW5hcnlfY3Jvc3NlbnRyb3B5IiwKICBvcHRpbWl6ZXIgPSBvcHRpbWl6ZXJfcm1zcHJvcChsciA9IDFlLTQpLAogIG1ldHJpY3MgPSBjKCJhY2MiKQopCgpzdW1tYXJ5KGNubjIpCmBgYAoKIyMjIyAzLjMgRml0dGluZyBNb2RlbApgYGB7cn0KZml0MiA8LSBjbm4yICU+JSBmaXRfZ2VuZXJhdG9yKAogIEdlbmVyYXRlKCI0MDAwL3RyYWluIiwgQXVnbWVudCwgNDApLAogIHN0ZXBzX3Blcl9lcG9jaCA9IDEwMCwKICBlcG9jaHMgPSA1MCwKICB2YWxpZGF0aW9uX2RhdGEgPSBHZW5lcmF0ZSgiNDAwMC92YWxpZGF0aW9uIiksCiAgdmFsaWRhdGlvbl9zdGVwcyA9IDUwLAogIHZlcmJvc2U9MgogICkKYGBgCgpgYGB7cn0KcGxvdChmaXQyKQpgYGAKPGJyPgoKLSAtIC0KCiMjIyAzLiBDTk4gTW9kZWwgMzogUHJlVHJhaW4gQ05OIHdpdGggRGF0YSBBdWcuCgojIyMjIDMuMSBMb2FkIGBWR0cxNmAgUHJldHJhaW5lZCBNb2RlbCAKYGBge3J9CmNvbnZfYmFzZSA8LSBhcHBsaWNhdGlvbl92Z2cxNigKICB3ZWlnaHRzID0gImltYWdlbmV0IiwKICBpbmNsdWRlX3RvcCA9IEZBTFNFLAogIGlucHV0X3NoYXBlID0gYygxNTAsIDE1MCwgMykpCgpzdW1tYXJ5KGNvbnZfYmFzZSkKYGBgCgojIyMjIDMuMiBDb21iaW5lIGBWR0cxNmAgd2l0aCBPdXRwdXQgTGF5ZXJzCmBgYHtyfQpjbm4zIDwtIGtlcmFzX21vZGVsX3NlcXVlbnRpYWwoKSAlPiUgCiAgY29udl9iYXNlICU+JSAKICBsYXllcl9mbGF0dGVuKCkgJT4lIAogIGxheWVyX2RlbnNlKHVuaXRzID0gMjU2LCBhY3RpdmF0aW9uID0gInJlbHUiKSAlPiUgCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAxLCBhY3RpdmF0aW9uID0gInNpZ21vaWQiKSAgCgpzdW1tYXJ5KGNubjMpCmBgYAoKIyMjIyAzLjMgRnJlZXplIHRoZSBWR0cxNiBMYXllcnMKYGBge3J9Cmxlbmd0aChjbm4zJHRyYWluYWJsZV93ZWlnaHRzKSAgIyAzMApmcmVlemVfd2VpZ2h0cyhjb252X2Jhc2UpCmxlbmd0aChjbm4zJHRyYWluYWJsZV93ZWlnaHRzKSAgIyA0CmBgYAoKIyMjIyAzLjQgQ29tcGlsZSB0aGUgTW9kbGUgd2l0aCBUcmFpbmluZyBQYXJhbWV0ZXJzCmBgYHtyfQpjbm4zICU+JSBjb21waWxlKAogIGxvc3MgPSAiYmluYXJ5X2Nyb3NzZW50cm9weSIsCiAgb3B0aW1pemVyID0gb3B0aW1pemVyX3Jtc3Byb3AobHIgPSAyZS01KSwKICBtZXRyaWNzID0gYygiYWNjdXJhY3kiKSkKYGBgCgojIyMjIDMuNSBGaXJzdCBTdGFnZSBGaXR0aW5nCmBgYHtyfQpmaXQzIDwtIGNubjMgJT4lIGZpdF9nZW5lcmF0b3IoCiAgR2VuZXJhdGUoIjQwMDAvdHJhaW4iLEF1Z21lbnQsNDApLAogIHN0ZXBzX3Blcl9lcG9jaCA9IDEwMCwKICBlcG9jaHMgPSAzMCwKICB2YWxpZGF0aW9uX2RhdGEgPSBHZW5lcmF0ZSgiNDAwMC92YWxpZGF0aW9uIiksCiAgdmFsaWRhdGlvbl9zdGVwcyA9IDUwLAogIHZlcmJvc2UgPSAyCiAgKQpgYGAKCmBgYHtyfQpwbG90KGZpdDMpCmBgYAoKIyMjIyAzLjYgVW5mcmVlemUgdGhlIExvd2VyIExheWVycwpgYGB7cn0KdW5mcmVlemVfd2VpZ2h0cyhjb252X2Jhc2UsIGZyb20gPSAiYmxvY2s1X2NvbnYxIikKbGVuZ3RoKGNubjMkdHJhaW5hYmxlX3dlaWdodHMpICAjIDEwCmBgYAoKCiMjIyMgMy43IFJlLUNvbXBpbGUgd2l0aCBBZGp1c3RlZCBUcmFpbmluZyBQYXJhbWV0ZXJzCmBgYHtyfQpjbm4zICU+JSBjb21waWxlKAogIGxvc3MgPSAiYmluYXJ5X2Nyb3NzZW50cm9weSIsCiAgb3B0aW1pemVyID0gb3B0aW1pemVyX3Jtc3Byb3AobHIgPSAxZS01KSwKICBtZXRyaWNzID0gYygiYWNjdXJhY3kiKQogICkKYGBgCgojIyMjIDMuOCBTZWNvbmQgU3RhZ2UgRml0dGluZwpgYGB7cn0KZml0M2EgPSBjbm4zICU+JSBmaXRfZ2VuZXJhdG9yKAogIEdlbmVyYXRlKCI0MDAwL3RyYWluIixBdWdtZW50LDQwKSwKICBzdGVwc19wZXJfZXBvY2ggPSAxMDAsCiAgZXBvY2hzID0gNTAsCiAgdmFsaWRhdGlvbl9kYXRhID0gR2VuZXJhdGUoIjQwMDAvdmFsaWRhdGlvbiIpLAogIHZhbGlkYXRpb25fc3RlcHMgPSA1MCwKICB2ZXJib3NlID0gMgogICkKYGBgCgpgYGB7cn0KcGxvdChmaXQzYSkKYGBgCgojIyMjIDMuOSBUZXN0IEFjY3VyYWN5CmBgYHtyfQpjbm4zICU+JSBldmFsdWF0ZV9nZW5lcmF0b3IoR2VuZXJhdGUoIjQwMDAvdGVzdCIpLCBzdGVwcyA9IDUwKSAjIGFjYyA9IDAuOTM4CmBgYAoKCjxicj48YnI+PGJyPjxicj4KCjxzdHlsZT4KLmNhcHRpb24gewogIGNvbG9yOiAjNzc3OwogIG1hcmdpbi10b3A6IDEwcHg7Cn0KcCBjb2RlIHsKICB3aGl0ZS1zcGFjZTogaW5oZXJpdDsKfQpwcmUgewogIHdvcmQtYnJlYWs6IG5vcm1hbDsKICB3b3JkLXdyYXA6IG5vcm1hbDsKICBsaW5lLWhlaWdodDogMTsKfQpwcmUgY29kZSB7CiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7Cn0KcCxsaSB7CiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7Cn0KCi5yewogIGxpbmUtaGVpZ2h0OiAxLjI7Cn0KCi5xaXogewogIGxpbmUtaGVpZ2h0OiAxLjc1OwogIGJhY2tncm91bmQ6ICNmMGYwZjA7CiAgYm9yZGVyLWxlZnQ6IDEycHggc29saWQgI2NjZmZjYzsKICBwYWRkaW5nOiA0cHg7CiAgcGFkZGluZy1sZWZ0OiAxMHB4OwogIGNvbG9yOiAjMDA5OTAwOwp9Cgp0aXRsZXsKICBjb2xvcjogI2NjMDAwMDsKICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsKfQoKYm9keXsKICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsKfQoKaDEsaDIsaDMsaDQsaDV7CiAgY29sb3I6ICMwMDY2ZmY7CiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7Cn0KCgpoM3sKICBjb2xvcjogIzAwODgwMDsKICBiYWNrZ3JvdW5kOiAjZTZmZmU2OwogIGxpbmUtaGVpZ2h0OiAyOwogIGZvbnQtd2VpZ2h0OiBib2xkOwp9CgpoNXsKICBjb2xvcjogIzAwNjAwMDsKICBiYWNrZ3JvdW5kOiAjZjhmOGY4OwogIGxpbmUtaGVpZ2h0OiAxLjU7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KPC9zdHlsZT4KCgoKCg==