Skip to content

Commit

Permalink
Adding Matrix Tensor with auto shape / auto flat functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
RockfordWei committed Jul 4, 2017
1 parent 7480a5a commit 5317f60
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 16 deletions.
10 changes: 10 additions & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ let datastr = tensor.strings
let str = datastr.map { $0.string }
```

### Matrix

Since Perfect-TensorFlow v1.2.1, however, you can apply a multi-dimensional array to a tensor as a matrix without considering the shape or dimensions. The equivalent example of above will look like:

``` swift
let M = try TF.Tensor.Matrix([[1, 2], [3, 4]])
```

⚠️**NOTES**⚠️ Element in a Matrix must be number!

### Raw Data of a Tensor

To access raw data of a tensor, you can use either `data` property, or `withDataPointer()` method with better performance but tricky pointer operations - and property of `bytesCount` and `type` will be useful in this case:
Expand Down
10 changes: 10 additions & 0 deletions GUIDE.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,16 @@ let datastr = tensor.strings
let str = datastr.map { $0.string }
```

### Matrix

自从 Perfect-TensorFlow v1.2.1 版本开始,您可以直接输入矩阵作为张量了!上述例子现在可以改写为:

``` swift
let M = try TF.Tensor.Matrix([[1, 2], [3, 4]])
```

⚠️**NOTES**⚠️ Element in a Matrix must be number!

### 访问张量原始数据

如果您希望在程序中访问张量的原始数据,您可以使用`data`属性,或者调用`withDataPointer()`方法通过指针进行访问(虽然有些技巧性难度,但是性能要快很多)——这种情况下`byteCount`属性(张量数据在内存中的大小)和`type`(张量数据类型)会有很大用处:
Expand Down
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,8 @@ Here is an other simple example of matrix operations in Perfect TensorFlow:
| 3 4 | * |0 0| = |0 3|
*/
// input the matrix.
// *NOTE* no matter how many dimensions a matrix may have,
// the matrix should always input as an flattened array
let srcA:[Float] = [[1, 2], [3, 4]].flatMap { $0 }
let srcB:[Float] = [[0, 0], [1, 0]].flatMap { $0 }

// create tensors for these matrices
let tA = try TF.Tensor.Array(dimensions: [2,2], value: srcA)
let tB = try TF.Tensor.Array(dimensions: [2,2], value: srcB)
let tA = try TF.Tensor.Matrix([[1, 2], [3, 4]])
let tB = try TF.Tensor.Matrix([[0, 0], [1, 0]])

// adding tensors to graph
let g = try TF.Graph()
Expand Down
9 changes: 2 additions & 7 deletions README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,8 @@ print(s2)
| 3 4 | * |0 0| = |0 3|
*/
// 输入矩阵
// *注意* 不管目标矩阵的维度到底是多少,输入时必须按照扁平化处理,即所有元素一个挨一个列出
let srcA:[Float] = [[1, 2], [3, 4]].flatMap { $0 }
let srcB:[Float] = [[0, 0], [1, 0]].flatMap { $0 }

// 根据矩阵创建张量
let tA = try TF.Tensor.Array(dimensions: [2,2], value: srcA)
let tB = try TF.Tensor.Array(dimensions: [2,2], value: srcB)
let tA = try TF.Tensor.Matrix([[1, 2], [3, 4]])
let tB = try TF.Tensor.Matrix([[0, 0], [1, 0]])

// 将张量转化为流程图节点
let g = try TF.Graph()
Expand Down
66 changes: 66 additions & 0 deletions Sources/PerfectTensorFlow/PerfectTensorFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ public extension Array {
public func flat() -> Array<Any> {
return Array.Flat(self)
}

public var shape: [Int] {
var _shape = [Int]()
var a = self as Array<Any>
while a.count > 0 {
_shape.append(a.count)
if let b = a as? Array<Array<Any>> , let c = b.first {
a = c
} else {
break
}//end if
}//end while
return _shape
}//end var

public func column(index: Int) -> Array<Any> {
var b = [Any]()
let s = shape
guard s.count > 1, index > -1, index < s[1],
let a = self as? Array<Array<Any>> else {
if index > -1 && index < self.count {
b.append(self[index])
}//end if
return b
}//end guard
a.forEach { c in
b.append(c[index])
}//next
return b
}//end func
}

typealias SwiftArray<T> = Array<T>
Expand Down Expand Up @@ -568,6 +598,41 @@ public class TensorFlow {
}//end if
}//end tensor

/// Create a tensor from a Matrix. *NOTE* Element must be number
/// - parameters:
/// - matrix: Matrix in form of Array[Array[Array ... Array[Number]]]
/// - throws: Panic.FAULT
/// - returns: tensor
public static func Matrix(_ matrix: Array<Any>) throws -> Tensor {
let shape = matrix.shape.map { Int64($0) }
let flattened = matrix.flat()
let f: [Float]
if flattened is [UInt8], let i = flattened as? [UInt8] {
f = i.map { Float($0) }
} else if flattened is [UInt32], let i = flattened as? [UInt32] {
f = i.map { Float($0) }
} else if flattened is [UInt], let i = flattened as? [UInt] {
f = i.map { Float($0) }
} else if flattened is [UInt64], let i = flattened as? [UInt64] {
f = i.map { Float($0) }
} else if flattened is [Int8], let i = flattened as? [Int8] {
f = i.map { Float($0) }
} else if flattened is [Int32], let i = flattened as? [Int32] {
f = i.map { Float($0) }
} else if flattened is [Int], let i = flattened as? [Int] {
f = i.map { Float($0) }
} else if flattened is [Int64], let i = flattened as? [Int64] {
f = i.map { Float($0) }
} else if flattened is [Float], let i = flattened as? [Float] {
f = i
} else if flattened is [Double], let i = flattened as? [Double] {
f = i.map { Float($0) }
} else {
throw Panic.FAULT(reason: "Matrix Element Must Be Number")
}//end if
return try Array(dimensions: shape, value: f)
}

/// Create a tensor by passing its value
/// type can be Int, Float,... or String / Data
/// - parameters:
Expand All @@ -577,6 +642,7 @@ public class TensorFlow {
/// Tensor
/// - throws:
/// Panic

public static func Array<T> (dimensions:[Int64], value: [T]) throws -> Tensor {
let count = Int(dimensions.reduce(1) { $0 * $1 })
guard let _ = TFLib.libDLL,
Expand Down
36 changes: 35 additions & 1 deletion Tests/PerfectTensorFlowTests/PerfectTensorFlowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,20 @@ class PerfectTensorFlowTests: XCTestCase {
("testBasicExpress", testBasicExpress),
("testLabels", testLabels),
("testSessionLeak", testSessionLeak),
("testGradients", testGradients)
("testGradients", testGradients),
("testMatrix", testMatrix),
("testBasicImproved",testBasicImproved)
]

func testMatrix() {
let x = [[1, 2, 3], [4, 5, 6]]
let y = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]],[[13,14],[15,16],[17,18]],[[19,20],[21,22],[23,24]]]
XCTAssertEqual(x.shape, [2, 3])
XCTAssertEqual(y.shape, [4, 3, 2])
XCTAssertEqual(x[1][2], 6)
XCTAssertEqual(x.column(index: 1) as! [Int], [2, 5])
}

func testGradients() {
do {
let grad = TestGradients()
Expand Down Expand Up @@ -353,6 +364,29 @@ class PerfectTensorFlowTests: XCTestCase {

}

func testBasicImproved() {
do {
/*
Matrix Test:
| 1 2 | |0 1| |0 1|
| |* | |= | |
| 3 4 | |0 0| |0 3|
*/
let tA = try TF.Tensor.Matrix([[1, 2], [3, 4]])
let tB = try TF.Tensor.Matrix([[0, 0], [1, 0]])
let g = try TF.Graph()
let A = try g.const(tensor: tA, name: "Const_0")
let B = try g.const(tensor: tB, name: "Const_1")
let v = try g.matMul(l: A, r: B, name: "v", transposeB: true)
let o = try g.runner().fetch(v).addTarget(v).run()
let m:[Float] = try o[0].asArray()
let r:[Float] = [0, 1, 0, 3]
XCTAssertEqual(m, r)
}catch {
XCTFail("improved: \(error)")
}
}

func testBasicExpress() {
do {
/*
Expand Down

0 comments on commit 5317f60

Please sign in to comment.