Should we all be a “maker”?

As a bit of a constant over my photographic journey, printing has always been a passion. Once you print, then what? Do you box and store? Do you hang on the wall? Do you swap out prints within a frame or two? For me, I’m curious about frame making and canvas printing.

With the imagePrograf pro-2000, I now have the ability to print on canvas. My first print was a 16x16 beach print. First, I printed on canvas just to see the results. Then, it sat around for a month waiting on me to figure out how to frame a structure to host the print. I also wanted to make a “floating frame” for the finished print. Just how does one do that?

For me, that means YouTube research. How to print on canvas? How to stretch a canvas? How to coat a canvas print? How to make a floating frame? Each point of this learning journey was another step towards being a maker. What is a maker you ask?

I watched a recent Adam Savage video that defined a Maker beautifully.

https://youtube.com/watch?v=DUsBoLT1Yv8&feature=share

So I’m a maker even though I just learned of this term. I hope you can be a maker too!

As for what I made, here’s a quick visual telling of my first canvas print.

My first printing on Canvas. This was on a Breathing Color matte canvas -17” wide

My first printing on Canvas. This was on a Breathing Color matte canvas -17” wide

Here, I’m trying to cover the print with a thin coating of Mod Podge. Note, I failed on the thin coat. This was taking forever to cure into the Florida humidity so I decided to take it outside into Florida sun.  That worked wonders and also led to a…

Here, I’m trying to cover the print with a thin coating of Mod Podge. Note, I failed on the thin coat. This was taking forever to cure into the Florida humidity so I decided to take it outside into Florida sun. That worked wonders and also led to a small bug or two getting stuck. I tried to pick them out with my fingers and botched the surface texture. Lesson learned.

For cutting the frame, I YouTube miter jigs for table saws.  I made one using a variant for the Ryobi BT3000 table saw.  This saw has a built in sliding miter plate that I mounted the plywood too.  It worked great.  I hope to write this up for a fut…

For cutting the frame, I YouTube miter jigs for table saws. I made one using a variant for the Ryobi BT3000 table saw. This saw has a built in sliding miter plate that I mounted the plywood too. It worked great. I hope to write this up for a future post.

The miter jig did great.  I measured and cut with ease.  But I failed to appreciate the change in dimensions associated with the relief in the frame.  The inner square was just the write proportion.  The frame, however, was 1.5” to wide for failing …

The miter jig did great. I measured and cut with ease. But I failed to appreciate the change in dimensions associated with the relief in the frame. The inner square was just the write proportion. The frame, however, was 1.5” to wide for failing to account for the two 3/4” reliefs. No worries, just break apart, recut and learn.

The finished piece! After recutting, the print mounted perfectly into the frame.  Prior to mounting the canvas, I stained and then coated the frame with white paint to give it a weathered driftwood look. This picture doesn’t show that too clearly, b…

The finished piece! After recutting, the print mounted perfectly into the frame. Prior to mounting the canvas, I stained and then coated the frame with white paint to give it a weathered driftwood look. This picture doesn’t show that too clearly, but it turned out quite nice.

I believe in the making process. I don’t do it enough. But, I think we should strive more for this in life. Whether it is cooking something from scratch to building a rocket ship with hopes of traveling to Mars, we are better for people thinking through the details and creating.

Photography Printing -- Getting the Exposure Right

About two years ago, I posted a blog post entitled The Quest for Perfect Home Photography Printing. In the time since, I have continued to learn and advanced my skills at printing. This is a start of a series of tips to help you get better prints either at home or with a lab.

Tip: Get your exposure right

If you participate in online forums or Facebook groups on photography printing, without fail, new users will come in daily with a comment problem — the printed image is too dark! Frustration due to the wasted money usually follows the question of why the print looks so bad. I am going to break this down into a couple of key concepts.

More times than not, the more experienced printers will talk about a “color managed workflow” and “monitor calibration”. To an extent, this conversation is well grounded. In fact, I use Datacolor products to color manage my workflow. An important part of the calibration process is setting your monitor to just the right brightness, or should I say dimness, and working in largely a darkened room. For those of us that have their computers in rooms that are not cave dark, using brighter displays is essential. So, if the monitor is bright, your images will look bright on the screen. And when this happens, your prints are guaranteed to be too dark. Here is why.

First, your monitor emits lights. Your prints will need to reflect light. If you view a print in the dark, it will be dark. If you view even a dim smartphone in the dark, you will see the room light up. This is in part why editing in a dark room with a dim monitor will give you better results. As noted above, this is not possible for most people, so there is a trick all printers need to know. You need to use the histogram.

The histogram is an attribute of the image file and not of the monitor. Changing your monitor brightness will have no impact on the exposure. I present two examples of histograms below. These are the same image and both look reasonably good on the screen. Which will print better?

Exposure Setting 1

Exposure Setting 1

Exposure Setting 2

Exposure Setting 2

Take a moment to look at the histograms before moving forward. For those not familiar with histograms, the shadows are on the left. The highlights are on the right. Printing requires highlights and shifting the histogram will be the single biggest image editing step you can do to give better results. Based on these examples, Exposure Setting 2 will give much better results. So the tip is this — before sending anything to the printer, check the histogram. Memorize the shapes and mentally compare the results to the printed image. You will soon learn where you like the histogram and it will be, as you will discover, shifted to the right.

What about blown highlights? (histogram 2 shows them, can you see why?)

Embrace them! Forget all the pixel peeping woes you hear online about blown highlights when you are printing on fine part papers. Unlike viewing on a screen, the blown highlights tell the printer to not lay down any ink there. What remains, is the texture and warmth of your paper. This creates very natural looking images and help the print become one with the paper. If given the choice of muddy shadows and dull appearance or shadow details and blown highlights, take the latter every time.

The quest for perfect home photography printing

Introduction

Hands down, the best value in home photography printer is the Canon Pixma Pro-100. This is a printer that is frequently given away by Canon with purchase of cameras and other accessories. There's frequently a rebate for 60 - 70% off MSRP, a true bargain!  And because Canon pushes these printers out for virtually nothing, careful or patient shopping on Craigslist or Facebook marketplace can yield a new-in-the-box printer for sometimes as low as $40. Honestly, at that price, it is your single best investment in photography because if you are not seeing your work in the physical world, you are missing the tangible aspects of photography.

However, if you are like most people that thinking pushing the printer icon in your software is sufficient to yield high quality results, you will be disappointed at first.  Printing photographs is a whole lot more nuanced than pushing print on a simple office document. But do not despair, excellent results are well within your reach!

This guide is broken down into a beginner, avid and advanced user of photo printing. The beginner section installs the software and walks through printing on Canon paper using the Print Studio Pro plugin from Lightroom.   The avid printer post will discuss ICC profiles and using non-Canon papers.  The advanced section moves into the world of custom ICC profiles and ink refilling.  The latter is an excellent option if you are heavy printer and want to visualize your work outside the electrons known as Facebook or Instagram. 

Given the scope of this blog post, the content will evolve over time. Feel free to check back or leave a comment on areas you want added or clarified in the guide. 

Table of Contents

Beginner Guide

Avid Printer Guide

Advanced User Guide

 

Beginner Guide

Welcome to the exciting world of home photography printing. Step 1 includes the usual--unboxing and assembly.  I'm just going to say it--breathe.  Yes, the printer is alarmingly large. Honestly, it's a beast. Fortunately, you only need the printer close to the computer during the initial set up. Then, because it is wifi enabled, you can set the printer up in a closet, the garage, the mother-in-laws bedroom, etc. 

For setup, follow the Canon directions carefully. Setting up the wifi on a Mac computer can be a little tricky.  I do not have a PC, but I understand that process is a little more straight out of the box. A largely undocumented step is to use the Print Studio Pro plugin for all printing (Photoshop or Lightroom) at first. Step 1b is to rid yourself of any notion that you are going to just push "print" and go. This guide will encourage you to take it slow. Paper and ink can be a little expensive at first, so taking it slow will help keep it financially constrained.

For users just getting started and are not comfortable with configuring the WiFi through the Canon software, simply start by using the USB cable. You'll need the USB cable connecting the printer to the computer during setup, so just leave it as is so we can print our first set of photos.

Installation of Drivers and Supporting Software

First, throw away ALL of the CDs that came with the printer. Chances are your computer doesn't even have a CDROM drive. Moreover, the drivers and programs on the disk are old and outdated. Start fresh by downloading the latest drivers here: https://www.usa.canon.com/internet/portal/us/home/support/details/professional-large-format-printers/professional-inkjet-printers/pro-100

Install and use the Print Studio Pro plugin

 For beginners, I recommend only printing from this Plugin. It makes much of the process of printing a photograph very clear and reproducible. It's still not foolproof as you do have to carefully consider each of the options, but the options are presented in a logical order that mirrors the process of printing. The plugin also has easy access to "tweaks" you need to make to improve the quality of the printed photo (note: the more advanced tutorials will guide you to get the image right for printing in the edit/virtual copy and not to do post  hoc adjustments). 

This plugin is not obviously located or advertised as a "must use" by the software. You need to fetch it off the internet. You will also likely need to install an updated version every time a new Lr or Ps version is released. So, you may want to bookmark this location as you'll go back to get the plugin on occasion.

On the driver link above, there is a tab labeled "Software". The Print Studio Pro plugin should be available on this page. The software page strives to autodetect your computers operating system and version. You may need to adjust the selections, but generally, you should be presented the correction version automatically.

You will want to have all programs (e.g., Ps, Lr) closed when installing this plug in. 

Canon has a few guides for using the plugin in various tools. There are also some excellent YouTube videos available. I would recommend reading and watching a few of these before you attempt to print your first photo. 

WiFi Network Drivers (Mac)

For those using a Mac, the IJ Network Tool is used to set up the computer to print to the printer via WiFi.  See the installation book that came with the printer for details on configuring this tool. It is straightforward, but it is only needed if you are going to print over WiFi. 


Tips I wish someone had told me when I started home printing:

  • You must match the paper type (brand of paper, sheen of paper, paper size) with the specifications in the Print Studio Pro plugin. Incorrect specification will result in poor print quality without fail.

  • Not all paper is created the same. Subtle differences in paper texture and color will result in printed images that will vary in look *widely* between papers. Do not let this confuse you. For a beginner, make the decision to *only* print on genuine Canon photo paper. Do not be tempted to buy cheap Avery or Staples branded photo paper as a beginner. Shop around for deals on real Canon photo paper. It’s cheap.

  • Sometimes Canon has a “papergate” special where you can stock up on hundreds of sheets of papers with every ink cartridge purchased. Be on the look out for these deals.

  • Your monitor emits light and photographs that look lovely on the computer may be dark and muddy on paper, particularly matte paper. Monitor calibration for both color and brightness is important in photo printing. Starting out, knowing how to read a histogram to ensure the image is properly exposed is good enough for a beginner. The advanced guides below get into more details on what is known as a "color managed workflow". In general, if you see the histogram shifted towards the left, the picture will come out “muddy” on paper, even luster types of paper.

  • Almost any photo will look good on a glossy or luster paper. Matte paper will be low in contrast and will work for some photos and not others. Experimentation is a the key. Do not be discouraged that images print unexpectedly using papers that might be included in a "sampler" pack.

  • Print SMALL at first. Canon practically gives the printers away to sell you more ink. Once you make this connection, you will know why Canon gives you a pack of 13x19 photo paper with the printer. Don't be afraid to cut this paper down to size. Don't be afraid to print a 4x6 images on the top half of a 13x19 piece of paper. Make sure you are comfortable with the processing and look of the pictures before you go large.


Printing your first photo!

Housekeeping Items: At this point, your printer should be sitting some place close to the computer. All of the hidden packing tape should be removed. The printer head and inks should be installed. The printer should be powered on and your computer should see a printer labeled something to the effect "Canon PIXMA Pro-100" in the printer settings window. You should be able to click on the printer icon and view properties of the printer. One of the properties you should check is the ink supply levels. You'll want to keep an eye on these levels as you print so you know which inks you more frequently use and need to replace. It's also a good strategy to open up the printer supplies before printing to verify sufficient ink and connectivity to the printer before printing. 

This guide is going to focus on printing from Lr, which is about the only software I use anymore. Go ahead and navigate to your favorite image and select it. 

One of the first steps in printing is you need to think of the physical medium you are printing too. Most cameras capture images in a 4:3 format. Many people that are used to prints from the pre-digital era think of photos as 3x5x, 5x7s, 8x10s. Note how none of these match the 4:3 format. So as a general recommendation, I suggest you create a virtual copy of your image in Lr so that you can perform a constrained crop to match the aspect ratio you want (often, it is the frame you want to use for the printed photograph). You can try to preserve as much of the image as you would like, but you want to think of the final ratio and crop deliberately on the virtual copy.  You may end up with multiple virtual copies--one for a say a 5x7, one for a 8x10, etc. The virtual copy makes repeated print possible — you never want to let the software crop on the fly or have you manually adjusting every time you print an image.

Once you have the image sized for your paper (or your intended print size), you load the printer with paper.  The manual paper feed is off the back of the printer. Normally, you will use the feeder that is on the top of the printer. You will need to match the paper - feeder location in the plugin.  Take note of the exact name of the paper -- you will also need that in the Print Studio Pro plugin. In general, you do not want to print a "full bleed" image (ink all the way to the side of the paper). You will want a white border around the photo to make mounting the image possible. It also gives you a place to sign your name and helps conserve inks (white space = no ink). So, while the ratio generally needs to match the photo paper size, you print the photo slightly smaller than the paper size--something that is easily performed using the plugin.

Now, launch the plug in by goin to the File - Plugin Extras menu. From there, select the Canon Print Studio Pro option.

This will launch the plugin with the image preloaded (as an aside: ensure you only have a single image selected in lightroom before launching the plugin). In the right panel, specify the paper size, paper type and the printer if needed. As mentioned above, you will want to print with a border, so select that option. You should be presented with sliders that adjust the relative size of the image on the paper. You are presented the white space that will remain. The image can be centered on the paper (the usual setting) or if you are printing a small image on a large piece of paper, you can move the image around the page using the sliders or direct text entry of the location. 

Before you push the print button, make sure your first image you print is not a 13x19! Yes, I know it is tempting, but don't do it. Save your inks. Print a small 4x6 (again, make sure you are not using some random junk paper; genuine Canon paper as a beginner!). If you do not have small paper, cut the 13x19 that came with the printer or simply scale the image down small and move it out of the center of the paper. This way, you can run the same sheet of photo paper through the printer a few times.

Let 'er rip!  Now push the "print" button on the plug in.  On a Mac, you are presented with the MacOS print dialogue. You should just push the print option with no changes. [note: I don't know what a Windows computer presents here, but it is probably about the same...no changes, just print or continue to move past the dialogue without changes].

 

Review your print

First, the printer will print with quality like you have never seen. The image you look at, however, may look off. Generally, it will appear darker than you anticipated, particularly if you are viewing the photo in a dark editing room. You need to take the photo out into some good natural or bring interior lights before making a final judgement on the print. The color spectrum of your house lights will affect the results too.  For example, warm interior lights will make the image look warm. Hard, "daylight" spectrum will create a different feeling to the image. There are advanced printing techniques that can account for this, but just remember what happens when buy a gallon of paint for a room. You will find something that looks great in the store to only be confused why the paint looks wrong on the wall. If you carried that can back to the store, you would find that the paint does indeed match the chip perfectly.  It's like some evil magic is at work.  It's not. It is simply light reflecting off the surface; the light changes the look and feel of everything from a gallon of Behr to a 4x6 glossy print.

If you do find your printed image is wrong (and as you start, it will be). Run a double check of all of the setting in Print Studio Pro (the plugin remains open once you print...great for double checking). If all matches the paper correctly, then move on to other sources of trouble. If the printed image appears too dark in good light, verify your histogram and monitor brightness. I favor adjusting the exposure in the virtual image as that makes printing reproducible. You can update the brightness in the plugin, but that requires you to remember the settings. If the colors look off, review your image on other computers/devices. This may involve sending it to a friend with a calibrated monitor. Many times computer monitors are set to the wrong color temperature and that causes the print to look different than expected. 

If  you found your image looked ready to be shared with the world, try to print a few other images small. Select some that are black and white or show a wide color range. I would recommend not printing low key images at home unless you feel that you want to buy a lot of black ink cartridges.  The low key images are also hard to print as they frequently come out too dark. I would save those for send away services. 

Avid Printer Guide

At this point in the guide, you should be reliably printing using standard Canon papers. You have a work flow that doesn’t lead to wasted paper or ink. You can tell by looking at the histogram how well the picture will look on paper. Now, you are ready to go more creative things with the printer.

The first step in venturing out is to look at other paper sources. There’s great options from places like Canson, Hahnemühle, and other smaller suppliers. My favorite source is Red River Paper. I have found the quality of the paper from Red River to outstanding. The price is affordable, even for their fine art papers. Red River is generous with “ICC Profiles” for all of their papers across many printers, including the Pro 100.

What is an ICC profile you ask? Think of the ICC profile as something like high altitude baking directions. It’s important to get the ingredients just right so that the meal comes together correctly. That’s what the ICC profile does. Each type of paper will have a slightly different surface, slightly different color, and slightly different properties for how the paper absorbs ink. The combination of these things means something as simple as “red” will vary from paper from paper. To bring more uniformity to “red” across various papers, subtle differences in the ink mixtures are required. The ICC profiles store all of this and bring the paper to life.

Install ICC Profiles. For the installation of ICC profiles, I refer readers to the excellent documentation on Red River Paper’s support site. The general process is select your printer type, select your paper type, download the ICC profiles, and install it. Red River has detailed instructions along with a video guide. It’s not hard. You only do it once, too.

Using ICC profiles in the Print Studio Pro plug in is straight forward, sort of. Each box of paper will give you instructions on how to select the correct paper type for the specialty paper. This is needed since the Canon branded paper names are the only papers showing up in the print driver. For example, you won’t see one of my favorites general purposes paper - Red River UltraPro Statin. Assuming the ICC profiles are installed, you deselect the “auto” option from the printer profile dropdown and instead select the correct ICC profile for the paper you are printing.

While this doesn’t seem all that “avid”, you are now venturing out into a new area. You are now having to be responsible for coordinating paper types and ICC profiles for the paper of your choosing. This means more chances to go wrong. The plan to start small is a good one.

Use this as an opportunity to get creative with papers. Experiment. You can print on a variety of media types. Each will behave differently—glossy to matte, white to natural (warm white). Using vendor provided ICC profiles generally gives good results. Things change when you start exploring different inks, which brings us to the Advanced guide.

Advanced User Guide

Coming Soon

Building a Deep Learning Mac

Let's face it. Deep learning is rapidly being explored as the next frontier in statistical modeling. The current options for deep learning include cloud-based computing, UNIX workstations, and to a limited extent Windows computers (Windows and Python do not readily agree). Mac OS has been left in the dust because of the lack of support for NVIDIA at Apple. Honestly, it's a disgrace and a huge misstep for Apple. 


Things are slowly improving based on work featured at egpu.io.  Support for NVIDIA GPUs is still unsupported at Apple, but people are having great success getting systems up and running. I'm one of those people. We are in the process of receiving an NIH grant to help document and train people on how to turn their run-of-the-mill Mac into a deep learning power house.  The instructions for this are evolving, so I'm using Github.com to help with version control. 

The documentation is underway and can be found here:

https://github.com/rickeycarter/macDeepLearning/

Please feel free to drop a question or feedback here or on Github. 

 

My first R package on CRAN

There comes a day when one needs to share programming code that could be useful to the broad scientific community. In the past, I have made a passing note in manuscripts that the statistical code is made available by simply emailing me with a request. This was nice in some ways as I was able to meet people around the world interested in some of my research. However, this isn't practical as email accounts can change and it limits discovery of the methods. So, we need a code repository to host the data. The current state of code sharing seems to be dominated by GitHub, and I have a GitHub for this purpose. However, there is still a desire to have an R package be "officially" available on the Comprehensive R Archive Network (CRAN).   

So perhaps this could be thought of as a statistical right of passage. Said differently, it's about time that I made this step to share code on CRAN. Well, it's my pleasure to introduce my first package -- mueRelativeRisk. The methods for the methods have been published elsewhere, so I wanted to give a general summary of the method here.

First, what's the problem?

A problem that is common to many areas of math is division by zero is bad. When quantifying relative risk, you need the probability that an outcome will happen if 'exposed' and divide that by the probability in a control condition. In the example that is listed in the above paper, the "outcome" was serious hypoglycemia. The exposure in question was intensive glycemic control for patients with diabetes.  This technique tries to mimic the body's natural ability to regulate glucose in the body. A frequently encountered problem is that the attempts to keep glucose levels low can result in glucose levels that are too low and are unsafe (serious hypoglycemia). The control condition in the study was a less intensive management. We wanted to quantify if the intensively managed patients were at an increased risk of hypoglycemia in the context of the research study.  If so, protocol modifications would need to be considered to minimize the risks of participating in the study.

The statistical problem is that we didn't observe hypoglycemia early in the study. So, our estimates of relative risk were undefined. Do we throw are hands up and say, sorry, I can't quantify the relative risk? Well, in fairness, that part of our approach. However, importantly, we worked to try to come up with a solution that work.  Our estimator for relative risk, based on the median unbiased estimator, is now available and simple to use.

In the paper, we reported that at time of the first interim analysis, we had 7 total participants in the study, 3 of which were randomized to intensive glycemic control. There were no serious hypoglyemic events at that point in the study, so the the common estimate for relative risk would be RR = (0/3) / (0/4), which is not defined. The following code allows one to estimate the relative risk based on the median unbiased estimator. 

# Using The statistical programming software R...
# Install the Package from CRAN
install.packages("mueRelativeRisk")

# load the package for use
library(mueRelativeRisk)

# Estimate the MUE-based estimate
mue_RelativeRisk(3,0,4,0)

Once the function is executed, the following results are obtained. This blog post skips over how the confidence interval is generated. We'll save that for a future post as it's pretty cool. 

  prop1    p1_mue prop2     p2_mue mue_rr_estimate mue_ci_lower mue_ci_upper
1   0/3 0.1031497   0/4 0.07955179        1.296636    0.2067111     8.055469

The methods suggests that the estimated RR is 1.3 (95% CI: 0.2 to 8.1). Essentially, this result is statistically inconclusive, but nonetheless, it can give valuable information about the statistical uncertainty in the estimate and allows for complete monitoring of the study results. 

Questioning the universal truths

We are surrounded in life by universal truths.  I'm talking about everyday beliefs that are believed in so strongly that questioning them seems wrong. I'm not talking about religion, but rather important things such as stepping on a crack and breaking your mother's back.  Another one is having to put a jigsaw puzzle together by first completing the border. I suppose I like to question things.

Let's talk about jigsaw puzzle strategy. Before that, here are my credentials.  I'm a self-declared jigsaw master.  I have no data, no awards or really anything other than my own perception to support this claim. Nonetheless, I'm a master; trust me ;)

Five reasons you should adopt a more liberating strategy of puzzle solving.

  1. You stop wasting time looking for those hidden border pieces.
  2. Focusing on high contrast areas will sort and reduce the puzzle piece count quickly.
  3. You are easily able to move pieces/chunks in and out of the center of the puzzle.
  4. The border is easily solved as pieces are located. You can solve the border in parallel with the inside pieces.
  5. I am a puzzle master.

Just in case you are wondering how I solve a puzzle, I made a time lapse of me solving a relatively easy puzzle. You can see my strategy at work. Start with a clear workspace. As you turn over puzzle pieces, look for high contrast pieces that you know generally where they will go. Group those together in the general area that they will be placed in the final puzzle. For the others, group roughly by color. Then, work by selectively moving over various high contrast regions to dwindle down the piece count. This can include the border pieces, but you don't have to start there. Good luck!

tflearns applied to MNIST data

Preamble. Deep learning is hard. It is much harder than MNIST would lead you to believe. MNIST for all practical purposes is "solved" and as such, it isn't as interesting as it once was.  Nonetheless, we know models can be trained to perform very well against the data. This provides an opportunity for me to test out some of my generic coding based on tfruns.

 

This blog post presents my newly created "tunable" convolutional neural network (CNN) that runs within RStudio using their tfruns package.  The tfruns package addresses one of the large hassles of training a CNN--how does one systematically search over the numerous tunable parameters?  A large tuning array crossed with significant training time means either you stay glued to the computer to minimize computational downtime or you write your own wrappers to do the grid search.  The latter is a good approach. However, the good folks at RStudio have written something that works extremely well.

 

The following is the code for a three part program.  First, is the control program that defines the grid search.  The second program is the flexible CNN architecture that is tunable. The final program analyzes the results and shows how a model can be extracted from the results and utilized for prediction.

 

This video details the programs and walks through the results that were obtained.


Program 01: prog01_tfruns_control.R

library(tfruns)
library(keras)
library(tidyverse)
library(keras)
library(reticulate)


## load the mnist data
# Input image dimensions
num_classes <- 10
img_rows <- 28
img_cols <- 28

# The data, shuffled and split between train and test sets
mnist <- dataset_mnist()
x_train <- mnist$train$x
y_train <- mnist$train$y
x_test <- mnist$test$x
y_test <- mnist$test$y

# Redefine  dimension of train/test inputs
x_train <- array_reshape(x_train, c(nrow(x_train), img_rows, img_cols, 1))
x_test <- array_reshape(x_test, c(nrow(x_test), img_rows, img_cols, 1))
input_shape <- c(img_rows, img_cols, 1)

# Transform RGB values into [0,1] range  and drop underscore for skeleton program
xtrain <- x_train / 255
xtest <- x_test / 255

cat('x_train_shape:', dim(xtrain), '\n')
cat(nrow(xtrain), 'train samples\n')
cat(nrow(xtest), 'test samples\n')

# Convert class vectors to binary class matrices
y_train <- to_categorical(y_train, num_classes)
y_test <- to_categorical(y_test, num_classes)


# initial tuning run
runs <- tuning_run("prog02_keras_skeleton.R", sample=.005, flags=list(
        batchsize=c(128,256),
        nepochs=20,
        lrate=c(0.001),
        augment=c(T, F),
        flip=c(T,F),
        valsplit=.1,
        nconvolutions = 2,
        drop1 = .5,                                                       
        activationc= c("leaky","relu"),
        meanpool = c(T,F),
        
        pad1="same",
        pool1=c(2),
        pool2=c(2),
        kernel1=c(3),
        kernel2=c(3),
        filter1 = c(32, 64, 96),
        filter2 = c(32, 64, 96),
        filter3 = c(32, 64, 96),
        
        ndense1 = c(1,2),
        ndense2 = c(1,2,4),
        activationd= c("relu","leaky"),
        hidden1=c(100,500), 
        hidden2=c(100,500),
        drop2= .5
        ) 
)


View(runs)

Program 02: prog02_keras_skeleton.R

FLAGS <- flags(
  flag_integer("batchsize", 128, "Batch size"),
  flag_numeric("nepochs", 10, "Number of epochs"),
  flag_numeric("lrate",0.01,"Learning rate"),
  flag_boolean("augment",T, "Use data augmentation"),
  flag_boolean("flip",T,"Horizontal flip of images"),
  flag_numeric("valsplit",0.2, "Validation sample split (non-augmented only)"),
  
  
  ## convolution turning parameters
  flag_numeric("nconvolutions",1,"Number of extra convolution cycles"),
  flag_numeric("drop1",0.5, "Dropout for the pooling"),
  flag_string("activationc","relu","Activation for the convolutions"),
  flag_boolean("meanpool",T, "Use mean or max pooling"),
  flag_string("pad1","same", "Padding"),
  flag_integer("pool1",2, "Size of first pooling"),
  flag_integer("pool2",2, "Size of subsequent pooling"),
  flag_integer("kernel1",3, "Kernel size for first set of convs / pooling"),
  flag_integer("kernel2",3, "Kernel size for extra set of convolutions"),

  flag_integer("filter1",16, "Number of filters for first conv within set"),
  flag_integer("filter2",32, "Number of filters for second conv within set"),
  flag_integer("filter3",16, "Number of filters for third conv within set"),
  
  ## dense layer tuning
  flag_numeric("ndense1",1,"Number of dense layer 1s"),
  flag_numeric("ndense2",1, "Number of dense Layer 2s"),
  
  flag_string("activationd","relu","Activation for the dense layers"),
  flag_numeric("hidden1",100, "Size of first dense layer"),
  flag_numeric("hidden2",100, "Size of subsequent dense layers"),
  flag_numeric("drop2",0.5, "Dropout for the dense layers")
)


ydim <- ncol(y_train)
numsamples <- nrow(xtrain)
numtest <- nrow(xtest)

batch_size <- FLAGS$batchsize
n_epoch <- FLAGS$nepochs
meanpooling <- FLAGS$meanpool
activation <- FLAGS$activationc
denseactivation <- FLAGS$activationd

model <- keras_model_sequential() 


  ############################# CONVOLUTION SET 1 ##########################
  # three set of filters, then a pooling
  # note: using several model %>% commands to make the whole model more programatic 
model %>%  layer_conv_2d(filter = FLAGS$filter1, kernel_size = c(FLAGS$kernel1,FLAGS$kernel1), padding = FLAGS$pad1, input_shape = c(img_rows, img_cols, 1) )
model %>% layer_batch_normalization()   
# add switch for the activation function
if (activation == "leaky"){
model %>% layer_activation_leaky_relu() 
} else {
model %>% layer_activation("relu")  
}

model %>% layer_conv_2d(filter = FLAGS$filter2, kernel_size = c(FLAGS$kernel1,FLAGS$kernel1), padding = FLAGS$pad1)
model %>%  layer_batch_normalization()   
if (activation == "leaky"){
  model %>% layer_activation_leaky_relu() 
} else {
  model %>% layer_activation("relu")  
}

model %>% layer_conv_2d(filter = FLAGS$filter3, kernel_size = c(FLAGS$kernel1,FLAGS$kernel1), padding = FLAGS$pad1) 
model %>%  layer_batch_normalization() 
# add switch for the activation function
if (activation == "leaky"){
  model %>% layer_activation_leaky_relu() 
} else {
  model %>% layer_activation("relu")  
}

if ( meanpooling) {
# Use mean pooling
  model %>% layer_average_pooling_2d(pool_size = c(FLAGS$pool1, FLAGS$pool1)) 
} else {
  model %>% layer_max_pooling_2d(pool_size = c(FLAGS$pool1, FLAGS$pool1)) 
}
model %>%  layer_dropout(FLAGS$drop1) 
  
  
  ############################## extra convolutions
for (i in seq(1, FLAGS$nconvolutions)){
  
model %>%  layer_conv_2d(filter = FLAGS$filter1, kernel_size = c(FLAGS$kernel2,FLAGS$kernel2), padding = FLAGS$pad1) 
model %>%  layer_batch_normalization()   
# add switch for the activation function
if (activation == "leaky"){
  model %>% layer_activation_leaky_relu() 
} else {
  model %>% layer_activation("relu")  
}

  
model %>%  layer_conv_2d(filter = FLAGS$filter2, kernel_size = c(FLAGS$kernel2,FLAGS$kernel2), padding = FLAGS$pad1) 
model %>%  layer_batch_normalization() 
# add switch for the activation function
if (activation == "leaky"){
  model %>% layer_activation_leaky_relu() 
} else {
  model %>% layer_activation("relu")  
}

  
  
  
model %>%  layer_conv_2d(filter = FLAGS$filter3, kernel_size = c(FLAGS$kernel2,FLAGS$kernel2), padding = FLAGS$pad1) 
model %>%  layer_batch_normalization() 
# add switch for the activation function
if (activation == "leaky"){
  model %>% layer_activation_leaky_relu() 
} else {
  model %>% layer_activation("relu")  
}
 
 
  if ( meanpooling) {
    # Use mean pooling
model %>% layer_average_pooling_2d(pool_size = c(FLAGS$pool2, FLAGS$pool2), padding=FLAGS$pad1) 
  } else {
model %>% layer_max_pooling_2d(pool_size = c(FLAGS$pool2, FLAGS$pool2), padding=FLAGS$pad1) 
  }
model %>%  layer_dropout(FLAGS$drop1)
  
}  
  ################# end of extra convolutions
    
    
  # Flatten max filtered output into feature vector 
  # and feed into dense layer
model %>%  layer_flatten()
  

## now loop over the number of dense layer 1s

for (i in seq(1,FLAGS$ndense1)){
model %>%    layer_dense(FLAGS$hidden1) 
  if (denseactivation == "leaky"){
    model %>% layer_activation_leaky_relu() 
  } else {
    model %>% layer_activation("relu")  
  }
model %>%    layer_dropout(FLAGS$drop2)
}  
 
for (i in seq(1,FLAGS$ndense2)){ 
model %>%    layer_dense(FLAGS$hidden2) 
    if (denseactivation == "leaky"){
      model %>% layer_activation_leaky_relu() 
    } else {
      model %>% layer_activation("relu")  
    }
model %>%   layer_dropout(FLAGS$drop2) 
}  
  

model %>%   layer_dense(ydim) 
model %>%    layer_activation("softmax")

opt <- optimizer_adam(lr=FLAGS$lrate)

model %>% compile(
  loss = "categorical_crossentropy",
  optimizer = opt,
  metrics = "accuracy"
)

summary(model)

# Training ----------------------------------------------------------------

callbacks_list <- list(
 callback_model_checkpoint(filepath = "bestepoch.h5", save_best_only = TRUE, save_weights_only = FALSE) 
  
)


data_augmentation <- FLAGS$augment
#data_augmentation <- F
if(! data_augmentation){
  
  model %>% fit(
    xtrain, y_train,
    batch_size = FLAGS$batchsize,
    epochs = FLAGS$nepochs,
    validation_split = FLAGS$valsplit,
    shuffle = TRUE,
    callbacks = callbacks_list
  )
  
} else {
  
  datagen <- image_data_generator(
    featurewise_center = TRUE,
    featurewise_std_normalization = TRUE,
    rotation_range = 20,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    horizontal_flip = TRUE
  )
  valgen <- image_data_generator(
    featurewise_center = TRUE,
    featurewise_std_normalization = TRUE,
    rotation_range = 20,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    horizontal_flip = TRUE
  )
  
  
  datagen %>% fit_image_data_generator(xtrain)
  valgen %>% fit_image_data_generator(xtest)
  
  model %>% fit_generator(
    flow_images_from_data(xtrain, y_train, datagen, batch_size = FLAGS$batchsize),
    steps_per_epoch = as.integer(floor(numsamples/FLAGS$batchsize)), 
    epochs = FLAGS$nepochs,
    callbacks = callbacks_list,
    validation_data = flow_images_from_data(xtest,y_test, valgen, batch_size=FLAGS$batchsize),
    validation_steps = as.integer(floor(numtest/FLAGS$batchsize))
  )
  
}


# ---------

save_model_hdf5(model, "model.h5")
scores <- model %>% evaluate(xtest, y_test, verbose=0)

cat('Test loss', scores[[1]], '\n')
cat('Test accuracy:', scores[[2]], '\n')

Program 03: program03_analyzeruns.R

## analyze Runs
library(tidyverse)
library(tfruns)
library(keras)
load("finishedruns.RData")

myplot_cat <- function(varname){
  p<-ggplot(finishedruns, aes_string(y="metric_val_acc", x=varname)) + geom_jitter(height=0, width=.2) +
    theme_bw()
  return(p)
}
flagnames <- names(finishedruns)
flagtrue <- stringr::str_detect(flagnames, "flag")
subflagnames <- flagnames[flagtrue]

for (i in subflagnames){
print(myplot_cat(i))
}


## now look at the poor performance
poormodels <- dplyr::filter(finishedruns, metric_val_acc < .9)

View(poormodels)


## load best model
bestrun <- finishedruns %>% arrange(-metric_val_acc)
run_info(bestrun$run_dir[1])
bestrun<-run_info(bestrun$run_dir[1])

names(bestrun)


bestrun$run_dir
modelpath<- paste0(bestrun$run_dir, "/model.h5")
mod1 <- load_model_hdf5(modelpath)

############# test model on original images
x_train <- mnist$train$x
y_train <- mnist$train$y
x_test <- mnist$test$x
y_test <- mnist$test$y

# Redefine  dimension of train/test inputs
x_train <- array_reshape(x_train, c(nrow(x_train), img_rows, img_cols, 1))
x_test <- array_reshape(x_test, c(nrow(x_test), img_rows, img_cols, 1))
input_shape <- c(img_rows, img_cols, 1)

# Transform RGB values into [0,1] range  and drop underscore for skeleton program
xtrain <- x_train / 255
xtest <- x_test / 255

pred_test <- predict_classes(mod1, xtest)
head(pred_test)

cm<-table(pred_test, y_test)

caret::confusionMatrix(cm)

Welcome to my website!

I've wanted to start a website and blog for a long time. Since 2018 is well underway, it would appear I could either wait 9 months for a 2019 resolution or come up with a backup plan. I suppose the first day of Spring is just as good as the first day of the year to make a resolution, so here it is. I'm striving to share a little about my interests.  Maybe I'll share something useful.  Perhaps I'll share something irrelevant. Hopefully in the end, I'll capitalize on the opportunity to share something!

My goals are to write up some technical aspects of my work transitioning from the ideas of classical biostatistics to modern machine learning techniques. In addition, I hope to share some interest of mine that range from cycling to photography.

The name "pedaling time" is meant to be a playful adaption of my interest in cycling and passing some time with hobbies. 

I look forward to the growth of the website. 

~Rickey