diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2018-06-02 20:44:46 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2018-06-02 20:44:46 +0200 |
| commit | fdf927db614a1e7696688b6e39c2bdb7548a72cc (patch) | |
| tree | 1c8e3cf64dfa4275e0526265f296b376c2c1b827 /app | |
| parent | 01cda57ffd9edc0a3f53501399c134815232e4b5 (diff) | |
loss report
Diffstat (limited to 'app')
| -rw-r--r-- | app/client/dashboard/dashboard.component.js | 2 | ||||
| -rw-r--r-- | app/client/dataset/dataset.component.js | 3 | ||||
| -rw-r--r-- | app/client/modules/samplernn/index.js | 7 | ||||
| -rw-r--r-- | app/client/modules/samplernn/samplernn.actions.js | 48 | ||||
| -rw-r--r-- | app/client/modules/samplernn/samplernn.datasets.js | 31 | ||||
| -rw-r--r-- | app/client/modules/samplernn/samplernn.loss.js | 143 | ||||
| -rw-r--r-- | app/client/modules/samplernn/samplernn.reducer.js | 8 | ||||
| -rw-r--r-- | app/client/types.js | 1 | ||||
| -rw-r--r-- | app/client/util.js | 7 | ||||
| -rw-r--r-- | app/server/bridge.js | 2 |
10 files changed, 194 insertions, 58 deletions
diff --git a/app/client/dashboard/dashboard.component.js b/app/client/dashboard/dashboard.component.js index 64200b0..c74c4df 100644 --- a/app/client/dashboard/dashboard.component.js +++ b/app/client/dashboard/dashboard.component.js @@ -10,7 +10,7 @@ import Button from '../common/button.component' import DashboardHeader from './dashboardheader.component' import TaskList from './tasklist.component' -import FileList from '../common/fileList.component' +import { FileList } from '../common/fileList.component' import Gallery from '../common/gallery.component' import * as dashboardActions from './dashboard.actions' diff --git a/app/client/dataset/dataset.component.js b/app/client/dataset/dataset.component.js index c64a51f..73f1720 100644 --- a/app/client/dataset/dataset.component.js +++ b/app/client/dataset/dataset.component.js @@ -6,7 +6,7 @@ import * as datasetActions from './dataset.actions' import Group from '../common/group.component' import Param from '../common/param.component' -import FileList from '../common/fileList.component' +import { FileList } from '../common/fileList.component' import FileUpload from '../common/fileUpload.component' import TextInput from '../common/textInput.component' @@ -23,6 +23,7 @@ class Dataset extends Component { fileOptions, pickFile, onPick } = this.props // sort files?? + if (!folder.id) { return ( <div className='dataset'> diff --git a/app/client/modules/samplernn/index.js b/app/client/modules/samplernn/index.js index e020c6c..e8254dd 100644 --- a/app/client/modules/samplernn/index.js +++ b/app/client/modules/samplernn/index.js @@ -2,12 +2,15 @@ import { h, Component } from 'preact' import { Route, Link } from 'react-router-dom' import SampleRNNDatasets from './samplernn.datasets' import SampleRNNInspect from './samplernn.inspect' +import SampleRNNLoss from './samplernn.loss' function router () { return ( <div> - <Route path='/samplernn/inspect/' component={SampleRNNInspect} /> - <Route path='/samplernn/datasets/' component={SampleRNNDatasets} /> + <Route exact path='/samplernn/loss/' component={SampleRNNLoss} /> + <Route exact path='/samplernn/inspect/' component={SampleRNNInspect} /> + <Route exact path='/samplernn/datasets/' component={SampleRNNDatasets} /> + <Route exact path='/samplernn/dataset/new/' component={SampleRNNDatasets} /> </div> ) } diff --git a/app/client/modules/samplernn/samplernn.actions.js b/app/client/modules/samplernn/samplernn.actions.js index 339c347..4b8d00b 100644 --- a/app/client/modules/samplernn/samplernn.actions.js +++ b/app/client/modules/samplernn/samplernn.actions.js @@ -11,10 +11,9 @@ export const load_directories = () => (dispatch) => { actions.task.index({ module: 'samplernn' }), actions.socket.list_directory({ module: 'samplernn', dir: 'results' }), actions.socket.list_directory({ module: 'samplernn', dir: 'datasets' }), - actions.socket.run_script({ module: 'samplernn', activity: 'report' }) ]).then(res => { - console.log(res) - const [folders, files, tasks, results, datasets, report] = res + // console.log(res) + const [folders, files, tasks, results, datasets] = res const folderLookup = folders.reduce((folderLookup, folder) => { folderLookup[folder.id] = folder @@ -75,27 +74,14 @@ export const load_directories = () => (dispatch) => { .map(s => s.split(':')) .filter(b => b.length && b[1]) .reduce((a,b) => (a[b[0]] = b[1]) && a, {}) + // console.log(checkpoint.dataset) + checkpoint.name = checkpoint.dataset checkpoint.dir = s const file = fileLookup[checkpoint.dataset] || fileLookup.unsorted file.checkpoints.push(checkpoint) return checkpoint }) - // console.log(folders.length, files.length, tasks.length, results.length, datasets.length) - // console.log(report) - report.stdout.split('\n\n').filter(a=>!!a).forEach(data => { - const [ name, ...lines ] = data.split('\n') - const file = fileLookup[name] || fileLookup.unsorted - file.log = lines - .map(s => - s.split('\t').map(s => - s.split(': ') - .filter(b => b.length && b[1]) - .reduce((a,b) => (a[b[0]] = b[1])&&a, {}) - ) - ) - }) - dispatch({ type: types.samplernn.init, data: { @@ -103,13 +89,12 @@ export const load_directories = () => (dispatch) => { folders, files, checkpoints, builtDatasets, - report }, }) if (folders.length) { dispatch({ type: types.samplernn.set_folder, - folder: folders[0].name, + folder: folders[0], }) } }).catch(e => { @@ -117,6 +102,29 @@ export const load_directories = () => (dispatch) => { }) } +export const load_loss = () => dispatch => { + actions.socket.run_script({ module: 'samplernn', activity: 'report' }) + .then(report => { + const lossReport = {} + report.stdout.split('\n\n').filter(a=>!!a).forEach(data => { + const [ name, ...lines ] = data.split('\n') + lossReport[name] = lines + .map(s => + s.split('\t').reduce((a,s) => { + const b = s.split(': ') + a[b[0]] = b[1] + return a + }, {}) + ) + // console.log(loss[name]) + }) + dispatch({ + type: types.samplernn.load_loss, + lossReport + }) + }) +} + export const set_folder = (folder) => { types.samplernn.set_folder, folder } export const fetch_url = (url) => (dispatch) => { diff --git a/app/client/modules/samplernn/samplernn.datasets.js b/app/client/modules/samplernn/samplernn.datasets.js index bcc7878..ac0a667 100644 --- a/app/client/modules/samplernn/samplernn.datasets.js +++ b/app/client/modules/samplernn/samplernn.datasets.js @@ -24,7 +24,6 @@ class SampleRNNDatasets extends Component { console.log('pick', file) } fileOptions(file){ - // console.log(file) if (file.activity === 'url' && !file.dataset) { if (this.props.runner.cpu.status !== 'IDLE') { return ( @@ -72,36 +71,6 @@ class SampleRNNDatasets extends Component { </div> ) } - renderData(){ - // {this.renderData()} - const { samplernn, actions } = this.props - if (samplernn.data === null) { - return - } - return ( - <div class='row params'> - <FileList - title='Folders' - className='folders' - fields='name' - onPick={actions.set_folder} - files={samplernn.data.folders} - /> - <FileList - title='Files' - files={samplernn.data.files} - /> - <FileList - title='Datasets' - files={samplernn.data.builtDatasets} - /> - <FileList - title='Checkpoints' - files={samplernn.data.checkpoints} - /> - </div> - ) - } } const mapStateToProps = state => ({ diff --git a/app/client/modules/samplernn/samplernn.loss.js b/app/client/modules/samplernn/samplernn.loss.js new file mode 100644 index 0000000..3900c31 --- /dev/null +++ b/app/client/modules/samplernn/samplernn.loss.js @@ -0,0 +1,143 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import { lerp, norm, randint, randrange } from '../../util' + +import * as samplernnActions from './samplernn.actions' + +import Dataset from '../../dataset/dataset.component' + +import Group from '../../common/group.component' +import Slider from '../../common/slider.component' +import Select from '../../common/select.component' +import Button from '../../common/button.component' +import { FileList } from '../../common/fileList.component' +import TextInput from '../../common/textInput.component' + +class SampleRNNLoss extends Component { + constructor(props){ + super() + props.actions.load_loss() + } + render(){ + this.refs = {} + return ( + <div className='app lossGraph'> + <div className='heading'> + <h3>SampleRNN Loss</h3> + <canvas ref={(ref) => this.refs['canvas'] = ref} /> + </div> + </div> + ) + } + componentDidUpdate(){ + const { lossReport } = this.props.samplernn + if (! lossReport) return + const canvas = this.refs.canvas + canvas.width = window.innerWidth + canvas.height = window.innerHeight + canvas.style.width = canvas.width + 'px' + canvas.style.height = canvas.height + 'px' + + const ctx = canvas.getContext('2d') + const w = canvas.width = canvas.width * devicePixelRatio + const h = canvas.height = canvas.height * devicePixelRatio + + const keys = Object.keys(lossReport).sort().filter(k => !!lossReport[k].length) + let scaleMax = 0 + let scaleMin = Infinity + let epochsMax = 0 + keys.forEach(key => { + const loss = lossReport[key] + epochsMax = Math.max(loss.length, epochsMax) + loss.forEach((a) => { + const v = parseFloat(a.training_loss) + if (! v) return + scaleMax = Math.max(v, scaleMax) + scaleMin = Math.min(v, scaleMin) + }) + }) + // scaleMax *= 10 + console.log(scaleMax, scaleMin, epochsMax) + + scaleMax = 3 + scaleMin = 0 + const margin = 0 + const wmin = 0 + const wmax = w + const hmin = 0 + const hmax = h + const epochsScaleFactor = 1 // 3/2 + + let X, Y + for (var ii = 0; ii < epochsMax; ii++) { + X = lerp((ii)/(epochsMax/(epochsScaleFactor))*(epochsScaleFactor), wmin, wmax) + ctx.strokeStyle = 'rgba(0,0,0,0.3)' + ctx.beginPath(0, 0) + ctx.moveTo(X, 0) + ctx.lineTo(X, h) + ctx.lineWidth = 1 + // ctx.stroke() + if ( (ii % 5) === 0 ) { + ctx.lineWidth = 2 + ctx.stroke() + } + } + for (var ii = scaleMin; ii < scaleMax; ii += 1) { + Y = lerp(ii/scaleMax, wmin, wmax) + // ctx.strokeStyle = 'rgba(255,255,255,1.0)' + ctx.beginPath(0, 0) + ctx.moveTo(0, (h-Y)) + ctx.lineTo(w, (h-Y)) + ctx.lineWidth = 1 + // ctx.stroke() + // if ( (ii % 1) < 0.1) { + // ctx.strokeStyle = 'rgba(255,255,255,1.0)' + ctx.lineWidth = 2 + ctx.stroke() + ctx.stroke() + ctx.stroke() + // } + } + ctx.lineWidth = 1 + + keys.forEach(key => { + const loss = lossReport[key] + const vf = parseFloat(loss[loss.length-1].training_loss) || 0 + const vg = parseFloat(loss[0].training_loss) || 5 + console.log(vf) + const vv = 1 - norm(vf, scaleMin, scaleMax/2) + ctx.lineWidth = (1-norm(vf, scaleMin, scaleMax)) * 5 + ctx.strokeStyle = 'rgba(' + [randrange(30,190), randrange(30,150), randrange(60,120)].join(',') + ',' + 0.8+ ')' + let begun = false + loss.forEach((a, i) => { + const v = parseFloat(a.training_loss) + if (! v) return + const x = lerp((i-2)/(epochsMax/(epochsScaleFactor))*(epochsScaleFactor), wmin, wmax) + const y = lerp(norm(v, scaleMin, scaleMax), hmax, hmin) + if (i === 0) { + return + } + if (! begun) { + begun = true + ctx.beginPath(x,y) + } else { + ctx.lineTo(x,y) + // ctx.stroke() + } + }) + ctx.stroke() + }) + } +} + +const mapStateToProps = state => ({ + samplernn: state.module.samplernn, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators(samplernnActions, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(SampleRNNLoss) diff --git a/app/client/modules/samplernn/samplernn.reducer.js b/app/client/modules/samplernn/samplernn.reducer.js index 27d4d58..372b3bc 100644 --- a/app/client/modules/samplernn/samplernn.reducer.js +++ b/app/client/modules/samplernn/samplernn.reducer.js @@ -6,12 +6,12 @@ const samplernnInitialState = { folders: [], folder: {}, data: null, + lossReport: null, } const samplernnReducer = (state = samplernnInitialState, action) => { switch(action.type) { case types.samplernn.init: - console.log(action.data) return { ...state, loading: false, @@ -54,6 +54,12 @@ const samplernnReducer = (state = samplernnInitialState, action) => { folder: action.folder, } + case types.samplernn.load_loss: + return { + ...state, + lossReport: action.lossReport, + } + default: return state } diff --git a/app/client/types.js b/app/client/types.js index 092ad8f..d758bc6 100644 --- a/app/client/types.js +++ b/app/client/types.js @@ -77,6 +77,7 @@ export default { samplernn: { init: 'SAMPLERNN_INIT', set_folder: 'SAMPLERNN_SET_FOLDER', + load_loss: 'SAMPLERNN_LOAD_LOSS', // queue and train // update checkpoint settings // reset checkpoint settings diff --git a/app/client/util.js b/app/client/util.js index 2ba6d3f..34fa023 100644 --- a/app/client/util.js +++ b/app/client/util.js @@ -10,7 +10,12 @@ htmlClassList.remove('loading') // window.debug = false -function randint(n) { return Math.floor(Math.random()*n) } +export function clamp(n,a,b) { return n<a?a:n<b?n:b } +export function norm(n,a,b) { return (n-a) / (b-a) } +export function lerp(n,a,b) { return (b-a)*n+a } +export function mix(n,a,b) { return a*(1-n)+b*n } +export function randint(n) { return Math.floor(Math.random()*n) } +export function randrange(a,b){ return Math.random() * (b-a) + a } document.body.style.backgroundImage = 'linear-gradient(' + (randint(40)+40) + 'deg, #fde, #ffe)' diff --git a/app/server/bridge.js b/app/server/bridge.js index f6af00d..a6c465e 100644 --- a/app/server/bridge.js +++ b/app/server/bridge.js @@ -9,7 +9,7 @@ client.on('connect', bind_client) export const relay = (() => { let relay; if (process.env.EXPRESS_CONNECTS_TO_RELAY === 'true') { - const relay_endpoint = (process.env.SECURE_PROXY ? 'https' : 'http') + process.env.PROXY_REMOTE + '/client' + const relay_endpoint = (process.env.SECURE_PROXY ? 'https' : 'http') + "://" + process.env.PROXY_REMOTE + '/client' console.log('Connecting to relay on ' + relay_endpoint) relay = require('socket.io-client').connect(relay_endpoint) proxy.attach(server) |
