federer
Version:
Experiments in asynchronous federated learning and decentralized learning
134 lines • 5.76 kB
TypeScript
/// <reference types="node" />
import * as http from "http";
import * as https from "https";
import * as io from "socket.io";
import { Logger } from "winston";
import { ClientToServerMessages, DownloadMessage, MetadataMessage, RoundSummary, SerializedWeights, ServerToClientMessages, Weights, ServerStartCommonOptions } from "../common";
import { ClientPool } from "./utils/ClientPool";
import { Instrumentation } from "./utils/Instrumentation";
/** Base interface for round states in an FL algorithm. */
export interface FLRoundState {
/**
* The current round number.
*
* All implementations need to advance in rounds. This is necessary for our
* evaluation and visualization features.
*/
roundNumber: number;
}
/** Mapping of event names to event listener callback types. */
export interface FLServerEvents {
/** When the round ends, a summary of what happened in the round. */
roundEnd: (summary: RoundSummary) => void;
}
/**
* Abstract base class for a Federated Learning aggregation server.
*
* This abstract class defines the basic interface that all servers should
* respect; most notably, servers should expose an event emitter that informs
* code outside of this class of certain server events.
*
* The class also does some basic bookkeeping. For instance, it maintains
* metadata that clients have sent when authenticating, as well as the set of
* clients that are ready to train, and some statistics on how the FL process is
* advancing.
*
* Finally, the class offers a few utility methods that subclasses can use.
*/
export declare abstract class FLServer<RoundState extends FLRoundState = FLRoundState, StartOptions extends ServerStartCommonOptions = ServerStartCommonOptions> {
protected readonly options: StartOptions;
protected readonly logger: Logger;
/** socket.io server used for communicating with clients. */
protected readonly server: io.Server<ClientToServerMessages, ServerToClientMessages>;
/** Event emitter notifying outside code of FL events. */
readonly events: import("nanoevents").Emitter<FLServerEvents>;
/** Current round state. */
protected currentRound: RoundState;
/**
* Mapping of socket IDs to metadata about the client represented by this
* socket ID.
*
* The metadata is collected from the clients, which send it through socket.io
* when connecting to the server. Note that clients are not considered "ready"
* for training until they have sent their metadata.
*/
private readonly clientsMetadata;
/** Client pool, keeping track of ready clients. */
protected readonly clientPool: ClientPool;
/** Timer used for round summaries. */
private readonly timer;
/** Number of epochs that have been aggregated so far */
private numberEpochs;
/** Number of upload messages received so far. */
private numberUploads;
/** Helper class to instrument various metrics on the server. */
protected readonly instrumentation: Instrumentation;
constructor(server: http.Server | https.Server, initialWeights: Weights, options: StartOptions, logger: Logger);
terminate(): void;
/**
* Whether the FL server implementation expects clients to upload with updates
* as full weights (`false`) or as deltas of the change (`true`).
*
* If a client declares that it will upload the opposite of what the server
* expects, an assertion error will be thrown on the server.
*/
protected abstract readonly expectDeltaUpdates: boolean;
/**
* Returns the initial round state at round 0.
*
* @param initialWeights Weights to initialize the state with
*/
protected abstract getInitialRoundState(initialWeights: Weights): RoundState;
/**
* Registers listeners to react to events on `this.server`.
*
* Subclasses are not meant to call this method (doing so could register
* listeners twice), so this is marked as private.
*/
private registerServerListeners;
/**
* Registers listeners to react to events on the given `socket`.
*
* Subclasses overriding this method should first call
* `super.registerSocketListeners(socket)`.
*
* @param socket Socket to a client
*/
protected registerSocketListeners(socket: io.Socket<ClientToServerMessages, ServerToClientMessages>): void;
/** Number of currently connected and ready clients. */
protected get numberClients(): number;
/**
* Readonly map of socket IDs to the metadata we keep about this node.
*/
protected get metadata(): ReadonlyMap<string, Readonly<MetadataMessage>>;
private registerMetadata;
private logDisconnect;
/**
* Gets the client metadata for a socket, or fails if we do not have metadata
* for that socket.
*/
protected getMetadata(socketId: string): Readonly<MetadataMessage>;
/**
* Returns the socket with ID `id`.
* @throws if no socket with ID `id` is connected
*/
protected getSocketWithID(id: string): io.Socket;
/**
* Sends a {@link DownloadMessage} to a list of clients
*
* @param clients List of clients to send to
*/
protected sendDownloadMessage(clients: io.Socket[], message: DownloadMessage): void;
/**
* Emit the round summary to the coordinator.
*/
protected emitRoundSummary(filename: string, finishedRoundNumber: number, serializedWeights: SerializedWeights): void;
private createRoundSummary;
/**
* Given a unique name for the weights, returns the full filepath to save
* weights to.
*/
protected weightsFilepath(name: string): string;
private shouldStartTimer;
}
//# sourceMappingURL=FLServer.d.ts.map