TensorFlow基础

import tensorflow as tf

文章内容

主要对 TensorFlow 2 的张量操作,通过对张量的一系列操作介绍,可以使学员对 TensorFlow
2 的基本语法有所了解。
包括张量的创建、切片、索引、张量维度变化、张量的算术运算、张量排序中介绍 TensorFlow 2 的语法。

张量的创建方法。
张量的切片与索引方法。
张量维度变化的语法。
张量的算术运算操作。
张量的排序方法。

学习步骤

什么是tensor

TensorFlow 中,tensor 通常分为:常量 tensor 与变量 tensor:

  • 常量 tensor 定义后值和维度不可变,变量定义后值可变而维度不可变.
  • 在神经网络中,变量 tensor 一般可作为储存权重和其他信息的矩阵,是可训练的数据类型。而常量
    tensor 可作为储存超参数或其他结构信息的变量

创建tensor

创建常量tensor

常量 tensor 的创建方式比较多,常见的有一下几种方式:

  • tf.constant():创建常量 tensor;
  • tf.zeros(), tf.zeros_like(), tf.ones(),tf.ones_like(): 创建全零或者全一的常量 tensor;
  • tf.fill(): 创建自定义数值的 tensor;
  • tf.random: 创建已知分布的 tensor;
  • 从 numpy,list 对象创建,再利用 tf.convert_to_tensor 转换为类型。
    步骤1        tf.constant()
    tf.constant(value, dtype=None, shape=None, name=‘Const’, verify_shape=False):
  • value:值;
  • dtype:数据类型;
  • shape:张量形状;
  • name:常量名称;
  • verify_shape:布尔值,用于验证值的形状,默认 False。verify_shape 为 True 的话表示检查
    value 的形状与 shape 是否相符,如果不符会报错。
const_a = tf.constant([[1, 2, 3, 4]],shape=[2,2], dtype=tf.float32) # 创建 2x2 矩阵,值 1,2,3,4
const_a
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[1., 2.],
       [3., 4.]], dtype=float32)>
#查看常见属性
print("常量 const_a 的数值为:", const_a.numpy())
print("常量 const_a 的数据类型为:", const_a.dtype)
print("常量 const_a 的形状为:", const_a.shape)
print("常量 const_a 将被产生的设备名称为:", const_a.device)
常量 const_a 的数值为: [[1. 2.]
 [3. 4.]]
常量 const_a 的数据类型为: <dtype: 'float32'>
常量 const_a 的形状为: (2, 2)
常量 const_a 将被产生的设备名称为: /job:localhost/replica:0/task:0/device:GPU:0

步骤 2     tf.zeros(), tf.zeros_like(), tf.ones(),tf.ones_like()
因为 tf.ones(),tf.ones_like()与 tf.zeros(),tf.zeros_like()的用法相似,因此下面只演示前者的使用
方法。
创建一个值为 0 的常量。
   tf.zeros(shape, dtype=tf.float32, name=None):

  • shape:张量形状;
  • dtype:类型;
  • name:名称。
zeros_b = tf.zeros(shape=[2, 3], dtype=tf.int32) # 创建 2x3 矩阵,元素值均为 0
zeros_b
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[0, 0, 0],
       [0, 0, 0]])>

根据输入张量创建一个值为 0 的张量,形状和输入张量相同。
tf.zeros_like(input_tensor, dtype=None, name=None, optimize=True):

  • input_tensor:张量;
  • dtype:类型;
  • name:名称;
  • optimize:优化。
zeros_like_c = tf.zeros_like(const_a)
#查看生成数据
zeros_like_c.numpy()
array([[0., 0.],
       [0., 0.]], dtype=float32)

步骤 3    tf.fill()
创建一个张量,用一个具体值充满张量。
tf.fill(dims, value, name=None):

  • dims:张量形状,同上述 shape;
  • vlaue:张量数值;
  • name:名称。
fill_d = tf.fill([3,3], 8) # 2x3 矩阵,元素值均为为 8
#查看数据
fill_d.numpy()
array([[8, 8, 8],
       [8, 8, 8],
       [8, 8, 8]])

步骤 4    tf.random
用于产生具体分布的张量。该模块中常用的方法包括:tf.random.uniform(),tf.random.normal()和
tf.random.shuffle()等。下面演示 tf.random.normal()的用法。

创建一个符合正态分布的张量。
tf.random.normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32,seed=None,
name=None):

  • shape:数据形状;
  • mean:高斯分布均值;
  • stddev:高斯分布标准差;
  • dtype:数据类型;
  • seed:随机种子
  • name:名称。
random_e = tf.random.normal([5,5],mean=0,stddev=1.0, seed = 1)
#查看创建数据
random_e.numpy()
array([[-0.8113182 ,  1.4845989 ,  0.06532937, -2.4427042 ,  0.0992484 ],
       [ 0.5912243 ,  0.59282297, -2.1229296 , -0.72289723, -0.05627037],
       [ 0.6435448 , -0.26432407,  1.8566332 ,  0.5678417 , -0.3828359 ],
       [-1.4853433 ,  1.2617711 , -0.02530608, -0.2646297 ,  1.5328138 ],
       [-1.7429771 , -0.4378929 , -0.56601   ,  0.32066926,  1.132831  ]],
      dtype=float32)

步骤 5    从 numpy,list 对象创建,再利用 tf.convert_to_tensor 转换为类型。
      将给定制转换为张量。可利用这个函数将 python 的数据类型转换成 TensorFlow 可用的 tensor 数据
类型。
tf.convert_to_tensor(value,dtype=None,dtype_hint=None,name=None):

  • value:需转换数值;
  • dtype:张量数据类型;
  • dtype_hint:返回张量的可选元素类型,当 dtype 为 None 时使用。在某些情况下,调用者在
    tf.convert_to_tensor 时可能没有考虑到 dtype,因此 dtype_hint 可以用作为首选项。
#创建一个列表
list_f = [1,2,3,4,5,6]
#查看数据类型
type(list_f)
list
tensor_f = tf.convert_to_tensor(list_f, dtype=tf.float32)
tensor_f
<tf.Tensor: shape=(6,), dtype=float32, numpy=array([1., 2., 3., 4., 5., 6.], dtype=float32)>

创建变量Tensor

TensorFlow 中,变量通过 tf.Variable 类进行操作。tf.Variable 表示张量,其值可以通过在其上运行
算术运算更改。可读取和修改变量值。

# 创建变量,只需提供初始值
var_1 = tf.Variable(tf.ones([2,3]))
var_1
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[1., 1., 1.],
       [1., 1., 1.]], dtype=float32)>
#变量数值读取
print("变量 var_1 的数值:",var_1.read_value())
#变量赋值
var_value_1=[[1,2,3],[4,5,6]]
var_1.assign(var_value_1)
print("变量 var_1 赋值后的数值:",var_1.read_value())
变量 var_1 的数值: tf.Tensor(
[[1. 1. 1.]
 [1. 1. 1.]], shape=(2, 3), dtype=float32)
变量 var_1 赋值后的数值: tf.Tensor(
[[1. 2. 3.]
 [4. 5. 6.]], shape=(2, 3), dtype=float32)
#变量加法
var_1.assign_add(tf.ones([2,3]))
var_1
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[2., 3., 4.],
       [5., 6., 7.]], dtype=float32)>

tensor的切片与索引

切片

切片的方式主要有:

  • [start: end]:从 tensor 的开始位置到结束位置的数据切片;
  • [start :end :step]或者[::step]:从 tensor 的开始位置到结束位置每隔 step 的数据切片;
  • ‘…’:任意长。
#创建一个 4 维 tensor。tensor 包含 4 张图片,每张图片的大小为 100*100*3
tensor_h = tf.random.normal([4,100,100,3])
tensor_h
#取出第一张图片
tensor_h[0,:,:,:]
#每两张图片取出一张的切片
tensor_h[::2,...]
#倒序切片
tensor_h[::-1]
索引

索引的基本格式:a[d1][d2][d3]

#取出第一张图片第二个通道中在[20,40]位置的像素点
tensor_h[0][19][39][1]
<tf.Tensor: shape=(), dtype=float32, numpy=0.7021317>

如果要提取的索引不连续的话,在 TensorFlow 中,常见的用法为 tf.gather 和 tf.gather_nd。

在某一维度进行索引。
tf.gather(params, indices,axis=None):

  • params:输入张量;
  • indices:取出数据的索引;
  • axis:所取数据所在维度。
#取出 tensor_h([4,100,100,3])中,第 1,2,4 张图像。
indices = [0,1,3]
tf.gather(tensor_h,axis=0,indices=indices,batch_dims=1)b

tf.gather_nd 允许在多维上进行索引:

tf.gather_nd(params,indices):

  • params:输入张量;
  • indices:取出数据的索引,一般为多维列表。
#取出 tensot_h([4,100,100,3])中,第一张图像第一个维度中[1,1]的像素点;第二张图片第一像素点中[2,2]的像素点
indices = [[0,1,1,0],[1,2,2,0]]
tf.gather_nd(tensor_h,indices=indices)
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-1.0100561 ,  0.39256692], dtype=float32)>

tensor的维度变化

维度查看
const_d_1 = tf.constant([[1, 2, 3, 4]],shape=[2,2], dtype=tf.float32)
#查看维度常用的三种方式
print(const_d_1.shape)
print(const_d_1.get_shape())
print(tf.shape(const_d_1))#输出为张量,其数值表示的是所查看张量维度大小
(2, 2)
(2, 2)
tf.Tensor([2 2], shape=(2,), dtype=int32)

可以看出.shape 和.get_shape()都是返回 TensorShape 类型对象,而 tf.shape(x)返回的是
Tensor 类型对象。

维度重组

tf.reshape(tensor,shape,name=None):

  • tensor:输入张量;
  • shape:重组后张量的维度。
reshape_1 = tf.constant([[1,2,3],[4,5,6]])
print(reshape_1)
tf.reshape(reshape_1, (3,2))
tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)





<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[1, 2],
       [3, 4],
       [5, 6]])>
维度增加

tf.expand_dims(input,axis,name=None):

  • input:输入张量;
  • axis:在第 axis 维度后增加一个维度。在输入 D 尺寸的情况下,轴必须在[-(D + 1),D](含)范围
    内。负数代表倒序。
#生成一个大小为 100*100*3 的张量来表示一张尺寸为 100*100 的三通道彩色图片
expand_sample_1 = tf.random.normal([100,100,3], seed=1)
print("原始数据尺寸:",expand_sample_1.shape)
print("在第一个维度前增加一个维度(axis=0):",tf.expand_dims(expand_sample_1, axis=0).shape)
print("在第二个维度前增加一个维度(axis=1):",tf.expand_dims(expand_sample_1, axis=1).shape)
print("在最后一个维度后增加一个维度(axis=-1):",tf.expand_dims(expand_sample_1, axis=-1).shape)
原始数据尺寸: (100, 100, 3)
在第一个维度前增加一个维度(axis=0): (1, 100, 100, 3)
在第二个维度前增加一个维度(axis=1): (100, 1, 100, 3)
在最后一个维度后增加一个维度(axis=-1): (100, 100, 3, 1)
维度减少

tf.squeeze(input,axis=None,name=None):

  • input:输入张量;
  • axis:axis=1,表示要删掉的为 1 的维度。
#生成一个大小为 100*100*3 的张量来表示一张尺寸为 100*100 的三通道彩色图片
squeeze_sample_1 = tf.random.normal([1,100,100,3])
print("原始数据尺寸:",squeeze_sample_1.shape)
squeezed_sample_1 = tf.squeeze(expand_sample_1)
print("维度压缩后的数据尺寸:",squeezed_sample_1.shape)
原始数据尺寸: (1, 100, 100, 3)
维度压缩后的数据尺寸: (100, 100, 3)
转置

tf.transpose(a,perm=None,conjugate=False,name=‘transpose’):

  • a:输入张量;
  • perm:张量的尺寸排列;一般用于高维数组的转置。
  • conjugate:表示复数转置;
  • name:名称。

低维的转置问题比较简单,输入需转置张量调用 tf.transpose

trans_sample_1 = tf.constant([1,2,3,4,5,6],shape=[2,3])
print("原始数据尺寸:",trans_sample_1.shape)
transposed_sample_1 = tf.transpose(trans_sample_1)
print("转置后数据尺寸:",transposed_sample_1.shape)
原始数据尺寸: (2, 3)
转置后数据尺寸: (3, 2)

高维数据转置需要用到 perm 参数,perm 代表输入张量的维度排列。
对于一个三维张量来说,其原始的维度排列为[0,1,2](perm)分别代表高维数据的长宽高。
通过改变 perm 中数值的排列,可以对数据的对应维度进行转置

#生成一个大小为$*100*200*3 的张量来表示 4 张尺寸为 100*200 的三通道彩色图片
trans_sample_2 = tf.random.normal([4,100,200,3])
print("原始数据尺寸:",trans_sample_2.shape)
#对 4 张图像的长宽进行对调。原始 perm 为[0,1,2,3],现变为[0,2,1,3]
transposed_sample_2 = tf.transpose(trans_sample_2,[0,2,1,3])
print("转置后数据尺寸:",transposed_sample_2.shape)
原始数据尺寸: (4, 100, 200, 3)
转置后数据尺寸: (4, 200, 100, 3)
广播(broadcast_to)

利用把 broadcast_to 可以将小维度推广到大维度。

tf.broadcast_to(input,shape,name=None):

  • input:输入张量;
  • shape:输出张量的尺寸。
broadcast_sample_1 = tf.constant([1,2,3,4,5,6])
print("原始数据:",broadcast_sample_1.numpy())
broadcasted_sample_1 = tf.broadcast_to(broadcast_sample_1,shape=[4,6])
print("广播后数据:\n",broadcasted_sample_1.numpy())
原始数据: [1 2 3 4 5 6]
广播后数据:
 [[1 2 3 4 5 6]
 [1 2 3 4 5 6]
 [1 2 3 4 5 6]
 [1 2 3 4 5 6]]

运算时,当两个数组的形状不同时,与 numpy 一样,TensorFlow 将自动触发广播机制。

#运算时,当两个数组的形状不同时,与 numpyy 一样,TensorFlow 将自动触发广播机制。
a = tf.constant([[ 0, 0, 0],
 [10,10,10],
 [20,20,20],
 [30,30,30]])
b = tf.constant([1,2,3])
print(a + b)
tf.Tensor(
[[ 1  2  3]
 [11 12 13]
 [21 22 23]
 [31 32 33]], shape=(4, 3), dtype=int32)

张量的算术运算

算术运算符

算术运算主要包括了:加(tf.add)、减(tf.subtract)、乘(tf.multiply)、除(tf.divide)、取对数
(tf.math.log)和指数(tf.pow)等。 因为调用比较简单,下面只演示一个加法例子。

a = tf.constant([[3, 5], [4, 8]])
b = tf.constant([[1, 6], [2, 9]])
print(tf.add(a, b))
tf.Tensor(
[[ 4 11]
 [ 6 17]], shape=(2, 2), dtype=int32)
矩阵乘法运算
tf.matmul(a, b)
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[13, 63],
       [20, 96]])>
张量的数据统计

张量的数据统计主要包括:

  • tf.reduce_min/max/mean():求解最小值最大值和均值函数;
  • tf.argmax()/tf.argmin():求最大最小值位置;
  • tf.equal():逐个元素判断两个张量是否相等;
  • tf.unique():除去张量中的重复元素。
  • tf.nn.in_top_k(prediction, target, K):用于计算预测值和真是值是否相等,返回一个 bool 类型的
    张量。

下面演示 tf.argmax()的用法:

返回最大值所在的下标

  • tf.argmax(input,axis):
  • input:输入张量;
  • axis:按照 axis 维度,输出最大值。
argmax_sample_1 = tf.constant([[1,3,2],[2,5,8],[7,5,9]])
print("输入张量:",argmax_sample_1.numpy())
max_sample_1 = tf.argmax(argmax_sample_1, axis=0)
max_sample_2 = tf.argmax(argmax_sample_1, axis=1)
print("按列寻找最大值的位置:",max_sample_1.numpy())
print("按行寻找最大值的位置:",max_sample_2.numpy())
输入张量: [[1 3 2]
 [2 5 8]
 [7 5 9]]
按列寻找最大值的位置: [2 1 2]
按行寻找最大值的位置: [1 2 2]

基于维度的算术操作

TensorFlow 中,tf.reduce_*一系列操作等都造成张量维度的减少。这一系列操作都可以对一个张量在
维度上的元素进行操作,如按行求平均,求取张量中所有元素的乘积等。
常用的包括:tf.reduce_sum(加法)、tf.reduce_prod(乘法)、tf.reduce_min(最小)、
tf.reduce_max(最大)、tf.reduce_mean(均值)、tf.reduce_all(逻辑和)、tf.reduce_any
(逻辑或)和 tf.reduce_logsumexp(log(sum(exp)))操作)等。

这些操作的使用方法都相似,下面只演示 tf.reduce_sum 的操作案例。

计算一个张量的各个维度上元素的总和

tf.reduce_sum(input_tensor, axis=None, keepdims=False,name=None):

  • input_tensor:输入张量;
  • axis:指定需要计算的轴,如果不指定,则计算所有元素的均值;
  • keepdims:是否降维度,设置为 True,输出的结果保持输入 tensor 的形状,设置为 False,
    输出结果会降低维度;
  • name:操作名称。
reduce_sample_1 = tf.constant([1,2,3,4,5,6],shape=[2,3])
print("原始数据",reduce_sample_1.numpy())
print("计算张量中所有元素的和(axis=None):",tf.reduce_sum(reduce_sample_1,axis=None).numpy())
print("按列计算,分别计算各列的和(axis=0):",tf.reduce_sum(reduce_sample_1,axis=0).numpy())
print("按行计算,分别计算各列的和(axis=1):",tf.reduce_sum(reduce_sample_1,axis=1).numpy())
原始数据 [[1 2 3]
 [4 5 6]]
计算张量中所有元素的和(axis=None): 21
按列计算,分别计算各列的和(axis=0): [5 7 9]
按行计算,分别计算各列的和(axis=1): [ 6 15]

张量的拼接与分割

张量的拼接

TensorFlow 中,张量拼接的操作主要包括:

  • tf.contact():将向量按指定维连起来,其余维度不变。
  • tf.stack() :将一组 R 维张量变为 R+1 维张量,拼接前后维度变化。

tf.concat(values, axis, name=‘concat’):

  • values:输入张量;
  • axis:指定拼接维度;
  • name:操作名称。
concat_sample_1 = tf.random.normal([4,100,100,3])
concat_sample_2 = tf.random.normal([40,100,100,3])
print("原始数据的尺寸分别为:",concat_sample_1.shape,concat_sample_2.shape)
concated_sample_1 = tf.concat([concat_sample_1,concat_sample_2],axis=0)
print("拼接后数据的尺寸:",concated_sample_1.shape)
原始数据的尺寸分别为: (4, 100, 100, 3) (40, 100, 100, 3)
拼接后数据的尺寸: (44, 100, 100, 3)

在原来矩阵基础上增加了一个维度,也是同样的道理,axis 决定维度增加的位置。

tf.stack(values, axis=0, name=‘stack’):

  • values:输入张量;一组相同形状和数据类型的张量。
  • axis:指定拼接维度;
  • name:操作名称。
stack_sample_1 = tf.random.normal([100,100,3])
stack_sample_2 = tf.random.normal([100,100,3])
print("原始数据的尺寸分别为:",stack_sample_1.shape, stack_sample_2.shape)
#拼接后维度增加。axis=0,则在第一个维度前增加维度。
stacked_sample_1 = tf.stack([stack_sample_1, stack_sample_2],axis=0)
print("拼接后数据的尺寸:",stacked_sample_1.shape)
原始数据的尺寸分别为: (100, 100, 3) (100, 100, 3)
拼接后数据的尺寸: (2, 100, 100, 3)
张量的分割

TensorFlow 中,张量分割的操作主要包括:

  • tf.unstack():将张量按照特定维度分解。
  • tf.split():将张量按照特定维度划分为指定的分数。

与 tf.unstack()相比,tf.split()更佳灵活。

tf.unstack(value,num=None,axis=0,name=‘unstack’):

  • value:输入张量;
  • num:表示输出含有 num 个元素的列表,num 必须和指定维度内元素的个数相等。通常可以忽略
    不写这个参数。
  • axis:指明根据数据的哪个维度进行分割;
  • name:操作名称。
#按照第一个维度对数据进行分解,分解后的数据以列表形式输出。
tf.unstack(stacked_sample_1,axis=0)

tf.split(value, num_or_size_splits, axis=0):

  • value:输入张量;
  • num_or_size_splits:准备切成几份
  • axis:指明根据数据的哪个维度进行分割。

tf.split()的分割方式有两种:

  1. 如果 num_or_size_splits 传入的是一个整数,那直接在 axis=D 这个维度上把张量平均切分成几
    个小张量。
  2. 如果 num_or_size_splits 传入的是一个向量,则在 axis=D 这个维度上把张量按照向量的元素值
    切分成几个小张量。
import numpy as np
split_sample_1 = tf.random.normal([10,100,100,3])
print("原始数据的尺寸为:",split_sample_1.shape)
splited_sample_1 = tf.split(split_sample_1, num_or_size_splits=5,axis=0)
print("当 m_or_size_splits=10,分割后数据的尺寸为:",np.shape(splited_sample_1))
splited_sample_2 = tf.split(split_sample_1, num_or_size_splits=[3,5,2],axis=0)
print("当 num_or_size_splits=[3,5,2],分割后数据的尺寸分别为:",
 np.shape(splited_sample_2[0]),
 np.shape(splited_sample_2[1]),
 np.shape(splited_sample_2[2]))
原始数据的尺寸为: (10, 100, 100, 3)
当 m_or_size_splits=10,分割后数据的尺寸为: (5, 2, 100, 100, 3)
当 num_or_size_splits=[3,5,2],分割后数据的尺寸分别为: (3, 100, 100, 3) (5, 100, 100, 3) (2, 100, 100, 3)

张量排序

TensorFlow 中,张量排序的操作主要包括:

  • tf.sort():按照升序或者降序对张量进行排序,返回排序后的张量。
  • tf.argsort():按照升序或者降序对张量进行排序,但返回的是索引。
  • tf.nn.top_k():返回前 k 个最大值。

tf.sort/argsort(input, direction, axis):

  • input:输入张量;
  • direction:排列顺序,可为 DESCENDING 降序或者 ASCENDING(升序)。默认为
    ASCENDING(升序);
  • axis:按照 axis 维度进行排序。默认 axis=-1 最后一个维度。
sort_sample_1 = tf.random.shuffle(tf.range(10))
print("输入张量:",sort_sample_1.numpy())
sorted_sample_1 = tf.sort(sort_sample_1, direction="ASCENDING")
print("生序排列后的张量:",sorted_sample_1.numpy())
sorted_sample_2 = tf.argsort(sort_sample_1,direction="ASCENDING")
print("生序排列后,元素的索引:",sorted_sample_2.numpy())
输入张量: [3 2 8 7 6 0 4 5 9 1]
生序排列后的张量: [0 1 2 3 4 5 6 7 8 9]
生序排列后,元素的索引: [5 9 1 0 6 7 4 3 2 8]

tf.nn.top_k(input,K,sorted=TRUE):

  • input:输入张量;
  • K:需要输出的前 k 个值及其索引。
  • sorted: sorted=TRUE 表示升序排列;sorted=FALSE 表示降序排列。

返回两个张量:

  • values:也就是每一行的最大的 k 个数字
  • indices:这里的下标是在输入的张量的最后一个维度的下标
values, index = tf.nn.top_k(sort_sample_1,5)
print("输入张量:",sort_sample_1.numpy())
print("升序排列后的前 5 个数值:", values.numpy())
print("升序排列后的前 5 个数值的索引:", index.numpy())
输入张量: [3 2 8 7 6 0 4 5 9 1]
升序排列后的前 5 个数值: [9 8 7 6 5]
升序排列后的前 5 个数值的索引: [8 2 3 4 7]

内容来自于华为HCIA-AI V3.0实验手册

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值