Edited at

MLMultiArrayの初期化

More than 1 year has passed since last update.


初期値は保証されない

こんなふうにイニシャライズする。

let input = try! MLMultiArray(shape: [3, 100, 100], dataType: .double)

何度か確認してみて0で初期化されてるっぽい、と騙されたら駄目。

時折↓こんな値が入っている。

  [0] = 0

[1] = 4.2481962465896993E+180
[2] = 0
[3] = 3.991904287573309E+252
[4] = 4.71049340390293E+257
[5] = 1.9485307275297634E-153
[6] = 6.0134700169917274E-154
[7] = 0.0000000000000000000000000000000000000000000000000000000035248571487052602
[8] = 6.0134700169916227E-154
[9] = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080177859870554834
[10] = 2.5827657058487438E-144
[11] = 1.1459827119906385E-259
[12] = 4.134823634245056E+193
以下略

0で初期化したい場合はちゃんと0を入れましょうね、という事でした。


おまけ

ちなみにMLMultiArrayをflattenしてDouble型の1次元配列にする拡張をデバッグでよく使ってる。

extension MLMultiArray {

public func doubleArray() -> [Double] {
if self.count == 0 {
return [Double]()
}
let ptr = self.dataPointer.bindMemory(to: Double.self, capacity: self.count)
return Array(UnsafeBufferPointer(start: ptr, count: self.count))
}
}


おまけ2

【追記】

割と大きいサイズのMLMultiArrayのすべてに0を愚直に代入するのは駄目だろうと思って色々やり方を模索した結果、

extension MLMultiArray {

public func doubleArray() -> [Double] {
【略】
}

public func zeroInit() {
let ptr = self.dataPointer.bindMemory(to: Double.self, capacity: self.count)
let ptr_buf = UnsafeMutableBufferPointer.init(start: ptr, count: self.count)
let zeros = repeatElement(Double(0.0), count: self.count)
_ = ptr_buf.initialize(from: zeros)
}
}

こうなった。

サイズ分の0の配列を定義して領域確保するよりもRepeated型(他のプログラミング言語的にいうイテレータ?)で渡す方が節約されてそうという印象。(実際は確証はないですが…)

ただしサイズの情報を持った UnsafeMutable「Buffer」Pointer でないとRepeatedを渡して値を初期化できないのでそのような型変換をしています。

※ 厳密にはUnsafeMutablePointerでもできますが、DeprecatedでSwift4.0で削除されるっぽいです。