{"cells":[{"cell_type":"markdown","metadata":{"_cell_guid":"7d25a4c1-9335-0638-6042-14de1f6c1c4d"},"source":"#This script is used to execute the following steps\n\n- Load images using the [ImageR package](http://dahtah.github.io/imager/), crop them to a standardized dimension and save them as an array \n- Run a [VGG inspired](http://josephpcohen.com/w/visualizing-cnn-architectures-side-by-side-with-mxnet/) convolutional network using the [MXNET package](https://github.com/dmlc/mxnet/)"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"1603b517-e414-96c8-3090-f15f2638cd04"},"outputs":[],"source":"### Load packages\nlibrary(\"imager\")\nlibrary(\"data.table\")\nlibrary(\"dtplyr\")\nlibrary(\"dplyr\")\nlibrary(\"readr\")\nlibrary(\"ggplot2\")\nlibrary(\"plotly\")\nlibrary(\"mxnet\")\n\n# Input data files are available in the \"../input/\" directory."},{"cell_type":"markdown","metadata":{"_cell_guid":"3c444697-778b-bc69-c652-83a6fb812316"},"source":"###List image files\n\nTrain and evaluation images are shuffled and test images files are sorted in numerica order as expected by the submission."},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"fa5a2374-c986-28b2-5d6d-4039888f7c97"},"outputs":[],"source":"#### Alternate cases of dogs and cats\ncat_files<- list.files(path = \"../input/train\", pattern = \"cat.+\")\ndog_files<- list.files(path = \"../input/train\", pattern = \"dog.+\")\n\n### randomize image order\nset.seed(123)\ncat_files<- sample(cat_files)\ndog_files<- sample(dog_files)\n\n### list test files\ntest_files<- list.files(path = \"../input/test\", pattern = \".+\\\\.jpg\")\ntest_num<- as.numeric(gsub(pattern=\"(\\\\d+)(.+)\", replacement = \"\\\\1\", x = test_files))\ntest_position<- order(test_num)\ntest_files<- test_files[test_position]\n\nhead(cat_files)\nhead(dog_files)\nhead(test_files)"},{"cell_type":"markdown","metadata":{"_cell_guid":"56266c94-7db7-1dac-3f46-7b9dc1a54202"},"source":"###Function to import images as arrays\n\nPixel values are rounded to manage space when run locally from a csv data iterator"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"dac235b9-0753-f0c7-c7f0-d73e6561c5eb"},"outputs":[],"source":"### Load images and and convert to array\ntrain_prep<- function(start,end, size){\n\n  count<- 2*length(start:end)\n  data_array<- array(NA, dim = c(size, size, 3, count))\n  \n  for (i in start:end) {\n    ### load jpeg into imageR\n    cat <- load.image(paste(\"../input/train/\", cat_files[i], sep=\"\"))\n    cat<- resize(cat,size_x = size, size_y = size, size_c = 3, interpolation_type = 2)\n    cat_array<-t(round(array(cat),4))\n      \n    dog <- load.image(paste(\"../input/train/\", dog_files[i], sep=\"\"))\n    dog<- resize(dog,size_x = size, size_y = size, size_c = 3, interpolation_type = 2)\n    dog_array<-t(round(array(dog),4))\n    \n    data_array[, , , 2*(i-start+1)-1]<- cat_array\n    data_array[, , , 2*(i-start+1)]<- dog_array\n  }\n  return(data_array)\n}\n\nsize<- 80\ntrain_array<- train_prep(start=1, end=160, size=size)\ntrain_labels<- rep(c(0,1), times=160)\neval_array<- train_prep(start=10001, end=10032, size=size)\neval_labels<- rep(c(0,1), times=32)"},{"cell_type":"markdown","metadata":{"_cell_guid":"11654b24-fd31-3f97-a8f6-49dc6390de42"},"source":"###Validate the soundness of the created arrays"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"6695575e-6c41-8298-4c8d-eaa50e6a4e96"},"outputs":[],"source":"img_test<- train_array[, , , 1]\ndim(img_test)<- c(size, size, 1, 3)\nimg_test<-as.cimg(img_test)\nplot(img_test)\n\nimg_test<- train_array[, , , 2]\ndim(img_test)<- c(size, size, 1, 3)\nimg_test<-as.cimg(img_test)\nplot(img_test)"},{"cell_type":"markdown","metadata":{"_cell_guid":"9e523ee1-f9a0-ba74-8136-7d799a5b973e"},"source":"###Build the symbolic representation of the model"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"da31f4d6-ab96-c275-4fe0-d28c80c2d49b"},"outputs":[],"source":"# input\ndata <- mx.symbol.Variable('data')\n\nconv1A <- mx.symbol.Convolution(data=data, kernel=c(3,3), num_filter=32, stride=c(1,1), pad=c(1,1))\nact1A <- mx.symbol.Activation(data=conv1A, act_type=\"relu\")\nconv1B <- mx.symbol.Convolution(data=act1A, kernel=c(3,3), num_filter=32, stride=c(1,1), pad=c(1,1))\nact1B <- mx.symbol.Activation(data=conv1B, act_type=\"relu\")\npool1<- mx.symbol.Pooling(data=act1B, pool_type=\"max\", kernel=c(2,2), stride=c(2,2), pad=c(0,0))\n\nconv2A <- mx.symbol.Convolution(data=pool1, kernel=c(3,3), num_filter=64, stride=c(1,1), pad=c(1,1))\nact2A <- mx.symbol.Activation(data=conv2A, act_type=\"relu\")\nconv2B <- mx.symbol.Convolution(data=act2A, kernel=c(3,3), num_filter=64, stride=c(1,1), pad=c(1,1))\nact2B <- mx.symbol.Activation(data=conv2B, act_type=\"relu\")\npool2<- mx.symbol.Pooling(data=act2B, pool_type=\"max\", kernel=c(2,2), stride=c(2,2), pad=c(0,0))\n\nconv3A <- mx.symbol.Convolution(data=pool2, kernel=c(3,3), num_filter=128, stride=c(1,1), pad=c(1,1))\nact3A <- mx.symbol.Activation(data=conv3A, act_type=\"relu\")\nconv3B <- mx.symbol.Convolution(data=act3A, kernel=c(3,3), num_filter=128, stride=c(1,1), pad=c(1,1))\nact3B <- mx.symbol.Activation(data=conv3B, act_type=\"relu\")\npool3<- mx.symbol.Pooling(data=act3B, pool_type=\"max\", kernel=c(2,2), stride=c(2,2), pad=c(0,0))\n\nconv4A <- mx.symbol.Convolution(data=pool3, kernel=c(3,3), num_filter=128, stride=c(1,1), pad=c(1,1))\nact4A <- mx.symbol.Activation(data=conv4A, act_type=\"relu\")\nconv4B <- mx.symbol.Convolution(data=act4A, kernel=c(3,3), num_filter=128, stride=c(1,1), pad=c(1,1))\nact4B <- mx.symbol.Activation(data=conv4B, act_type=\"relu\")\npool4<- mx.symbol.Pooling(data=act4B, pool_type=\"max\", kernel=c(2,2), stride=c(2,2), pad=c(0,0))\n\n# flatten\nflatten <- mx.symbol.Flatten(data=pool4)\n\nfc1 <- mx.symbol.FullyConnected(data=flatten, num_hidden=512)\nact_fc1 <- mx.symbol.Activation(data=fc1, act_type=\"relu\")\ndrop1 <- mx.symbol.Dropout(data=act_fc1, p=0.5)\n\n# loss\nfc_final <- mx.symbol.FullyConnected(data=drop1, num_hidden=2)\nconvnet <- mx.symbol.SoftmaxOutput(data=fc_final)\n\n### plot the model structure\ngraph.viz(model=convnet$as.json())"},{"cell_type":"markdown","metadata":{"_cell_guid":"f1211635-1780-d937-c6ed-dd8deecfaab5"},"source":"###Train a model on a small sample of data"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"8d99c1d9-4011-f77f-4a4d-583c38d76fd5"},"outputs":[],"source":"devices <- mx.cpu()\n\n### combine symbols and create executor for inspection of learned features\ncombined<- mx.symbol.Group(act1A, convnet)\nexecutor <- mx.simple.bind(symbol=combined, data=dim(train_array), ctx=devices)\n\nmx.set.seed(123)\nmodel_mxnet <- mx.model.FeedForward.create(convnet,\n                                               X=train_array, \n                                               y=train_labels,, \n                                               eval.data = list(data=eval_array, label=eval_labels),\n                                               array.batch.size = 16, \n                                               ctx=devices, \n                                               num.round=5,\n                                               learning.rate=0.05,\n                                               wd=0.001,\n                                               momentum=0.9,\n                                               clip_gradient=1,\n                                               eval.metric=mx.metric.accuracy, \n                                               initializer=mx.init.Xavier(rnd_type = \"gaussian\", factor_type = \"avg\", magnitude = 3),\n                                               epoch.end.callback = mx.callback.log.train.metric(1))"},{"cell_type":"markdown","metadata":{"_cell_guid":"ad0ebb75-a7f0-9854-d14b-08dfe5fbdedf"},"source":"###Look at the first 16 features learned in first convolution\n\nWill make more sense after training on full dataset!"},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"792584fd-ba93-0218-802a-2cb1f355f5ae"},"outputs":[],"source":"mx.exec.update.arg.arrays(exec = executor, arg.arrays = model_mxnet$arg.params, match.name=TRUE)\nmx.exec.update.arg.arrays(executor, list(data=mx.nd.array(train_array)), match.name=TRUE)\nmx.exec.forward(executor, is.train=FALSE)\n\npar(mfrow=c(4,4), mar=c(0.1,0.1,0.1,0.1))\nfor (i in 1:16) {\n  img_array <- as.array(executor$outputs$activation0_output)[,,i,1]\n  img<-as.cimg(img_array)\n  plot(img)\n}"},{"cell_type":"markdown","metadata":{"_cell_guid":"5cca1eaf-4317-4f85-9ced-d6497b3165e5"},"source":"###Generate the predictions\n\nTraining on full data should result in a viable model. Ran locally, logloss is around 0.28 and accuracy 87%."},{"cell_type":"code","execution_count":null,"metadata":{"_cell_guid":"ae2e2fa2-ad96-c939-e891-cc97496d9e66"},"outputs":[],"source":"pred_prob<- t(predict(model_mxnet, eval_array))\nsubmit <- data.frame(id=1:64, label=pred_prob[, 2])\nhead(submit)"}],"metadata":{"_change_revision":0,"_is_fork":false,"kernelspec":{"display_name":"R","language":"R","name":"ir"},"language_info":{"codemirror_mode":"r","file_extension":".r","mimetype":"text/x-r-source","name":"R","pygments_lexer":"r","version":"3.3.1"}},"nbformat":4,"nbformat_minor":0}