简单的入门例子
这个例子就是取一些数据集, 很简单,热个身,稍微熟悉一下 写法即可
python
from tensorflow.keras.datasets import mnist
if __name__ == '__main__':
# train 代表训练集 test 代表测试集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# (60000, 28, 28)
print(train_images.shape)
# 60000
print(len(train_labels))
print(train_labels)
print("------------------------------")
print(test_images.shape)
print(len(test_labels))
print(test_labels)
熟悉一下 深度学习的基本写法
这个例子就是简单的 根据图像,来预测 图像内容是 数字几
也是熟悉基本概念,不需要弄懂 每行调用到底干啥
python
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist
if __name__ == '__main__':
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# layer 就理解成过滤器,进去一些数据,出来的数据变的更加有用
model = keras.Sequential([
layers.Dense(512, activation='relu'),
# 返回一个数组,长度为10,和为1,其实就是每个数字的概率值,每个概率值表示当前数字图像 属于10个数字类别中的某一个的概率
layers.Dense(10, activation="softmax")
])
# 这个步骤是预处理
# optimizer 优化器, 基于训练数据自我更新模型,目的是提高模型性能
# loss 损失函数,衡量在训练数据上的性能,引导自己朝着正确的方向前进
# metrics 训练和测试过程中需要关心的指标, 我们这个数字的例子 只关心精度,即正确分类的图像的占比
model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# 之前的数据是 uint8类型的数组中,其形状为 (60000,28,28) 取值区间为 [0,255]
# 变为 60000,28*28 取值范围为[0,1]
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
# 开始训练模型/拟合模型
# 469/469 [==============================] - 1s 2ms/step - loss: 0.0377 - accuracy: 0.9891
# loss 代表损失值,acc 代表精度
model.fit(train_images, train_labels, epochs=5, batch_size=128)
test_digits = test_images[0:10]
# 这个数组中每个索引为i的数组 对应着 数字图像属于 i的概率
pred = model.predict(test_digits)
# 这个打印 位置为7的 值是9.9993300 代表为7的概率几乎等于1了
print(pred[0])
# 实际这个测试数据的值也确实为7
print(test_labels[0])
# 在数据上评估新模型
test_loss, test_acc = model.evaluate(test_images, test_labels)
# 这里测试精度比训练精度低,正常现象, 一般称之为 overfit 毕竟训练数据 等于是你做过的卷子了
print(f"Test acc: {test_acc:}")
向量与张量 轴
这一章就要仔细弄懂每个细节了
python
import numpy as np
if __name__ == '__main__':
# 仅包含一个数字 叫 标量
# 也可以叫 0阶张量 或者 0维张量
x0 = np.array(12)
print(x0)
# ndim 属性 查看numpy 张量 轴的个数, 也叫rank
# 显然这里 的输出是0
print(x0.ndim)
print("-----------------")
# 数字组成的数组 叫 向量(vector)
# 也叫 1阶张量,1维张量
x1 = np.array([1, 2, 3, 5, 6])
print(x1)
# rank 也就是轴的值1
# 这里概念很容易混淆,不要把5维向量和5维张量 混为一谈, 5维向量 只有一个1轴,这个轴的方向有5个维度
# 而 5维张量 有5个轴,每个轴的 维度可能有个n个
print(x1.ndim)
print("-----------------")
# 向量组成的数组叫做矩阵, 也叫 2维张量,2阶张量
# 其实就是程序里的 2维数组了
x2 = np.array([[1, 2, 3], [3, 4, 5]])
print(x2)
# 输出为2
print(x2.ndim)
print("-----------------")
# 将多个矩阵打包成一个新的数组,就可以得到一个 3rank的张量
# 将多个3阶张量 打包成一个数组 就可以得到 一个4rank的张量,以此类推
x3 = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
print(x3.ndim)
# 形状的概念: 前面的矩阵 形状就是 (3,5) 3阶张量的形状为 (3,3,5) 向量的形状就是 (5,)标量的形状就是空了()
为了加深一下理解 ,我们基于前面的 mnist数据 来感受下
python
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
if __name__ == '__main__':
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 3
print(train_images.ndim)
# 输出形状为 (60000, 28, 28)
print(train_images.shape)
# 类型为 uint8
print(train_images.dtype)
# 总结一下,这个train_images 就是3阶张量,一共有60000个矩阵, 每个矩阵是28*28个整数组成
# 每个矩阵 都是一张灰度图像,元素取值在0~255
# ------------------------------------------------------
# 显示第5个数字
digit = train_images[4]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
print(train_labels[4])
显示的图像为
在numpy中操作张量
ini
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
if __name__ == '__main__':
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 选择第 10~100个数字,不包括第100个
s1 = train_images[10:100]
print(s1.shape)
# 和s1的写法保持一致
s2 = train_images[10:100, :, :]
print(s2.shape)
# 和前面2个意思一样
s3 = train_images[10:100, 0:28, 0:28]
# 做点骚操作,选择图片中心的位置区域
# 负数索引表示与当前轴终点的相对位置
s4 = train_images[:, 7:-7, 7:-7]
digit = s4[4]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
对应的图
数据批量
深度学习一般都是一次处理 小批量的数据,会把数据拆分成小数据。 一般来说 深度学习中的所有数据张量的第一个轴 都是样本轴,也就是样本维度
例如
ini
batch = train_images[:128]
batch2 = train_images[128:256]
常用的数据张量
一般来说,图像数据 为4阶张量, samples,height,width,channels 视频为5阶张量 时间序列数据为三阶张量
最常见的就是向量数据 (samples,features) 2阶张量,每个样本都是一个数值张量
这里大家有点印象即可
逐元素运算
前面的代码中有一个relu的东西
这东西其实就是逐元素运算。
ini
import numpy as np
if __name__ == '__main__':
# 随机一个2行3列的 矩阵
x = np.random.random((2, 3))
print(x)
# 显然值为2
print(x.ndim)
执行结果
ini
import numpy as np
if __name__ == '__main__':
# 随机一个2行3列的 矩阵
x = np.random.random((2, 3))
y = np.random.random((2, 3))
print(x)
print(y)
# 逐元素运算,
z = x + y
# 选择最大的值,如果计算出来<0 那么也算0 不允许负值
z = np.maximum(z, 0.)
print(z)
广播
如果张量的轴数不一样,那么如何做逐元素运算呢?一个二阶张量 和一个 1阶张量 相加?怎么搞? 一般而言,我们会 把较小的张量 拿来做广播, 其实就是 把1阶张量 给 做成 2阶张量 再相加
css
import numpy as np
if __name__ == '__main__':
x = np.random.random((2, 3))
y = np.random.random((3,))
print("x.shape:{}".format(x.shape))
print("y.shape:{}".format(y.shape))
print("x:{}".format(x))
print("y:{}".format(y))
# 向y天假 第一个轴, 这样y就变成了 1,10
y = np.expand_dims(y, axis=0)
print("y:{}".format(y))
print("y.shape:{}".format(y.shape))
# 将y 沿着这个新轴重复2次,这样就可以得到 y2的 形状为 2,3
y2 = np.concatenate([y] * 2, axis=0)
print("y2:{}".format(y2))
print("y2.shape:{}".format(y2.shape))
np库中 有更方便的函数 来辅助我们做这件事 如果一个张量的形状是 a,b,c,.....n,n+1,m 而另外一个张量的形状为 n,n+1,m 则广播可以自动生效
上面的例子可以改成
lua
import numpy as np
if __name__ == '__main__':
x = np.random.random((2, 3))
y = np.random.random((3,))
z = np.maximum(x, y)
print("x.shape:{}".format(x.shape))
print("y.shape:{}".format(y.shape))
print("x:{}".format(x))
print("y:{}".format(y))
print("z:{}".format(z))
print("z.shape:{}".format(z.shape))
张量积
lua
if __name__ == '__main__':
x = np.random.random((3,))
y = np.random.random((3,))
print("x.shape:{}".format(x.shape))
print("y.shape:{}".format(y.shape))
print("x:{}".format(x))
print("y:{}".format(y))
# 点积 和 逐元素运算 完全不同
z = np.dot(x, y)
print("z.shape:{}".format(z.shape))
print("z:{}".format(z))
换一种写法
lua
import numpy as np
if __name__ == '__main__':
x = np.random.random((3,1))
y = np.random.random((1,6))
print("x.shape:{}".format(x.shape))
print("y.shape:{}".format(y.shape))
print("x:{}".format(x))
print("y:{}".format(y))
# 点积 和 逐元素运算 完全不同
z = np.dot(x, y)
print("z.shape:{}".format(z.shape))
print("z:{}".format(z))
点积 大家只要记住 dot(X,Y)肯定不等于 dot(Y,X)除非是2个 rank=1的张量
点积的运算是有条件限制的,即 x的行一定要等于y的 列
张量变形 reshape
这个其实就比较简单了
lua
import numpy as np
if __name__ == '__main__':
x = np.array([[0., 1.], [2., 3.], [4., 5.]])
print("x.shape:{}".format(x.shape))
print("x:{}".format(x))
x = x.reshape((6, 1))
print("x:{}".format(x))
x = x.reshape((2, 3))
print("x:{}".format(x))
x = np.zeros((300, 200))
# 这是一种特殊的变形,其实就是 把矩阵的行和列互换位置
x = np.transpose(x)
print("x.shape:{}".format(x.shape))
总结
所谓的模型 就是许多层 链接在一起组成,并且将输入值 映射为 预测值。 随后, 损失函数将这些预测值与目标值进行比较,得到一个损失值,用于衡量模型预测值 与预期结果之间的匹配程度。 最后优化器 将利用这个损失值 来更新模型的权重。
深度学习模型由简单的张量运算链接而成,权重为参数,权重本身就是张量。