Notes on generating printable Keras documentation

It started when I wanted to print the documentation for Keras so that I could peruse it on a train journey. Obviously this is a weird thing to want to do in at least two different ways, but sometimes you’ve just got to have ink on paper.

The online HTML documentation for Keras is built from extended markdown files, and can (in theory – hence this post) also be used to generate a PDF file. However, when I tried it there turned out to be a few “issues”, so I thought I’d document this in case anyone (including future-me) wants to go on the same journey. I’m not going to document the process of discovery I went though, just what seems to be the easiest route to getting a printable PDF. Note that these instructions are for Windows.

Ready? Lets go.

Part 1: Install the prerequisites.

1. Install Python 3.6 if you don’t already have it.

2. Download and install mkdocs. I used pip3 to do this. It will install itself into <user>\AppData\Local\Pandoc and you’ll need to add this to your path.

3. Download and install mkdocs-pandoc.

4. Download and install MiKTeX. mkdocs-pandoc emits LaTeX and expects you to have a way to convert this to PDFusing pdflatex.exe, which is included in MiKTeX (and probably other TeX distributions). Choosing the option to automatically install missing packages will save time later. Add C:\Program Files\MiKTeX 2.9\miktex\bin\x64 to your path.

5. Download the Keras repo from Github and unzip keras-master.zip. You’ll need this because it includes the documentation source files.

Part 2: Generate the PDF

1. In an command window, go to keras-master/docs. You’ll see a readme.md file containing instructions for building the docs. We’ll be following this outline but adding some workarounds.

2. Run python autogen.py and wait for errors to occur:

Traceback (most recent call last):
File “autogen.py”, line 559, in <module> readme = read_file(‘../README.md’) File “autogen.py”, line 532, in read_file return f.read() File “C:\Program Files\Python36\lib\encodings\cp1252.py”, line 23, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0] UnicodeDecodeError: ‘charmap’ codec can’t decode byte 0x81 in position 7411: character maps to <undefined>

This is happening because autogen.py is trying to read files that don’t match the default file encoding. We’ll need to hack autogen.py, so open it in an editor ando to the first place that f.read() is called, which for me was line 532. Change the previous line from

with open(path) as f:


with open(path, encoding=”latin1″) as f:

Save autogen.py and run the command again. You should get a similar error on a different line (it was line 563 for me) so fix it the same way. Save autogen.py and run the command yet again. This time it should complete successfully and generate a bunch of markdown files in the sources directory.

3. Run the mkdocs serve command. This does some stuff and starts a local web server. Since this blocks the command window, you’ll need to start another command window and go to the docs directory.

4. In the new command window, run mkdocs build. This generates an html web site in the site directory. This may not be strictly necessary, but its a useful check that things are working.

5. At this point we leave the instructions in readme.md behind. Run the command mkdocs2pandoc > keras.pd. This creates a single large markdown file (keras.pd) that is optimised for generating PDFs.

6. The markdown document has a few problems at this point, which we can rectify by hand-editing it. I used notepad++ for this.

  • Change the top-level heading on the first line from #Home to #Introduction.
  • The markdown document contains a number of HTML <span> tags with level five headings on the next line. This causes pandoc (see step 7 below) to output the tag’s alt-text but fail to render the heading correctly. The solution is to add a line between them by using search and replace to replace </span>\r\n##### with </span>\r\n\r\n#####.
  • The markdown contains HTML <img> tags that pandoc won’t handle. Either remove these manually or (as I did) leave them in and pandoc will render the alt text. Annoying but I can live with it.

7. Run the command pandoc –toc -f markdown+grid_tables+table_captions -V geometry:margin=2.5cm –pdf-engine=xelatex -o keras.pdf keras.pdYou’ll probably see some warnings: just ignore them. If you chose not to allow MiKTeX to automatically install missing packages then you be asked for permission to install various things as they are needed. The default LaTeX stylesheet renders pages with large margins, so I overrode this by setting them to 2.5 cm (about one inch) – tweak this according to preference. I also specified xelatex as the PDF engine because the default engine had fatal problems with some Unicode characters in the document. The table of contents defaults to three levels: if you want more detail then add –toc-depth=4 to the command.

At the end of all this, you’ll see you have a keras.pdf file. Load this into your favourite PDF viewer or print it out according to your preference.


UX: Words and meanings

Consider avoiding words like “enabled” and “disabled” as most people consider them to have different meanings from those used by software developers.

(And obligatory. Jira. Please. No.)



Some wise words as we embark on the long winter journey:

“From this distant vantage point, the Earth might not seem of any particular interest. But for us, it’s different. Consider again that dot. That’s here. That’s home. That’s us. On it everyone you love, everyone you know, everyone you ever heard of, every human being who ever was, lived out their lives. The aggregate of our joy and suffering, thousands of confident religions, ideologies, and economic doctrines, every hunter and forager, every hero and coward, every creator and destroyer of civilization, every king and peasant, every young couple in love, every mother and father, hopeful child, inventor and explorer, every teacher of morals, every corrupt politician, every ‘superstar,’ every ‘supreme leader,’ every saint and sinner in the history of our species lived there — on a mote of dust suspended in a sunbeam.


The Earth is a very small stage in a vast cosmic arena. Think of the rivers of blood spilled by all those generals and emperors so that in glory and triumph they could become the momentary masters of a fraction of a dot. Think of the endless cruelties visited by the inhabitants of one corner of this pixel on the scarcely distinguishable inhabitants of some other corner. How frequent their misunderstandings, how eager they are to kill one another, how fervent their hatreds. Our posturings, our imagined self-importance, the delusion that we have some privileged position in the universe, are challenged by this point of pale light. Our planet is a lonely speck in the great enveloping cosmic dark. In our obscurity — in all this vastness — there is no hint that help will come from elsewhere to save us from ourselves.


The Earth is the only world known, so far, to harbor life. There is nowhere else, at least in the near future, to which our species could migrate. Visit, yes. Settle, not yet. Like it or not, for the moment, the Earth is where we make our stand. It has been said that astronomy is a humbling and character-building experience. There is perhaps no better demonstration of the folly of human conceits than this distant image of our tiny world. To me, it underscores our responsibility to deal more kindly with one another and to preserve and cherish the pale blue dot, the only home we’ve ever known.”

— Carl Sagan,  Pale Blue Dot: A Vision of the Human Future in Space, 1994


Climbing wall etiquette for beginners

As a service to those new to indoor climbing walls, I have collected together the following rules as a guide to contemporary de rigueur behaviour:

1. Save time and impress other wall users by arriving with your harness already on. Keep it on when you leave, too, as this will provide endless opportunities to for conversations with people you meet on your journey home.

2. If you’re climbing in the trainers you arrived in, rather than using old-style rock shoes, any mud or grit on the soles will provide valuable additional friction as it sticks to all but the the smallest holds.

3. The machines that let you climb on your own are called “The Pulleys”. The term “auto-belay” is regarded as rather old-fashioned.

4. When climbing indoors, it is important to carry appropriate safety equipment. This means as couple of prusik loops and a screwgate. Some experienced indoor climbers choose to add a spare belay device, pulley, slings and/or Mini Traxion.

5. If carrying a smartphone to take selfies, videos, or phone calls when on a route, remember to tuck the phone into the back of your harness when it is not in use. This is called “racking”. Pro tip: marking your phone with coloured tape will help make sure you get it back if you need to share your “rack” with other people.

The following apply mainly to bouldering:

6. For safety reasons, when bouldering,  it is important not to climb below another climber – as they may fall on you. However, climbing above another climber is considered perfectly safe.

7. Easy V0 or V1-grade bouldering problems are a perfect opportunity for your friends/family/colleagues/club to film you with a smartphone or video camera. Background sounds add interest to any video, so be sure to encourage them to cheer loudly as you jump down.

8. Stand out from the crowd while bouldering by wearing your harness. To really get noticed, consider wearing a chest harness and/or jumars.

9. Help other wall users to keep cool in hot weather by shaking excess sweat onto them from your arms, legs and/or hair as you climb. Bouldering topless makes this considerably easier, and you will quickly notice the gratitude of the people around you.


Disclaimer: Really, really, really don’t do any of the things above. Some of them are very unsafe and can get you killed or injured, or can kill or injure other wall users (or annoy them, which may also get you killed or injured). Just don’t do any of these things.


An Editorial

[A couple of evenings ago I read Yonatan Zunger’s blog post “Trial Balloon for a Coup? Analyzing the news of the past 24 hours“. The next morning I woke at 2:47 am from a strange dream. The following is fiction.]



[draft / evening eds. mtg.]

A little over a day has now passed since the Trump administration’s announcement of the suspension of the US constitution. A day of nervous waiting.  The announcement by Mr Trump — surely few now refer to him as President — of the uncovering of a “secret liberal plot” to “frustrate the will of the American voter” has been watched and re-watched and dissected. But the uncomfortable truth is that, apart from the brief statement of “watchful neutrality” issued by the US Joint Chiefs of Staff, we know little more than we did yesterday.

And so we go about our lives. Thinking perhaps of loved ones in the US, who are no doubt thinking of us. We glance over our shoulders; skittish. Many who lived through the Cuban missile crisis remember this feeling well, and never thought they would experience it again.

For the time being the world’s conversation is stilled. Twitter is suspended, despite the efforts of its engineers in Toronto and London to take control of its servers. Facebook is blocked in North America, and unreliable across the rest of the world. Their main offices and data centres are reported to be guarded by the same men in unmarked uniforms who were earlier observed surrounding the headquarters of the US State and Justice departments. Web connections time-out and telephone calls fail to connect. Perhaps surprisingly, email and text messages continue to leak out of the country, but the fragmented stories that they bring — street protests met by force, panic buying of food, disappearances, and convoys of unmarked vehicles arriving at sports stadiums in major cities — provide no reassurance. Only anguish.

Global financial markets remain closed. The skies over the US are clear of aircraft for the first time since September 2001, and tens of thousands of passengers find themselves unexpectedly deposited in Canada and Mexico. The governments of those countries remain tight-lipped: perhaps nervous of a repeat of yesterday’s lethal events at Niagara Falls. And the irony of US borders that are finally impassible to migrants is unlikely to be lost on anyone.

Since it seems clear that the US federal government has been largely suborned, and the its military will not intervene, all now depends on the response of the individual states. With the exception of Hawaii, Virginia and Texas, we do not know how the state governors have reacted, or whether Trump’s unprecedented nationwide federalisation of national guard units has been obeyed. The widely publicised eyewitness statements of the Queen Mary 2 passengers and crew demonstrate that the plans of Trump and his backers were well executed, at least in major cities such as New York. On the other hand,  the film of open battles at Shreveport and Oklahoma City, and the rumoured siege at Portland, suggest that not all is going their way.

It is clear that the US has experienced a coup d’etat. It may even be that, after two hundred and forty years, the great American Experiment has failed. What is certain is that in these dark days the world needs cool leadership and more than a little good fortune.



Decision Time

Tomorrow I will be voting for the UK to remain a member of the European Union. While I find the economic and political arguments for Remain persuasive, ultimately I’ll be doing this because peace and cooperation are necessary preconditions for progress and our collective futures.

I’m not going to tell you how to vote. But, if you find yourself genuinely undecided, I offer a suggestion: don’t abstain. Instead, ask a child or young person in your life how they would vote if they were able, and then vote for them and their future. And vote with hope for that future.