如何在tensorflow-js中反转矩阵?

时间:2018-08-12 03:15:25

标签: tensorflow.js

简单的问题。是否有针对它的操作,如何创建一个单位矩阵?我已经检查了文档,但是找不到单个操作。

2 个答案:

答案 0 :(得分:0)

对于身份矩阵,您可以使用tf.eye(),但不确定通过反转矩阵的含义,但是它可以是执行元素1/x的{​​{3}}或您想要进行转置,可以使用tf.reciprocal()

答案 1 :(得分:0)

现在tensorflowJs没有任何可以返回矩阵M逆的直接运算符。 您可以考虑使用模块Math.js

话虽如此,可以使用tensorflowJs运算符求矩阵求逆。

以下内容使用 adjoint方法和tensorflowJs运算符来计算矩阵的逆。

// calculate the determinant of a matrix m
function det(m) {
    return tf.tidy(() => {
        const [r, _] = m.shape
        if (r === 2) {
            const t = m.as1D()
            const a = t.slice([0], [1]).dataSync()[0]
            const b = t.slice([1], [1]).dataSync()[0]
            const c = t.slice([2], [1]).dataSync()[0]
            const d = t.slice([3], [1]).dataSync()[0]
            result = a * d - b * c
            return result

        } else {
            let s = 0;
            rows = [...Array(r).keys()]
            for (let i = 0; i < r; i++) {
                sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
                sli = sub_m.slice([0, 1], [r - 1, r - 1])
                s += Math.pow(-1, i) * det(sli)
            }
            return s
        }
    })
}

// the inverse of the matrix : matrix adjoint method
function invertMatrix(m) {
    return tf.tidy(() => {
        const d = det(m)
        if (d === 0) {
            return
        }
        [r, _] = m.shape
        rows = [...Array(r).keys()]
        dets = [];
        for (let i = 0; i < r; i++) {
            for (let j = 0; j < r; j++) {
                const sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
                let sli
                if (j === 0) {
                    sli = sub_m.slice([0, 1], [r - 1, r - 1])
                } else if (j === r - 1) {
                    sli = sub_m.slice([0, 0], [r - 1, r - 1])
                } else {
                    const [a, b, c] = tf.split(sub_m, [j, 1, r - (j + 1)], 1)
                    sli = tf.concat([a, c], 1)
                }
                dets.push(Math.pow(-1, (i + j)) * det(sli))
            }
        }
        com = tf.tensor2d(dets, [r, r])
        tr_com = com.transpose()
        inv_m = tr_com.div(tf.scalar(d))
        return inv_m
    })
}

const a = tf.tensor2d([1, 3, 3, 1, 4, 3, 1, 3, 4], [3, 3])
console.log("matrix a")
a.print()
const i = invertMatrix(a)
console.log("inverse i")
i.print()
const prod = i.dot(a)
console.log("a * i")
prod.print()
<html>
  <head>
    <!-- Load TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.12.0"> </script>
  </head>

  <body>
  </body>
</html>

使用 Jordan-Gauss 方法,可以通过以下方式计算矩阵的逆:

// calculate the determinant of a matrix m
function det(m) {
    return tf.tidy(() => {
        const [r, _] = m.shape
        if (r === 2) {
            const t = m.as1D()
            const a = t.slice([0], [1]).dataSync()[0]
            const b = t.slice([1], [1]).dataSync()[0]
            const c = t.slice([2], [1]).dataSync()[0]
            const d = t.slice([3], [1]).dataSync()[0]
            result = a * d - b * c
            return result

        } else {
            let s = 0;
            rows = [...Array(r).keys()]
            for (let i = 0; i < r; i++) {
                sub_m = m.gather(tf.tensor1d(rows.filter(e => e !== i), 'int32'))
                sli = sub_m.slice([0, 1], [r - 1, r - 1])
                s += Math.pow(-1, i) * det(sli)
            }
            return s
        }
    })
}

// the inverse of the matrix : jordan-gauss method
function invertM(m) {
    return tf.tidy(() => {
        if (det(m) === 0) {
            return
        }
        const [r, _] = m.shape
        let inv = m.concat(tf.eye(r), 1)
        rows = [...Array(r).keys()]
        for (let i = 0; i < r; i++) {
            inv = tf.tidy(() => {
                for (let j = i + 1; j < r; j++) {
                    const elt = inv.slice([j, i], [1, 1]).as1D().asScalar()
                    const pivot = inv.slice([i, i], [1, 1]).as1D().asScalar()
                    let newrow
                    if (elt.dataSync()[0] !== 0) {
                        newrow = inv.gather(tf.tensor1d([i], 'int32')).sub(inv.gather(tf.tensor1d([j], 'int32')).div(elt).mul(pivot)).as1D()
                        const sli = inv.gather(rows.filter(e => e !== j))
                        const arr = []
                        if (j === 0) {
                            arr.push(newrow)
                        }
                        sli.unstack().forEach((t, ind) => {
                            if (ind !== j) {
                                arr.push(t)
                            } else {
                                arr.push(newrow)
                                arr.push(t)
                            }
                        })
                        if (j === r - 1) {
                            arr.push(newrow)
                        }
                        inv = tf.stack(arr)
                    }
                }
                return inv
            })
        }
        const trian = tf.unstack(inv)
        len = trian.length
        trian[len - 1] = trian[len - 1].div(trian[len - 1].slice(trian[len - 1].shape[0] - 1, 1).asScalar())
        for (let i = r - 2; i > -1; i--) {
            for (j = r - 1; j > i; j--) {
                trian[i] = trian[i].sub(trian[j].mul(trian[i].slice(j, 1).asScalar()))
            }
            trian[i] = trian[i].div(trian[i].slice(i, 1).asScalar())
        }
        return tf.split(tf.stack(trian), 2, 1)[1]
    })
}

const a = tf.tensor2d([1, 3, 3, 1, 4, 3, 1, 3, 4], [3, 3])
console.log("matrix a")
a.print()
const i = invertM(a)
console.log("inverse i")
i.print()
const prod = i.dot(a)
console.log("a * i")
prod.print()
<html>
  <head>
    <!-- Load TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.12.0"> </script>
  </head>

  <body>
  </body>
</html>