• TensorFlow基本概念与常用函数


    TensorFlow基本概念与常用函数

    本人人工智能入门小白一枚,在网上学习人工智能实践-TensorFlow2.0(北大公开课)课程,将自己学习到的东西进行整理,为方便后面复习,如有错误,烦请指出!多谢!!

    一:张量

    (一):张量概念

    TensorFlow 中的 Tensor 表示张量,即多维数组、多维列表,用阶表示张量的维数
    在这里插入图片描述

    0 阶张量叫做标量,表示的是一个单独的数,如 123

    1阶张量叫作向量,表示的是一个一维数组如[1,2,3]

    2 阶张量叫作矩阵,表示的是一个二维数组,它可以有 ij 列个元素,每个元素用它的行号和列号共同索引到,如在[[1,2,3],[4,5,6],[7,8,9]]中,2 的索引即为第 0 行第 1 列。

    张量的阶数与方括号的数量相同,0 个方括号即为 0 阶张量,1 个方括号即为 1 阶张量。故张量可以表示 0阶到 n 阶的数组

    (二):TensorFlow中的数据类型

    在这里插入图片描述

    TensorFlow 中数据类型包括 32 位整型(tf.int32)、32 位浮点(tf.float32)、64 位浮点(tf.float64)、布尔型(tf.bool)、字符串型(tf.string)

    (三):创建张量

    1、利用tf.constant()

    '''
    创建张量
        tf.constant(张量内容,dtype=数据类型(可选))
    '''
    a = tf.constant([1,5],dtype=tf.int64)   # 创建一个一维张量,,数据类型是int64
    print(a)    # tf.Tensor([1 5], shape=(2,), dtype=int64)
    print(a.dtype)  # 显示张量的数据类型 
    print(a.shape)  # 显示张量的形状 (2,)  ,2表示张量的内容有两个数据,逗号表示几维张量
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    利用 tf.constant(张量内容,dtype=数据类型(可选)),第一个参数表示张量内容,第二个参数表示张量的数据类型

    输出结果:

    <tf.Tensor([1,5], shape=(2 , ) , dtype=int64)> 
    <dtype: 'int64'>
    (2,)
    
    • 1
    • 2
    • 3

    即会输出张量内容、形状与数据类型,shape 中数字为 2,表示一维张量里有 2个元素。

    注:去掉 dtype 项,不同电脑环境不同导致默认值不同,可能导致后续程序 bug

    2、利用tf.convert_to_tensor()

    很多时候数据是由 numpy 格式给出的,此时可以通过如下函数将 numpy 格式化为 Tensor 格式

    '''
    将numpy的数据类型转换成Tensor数据类型
        使用tf.convert_to_tensor(数据名,dtype=数据类型(可选))
        
    '''
    a = np.arange(0,5)      # 生成一个0到4的numpy列表
    print(type(a))          # 此时的a是类型的数据
    b = tf.convert_to_tensor(a,dtype=tf.int64)      # tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64)
    print(a)				# 得到的是一个0-4的numpy列表:[0 1 2 3 4]
    print(b)
    
    # 输出:
    <class 'numpy.ndarray'>
    [0 1 2 3 4]
    tf.Tensor([0 1 2 3 4], shape=( 5 , ), dtype=int64)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可见,通过此函数将原本numpy格式的a数据转变成了Tensor的b数据

    3、通过不同的函数来创建不同值的张量

    tf. zeros(维度) 创建全为 0 的张量

    tf.ones(维度) 创建全为 1 的张量

    tf. fill(维度,指定值) 创建全为指定值的张量

    注意:其中维度参数部分,如一维则直接写个数,二维用[行,列]表示,多维用[n,m,j…]

    '''
    创建张量
        创建全为0的张量
        tf.zeros(维度)
        
        创建全为1的张量
        tf.one(维度)
        
        创建指定值的张量
        tf.fill(维度,指定值)
    '''
    a = tf.zeros(4)     # 创建一维张量 tf.Tensor([0. 0. 0. 0.], shape=(4,), dtype=float32)
    print(a)
    
    b = tf.ones(2)  # 创建全为1的一维张量,共有2个数据
    print(b)
    
    c = tf.ones([2,3])  # 创建两行三列的全为1的二阶张量
    print(c)
    
    d = tf.fill([2,3],4)        # 创建一个2行3列的,值为4的二阶张量
    print(d)
    
    # 输出结果
    tf.Tensor([0. 0. 0. 0.], shape=(4,), dtype=float32)
    
    tf.Tensor([1. 1.], shape=(2,), dtype=float32)
    
    tf.Tensor(
    [[1. 1. 1.]
     [1. 1. 1.]], shape=(2, 3), dtype=float32)
    
    tf.Tensor(
    [[4 4 4]
     [4 4 4]], shape=(2, 3), dtype=int32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    注意:tf.zeros()、tf.ones()这两个函数产生的数据默认是浮点型,tf.fill()函数则会根据输入的数据来判断是什么类型

    4、采用不同的函数创建符合不同分布的张量

    • 生成正态分布的随机数,默认均值为 0,标准差为 1

      • tf. random.normal (维度,mean=均值,stddev=标准差)
    • 生成截断式正态分布的随机数

      • tf. random.truncated_normal (维度,mean=均值,stddev=标准差)

      • 生成截断式正态分布的随机数,能使生成的这些随机数更集中一些,如果随机生成数据的取值在 (µ - 2σu + 2σ ) 之外则重新进行生成,保证了生成值在均值附近;µ:表示均值,σ:表示标准差

      • 标准差的计算公式:
        σ = ∑ i = 1 n ( x i − x ˉ ) 2 n \sigma = \sqrt{\frac{\sum_{i=1}^{n}{(x_i-\bar{x})}^2}{n}} σ=ni=1n(xixˉ)2

    • 生成指定维度的均匀分布随机数

      • tf. random. uniform(维度,minval=最小值,maxval=最大值)
      • 生成指定维度的均匀分布随机数,用 minval 给定随机数的最小值,用 maxval 给定随机数的最大值,最小、最大值是前闭后开区间
    '''
    创建随机张量
        生成正态分布的随机数。默认值为0,标准差为1
        tf.random.normal(维度,mean=均值,stddev =标准差)
        
        生成截断式正态分布的随机数
        tf.random.truncated_normal(维度,mean=均值,stddev=标准差)
        
        生成均匀分布的随机数
        tf.random.uniform(维度,minval=最小值,maxval=最大值)
    '''
    a = tf.random.normal([2,2],mean=0.5,stddev=1)
    print(a)
    
    b = tf.random.truncated_normal([2,2],mean=0.5,stddev=1)
    print(b)
    
    c = tf.random.uniform([2,2],minval=0,maxval=1)
    print(c)
    
    # 结果展示
    tf.Tensor(
    [[1.0505471  0.45032525]
     [1.901815   0.4857818 ]], shape=(2, 2), dtype=float32)
    
    tf.Tensor(
    [[ 0.4339631  -0.23717612]
     [ 0.07864216  2.1449685 ]], shape=(2, 2), dtype=float32)
    
    tf.Tensor(
    [[0.6278517  0.34148467]
     [0.76214504 0.15577471]], shape=(2, 2), dtype=float32)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    二:常用函数

    (一):强制转换

    利用 tf.cast (张量名,dtype=数据类型)强制将 Tensor 转换为该数据类型

    '''
    强制tensor转换成该数据类型
        tf.cast(张量名,dtype=数据类型)
    '''
    x1 = tf.constant([1.,2.,3.],dtype=tf.float64)	
    print(x1)	# 张量中的数据是64位的浮点类型
    x2 = tf.cast(x1,tf.int64)	# 将类型转变成64位整型
    print(x2)
    
    # 结果
    tf.Tensor([1. 2. 3.], shape=(3,), dtype=float64)
    tf.Tensor([1 2 3], shape=(3,), dtype=int64)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (二):张量维度上的最值

    '''
    计算张量维度上元素的最小值
        tf.reduce_min(张量名)
        
    计算张量维度上元素的最大值
        tf.reduce_max(张量名)
    '''
    print(tf.reduce_min(x2),tf.reduce_max(x2))
    
    #结果:
    tf.Tensor(1, shape=(), dtype=int64)   tf.Tensor(3, shape=(), dtype=int64)
    # 可见张量x2中的最小值为1,最大值为3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (三):理解axis

    在一个二维张量或者数组中,可以通过调整axis等于0还是等于1来控制执行维度。

    axis=0代表跨行(经度,down),而axis=1代表跨列(纬度,across)

    如果不指定axis,则默认所有元素都参与计算

    在这里插入图片描述

    • 计算张量沿着指定维度的平均值
      • tf.reduce_mean(张量名,axis=操作轴)
    • 计算张量沿着指定维度的和
      • tf.reduce_sum(张量名,axis=操作轴)
    x=tf.constant( [ [ 1, 2,3],[2, 2, 3] ] )
    print(x)
    print(tf.reduce_mean( x ))
    print(tf.reduce_sum( x, axis=1 ))
    
    # 结果:
    tf.Tensor([[1 2 3] [2 2 3]], shape=(2, 3), dtype=int32)
    tf.Tensor(2, shape=(), dtype=int32) (对所有元素求均值)
    tf.Tensor([6 7], shape=(2,), dtype=int32) (横向求和,两行分别为 67)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (四):标记变量为可训练

    利用 tf.Variable(initial_value,trainable,validate_shape,name)函数可以将变量标记为“可训练”的,被它标记了的变量,会在反向传播中记录自己的梯度信息。

    其中 initial_value 默认为 None,可以搭配 tensorflow 随机生成函数来初始化参数;

    trainable 默认为 True,表示可以后期被算法优化的,如果不想该变量被优化,即改为 False;

    validate_shape 默认为 True,形状不接受更改,如果需要更改,validate_shape=False;

    name 默认为 None,给变量确定名称。

    w = tf.Variable(tf.random.normal([2,2],mean=0,stddev=1))
    print(w)
    
    # 结果
    <tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
    array([[ 1.3795949 ,  0.15414491],
           [-0.33091652, -0.03092775]], dtype=float32)>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们训练一个网络,其实就是通过数据来训练网络中的权值和阈值,来达到一个合适的状态,使得误差最小,因此我们在初始化权值后,就要将初始化的随机权值标记成可训练的,这样就可以在反向传播中通过梯度下降来更新权值了。

    (五):常用的数学运算函数

    在这里插入图片描述

    1、四则运算

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n9UXPXvm-1660137131420)(E:\学习资料\机器学习\人工智能知识点整理\TensorFlow\TensorFlow基本概念与常用函数.assets\Image-16601266707793.png)]

    a = tf.ones([1,3])
    b = tf.fill([1,3],3.)
    print(a)
    print(b)
    print(tf.add(a,b))      # 加法运算 a + b
    print(tf.subtract(a,b))     # 减法运算 a - b
    print(tf.multiply(a,b))     # 乘法运算a*b
    print(tf.divide(a,b))       # 除法运算 a/b
    
    #结果:
    tf.Tensor([[1. 1. 1.]], shape=(1, 3), dtype=float32)
    tf.Tensor([[3. 3. 3.]], shape=(1, 3), dtype=float32)
    tf.Tensor([[4. 4. 4.]], shape=(1, 3), dtype=float32)
    tf.Tensor([[-2. -2. -2.]], shape=(1, 3), dtype=float32)
    tf.Tensor([[3. 3. 3.]], shape=(1, 3), dtype=float32)
    tf.Tensor([[0.33333334 0.33333334 0.33333334]], shape=(1, 3), dtype=float32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    只有维度相同的张量才能够做四则运算

    2、平方、次方与开方

    • 计算某个张量的平方
      • tf.square(张量名)
    • 计算某个张量的n次方
      • tf.pow(张量名,n次方数)
    • 计算某个张量的开放
      • tf.sqrt(张量名)
    '''
    平方、次方与开方
    计算某个张量的平方
        tf.square(张量名)
    计算某个张量的n次方
        tf.pow(张量名)
    计算某个张量的开放
        tf.sqrt(张量名)
    '''
    
    c = tf.fill([1,2],3.)
    print(c)
    print(tf.square(c))     # 平方计算
    print(tf.pow(c,3))      # n次方计算
    print(tf.sqrt(c))       # 开方
    
    # 结果
    tf.Tensor([[3. 3.]], shape=(1, 2), dtype=float32)
    tf.Tensor([[9. 9.]], shape=(1, 2), dtype=float32)
    tf.Tensor([[27. 27.]], shape=(1, 2), dtype=float32)
    tf.Tensor([[1.7320508 1.7320508]], shape=(1, 2), dtype=float32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3、矩阵乘

    • 实现两个矩阵的相乘
      • tf.matmul(矩阵1,矩阵2)
    '''
    实现两个矩阵的相乘,矩阵乘法遵循3*2 x 2*3
        tf.matmul(矩阵1,矩阵2)
    '''
    a = tf.fill([2,3],3.)
    b = tf.fill([3,2],2.)
    print(a)
    print(b)
    print(tf.matmul(a,b))
    # 结果
    tf.Tensor(
    [[3. 3. 3.]
     [3. 3. 3.]], shape=(2, 3), dtype=float32)
    tf.Tensor(
    [[2. 2.]
     [2. 2.]
     [2. 2.]], shape=(3, 2), dtype=float32)
    tf.Tensor(
    [[18. 18.]
     [18. 18.]], shape=(2, 2), dtype=float32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    (六):特征与标签配对

    可利用 tf.data.Dataset.from_tensor_slices((输入特征, 标签)) 切分传入张量的第一维度,生成输入特征/标签对,构建数据集,此函数对Tensor 格式与 Numpy格式均适用,其切分的是第一维度,表征数据集中数据的数量,之后切分 batch等操作都以第一维为基础。

    '''
    神经网络在训练时,是把输入特征和标签配对后喂入网络的,所以tf给出了一种把特征和标签配对的函数
    tf.data.Dataset.form_tensor_slices
    Numpy和Tensor格式的数据都可以使用该条语句读入数据
    '''
    features = tf.constant([12,23,10,17])   # 特征值
    labels = tf.constant([0,1,1,0])       # 标签
    dataset = tf.data.Dataset.from_tensor_slices((features,labels))
    print(dataset)
    for element in dataset:
        print(element)
        
    #结果:
    <TensorSliceDataset element_spec=(TensorSpec(shape=(), dtype=tf.int32, name=None), TensorSpec(shape=(), dtype=tf.int32, name=None))>
    (<tf.Tensor: shape=(), dtype=int32, numpy=12>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)
    (<tf.Tensor: shape=(), dtype=int32, numpy=23>, <tf.Tensor: shape=(), dtype=int32, numpy=1>)
    (<tf.Tensor: shape=(), dtype=int32, numpy=10>, <tf.Tensor: shape=(), dtype=int32, numpy=1>)
    (<tf.Tensor: shape=(), dtype=int32, numpy=17>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)
    '''
    可见特征值 12 与标签0进行配对,特征值 23 与标签1进行配对,同理后面特征
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    (七):计算损失函数在某一张量处的梯度

    利用 tf.GradientTape( )函数搭配 with 结构计算损失函数在某一张量处的梯度

    '''
    gradient 求出张量的梯度
        gradient(函数,对谁求导)
    
    '''
    with tf.GradientTape() as tape:
        w = tf.Variable(tf.constant(3.0))
        loss = tf.pow(w,2)			# loss = w^2
    grade = tape.gradient(loss,w) # 对loss函数,对w进行求导
    print(grade)
    
    # 结果
    tf.Tensor(6.0, shape=(), dtype=float32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上例中损失函数为:
    l o s s = w 2 loss = w^{2} loss=w2
    且当前w的取值是3,那么通过tape.gradient(loss,w)函数,将loss函数对w进行求导:即
    ∂ w 2 ∂ w = 2 w = 6 \frac{\partial w^2}{\partial w}=2w = 6 ww2=2w=6

    (八):枚举

    enumerate是python的内建函数,它可以遍历每个元素(如:列表、元组或字符串)并在元素前配上对应的索引号,常在 for 循环中使用。

    '''
    枚举类型:
    enumerate
    '''
    seq = ['one','two','three','four']
    for i,element in enumerate(seq):
        print(i,element)
        
    #结果:
    0 one
    1 two
    2 three
    3 four
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (九):独热码表示

    什么是独热码:独热码

    独热编码(one-hot encoding):在分类问题中,常用独热编码做标签,标签类别:1表示是,0表示非

    tf.one_hot(待转换数据,depth=几分类) 函数实现用独热码表示标签,在分类问题中很常见,标记类别为为 1 和 0,其中 1 表示是,0 表示非。如在鸢尾花分类任务中,如果标签是 1,表示分类结果是 1 杂色鸢尾,其用把它用独热码表示就是 0,1,0,这样可以表示出每个分类的概率:也就是百分之 0 的可能是 0狗尾草鸢尾,百分百的可能是 1 杂色鸢尾,百分之 0 的可能是弗吉尼亚鸢尾。

    '''
    独热码
        tf.one_hot()函数将待转换数据转换为one-hot形式的数据输出
        tf.one_hot(待转换数据,depth=几分类)
    '''
    classes = 3
    labels = tf.constant([1,0,2])   # 输入的数据元素0最小,2最大
    output = tf.one_hot(labels,depth=classes) # 将张量转变成独热码,3分类
    print(output)
    
    # 结果
    tf.Tensor(
    [[0. 1. 0.]			#  表示1
     [1. 0. 0.]			#  表示0
     [0. 0. 1.]], shape=(3, 3), dtype=float32)		# 表示2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以上案例为什么是这样的结果?因为张量中的数据最小是0,最大是2,即值可能是1,2,3。则可令1 0 0 表示0、0 1 0表示1、0 0 1 表示2,所以结果如上显示。

    另外,索引是从0开始的,待转换数据中各元素值应小于 depth,若带转换元素值大于等于depth,则该元素输出编码为 [0, 0 … 0, 0]。即depth 确定列数,待转换元素的个数确定行数。

    classes = 3
    labels = tf.constant([1,4,2]) # 输入的元素值 4 超出 depth-1
    output = tf.one_hot(labels,depth=classes)
    print(output)
    
    # 结果
    tf.Tensor([[0. 1. 0.] [0. 0. 0.] [0. 0. 1.]], shape=(3, 3), dtype=float32)
    # 即元素4对应的输出编码为[0. 0. 0.]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (十):softmax()

    利用 tf.nn.softmax( )函数使前向传播的输出值符合概率分布,进而与独热码形式的标签作比较

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcLUKdkD-1660137131421)(E:\学习资料\机器学习\人工智能知识点整理\TensorFlow\TensorFlow基本概念与常用函数.assets\Image-16601357310235.png)]

    由上图可知,我们已经能够计算出前传播的输出值,分别是1.01,2.01,-0.66,我们可以使用公式:
    e y i ∑ j = 0 n e y i \frac{e^{y_i}}{\sum_{j=0}^{n}{e^{y_i}}} j=0neyieyi
    来计算出对应的概率值,其中yi就是前向传播的输出值。

    '''
    tf.nn.softmax()
    该函数使得输出的数据符合概率分布
    '''
    y = tf.constant([1.01,2.01,-0.66])
    y_pro = tf.nn.softmax(y)
    print(y_pro)
    
    
    # 结果
    tf.Tensor([0.25598174 0.69583046 0.04818781], shape=(3,), dtype=float32)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果的概率值相加为1

    (十一):实现自更新

    利用 assign_sub()函数 对参数实现自更新,更新参数的值并返回,在使用此函数前需利用 tf.Variable定义变量 w为可训练(可自更新)

    '''
    自减操作
    在使用assign_sub函数前,先用tf.Variable定义变量为可训练的
    w.assign_sub(要自减的内容)
    '''
    w = tf.Variable(4)
    w.assign_sub(1)     # 相当于 w = w-1
    print(w)
    
    # 结果
    <tf.Variable 'Variable:0' shape=() dtype=int32, numpy=3>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注:直接调用 tf.assign_sub 会报错,要用 w.assign_sub。

    (十二):tf.argmax()函数

    利用 tf.argmax (张量名,axis=操作轴) 返回张量沿指定维度最大值的索引

    '''
    返回张量沿指定维度最大值的索引
    tf.argmax(张量名,axis=操作轴)
    '''
    test = np.array([[1,2,3],[2,3,4],[5,4,3],[8,7,2]])
    print(test)
    print(tf.argmax(test,axis=0))   # 返回每一列最大值的索引
    print(tf.argmax(test,axis=1))   # 返回每一行最大值的索引
    
    
    # 结果
    [[1 2 3]
     [2 3 4]
     [5 4 3]
     [8 7 2]]
    tf.Tensor([3 3 1], shape=(3,), dtype=int64)
    tf.Tensor([2 2 0 0], shape=(4,), dtype=int64)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    MFC Windows 程序设计[214]之对话框样式修改例程(附源码)
    区块链加密虚拟货币交易平台安全解决方案
    vite和webpack的对比
    c流程控制
    2015年“梦想杯”年江苏省信息与未来小学生程序设计比赛试题--加数
    2023阿里云双十一到底有没有活动?去年就没有
    Dapr学习积累(一)
    C#Winform中打印预览时设置横向打印
    mysql同时使用order by排序和limit分页数据重复问题
    基于window10的远程桌面报错:要求的函数不受支持 的问题解决方法
  • 原文地址:https://blog.csdn.net/weixin_43288447/article/details/126274568