UNPKG

federer

Version:

Experiments in asynchronous federated learning and decentralized learning

87 lines 4.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TensorBoardOutput = void 0; const tslib_1 = require("tslib"); const assert = require("assert"); const path = tslib_1.__importStar(require("path")); const tf = tslib_1.__importStar(require("@tensorflow/tfjs-node")); const root = tslib_1.__importStar(require("app-root-path")); const common_1 = require("../../common"); /** * Represents a TensorBoard output file to which we can write. */ class TensorBoardOutput { constructor(runName, options, logger) { this.runName = runName; this.options = options; this.logger = logger; this.resultsPath = root.resolve(path.join("results", runName)); common_1.mkdirp(this.resultsPath); this.summaryFileWriter = tf.node.summaryFileWriter(this.resultsPath); } /** Writes data distrbution to summary file*/ writeDataVisualization(dataDistibution) { this.summaryFileWriter.histogram("Data Distribution: # of clients per # of samples", dataDistibution.sum(1), 0, undefined, "Buckets number of clients by number of samples that they hold."); const unstacker = (data, boardName, description) => { tf.unstack(data).forEach((perClient, i) => { perClient.dataSync().forEach((perLabel, j) => { this.summaryFileWriter.histogram(boardName, tf.ones([perLabel]).mul(j), i, undefined, description); }); }); }; unstacker(dataDistibution, "Data Distribution: Per client(y) by label(x)", "Describes how many samples of each labels a client has."); unstacker(dataDistibution.transpose(), "Data Distribution: Per label(y) by client(x)", "Describes how a label is distributed across clients."); } /** Write the graphs showing evaluation results. */ writeEvaluationResults(results) { // Loss graphs: this.summaryFileWriter.scalar("Global test loss (by round number)", results.loss, results.round.roundNumber); // Accuracy graphs: this.summaryFileWriter.scalar("Global test accuracy (by round number)", results.accuracy, results.round.roundNumber); this.summaryFileWriter.scalar("Global test accuracy (by wall-clock time in ms since all clients connected)", results.accuracy, results.round.timeSinceStart); this.summaryFileWriter.scalar("Global test accuracy (by number of epochs)", results.accuracy, results.round.numberEpochs); this.summaryFileWriter.scalar("Global test accuracy (by number of uploads)", results.accuracy, results.round.numberUploads); this.summaryFileWriter.flush(); this.logger.info(`wrote evaluation of round ${results.round.roundNumber}`); } /** * Write the graphs that can be written from a round summary without * evaluating the results. * * @see {@link Coordinator.evaluate} for the graphs that result from evaluation */ writeRoundSummary(summary) { this.summaryFileWriter.scalar("Number of clients training at round end", summary.numberClientsTraining, summary.roundNumber); // Instrumentation graphs: const stalenessCounts = summary.instrumentation?.stalenessCounts; if (stalenessCounts !== undefined) { assert.strictEqual(this.options.instrument?.uploadStaleness, true); this.writeStalenessGraph(stalenessCounts, summary.roundNumber); } else { assert(!this.options.instrument?.uploadStaleness); } const memory = summary.instrumentation?.memory; if (memory !== undefined) { assert.strictEqual(this.options.instrument?.memoryUsage, true); this.summaryFileWriter.scalar("RSS (in MB) by round number", memory.node.rss / 1024 / 1024, summary.roundNumber); this.summaryFileWriter.scalar("Number of TensorFlow tensors by round number", memory.tf.numTensors, summary.roundNumber); } else { assert(!this.options.instrument?.memoryUsage); } } writeStalenessGraph(stalenessCounts, round) { const entries = Object.entries(stalenessCounts); if (entries.length === 0) { return; } tf.tidy(() => { const data = tf.concat(entries.map(([staleness, count]) => tf.ones([count]).mul(Number.parseInt(staleness)))); const name = `Staleness of ${this.runName}`; this.summaryFileWriter.histogram(name, data, round, entries.length); }); } } exports.TensorBoardOutput = TensorBoardOutput; //# sourceMappingURL=TensorBoardOutput.js.map