四、TensorFlow基础

这篇博客主要介绍了TensorFlow的基础,包括数据类型、数据精度、张量的创建与优化、索引切片、维度变换、广播机制以及数学运算。还提到了张量在深度学习中的应用,如创建随机分布的张量,以及前向传播的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

四、TensorFlow基础

内容参考来自https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book开源书籍《TensorFlow2深度学习》,这只是我做的简单的学习笔记,方便以后复习

1.数据类型

数值类型的张量是 TensorFlow 的主要数据载体,根据维度数来区分,可分为:标量(Scalar),向量(Vector),矩阵(Matrix),张量(Tensor)

# tensor和Numpy相互转换
import tensorflow as tf
a = 1.2 # python 语言方式创建标量
aa = tf.constant(1.2) # TF 方式创建标量
type(a), type(aa), tf.is_tensor(aa) # (float, tensorflow.python.framework.ops.EagerTensor, True)
aa.numpy() # 1.2

2. 数据精度

常用的精度类型有 tf.int16、tf.int32、tf.int64、tf.float16、tf.float32、tf.float64 等,其中 tf.float64 即为 tf.double。

# 创建指定精度的张量
tf.constant(123456789, dtype=tf.int16)

类型转换

a = tf.constant(np.pi, dtype=tf.float16) # 创建 tf.float16 低精度张量
tf.cast(a, tf.double) # 转换为高精度张量

a = tf.constant([True, False])
tf.cast(a, tf.int32) # 布尔类型转整型 numpy=array([1, 0])

3.待优化张量

为了区分需要计算梯度信息的张量与不需要计算梯度信息的张量,TensorFlow 增加了一种专门的数据类型来支持梯度信息的记录:tf.Variable。

a = tf.constant([-1, 0, 1, 2]) # 创建 TF 张量
aa = tf.Variable(a) # 转换为 Variable 类型
aa.name, aa.trainable # Variable 类型张量的属性 ('Variable:0', True)

4.创建张量

通过 tf.convert_to_tensor 函数可以创建新 Tensor,并将保存在 Python List 对象或者Numpy Array 对象中的数据导入到新 Tensor 中。

tf.convert_to_tensor([1,2.]) # 从列表创建张量

实际上,tf.constant()和 tf.convert_to_tensor()都能够自动的把 Numpy 数组或者 Python列表数据类型转化为 Tensor 类型,这两个 API 命名来自 TensorFlow 1.x 的命名习惯,在TensorFlow 2 中函数的名字并不是很贴切,使用其一即可。

特殊张量的创建

tf.zeros([2,2]) # 创建全 0 矩阵,指定 shape 为 2 行 2 列
tf.ones([3,2]) # 创建全 1 矩阵,指定 shape 为 3 行 2 列

a = tf.ones([2,3]) # 创建一个矩阵
tf.zeros_like(a) # 创建一个与 a 形状相同,但是全 0 的新矩阵

a = tf.zeros([3,2]) # 创建一个矩阵
tf.ones_like(a) # 创建一个与 a 形状相同,但是全 1 的新矩阵

tf.fill([2,2], 99) # 创建 2 行 2 列,元素全为 99 的矩阵

创建已知分布的张量

通过 tf.random.normal(shape, mean=0.0, stddev=1.0)可以创建形状为 shape,均值为mean,标准差为 stddev 的正态分布𝒩(mean,stddev^2 )。

 tf.random.normal([2,2]) # 创建标准正态分布的张量
 tf.random.normal([2,2], mean=1,stddev=2) # 创建正态分布的张量

通过 tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自[minval,maxval)区间的均匀分布的张量。

tf.random.uniform([2,2]) # 创建采样自[0,1)均匀分布的矩阵
tf.random.uniform([2,2],maxval=10) # 创建采样自[0,10)均匀分布的矩阵
tf.random.uniform([2,2],maxval=100,dtype=tf.int32) # # 创建采样自[0,100)均匀分布的整型矩阵

5.张量的典型应用

6.索引与切片

切片方式 意义

# 切片方式  意义
# start::end:step  从 start 开始读取到 end(不包含 end),步长为 step
# start:end  从 start 开始读取到 end(不包含 end),步长为 1
# start:  从 start 开始读取完后续所有元素,步长为 1
# start::step  从 start 开始读取完后续所有元素,步长为 step
# :end:step  从 0 开始读取到 end(不包含 end),步长为 step
# :end  从 0 开始读取到 end(不包含 end),步长为 1
# ::step  步长为 step 采样
# ::  读取所有元素
# :  读取所有元素
# 切片方式  意义
# a,⋯,b  a 维度对齐到最左边,b 维度对齐到最右边,中间的维度全部读取,其他维度按 a/b 的方式读取
# a,⋯  a 维度对齐到最左边,a 维度后的所有维度全部读取,a 维度按 a 方式读取。这种情况等同于 a 索引/切片方式
# ⋯,b  b 维度对齐到最右边,b 之前的所有维度全部读取,b 维度按 b 方式读取
# ⋯  读取张量所有数据

7.维度变换

基本的维度变换操作函数包含了改变视图 reshape、插入新维度 expand_dims,删除维度 squeeze、交换维度 transpose、复制数据 tile 等函数。

改变视图tf.reshape

x=tf.range(96) # 生成向量
x=tf.reshape(x,[2,4,4,3]) # 改变 x 的视图,获得 4D 张量,存储并未改变

增加维度tf.expand_dims(x, axis)和删除维度 tf.squeeze(x, axis)

# 产生矩阵
x = tf.random.uniform([28,28],maxval=10,dtype=tf.int32)
x = tf.expand_dims(x,axis=2) # axis=2 表示宽维度后面的一个维度 > shape=(28, 28, 1)
x = tf.expand_dims(x,axis=0) # 高维度之前插入新维度 > shape=(1, 28, 28, 1)

x = tf.squeeze(x, axis=0) # 删除图片数量维度 > shape=(28, 28, 1)
# 如果不指定维度参数 axis,即 tf.squeeze(x),那么它会默认删除所有长度为 1 的维度
x = tf.random.uniform([1,28,28,1],maxval=10,dtype=tf.int32)
tf.squeeze(x) # 删除所有长度为 1 的维度 > shape=(28, 28)

交换维度(Transpose(x, perm))

x = tf.random.normal([2,32,32,3])
tf.transpose(x,perm=[0,3,1,2]) # 交换维度 > shape=(2, 3, 32, 32)

复制数据:可以通过 tf.tile(x, multiples)函数完成数据在指定维度上的复制操作,multiples 分别指定了每个维度上面的复制倍数,对应位置为 1 表明不复制,为 2 表明新长度为原来长度的2 倍,即数据复制一份,以此类推。

b = tf.constant([1,2]) # 创建向量 b  shape=(2,)
b = tf.expand_dims(b, axis=0) # 插入新维度,变成矩阵 shape=(1, 2)
b = tf.tile(b, multiples=[2,1]) # 样本维度上复制一份 shape=(2, 2) numpy=array([[1, 2],[1, 2]])

8.Broadcasting

tf.broadcast_to(x, new_shape)函数可以显式地执行自动扩展功能,将现有 shape 扩张为 new_shape

A = tf.random.normal([32,1]) # 创建矩阵
tf.broadcast_to(A, [2,32,32,3]) # 扩展为 4D 张量

9.数学运算

矩阵相乘:根据矩阵相乘的定义,𝑩和𝑪能够矩阵相乘的条件是,𝑩的倒数第一个维度长度(列)和𝑪的倒数第二个维度长度(行)必须相等。

a = tf.random.normal([4,3,28,32])
b = tf.random.normal([4,3,32,2])
a@b # 批量形式的矩阵相乘  得到 shape 为[4,3,28,2]

a = tf.random.normal([4,28,32])
b = tf.random.normal([32,16])
tf.matmul(a,b) # 先自动扩展,再矩阵相乘 得到 shape 为[4,28,16]

10. 前向传播实战

import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.keras.datasets as datasets

plt.rcParams['font.size'] = 16
plt.rcParams['font.family'] = ['STKaiti']
plt.rcParams['axes.unicode_minus'] = False


def load_data():
    # 加载 MNIST 数据集
    (x, y), (x_val, y_val) = datasets.mnist.load_data()
    # 转换为浮点张量, 并缩放到-1~1
    x = tf.convert_to_tensor(x, dtype=tf.float32) / 255.
    # 转换为整形张量
    y = tf.convert_to_tensor(y, dtype=tf.int32)
    # one-hot 编码
    y = tf.one_hot(y, depth=10)

    # 改变视图, [b, 28, 28] => [b, 28*28]
    x = tf.reshape(x, (-1, 28 * 28))

    # 构建数据集对象
    train_dataset = tf.data.Dataset.from_tensor_slices((x, y))
    # 批量训练
    train_dataset = train_dataset.batch(200)
    return train_dataset


def init_paramaters():
    # 每层的张量都需要被优化,故使用 Variable 类型,并使用截断的正太分布初始化权值张量
    # 偏置向量初始化为 0 即可
    # 第一层的参数
    w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
    b1 = tf.Variable(tf.zeros([256]))
    # 第二层的参数
    w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
    b2 = tf.Variable(tf.zeros([128]))
    # 第三层的参数
    w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
    b3 = tf.Variable(tf.zeros([10]))
    return w1, b1, w2, b2, w3, b3


def train_epoch(epoch, train_dataset, w1, b1, w2, b2, w3, b3, lr=0.001):
    for step, (x, y) in enumerate(train_dataset):
        with tf.GradientTape() as tape:
            # 第一层计算, [b, 784]@[784, 256] + [256] => [b, 256] + [256] => [b,256] + [b, 256]
            h1 = x @ w1 + tf.broadcast_to(b1, (x.shape[0], 256))
            h1 = tf.nn.relu(h1)  # 通过激活函数

            # 第二层计算, [b, 256] => [b, 128]
            h2 = h1 @ w2 + b2
            h2 = tf.nn.relu(h2)
            # 输出层计算, [b, 128] => [b, 10]
            out = h2 @ w3 + b3

            # 计算网络输出与标签之间的均方差, mse = mean(sum(y-out)^2)
            # [b, 10]
            loss = tf.square(y - out)
            # 误差标量, mean: scalar
            loss = tf.reduce_mean(loss)

            # 自动梯度,需要求梯度的张量有[w1, b1, w2, b2, w3, b3]
            grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])

        # 梯度更新, assign_sub 将当前值减去参数值,原地更新
        w1.assign_sub(lr * grads[0])
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])
        w3.assign_sub(lr * grads[4])
        b3.assign_sub(lr * grads[5])

        if step % 100 == 0:
            print(epoch, step, 'loss:', loss.numpy())

    return loss.numpy()


def train(epochs):
    losses = []
    train_dataset = load_data()
    w1, b1, w2, b2, w3, b3 = init_paramaters()
    for epoch in range(epochs):
        loss = train_epoch(epoch, train_dataset, w1, b1, w2, b2, w3, b3, lr=0.001)
        losses.append(loss)

    x = [i for i in range(0, epochs)]
    # 绘制曲线
    plt.plot(x, losses, color='blue', marker='s', label='训练')
    plt.xlabel('Epoch')
    plt.ylabel('MSE')
    plt.legend()
    plt.savefig('MNIST数据集的前向传播训练误差曲线.png')
    plt.close()


if __name__ == '__main__':
    train(epochs=20)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

coder_jyz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值