Mutating 3D slice without modifying the original

agolangf · 2017-02-23 18:00:10 · 610 次点击    
这是一个分享于 2017-02-23 18:00:10 的资源,其中的信息可能已经有所发展或是发生改变。

So, In order to learn the golang I'm porting an neural network project that I have.

I'm storing the network as an 3D matrix ([][][]float64). Ex:

[
    [[] []] // layer 0
    [[0 0 0] [0 0 0] [0 0 0]] // layer 1
    [[0 0 0 0] [0 0 0 0]] // layer 2
    [[0 0 0]] // layer 3
]

I need to write a function that receives one network, mutate it's values and return A NEW mutated network without modifying the old one.

Here is how I did it:

func Mutate(net [][][]float64) [][][]float64 {
  for l:=0;l<len(net);l++{// fore layer...
    for n:=0;n<len(net[l]);n++{// fore neuron...
      for a:=0;a<len(net[l][n]);a++ {// fore element in neuron array...
        net[l][n][a] = 1// set new value
      }
    }
  }
  return net
}

Here is the commented code for creating and mutating the network http://pastebin.com/sJsQQN1C

And here is the test main function:

func main() {  
  net := neuralArray.GenerateEmptyNet([]int{2,3,2,1})

  fmt.Println("created net: " ,net)
  net2 := neuralArray.Mutate(net)
  fmt.Println("old net:" ,net)
  fmt.Println("new net:", net2)
}

The result:

go run src/main/main2.go                                                                                                                                
created net:  [[[] []] [[0 0 0] [0 0 0] [0 0 0]] [[0 0 0 0] [0 0 0 0]] [[0 0 0]]]                                                                                                           
old net: [[[] []] [[1 1 1] [1 1 1] [1 1 1]] [[1 1 1 1] [1 1 1 1]] [[1 1 1]]]                                                                                                                
new net: [[[] []] [[1 1 1] [1 1 1] [1 1 1]] [[1 1 1 1] [1 1 1 1]] [[1 1 1]]]     

As you see, the old got mutated too. What is causing this behavior? I heard that passing a value as parameter rather than pointer creates a separated clone. But I'm clearly missing something here.

Thanks for your time!


评论:

Sythe2o0:

Go does pass value copies, but slices are just pointers to some area of memory, so you end up copying that pointer.

See this stack overflow post.

Ablaek:

Hm, so my best bet it to change to arrays, or to copy() the slices and build a new one.

I'm gonna redo the code with arrays. Thanks!

EDIT:

actually I just created a new slice, and used it as return value instead....

gdey:

A slice is really a struct that has a pointer to a backing array and two other fields that record the length and capacity of the backing error. So when you pass a slice, you are just passing a copy of this struct. So, both struct point to the original backing array.

Here is a great article on how slices work. https://blog.golang.org/go-slices-usage-and-internals

chewxy:

You can use the tensor library:

a := tensor.New(tensor.Float64, tensor.WithShape(2,3,4))
b := a.Clone().(*tensor.Dense)
b.Memset(1.0)
return b

Best part is... you can just swap out tensor.Float64 for other types like tensor.Float32 and it'll still work the same (for the most part.. you still have to memset the correct values).

More documentation can be found here


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

610 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传