diff options
Diffstat (limited to 'app/client/modules')
| -rw-r--r-- | app/client/modules/pix2pixhd/pix2pixhd.actions.js | 18 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/pix2pixhd.tasks.js | 20 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/views/pix2pixhd.train.js | 108 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/views/sequence.editor.js | 181 |
4 files changed, 178 insertions, 149 deletions
diff --git a/app/client/modules/pix2pixhd/pix2pixhd.actions.js b/app/client/modules/pix2pixhd/pix2pixhd.actions.js index 2c72f06..d067017 100644 --- a/app/client/modules/pix2pixhd/pix2pixhd.actions.js +++ b/app/client/modules/pix2pixhd/pix2pixhd.actions.js @@ -202,18 +202,18 @@ export const list_epochs = (checkpoint_name) => (dispatch) => { }) } -export const count_dataset = (checkpoint_name) => (dispatch) => { +export const count_dataset = (dataset) => (dispatch) => { const module = pix2pixhdModule.name util.allProgress([ - actions.socket.list_directory({ module, dir: 'sequences/' + checkpoint_name + '/' }), - actions.socket.count_directory({ module, dir: 'datasets/' + checkpoint_name + '/train_A/' }), + actions.socket.list_directory({ module, dir: 'sequences/' + dataset + '/' }), + actions.socket.count_directory({ module, dir: 'datasets/' + dataset + '/train_A/' }), ], (percent, i, n) => { console.log('pix2pixhd load progress', i, n) - dispatch({ - type: types.app.load_progress, - progress: { i, n }, - data: { module: 'pix2pixhd' }, - }) + // dispatch({ + // type: types.app.load_progress, + // progress: { i, n }, + // data: { module: 'pix2pixhd' }, + // }) }).then(res => { const [sequence, datasetCount] = res //, datasets, results, output, datasetUsage, lossReport] = res const sequenceCount = sequence.length @@ -221,7 +221,7 @@ export const count_dataset = (checkpoint_name) => (dispatch) => { dispatch({ type: types.pix2pixhd.load_dataset_count, data: { - name: checkpoint_name, + name: dataset, sequence, sequenceCount, datasetCount, diff --git a/app/client/modules/pix2pixhd/pix2pixhd.tasks.js b/app/client/modules/pix2pixhd/pix2pixhd.tasks.js index 8fec652..89184d2 100644 --- a/app/client/modules/pix2pixhd/pix2pixhd.tasks.js +++ b/app/client/modules/pix2pixhd/pix2pixhd.tasks.js @@ -23,10 +23,12 @@ export const fetch_task = (url, file_id, dataset) => dispatch => { } export const train_task = (dataset, folder_id, epochs=1) => dispatch => { + dataset = dataset.name || dataset + if (dataset === 'PLACEHOLDER') return const task = { module: module.name, activity: 'train', - dataset: dataset.name || dataset, + dataset, epoch: 0, epochs: epochs, opt: { @@ -58,6 +60,7 @@ export const live_task = (sequence, checkpoint, opt) => dispatch => { } export const augment_task = (dataset, opt) => dispatch => { + if (dataset === 'PLACEHOLDER') return const task = { module: module.name, activity: 'augment', @@ -72,14 +75,17 @@ export const augment_task = (dataset, opt) => dispatch => { return actions.queue.add_task(task) } -export const clear_recursive_task = (dataset) => dispatch => { +export const create_dataset_task = (opt) => dispatch => { const task = { module: module.name, - activity: 'clear_recursive', - dataset, + activity: 'create_dataset', + dataset: opt.title, + folder_id: opt.folder_id, + opt: { + ...opt, + } } console.log(task) - console.log('add clear recursive task') + console.log('add create_dataset task') return actions.queue.add_task(task) -} - +}
\ No newline at end of file diff --git a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js index 6aade36..de32fcd 100644 --- a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js +++ b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js @@ -24,16 +24,17 @@ import SequenceEditor from './sequence.editor' import pix2pixhdModule from '../pix2pixhd.module' class Pix2PixHDTrain extends Component { + state = { + dataset: 'PLACEHOLDER', + epoch: 'latest', + augment_name: '', + augment_take: 100, + augment_make: 20, + generated: false, + } constructor(props){ super(props) this.handleChange = this.handleChange.bind(this) - this.state = { - checkpoint_name: 'PLACEHOLDER', - epoch: 'latest', - augment_name: '', - augment_take: 100, - augment_make: 20, - } } componentDidMount(){ const id = this.props.match.params.id || localStorage.getItem('pix2pixhd.last_id') @@ -50,15 +51,30 @@ class Pix2PixHDTrain extends Component { this.props.history.push('/pix2pixhd/new/') } if (dataset) { - this.setState({ checkpoint_name: dataset }) + this.setState({ dataset }) } } componentDidUpdate(prevProps, prevState){ - if (prevState.checkpoint_name !== this.state.checkpoint_name) { - localStorage.setItem('pix2pixhd.last_dataset', this.state.checkpoint_name) - this.setState({ epoch: 'latest' }) - this.props.actions.list_epochs(this.state.checkpoint_name) - this.props.actions.count_dataset(this.state.checkpoint_name) + if ((!prevProps.pix2pixhd.data && this.props.pix2pixhd.data) + || (prevProps.pix2pixhd.data && prevState.dataset !== this.state.dataset)) { + const dataset = this.props.pix2pixhd.data.datasetLookup[this.state.dataset] + if (dataset) { + const generated = dataset.input + .map(f => this.props.pix2pixhd.data.fileLookup[f]) + .reduce((a,b) => { + return b.generated || a + }, false) + dataset.generated = generated + this.setState({ generated }) + } + } + if (prevState.dataset !== this.state.dataset) { + localStorage.setItem('pix2pixhd.last_dataset', this.state.dataset) + this.setState({ + epoch: 'latest', + }) + this.props.actions.list_epochs(this.state.dataset) + this.props.actions.count_dataset(this.state.dataset) } } handleChange(name, value){ @@ -72,17 +88,18 @@ class Pix2PixHDTrain extends Component { if (this.props.pix2pixhd.loading) { return <Loading progress={this.props.pix2pixhd.progress} /> } - const { pix2pixhd, match, history, queue } = this.props + const { pix2pixhd, match, history } = this.props const { folderLookup, datasetLookup } = (pix2pixhd.data || {}) const folder = (folderLookup || {})[pix2pixhd.folder_id] || {} + const { checkpoint } = pix2pixhd // console.log(pix2pixhd) - const checkpointGroups = Object.keys(folderLookup).map(id => { + const sequenceGroups = Object.keys(folderLookup).map(id => { const folder = this.props.pix2pixhd.data.folderLookup[id] if (folder.name === 'results') return const datasets = folder.datasets.map(name => { const dataset = datasetLookup[name] - if (dataset.checkpoints.length) { + if (dataset.isBuilt && dataset.checkpoints.length) { return name } return null @@ -94,7 +111,7 @@ class Pix2PixHDTrain extends Component { }).filter(n => !!n && !!n.options.length).sort((a,b) => a.name.localeCompare(b.name)) // console.log('state', this.props.pix2pixhd.data.epochs) - // console.log(this.state.checkpoint_name, this.state.epoch) + // console.log(this.state.dataset, this.state.epoch) // console.log(queue) return ( <div className='app pix2pixhd'> @@ -103,57 +120,70 @@ class Pix2PixHDTrain extends Component { </div> <div className='columns'> <div className='column'> - <Group title='Dataset'> + <Group title='Sequence'> <SelectGroup - name='checkpoint_name' - title='Dataset' - options={checkpointGroups} + name='dataset' + title='Sequence name' + options={sequenceGroups} onChange={this.handleChange} placeholder='Pick a dataset' - value={this.state.checkpoint_name} + value={this.state.dataset} /> <Select title="Epoch" name="epoch" - options={this.props.pix2pixhd.data.epochs} + options={this.props.pix2pixhd.epochs} onChange={this.handleChange} value={this.state.epoch} /> </Group> </div> </div> - <div> - <Group title='Sequence Editor'> - <SequenceEditor - module={pix2pixhdModule} - checkpoint={this.props.pix2pixhd.checkpoint} - /> - </Group> - </div> + {checkpoint && checkpoint.sequence && checkpoint.sequence.length + ? this.renderEditor() + : checkpoint && <div>Sequence empty, augmentation impossible</div>} + </div> + ) + } + + renderEditor(){ + const { pix2pixhd, queue, remote } = this.props + const { checkpoint, folder_id } = pix2pixhd + const { dataset, generated } = this.state + return ( + <div> + <Group title='Sequence Editor'> + <SequenceEditor + folder_id={folder_id} + module={pix2pixhdModule} + checkpoint={checkpoint} + generated={generated} + /> + </Group> <div className='columns'> <div className='column'> <Group title='Augmentation Grid'> <AugmentationGrid - checkpoint={this.props.pix2pixhd.checkpoint} + checkpoint={checkpoint} take={[1,2,3,4,5,10,15,20,25,50,75,100,200,300,400,500,1000]} make={[1,2,3,4,5,10,15,20,25,50,75,100,200,]} onAugment={(augment_take, augment_make) => { - this.props.remote.augment_task(this.state.checkpoint_name, { + remote.augment_task(dataset, { ...this.state, augment_take, augment_make, }) }} onTrain={() => { - this.props.remote.train_task(this.state.checkpoint_name, pix2pixhd.folder_id, 1) + remote.train_task(dataset, folder_id, 1) setTimeout(() => { // auto-generate epoch demo - this.props.remote.augment_task(this.state.checkpoint_name, { + remote.augment_task(dataset, { ...this.state, augment_take: 10, augment_make: 149, no_symlinks: true, mov: true, - folder_id: this.props.pix2pixhd.data.resultsFolder.id + folder_id: pix2pixhd.data.resultsFolder.id }) }, 250) }} @@ -181,17 +211,17 @@ class Pix2PixHDTrain extends Component { <Button title="Augment dataset" value="Augment" - onClick={() => this.props.remote.augment_task(this.state.checkpoint_name, this.state)} + onClick={() => this.props.remote.augment_task(dataset, this.state)} /> <Button title="Make a movie without augmenting" value="Generate" onClick={() => { - this.props.remote.augment_task(this.state.checkpoint_name, { + this.props.remote.augment_task(dataset, { ...this.state, no_symlinks: true, mov: true, - folder_id: this.props.pix2pixhd.data.resultsFolder.id + folder_id: pix2pixhd.data.resultsFolder.id }) }} /> diff --git a/app/client/modules/pix2pixhd/views/sequence.editor.js b/app/client/modules/pix2pixhd/views/sequence.editor.js index e66aebf..135dfb3 100644 --- a/app/client/modules/pix2pixhd/views/sequence.editor.js +++ b/app/client/modules/pix2pixhd/views/sequence.editor.js @@ -2,147 +2,140 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Route, Link } from 'react-router-dom' +import moment from 'moment/min/moment.min' -import { Loading, FileList, FileViewer } from '../../../common' +import util from '../../../util' +import { FileViewer, Timeline, Param, Button, Group, TextInput } from '../../../common' + +import * as pix2pixhdTasks from '../pix2pixhd.tasks' import actions from '../../../actions' const initialState = { dir: '/', - frameA: null, - frameB: null, + cursor: null, selection: null, - loading: true + title: null, } -/* - when the sequence editor loads, - reset the selection - reset the two frames - set the two frames to the beginning and end of the video - when mousing over the video - ideally you would see a tiny thumbnail preview of the frame :) - - click to start a selection, drag over, mouseup to end the selection - this should update the start/end frame - ... - so there are two things you could do with this - 1) create an entirely new dataset - 2) add frames to an existing dataset - ... - method 1) - - requires minimal setup, just a server script which.. - - creates the new sequence folder - - symlinks the frames - - runs build_dataset - - create appropriate file object, using parent dataset's folder_id - - enqueue initial training - ---> we can then train on basic subsets, with more control, like we do already... - - tell parent dataset thing the new sequence name - ... - method 2) - - requires sequence editor to be aware of its own dataset - - requires sequence editor to know whether a sequence is original or not -*/ - class SequenceEditor extends Component { state = { ...initialState } constructor() { super() - this.handleMouseDown = this.handleMouseDown.bind(this) - this.handleMouseMove = this.handleMouseMove.bind(this) - this.handleMouseEnter = this.handleMouseEnter.bind(this) - this.handleMouseLeave = this.handleMouseLeave.bind(this) - this.handleMouseUp = this.handleMouseUp.bind(this) + this.handleCursor = this.handleCursor.bind(this) + this.handleSelect = this.handleSelect.bind(this) } componentDidMount() { const { checkpoint } = this.props - window.addEventListener('mousemove', this.handleMouseMove) - window.addEventListener('mouseup', this.handleMouseUp) - if (checkpoint && checkpoint.sequence) { - console.log(checkpoint) - const frameA = checkpoint.sequence[0] - const frameB = checkpoint.sequence[checkpoint.sequence.length-1] - this.setState({ - ...initialState, - frameA, - frameB, - }) + if (checkpoint) { + this.reset() } } componentDidUpdate(prevProps) { const { checkpoint } = this.props if (checkpoint !== prevProps.checkpoint) { - console.log(checkpoint) - const frameA = checkpoint.sequence[0] - const frameB = checkpoint.sequence[checkpoint.sequence.length-1] - this.setState({ - ...initialState, - frameA, - frameB, - }) + this.reset() } } - componentWillUnmount(){ - window.removeEventListener('mouseup', this.handleMouseUp) - window.removeEventListener('mousemove', this.handleMouseMove) + reset(){ + const { checkpoint } = this.props + if (!(checkpoint && checkpoint.sequence)) return + console.log(checkpoint) + this.setState({ + ...initialState, + title: checkpoint.name + '_' + moment().format("YYYYMMDD") + }) } - handleMouseDown(e) { - this.setState({ dragging: true }) - } - handleMouseMove(e) { - } - handleMouseEnter(e) { - } - handleMouseLeave(e) { - } - handleMouseUp(e) { - this.setState({ dragging: false }) + handleCursor(cursor) { + this.setState({ cursor }) } - handlePick(file) { - console.log(file) - // this.setState({ dir, file: null, loading: true }) + handleSelect(selection) { + this.setState({ selection }) } render() { - const { app, checkpoint } = this.props - const { - loading, - selection, - frameA, frameB, - } = this.state - // console.log(this.props, this.state) - const width = 200 + const { app, pix2pixhd, remote, checkpoint, folder_id, generated } = this.props + const { cursor, selection, title } = this.state const path = "sequences/" + checkpoint.name + console.log(checkpoint, pix2pixhd) return ( - <div className='sequenceEditor'> - <div - className='timeline' - style={{ width }} - mouseDown={this.handleSelectionStart} - mouseEnter={this.handleMouseEnter} - mouseLeave={this.handleMouseLeave} - > - {selection && <div className='selection' style={selection}></div>} + <div className='sequenceEditor row'> + {selection + ? <div className='form'> + <Param title='Selection length'> + {selection.end.i - selection.start.i}{' frames'} + </Param> + <Param title='Duration'> + {util.frameTimestamp(selection.end.i - selection.start.i)} + </Param> + <Group title='New dataset'> + <TextInput + title='Title dataset' + value={title} + onInput={title => this.setState({ title: title.replace(/ /g, '_').replace(/\/\./g, '') })} + /> + <Button + title='Create a new dataset?' + onClick={() => remote.create_dataset_task({ title, sequence: checkpoint.name, selection, folder_id })} + > + Create + </Button> + </Group> + <Group title='Salt dataset'> + {generated + ? 'Salting is only available on generated datasets.' + : 'Salting coming soon!'} + </Group> + </div> + : <div className='form'><Group title='New dataset'>Please select some frames</Group></div> + } + <div className='rows'> + <div className='row'> + <Frame label='Cursor' path={path} frame={cursor} /> + {selection && selection.start && + <Frame label='Selection Start' path={path} frame={selection.start} /> + } + {selection && selection.end && + <Frame label='Selection End' path={path} frame={selection.end} /> + } + </div> + <Timeline + sequence={checkpoint.sequence} + onCursor={this.handleCursor} + onSelect={this.handleSelect} + /> </div> - <FileViewer thumbnail path={path} file={this.state.frameA} /> - <FileViewer thumbnail path={path} file={this.state.frameB} /> </div> ) } } +function Frame ({ label, path, frame }) { + if (!frame) return <div class='frame'></div> + return ( + <div class='frame'> + <FileViewer thumbnail={140} path={path} file={frame.frame} /> + <div class='spaced'> + <span>{label}</span> + <span>{'#'}{frame.i} {util.frameTimestamp(frame.i)}</span> + </div> + </div> + ) +} + const mapStateToProps = state => ({ app: state.system.app, + pix2pixhd: state.module.pix2pixhd, }) const mapDispatchToProps = (dispatch, ownProps) => ({ - actions: bindActionCreators({}, dispatch), + remote: bindActionCreators(pix2pixhdTasks, dispatch), }) export default connect(mapStateToProps, mapDispatchToProps)(SequenceEditor) |
