/******************************************************************************* * Copyright (c) 2015-2019 Skymind, Inc. * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * SPDX-License-Identifier: Apache-2.0 ******************************************************************************/ include "array.fbs"; //For FlatArray namespace nd4j.graph; /* An "Event" is any value that may occur multiple times (score vs. iteration, or accuracy for example) All events have timestamps and iteration/epoch. Design: Given given FlatBuffers doesn't support polymorphism, each "frame" in our log file will comprise a sequence of (Event,X) pairs "Event" is common information/header for the frame (i.e., determines type that follows and allows decoding), and can also be used for filtering - i.e., can skip the next entry Alternatives: 1. Have a large Event class, with all but 1 of the 'type specific' fields being null (inefficient, especially for things like scalars) 2. Use pair of (ubyte,X) and have duplicate fields in every event subtype Types of entries that can follow an Event: array:FlatArray; //Use standard/existing graph FlatArray class. Also used for scalars! (For types and also strings etc) arrayList:[FlatArray]; //For TensorArray and the like histogram:Histogram; //Histogram class image:Image; //Could just use array/FlatArray, but idea is to store more efficiently here in compressed format summaryStat:SummaryStatistics; //One class for holding stuff like min/mean/max/stdev etc - more efficiently than a whole lot of separate scalar entries... opTiming:FlatTiming; //Timing/profiling information about a single op execution. Use existing FlatTiming, but maybe extend if required hardwareState:HardwareState; //Information about hardware at a specific point in time: CPU/GPU utilization, etc */ enum UIEventType:byte { ADD_NAME, //Used to register a name (essentialy, Map.put(i,name)), so it can be referred to by index later. Saves us encoding really long names in every single frame... SCALAR, ARRAY, ARRAY_LIST, HISTOGRAM, IMAGE, //To be added later SUMMARY_STATISTICS, OP_TIMING, HARDWARE_STATE } /* UIEventSubtype relates to what the metric is about. This determines where the value should be presented in the UI For example, we can have scalars for: evaluation, tuning (mean magnitudes), performance (op runtime) etc. But these should be presented in different sections of the UI. It can also be thought of as the "semantic type of event" whereas UIEventType is the "data type of event" */ enum UIEventSubtype:byte { NONE, //Not applicable (for example, ADD_NAME event type) EVALUATION, //Train/test accuracy, etc LOSS, //Value of the loss function (or any sub-component there-of, such as L2) LEARNING_RATE, //Learning rate TUNING_METRIC, //Metrics like: parameter:update ratio, or parameter and gradient histograms, etc PERFORMANCE, //Global performance metrics - batches/sec, epoch time, etc PROFILING, //Op profiling/performance metrics - how long to run each op, etc FEATURE_LABEL, //Feature/input - for visualization, debugging, etc PREDICTION, //Network prediction/output USER_CUSTOM //Custom, user-defined metric or value } table UIEvent { eventType:UIEventType; //Type of the event that follows eventSubType:UIEventSubtype;//Subtype of event that follows nameIdx:int; //Integer representing the previously registered name of the event - for example, 0=="accuracy", 1=="score", 2=="weights" etc as previously registered timestamp:long; iteration:int; epoch:int; variableId:int16; //Number of the variable. Optional (-1 == not applicable) frameIter:FrameIteration; //Optional - some events have a corresponding frame/iteration plugin:uint16; //An ID number - what UI page/plugin should be used to render this information? (Allows for extensibility, separation of data for different UI components) } //Optional, often null. Used for events that have an associated frame/iteration (like array values in a loop) table FrameIteration { frame:string; iteration:uint16; } //Used to register a name (essentialy, Map.put(i,name)), so it can be referred to by index later. Saves us encoding really long names in every single frame... table UIAddName { nameIdx:int; name:string; } //A simple list of arrays table FlatArrayList { list:[FlatArray]; } enum UIHistogramType:byte { DISCRETE, EQUAL_SPACING, //use min/max + num bins to determine where CUSTOM } table UIHistogram { type:UIHistogramType; numbins:uint32; binranges:FlatArray; //Shape [2] for EQUAL_SPACING (min/max), or shape [2,numbins] for custom bin min/max values y:FlatArray; //Shape [numbins] - could be integer or floating point, positive or negative binlabels:[string]; //Optional - used for discrete histograms (essentially, bar chart) //TODO might want to register this value once + reuse? } table UISummaryStatistics { bitmask:uint32; //Bit mask that represents which of the primitives are actually present (FB doesn't support null primitives AFAIK) min:FlatArray; //Typed - but it would be more space efficient to use double... max:FlatArray; mean:double; stdev:double; countzero:long; countpositive:long; countnegative:long; countnan:long; countinf:long; } //Standard metrics related to current hardware status table UIHardwareState { //TODO - do we want CPU/GPU utilization statistics and the like? gpuMemory:[long]; hostMemory:long; }