encoding.jl

FastAI/datablock/encoding.jl is a source file in module FastAI

			
			
			
			
			
			"""
			

			    abstract type Encoding

			

			Transformation of `Block`s. Can encode some `Block`s ([`encode`]), and optionally

			decode them [`decode`]

			

			## Interface

			

			- `encode(::E, ::Context, block::Block, data)` encodes `block` of `data`.

			    The default is to do nothing. This should be overloaded for an encoding `E`,

			    concrete `Block` types and possibly a context.

			- `decode(::E, ::Context, block::Block, data)` decodes `block` of `data`. This

			    should correspond as closely as possible to the inverse of `encode(::E, ...)`.

			    The default is to do nothing, as not all encodings can be reversed. This should

			    be overloaded for an encoding `E`, concrete `Block` types and possibly a context.

			- `encodedblock(::E, block::Block) -> block'` returns the block that is obtained by

			    encoding `block` with encoding `E`. This needs to be constant for an instance of `E`,

			    so it cannot depend on the sample or on randomness. The default is to return `nothing`,

			    meaning the same block is returned and not changed. Encodings that return the same

			    block but change the data (e.g. `ProjectiveTransforms`) should return `block`.

			- `decodedblock(::E, block::Block) -> block'` returns the block that is obtained by

			    decoding `block` with encoding `E`. This needs to be constant for an instance of `E`,

			    so it cannot depend on the sample or on randomness. The default is to return `nothing`,

			    meaning the same block is returned and not changed.

			- `encode!(buf, ::E, ::Context, block::Block, data)` encodes `data` inplace.

			- `decode!(buf, ::E, ::Context, block::Block, data)` decodes `data` inplace.

			

			"""
			

			
			abstract
			 
			type
			 

	
			Encoding
			 
			end
			

			

			
			
			
			"""
			

			    fillblock(inblocks, outblocks)

			

			Replaces all `nothing`s in outblocks with the corresponding block in `inblocks`.

			`outblocks` may be obtained by

			"""
			

			
			

	
			fillblock
			(
			
			inblocks
			::
			Tuple
			,
			 
			
			outblocks
			::
			Tuple
			)
			 
			=
			 
			
			map
			(

	
			fillblock
			,
			 
			inblocks
			,
			 
			outblocks
			)
			

			
			

	
			fillblock
			(
			
			inblock
			::

	
			AbstractBlock
			,
			 
			
			::
			Nothing
			)
			 
			=
			 
			inblock
			

			
			

	
			fillblock
			(
			
			inblocks
			::
			Tuple
			,
			 
			
			::
			Nothing
			)
			 
			=
			 
			inblocks
			

			
			

	
			fillblock
			(
			
			::

	
			AbstractBlock
			,
			 
			
			outblock
			::

	
			AbstractBlock
			)
			 
			=
			 
			outblock
			

			

			
			

	
			encodedblockfilled
			(
			enc
			,
			 
			block
			)
			 
			=
			 
			

	
			fillblock
			(
			block
			,
			 
			

	
			encodedblock
			(
			enc
			,
			 
			block
			)
			)
			

			
			

	
			decodedblockfilled
			(
			enc
			,
			 
			block
			)
			 
			=
			 
			

	
			fillblock
			(
			block
			,
			 
			

	
			decodedblock
			(
			enc
			,
			 
			block
			)
			)

encode methods By default an encoding doesn't change the data


			
			
			
			function
			 
			

	
			encode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			ctx
			,
			 
			
			block
			::

	
			Block
			,
			 
			obs
			
			;
			 
			
			kwargs
			...
			)
			
			
    
			
			
			isempty
			(
			kwargs
			)
			 
			?
			 
			obs
			 
			:
			 
			

	
			encode
			(
			encoding
			,
			 
			ctx
			,
			 
			block
			,
			 
			obs
			)
			

			end

By default, a tuple of encodings encodes by encoding the data one encoding after the other


			
			
			
			
			
			"""
			

			    encode(encoding, context, block, obs)

			    encode(encoding, context, blocks, obss)

			    encode(encodings, context, blocks, obss)

			

			Apply one or more [`Encoding`](#)s to observation(s) `obs`.

			"""
			

			
			function
			 
			
			

	
			encode
			(
			
			encodings
			::
			
			NTuple
			{
			N
			,
			 

	
			Encoding
			}
			,
			 
			context
			,
			 
			blocks
			,
			 
			data
			)
			 
			where
			 
			{
			N
			}
			
			
    
			
			for
			
			 
			encoding
			 
			in
			 
			encodings
			
			
        
			
			data
			 
			=
			 
			

	
			encode
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			data
			)
			
        
			
			blocks
			 
			=
			 
			

	
			encodedblockfilled
			(
			encoding
			,
			 
			blocks
			)
			
    
			end
			
    
			
			return
			 
			data
			

			end

By default, an encoding encodes every element in a tuple separately


			
			
			
			function
			 
			

	
			encode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			context
			,
			 
			
			blocks
			::
			Tuple
			,
			 
			
			obss
			::
			Tuple
			)
			
			
    
			
			@
			assert
			
			 
			
			length
			(
			blocks
			)
			 
			==
			 
			
			length
			(
			obss
			)
			
    
			
			return
			 
			
			map
			(
			
			
			(
			block
			,
			 
			obs
			)
			 
			->
			 
			

	
			encode
			(
			encoding
			,
			 
			context
			,
			 
			block
			,
			 
			obs
			)
			,
			
               
			blocks
			,
			 
			obss
			)
			

			end

Named tuples of data are handled like tuples, but the keys are preserved


			
			
			
			function
			 
			

	
			encode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			context
			,
			 
			
			blocks
			::
			NamedTuple
			,
			 
			
			obss
			::
			NamedTuple
			)
			
			
    
			
			@
			assert
			
			 
			
			length
			(
			blocks
			)
			 
			==
			 
			
			length
			(
			obss
			)
			
    
			
			return
			 
			
			NamedTuple
			(
			
			zip
			(
			
			keys
			(
			obss
			)
			,
			
                          
			

	
			encode
			(
			encoding
			,
			 
			context
			,
			 
			
			values
			(
			blocks
			)
			,
			 
			
			values
			(
			obss
			)
			)
			)
			)
			

			end

decode methods By default an encoding doesn't change the data when decoding


			
			
			
			function
			 
			

	
			decode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			ctx
			,
			 
			
			block
			::

	
			Block
			,
			 
			obs
			
			;
			 
			
			kwargs
			...
			)
			
			
    
			
			
			isempty
			(
			kwargs
			)
			 
			?
			 
			obs
			 
			:
			 
			

	
			decode
			(
			encoding
			,
			 
			ctx
			,
			 
			block
			,
			 
			obs
			)
			

			end

By default, a tuple of encodings decodes by decoding the data one encoding after the other, with encodings iterated in reverse order


			
			
			
			function
			 
			
			

	
			decode
			(
			
			encodings
			::
			
			NTuple
			{
			N
			,
			 

	
			Encoding
			}
			,
			 
			context
			,
			 
			blocks
			,
			 
			obs
			)
			 
			where
			 
			{
			N
			}
			
			
    
			
			for
			
			 
			encoding
			 
			in
			 
			
			
			Iterators
			.
			
			reverse
			(
			encodings
			)
			
			
        
			
			obs
			 
			=
			 
			

	
			decode
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			obs
			)
			
        
			
			blocks
			 
			=
			 
			

	
			decodedblockfilled
			(
			encoding
			,
			 
			blocks
			)
			
    
			end
			
    
			
			return
			 
			obs
			

			end

By default, an encoding decodes every element in a tuple separately


			
			
			
			function
			 
			

	
			decode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			context
			,
			 
			
			blocks
			::
			Tuple
			,
			 
			
			obss
			::
			Tuple
			)
			
			
    
			
			@
			assert
			
			 
			
			length
			(
			blocks
			)
			 
			==
			 
			
			length
			(
			obss
			)
			
    
			
			return
			 
			
			map
			(
			
			
			(
			block
			,
			 
			obs
			)
			 
			->
			 
			

	
			decode
			(
			encoding
			,
			 
			context
			,
			 
			block
			,
			 
			obs
			)
			,
			
               
			blocks
			,
			 
			obss
			)
			

			end

Named tuples of data are handled like tuples, and the keys are preserved


			
			
			
			function
			 
			

	
			decode
			(
			
			encoding
			::

	
			Encoding
			,
			 
			context
			,
			 
			
			blocks
			::
			NamedTuple
			,
			 
			
			obss
			::
			NamedTuple
			)
			
			
    
			
			@
			assert
			
			 
			
			length
			(
			blocks
			)
			 
			==
			 
			
			length
			(
			obss
			)
			
    
			
			return
			 
			
			NamedTuple
			(
			
			zip
			(
			
			keys
			(
			obss
			)
			,
			
                          
			

	
			decode
			(
			encoding
			,
			 
			context
			,
			 
			
			values
			(
			blocks
			)
			,
			 
			
			values
			(
			obss
			)
			)
			)
			)
			

			end
			

			

			
			
			
			"""
			

			    encodedblock(encoding, block)

			    encodedblock(encoding, blocks)

			    encodedblock(encodings, blocks)

			

			Return the block that is obtained by encoding `block` with encoding `E`.

			This needs to be constant for an instance of `E`, so it cannot depend on the

			sample or on randomness. The default is to return `nothing`,

			meaning the same block is returned and not changed. Encodings that return the same

			block but change the data (e.g. `ProjectiveTransforms`) should return `block`.

			"""
			

			
			

	
			encodedblock
			(
			
			::

	
			Encoding
			,
			 
			
			::

	
			Block
			)
			 
			=
			 
			nothing
			

			

			
			function
			 
			

	
			encodedblock
			(
			
			encoding
			::

	
			Encoding
			,
			 
			
			blocks
			::
			Tuple
			)
			
			
    
			
			map
			(
			
			block
			 
			->
			 
			

	
			encodedblock
			(
			encoding
			,
			 
			block
			)
			,
			 
			blocks
			)
			

			end
			

			
			function
			 
			

	
			encodedblock
			(
			
			encodings
			::
			Tuple
			,
			 
			blocks
			)
			
			
    
			
			encoded
			 
			=
			 
			false
			
    
			
			for
			
			 
			encoding
			 
			in
			 
			encodings
			
			
        
			
			encoded
			 
			=
			
			 
			encoded
			 
			||
			 
			
			!
			
			isnothing
			(
			

	
			encodedblock
			(
			encoding
			,
			 
			blocks
			)
			)
			
        
			
			blocks
			 
			=
			 
			

	
			encodedblockfilled
			(
			encoding
			,
			 
			blocks
			)
			
    
			end
			
    
			
			return
			
			 
			encoded
			 
			?
			 
			blocks
			 
			:
			 
			nothing
			

			end
			

			

			
			
			
			"""
			

			    decodedblock(encoding, block)

			    decodedblock(encoding, blocks)

			    decodedblock(encodings, blocks)

			

			Return the block that is obtained by decoding `block` with encoding `E`.

			This needs to be constant for an instance of `E`, so it cannot depend on the

			sample or on randomness. The default is to return `nothing`,

			meaning the same block is returned and not changed. Encodings that return the same

			block but change the data when decoding should return `block`.

			"""
			

			
			

	
			decodedblock
			(
			
			::

	
			Encoding
			,
			 
			
			::

	
			Block
			)
			 
			=
			 
			nothing
			

			

			
			function
			 
			

	
			decodedblock
			(
			
			encoding
			::

	
			Encoding
			,
			 
			
			blocks
			::
			Tuple
			)
			
			
    
			
			map
			(
			
			block
			 
			->
			 
			

	
			decodedblock
			(
			encoding
			,
			 
			block
			)
			,
			 
			blocks
			)
			

			end
			

			
			function
			 
			

	
			decodedblock
			(
			encodings
			,
			 
			blocks
			)
			
			
    
			
			decoded
			 
			=
			 
			false
			
    
			
			for
			
			 
			encoding
			 
			in
			 
			
			
			Iterators
			.
			
			reverse
			(
			encodings
			)
			
			
        
			
			decoded
			 
			=
			
			 
			decoded
			 
			||
			 
			
			!
			
			isnothing
			(
			

	
			decodedblock
			(
			encoding
			,
			 
			blocks
			)
			)
			
        
			
			blocks
			 
			=
			 
			

	
			decodedblockfilled
			(
			encoding
			,
			 
			blocks
			)
			
    
			end
			
    
			
			return
			
			 
			decoded
			 
			?
			 
			blocks
			 
			:
			 
			nothing
			

			end
			

			

			
			
			
			"""
			

			    abstract type StatefulEncoding <: Encoding

			

			Encoding that needs to compute some state from the whole sample, even

			if it only transforms some of the blocks. This could be random state

			for stochastic augmentations that needs to be the same for every block

			that is encoded.

			

			The state is created by calling `encodestate(encoding, context, blocks, sample)`

			and passed to recursive calls with the keyword argument `state`.

			As a result, you need to implement `encode`, `decode`, `encode!`, `decode!` with a

			keyword argument `state` that defaults to the above call.

			

			Same goes for `decode`, which should accept a `state` keyword argument defaulting

			to `decodestate(encoding, context, blocks, sample)`

			"""
			

			
			abstract
			 
			type
			
			 

	
			StatefulEncoding
			 
			<:
			 

	
			Encoding
			 
			end
			

			

			
			

	
			encodestate
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			obs
			)
			 
			=
			 
			nothing
			

			
			

	
			decodestate
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			obs
			)
			 
			=
			 
			nothing
			

			

			
			function
			 
			

	
			encode
			(
			
			encoding
			::

	
			StatefulEncoding
			,
			
                
			context
			,
			
                
			
			blocks
			::
			Tuple
			,
			
                
			
			obss
			::
			Tuple
			
			;
			
                
			
			state
			 
			=
			 
			

	
			encodestate
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			obss
			)
			)
			
			
    
			
			return
			 
			
			map
			(
			
			
			(
			block
			,
			 
			obs
			)
			 
			->
			 
			

	
			encode
			(
			encoding
			,
			 
			context
			,
			 
			block
			,
			 
			obs
			
			;
			 
			
			state
			 
			=
			 
			state
			)
			,
			
               
			blocks
			,
			 
			obss
			)
			

			end
			

			

			
			function
			 
			

	
			decode
			(
			
			encoding
			::

	
			StatefulEncoding
			,
			
                
			context
			,
			
                
			
			blocks
			::
			Tuple
			,
			
                
			
			obss
			::
			Tuple
			
			;
			
                
			
			state
			 
			=
			 
			

	
			decodestate
			(
			encoding
			,
			 
			context
			,
			 
			blocks
			,
			 
			obss
			)
			)
			
			
    
			
			@
			assert
			
			 
			
			length
			(
			blocks
			)
			 
			==
			 
			
			length
			(
			obss
			)
			
    
			
			return
			 
			
			Tuple
			(
			
			

	
			decode
			(
			encoding
			,
			 
			context
			,
			 
			block
			,
			 
			obs
			
			;
			 
			
			state
			 
			=
			 
			state
			)
			
                 
			for
			
			
                 
			
			(
			block
			,
			 
			obs
			)
			 
			in
			 
			
			zip
			(
			blocks
			,
			 
			obss
			)
			)
			

			end
			

			

			
			
			
			"""
			

			    testencoding(encoding, block[, obs])

			

			Performs some tests that the encoding interface is set up properly for

			`encoding` and `block`. Tests that

			

			- `obs` is a valid instance `block`

			- `encode` returns a valid `encodedblock(encoding, block)`

			- `decode` returns a valid `decodedblock(encoding, encodedblock(encoding, block))`

			    and that the block is identical to `block`

			"""
			

			
			function
			 
			

	
			testencoding
			(
			encoding
			,
			 
			block
			,
			 
			
			obs
			 
			=
			 
			

	
			mockblock
			(
			block
			)
			)
			
			
    
			
			
			Test
			.
			
			@
			testset
			 
			
			"
			Encoding `
			$
			(
			
			typeof
			(
			encoding
			)
			)
			` for block `
			$
			block
			`
			"
			 
			
			begin
			
        
			# Test that `obs` is a valid instance of `block`
			
        
			
			
			Test
			.
			
			@
			test
			 
			

	
			checkblock
			(
			block
			,
			 
			obs
			)
			
        
			
			
			Test
			.
			
			@
			test
			 
			
			!
			
			isnothing
			(
			

	
			encodedblock
			(
			encoding
			,
			 
			block
			)
			)
			
        
			
			outblock
			 
			=
			 
			

	
			encodedblockfilled
			(
			encoding
			,
			 
			block
			)
			
        
			
			outobs
			 
			=
			 
			

	
			encode
			(
			encoding
			,
			 
			

	
			Training
			(
			)
			,
			 
			block
			,
			 
			obs
			)
			
        
			# The encoded data should be a valid instance for the `encodedblock`
			
        
			
			
			Test
			.
			
			@
			test
			 
			

	
			checkblock
			(
			outblock
			,
			 
			outobs
			)
			

			
        
			# Test decoding (if supported) works correctly
			
        
			
			if
			 
			(
			
			outblock
			 
			isa
			 
			Tuple
			)
			
			
            
			
			for
			
			 
			idx
			 
			in
			
			 
			1
			:
			
			length
			(
			outblock
			)
			
			
                
			
			inblock
			 
			=
			 
			

	
			decodedblock
			(
			encoding
			,
			 
			
			outblock
			[
			idx
			]
			)
			
                
			
			if
			 
			
			!
			
			isnothing
			(
			inblock
			)
			
			
                    
			
			
			Test
			.
			
			@
			test
			
			 
			

	
			wrapped
			(
			
			block
			[
			idx
			]
			)
			 
			==
			 
			

	
			wrapped
			(
			inblock
			)
			
                    
			
			inobs
			 
			=
			 
			

	
			decode
			(
			encoding
			,
			 
			

	
			Training
			(
			)
			,
			 
			
			outblock
			[
			idx
			]
			,
			 
			
			outobs
			[
			idx
			]
			)
			
                    
			
			
			Test
			.
			
			@
			test
			 
			

	
			checkblock
			(
			inblock
			,
			 
			inobs
			)
			
                
			end
			
            
			end
			
        
			else
			
			
            
			
			inblock
			 
			=
			 
			

	
			decodedblock
			(
			encoding
			,
			 
			outblock
			)
			
            
			
			if
			 
			
			!
			
			isnothing
			(
			inblock
			)
			
			
                
			
			
			Test
			.
			
			@
			test
			
			 
			

	
			wrapped
			(
			block
			)
			 
			==
			 
			

	
			wrapped
			(
			inblock
			)
			
                
			
			inobs
			 
			=
			 
			

	
			decode
			(
			encoding
			,
			 
			

	
			Training
			(
			)
			,
			 
			outblock
			,
			 
			outobs
			)
			
                
			
			
			Test
			.
			
			@
			test
			 
			

	
			checkblock
			(
			inblock
			,
			 
			inobs
			)
			
            
			end
			
        
			end
			
    
			end
			

			end