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 = 20,                        # 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_4 (Conv2D)                                   (None, 148, 148, 32)                           896               
_____________________________________________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D)                      (None, 74, 74, 32)                             0                 
_____________________________________________________________________________________________________________________
conv2d_5 (Conv2D)                                   (None, 72, 72, 64)                             18496             
_____________________________________________________________________________________________________________________
max_pooling2d_4 (MaxPooling2D)                      (None, 36, 36, 64)                             0                 
_____________________________________________________________________________________________________________________
conv2d_6 (Conv2D)                                   (None, 34, 34, 128)                            73856             
_____________________________________________________________________________________________________________________
max_pooling2d_5 (MaxPooling2D)                      (None, 17, 17, 128)                            0                 
_____________________________________________________________________________________________________________________
conv2d_7 (Conv2D)                                   (None, 15, 15, 128)                            147584            
_____________________________________________________________________________________________________________________
max_pooling2d_6 (MaxPooling2D)                      (None, 7, 7, 128)                              0                 
_____________________________________________________________________________________________________________________
flatten_2 (Flatten)                                 (None, 6272)                                   0                 
_____________________________________________________________________________________________________________________
dense_5 (Dense)                                     (None, 512)                                    3211776           
_____________________________________________________________________________________________________________________
dense_6 (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
  )
Found 1000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
Epoch 1/20
 - 21s - loss: 0.6883 - acc: 0.5340 - val_loss: 0.6798 - val_acc: 0.5160
Epoch 2/20
 - 8s - loss: 0.6577 - acc: 0.6120 - val_loss: 0.6338 - val_acc: 0.6380
Epoch 3/20
 - 8s - loss: 0.6188 - acc: 0.6620 - val_loss: 0.6051 - val_acc: 0.6720
Epoch 4/20
 - 8s - loss: 0.5749 - acc: 0.7060 - val_loss: 0.5869 - val_acc: 0.6840
Epoch 5/20
 - 8s - loss: 0.5408 - acc: 0.7325 - val_loss: 0.5849 - val_acc: 0.6830
Epoch 6/20
 - 8s - loss: 0.5105 - acc: 0.7500 - val_loss: 0.5719 - val_acc: 0.7050
Epoch 7/20
 - 8s - loss: 0.4850 - acc: 0.7670 - val_loss: 0.5508 - val_acc: 0.7180
Epoch 8/20
 - 8s - loss: 0.4587 - acc: 0.7845 - val_loss: 0.5502 - val_acc: 0.7220
Epoch 9/20
 - 9s - loss: 0.4388 - acc: 0.8000 - val_loss: 0.5485 - val_acc: 0.7260
Epoch 10/20
 - 9s - loss: 0.4072 - acc: 0.8120 - val_loss: 0.5283 - val_acc: 0.7380
Epoch 11/20
 - 8s - loss: 0.3909 - acc: 0.8265 - val_loss: 0.5535 - val_acc: 0.7340
Epoch 12/20
 - 9s - loss: 0.3632 - acc: 0.8410 - val_loss: 0.5524 - val_acc: 0.7380
Epoch 13/20
 - 8s - loss: 0.3473 - acc: 0.8500 - val_loss: 0.5342 - val_acc: 0.7520
Epoch 14/20
 - 9s - loss: 0.3235 - acc: 0.8630 - val_loss: 0.5384 - val_acc: 0.7430
Epoch 15/20
 - 9s - loss: 0.3037 - acc: 0.8700 - val_loss: 0.5543 - val_acc: 0.7420
Epoch 16/20
 - 9s - loss: 0.2832 - acc: 0.8835 - val_loss: 0.5508 - val_acc: 0.7310
Epoch 17/20
 - 9s - loss: 0.2631 - acc: 0.8930 - val_loss: 0.5896 - val_acc: 0.7420
Epoch 18/20
 - 9s - loss: 0.2464 - acc: 0.9030 - val_loss: 0.6628 - val_acc: 0.7070
Epoch 19/20
 - 9s - loss: 0.2268 - acc: 0.9055 - val_loss: 0.5735 - val_acc: 0.7490
Epoch 20/20
 - 8s - loss: 0.2010 - acc: 0.9240 - val_loss: 0.5944 - val_acc: 0.7440
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_8 (Conv2D)                                   (None, 148, 148, 32)                           896               
_____________________________________________________________________________________________________________________
max_pooling2d_7 (MaxPooling2D)                      (None, 74, 74, 32)                             0                 
_____________________________________________________________________________________________________________________
conv2d_9 (Conv2D)                                   (None, 72, 72, 64)                             18496             
_____________________________________________________________________________________________________________________
max_pooling2d_8 (MaxPooling2D)                      (None, 36, 36, 64)                             0                 
_____________________________________________________________________________________________________________________
conv2d_10 (Conv2D)                                  (None, 34, 34, 128)                            73856             
_____________________________________________________________________________________________________________________
max_pooling2d_9 (MaxPooling2D)                      (None, 17, 17, 128)                            0                 
_____________________________________________________________________________________________________________________
conv2d_11 (Conv2D)                                  (None, 15, 15, 128)                            147584            
_____________________________________________________________________________________________________________________
max_pooling2d_10 (MaxPooling2D)                     (None, 7, 7, 128)                              0                 
_____________________________________________________________________________________________________________________
flatten_3 (Flatten)                                 (None, 6272)                                   0                 
_____________________________________________________________________________________________________________________
dropout_1 (Dropout)                                 (None, 6272)                                   0                 
_____________________________________________________________________________________________________________________
dense_7 (Dense)                                     (None, 512)                                    3211776           
_____________________________________________________________________________________________________________________
dense_8 (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
 - 18s - loss: 0.6940 - acc: 0.5075 - val_loss: 0.6949 - val_acc: 0.5000
Epoch 2/50
 - 17s - loss: 0.6891 - acc: 0.5320 - val_loss: 0.7151 - val_acc: 0.5000
Epoch 3/50
 - 17s - loss: 0.6762 - acc: 0.5705 - val_loss: 0.6767 - val_acc: 0.5430
Epoch 4/50
 - 17s - loss: 0.6615 - acc: 0.6015 - val_loss: 0.6588 - val_acc: 0.5950
Epoch 5/50
 - 17s - loss: 0.6476 - acc: 0.6130 - val_loss: 0.6217 - val_acc: 0.6550
Epoch 6/50
 - 17s - loss: 0.6392 - acc: 0.6370 - val_loss: 0.6041 - val_acc: 0.6530
Epoch 7/50
 - 17s - loss: 0.6244 - acc: 0.6500 - val_loss: 0.5932 - val_acc: 0.6750
Epoch 8/50
 - 17s - loss: 0.6223 - acc: 0.6525 - val_loss: 0.5809 - val_acc: 0.6660
Epoch 9/50
 - 17s - loss: 0.5945 - acc: 0.6755 - val_loss: 0.5784 - val_acc: 0.6900
Epoch 10/50
 - 16s - loss: 0.5938 - acc: 0.6750 - val_loss: 0.5889 - val_acc: 0.6770
Epoch 11/50
 - 17s - loss: 0.5941 - acc: 0.6770 - val_loss: 0.5602 - val_acc: 0.7060
Epoch 12/50
 - 17s - loss: 0.5958 - acc: 0.6760 - val_loss: 0.7220 - val_acc: 0.5550
Epoch 13/50
 - 17s - loss: 0.5870 - acc: 0.6875 - val_loss: 0.5691 - val_acc: 0.6920
Epoch 14/50
 - 17s - loss: 0.5740 - acc: 0.6965 - val_loss: 0.5319 - val_acc: 0.7330
Epoch 15/50
 - 17s - loss: 0.5621 - acc: 0.7090 - val_loss: 0.5373 - val_acc: 0.7170
Epoch 16/50
 - 16s - loss: 0.5569 - acc: 0.7225 - val_loss: 0.5192 - val_acc: 0.7370
Epoch 17/50
 - 17s - loss: 0.5624 - acc: 0.7180 - val_loss: 0.5315 - val_acc: 0.7330
Epoch 18/50
 - 16s - loss: 0.5623 - acc: 0.7065 - val_loss: 0.5717 - val_acc: 0.6900
Epoch 19/50
 - 17s - loss: 0.5511 - acc: 0.7255 - val_loss: 0.5594 - val_acc: 0.7130
Epoch 20/50
 - 16s - loss: 0.5468 - acc: 0.7220 - val_loss: 0.5192 - val_acc: 0.7370
Epoch 21/50
 - 17s - loss: 0.5475 - acc: 0.7105 - val_loss: 0.5199 - val_acc: 0.7310
Epoch 22/50
 - 17s - loss: 0.5346 - acc: 0.7300 - val_loss: 0.5227 - val_acc: 0.7390
Epoch 23/50
 - 17s - loss: 0.5423 - acc: 0.7300 - val_loss: 0.5040 - val_acc: 0.7480
Epoch 24/50
 - 17s - loss: 0.5336 - acc: 0.7325 - val_loss: 0.4979 - val_acc: 0.7470
Epoch 25/50
 - 17s - loss: 0.5412 - acc: 0.7240 - val_loss: 0.5148 - val_acc: 0.7300
Epoch 26/50
 - 17s - loss: 0.5241 - acc: 0.7445 - val_loss: 0.5274 - val_acc: 0.7290
Epoch 27/50
 - 17s - loss: 0.5361 - acc: 0.7280 - val_loss: 0.4908 - val_acc: 0.7620
Epoch 28/50
 - 17s - loss: 0.5242 - acc: 0.7395 - val_loss: 0.5169 - val_acc: 0.7450
Epoch 29/50
 - 16s - loss: 0.5061 - acc: 0.7545 - val_loss: 0.4938 - val_acc: 0.7540
Epoch 30/50
 - 17s - loss: 0.5106 - acc: 0.7595 - val_loss: 0.4929 - val_acc: 0.7610
Epoch 31/50
 - 16s - loss: 0.5192 - acc: 0.7475 - val_loss: 0.5166 - val_acc: 0.7370
Epoch 32/50
 - 16s - loss: 0.5022 - acc: 0.7510 - val_loss: 0.5014 - val_acc: 0.7500
Epoch 33/50
 - 16s - loss: 0.5167 - acc: 0.7460 - val_loss: 0.5310 - val_acc: 0.7240
Epoch 34/50
 - 17s - loss: 0.4976 - acc: 0.7515 - val_loss: 0.4943 - val_acc: 0.7660
Epoch 35/50
 - 16s - loss: 0.5022 - acc: 0.7555 - val_loss: 0.5142 - val_acc: 0.7400
Epoch 36/50
 - 17s - loss: 0.5132 - acc: 0.7480 - val_loss: 0.4955 - val_acc: 0.7600
Epoch 37/50
 - 17s - loss: 0.5044 - acc: 0.7460 - val_loss: 0.5446 - val_acc: 0.7160
Epoch 38/50
 - 17s - loss: 0.5061 - acc: 0.7530 - val_loss: 0.5217 - val_acc: 0.7270
Epoch 39/50
 - 17s - loss: 0.5056 - acc: 0.7565 - val_loss: 0.4730 - val_acc: 0.7640
Epoch 40/50
 - 17s - loss: 0.4981 - acc: 0.7545 - val_loss: 0.4968 - val_acc: 0.7510
Epoch 41/50
 - 17s - loss: 0.4913 - acc: 0.7545 - val_loss: 0.4530 - val_acc: 0.7840
Epoch 42/50
 - 17s - loss: 0.4866 - acc: 0.7625 - val_loss: 0.5143 - val_acc: 0.7440
Epoch 43/50
 - 17s - loss: 0.4893 - acc: 0.7670 - val_loss: 0.4739 - val_acc: 0.7700
Epoch 44/50
 - 17s - loss: 0.4827 - acc: 0.7710 - val_loss: 0.5646 - val_acc: 0.7080
Epoch 45/50
 - 17s - loss: 0.4757 - acc: 0.7700 - val_loss: 0.5269 - val_acc: 0.7360
Epoch 46/50
 - 17s - loss: 0.4857 - acc: 0.7750 - val_loss: 0.4689 - val_acc: 0.7800
Epoch 47/50
 - 17s - loss: 0.4579 - acc: 0.7790 - val_loss: 0.5018 - val_acc: 0.7530
Epoch 48/50
 - 16s - loss: 0.4820 - acc: 0.7795 - val_loss: 0.5090 - val_acc: 0.7600
Epoch 49/50
 - 17s - loss: 0.4504 - acc: 0.7780 - val_loss: 0.4908 - val_acc: 0.7530
Epoch 50/50
 - 16s - loss: 0.4633 - acc: 0.7875 - val_loss: 0.4821 - val_acc: 0.7710
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_4 (Flatten)                                 (None, 8192)                                   0                 
_____________________________________________________________________________________________________________________
dense_9 (Dense)                                     (None, 256)                                    2097408           
_____________________________________________________________________________________________________________________
dense_10 (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
 - 24s - loss: 0.5973 - acc: 0.6770 - val_loss: 0.4640 - val_acc: 0.8060
Epoch 2/30
 - 21s - loss: 0.4992 - acc: 0.7680 - val_loss: 0.3929 - val_acc: 0.8450
Epoch 3/30
 - 22s - loss: 0.4493 - acc: 0.8015 - val_loss: 0.3547 - val_acc: 0.8470
Epoch 4/30
 - 22s - loss: 0.4188 - acc: 0.8110 - val_loss: 0.3269 - val_acc: 0.8680
Epoch 5/30
 - 21s - loss: 0.3929 - acc: 0.8310 - val_loss: 0.3080 - val_acc: 0.8730
Epoch 6/30
 - 22s - loss: 0.3786 - acc: 0.8315 - val_loss: 0.2922 - val_acc: 0.8720
Epoch 7/30
 - 22s - loss: 0.3582 - acc: 0.8435 - val_loss: 0.2806 - val_acc: 0.8800
Epoch 8/30
 - 22s - loss: 0.3622 - acc: 0.8395 - val_loss: 0.2751 - val_acc: 0.8810
Epoch 9/30
 - 22s - loss: 0.3364 - acc: 0.8520 - val_loss: 0.2687 - val_acc: 0.8810
Epoch 10/30
 - 22s - loss: 0.3384 - acc: 0.8535 - val_loss: 0.2656 - val_acc: 0.8800
Epoch 11/30
 - 22s - loss: 0.3420 - acc: 0.8525 - val_loss: 0.2613 - val_acc: 0.8860
Epoch 12/30
 - 22s - loss: 0.3279 - acc: 0.8555 - val_loss: 0.2571 - val_acc: 0.8970
Epoch 13/30
 - 22s - loss: 0.3177 - acc: 0.8700 - val_loss: 0.2518 - val_acc: 0.8950
Epoch 14/30
 - 22s - loss: 0.3071 - acc: 0.8730 - val_loss: 0.2532 - val_acc: 0.8940
Epoch 15/30
 - 22s - loss: 0.3133 - acc: 0.8635 - val_loss: 0.2517 - val_acc: 0.8960
Epoch 16/30
 - 22s - loss: 0.3072 - acc: 0.8675 - val_loss: 0.2511 - val_acc: 0.8920
Epoch 17/30
 - 22s - loss: 0.3149 - acc: 0.8575 - val_loss: 0.2522 - val_acc: 0.8860
Epoch 18/30
 - 22s - loss: 0.3111 - acc: 0.8645 - val_loss: 0.2485 - val_acc: 0.8970
Epoch 19/30
 - 22s - loss: 0.3037 - acc: 0.8740 - val_loss: 0.2456 - val_acc: 0.8990
Epoch 20/30
 - 22s - loss: 0.3006 - acc: 0.8685 - val_loss: 0.2467 - val_acc: 0.8960
Epoch 21/30
 - 22s - loss: 0.2927 - acc: 0.8825 - val_loss: 0.2428 - val_acc: 0.8990
Epoch 22/30
 - 22s - loss: 0.2858 - acc: 0.8760 - val_loss: 0.2421 - val_acc: 0.8990
Epoch 23/30
 - 22s - loss: 0.2950 - acc: 0.8700 - val_loss: 0.2415 - val_acc: 0.9030
Epoch 24/30
 - 22s - loss: 0.2862 - acc: 0.8790 - val_loss: 0.2402 - val_acc: 0.9000
Epoch 25/30
 - 21s - loss: 0.2921 - acc: 0.8805 - val_loss: 0.2417 - val_acc: 0.8990
Epoch 26/30
 - 22s - loss: 0.3019 - acc: 0.8605 - val_loss: 0.2405 - val_acc: 0.8990
Epoch 27/30
 - 23s - loss: 0.2906 - acc: 0.8810 - val_loss: 0.2438 - val_acc: 0.9010
Epoch 28/30
 - 22s - loss: 0.2909 - acc: 0.8730 - val_loss: 0.2593 - val_acc: 0.8910
Epoch 29/30
 - 22s - loss: 0.2885 - acc: 0.8700 - val_loss: 0.2469 - val_acc: 0.8980
Epoch 30/30
 - 22s - loss: 0.2834 - acc: 0.8740 - val_loss: 0.2386 - val_acc: 0.8970
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
 - 24s - loss: 0.3056 - acc: 0.8665 - val_loss: 0.2189 - val_acc: 0.9080
Epoch 2/50
 - 23s - loss: 0.2570 - acc: 0.8870 - val_loss: 0.2110 - val_acc: 0.9190
Epoch 3/50
 - 23s - loss: 0.2498 - acc: 0.9015 - val_loss: 0.1983 - val_acc: 0.9260
Epoch 4/50
 - 23s - loss: 0.2175 - acc: 0.9090 - val_loss: 0.1924 - val_acc: 0.9290
Epoch 5/50
 - 23s - loss: 0.2147 - acc: 0.9170 - val_loss: 0.2015 - val_acc: 0.9220
Epoch 6/50
 - 23s - loss: 0.1882 - acc: 0.9235 - val_loss: 0.1965 - val_acc: 0.9210
Epoch 7/50
 - 23s - loss: 0.1911 - acc: 0.9165 - val_loss: 0.2223 - val_acc: 0.9180
Epoch 8/50
 - 23s - loss: 0.1764 - acc: 0.9270 - val_loss: 0.1771 - val_acc: 0.9330
Epoch 9/50
 - 23s - loss: 0.1589 - acc: 0.9365 - val_loss: 0.1888 - val_acc: 0.9330
plot(fit3a)

3.9 Test Accuracy

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

$acc
[1] 0.933





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