Skip to content
This repository has been archived by the owner on Jan 25, 2021. It is now read-only.

Added multiple enhancements, documented in Training_analysis.ipynb accordingly #12

Open
wants to merge 7 commits into
base: enhance-log-analysis
Choose a base branch
from
144 changes: 131 additions & 13 deletions log-analysis/Training_analysis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
"# la.normalize_rewards(df)\n",
"\n",
"#Uncomment the line of code below to evaluate a different reward function\n",
"#la.new_reward(df, l_center_line, 'reward.reward_sample') #, verbose=True)"
"#la.new_reward(df, l_center_line, l_inner_border, l_outer_border, 'reward.reward_sample') #, verbose=True)"
]
},
{
Expand Down Expand Up @@ -420,7 +420,7 @@
"\n",
"#### Total reward per episode\n",
"\n",
"This graph has been taken from the orignal notebook and can show progress on certain groups of behaviours. It usually forms something like a triangle, sometimes you can see a clear line of progress that shows some new way has been first taught and then perfected.\n",
"This graph has been taken from the orignal notebook and can show progress on certain groups of behaviours. It usually forms something like a triangle, sometimes you can see a clear line of progress that shows some new way has been first taught and then perfected. It has been updated with colour coding according to start_at. This makes it more useful to notice patterns, similarly colour-coded datapoints should be compared together. This is because the model performs drastically different with different start points. For e.g. if there is a difficult turn at waypoint 100, the model will have a progress of let's say 50% when starting at start_at=0. But when starting at start_at=80, the model will only have a progress of 5%, and it will continue this trend over the iterations.\n",
"\n",
"#### Mean completed lap times per iteration\n",
"\n",
Expand Down Expand Up @@ -495,8 +495,9 @@
"\n",
"In such case `scatter_aggregates` may come handy. It comes with three types of graphs:\n",
"* progress/steps/reward depending on the time of an episode - of this I find reward/time and new_reward/time especially useful to see that I am rewarding good behaviours - I expect the reward to time scatter to look roughly triangular\n",
"* histogram of actions - this plots a count of actions in the first and last iteration, it is useful to compare how your model has shifted its use of actions (especially when improving speed of the model, as you want the model to learn to use actions with higher speeds.).\n",
"* histograms of time and progress - for all episodes the progress one is usually quite handy to get an idea of model's stability\n",
"* progress/time_if_complete/reward to closest waypoint at start - these are really useful during training as they show potentially problematic spots on track. It can turn out that a car gets best reward (and performance) starting at a point that just cannot be reached if the car starts elsewhere, or that there is a section of a track that the car struggles to get past and perhaps it's caused by an aggressive action space or undesirable behaviour prior to that place\n",
"* progress/time_if_complete/reward to closest waypoint at start - these are really useful during training as they show potentially problematic spots on track. It can turn out that a car gets best reward (and performance) starting at a point that just cannot be reached if the car starts elsewhere, or that there is a section of a track that the car struggles to get past and perhaps it's caused by an aggressive action space or undesirable behaviour prior to that place. The greyscale colormap will show movement of the graph across iteration, so that you can judge at which 'start_at' your model has improved and where it hasn't. You can disable this behaviour by removing the colourmap parameter. Fun fact: try changing 'Greys' to 'viridis' for a more distinctively colourful graph.\n",
"\n",
"Side note: `time_if_complete` is not very accurate and will almost always look better for episodes closer to 100% progress than in case of those 50% and below."
]
Expand All @@ -505,7 +506,7 @@
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": false
"scrolled": true
},
"outputs": [
{
Expand All @@ -532,7 +533,7 @@
],
"source": [
"# This gives the warning about ptp method deprecation. The code looks as if np.ptp was used, I don't know how to fix it.\n",
"la.scatter_aggregates(simulation_agg, 'Stats for all laps')"
"la.scatter_aggregates(simulation_agg, 'Stats for all laps', action_data = df[['iteration', 'action']], colormap='Greys')"
]
},
{
Expand Down Expand Up @@ -579,7 +580,7 @@
"complete_ones = simulation_agg[simulation_agg['progress']==100]\n",
"\n",
"if complete_ones.shape[0] > 0:\n",
" la.scatter_aggregates(complete_ones, 'Stats for complete laps')\n",
" la.scatter_aggregates(complete_ones, 'Stats for complete laps', action_data = df[['iteration', 'action']], colormap='Greys')\n",
"else:\n",
" print('No complete laps yet.')"
]
Expand Down Expand Up @@ -2131,7 +2132,7 @@
"\n",
"Being able to plot the car's route in an episode can help you detect certain patterns in its behaviours and either promote them more or train away from them. While being able to watch the car go in the training gives some information, being able to reproduce it after the training is much more practical.\n",
"\n",
"Graphs below give you a chance to look deeper into your car's behaviour on track."
"Graphs below give you a chance to look deeper into your car's behaviour on track. Set the wp=False if you wish to prevent labelling waypoints."
]
},
{
Expand Down Expand Up @@ -2174,7 +2175,7 @@
"# highest progress from all episodes:\n",
"# sorted_idx = list(simulation_agg.nlargest(3,'progress')['episode'])\n",
"\n",
"fig = la.plot_top_laps(sorted_idx[:], episode_map, l_center_line, l_inner_border, l_outer_border, 3)"
"fig = la.plot_top_laps(sorted_idx[:], episode_map, l_center_line, l_inner_border, l_outer_border, 3, wp=True)"
]
},
{
Expand Down Expand Up @@ -2275,10 +2276,11 @@
"outputs": [],
"source": [
"## Evaluation RUN\n",
"\n",
"def plot_episode_run(df, E, center_line, inner_border, outer_border):\n",
" fig = plt.figure(1, figsize=(12, 16))\n",
" ax = fig.add_subplot(211)\n",
" la.print_border(ax, center_line, inner_border, outer_border) \n",
" la.print_border(ax, center_line, inner_border, outer_border, wp=True) #Set wp=False to prevent labelling waypoints\n",
" episode_data = df[df['episode'] == E]\n",
" for row in episode_data.iterrows():\n",
" x1,y1,action,reward = row[1]['x'], row[1]['y'], row[1]['action'], row[1]['reward']\n",
Expand Down Expand Up @@ -2312,7 +2314,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Path taken in a particular Iteration"
"### Path taken in a particular Iteration\n",
"\n",
"In the original log analysis, this code took about 10-20 seconds to run. Its a very useful graph and needs to be plotted frequently so it was important to build a faster implementation. This code has been improved to plot the entire iteration within a second."
]
},
{
Expand Down Expand Up @@ -2344,10 +2348,124 @@
}
],
"source": [
"def plot_iteration_run(df, I, center_line, inner_border, outer_border):\n",
" fig = plt.figure(1, figsize=(12, 16))\n",
" ax = fig.add_subplot(211)\n",
" la.print_border(ax, center_line, inner_border, outer_border, wp=False) \n",
" iteration_data = df[df['iteration'] == I]\n",
" iteration_data.plot.scatter(x='x', y='y', ax=ax)\n",
" \n",
"iteration_id = 10\n",
"\n",
"for i in range((iteration_id-1)*EPISODES_PER_ITERATION, (iteration_id)*EPISODES_PER_ITERATION):\n",
" plot_episode_run(df, i, l_center_line, l_inner_border, l_outer_border)"
"plot_iteration_run(df, iteration_id, l_center_line, l_inner_border, l_outer_border)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plot the perfect race line\n",
"\n",
"This code uses raycasting (Bresenham line) to find the perfect race line. It is very fast, but its accuracy could be improved with right start and end conditions."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from shapely.geometry.polygon import LineString\n",
"from shapely.geometry.polygon import Polygon\n",
"from shapely.geometry import Point\n",
"import math\n",
"\n",
"def br(x0, y0, x1, y1):\n",
" \"\"\"Yield integer coordinates on the line from (x0, y0) to (x1, y1).\n",
"\n",
" Input coordinates should be integers.\n",
"\n",
" The result will contain both the start and the end point.\n",
" \"\"\"\n",
" dx = x1 - x0\n",
" dy = y1 - y0\n",
"\n",
" xsign = 1 if dx > 0 else -1\n",
" ysign = 1 if dy > 0 else -1\n",
"\n",
" dx = abs(dx)\n",
" dy = abs(dy)\n",
"\n",
" if dx > dy:\n",
" xx, xy, yx, yy = xsign, 0, 0, ysign\n",
" else:\n",
" dx, dy = dy, dx\n",
" xx, xy, yx, yy = 0, ysign, xsign, 0\n",
"\n",
" D = 2*dy - dx\n",
" y = 0\n",
"\n",
" for x in range(dx + 1):\n",
" yield x0 + x*xx + y*yx, y0 + x*xy + y*yy\n",
" if D >= 0:\n",
" y += 1\n",
" D -= 2*dx\n",
" D += 2*dy\n",
" \n",
"def get_vector_length(v):\n",
" return (v[0] ** 2 + v[1] ** 2) ** 0.5\n",
"\n",
"def vector(a, b):\n",
" return b[0] - a[0], b[1] - a[1]\n",
"\n",
"def plot_perfect_line(df, l_center_line, inner_border, outer_border):\n",
" road_poly2 = Polygon(np.vstack((outer_border, np.flipud(inner_border))))\n",
" fig = plt.figure(1, figsize=(12, 16))\n",
" ax = fig.add_subplot(211)\n",
" la.print_border(ax, l_center_line, inner_border, outer_border, wp=True)\n",
" x0 = df[df['episode'] == 0]['x'].iloc[0]\n",
" y0 = df[df['episode'] == 0]['y'].iloc[0]\n",
" params = la.df_to_params(df[df['episode'] == 0].iloc[0], l_center_line, inner_border, outer_border)\n",
" h = params['heading']\n",
" x1 = x0\n",
" y1 = y0\n",
" X = [x0]\n",
" Y = [y0]\n",
" for iii in range(200):\n",
" plists = [None] * 9\n",
" llists = [None] * 9\n",
" for i in range(9):\n",
" plists[i] = list(br(int(x1), int(y1), int(x1 + 700 * math.cos(math.radians(h - 30 + (i*60.0)/8.0))), int(y1 + 700 * math.sin(math.radians(h - 30 + (i*(60.0/8.0)))))))\n",
" for j in range(len(plists[i])):\n",
" if not road_poly2.contains(Point(plists[i][j][0], plists[i][j][1])):\n",
" plists[i] = plists[i][:j]\n",
" break\n",
" if len(plists[i]) > 0: #== 1427:\n",
" #parr = np.array(plists[i])\n",
" #plt.plot(parr[:, 0], parr[:, 1])\n",
" llists[i] = get_vector_length(vector(plists[i][0], plists[i][len(plists[i]) - 1]))\n",
" else:\n",
" llists[i] = 0\n",
" \n",
" l = llists.index(max(llists))\n",
" #print(l)\n",
" if len(plists[l]) <= 0:\n",
" break\n",
" x1 = plists[l][0][0]\n",
" y1 = plists[l][0][1]\n",
" x2 = plists[l][len(plists[l]) - 1][0]\n",
" y2 = plists[l][len(plists[l]) - 1][1]\n",
" \n",
" right_heading = math.atan2(y2 - y1, x2 - x1)\n",
" #h = math.degrees(right_heading)\n",
" h += (l-4) * 30 * 0.5 \n",
" x1 += 25*math.cos(right_heading)\n",
" y1 += 25*math.sin(right_heading)\n",
" X.append(x1)\n",
" Y.append(y1)\n",
"\n",
" \n",
" plt.plot(X, Y, 'r.')"
]
},
{
Expand Down Expand Up @@ -2601,7 +2719,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
"version": "3.5.2"
}
},
"nbformat": 4,
Expand Down
Loading