Cómo convertir tensorflow. js pesos modelo para pytorch tensors, y atrás?

Estoy usando ml5.jsUn envoltorio alrededor de tensorflowjs. Quiero entrenar una red neuronal en el navegador, descargar los pesos, procesarlos como tensores en pyTorch, y cargarlos de nuevo en el modelo tensorflowjs del navegador. Cómo puedo convertir entre estos formatos tfjs <-> pytorch?

El modelo del navegador tiene un save() función que genera tres archivos. Un archivo de metadatos específico a ml5.js (json), un archivo de topología que describe la arquitectura modelo (json), y un archivo de pesos binarios (bin).

// Browser
model.save()
// HTTP/Download
model_meta.json   (needed by ml5.js)
model.json        (needed by tfjs)
model.weights.bin (needed by tfjs)
# python backend
import json

with open('model.weights.bin', 'rb') as weights_file:
    with open('model.json', 'rb') as model_file:
        weights = weights_file.read()
        model = json.loads(model_file.read())
        ####
        pytorch_tensor = convert2tensor(weights, model) # whats in this function?
        ####
        # Do some processing in pytorch

        ####
        new_weights_bin = convert2bin(pytorch_tensor, model) # and in this?
        ####

Aquí está la muestra código de javascript para generar y cargar los 3 archivos en el navegador. Para cargar, seleccione los 3 archivos a la vez en el cuadro de diálogo. Si son correctos, un popup mostrará una predicción de muestra.

Pregunta hecha hace 3 años, 4 meses, 29 días - Por scriptsculptor


3 Respuestas:

  • Fui capaz de encontrar una manera de convertir de tfjs model.weights.bin a numpy ndarrays. Es trivial convertir de arrays numpy a pitorch state_dict que es un diccionario de tensores y sus nombres.

    Teoría

    En primer lugar, debe entenderse la representación tfjs del modelo. model.json describe el modelo. En pitón, se puede leer como diccionario. Tiene las siguientes llaves:

    1. La arquitectura modelo se describe como otro json / diccionario bajo la clave modelTopology.

    2. También tiene un json / diccionario bajo la llave weightsManifest que describe el tipo/forma/ubicación de cada peso envuelto en el correspondiente model.weights.bin archivo. Como un lado, el manifiesto de pesos permite múltiples .bin archivos para almacenar pesos.

    Tensorflow.js tiene un paquete de pitón compañero tensorflowjs, que viene con funciones de utilidad a leído y escribir pesos entre el formato tf.js binario y numpy array.

    Cada archivo de peso se lee como un "grupo". Un grupo es una lista de diccionarios con llaves name y data que se refieren al nombre de peso y la matriz numposa que contiene pesos. También hay otras llaves.

    group = [{'name': weight_name, 'data': np.ndarray}, ...]   # 1 *.bin file
    

    Aplicación

    Instala tensorflowjs. Desafortunadamente, también instalará tensorflow.

    pip install tensorflowjs
    

    Utilice estas funciones. Tenga en cuenta que he cambiado las firmas para mayor comodidad.

    from typing import Dict, ByteString
    import torch
    from tensorflowjs.read_weights import decode_weights
    from tensorflowjs.write_weights import write_weights
    
    def convert2tensor(weights: ByteString, model: Dict) -> Dict[str, torch.Tensor]:
        manifest = model['weightsManifest']
        # If flatten=False, returns a list of groups equal to the number of .bin files.
        # Use flatten=True to convert to a single group
        group = decode_weights(manifest, weights, flatten=True)
        # Convert dicts in tfjs group format into pytorch's state_dict format:
        # {name: str, data: ndarray} -> {name: tensor}
        state_dict = {d['name']: torch.from_numpy(d['data']) for d in group}
        return state_dict
    
    def convert2bin(state_dict: Dict[str: np.ndarray], model: Dict, directory='./'):
        # convert state_dict to groups (list of 1 group)
        groups = [[{'name': key, 'data': value} for key, value in state_dict.items()]]
        # this library function will write to .bin file[s], but you can read it back
        # or change the function internals my copying them from source
        write_weights(groups, directory, write_manifest=False)
    

    Respondida el Dec 18, 2020 a las 02:25 - por algoarchitect

    Votos positivos: 0 | Votos negativos: 0

  • Para convertir los pesos del modelo de TensorFlow.js a tensores de PyTorch y viceversa, necesitarás realizar un proceso de conversión de los formatos de los datos. Aquí te dejo un ejemplo de cómo podrías hacerlo:

    • Convertir los pesos del modelo de TensorFlow.js a tensores de PyTorch:
    python
    import torch
    import json
    import numpy as np
    
    

    Leer los archivos de pesos binarios y el archivo de modelo json

    with open('model.weights.bin', 'rb') as weights_file: with open('model.json', 'r') as model_file: weights = weights_file.read() model = json.load(model_file)

    Convertir los pesos binarios a tensores de PyTorch

    Aquí asumimos que los pesos son arrays numpy serializados

    weights_np = np.frombuffer(weights, dtype=np.float32) weights_tensor = torch.tensor(weights_np)

    Procesar los tensores en PyTorch como deseado

    Guardar el tensor PyTorch

    torch.save(weights_tensor, 'pytorch_weights.pth')
    • Convertir los tensores de PyTorch de vuelta a los pesos del modelo de TensorFlow.js:
    python
    import torch
    import json
    import numpy as np
    
    

    Cargar los tensores de PyTorch

    weights_tensor = torch.load('pytorch_weights.pth')

    Convertir el tensor de PyTorch a un array numpy

    weights_np = weights_tensor.numpy()

    Serializar el array numpy de nuevo a formato binario

    weights_bin = weights_np.tobytes()

    Escribir los pesos binarios a un archivo

    with open('new_model.weights.bin', 'wb') as new_weights_file: new_weights_file.write(weights_bin)

    Con estos fragmentos de código, deberías poder convertir los pesos del modelo entre TensorFlow.js y PyTorch. Ten en cuenta que en la función convert2tensor y convert2bin tendrás que implementar la lógica específica para tu caso de uso, basándote en cómo están estructurados los pesos en cada modelo.

    Respondida el Dec 19, 2020 a las 02:25 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Convertir desde TensorFlow.js pesos a PyTorch tensores

    python
    import numpy as np
    import json
    
    def convert2tensor(weights_bin, model):
        

    Leer pesos binarios en un objeto Numpy array

    weights_np = np.frombuffer(weights_bin, dtype=np.float32)

    Obtener la topología del modelo

    model_layers = model['layers']

    Iterar sobre las capas del modelo y convertir pesos a tensores PyTorch

    pytorch_tensors = [] for layer in model_layers: type = layer['class_name'] if type == 'Conv2D':

    Obtener pesos de convolución

    kernel = np.transpose(weights_np[:layer['config']['filters'], :layer['config']['kernel_size'][0], :layer['config']['kernel_size'][1], :layer['config']['filters']], (3, 2, 1, 0)) bias = weights_np[layer['config']['filters']:, :layer['config']['filters']]

    Convertir a tensor PyTorch

    pytorch_tensors.append(torch.nn.Conv2d(layer['config']['filters'], layer['config']['filters'], kernel.shape[1:])) pytorch_tensors[-1].weight = torch.nn.Parameter(torch.from_numpy(kernel)) pytorch_tensors[-1].bias = torch.nn.Parameter(torch.from_numpy(bias)) weights_np = weights_np[layer['config']['filters']:, layer['config']['filters']:] elif type == 'Dense':

    Obtener pesos de capa densa

    kernel = weights_np[:layer['config']['units'], :] bias = weights_np[layer['config']['units']:, :]

    Convertir a tensor PyTorch

    pytorch_tensors.append(torch.nn.Linear(layer['config']['units'], layer['config']['units'])) pytorch_tensors[-1].weight = torch.nn.Parameter(torch.from_numpy(kernel)) pytorch_tensors[-1].bias = torch.nn.Parameter(torch.from_numpy(bias)) weights_np = weights_np[layer['config']['units']:, layer['config']['units']:] return pytorch_tensors

    Convertir desde PyTorch tensores a TensorFlow.js pesos

    python
    def convert2bin(pytorch_tensor, model):
        

    Obtener la topología del modelo

    model_layers = model['layers']

    Crear lista de pesos binarios

    weights_bin = [] for layer, pytorch_tensor in zip(model_layers, pytorch_tensor): if layer['class_name'] == 'Conv2D':

    Obtener pesos y sesgos de convolución

    kernel = pytorch_tensor.weight.numpy().transpose((3, 2, 1, 0)) bias = pytorch_tensor.bias.numpy()

    Añadir a la lista de pesos binarios

    weights_bin.extend(kernel.reshape(-1)) weights_bin.extend(bias.reshape(-1)) elif layer['class_name'] == 'Dense':

    Obtener pesos y sesgos de capa densa

    kernel = pytorch_tensor.weight.numpy() bias = pytorch_tensor.bias.numpy()

    Añadir a la lista de pesos binarios

    weights_bin.extend(kernel.reshape(-1)) weights_bin.extend(bias.reshape(-1)) return np.array(weights_bin, dtype=np.float32).tobytes()

    Respondida el Dec 19, 2020 a las 02:34 - por Gemini

    Votos positivos: 0 | Votos negativos: 0