tensorflow 2.x 修改tensor中某些元素

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'

有如下一些方法修改tensor

方法1

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())

方法2

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))  # <class 'tensorflow.python.framework.ops.EagerTensor'>
    # 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))  # <class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>
    new_tensor = my_func(new_tensor_v)
    print(type(new_tensor))  # <class 'tensorflow.python.framework.ops.EagerTensor'>
    # print(new_tensor.numpy())
    '''
    [[  0.   1.   2.   3.   4.]
    [  5.   6.   7.   8.   9.]
    [ 10.  11.  12. 100.  14.]
    [ 15.  16.  17.  18.  19.]]
    '''

方法3

思路:仿照方法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.]]
    '''

方法4

思路:利用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)  # <dtype: 'float32'>

    new_tensor = tf.py_function(mo, inp=[tensor_input, (2, 3), 100], Tout=tensor_input.dtype)
    print(type(new_tensor))  # <class 'tensorflow.python.framework.ops.EagerTensor'>
    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配合使用。如下为一些程序截图:

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忧郁的常凯申

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值