在 Theano 中模拟布尔掩码
Emulating boolean masks in Theano
我正在将一个 numpy 表达式移植到 theano。给定一个 one-hot 矩阵 Y
的 ground truth classes 和一个 one-hot 矩阵 Y_hat
classes。 numpy 代码是:
import numpy as np
y = np.array([1, 0, 1, 2, 2])
y_hat = np.array([2, 0, 1, 1, 0])
Y = np.zeros(shape=(len(y), len(np.unique(y))))
Y_hat = np.zeros_like(Y)
rows = np.arange(len(y))
Y[rows, y] = 1
Y_hat[rows, y_hat] = 1
((Y_hat == Y) & (Y == 1)).sum(axis=0)
最后一个表达式产生 array([1, 1, 0])
。我试过使用 theano 的非零值:
from theano import shared
Yt = shared(Y)
Yt_hat = shared(Y_hat)
Yt_hat[Yt.nonzero()].eval()
eval 结果为 array([ 0., 1., 1., 0., 0.])
,它是 Yt_hat
行的 0-1 掩码,其中预测是正确的。关于如何使这项工作有什么建议吗?对于不同的做法?谢谢。
以下三个变体演示了如何在 Theano 中重新实现部分 numpy 代码。
请注意 Theano 的 Unique
操作在 GPU 上不支持 运行 并且似乎也不支持梯度。结果版本 3 很多用处不大。版本 2 提供了一个解决方法:在 Theano 之外计算唯一值并将它们传递进来。版本 1 是你的 numpy 代码最后一行的 Theano 实现。
针对您的具体问题:没有必要使用nonzero
;在这种情况下,索引在 Theano 中的工作就像在 numpy 中一样。也许您对 y
和 Y
感到困惑? (常见的 Python 风格是所有变量和参数名称都坚持小写)。
import numpy as np
import theano
import theano.tensor as tt
import theano.tensor.extra_ops
def numpy_ver(y, y_hat):
Y = np.zeros(shape=(len(y), len(np.unique(y))), dtype=np.int64)
Y_hat = np.zeros_like(Y, dtype=np.int64)
rows = np.arange(len(y), dtype=np.int64)
Y[rows, y] = 1
Y_hat[rows, y_hat] = 1
return ((Y_hat == Y) & (Y == 1)).sum(axis=0), Y, Y_hat
def compile_theano_ver1():
Y = tt.matrix(dtype='int64')
Y_hat = tt.matrix(dtype='int64')
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([Y, Y_hat], outputs=z)
def compile_theano_ver2():
y = tt.vector(dtype='int64')
y_hat = tt.vector(dtype='int64')
y_uniq = tt.vector(dtype='int64')
Y = tt.zeros(shape=(y.shape[0], y_uniq.shape[0]), dtype='int64')
Y_hat = tt.zeros_like(Y, dtype='int64')
rows = tt.arange(y.shape[0], dtype='int64')
Y = tt.set_subtensor(Y[rows, y], 1)
Y_hat = tt.set_subtensor(Y_hat[rows, y_hat], 1)
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([y, y_hat, y_uniq], outputs=z)
def compile_theano_ver3():
y = tt.vector(dtype='int64')
y_hat = tt.vector(dtype='int64')
y_uniq = tt.extra_ops.Unique()(y)
Y = tt.zeros(shape=(y.shape[0], y_uniq.shape[0]), dtype='int64')
Y_hat = tt.zeros_like(Y, dtype='int64')
rows = tt.arange(y.shape[0], dtype='int64')
Y = tt.set_subtensor(Y[rows, y], 1)
Y_hat = tt.set_subtensor(Y_hat[rows, y_hat], 1)
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([y, y_hat], outputs=z)
def main():
y = np.array([1, 0, 1, 2, 2], dtype=np.int64)
y_hat = np.array([2, 0, 1, 1, 0], dtype=np.int64)
y_uniq = np.unique(y)
result, Y, Y_hat = numpy_ver(y, y_hat)
print result
theano_ver1 = compile_theano_ver1()
print theano_ver1(Y, Y_hat)
theano_ver2 = compile_theano_ver2()
print theano_ver2(y, y_hat, y_uniq)
theano_ver3 = compile_theano_ver3()
print theano_ver3(y, y_hat)
main()
我正在将一个 numpy 表达式移植到 theano。给定一个 one-hot 矩阵 Y
的 ground truth classes 和一个 one-hot 矩阵 Y_hat
classes。 numpy 代码是:
import numpy as np
y = np.array([1, 0, 1, 2, 2])
y_hat = np.array([2, 0, 1, 1, 0])
Y = np.zeros(shape=(len(y), len(np.unique(y))))
Y_hat = np.zeros_like(Y)
rows = np.arange(len(y))
Y[rows, y] = 1
Y_hat[rows, y_hat] = 1
((Y_hat == Y) & (Y == 1)).sum(axis=0)
最后一个表达式产生 array([1, 1, 0])
。我试过使用 theano 的非零值:
from theano import shared
Yt = shared(Y)
Yt_hat = shared(Y_hat)
Yt_hat[Yt.nonzero()].eval()
eval 结果为 array([ 0., 1., 1., 0., 0.])
,它是 Yt_hat
行的 0-1 掩码,其中预测是正确的。关于如何使这项工作有什么建议吗?对于不同的做法?谢谢。
以下三个变体演示了如何在 Theano 中重新实现部分 numpy 代码。
请注意 Theano 的 Unique
操作在 GPU 上不支持 运行 并且似乎也不支持梯度。结果版本 3 很多用处不大。版本 2 提供了一个解决方法:在 Theano 之外计算唯一值并将它们传递进来。版本 1 是你的 numpy 代码最后一行的 Theano 实现。
针对您的具体问题:没有必要使用nonzero
;在这种情况下,索引在 Theano 中的工作就像在 numpy 中一样。也许您对 y
和 Y
感到困惑? (常见的 Python 风格是所有变量和参数名称都坚持小写)。
import numpy as np
import theano
import theano.tensor as tt
import theano.tensor.extra_ops
def numpy_ver(y, y_hat):
Y = np.zeros(shape=(len(y), len(np.unique(y))), dtype=np.int64)
Y_hat = np.zeros_like(Y, dtype=np.int64)
rows = np.arange(len(y), dtype=np.int64)
Y[rows, y] = 1
Y_hat[rows, y_hat] = 1
return ((Y_hat == Y) & (Y == 1)).sum(axis=0), Y, Y_hat
def compile_theano_ver1():
Y = tt.matrix(dtype='int64')
Y_hat = tt.matrix(dtype='int64')
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([Y, Y_hat], outputs=z)
def compile_theano_ver2():
y = tt.vector(dtype='int64')
y_hat = tt.vector(dtype='int64')
y_uniq = tt.vector(dtype='int64')
Y = tt.zeros(shape=(y.shape[0], y_uniq.shape[0]), dtype='int64')
Y_hat = tt.zeros_like(Y, dtype='int64')
rows = tt.arange(y.shape[0], dtype='int64')
Y = tt.set_subtensor(Y[rows, y], 1)
Y_hat = tt.set_subtensor(Y_hat[rows, y_hat], 1)
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([y, y_hat, y_uniq], outputs=z)
def compile_theano_ver3():
y = tt.vector(dtype='int64')
y_hat = tt.vector(dtype='int64')
y_uniq = tt.extra_ops.Unique()(y)
Y = tt.zeros(shape=(y.shape[0], y_uniq.shape[0]), dtype='int64')
Y_hat = tt.zeros_like(Y, dtype='int64')
rows = tt.arange(y.shape[0], dtype='int64')
Y = tt.set_subtensor(Y[rows, y], 1)
Y_hat = tt.set_subtensor(Y_hat[rows, y_hat], 1)
z = (tt.eq(Y_hat, Y) & tt.eq(Y, 1)).sum(axis=0)
return theano.function([y, y_hat], outputs=z)
def main():
y = np.array([1, 0, 1, 2, 2], dtype=np.int64)
y_hat = np.array([2, 0, 1, 1, 0], dtype=np.int64)
y_uniq = np.unique(y)
result, Y, Y_hat = numpy_ver(y, y_hat)
print result
theano_ver1 = compile_theano_ver1()
print theano_ver1(Y, Y_hat)
theano_ver2 = compile_theano_ver2()
print theano_ver2(y, y_hat, y_uniq)
theano_ver3 = compile_theano_ver3()
print theano_ver3(y, y_hat)
main()