# CatViews with Flux optimize!

**URL:** <https://discourse.julialang.org/t/catviews-with-flux-optimize/74759>\
**Category:** Machine Learning\
**Tags:** flux\
**Created:** [January 17, 2022, 3:09pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759 "2022-01-17T15:09:04Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![lineycroc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lineycroc/32/10078_2.png) [@lineycroc](https://discourse.julialang.org/u/lineycroc)\
**Post date:** [January 17, 2022, 3:09pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759/1 "2022-01-17T15:09:04Z")

</div>

Flux’s `update!(opt, x, x̄)` function errors when x and x̄ are of type CatView with the following message:  
`TypeError: in typeassert, expected Tuple{CatView{1, Float64}, CatView{1, Float64}, Vector{Float64}}, got a value of type Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}`

Using the debugger, I think the problem stems from the `x̄r = ArrayInterface.restructure(x, x̄)` call at the beginning of `update!`, which re-types x̄ to be a Vector so its type no longer matches the CatView type of x.

Is there a way around this error where I can still use CatView inputs to `update!`? I could (as shown in code below) just copy x to a simple vector format (and then re-copy the results back to x afterward), but that’s ugly code and a (small, but annoying) waste of memory/compute. Maybe there is a way to over-write the `restructure` function to do nothing? That sounds like bad practice too though…

MWE:

```julia
import Flux # adam optimizer
using CatViews

x = [randn(2)]
dx = [randn(2)]
opt = Flux.ADAM()

# create CatViews of the variable and gradient 
xCV = CatView([@view x[k][:] for k=1:length(x)]...)
dxCV = CatView([@view dx[k][:] for k=1:length(x)]...)

tmp = copy(xCV) # tmp is a Vector while xCV is a CatView
Flux.Optimise.update!(opt, tmp, dxCV) # this works 

Flux.Optimise.update!(opt, xCV, dxCV) # this does not work 

```

In terms of why I want to use CatView input: the input variables are actually a collection of OffsetArrays and the user can decide if they want to descend with respect to the OffsetArray values and/or other tuning parameters. Using CatViews allows me to update everything in place while letting Flux see the variables as a simple vector where the true structure is much more complicated.

---

<div class="post-metadata">

**Author:** ![Tomas\_Pevny](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomas_pevny/32/25466_2.png) [@Tomas\_Pevny](https://discourse.julialang.org/u/Tomas_Pevny)\
**Post date:** [January 17, 2022, 5:48pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759/2 "2022-01-17T17:48:46Z")

</div>

Cannot you use update the arrays inside CatView?  
I think uodating CatViews would be very non-performant, as Catviews will calculate indexes of wrapped arrays for each access. For a nice API, you can just overload the update!

---

<div class="post-metadata">

**Author:** ![lineycroc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lineycroc/32/10078_2.png) [@lineycroc](https://discourse.julialang.org/u/lineycroc)\
**Post date:** [January 18, 2022, 4:12pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759/3 "2022-01-18T16:12:11Z")

</div>

I’m not sure if this is what you meant, but  
`[Flux.Optimise.update!(opt, x[i], dx[i]) for i=1:length(x)]`  
works (`Flux.Optimise.update!(opt, x, dx)` does not).

I’ll have to think more if that or overloading update! makes more sense long-term. Thanks for the ideas!

---

<div class="post-metadata">

**Author:** ![Tomas\_Pevny](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomas_pevny/32/25466_2.png) [@Tomas\_Pevny](https://discourse.julialang.org/u/Tomas_Pevny)\
**Post date:** [January 18, 2022, 5:04pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759/4 "2022-01-18T17:04:48Z")

</div>

This is sort of what I meant. If you look how getindex in `CatViews` is implemented, you will see that it would be very wasteful.  
I would overload and you do not need a generator `foreach(i -> Flux.Optimise.update!(opt, x[i], dx[i]), 1:length(x)]`

---

<div class="post-metadata">

**Author:** ![darsnack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/darsnack/32/10144_2.png) [@darsnack](https://discourse.julialang.org/u/darsnack)\
**Post date:** [January 19, 2022, 3:35pm UTC](https://discourse.julialang.org/t/catviews-with-flux-optimize/74759/5 "2022-01-19T15:35:08Z")

</div>

The method in question is the default for dealing with non-standard array types. I think overloading would be appropriate here:

```julia
function Flux.Optimise.update!(opt, x::CatView, dx::CatView)
  foreach(i -> Flux.Optimiser.update!(opt, x[i], dx[i]), 1:length(x))
  return x
end

```
