Skip to content
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

216 lines (190 sloc) 7.05 KB
Attention Visualizer by Abigail See,
Originally based on code by Andrej Karpathy described here:
and available here:
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Attention Visualizer</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="external/d3.min.js"></script>
<script src="external/jquery-3.1.0.min.js"></script>
<script src="external/underscore-min.js"></script>
<script src="external/sprintf.min.js"></script>
<link href='' rel='stylesheet' type='text/css'>
#wrap {
font-family: 'Cousine';
margin: 10px;
font-size: 15px;
json_fname = "attn_vis_data.json" // file containing the text and the weights
greenhue = 151
yellowhue = 56
function round(x, dp) {
// round a float to dp decimal places
var power_of_10 = 10**dp
return Math.round(x*power_of_10)/power_of_10
function toColor(p, hue) {
// converts a scalar value p in [0,1] to a HSL color code string with base color hue
if (p<0 || p>1) {
throw sprintf("Error: p has value %.2f but should be in [0,1]", p)
var saturation = 100 // saturation percentage
p = 1-p // invert so p=0 is light and p=1 is dark
var min_lightness = 50 // minimum percentage lightness, i.e. darkest possible color
var lightness = (min_lightness + p*(100-min_lightness)) // lightness is proportional to p
return sprintf('hsl(%d,%s%%,%s%%)', hue, saturation, lightness)
function render_art(div, data, dec_idx, dec_word) {
// render the article. if dec_idx and dec_word are not null, we highlight the article with the attention distribution for decoder timestep dec_idx and corresponding decoder word dec_word
var startix = 0;
var endix = data.article_lst.length
var attn_len = data.attn_dists[0].length
var dec_len = data.attn_dists.length
div.html(''); // flush
for(var i=startix; i<endix; i++) {
var word = data.article_lst[i]; // a string
if (dec_idx == null) {
var attn_wt = 0;
} else {
var attn_wt = data.attn_dists[dec_idx][i];
var background_color = toColor(attn_wt, yellowhue);
var css = 'background-color:' + background_color;
css += ';display:inline'
var word_html = word + ' '
// Insert "truncated here" marker to indicate how much of the original article we actually fed into the RNN
// Note we only have attention distribution over the portion of the article before truncation
if (i==attn_len) {
dnew0 = div.append('div');
dnew0.attr('class', 'd')
.attr('style', 'color:green; font-weight:bold; text-decoration:underline; display:inline;') // apply this style
// write the sentence/word
var dnew = div.append('div');
dnew.attr('class', 'd')
.attr('style', css) // apply this style
function render_dec(div, data) {
// render the decoded summary
var startix = 0;
var endix = data.decoded_lst.length;
div.html(''); // flush
for(var i=startix; i<endix; i++) {
var word = data.decoded_lst[i]; // a string
css = 'display:inline;'
if (data.hasOwnProperty('p_gens')) {
var p_gen = data.p_gens[i];
var background_color = toColor(p_gen, greenhue);
css += 'background-color:' + background_color;
} else {
var p_gen = null;
var dnew = div.append('div');
dnew.html(word+' ') // this is the content
.attr('class', 'd')
.attr('style', css) // apply this style
// add interactivity for mouseover decoder words
.on('mouseover', getHandleMouseOver(i, word, p_gen))
.on('mousemove', handleMouseMove)
.on('mouseout', handleMouseOut)
function getHandleMouseOver(dec_idx, dec_word, p_gen) {
// When you mouseover a decoder word, shows attention distribution on article
// p_gen is null for non-pointer models
return function() {
// Renders the article with the appropriate highlighting
render_art('#art'), gdata, dec_idx, dec_word);
// Show a tooltip giving value of p_gen
if (p_gen != null) {
gtooltip.text(round(p_gen, 3))
return"visibility", "visible");
function handleMouseMove() {
// When you move cursor over a decoder word, tooltip shows value of generation probability for that word
return"top", (d3.event.pageY-20)+"px").style("left",(d3.event.pageX+10)+"px");
function handleMouseOut() {
// When you move cursor away from a decoder word, stop showing generation probability tooltip
return"visibility", "hidden");
function render_abs(div,data) {
// Show the reference abstract (summary)
div.html(''); // flush
var dnew = div.append('div');
function get_json_and_disp() {
// Retrieve the json data file and display the data
console.log("fetching " + json_fname + "...")
function json_success(data) {
// Displays the data
console.log("success!")"#curr_datafile").html('<font color="09B509">Currently displaying: ' + json_fname + "</font>")
gdata = data; // store globally
render_art("#art"), gdata, null, null);
render_abs("#abs"), gdata);
render_dec("#dec"), gdata);
function json_fail(d) {
// Tell the user it failed to load
console.log("failure.")"#curr_datafile").html('<font color="red">Failed to load ' + json_fname + "</font>")
$.getJSON(json_fname, json_success).fail(json_fail);
function start() {
// Define a tooltip that we will use to display generation probability of a decoder word when you hover over it
var tooltip ="body")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background", "white")
.style("font-size", "15px")
.style("font-family", "Cousine")
.text("a simple tooltip");
gtooltip = tooltip // global
<body onload="start();">
<div id="wrap">
<div id="curr_datafile">
Current datafile name goes here.
<div id="art">
article goes here
<h2>Reference summary</h2>
<div id="abs">
reference summary goes here
<h2>Generated summary (highlighted = high generation probability)</h2>
<div id="dec">
generated summary goes here
You can’t perform that action at this time.