summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2018-06-02 20:44:46 +0200
committerJules Laplace <julescarbon@gmail.com>2018-06-02 20:44:46 +0200
commitfdf927db614a1e7696688b6e39c2bdb7548a72cc (patch)
tree1c8e3cf64dfa4275e0526265f296b376c2c1b827 /app
parent01cda57ffd9edc0a3f53501399c134815232e4b5 (diff)
loss report
Diffstat (limited to 'app')
-rw-r--r--app/client/dashboard/dashboard.component.js2
-rw-r--r--app/client/dataset/dataset.component.js3
-rw-r--r--app/client/modules/samplernn/index.js7
-rw-r--r--app/client/modules/samplernn/samplernn.actions.js48
-rw-r--r--app/client/modules/samplernn/samplernn.datasets.js31
-rw-r--r--app/client/modules/samplernn/samplernn.loss.js143
-rw-r--r--app/client/modules/samplernn/samplernn.reducer.js8
-rw-r--r--app/client/types.js1
-rw-r--r--app/client/util.js7
-rw-r--r--app/server/bridge.js2
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)