Search

Geek Girl Joy

The Impending Death of the Programmer

Programming WILL NOT be the last job automated

EndangeredSpecies

If you are a programmer your days are numbered and I am not talking about the coming bootcamp tech bubble bursting!

I suspect the next tech bubble (the “tech-pocalyps” if you will) will be brought on by all the programming bootcamps which are selling an unsustainable idea, “everyone needs to be a programmer!”, I honestly don’t disagree in principal as having some coding skills are REQUIRED going into the coming decade, no argument there!

Yet, if you ask just about anyone what is the hot tech career path right now and the answer is almost always “coding, coding, CODING!!!”.

But is that right? There is this sense that if you know how to code you will be employed until we succeed as a species in establishing a technological singularity.

I suspect that many junior dev’s imagine quite literally that it will be their job’s that go down in the history books with their image along with a caption that reads “John or Jane Smith, the last employed person…”smiley-1914523_640

That dubious honor will almost certainly NOT go to a programmer, perhaps a mathematics PhD, but probably a politician. πŸ˜›

Yet, it’s hard to miss all the automation happening around us that is rapidly supplanting “unskilled labor” jobs with robots (currently on the market):Β plumber robots, window washing robots , robotic vacuums & mops & pool cleaners, even a robotic chef:

It’s only the beginning! The “Age of the Robot” is upon us!

So, logically you’d think we would need a ton of programmers right? Even if its just to write minor changes to behavior routines and bug fixes…. think again!

New methodologies allow industry manufacturing / warehouse automatons like Baxter to learn from unskilled personnel (sans programming) just by watching them perform the desired action.

You might think “that’s real cute Joy” but you can’t really code software by teaching a computer! Even WixΒ and WordPress require a coder to build the template first. Surely the the data is too complex, there is too much subtle variance to model… perhaps that isn’t the case.

What if, you could employ machine learning to take a description in plain English… (or insert your native tongue here)… of a function, method, class, application, website etc…

Then have another neural network draw a set of images of what it should look like? Perhaps like thumbnails or rough sketches for the user to pick from. This would also allow the user skip the description phase and simply supply their own sketches and drawings for the next step.

What if, you then took those images and fed them into another set of neural networks which could convolve (yes that’s a word :-P) over them to identify the parts of the image as “components” such as an input field, a button, a menu etc… and then use that data to generate the appropriate code (not just the visual code but the linking and processing back-end code as well).

Further still, what if that code was cross language, domain and platform?

Ok now I start to sound like I’m way off in the weeds talking about the future right? Such a feat sounds too good to be true! Until very recently I would have agreed with you… but I’ve seen it, it exists! Or rather, the pieces of the puzzle now exist and its time to start putting it together!

First lets address the subject cross language, domain and platform. You may already be aware that we have effectively solved the cross language, domain and platform challenge via tools like KikAppTools (PHP to Android (Java) or iOS (Objective C)) and Unity3D (C# & JavaScript) which literally transpiles to run on every platform.

So we can already take one programming language and convert it to another depending on whatever the situation requires… mostly.

As an aside, there is actually a need for more of these Language X to Language Y converters which will finally end the epic flame wars (fan-boy/girl-ism) among programmers over the best language and usher in a period of true “language agnosticism” among developers as you can use multiple languages concurrently on any product and then munge (think git merge) them into the final product!

What about the other stuff? Well I’m glad you asked!

Using predictive text this Char-RNN this will write paragraphs about the subject and style of the material it is trained on: http://karpathy.github.io/2015/05/21/rnn-effectiveness/

Here is an RNN that takes an image and writes a little story about it: https://github.com/ryankiros/neural-storyteller

This GAN (Generative Adversarial Networks) learned to turn stills into animations:

What if, we trained something like these neural networks to receive software descriptions and generate software layouts as well as vice versa?

Still, that is far cry from producing actual compilable code.

Well take a look at this article on “how to train a neural network to code by itself” by Thibault Neveu. He demonstrates training an LSTM RNN using TensorFlow to write C code!

It is NOT a perfect push button example, none of the examples are perfect, however they work well enough that they foreshadow things that are coming sooner than you think!

Now imagine if you could build an API around the systems I describe in this article, it would generate trillions in profit and end the career of the typical programmer!

Once I complete my current dev cycle I will begin experimenting with implementing the system I describe above for myself and my followers. Anyone who wants to help or fund me, please support me on Patreon or contact me directly.

Programmers you are on notice, my bots are coming for your jobs!

Please note that the statements and thoughts in this post are my own, none of the brands or companies I mention have payed me or offered me anything for this blog post. Having said that, I would love to have them and all of you as sponsors over on Patreon!

Much Love,

~Joy

Machine Learning from a Database

At some point it will cross your mind…

“I want to train my Neural network from data stored in my database…”

Fear not! because that’s what this post is about!

This post will include actual functional (cut and paste) code so rather than a long series of tutorials I will keep things simple and brief so you can see how easy it is.

You might recall reviewing the XOR function when I wrote about it over in Getting started with Neural Networks Part 2

In that post I trained a neural network to perform the XOR operation.

XOR is frequently used as a sort of “hello world” example and the training data required is short and simple so we will use XOR again here, however you could easily extend the code so that it meets your project needs.

As for the database, MySQL (or MariaDB) is wildly popular, especially for web based projects and it also offers ACID compliance so it stands to reason that any important data you want to train your Neural Network on will likely already be stored in MySQL and as such I will be using it in this tutorial but you could do this with MongoDB or some other storage resource if you prefer.

Step 1 – Setup the Database

So to get started, go create an empty database, you can call it whatever you like but in this example my database will simply be called ‘test‘. There is a function bellow called “CreateTable” that will put the XOR training data in the database for you or you can use this SQL query:



CREATE TABLE `TrainingSets` (
  `ID` int(11) NOT NULL,
  `Name` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
  `TrainingData` text COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `TrainingSets` ADD PRIMARY KEY (`ID`);
 
INSERT INTO `TrainingSets` (`ID`, `Name`, `TrainingData`) VALUES(1, 'XOR', '-1 -1\n-1\n-1 1\n1\n1 -1\n1\n1 1\n-1');
ALTER TABLE `TrainingSets` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;


 

Step 2 – The Functions

Here are the functions you will need. You will need to modify them to meet your needs or write your own versions as the code here is written with the XOR example in mind.



// This function will setup the $table table in your database and
// then insert the XOR Training Data
function CreateTable($host, $user, $pass, $database, $table, $field){
    
    $result = false;
    
    // Create connection
    $connection = new mysqli($host, $user, $pass, $database);
    // Check connection
    if ($connection->connect_error) {
        die('Connection failed: ' . $connection->connect_error);
    }
    // sql to create $table table
    $sql = "CREATE TABLE `$table` (
  `ID` int(11) NOT NULL,
  `Name` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
  `$field` text COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    if ($connection->query($sql) === TRUE) {
        echo "Table $table created successfully.<br>";
        
        // sql to set the ID field as the PRIMARY KEY
        $sql = "ALTER TABLE `$table` ADD PRIMARY KEY (`ID`)";
        if ($connection->query($sql) === TRUE) {
            echo "PRIMARY KEY set to ID.<br>";
            
            // sql to insert XOR into DB
            $sql = "INSERT INTO `$table` (`ID`, `Name`, `$field`) VALUES(1, 'XOR', '-1 -1\n-1\n-1 1\n1\n1 -1\n1\n1 1\n-1')";
            if ($connection->query($sql) === TRUE) {
                echo "XOR inserted into DB.<br>";
                // sql to "auto increment" ID when new $table are added
                $sql = "ALTER TABLE `$table` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2";
                if ($connection->query($sql) === TRUE) {
                    echo 'ID will AUTO_INCREMENT.<br>';
                    $result = TRUE;
                } else {
                    echo 'Error altering ID: ' . $connection->error . '<br>';
                }
            } else {
                echo 'Error inserting XOR into DB: ' . $connection->error . '<br>';
            }
        } else {
            echo 'Error setting PRIMARY KEY to ID: ' . $connection->error . '<br>';
        }
    } else {
        echo "Error creating $table table: " . $connection->error . '<br>';
    }
    $connection->close();
    
    return $result;
}

// This function calls/pulls the TrainingData from MySQL
function GetTrainingDataFromDB($host, $user, $password, $database, $table_name, $field, $id) {
    $connection=mysqli_connect($host, $user, $password, $database); // open db connection
    $result=mysqli_query($connection,"SELECT $field FROM $table_name WHERE ID=$id"); // query the db
    $data=mysqli_fetch_assoc($result); // pull training data
    mysqli_close($connection); // close connection
    return $data[$field]; // return training data
}

// This function prepares the newline delimited data to be handed off to FANN
/*
Example of "newline delimited data" (like XOR in a Plain Text File) stored in MySQL:
-1 -1
-1
-1 1
1
1 1
-1
1 -1
1
*/
function PrepareDataFromDB($training_data) {
    $training_data = explode("\n", $training_data); // convert training data rows to array
    $num_data = count($training_data);
	   
    // Sift the data and split inputs and outputs
    for($i=0;$i<$num_data;$i++) {
      if($i % 2) { // $training_data[$i] is Output
       $training_data['outputs'][] = explode(' ', $training_data[$i]);
      }else{ // $training_data[$i] is Input
       $training_data['inputs'][] = explode(' ', $training_data[$i]);
      }
    }
    // remove the unsifted data
    foreach ($training_data as $key => $value) {
        if (is_numeric($key)) {
            unset($training_data[$key]);
        }
    }
    return $training_data; // returned the prepared associative array
}

// This function hands the prepared data over to FANN
function create_train_callback($num_data, $num_input, $num_output) {
    global $training_data;
    global $current_dataset;
  
    $dataset = array('input' => $training_data['inputs'][$current_dataset],
                    'output' => $training_data['outputs'][$current_dataset]);
    $current_dataset++;
	
    return $dataset;
}


Step 3 – The Code

Great, now here is the code that demonstrates how to read the data from your database and then train an FANN Neural Network.




// Change to your DB credentials
$host = '127.0.0.1';
$user = 'username';
$password = 'password';
$database = 'test';
$table = 'TrainingSets';
$field = 'TrainingData';

// Insert training data into the database
CreateTable($host, $user, $password, $database, $table, $field); 



// Initialize the program variables
$record_id = 1; // the 'ID' for the training data in MySQL
$current_dataset = 0;
$num_input = 2;
$num_output = 1;
$num_layers = 3;
$num_neurons = 3;
$desired_error = 0.001;
$max_epochs = 500000;
$epochs_between_reports = 1000;

// Get the Training Data from MySQL
$training_data = GetTrainingDataFromDB($host, $user, $password, $database, $table, $field, $record_id);

// Prepare the data
$training_data = PrepareDataFromDB($training_data); 


// How many sets are there?
$num_data = count($training_data['inputs']); 

// Hand the data over to FANN
$train_data = fann_create_train_from_callback($num_data, $num_input, $num_output, "create_train_callback");



// Test for $train_data
if ($train_data) {

    // Create $ann
    $ann = fann_create_standard($num_layers, $num_input, $num_neurons, $num_output);
	
	 

    // Test for $ann
    if ($ann) {
        fann_set_activation_function_hidden($ann, FANN_SIGMOID_SYMMETRIC);
        fann_set_activation_function_output($ann, FANN_SIGMOID_SYMMETRIC);
		
		$result = fann_train_on_data($ann, $train_data, $max_epochs, $epochs_between_reports, $desired_error);

		
		// Train XOR ANN with training data obtained from MySQL
        if (fann_train_on_data($ann, $train_data, $max_epochs, $epochs_between_reports, $desired_error))
		{
           echo 'XOR trained.<br>' . PHP_EOL;
           // Test $ann
           $input = array(-1, 1);
           $calc_out = fann_run($ann, $input);
           printf("XOR test (%f,%f) -> %f\n", $input[0], $input[1], $calc_out[0]);
          
           // destroy $ann
           fann_destroy($ann);
         }
    }
}


echo "<br>All Done!";

If you would like to obtain a copy of this code from GitHub you can find it here: TrainFANNNeuralNetworkFromMySQL.php on GitHub

Here is how it works,Β  we first make sure the training data is in the database by calling CreateTable(), we then define the variables to use with the ANN. You could compute these values at run time from the training data or store it elsewhere in the database, its up to you but I wanted to keep things simple to lessen the chance of confusion so I predefined them.

We call GetTrainingDataFromDB() to retrieve the raw training data from MySQL.

We call the PrepareDataFromDB() function to split the inputs and outputs into an associative array of ‘inputs’ and ‘outputs’ followed up with a call to fann_create_train_from_callback() which uses my callback function create_train_callback() to build the training resource.

At this point we can create a standard ANN resource using fann_create_standard().

Then as usual we specify the activation functions, but instead of using fann_train_on_file() as you may be familiar with, we useΒ  fann_train_on_data() since our training data is a resource in memory because it loaded from MySQL.

We follow that up with a quick test using fann_run() before destroying the resource.

And with that, you now know how to train a neural network from a database!

Please support me on Patreon so I can continue to bring you more great tutorials like this!

As always I hope you found this both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

 

Lets teach AI how to read using PHP IV

 

Welcome back to the fourth and final installment of the OCR tutorial series. I know you have been eagerly awaiting this post which will tie everything together and enable us to finally test the OCR ANN.

Here are the previous posts in this series:

Lets teach AI how to read using PHP

Lets teach AI how to read using PHP Part 2

Lets teach AI how to read using PHP Part 3

 

Before proceeding here is the code we will be considering:

test_ocr.php


<style>
	.blue{color:blue;}
	.green{color:green;}
	.red{color:red;}
</style>

<?php
/*
    OCR( 
	    (string) $img, 
	    (char) $expected, 
		(array) $input, 
		(array)$lookup_array, 
		(FANN neural network resource)$ann
	   );
	
	Description: 
	
	With this function I simply try to illustrate how you could test the OCR ANN. 
				
	$img is a string that should be the name to the training image you are reading from. It is
	used to output the image to the browser results.
	
	$expected is a char that you are actually testing for. eg  
	
	$input should be an array of inputs (encoded pixel data)
	
	$lookup_array should be an array of ASCII characters normalized as floating point values in increments of 0.01
	
	$ann should be a FANN neural network resource.
	
	References:   
	   global - http://php.net/language.variables.scope
	   PHP_EOL - http://php.net/manual/en/reserved.constants.php
	   fann_run() - http://php.net/manual/en/function.fann-run.php
	   floor() - http://php.net/manual/en/function.floor.php
	   count() - http://php.net/manual/en/function.count.php
*/
function OCR($img, $expected, $input, $lookup_array, $ann) {
	global $correct; // refer to the non local $correct variable
	$output = ""; 
	
	/* Display image for reference */
	$output .= "Image: <img src='images/$img'><br>" . PHP_EOL;

	// Run the ANN
	$calc_out = fann_run($ann, $input);
	
	$output .= 'Raw: ' .  $calc_out[0] . '<br>' . PHP_EOL;
	$output .= 'Trimmed: ' . floor($calc_out[0]*100)/100 . '<br>' . PHP_EOL;
	$output .= 'Decoded Symbol: ';
	
	/* What did the ANN think it saw? */
	for($i = 0; $i < count($lookup_array); $i++) {
       if( floor($lookup_array[$i][0]*100)/100 == floor($calc_out[0]*100)/100) {
	        $output .= $lookup_array[$i][1] . '<br>' . PHP_EOL;
	        $output .= "Expected: $expected <br>" . PHP_EOL;
	        $output .= 'Result: ';
	        if($expected == $lookup_array[$i][1]){
	        	$output .= '<span class="green">Correct!</span>';
				
				++$correct;
				
	        }else{
	        	$output .= '<span class="red">Incorrect!</span> <a href="train_ocr.php">Retrain OCR</a>';
	        }
		}
	}
	$output .= '<br><br>' . PHP_EOL;
	
	return $output;	
}


$total = 11; // How many images are to be tested
$correct = 0; // The count of how many images were correctly read by the ANN


/* Setup a resource that points to our ANN .net file */
$train_file = (dirname(__FILE__) . '/ocr_float.net');

/* Confirm the ANN exists */
if (!is_file($train_file))
	die('<span class="red">The file ocr_float.net has not been created!</span><a href="train_ocr.php">Train OCR</a>' . PHP_EOL);

/* Create the ANN resource */
$ocr_ann = fann_create_from_file($train_file);
if ($ocr_ann) {
	// Display the images we are testing (hard coded)
	?>
	<h1 class='blue'>OCR Test</h1>
	<strong>Testing: </strong>
	<img src='images/38.png'> <!-- G -->
	<img src='images/68.png'> <!-- e -->
	<img src='images/68.png'> <!-- e -->
	<img src='images/74.png'> <!-- k -->
	<img src='images/38.png'> <!-- G -->
	<img src='images/72.png'> <!-- i -->
	<img src='images/81.png'> <!-- r -->
	<img src='images/75.png'> <!-- l -->
	<img src='images/41.png'> <!-- J -->
	<img src='images/78.png'> <!-- o -->
	<img src='images/88.png'> <!-- y -->
	<br>
	<?php

	/* 
	    Create the lookup_array from ASCII
		https://en.wikipedia.org/wiki/ASCII
		
        start: ascii dec 33 (!) 
        stop:  ascii dec 126 (~) 
    */
	$result_lookup_array = array();
	$curr = 0.00;
	for($i = 33; $i <= 126; $i++) {
		array_push($result_lookup_array, array($curr, chr($i)));
		$curr+= 0.01;
	}
	

	// For simplicity sake I hardcoded these values below as there is no need to prove that we can read
	// the pixel data for each image (as we already did that in generate_training_data.php) however you 
	// can implement similar methodology to what as I did with GenerateTrainingData() to read pixel values
	// programmaticlly into an array rather than manually specifying it as I show here.
	
	$test_G = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_e = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_k = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_i = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_r = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_l = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_J = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_o = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	$test_y = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	
       
	/* Test OCR and buffer results in the $output variable as string data */
	$output = "";
	$output .= OCR('38.png', 'G', $test_G, $result_lookup_array, $ocr_ann);
	$output .= OCR('68.png', 'e', $test_e, $result_lookup_array, $ocr_ann);
	$output .= OCR('68.png', 'e', $test_e, $result_lookup_array, $ocr_ann);
	$output .= OCR('74.png', 'k', $test_k, $result_lookup_array, $ocr_ann);
	$output .= OCR('38.png', 'G', $test_G, $result_lookup_array, $ocr_ann);
	$output .= OCR('72.png', 'i', $test_i, $result_lookup_array, $ocr_ann);
	$output .= OCR('81.png', 'r', $test_r, $result_lookup_array, $ocr_ann);
	$output .= OCR('75.png', 'l', $test_l, $result_lookup_array, $ocr_ann);
	$output .= OCR('41.png', 'J', $test_J, $result_lookup_array, $ocr_ann);
	$output .= OCR('78.png', 'o', $test_o, $result_lookup_array, $ocr_ann);
	$output .= OCR('88.png', 'y', $test_y, $result_lookup_array, $ocr_ann);
	
    // Determine how accurate the Neural Network is
    $percent_correct = round(($correct / $total) * 100, 2 );
    
	// Output the accuracy results
	echo "<strong>Results:</strong> $correct images correctly decoded out of $total. (<span class='"; 
	
	/* Add a css style to the percentage results */
	if($percent_correct < 70){echo "red'>";}
	elseif($percent_correct < 90){echo "blue'>";}
	else{echo "green'>";}
	
	/* Close css style span and offer link to retrain */
	echo $percent_correct . "%</span>)<br>Not good enough? <a href='train_ocr.php'>Retrain OCR</a><br><br>" ;
	
	/* display detailed results */
	echo "<h2 class='blue'>Details</h2>";
	echo $output;
	
	/* Free up memory associated with the OCR ANN resource. */ 
	fann_destroy($ocr_ann);
} else {
	die("<span class='red'>Invalid file format.</span>" . PHP_EOL);
}

?>

If you run this code the following things will happen:
  1. Β The images we are testing will display on page using HTML <img> elements.
  2. Our neural network will be loaded from the file we created in step 3 of this tutorial.
  3. 11 Tests using the OCR function I provide will be preformed.
  4. The results of the ANN will be computed then displayed as an accuracy %.
  5. Detailed results of each test result will be displayed.

Now that we have tested the OCR ANN, lets break it down and understand what is going on.

 

Step 1 – generate_training_images.php

In Step 1 we create our images and log file.

 

 

 

 

 

 

 

 

 

Step 2 –Β generate_training_data.php

In Step 2 we use the log file as a reference to step through each image and examine every pixel and assign it a value of 1 or 0 based on the color of the pixel. We then save our results to a new file called ocr.data.

 

Step 3 – train_ocr.php

In Step 3 we train the neural network and save it as ocr_float.net.

Step 4 – test_ocr.php (This part of the tutorial)

In Step 4 load the ANN from file ocr_float.net and then proceed to test it. In this image I ran multiple tests and excluded the individual image details however in the code I provided you will get additional data about each test image.

At this point our toy OCR neural network is complete and operating as well as can be expected.

Why is this a “toy” neural network? Because it is trained to “classify” or identify images in a single one off event rather than convolvingΒ (yes that is a real word πŸ˜› ) over the images and extracting features. Basically what this means is that while it eventually got a ~73% correct identification rate it’s not actually going to read text out of just any image… not only that we broke the cardinal rule of testing our ANN with the same data we trained it on (always test on new data not what it was trained on) so the ANN is “hyper fitting” its data set.

We could probably improve accuracy by moving the letters in the images, blurring them rotating them, changing their color and adding the ability for the ANN to work with more than black and white text etc… but in the end it would only be a marginal improvement.

To use OCR for more real world scenarios you will need to implement convolution layers. Which will allow you to not only read the letters and words in an image of any size or color but also do object recognition such as test image 1 is a cat and test image 2 is aΒ ti82 calculator…

And with that I hope you had as much fun following along with this tutorial as much as I had creating it! πŸ™‚

Please support me on Patreon.

If you would like to obtain a copy of this code from GitHub you can find the complete project here: OCR on GitHub

Note: This project (all the code, the title images as well as the infographic licensed under everyone’s favorite license (MIT LICENSE) so feel free to take this code and develop it into something amazing! Please just attribute me as the author of the initial code base. Also if you use this to create something cool, I’d love to hear about it! πŸ™‚

As always I hope you found this project both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

Exciting KikAppTools News

I know many of you are waiting for the last installment of the OCR Neural network series and I will be posting that soon. Today, however I want to talk about something different.

As you know, occasionally I talk about cool tech products and trends that I think my readers should know about and recently I mentioned KikAppTools in this post.

In case you don’t recall, KikAppTools is a free transpiler that lets you build mobile apps using PHP and then compile them to a native iOS or Android installer package.

Well, recently I was speaking with the Executive Developer Liaison for KikAppTools who told me that the initial beta testing phase went better than expected!

During the conversation they let slip a short list of some very exciting features that are being discussed by their dev team for implementation during their next development cycle and at the TOP of everyone list was a GUI interface!

They also said they are looking to expand their operation as they have a small team of developers and need funding to grow so they have started an Indiegogo campaign to help fund their expansion, they need our help to grow!

IF you are a PHP programmer then listen carefully, You can right now (today) automatically expand into the mobile device arena, Over 2 Billion Android devices and while I couldn’t find an exact number for iOS devices it’s roughly around the same adoption, so approximately 4 Billion devices total in 2017, all by adding this free tool to your work flow!

Further still, consider that most of the world now accesses websites and their associated apps from a mobile device! Then its a no brainier to add PHP mobile development to your work flow!

The fact is that yes, today you can make a very good living only developing WordPress, Zend Framework, Laravel, Cake,Β Symfony etc… sites and calling it a day, however unless you are willing to grow, expand and innovate, projects that would have gone to you tomorrow will instead go to the Node, Python, Go or Ruby developers because they are innovating!

You owe it to yourself and the larger PHP community as a whole to start using KikAppTools today! Go download it then head over to their Indiegogo page and fund their work so we can ensure PHP remains the top Server Language on the web and also becomes the preferred language to develop mobile apps with as well!

Please note that the statements and thoughts in this post are my own, KikAppTools has not payed me or offered me anything for this blog post. Having said that, I would love to have them and all of you as sponsors over on Patreon!

As always I hope you found this post both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

Lets teach AI how to read using PHP III

 

Welcome back to the third installment of the OCR series.

In the last post I showed you how to encode the images from a set of training images into training data for the OCR Neural Network we are building.

Here are the previous posts in this series:

Lets teach AI how to read using PHP

Lets teach AI how to read using PHP Part 2

Once the images are encoded as numbers representing the pixel color we are now ready to teach our ANN how to identify symbols in images.

train_ocr.php



<?php

set_time_limit ( 300 ); // max run time 5 minutes (adjust as needed)

$num_input = 160;
$num_output = 1;
$num_layers = 3;
$num_neurons_hidden = 107;
$desired_error = 0.00001;
$max_epochs = 5000000;
$epochs_between_reports = 10;

$ann = fann_create_standard($num_layers, $num_input, $num_neurons_hidden, $num_output);

if ($ann) {
	echo 'Training OCR... '; 
	fann_set_activation_function_hidden($ann, FANN_SIGMOID_SYMMETRIC);
	fann_set_activation_function_output($ann, FANN_SIGMOID_SYMMETRIC);

	$filename = dirname(__FILE__) . "/ocr.data";
	if (fann_train_on_file($ann, $filename, $max_epochs, $epochs_between_reports, $desired_error))
		fann_save($ann, dirname(__FILE__) . "/ocr_float.net");

	fann_destroy($ann);
}

echo 'All Done! Now run <a href="test_ocr.php">Test OCR</a><br>' . PHP_EOL;



If you run this code the following things will happen:
  1. Β A standard fully connected 3 layer backward propagating neural network will be created with 160 inputs, and 1 output.
  2. The ANN will be configured to use the Sigmoid activation function.
  3. The ANN is trained, saved and dumped from memory.

Now that we have trained the ANN all that is left is to test it, which I will cover in my next post.

If you would like to obtain a copy of this code from GitHub or fork this project to follow along as I release the code you can find this project here: OCR on GitHub

Note: This project (all the code, the title images as well as the infographic licensed under everyone’s favorite license (MIT LICENSE) so feel free to take this code and develop it into something amazing! Please just attribute me as the author of the initial code base. Also if you use this to create something cool, I’d love to hear about it! πŸ™‚

As always I hope you found this project both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

Also please support me on Patreon.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

Lets teach AI how to read using PHP II

Welcome back I hope you enjoyed the last post in this series:

Lets teach AI how to read using PHP

We last left off by creating a set of training images for the OCR Neural Network we are building.

This time we will convert the training images we generated into training data that the OCR ANN can use to learn the letters, numbers and symbols in our training images.

This post will be on the short side as the operation is rather simple and the code is commented and referenced so refer to the code below directly. I will cover more of the details in the next post however if you have any questions, comments or trouble leave please leave it in the “Leave a Reply” section below and I will do my best to help out.

Prior to proceeding, you may find it helpful to refer back to the info graphic for this project:

 

generate_training_data.php



<?php
/*
    GenerateTrainingData(
                            (NULL)
                        );
    
    Description: 
        
    This function manages the image creation, call it to create a new image training set.
    
    The images will be 10px wide and 16px tall.
    
    [Example: Capital A Training Image]
    
      Pixels     Encoded
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000
    β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  0000110000
    β–ˆβ–ˆβ–ˆ    β–ˆβ–ˆβ–ˆ  0001111000
    β–ˆβ–ˆ  β–ˆβ–ˆ  β–ˆβ–ˆ  0011001100
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆ        β–ˆ  0111111110
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆ  β–ˆβ–ˆβ–ˆβ–ˆ  β–ˆ  0110000110
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  0000000000

    
    [Example: Capital A Prepared for ANN ]  
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0.32
    
    This algorithm works by iterating over an image pixel by pixel and evaluating the RBG color values of a pixel in an image and assigning a single numerical value to represent the color of the pixel.
    
    White pixels will be encoded as 1 and black pixels will be 0.
    
    Counts begin with 0.
    
    We proceed from the top left corner of the image which for descriptive purposes could be referred to as $row 0, and $col 0 (0,0) and the bottom most right pixel would be the last processed and would be (15,9). 
    
    All columns on a given row will be encoded prior to proceeding to the next row.
  
    As it is currently written the images should be in a sub-folder named 'images' and the image set should 
    be named from 0.png to the last image in the set e.g. 93.png or other if you changed the code that generates
    the training images.
    
    
    References:       
       file_exists() - http://php.net/manual/en/function.file-exists.php
       die() - http://php.net/manual/en/function.die.php
       fopen() - http://php.net/manual/en/function.fopen.php
       fgets() - http://php.net/manual/en/function.fgets.php
       PHP_EOL - http://php.net/manual/en/reserved.constants.php
       str_replace() - http://php.net/manual/en/function.str-replace.php
       array_push() - http://php.net/manual/en/function.array-push.php
       explode() - http://php.net/manual/en/function.explode.php
       feof() - http://php.net/manual/en/function.feof.php
       fclose() - http://php.net/manual/en/function.fclose.php
       getimagesize() - http://php.net/manual/en/function.getimagesize.php
       count() - http://php.net/manual/en/function.count.php
       fwrite() - http://php.net/manual/en/function.fwrite.php
       imagecreatefrompng() - http://php.net/manual/en/function.imagecreatefrompng.php
       imagecolorat() - http://php.net/manual/en/function.imagecolorat.php
       imagecolorsforindex() - http://php.net/manual/en/function.imagecolorat.php
       fwrite() - http://php.net/manual/en/function.fwrite.php
       imagedestroy() - http://php.net/manual/en/function.imagedestroy.php
       fclose() - http://php.net/manual/en/function.fclose.php
       
*/
function GenerateTrainingData() {
    
    /* 
        We will use the $image_array variable to store all the image data as an array.
    
        $image_array[$i][0] = File name / ASCII number
        $image_array[$i][1] = ASCII symbol
        $image_array[$i][2] = Desired output value from the ANN as a floating point number between -1 & 1
        $image_array[$i][3] = Encoded pixel data
    */
    $image_array = array();
    
    /* If no training images don't proceed. Determined by checking for images/0.png */
    if (!file_exists('images/0.png')) {
        /* No Image so do not proceed with the encoding. Output a hyperlink to generate_training_images.php */
        die('No training images run <a href="generate_training_images.php">generate_training_images.php</a> first.');
    }
    
    /* Create an empty file resource that points to ocr.data (where the training data will be stored) */
    $trainingfile = fopen("ocr.data", "w") or die("Unable to open: " . $trainingfile . '. Ending program.');
    
    /* Create a file resource that points to generate_images.log */
    $logfile = fopen("images/generate_images.log", "r") or die("Unable to open: " . $logfile . '. Ending program.');
    
    
    /*
        Use fgets() to open then buffer generate_images.log line by line.
        
        Use str_replace() on the buffered data to remove line ending terminators.
        
        Use explode() to split the remaining buffered data using spaces ' ' as
        delimiter into $image_array
                        
        Example generate_images.log excerpt:
        
        0 !
        1 "
        2 #
        3 $
        4 %
        5 &
        6 '
        7 (
        .......
    */    
    while (($buffer = fgets($logfile, 4096)) !== false) {
        $buffer = str_replace(PHP_EOL, '', $buffer);
        array_push($image_array,  explode(' ', $buffer));
    }
    if (!feof($logfile)) {
        echo "Error: unexpected fgets() fail while reading logfile.\'n";
    }
    
    /* Close the logfile */
    fclose($logfile);
    
    
    /* 
       Use getimagesize() to obtain the width and height of the training images.
       
       We could just hand code these but I wanted to demonstrate how you could 
       programmatically determine the image dimensions.
       
       imgsize[0] = width (10)
       imgsize[1] = height (16)
    */
    $imgsize = getimagesize('images/0.png');
    
    
    /*       
       Next we programmatically determine the number of inputs for the ANN by computing
       the area of the image in pixels. The area of a rectangle is Width * Height, therefore:
       
       10 * 16 = 160 (pixels / inputs) 
    */
    
    $num_of_inputs = $imgsize[0] * $imgsize[1]; 
    
    /* Determine how many images there are */
    $num_of_images = count($image_array);
    
    /* 
        Start writing to the training data file.        
        Write: $num_of_images $num_of_inputs 1
    */
    fwrite($trainingfile, "$num_of_images $num_of_inputs 1" . PHP_EOL);
    
    
    /* Process each image */
    for($i = 0; $i < $num_of_images; $i++){
        $curr_image = "images/$i.png";
        
        /* Load the training image into memory */
        $im = imagecreatefrompng($curr_image);
        
        /* 
            Determine the desired output value for this training image.
            
            Use array_push() to add the desired output to $image_array[$i][2]
        */
        if($i > 0){
            $output_value = 0.01 * $i;
        }else{
            $output_value = 0.00;
        }
        array_push($image_array[$i], $output_value); 
        
        
        
        /* 
            Step through the image and look at each pixel using imagecolorat().
            
            Use imagecolorsforindex() to split $rgb resource to separate $colors array.
            
            Assign the pixel a single value based on its RGB color.
            
            Concatenate all the pixel values into the $pixel_values variable.
        */
        $pixel_values = "";
        for($row = 0; $row < $imgsize[1]; $row++){
            for($col = 0; $col < $imgsize[0]; $col++){
                $rgb = imagecolorat($im, $col, $row);
                $colors = imagecolorsforindex($im, $rgb);
                
                if($colors['red'] >= 225 && $colors['green'] >= 225 && $colors['blue'] >= 225){
                    $pixel_values .= 1 . ' ';
                } else{
                    $pixel_values .= 0 . ' ';
                }
            }
        }
        /*
            Once every pixel has been scanned and encoded for use as inputs
            use array_push() to add the pixel value inputs to $image_array[$i][3]
        */
        array_push($image_array[$i], $pixel_values);
        
        /* Echo links and values for the image */
        echo "<a href='images/" . $image_array[$i][0] . ".png' target='_blank'>" . $image_array[$i][0] . "</a>.png encoded as " . $image_array[$i][2] . "<br>"  . PHP_EOL;
        echo "Pixel Data: " . $image_array[$i][3] . "<br>"  . PHP_EOL;
    
        /* Write the inputs and desired outputs to the training data file */    
        fwrite($trainingfile, $image_array[$i][3] . PHP_EOL . $image_array[$i][2] . PHP_EOL);
        
        /* Free up memory associated with the training image by destroying the resource. */ 
        imagedestroy($im);
    }
    /* All done! Close the training data file. */
    fclose($trainingfile);
}

/* Generate training data from training images. */
GenerateTrainingData();

/* In case the user wishes to review the training data file link to it. */
echo 'Training data: <a href="ocr.data">ocr.data</a><br>' . PHP_EOL;

/* Announce completion and link to next step. */
echo 'All Done! Now run <a href="train_ocr.php">Train OCR</a><br>' . PHP_EOL;



?>

If you run this code the following things will happen:
  1. Each image will be examined pixel by pixel and based on it’s color, encoded as a 0 (black) or 1 (white). As mentioned in the previous post I chose this encoding scheme becauseΒ  I wanted to use high contrast images with the text being white and the background being black, adjust as necessary.
  2. Each pattern of 1’s and 0’s will be assigned a floating point value between 0 and 1.
  3. All the encoded patterns and their values will be saved to a training data file for later use as inputs for the ANN.

Now comes the real fun! In my next post we will train the OCR Neural Network and take it for a test drive! πŸ˜›

If you would like to obtain a copy of this code from GitHub or fork this project to follow along as I release the code you can find this project here: OCR on GitHub

Note: This project (all the code, the title images as well as the infographic licensed under everyone’s favorite license (MIT LICENSE) so feel free to take this code and develop it into something amazing! Please just attribute me as the author of the initial code base. Also if you use this to create something cool, I’d love to hear about it! πŸ™‚

As always I hope you found this project both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

Also please support me on Patreon.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

Lets teach AI how to read using PHP

OCR is a practical example of Optical Character Recognition using FANN. While this example is limited and does make mistakes, the concepts illustrated by OCR can be applied to a more robust stacked network that uses feature extraction and convolution layers to recognize text of any font in any size image.

At the end of this series of tutorials you will be able to build Neural Networks using PHP that can read characters from images! I will be giving you actual working code!

OCR is a practical example of Optical Character Recognition using FANN. While this example is limited and does make mistakes, the concepts illustrated by OCR can be applied to a more robust stacked network that uses feature extraction and convolution layers to recognize text of any font in any size image.

As mentioned this will be a series of posts so that I don’t overwhelm you guys with too much information all at once and so I don’t have to sit here and type ad infinitum (infinite recursion).

πŸ˜›

OCR (Optical Character Recognition) isn’t exactly a new subject but surprisingly its something that few computer scientists have actual experience building! Further, any examples you see are descriptions at best that frequently “devolve” into a math lesson that ultimately glosses over practical application and important implementation details!

Don’t get me wrong, I love math but that isn’t required to start learning. The FANN Library will act as an abstraction layer so we can focus on our data and objectives and not complex differential equations.

Additionally all the code will be thoroughly documented and intentionally simplified and referenced so that even a student with minimal experience can benefit. I happen to believe that Neural Networks are complex enough already, and the more people who know how to build and deploy these systems the faster we can find solutions to the most horrible problems we face as a species (currently incurable diseases, famine, wars over resources, the global energy crisis) need I go on?

So, I am going to provide you with the tools and basic knowledge of how to build POWERFUL artificial intelligence systems and deploy them to cloud servers, not to shabby eh? πŸ˜‰

Not so you can go get rich building games and businesses (which you could easily do and that’s fine) but it is my very real hope that at lease some of you can apply these tools to help make the world a better place, start in your own community today!

In a very surreal way I am reminded of a lyric from the song “I’d Love to Change the World” by Ten Years After

I’d love to change the world, But I don’t know what to do, So I’ll leave it up to you-ooo-ooo

Its rather haunting in how true that actually is, isn’t it?

If you do happen to start a business using these tools and techniques or you simply appreciate the content that I create please support me on Patreon and please share this project with your followers, friends and coworkers on social media.

Now to begin you will need an environment to build your ANN (Artificial Neural Network), rather than reproduce the steps here you can follow this tutorial I wrote to get setup to work: Getting started with Neural Networks using the FANN library, PHP and C9.io

Go follow the setup process and come back, I’ll wait. πŸ˜‰

So, in order for a Neural Network to be useful it needs a β€œproblem space” (basically the thing we want it to learn or do) and a “training set” (examples of data similar to the data the ANN will encounter in the β€œproblem space” but which already has a known value or solution). In this case, because we are teaching the ANN to read characters from images, we need a set of images with alpha-numeric characters in them.

Further, before getting started we have to make sure that we don’t violate the licensing of any training set we use so to keep things simple for this tutorial I will show you how to generate your own basic training data programmatically.

Because the training set will be generated programmatically rather than by hand we are excluding hand written characters from this example ANN however with the use of additional training sets and convolution layers you could add that functionality to this neural network, however again, I want this example to be understandable by everyone.

So with that being said, lets begin by generating the training set of images!

We can use the PHP GD libraryΒ  which is a library used to manipulate images.

The GD Lib is almost always installed (compiled into php) by your host for you already and you probably have used it in the past (even if you didn’t realize it) for your other projects so I wont cover it in too much detail, suffice it to say its pretty east to get access to.

The images in our simple training set will be 10 pixels wide and 16 pixels high.

(10*16 = 160 pixels per image)

And in this example I will use only black and white for simplicity, white will be 1 and black will be 0. It’s completely arbitrary and you could reverse the colors if you wanted but white text on black seems to be high contrast so I decided to use that.

It’s also worth noting the importance of understanding that fundamentally there is no reason why you can’t use floating point values and represent the entire color spectrum or just gray scale.

Switching to a float would allow you to encode more information as a gradient however this will increase complexity of your ANN and you may require more hidden neurons, layers or both in addition to increased training epochs. In reality you would likely be MUCH better off adding convolutions and building a more robust ANN.

This ANN does not use convolution layers and will make a few mistakes from time to time, my point is that this is a simplified, stripped down, easy to understand example however with a little work you could build this into a very robust OCR ANN.

So now lets look at a sample training image as well as dive into the code to generate them!

generate_training_images.php



<?php

/*
    NewImage( 
	          (int)$char, 
	          (mixed)$curr_image, 
			  (int)$x , 
			  (int)$y, 
			  (file resource)$logfile
			);
	
	Description: 
	
	This function actually creates the images. 
	
	It is written with an iterative process in mind where more than a single training image (batch creation) would be generated however a single image can be generated if you prefer.
	
	I have created the GenerateTrainingImages() function that will call this function for you so you *could*
	ignore this function but its the one that does the real work. 
		
	$char uses the chr() function to convert the number passed to an ASCII character.
	
	$curr_image is a mixed type variable used to name the image that is being generated. In this
	case (i.e how I used it in GenerateTrainingImages()) I have used it as a number so it's easy to 
	iterate over the image files using a simple for loop to programmatically create the images we
    need however you could create an array of strings or chars and use those instead however that is
	not quite as simple as the implementation shown here.
	
	$x & $y are direct pass-through variables for the x & y coordinate placement variables as defined
	in the imagestring() function documentation: http://php.net/manual/en/function.imagestring.php
    
	The main reason why I made them "pass-through" rather than hard coding them in the NewImage()
    function is simply that you may want to vary or stagger the placement of the character within the images.
	
	$logfile is a file resource variable that points to the file that will log results of generating
	the training images. You may want to use this file in later steps or for reference. Please note that 
	NewImage() does not open its own access to the file so you will need to open the file resource yourself
	prior to calling NewImage().
	
	
	Example NewImage() Usage:
	
	// Create $logfile resource
	$logfile = fopen("images/generate_images.log", "w") or die("Error: Unable to open: " . $logfile . '. Ending program.');
	
	// This will create a b/w image of an exclamation mark(!) named 0.png
	NewImage(33, 0, 1, 0, $logfile);
	
	// Close log file 
    fclose($logfile);
	
	
	References:	   
	   chr() - http://php.net/manual/en/function.chr.php
	   imagecreate() - http://us.php.net/manual/en/function.imagecreate.php
	   imagecolorallocate() - http://us.php.net/manual/en/function.imagecolorallocate.php
	   imagestring() - http://us.php.net/manual/en/function.imagestring.php
	   imagepng() - http://us.php.net/manual/en/function.imagepng.php
	   imagedestroy() - http://us.php.net/manual/en/function.imagedestroy.php
	   fwrite() - http://us.php.net/manual/en/function.fwrite.php
*/
function NewImage($char, $curr_image, $x , $y, $logfile){
    /* Size the images */
    $width = 10; // px
    $height= 16; // px
	
	/* Set the filename */
    $file_name = $curr_image . '.png';


    /* Create the image resource 
	
	   Note: The @ operator is used to suppress any errors generated by php expressions. 
	         http://us.php.net/manual/en/language.operators.errorcontrol.php
			 
	         I use it to suppress any errors from @imagecreate() and instead cast my own
			 error message by adding an "or die()" to the @imagecreate() statement.
	*/
    $image = @imagecreate($width, $height) or die("Error: Unable to Initialize Image Stream");
	
	
	/* Add colors to the image resource	
	   
	   Note: colors are defined by the RBG color model
	   https://en.wikipedia.org/wiki/RGB_color_model

	   RGB Black: (0, 0, 0)
	   RBG White: (255, 255, 255)	   
	*/
    $background_color = imagecolorallocate($image, 0, 0, 0);
    $text_color = imagecolorallocate($image, 255, 255, 255);
	
	/* Add $char to the image resource */
    imagestring($image, 5, $x, $y,  chr($char), $text_color);
	
    /* Draw the image buffer stream to the file */
    imagepng($image, './images/' . $file_name);
	
	/* Free the memory associated with the $image resource by using imagedestroy() */
    imagedestroy($image); 

    /* write to log file */ 
    fwrite($logfile, $curr_image . ' ' . chr($char). PHP_EOL);
	
	/* echo results and link to file for review */
	echo "<a href='images/$curr_image.png' target='_blank'>" . $curr_image . ".png</a> - " . chr($char) . " ...complete.<br>" . PHP_EOL;
}



/*
	GenerateTrainingImages(
	                        (NULL)
	                      );
	
	Description:
	
	This function manages the creation of the training images. Call this function to create a new training set. 

	
	Example GenerateTrainingImages() Usage:
	
	GenerateTrainingImages();
	
	
	References:
	file_exists() - http://us.php.net/manual/en/function.file-exists.php
	mkdir() - http://us.php.net/manual/en/function.mkdir.php
	fopen() - http://us.php.net/manual/en/function.fopen.php
	fclose() - http://us.php.net/manual/en/function.fclose.php
	
*/
function GenerateTrainingImages() { 

    /* Check if the "images" folder was already created */
    if (file_exists('images')) {
        echo "The images folder already exists, no changes to the images folder were made!<br>" . PHP_EOL;
    }
    else{ /* There is no "images" folder */
        echo "The images folder does not exists, creating one... ";
		
		/* try to create one with the correct folder permissions */
        if (!mkdir("images", 0755, true)) {
            die('fail! Ending program.'); /* Failed to create the folder */
        }else{
            echo 'success!<br>' . PHP_EOL; /* Successfully created the folder */
        }
    }

    /* Create log file resource to log the results of generating the training images */
    $logfile = fopen("images/generate_images.log", "w") or die("Unable to open: " . $logfile . '. Ending program.');

    /* Current number of generated images */    
    $curr_image = 0;

	
    /* 
        Training images set is defined in ASCII 
		https://en.wikipedia.org/wiki/ASCII
		
        start: ascii dec 33 (!) 
        stop:  ascii dec 126 (~) 
    */
	
	$start = 33;
	$stop = 126;
	$total = $stop - $start + 1; /* Add 1 because the count starts at 0 */
	echo "Starting batch creation of " .  $total . " images.<br><br>" . PHP_EOL;
	
    for($i = $start; $i <= $stop; $i++) {
        NewImage($i, $curr_image, 1, 0, $logfile);
        $curr_image++;
    }
	echo "<br>Batch complete.<br>" . PHP_EOL;
	echo "Log: <a href='images/generate_images.log' target='_blank'>generate_images.log</a><br>" . PHP_EOL;
    
	
    /* Close log file */
    fclose($logfile);
}

/* Kick the tires and light the fires! */
GenerateTrainingImages();

/* Announce completion and link to next step */
echo 'All Done! Now run <a href="generate_training_data.php">generate_training_data.php</a><br>' . PHP_EOL;



It looks like a lot of code, I know! If you are feeling overwhelmed delete my comments and you will see that the actual code is quite short and very simple.

If you run this code the following things will happen:
  1. A sub-folder called ‘images’ will be created for you where you ran generate_training_images.php.
  2. 94 training images will be generated for you and saved in the images sub-folder.
  3. A log file named ‘generate_images.log’ will be created.

At this point we are ready to use these images to create the training set that the Neural Network will use. We’ll cover that in the next post in this series.

If you would like to obtain a copy of this code from GitHub or fork this project to follow along as I release the code you can find this project here: OCR on GitHub

If you have any questions, comments or trouble leave please leave it in the comments below and I will do my best to help out.

As always I hope you found this project both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

Also please support me on Patreon.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

Something I need to tell you

There is something I need to tell you…

ImSorry.jpg

Recently, I launched a Patreon account because I am looking to monetize my work so that I can bring my readers & fans even higher quality projects, but I forgot the most important thing in the process…

YOU GUYS!

πŸ˜‰

Like a complete moron I thought that I should limit my project submission ideas to Patreon subscribers! :-/

I was wrong!

Here’s the actual text (which has been removed):

My sponsors get extra perks like getting to suggest projects that I work on and topics that I blog or vlog about…

I changed it to:

Sponsors get their name or company listed as a sponsor on my website, posts and anywhere else that it is relevant to list and thank my sponsors as well as access to exclusive source code and and other content that I create.

Let me be clear, I have an “open inbox” policy! πŸ˜›

My sponsors of course can suggest projects and subjects for me to build or blog about but I also want to hear from my passive readers! This is a community that I’m working to build and I completely believe in having an open and honest dialog with you guys!

I get that not everyone can afford to sponsor my work monetarily! If you enjoy my work, and find even occasional value in my posts please consider retweeting out those posts to your followers or otherwise sharing my blog with your friends. I really need your help to grow! Even if you can’t help me financially just sharing my work with your friends, family and followers is incredibly helpful!

Now, I wish I could take credit for this change however I realized my mistake after receiving an email from one of my oldest followers Oliver Dvorski, you can find him on Twitter here: @Musmula and his GitHub is over here. Go Like, Subscribe and otherwise follow him on his various platforms!

Also, he’s available for hire so consider hiring him for your next project!

Thank you Oliver for really caring about me and my work!

As a result of this change I have added a new page Sponsors to my site where my current and active sponsors will be listed. This is a very public  thank you for supporting my work and making it possible! Sponsors names will also appear on each blog posting in the section titled “Patreon Supporters”. If you would like to support me please visit my Patreon page and click the orange “Become a Patron” button.

Currently the minimum level of support I have setup is $1 but more is definitely appreciated and very helpful! I expect that the support levels will evolve over time to match the needs and wants of my followers. If you would like to see more or different perks and additional tiers of support, or simply  would like to suggest a topic or project for an upcoming post feel free to contact me.

As always Much Love!

~Joy

Patreon

I’ve just opened a Patreon account and I need your support to grow.

I know the posts have been sporadic over the past few months as I have been taking care of my little Logich:

Thankfully I am starting to get into a schedule that allows me to work again. With your support we can create some amazing things!

Please like, share & subscribe!

Much Love,

~Joy

Blog at WordPress.com.

Up ↑