A knife for father’s day

My nephew loves his dad.

I said I would help my nephew to make a training blade as a father’s day gift. I’d planned on a simple wooden trainer – but he had other ideas. After saying that “his dad deserved the best” – he talked over his options with me then spent the day in the shop making a rather awesome knife.

I was impressed, as it was a lot of time-consuming work. We started with an old piece of scrap, a half finished milling prototype for a knife I made a while back. He used files to finish shaping the blade. The blade was made out of aluminum, and he insisted on 5 sanding passes to get the blade face to look just right.


Once he was happy with what the blade looked like – we stamped in his dad’s name on one side, and “I love you dad on the other”. He even made sure we checked that “I love you dad” would be right way up, and readable, when his dad was using the knife.


We watched a bunch of YouTube videos on para-cord wrapping knife handles. Once we found a pattern he liked, we drilled the handle and he wrapped it up.


It was a tricky process, as he had to hold tension on the cord, while setting the pattern on the top and bottom of the blade. I offered to do the wrapping, but he wanted to do it.


In the end I was really impressed with what he made. It is a sweet training blade in itself, but my nephew was right – you can read “I love you dad” when you are using it, and thats just awesome.


My Wednesday hammer….

This morning I was asking my nephew if he wanted to help me finish the hammer rack I was building. The conversation went something like this:

Nephew: “Do you really need that many hammers?”
Me: “Yes, yes I do!”
Nephew: “This is my Wednesday hammer, this is my….”

He is a funny kid. Might have a point though.

Structuring TensorFlow Models

Danijar Hafner has an excellent tutorial on Structuring Your TensorFlow Models. I really liked it so I am posting it here so its always easy to find. He is using Python’s decorators to provide a lazy initialization for the graph components. Its a neat trick. Totally separate from TensorFlow, I am actively working on improving my Python programming and will definitely be using this approach in the future.

Climbing at Index (April 26th)

Leaving Seattle at 7:30, I got to Index and met up with Cameron a little after 9. Then we headed over to our first climb of the day. It was the “ss-ultrabrutal”. I am glad I found about the name after we climbed it – that name is just awesomely intimidating.

It is a trad climb, Cameron led and I cleaned. At the time I thought it was just a 5.6 (it’s a 5.7) but it was an easy climb, and I had hard time on it, so while I enjoyed myself I came off it just feeling a little depressed about how out of climbing shape I was. Definitely time to hit the gym more. In the picture you can just make out Cameron at the bolts at the top of the climb. The climb traverses left to right on about a forty five degree angle – following the large crack above the old tunnel.


Next we moved over to do the GM route on The Country. Cameron had climbed it before and wanted to lead all three pitches in a single push. So I belayed him from the ground, then he rappelled back down to the first pitch belay ledge cleaning as he went. I’d thought I’d be doing the second two pitches, but I just made such a mess of cleaning the first pitch Cameron just pulled the rope and I cleaned the first pitch. You can see the rope line in the picture. Cameron had already been doing some rope soloing that morning – and I was having an off day – so we called it and went and put our heads in the river.


Think I am kidding? Nope. Cameron put his head in the river and it looked so refreshing I followed suit.


All in all a lovely day – but I confess after seeing the camping spot he snagged by showing up on a Wednesday, I was kicking myself for not joining the night before. I skipped the over night so I could attend a practice session on glacier travel. Lesson learned.


The view from the river was even better.


NetworkX Graph library for Python

I’ll admit – I still try and write Python like it was C or C++. To fix that for a while I am going to switch to writing things in Python for a while, while working on actually writing good Python.

Graph algorithms are the kidneys of computer science – there in the background filtering out all the bad things for us. In my switch over to writing in Python I needed to find a solid python graph library, and decided to try NetworkX. Here is a simple example program using it. These are mostly just notes for myself – but I am posting it here in case it is useful to anyone else.

This code is basically the NetworkX weighted graph example, with some annotations. Here is some code to create and plot a weighted graph.

import matplotlib.pyplot as plt
import networkx as nx

# Populate the graph...
map_graph = nx.Graph()

map_graph.add_edge('Issaquah','Bellevue', weight=0.11 )
map_graph.add_edge('Bellevue','Kirkland', weight=0.05 )
map_graph.add_edge('Bellevue','Redmond', weight=0.06 )
map_graph.add_edge('Kirkland','Redmond', weight=0.24 )
map_graph.add_edge('Bellevue','Seattle', weight=0.01 )
map_graph.add_edge('Renton','Seattle', weight=0.03 )
map_graph.add_edge('Renton','Bellevue', weight=0.48 )

# Determine the layout of points in the graph. Some other layouts that 
# would work here are spring_layout, shell_layout, and random_layout                                                                                                 
pos = nx.circular_layout( map_graph ) # Sets positions for nodes

# Put "dots" down for each node                                                     
nx.draw_networkx_nodes( map_graph, pos, node_size=700)

# Attaches Labesl to each node                                                               
nx.draw_networkx_labels( map_graph, pos, font_size=14, font_family='sans-serif')

map_edges = [(u,v) for (u, v, d) in map_graph.edges(data=True) ]

nx.draw_networkx_edges( map_graph,
                        pos,             # Spring
                        map_edges,       # List of edges                                     
                        width=5, alpha=0.5, edge_color='b', style='dashed' )


The plotted graph looks something like this.

Screen Shot 2018-04-29 at 5.01.30 PM

One of the things I want from a graph library is the standard graph algorithms – like finding me the shortest path between nodes, or testing for the presence of a path at all. So for example to find the shortest path from Issaquah to Renton we could add the following code to the example above?:

# Generates the shortest path - but since there could be more than                                                   
# one of them what you get back is a "generator" from which you                                                      
# need to pluck the shortest path.                                                                                   
a_shortest_path = nx.all_shortest_paths(map_graph, source='Issaquah', target='Renton')                              

print( [p for p in a_shortest_path] )    

The added code will give the path [['Issaquah', 'Bellevue', 'Renton']], which is the shortest path by number of edges traversed. To obtain the shortest path by edge weight we can use dijkstras like so:

a_shortest_path = nx.dijkstra_path(map_graph, ‘Issaquah’, ‘Renton’)
print( a_shortest_path )

Which gives the path: ['Issaquah', 'Bellevue', 'Seattle', 'Renton']

The problem is that this implementation of dijkstra’s fails when a path is not present between the origin and destination nodes. So for example if we add a disconnected vertex with no edges like below, searches on a path to that vertex will cause the call to fail.

map_graph.add_node(‘Mercer Island’)

Screen Shot 2018-04-29 at 8.15.15 PM

I think you need to use the has_path method to test for the existence of any path first, then if there is a path use dijkstras to find the minimum cost path. Something like this:

# Create a helper function for testing for a path
def shortest_weighted(from_node, to_node):
    if nx.has_path( map_graph, from_node, to_node ) == True :
	a_shortest_path = nx.dijkstra_path(map_graph, from_node, to_node)
        return( a_shortest_path )
        print("No path from",from_node,"to", to_node, "\r\n")
        return( False )

Then checking for the minimum path can look something like this:

# Test where path does not exist
shortest_weighted_path = shortest_weighted( 'Issaquah', 'Mercer Island' )
if shortest_weighted_path != False:
    print( shortest_weighted_path )

# Test where path does exist
shortest_weighted_path = shortest_weighted( 'Issaquah', 'Renton' )
if shortest_weighted_path != False:
    print( shortest_weighted_path )

Neither call will fail and checking for the existing path from Issaquah to Renton will return: ['Issaquah', 'Bellevue', 'Seattle', 'Renton']

Since the graphs are weighted – list comprehensions can be used to conditionally act based on edge weights. For example:

# Segment the nodes by weight                                                                                                  
map_red_edges  = [(u,v) for (u, v, d) in map_graph.edges(data=True) if d['weight'] >  0.1  ]
map_blue_edges = [(u,v) for (u, v, d) in map_graph.edges(data=True) if d['weight'] <= 0.1  ]

Then use the segmentation to perform multiple colorings.

nx.draw_networkx_edges( map_graph,
                        pos,             # Spring                                                                    
                        map_red_edges,   # List of edges                                                             
                        style='dashed' )

nx.draw_networkx_edges( map_graph,
                        pos,             # Spring                                                                    
                        map_blue_edges,  # List of edges                                                             
                        style='solid' )

Which will produce the following graph:

Screen Shot 2018-04-29 at 9.49.43 PM

Also useful is shortest_path, which returns all the paths between all nodes, but sorted by vertex traversal path length. So the following code:

paths = nx.shortest_path(map_graph)
print( paths )

Generates the following paths.

{'Issaquah': {'Issaquah': ['Issaquah'], 'Bellevue': ['Issaquah', 'Bellevue'], 'Kirkland': ['Issaquah', 'Bellevue', 'Kirkland'], 'Redmond': ['Issaquah', 'Bellevue', 'Redmond'], 'Seattle': ['Issaquah', 'Bellevue', 'Seattle'], 'Renton': ['Issaquah', 'Bellevue', 'Renton']}, 'Bellevue': {'Bellevue': ['Bellevue'], 'Issaquah': ['Bellevue', 'Issaquah'], 'Kirkland': ['Bellevue', 'Kirkland'], 'Redmond': ['Bellevue', 'Redmond'], 'Seattle': ['Bellevue', 'Seattle'], 'Renton': ['Bellevue', 'Renton']}, 'Kirkland': {'Kirkland': ['Kirkland'], 'Bellevue': ['Kirkland', 'Bellevue'], 'Redmond': ['Kirkland', 'Redmond'], 'Issaquah': ['Kirkland', 'Bellevue', 'Issaquah'], 'Seattle': ['Kirkland', 'Bellevue', 'Seattle'], 'Renton': ['Kirkland', 'Bellevue', 'Renton']}, 'Redmond': {'Redmond': ['Redmond'], 'Bellevue': ['Redmond', 'Bellevue'], 'Kirkland': ['Redmond', 'Kirkland'], 'Issaquah': ['Redmond', 'Bellevue', 'Issaquah'], 'Seattle': ['Redmond', 'Bellevue', 'Seattle'], 'Renton': ['Redmond', 'Bellevue', 'Renton']}, 'Seattle': {'Seattle': ['Seattle'], 'Bellevue': ['Seattle', 'Bellevue'], 'Renton': ['Seattle', 'Renton'], 'Issaquah': ['Seattle', 'Bellevue', 'Issaquah'], 'Kirkland': ['Seattle', 'Bellevue', 'Kirkland'], 'Redmond': ['Seattle', 'Bellevue', 'Redmond']}, 'Renton': {'Renton': ['Renton'], 'Seattle': ['Renton', 'Seattle'], 'Bellevue': ['Renton', 'Bellevue'], 'Issaquah': ['Renton', 'Bellevue', 'Issaquah'], 'Kirkland': ['Renton', 'Bellevue', 'Kirkland'], 'Redmond': ['Renton', 'Bellevue', 'Redmond']}, 'Mercer Island': {'Mercer Island': ['Mercer Island']}}

DeepFakes and Jordan Peele’s Obama PSA

This is an awesome PSA about information hygene and the problems that our society is about to face. Basically, breakthroughs in the last few years have been accelerating what you can do with machine learning at a break-neck pace. Since people can kind of suck, not all of that advancement has been for the benefit of society at large.

In late 2017 some equally brilliant and creepy work was released letting someone (super creepy) place the face of anyone for whom they could get a few hundred pictures on a porn star’s body. Basically this was the creation of a new, modern, sex crime. No one wanted to talk about this threat, because – porn. Well, thankfully Jordan Peele and some others put out a PSA about this coming threat. As you can see in this video they have generated video of “President Obama”, saying all sorts of things. The video effectively nailed generation of voice, tone, intonation, gesture, and lighting. Its an awesome fake.

Right know, with a little knowledge about how the video was generated, it is fairly easy to prove its is not authentic. That illustrates the problem though, you quickly start needing to use math to prove that the video is faked. Math is also quickly becoming inherently distrusted by more and more people. We are also not that far from this tech being able to be run reliably in real time. So – generation of a video of any public figure believably saying anything you want them to is not that far off.

The obvious threat is anyone caught committing an undesirable act will soon be able to more believably cry “fake news”. Thats the simpler problem though. The real problem will kick off as soon as people start generating revisionist historical records. That thread – when pulled – could unravel our cultural anchor to the past, changing our understanding of our cultural and societal path to now.

Data sets for Machine Learning

Grad school was a few years ago, and things are moving fast, so I am writing a bunch of small ML programs to get current with the state of the art again. Also switching form using C++ to Python for ML work. Wow, thats a huge improvement right there – can’t believe I waited this long.

The biggest problem in writing ML code is finding decent data sets. The UCI Machine Learning Repository has links to a bunch of curated data sets. Posting it here, like the rest of the ML stuff I’m about to, so its easy to find and point friends to.