# Why zip the data argument to the \`Flux::train!\` function?

**URL:** https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024
**Category:** Machine Learning
**Tags:** flux
**Created:** [February 22, 2020, 6:08pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024 "2020-02-22T18:08:10Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![arnaudmgh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arnaudmgh/32/7134_2.png) [@arnaudmgh](https://discourse.julialang.org/u/arnaudmgh)
#### Post date: [February 22, 2020, 6:08pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/1 "2020-02-22T18:08:10Z")

</div>

I have been playing with [the model zoo autoencoder code](https://github.com/FluxML/model-zoo/blob/master/vision/mnist/autoencoder.jl). I have a question about this line of code:

```julia
@epochs 10 Flux.train!(loss, params(m), zip(data), opt, cb = evalcb)

```

[(permalink)](https://github.com/FluxML/model-zoo/blob/025489c56afabd1f871ffea9482512e5e7ad42c4/vision/mnist/autoencoder.jl#L33)

**What is `zip(data)` doing to the data, and what type does `Flux::train!` expects for the data argument?**

I am confused because data is an array of 60 batches, and zip as only the one argument data. If I pass data directly, it stalls and does nothing. I suspect it has to do with the fact that the type of `zip(data)` is iterator, and may-be that is what `Flux::train!` needs for efficiency, but since I can’t find documentation for `train!`, I have no clue.

Any hints appreciated. Thanks!

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 22, 2020, 7:15pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/2 "2020-02-22T19:15:12Z")

</div>

```julia
julia> zz = zip([1,2,3], ["a","b","c"])
Base.Iterators.Zip{Tuple{Array{Int64,1},Array{String,1}}}(([1, 2, 3], ["a", "b", "c"]))

julia> for (x, y) in zz
           @show x, y
       end
(x, y) = (1, "a")
(x, y) = (2, "b")
(x, y) = (3, "c")

```

you’re right, the zipped thing can be iterated over and each element is a pair of `input` and `output` (of your ML model)

and in the example you linked, it looks like this is mainly for maintaining the type requirement, not for zipping input and label together

---

<div class="post-metadata">

### Author: ![arnaudmgh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arnaudmgh/32/7134_2.png) [@arnaudmgh](https://discourse.julialang.org/u/arnaudmgh)
#### Post date: [February 24, 2020, 4:19pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/3 "2020-02-24T16:19:11Z")

</div>

Thank you for your answer, jling. I guess I have to give iterator types to `train!` for data, always, then.

---

<div class="post-metadata">

### Author: ![dellison](https://avatars.discourse-cdn.com/v4/letter/d/ce73a5/32.png) [@dellison](https://discourse.julialang.org/u/dellison)
#### Post date: [February 24, 2020, 5:19pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/4 "2020-02-24T17:19:12Z")

</div>

Maybe here’s another way to think about it (or at least, here’s how I think about it)-

The `data` argument to `train!` just has to be an iterable of tuples that are splatted to `loss`. `train!` pretty much just does this:

```julia
for datapoint in data
    loss(datapoint...)
end

```

(Of course, it’s actually slightly fancier that than, since it takes the gradient and updates the parameters and all that stuff, but the training loop itself is quite straightforward, I think- the source is [here](https://github.com/FluxML/Flux.jl/blob/master/src/optimise/train.jl#L63), in case you’d like to take a look!)

So, if you’ve defined your loss function to look like this:

```julia
function loss(x, y)
    # ...
end

```

…then you can pass in a vector of `(x, y)` tuples to `train!` as the `data` argument. It could just as easily be `loss(a, b, c)`, if you calculate your model’s loss that way, where you’d want to pass in `(a, b, c)` tuples.

I hope that helps! 😃

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [February 24, 2020, 5:41pm UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/5 "2020-02-24T17:41:13Z")

</div>

This case is interesting in that — since it’s an autoencoder — the data is itself the label. That means that the loss function can be defined with just one argument.

A more typical use-case of flux might do something like:

```julia
loss(x, y) = Flux.mse(model(x), y)
Flux.train!(loss, params(model), zip(features, labels), opt)

```

Where `features` is the vector of all the input data, and `labels` is the corresponding vector of their corresponding known outputs. Zipping them together converts the two vectors to a single vector with each datapoint in the same tuple as its label.

You could define an auto-encoder with the loss definition above just by zipping `data` with itself: `zip(data, data)`, or you could do as the model zoo does: just recognize that a single argument is sufficient and then the one-argument `zip` is just a cute way of putting each element of the `data` vector into a 1-tuple that can be splatted into `loss`.

---

<div class="post-metadata">

### Author: ![arnaudmgh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arnaudmgh/32/7134_2.png) [@arnaudmgh](https://discourse.julialang.org/u/arnaudmgh)
#### Post date: [February 25, 2020, 5:07am UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/6 "2020-02-25T05:07:20Z")

</div>

Oh I see, yes that’s a good way to put it - I pay atttention now the loss function had only one argument, because of this particular case (`loss(x) = mse(m(x), x)`).

Thanks a lot!

---

<div class="post-metadata">

### Author: ![arnaudmgh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arnaudmgh/32/7134_2.png) [@arnaudmgh](https://discourse.julialang.org/u/arnaudmgh)
#### Post date: [February 25, 2020, 5:10am UTC](https://discourse.julialang.org/t/why-zip-the-data-argument-to-the-flux-train-function/35024/7 "2020-02-25T05:10:44Z")

</div>

Yes that helps - and thank you also for linking the source code, good idea to go look, especially in Julia, where the source code is often relatively concise and readable.
