In runMNISTModel, we call the helper method LoadModel to load the GAN model and then set the input tensor to be 6 batches of 100 random numbers with normal distribution (mean 0.0 and std 1.0). The random input with normal distribution is what the model expects. You can change 6 to any other number and get back that number of generated digits:
- (NSArray*) runMNISTModel {
tensorflow::Status load_status;
load_status = LoadModel(@"gan_mnist", @"pb", &tf_session);
if (!load_status.ok()) return NULL;
std::string input_layer = "z_placeholder";
std::string output_layer = "Sigmoid_1";
tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({6, 100}));
auto input_map = input_tensor.tensor<float, 2>();
unsigned seed = (unsigned)std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator (seed);
std::normal_distribution<double> distribution(0.0, 1.0);
for (int i = 0; i < 6; i++){
for (int j = 0; j < 100; j++){
double number = distribution(generator);
input_map(i,j) = number;
}
}
The rest of the code in the runMNISTModel method runs the model, gets the output of 6*28*28 floating numbers, representing the grayscale value at each pixel for each batch of image sized 28*28, and calls the method createMNISTImageInRect to render the numbers in an image context using UIBezierPath before converting the image context to UIImage, which gets returned and displayed in UIImageView:
std::vector<tensorflow::Tensor> outputs;
tensorflow::Status run_status = tf_session->Run({{input_layer, input_tensor}},
{output_layer}, {}, &outputs);
if (!run_status.ok()) {
LOG(ERROR) << "Running model failed: " << run_status;
return NULL;
}
tensorflow::string status_string = run_status.ToString();
tensorflow::Tensor* output_tensor = &outputs[0];
const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>, Eigen::Aligned>& output = output_tensor->flat<float>();
const long count = output.size();
NSMutableArray *arrayGreyscaleValues = [NSMutableArray array];
for (int i = 0; i < count; ++i) {
const float value = output(i);
[arrayGreyscaleValues addObject:[NSNumber numberWithFloat:value]];
}
return arrayGreyscaleValues;
}
The createMNISTImageInRect is defined as follows – we used the similar technique in Chapter 7, Recognizing Drawing with CNN and LSTM:
- (UIImage *)createMNISTImageInRect:(CGRect)rect values:(NSArray*)greyscaleValues
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(rect.size.width, rect.size.height), NO, 0.0);
int i=0;
const int size = 3;
for (NSNumber *val in greyscaleValues) {
float c = [val floatValue];
int x = i%28;
int y = i/28;
i++;
CGRect rect = CGRectMake(145+size*x, 50+y*size, size, size);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
UIColor *color = [UIColor colorWithRed:c green:c blue:c alpha:1.0];
[color setFill];
[path fill];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
For each pixel, we draw a small rectangle of width and height both as 3, with the grayscale value returned for the pixel.