forked from dlab-berkeley/R-Deep-Learning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path02-dogs-humans.Rmd
161 lines (124 loc) · 6.5 KB
/
02-dogs-humans.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
---
title: "Deep Learning in R - Part 2"
author: "D-Lab"
date: "11/26/2018 (updated: `r Sys.Date()`)"
output: html_document
---
## Dogs and humans
The MNIST dataset is a fun way to get your feet wet, but real images can require a bit more preprocessing to ensure that they are formatted correctly for input into keras. Let's try another example with some folders of images!
### The data
Load a folder of dog-human images from the `data-raw` folder in the workshop materials. First, we want to define the file paths of our already split training and validation (aka test data) image folders. We manually selected 600 training and 100 test images from the excellent [Stanford Dogs](http://vision.stanford.edu/aditya86/ImageNetDogs/) and [INRIA Person](http://pascal.inrialpes.fr/data/human/) image databases.
```{r examine_data}
# Specify the file paths for our training and validation (aka test) data
train_path = "data-raw/dog-human/TRAIN"
val_path = "data-raw/dog-human/VAL"
# Define two more variables as the actual names of the files
train_images = list.files(train_path, full.names = TRUE, recursive = TRUE)
val_images = list.files(val_path, full.names = TRUE, recursive = TRUE)
# We have 600 training set images and 100 validation set images
length(train_images)
length(val_images)
train_images[1]
val_images[1]
```
### Define model characteristics
Now, we want to define some of the characteristics outside of our model. This way, we can just pass in the same variable instead of a value each time.
```{r}
# Expected image width and height are 96 pixels.
img_width <- 96L
img_height <- 96L
# Number of observations to analyze per iteration.
batch_size <- 10L
# Number of images in our training data (600).
num_train_samples <- length(list.files(train_path, recursive = TRUE))
# Number of images in our validation data.
num_validation_samples <- 100L
# Number of full passes through the training data.
epochs <- 15L
```
`image_data_generator` performs data augmentation! However, we will just use the lone `rescale` parameter to scale our data to what will essentially become a bunch of binary matrices - one for each image that represents a dark or a light pixel.
See `?image_data_generator` to learn more.
```{r}
# Transform training data
train_datagen <- keras::image_data_generator(rescale = 1/255)
# Transform validation data
val_datagen <- keras::image_data_generator(rescale = 1/255)
```
> Remember that we can learn a lot more about our keras variables by using the dollar sign operator `$`. This functions in a similar way to dot notation in Python for calling methods. Press the tab key after the dollar sign in the cell below:
```{r, eval = F}
train_datagen
```
### Define the image characteristics
Before we define the model, we also need to give keras a few more details about the properties of our images. We will use the `flow_from_directory` method on both `train_datagen` and `val_datagen` to define our new variables.
```{r}
# Configure the training model
train_gen <-
# specify the file path to the training images
train_datagen$flow_from_directory(train_path,
# image shape
target_size = c(img_width, img_height),
# batch size
batch_size = batch_size,
# dog or human?
class_mode = "binary",
# color profile
color_mode = "grayscale")
# Configure the validation model
val_gen <-
# repeat for validation images
val_datagen$flow_from_directory(val_path,
target_size = c(img_width, img_height),
batch_size = batch_size,
class_mode = "binary",
color_mode = "grayscale")
```
## Define the model
Define the model.
```{r}
library(dplyr) # %>% come from here (and of course magrittr)
library(keras) # layer_flatten, layer_dense, layer_dropout
model <- keras::keras_model_sequential()
model %>%
# INPUT LAYER
# layer_flatten will turn our 3D array into a one-dimensional one
# Note: we did not have to do this in part1 because the data were already flattened
layer_flatten(input_shape = c(img_width, img_height, 1)) %>%
# HIDDEN LAYER
# layer_dense allows us to actually add the input layer. What parameters are we specifying?
layer_dense(units = 96, activation = 'relu', input_shape = c(img_width, img_height)) %>%
# layer_dropout allows us to apply regularization to our model.
layer_dropout(rate = 0.4) %>%
# HIDDEN LAYER
layer_dense(units = 192, activation = 'relu') %>%
layer_dropout(rate = 0.3) %>%
# OUTPUT LAYER
# here we can change our activation to a sigmoid function for a binary outcome
layer_dense(units = 1, activation = 'sigmoid')
summary(model)
```
### Defining the output metrics
We can use the generic `compile` function to specify our loss and optimizer functions and our classification metrics.
```{r}
model %>% compile(
# Dog or human?
loss = 'binary_crossentropy',
# Slow the learning rate a little...
optimizer = optimizer_adam(lr = 0.000001),
# How to evaluate model performance
metrics = c('accuracy'))
```
The `compile` step (loss function, activation function, and performance metric) is also similar to Part 1 except in Part 2 we use ["optimizer_adam"](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Adam) instead of ["optimizer_rmsprop"](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#RMSProp).
### Train the model and evaluate its performance on new data
Note that we have to use `fit_generator` to fit our model this time because we are also using the custom `flow_from_directory` function rather than the simpler format of part1.
```{r}
history <- model %>%
fit(train_gen,
epochs = epochs,
validation_data = val_gen)
```
```{r predict_valdata}
model %>% evaluate_generator(generator = val_gen, steps = 10)
```
Not bad for randomly selecting small subsets of the much larger dog and human datasets linked above! This neural net predicts roughly 70-75% images correctly.
## Challenge
How can we improve performance of this neural network? [Read this excellent post](https://blog.slavv.com/37-reasons-why-your-neural-network-is-not-working-4020854bd607) to learn 37 different ways. Try tuning some of our model (hypter)parameters in the above code to see if you can improve model performance.