save static method

Future<void> save(
  1. Interpreter interpreter,
  2. File file
)

Saves the current model weights to file.

The interpreter must have a get_weights signature. Weights are read from the model and serialized in the .flwt binary format.

The write is atomic, a temporary file is written first, then renamed.

Implementation

static Future<void> save(Interpreter interpreter, File file) async {
  if (!interpreter.signatureKeys.contains('get_weights')) {
    throw ArgumentError('Model does not have a "get_weights" signature.');
  }

  final runner = interpreter.getSignatureRunner('get_weights');
  try {
    runner.allocateTensors();
    runner.invoke();

    final tensors = <_TensorRecord>[];
    for (final name in runner.outputNames) {
      final tensor = runner.getOutputTensor(name);
      tensors.add(
        _TensorRecord(
          name: name,
          type: tensor.type.value,
          shape: tensor.shape,
          data: Uint8List.fromList(tensor.data),
        ),
      );
    }

    final builder = BytesBuilder(copy: false);
    // Header
    builder.add(Uint8List.fromList(_magic));
    builder.addByte(_version);
    builder.add(_uint32LE(tensors.length));

    // Tensor records
    for (final t in tensors) {
      final nameBytes = utf8.encode(t.name);
      builder.add(_uint32LE(nameBytes.length));
      builder.add(Uint8List.fromList(nameBytes));
      builder.add(_int32LE(t.type));
      builder.add(_uint32LE(t.shape.length));
      for (final dim in t.shape) {
        builder.add(_int32LE(dim));
      }
      builder.add(_uint32LE(t.data.length));
      builder.add(t.data);
    }

    // Atomic write
    final tmpFile = File('${file.path}.tmp');
    await tmpFile.writeAsBytes(builder.takeBytes(), flush: true);
    await tmpFile.rename(file.path);
  } finally {
    runner.close();
  }
}