1
votes

numpy.load du flux io.BytesIO

J'ai des tableaux numpy enregistrés dans Azure Blob Storage et je les charge dans un flux comme celui-ci:

b"\x93NUMPY\x01\x00v\x00{'descr': '|u1', 'fortran_order': False, 'shape': (720, 1280, 3), }                                                  \n\xc1\xb0\x94\xc2\xb1\x95\xc3\xb2\x96\xc4\xb3\x97\xc5\xb4\x98\xc6\xb5\x99\xc7\xb6\x9a\xc7"

Je sais grâce à stream.getvalue () code > que le flux contient les métadonnées pour reconstruire le tableau. Voici les 150 premiers octets:

stream = io.BytesIO()
store.get_blob_to_stream(container, 'cat.npy', stream)

Est-il possible de charger le flux d'octets avec numpy.load ou par une autre méthode simple? p>

Je pourrais plutôt sauvegarder le tableau sur le disque et le charger à partir du disque, mais j'aimerais éviter cela pour plusieurs raisons ...

EDIT: juste pour souligner, la sortie aurait besoin être un tableau numpy avec la forme et le type spécifiés dans les 128 premiers octets du flux.


4 commentaires

Si vous l'avez enregistré sur disque, comment le chargeriez-vous?


@hpaulj par numpy.load ()


load accepte un fichier ouvert comme un objet.


ok ouais ne pouvait pas faire fonctionner ça ...


3 Réponses :


2
votes

J'ai essayé d'utiliser plusieurs méthodes pour répondre à vos besoins.

Voici mes exemples de codes.

ds = np.DataSource()
# ds = np.DataSource(None)  # use with temporary file
# ds = np.DataSource(path) # use with path like `data/`
f = ds.open(url_with_sas)
dat = np.fromfile(f)
print('from DataSource', dat)

Exemple 1. Pour générer une URL blob avec le jeton sas à obtenir le contenu via requests

import io
stream = io.BytesIO()
blob_service.get_blob_to_stream(container_name, blob_name, stream)
dat = np.frombuffer(stream.getbuffer())
print('from BytesIO', dat)

Exemple 2. Pour télécharger le contenu du blob en mémoire via BytesIO p >

from azure.storage.blob import BlobPermissions
from datetime import datetime, timedelta
import requests

sas_token = blob_service.generate_blob_shared_access_signature(container_name, blob_name, permission=BlobPermissions.READ, expiry=datetime.utcnow() + timedelta(hours=1))
print(sas_token)
url_with_sas = blob_service.make_blob_url(container_name, blob_name, sas_token=sas_token)
print(url_with_sas)

r = requests.get(url_with_sas)
dat = np.frombuffer(r.content)
print('from requests', dat)

Exemple 3. Utilisez numpy.fromfile avec DataSource pour ouvrir une URL blob avec un jeton sas, il téléchargera en fait le fichier blob dans le système de fichiers local.

from azure.storage.blob.baseblobservice import BaseBlobService
import numpy as np

account_name = '<your account name>'
account_key = '<your account key>'
container_name = '<your container name>'
blob_name = '<your blob name>'

blob_service = BaseBlobService(
    account_name=account_name,
    account_key=account_key
)

Je pense que les échantillons 1 et 2 sont meilleurs pour vous.


1 commentaires

Hé merci beaucoup pour la réponse, mais j'imagine que j'ai oublié de souligner que j'aurais spécifiquement besoin d'un tableau numpy avec la forme et le dtype comme dans le stream.getvalue () 128 premiers octets ... < code> np.frombuffer (stream.read ()) fonctionnerait bien!



1
votes

C'est un peu une manière piratée que j'ai inventée, qui récupère simplement les métadonnées des 128 premiers octets:

def load_npy_from_stream(stream_):
    """Experimental, may not work!

    :param stream_: io.BytesIO() object obtained by e.g. calling BlockBlobService().get_blob_to_stream() containing
        the binary stream of a standard format .npy file.
    :return: numpy.ndarray
    """
    stream_.seek(0)
    prefix_ = stream_.read(128)  # first 128 bytes seem to be the metadata
    dict_string = re.search('\{(.*?)\}', prefix_[1:].decode())[0]
    metadata_dict = eval(dict_string)

    array = np.frombuffer(stream_.read(), dtype=metadata_dict['descr']).reshape(metadata_dict['shape'])

    return array

Peut échouer de nombreuses manières, mais je poste ici si quelqu'un veut essayer. Je vais faire des tests avec ceci et j'y reviendrai au fur et à mesure que j'en saurai plus.


0 commentaires

2
votes

En ce qui concerne np.savez, la solution ci-dessus veut normalement fonctionner.

Télécharger vers le stockage:

from numpy.lib.npyio import NpzFile 

stream = io.BytesIO()  
block_blob_service.get_blob_to_stream(container, "my/path.npz", stream)  

ret = NpzFile(stream, own_fid=True, allow_pickle=True)  
print(ret.files)  
""" ['A', 'B'] """  
print(ret['A'].shape)  
""" (20, 4) """  

Télécharger depuis le stockage:

import io    
import numpy as np    

stream = io.BytesIO()  
arr1 = np.random.rand(20,4)  
arr2 = np.random.rand(20,4)  
np.savez(stream, A=arr1, B=arr2)  
block_blob_service.create_blob_from_bytes(container, 
                                          "my/path.npz", 
                                          stream.getvalue())


0 commentaires