DataAugmentation
"""
makebuffer(tfm, item)
Create a buffer `buf` that can be used in a call to `apply!(buf, tfm, item)`.
Default to `buffer = apply(tfm, item)`.
You only need to implement this if the default `apply(tfm, item)` isn't
enough. See `apply(tfm::Sequence, item)` for an example of this.
"""
makebuffer
(
tfm
::
Transform
,
items
)
=
apply
(
tfm
,
items
)
"""
apply!(buffer::I, tfm, item::I)
Applies `tfm` to `item`, mutating the preallocated `buffer`.
`buffer` can be obtained with `buffer = makebuffer(tfm, item)`
apply!(buffer, tfm::Transform, item::I; randstate) = apply(tfm, item; randstate)
Default to `apply(tfm, item)` (non-mutating version).
"""
apply!
(
buf
,
tfm
::
Transform
,
items
;
randstate
=
getrandstate
(
tfm
)
)
=
apply
(
tfm
,
items
,
randstate
=
randstate
)
Applying transforms inplace to tuples of items works fine when they always have the same length. When you have a varying number of items however, (e.g. different number of bounding boxes per sample) the number of items doesn't match up with the buffer and we fall back to regular
apply.
function
apply!
(
bufs
::
Union
{
Tuple
,
AbstractVector
}
,
tfm
::
Transform
,
items
::
Union
{
Tuple
,
AbstractVector
}
;
randstate
=
getrandstate
(
tfm
)
)
if
length
(
bufs
)
==
length
(
items
)
return
map
(
(
item
,
buf
)
->
apply!
(
buf
,
tfm
,
item
;
randstate
=
randstate
)
,
items
,
bufs
)
else
return
apply
(
tfm
,
items
;
randstate
=
randstate
)
end
end
mutable
struct
Buffered
{
T
<:
Transform
}
<:
Transform
tfm
::
T
buffers
::
Dict
Buffered
(
tfm
::
T
,
buffer
=
nothing
)
where
T
=
new
{
T
}
(
tfm
,
Dict
(
)
)
end
getrandstate
(
buffered
::
Buffered
)
=
getrandstate
(
buffered
.
tfm
)
function
apply
(
buffered
::
Buffered
,
items
::
T
;
randstate
=
getrandstate
(
buffered
)
)
where
T
buf
=
get
(
buffered
.
buffers
,
T
,
nothing
)
if
isnothing
(
buf
)
buf
=
makebuffer
(
buffered
.
tfm
,
items
)
buffered
.
buffers
[
T
]
=
buf
end
titems
=
apply!
(
buf
,
buffered
.
tfm
,
items
,
randstate
=
randstate
)
return
titems
end
function
apply!
(
buf
,
buffered
::
Buffered
,
items
::
T
;
randstate
=
getrandstate
(
buffered
)
)
where
T
buf
=
get
(
buffered
.
buffers
,
T
,
nothing
)
if
isnothing
(
buf
)
buf
=
makebuffer
(
buffered
.
tfm
,
items
)
buffered
.
buffers
[
T
]
=
buf
end
res
=
apply!
(
buf
,
buffered
.
tfm
,
items
;
randstate
=
randstate
)
copyitemdata!
(
buf
,
res
)
return
buf
end
struct
BufferedThreadsafe
<:
Transform
buffereds
::
Vector
{
Buffered
}
function
BufferedThreadsafe
(
tfm
;
n
=
Threads
.
nthreads
(
)
)
@
assert
n
>=
1
return
new
(
[
Buffered
(
tfm
)
for
_
in
1
:
n
]
)
end
end
getrandstate
(
btfm
::
BufferedThreadsafe
)
=
getrandstate
(
btfm
.
buffereds
[
1
]
)
Base
.
show
(
io
::
IO
,
bt
::
BufferedThreadsafe
)
=
print
(
io
,
"
BufferedThreadsafe(
$
(
bt
.
buffereds
[
1
]
.
tfm
)
)
"
)
function
apply
(
bufferedt
::
BufferedThreadsafe
,
items
;
kwargs
...
)
bufferedthread
=
bufferedt
.
buffereds
[
Threads
.
threadid
(
)
]
return
apply
(
bufferedthread
,
items
;
kwargs
...
)
end
function
apply!
(
buf
,
bufferedt
::
BufferedThreadsafe
,
items
;
kwargs
...
)
bufferedthread
=
bufferedt
.
buffereds
[
Threads
.
threadid
(
)
]
return
apply!
(
buf
,
bufferedthread
,
items
;
kwargs
...
)
endUtils
copyitemdata!
(
buf
::
I
,
item
::
I
)
where
I
<:
Item
=
(
copy!
(
itemdata
(
buf
)
,
itemdata
(
item
)
)
;
return
buf
)
copyitemdata!
(
bufs
::
T
,
items
::
T
)
where
T
<:
Tuple
=
(
(
copyitemdata!
.
(
bufs
,
items
)
;
bufs
)
;
return
bufs
)
copyitemdata!
(
bufs
::
T
,
items
::
T
)
where
T
<:
AbstractVector
=
(
(
copyitemdata!
.
(
bufs
,
items
)
;
bufs
)
;
return
bufs
)