B
    #=6\Y                 @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlmZmZ ddlmZ ddlmZ ejd  dkrd dlZnd dlZd dlZdZedjZedjZed	jZd
ZdZdZG dd de Z!edd Z"g Z#dd Z$dd Z%dd Z&dd Z'dd Z(dd Z)e$de%e' e$de&e) dd  Z*d!d" Z+d#d$ Z,d%d& Z-d'd( Z.d)d* Z/d+d, Z0d-d. Z1eefd/d0Z2d1d2 Z3defd3d4Z4d5d6 Z5dS )7    N)closingcontextmanager   )_import_dotted_name)string_classes   z=lz=iz=hl   l|9QC
 i  ,c               @   s   e Zd ZdS )SourceChangeWarningN)__name__
__module____qualname__ r   r   6/tmp/pip-install-l3r2oljg/torch/torch/serialization.pyr	       s   r	   c              c   s   t  } | V  t|  d S )N)tempfilemkdtempshutilrmtree)pathr   r   r   r   $   s    r   c             C   s    | ||f}t | t   d S )N)_package_registryappendsort)prioritytaggerZdeserializerZ
queue_elemr   r   r   register_package.   s    

r   c             C   s   t | jdkrdS d S )Ntorchcpu)typer   )objr   r   r   _cpu_tag4   s    r   c             C   s"   t | jdkrdt|   S d S )Nz
torch.cudazcuda:)r   r   strZ
get_device)r   r   r   r   	_cuda_tag9   s    r    c             C   s   |dkr| S d S )Nr   r   )r   locationr   r   r   _cpu_deserialize>   s    r"   c             C   s   t | tjrt| } t | ts&td| dd  dkr<d}ntt| dd  d}tj	 sdt
d|tj krt
d|tj |S )Nz+location should be a string or torch.device    r   zAttempting to deserialize object on a CUDA device but torch.cuda.is_available() is False. If you are running on a CPU-only machine, please use torch.load with map_location='cpu' to map your storages to the CPU.zAttempting to deserialize object on CUDA device {} but torch.cuda.device_count() is {}. Please use torch.load with map_location to map your storages to an existing device.)
isinstancer   devicer   _string_classes
ValueErrormaxintcudaZis_availableRuntimeErrorZdevice_countformat)r!   r&   r   r   r   validate_cuda_deviceC   s    

r.   c             C   s    | drt|}| |S d S )Nr+   )
startswithr.   r+   )r   r!   r&   r   r   r   _cuda_deserialize\   s    
r0   
      c             C   s:   x"t D ]\}}}|| }|r|S qW tdt|  d S )Nz-don't know how to determine data location of )r   r,   r   typename)storage_r   r!   r   r   r   location_tagf   s    r6   c             C   sL   x(t D ] \}}}|| |}|d k	r|S qW tdt|  d | d d S )Nz+don't know how to restore data location of z (tagged with ))r   r,   r   r3   )r4   r!   r5   fnresultr   r   r   default_restore_locationo   s    
r:   c             C   s   t t| jS )N)getattrr   r
   )storage_typer   r   r   normalize_storage_typey   s    r=   c             C   s&   t | }t|j}t||jddS )NZStorageZTensor)r   r   r   r;   r
   replace)r4   r<   moduler   r   r   storage_to_tensor_type}   s    
r@   c             C   sj   d}t | ts@tjd dkr&t | ts@tjd dkrNt | tjrNd}t| |} z|| S |rd|   X dS )zq
    Executes a body function with a file object for f, opening
    it in 'mode' if it is a string filename.
    Fr   r      TN)	r%   r   sysversion_infounicodepathlibPathopenclose)fmodebodynew_fdr   r   r   _with_file_like   s    

rM   c             C   s*   dg}y
| j |kS  tk
r$   dS X d S )NgzipF)r   AttributeError)rI   Zcompress_modulesr   r   r   _is_compressed_file   s
    
rP   c             C   sF   t | rdS y|  dkS  tjk
r.   dS  tk
r@   dS X dS )z
    Checks if f is a file that should be read directly. It should be read
    directly if it is backed by a real file (has a fileno) and is not a
    a compressed file (e.g. gzip)
    Fr   N)rP   filenoioUnsupportedOperationrO   )rI   r   r   r   _should_read_directly   s    rT   c          
   C   sV   dd }y|  |   dS  tjtfk
rP } z|ddg| W d d }~X Y nX d S )Nc             S   sB   x8| D ]0}|t |krt |d d d }t||qW |d S )Nz7. You can only torch.load from a file that is seekable.z; Please pre-load the data into a buffer like io.BytesIO andz try to load from it instead.)r   r   )patternsepmsgr   r   r   raise_err_msg   s    
z&_check_seekable.<locals>.raise_err_msgTseektell)rZ   r[   rR   rS   rO   )rI   rY   rV   r   r   r   _check_seekable   s    	r\   c                s   t |d fddS )a  Saves an object to a disk file.

    See also: :ref:`recommend-saving-models`

    Args:
        obj: saved object
        f: a file-like object (has to implement write and flush) or a string
           containing a file name
        pickle_module: module used for pickling metadata and objects
        pickle_protocol: can be specified to override the default protocol

    .. warning::
        If you are using Python 2, torch.save does NOT support StringIO.StringIO
        as a valid file-like object. This is because the write method should return
        the number of bytes written; StringIO.write() does not do this.

        Please use something like io.BytesIO instead.

    Example:
        >>> # Save to file
        >>> x = torch.tensor([0, 1, 2, 3, 4])
        >>> torch.save(x, 'tensor.pt')
        >>> # Save to io.BytesIO buffer
        >>> buffer = io.BytesIO()
        >>> torch.save(x, buffer)
    wbc                s   t  | S )N)_save)rI   )r   pickle_modulepickle_protocolr   r   <lambda>   s    zsave.<locals>.<lambda>)rM   )r   rI   r_   r`   r   )r   r_   r`   r   save   s    rb   c                s  t jd dkr.dd l}t||jr.d}t|dd lm  i i  fdd}ttt j	dktt
ttdd}|jt||d	 |jt||d	 |j|||d	 |j||d	}||_||  t }	|j|	||d	 |  x |	D ]}
|
 |t| qW d S )
Nr   r   ztorch.save received unsupported StringIO.StringIO file object, whose write method does not return the number of bytes written. Please use something like io.BytesIO for torch.save instead.c       	         s   t | trt|  jr| kr"d S d| < d  }}yt| }t| }W n( tk
rr   t	d| j
 d  Y nX d| ||fS t| rtt| }d}t| j}t| }| |< | j| jk}|rt| j||  f}nd }d||||  |fS d S )NTz4Couldn't retrieve source code for container of type z3. It won't be checked for correctness upon loading.r?   r   r4   )r%   r   
issubclassModuleinspectgetsourcefile	getsource	Exceptionwarningswarnr
   r   Z
is_storager=   r   Z_cdatar6   size)	r   source_filesourcer<   offsetZobj_keyr!   Zis_viewview_metadata)nnserialized_container_typesserialized_storagesr   r   persistent_id   s:    


z_save.<locals>.persistent_idlittle)shortr*   long)protocol_versionZlittle_endianZ
type_sizes)protocol)rB   rC   StringIOr%   r,   Ztorch.nnrp   dictPROTOCOL_VERSION	byteorder
SHORT_SIZEINT_SIZE	LONG_SIZEdumpMAGIC_NUMBERPicklerrs   sortedkeysflushZ_write_filerT   )r   rI   r_   r`   ry   rX   rs   Zsys_infoZpicklerZserialized_storage_keyskeyr   )rp   rq   rr   r   r^      s6    *

r^   c             K   sr   d}t | ts@tjd dkr&t | ts@tjd dkrNt | tjrNd}t| d} zt| ||f|S |rl| 	  X dS )a9  Loads an object saved with :func:`torch.save` from a file.

    :meth:`torch.load` uses Python's unpickling facilities but treats storages,
    which underlie tensors, specially. They are first deserialized on the
    CPU and are then moved to the device they were saved from. If this fails
    (e.g. because the run time system doesn't have certain devices), an exception
    is raised. However, storages can be dynamically remapped to an alternative
    set of devices using the `map_location` argument.

    If `map_location` is a callable, it will be called once for each serialized
    storage with two arguments: storage and location. The storage argument
    will be the initial deserialization of the storage, residing on the CPU.
    Each serialized storage has a location tag associated with it which
    identifies the device it was saved from, and this tag is the second
    argument passed to map_location. The builtin location tags are `'cpu'` for
    CPU tensors and `'cuda:device_id'` (e.g. `'cuda:2'`) for CUDA tensors.
    `map_location` should return either None or a storage. If `map_location` returns
    a storage, it will be used as the final deserialized object, already moved to
    the right device. Otherwise, :math:`torch.load` will fall back to the default
    behavior, as if `map_location` wasn't specified.

    If `map_location` is a string, it should be a device tag, where all tensors
    should be loaded.

    Otherwise, if `map_location` is a dict, it will be used to remap location tags
    appearing in the file (keys), to ones that specify where to put the
    storages (values).

    User extensions can register their own location tags and tagging and
    deserialization methods using `register_package`.

    Args:
        f: a file-like object (has to implement read, readline, tell, and seek),
            or a string containing a file name
        map_location: a function, torch.device, string or a dict specifying how to remap storage
            locations
        pickle_module: module used for unpickling metadata and objects (has to
            match the pickle_module used to serialize file)
        pickle_load_args: optional keyword arguments passed over to
            ``pickle_module.load`` and ``pickle_module.Unpickler``, e.g.,
            ``encoding=...``.

    .. note::
        When you call :meth:`torch.load()` on a file which contains GPU tensors, those tensors
        will be loaded to GPU by default. You can call `torch.load(.., map_location='cpu')`
        and then :meth:`load_state_dict` to avoid GPU RAM surge when loading a model checkpoint.

    .. note::
        In Python 3, when loading files saved by Python 2, you may encounter
        ``UnicodeDecodeError: 'ascii' codec can't decode byte 0x...``. This is
        caused by the difference of handling in byte strings in Python2 and
        Python 3. You may use extra ``encoding`` keyword argument to specify how
        these objects should be loaded, e.g., ``encoding='latin1'`` decodes them
        to strings using ``latin1`` encoding, and ``encoding='bytes'`` keeps them
        as byte arrays which can be decoded later with ``byte_array.decode(...)``.

    Example:
        >>> torch.load('tensors.pt')
        # Load all tensors onto the CPU
        >>> torch.load('tensors.pt', map_location=torch.device('cpu'))
        # Load all tensors onto the CPU, using a function
        >>> torch.load('tensors.pt', map_location=lambda storage, loc: storage)
        # Load all tensors onto GPU 1
        >>> torch.load('tensors.pt', map_location=lambda storage, loc: storage.cuda(1))
        # Map tensors from GPU 1 to GPU 0
        >>> torch.load('tensors.pt', map_location={'cuda:1':'cuda:0'})
        # Load tensor from io.BytesIO object
        >>> with open('tensor.pt') as f:
                buffer = io.BytesIO(f.read())
        >>> torch.load(buffer)
    Fr   r   rA   TrbN)
r%   r   rB   rC   rD   rE   rF   rG   _loadrH   )rI   map_locationr_   pickle_load_argsrL   r   r   r   load,  s    H

r   c                s  i d krt nVttr*fddn>ttrBfddn&ttjr\fddnfdddd   fdd	}i d
d  fdd}t|  t| }|r|  dkry|| S  t	j
k
r   | d Y nX j| f}|tkr
tdj| f}|tkr.td| j| f}	j| f}
||
_|
 }j| f}|rt|  nd }x2|D ]*}|kst| | || d }q~W |S )Nc                s     ||}t| |S )N)getr:   )r4   r!   )r   r   r   restore_location  s    z_load.<locals>.restore_locationc                s
   t |  S )N)r:   )r4   r!   )r   r   r   r     s    c                s   t | t S )N)r:   r   )r4   r!   )r   r   r   r     s    c                s     | |}|d krt | |}|S )N)r:   )r4   r!   r9   )r   r   r   r     s    

c       
   	   S   s>  yt | }W n( tk
r6   td| j d  d S X ||kr:| jr| jd }tj|	d|	d||dd}d
|}ytt|dL}|dd	}|d |dkr|| n|t|ks| |krtW d Q R X d
| d | d }	W n" tk
r   d| d }	Y nX nd}	dt| |	}	t|	t d S )Nz4Couldn't retrieve source code for container of type z3. It won't be checked for correctness upon loading.z.patch
r$   )Zlinetermza+r   r   zSaved a reverse patch to z. Run `patch -p0 < z` to revert your changes.z;Tried to save a patch, but couldn't create a writable file zD. Make sure it doesn't exist and your working directory is writable.zyou can retrieve the original source code by accessing the object's source attribute or set `torch.nn.Module.dump_patches = True` and use the patch tool to revert the changes.z)source code of class '{}' has changed. {})re   rg   rh   ri   rj   r
   Zdump_patchesdifflibZunified_diffsplitjoinrG   rZ   writelenreadIOErrorr-   r   r3   r	   )
Zcontainer_typerl   Zoriginal_sourceZcurrent_source	file_nameZdifflinesrI   	file_sizerX   r   r   r   _check_container_source  s:    




z&_load.<locals>._check_container_sourcec                s6  i   fdd}t tj| dtjd}t }|jd|d ttj|ddd} j	| f}xDt
|D ]8}j	| f}|\}}}	|	| }
|
|}
|
 |< qtW j	| f}x0|D ](\}}}} | }||||   |< qW W d Q R X |jd	|d ttj|d	dd} j	| f}xt
|D ]}j	| f}|\}}} | }t|}td
| d\}| d td|| d| }td|| d| }td| d\}| ||||}| |< q8W W d Q R X |d}j|f}||_|	 }|S Q R X W d Q R X d S )Nc                s6   t | tr*t| dd  r" |   | d S t|  S )Nr   r   )r%   tupleallr*   )saved_id)r   deserialized_objectsr   r   persistent_load  s
    
z3_load.<locals>.legacy_load.<locals>.persistent_loadzr:)fileobjrJ   r-   Zstorages)r   r   r   Ztensorsz<i   z<{}q   z<qpickle)r   tarfilerG   
PAX_FORMATr   extractosr   r   r   rangeZ_new_with_filer@   structunpackr   r-   set_extractfile	Unpicklerr   )rI   r   tarZtmpdirZnum_storagesiargsr   r!   r<   r   Zstorage_viewsZtarget_cdataZ
root_cdatarn   rk   rootZnum_tensorsr5   Z
storage_idZoriginal_tensor_typer4   Ztensor_typendimZstrideZstorage_offsetZtensorZpickle_file	unpicklerr9   )r   r   r_   r   )r   r   legacy_load  sJ    



"


z_load.<locals>.legacy_loadc             S   s   t | tr| dS | S )Nascii)r%   bytesdecode)Z	bytes_strr   r   r   maybe_decode_ascii  s    

z!_load.<locals>.maybe_decode_asciic                s   t | tst| d }| dd  }|dkrNt|dd  rF |  |d S |dkr|\}}}}}|}|kr||||< | }|d k	r|\}	}
}|	kr||
|
|  |	< |	 S |S ntd| d  d S )Nr   r   r?   r4   zUnknown saved id type: %s)r%   r   AssertionErrorr   r,   )r   r3   dataZ	data_typeZroot_keyr!   rk   ro   r4   Zview_keyrn   Z	view_size)r   r   r   r   r   r   r     s*    
z_load.<locals>.persistent_loadr   z#Invalid magic number; corrupt file?zInvalid protocol version: %s)r:   r%   rz   r'   r   r&   r\   rT   r[   r   TarErrorrZ   r   r   r,   r{   r   r   r   Z_set_from_file)rI   r   r_   r   r   r   Zf_should_read_directlyZmagic_numberrw   Z	_sys_infor   r9   Zdeserialized_storage_keysrn   r   r   )r   r   r   r   r   r_   r   r   r     sN    

)4



r   )6r   re   r   rR   r   r   rB   r   r   r   ri   
contextlibr   r   _utilsr   Z_sixr   r'   rC   cPickler   rE   DEFAULT_PROTOCOLStructrk   r   r~   r}   r   r{   ZSTORAGE_KEY_SEPARATORWarningr	   r   r   r   r   r    r"   r.   r0   r6   r:   r=   r@   rM   rP   rT   r\   rb   r^   r   r   r   r   r   r   <module>   s^   
	
OU