tensorflow中直接使用下标赋值会报错误。
如下代码:
tensor_input = tf.constant([i for i in range(20)], tf.float32)
tensor_input = tf.reshape(tensor_input, [4, 5])
tensor_input[2, 3] = 100
报错:
TypeError: 'tensorflow.python.framework.ops.EagerTensor' object does not support item assignment
当然使用assign也会报错(assign针对的是tf.Variable):
AttributeError: 'tensorflow.python.framework.ops.EagerTensor' object has no attribute 'assign'
from https://blog.csdn.net/Strive_For_Future/article/details/82426015
主要思想:假设tensor为4行5列,要修改位置(2,3),将该位置元素修改为A。方法:生成一个矩阵D为4行5列,该矩阵在(2,3)位置为1,其余位置为0,然后生成一个新的tensor,公式为:
新的tensor = 原tensor - 原修改位置元素*D + A*D
首先第一步导致原tensor要修改位置元素置零而其余位置元素不变,然后第二步导致要修改位置元素改为A。因为D只有要修改的位置为1,这样不会影响其他位置元素。
import tensorflow as tf
def tensor_expand(tensor_Input, Num):
'''
张量自我复制扩展,将Num个tensor_Input串联起来,生成新的张量,
新的张量的shape=[tensor_Input.shape,Num]
:param tensor_Input:
:param Num:
:return:
'''
tensor_Input = tf.expand_dims(tensor_Input, axis=0)
tensor_Output = tensor_Input
for i in range(Num - 1):
tensor_Output = tf.concat([tensor_Output, tensor_Input], axis=0)
return tensor_Output
def get_one_hot_matrix(height, width, position):
'''
生成一个 one_hot矩阵,shape=【height*width】,在position处的元素为1,其余元素为0
:param height:
:param width:
:param position: 格式为【h_Index,w_Index】,h_Index,w_Index为int格式
:return:
'''
col_length = height # 4
row_length = width # 5
col_one_position = position[0] # 2
row_one_position = position[1] # 3
rows_num = height # 4
cols_num = width # 5
single_row_one_hot = tf.one_hot(row_one_position, row_length,
dtype=tf.float32) # tf.Tensor([0. 0. 0. 1. 0.], shape=(5,), dtype=float32)
single_col_one_hot = tf.one_hot(col_one_position, col_length,
dtype=tf.float32) # tf.Tensor([0. 0. 1. 0.], shape=(4,), dtype=float32)
one_hot_rows = tensor_expand(single_row_one_hot, rows_num)
one_hot_cols = tensor_expand(single_col_one_hot, cols_num)
one_hot_cols = tf.transpose(one_hot_cols)
one_hot_matrx = one_hot_rows * one_hot_cols
return one_hot_matrx
def tensor_assign_2D(tensor_input, position, value):
'''
给 2D tensor的特定位置元素赋值
:param tensor_input: 输入的2D tensor,目前只支持2D
:param position: 被赋值的张量元素的坐标位置,=【h_index,w_index】
:param value:
:return:
'''
shape = tensor_input.get_shape().as_list() # [4, 5] 为list
height = shape[0] # 4
width = shape[1] # 5
h_index = position[0] # 2
w_index = position[1] # 3
one_hot_matrix = get_one_hot_matrix(height, width, position)
new_tensor = tensor_input - tensor_input[h_index, w_index] * one_hot_matrix + one_hot_matrix * value
return new_tensor
if __name__ == "__main__":
##test
tensor_input = tf.constant([i for i in range(20)], tf.float32)
tensor_input = tf.reshape(tensor_input, [4, 5])
new_tensor = tensor_assign_2D(tensor_input, [2, 3], 100)
print(new_tensor.numpy())
tf.Variable配合assign。
首先将原tensor变为Variable,然后配合assign函数达到修改tensor的目的,之后再将Variable变回tensor。
import tensorflow as tf
def my_func(arg):
return tf.convert_to_tensor(arg)
if __name__ == "__main__":
##test
tensor_input = tf.constant([i for i in range(20)], tf.float32)
tensor_input = tf.reshape(tensor_input, [4, 5])
# print(type(tensor_input)) #
# tf.print(tensor_input)
# print(tensor_input[2, 3]) # tf.Tensor(13.0, shape=(), dtype=float32)
# print(tensor_input[2][3]) # tf.Tensor(13.0, shape=(), dtype=float32)
new_tensor_v = tf.Variable(tensor_input)
new_tensor_v[2, 3].assign(100)
###############################
# 错误 AttributeError: 'tensorflow.python.framework.ops.EagerTensor' object has no attribute 'assign'
# new_tensor_v[2][3].assign(100)
###############################
# print(type(new_tensor_v)) #
new_tensor = my_func(new_tensor_v)
print(type(new_tensor)) #
# print(new_tensor.numpy())
'''
[[ 0. 1. 2. 3. 4.]
[ 5. 6. 7. 8. 9.]
[ 10. 11. 12. 100. 14.]
[ 15. 16. 17. 18. 19.]]
'''
思路:仿照方法1,利用tf.where。
import numpy as np
import tensorflow as tf
if __name__ == "__main__":
##test
tensor_input = tf.constant([i for i in range(20)], tf.float32)
tensor_input = tf.reshape(tensor_input, [4, 5])
one_d_v = tf.cast(tf.Variable(tf.zeros_like(tensor_input))[2, 3].assign(1), tf.bool)
new_tensor = tf.where(one_d_v, 100, tensor_input)
print(new_tensor.numpy())
'''
[[ 0. 1. 2. 3. 4.]
[ 5. 6. 7. 8. 9.]
[ 10. 11. 12. 100. 14.]
[ 15. 16. 17. 18. 19.]]
'''
思路:利用tf.py_function
tf.py_function为tensorflow提供的接口,可用于像操作原生numpy一样操作tensor,常和tf.data等配合使用。
import tensorflow as tf
def mo(input_tensor, position=None, value=None):
input_tensor = input_tensor.numpy()
input_tensor[tuple(position)] = value
return input_tensor
if __name__ == "__main__":
##test
tensor_input = tf.constant([i for i in range(20)], tf.float32)
tensor_input = tf.reshape(tensor_input, [4, 5])
# print(tensor_input.dtype) #
new_tensor = tf.py_function(mo, inp=[tensor_input, (2, 3), 100], Tout=tensor_input.dtype)
print(type(new_tensor)) #
print(new_tensor.numpy())
'''
[[ 0. 1. 2. 3. 4.]
[ 5. 6. 7. 8. 9.]
[ 10. 11. 12. 100. 14.]
[ 15. 16. 17. 18. 19.]]
'''
pytorch则可以直接更改元素..
import torch
a = torch.tensor([1, 2, 3, 4.])
a[2] = 100
print(a) # tensor([ 1., 2., 100., 4.])
1 对于可扩展性来讲,毫无疑问方法4可扩展性最强,几乎可解决一切对tensor的操作。
2 对于某些情况,tf.where是较好的选择,如修改指定元素值的元素,如将tensor aa中值为100的元素全部改为200,则可以很方便使用:aa = tf.where(aa == 100, 200, aa)
3 某些情况似乎tf.where速度较快。
4 似乎不是很推荐先将tensor转化为Variable再使用assign的方法。
5 tf.py_function常常和tf.data配合使用。如下为一些程序截图: