Spaces:
Running
Running
!(async function(){ | |
var data = await util.getFile('cns-cache/model_grid_test_accuracy.json') | |
data = data | |
.filter(d => util.epsilonExtent[1] <= d.epsilon && d.epsilon <= util.epsilonExtent[0]) | |
.filter(d => d.dataset_size > 1000) | |
// .filter(d => d.dataset_size > 4000) | |
// console.log(data) | |
var bySize = d3.nestBy(data, d => d.dataset_size) | |
bySize.forEach((d, i) => { | |
d.dataset_size = d.key | |
d.color = d3.interpolatePlasma(.84- i/6) | |
if (d.key == 60000){ | |
d3.selectAll('.tp60').st({background: d.color, padding: 2}) | |
} | |
if (d.key == 7500){ | |
d3.selectAll('.tp75').st({background: d.color, color: '#fff', padding: 2}) | |
} | |
d.label = { | |
60000: {pos: [7, 11], textAnchor: 'middle', text: '60,000'}, | |
30000: {pos: [7, 11], textAnchor: 'middle', text: '30,000'}, | |
15000: {pos: [7, -5], textAnchor: 'start', text: '15,000'}, | |
7500: {pos: [0, 8], textAnchor: 'start', text: '7,500'}, | |
// 3750: {pos: [0, 14], textAnchor: 'end', text: '3,750 training points'}, | |
3750: {pos: [-34, 10], textAnchor: 'start', text: '3,750'}, | |
2000: {pos: [-50, 10], textAnchor: 'end', text: '2,000 training points'}, | |
}[d.key] | |
d.forEach(e => e.size = d) | |
}) | |
var sel = d3.select('.accuracy-v-privacy-dataset_size').html('') | |
.at({role: 'graphics-document', 'aria-label': `High privacy and accuracy requires more training data. Line chart showing too much differential privacy without enough data decreases accuracy.`}) | |
sel.append('div.chart-title').text('High privacy and accuracy requires more training data') | |
var c = d3.conventions({ | |
sel, | |
height: 400, | |
margin: {bottom: 125, top: 5}, | |
layers: 'sd', | |
}) | |
c.x = d3.scaleLog().domain(util.epsilonExtent).range(c.x.range()) | |
c.xAxis = d3.axisBottom(c.x).tickFormat(d => { | |
var rv = d + '' | |
if (rv.split('').filter(d => d !=0 && d != '.')[0] == 1) return rv | |
}) | |
c.yAxis.tickFormat(d => d3.format('.0%')(d))//.ticks(8) | |
d3.drawAxis(c) | |
util.addAxisLabel(c, 'Higher Privacy →', 'Test Accuracy') | |
util.ggPlotBg(c, false) | |
c.layers[1].append('div') | |
.st({fontSize: 12, color: '#555', width: 120*2, textAlign: 'center', lineHeight: '1.3em'}) | |
.translate([c.width/2 - 120, c.height + 70]) | |
.html('in ε, a <a href="https://desfontain.es/privacy/differential-privacy-in-more-detail.html">measure</a> of how much modifying a single training point can change the model (models with a lower ε are more private)') | |
c.svg.selectAll('.y .tick').filter(d => d == .9) | |
.select('text').st({fontWeight: 600}).parent() | |
.append('path') | |
.at({stroke: '#000', strokeDasharray: '2 2', d: 'M 0 0 H ' + c.width}) | |
var line = d3.line() | |
.x(d => c.x(d.epsilon)) | |
.y(d => c.y(d.accuracy)) | |
.curve(d3.curveMonotoneX) | |
var lineSel = c.svg.append('g').appendMany('path.accuracy-line', bySize) | |
.at({ | |
d: line, | |
fill: 'none', | |
}) | |
.st({ stroke: d => d.color, }) | |
.on('mousemove', setActiveDigit) | |
var circleSel = c.svg.append('g') | |
.appendMany('g.accuracy-circle', data) | |
.translate(d => [c.x(d.epsilon), c.y(d.accuracy)]) | |
.on('mousemove', setActiveDigit) | |
// .call(d3.attachTooltip) | |
circleSel.append('circle') | |
.at({r: 4, stroke: '#fff'}) | |
.st({fill: d => d.size.color }) | |
var labelSel = c.svg.appendMany('g.accuracy-label', bySize) | |
.translate(d => [c.x(d[0].epsilon), c.y(d[0].accuracy)]) | |
labelSel.append('text') | |
.filter(d => d.label) | |
.translate(d => d.label.pos) | |
.st({fill: d => d.color, fontWeight: 400}) | |
.at({textAnchor: d => d.label.textAnchor, fontSize: 14, fill: '#000', dy: '.66em'}) | |
.text(d => d.label.text) | |
.filter(d => d.key == 2000) | |
.text('') | |
.tspans(d => d.label.text.split(' ')) | |
c.svg.append('text.annotation') | |
.translate([225, 106]) | |
.tspans(d3.wordwrap('With limited data, adding more differential privacy improves accuracy...', 25), 12) | |
c.svg.append('text.annotation') | |
.translate([490, 230]) | |
.tspans(d3.wordwrap(`...until it doesn't`, 20)) | |
// setActiveDigit({dataset_size: 60000}) | |
function setActiveDigit({dataset_size}){ | |
lineSel | |
.classed('active', 0) | |
.filter(d => d.dataset_size == dataset_size) | |
.classed('active', 1) | |
.raise() | |
circleSel | |
.classed('active', 0) | |
.filter(d => d.dataset_size == dataset_size) | |
.classed('active', 1) | |
.raise() | |
labelSel | |
.classed('active', 0) | |
.filter(d => d.dataset_size == dataset_size) | |
.classed('active', 1) | |
} | |
})() | |
// aVal: 0.5 | |
// accuracy: 0.8936 | |
// accuracy_0: 0.9663265306122449 | |
// accuracy_1: 0.9806167400881057 | |
// accuracy_2: 0.9011627906976745 | |
// accuracy_3: 0.8633663366336634 | |
// accuracy_4: 0.8859470468431772 | |
// accuracy_5: 0.8733183856502242 | |
// accuracy_6: 0.9384133611691023 | |
// accuracy_7: 0.8657587548638133 | |
// accuracy_8: 0.8059548254620124 | |
// accuracy_9: 0.8434093161546086 | |
// dataset_size: 60000 | |
// epochs: 4 | |
// epsilon: 0.19034890168775565 | |
// l2_norm_clip: 0.75 | |
// noise_multiplier: 2.6 | |