1.正态分布和高斯分布
正态分布(Normal Distribution)和高斯分布(Gaussian Distribution)实际上指的是同一个概率分布,在统计学和概率论中是最常见和最重要的连续概率分布之一。这两个术语可以互换使用,但“高斯分布”这个名字是为了纪念德国数学家卡尔·弗里德里希·高斯(Carl Friedrich Gauss),他首次详细研究了这种分布。
正态分布有几个关键的特性:
1. **对称性**:正态分布的图形呈钟形曲线,关于均值μ对称。曲线的最高点位于均值处。
2. **均值(Mean)**:记为μ,表示分布的中心位置。均值决定了分布曲线的中心在哪里。
3. **方差(Variance)**:记为σ²,是衡量分布数据点离散程度的指标。标准差σ是方差的平方根,它决定了分布曲线的宽度。较小的标准差意味着数据点更紧密地聚集在均值周围;较大的标准差意味着数据点更分散。
4. **密度函数**:正态分布的概率密度函数由下式给出:
\[
f(x | \mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)
\]
这个函数描述了在任意给定值x处,随机变量出现的概率密度。
5. **68-95-99.7规则(经验法则)**:在正态分布中,大约68%的数据点落在距离均值一个标准差(μ±σ)的范围内,约95%的数据点落在两个标准差(μ±2σ)内,约99.7%的数据点落在三个标准差(μ±3σ)内。
正态分布的重要性在于许多自然现象和社会科学现象都近似服从正态分布,而且在大样本条件下,很多随机变量的分布会趋向于正态分布,这是中心极限定理的基础。此外,正态分布也是统计推断和数据建模中广泛使用的工具。在机器学习和数据科学中,正态分布经常被用来初始化神经网络的权重,或者在生成数据时作为基础的概率模型。
2.回归问题
#接下来是第二章回归问题的内容,y = 1.477x+0.089+E
#1.定义采样数据
#保存样本集的列表
import numpy as np
data = []
#循环采样100个点
for i in range(100):
#随机采样输入x
x = np.random.uniform(-10.,10.)
#采样高斯噪声
eps = np.random.normal(0.,0.01)
#得到模型的输出
y = 1.477 * x + 0.089 + eps
#保存数据到列表中
data.append([x,y])
#转换为2D Numpy数组
data = np.array(data)
#2.计算误差,计算真实值和预测值直接差的平方和并累加
#首先定义函数
def mse(b,w,points):
#根据当前的w,b参数计算均方差损失
totalError = 0
#循环迭代所有点
for i in range(0,len(points)):
#获得i号点的输入x
x = points[i,0]
#获得i号点的输入y
#计算差的平方,并累加
totalError += (y -(w * x +b)) ** 2
#将累加的误差求平均,得到均方差
return totalError/float(len(points))
#3.计算梯度,求出一次遍历的w和b
def step_gradient(b_current,w_current,points,lr):
#计算误差函数在所有定上的导数,并更新w,b
b_gradient = 0
w_gradient = 0
#总样本数
M = float(len(points))
for i in range(0,len(points)):
x = points[i,0]
y = points[i,1]
#误差函数对b的导数:grad_b = 2(wx+b-y)
b_gradient += (2/M) * ((w_current *x +b_current)-y)
#误差函数对w的导数:grad_w = 2(wx+b-y)*x
w_gradient += (2/M) * x * ((w_current * x + b_current)-y)
#根据梯度下降算法更新w和b的导数,其中lr为学习率
new_b = b_current - (lr * b_gradient)
new_w = w_current - (lr * w_gradient)
return [new_b,new_w]
#4.梯度更新,第三步中算出样本循环一次epoch,接下来算出循环num次
def gradient_descent(points,starting_b,starting_w,lr,num_iterations):
#循环更新w,b多次
#b的初始值
b = starting_b
#w的初始值
w = starting_w
#根据梯度下降算法更新多次
for step in range(num_iterations):
#计算梯度并更新一次
b,w = step_gradient(b,w,np.array(points),lr)
#计算当前的均方差,用于监控训练进度
loss = mse(b,w,points)
#打印误差和实时的w,b值
if step %50 == 0:
print(f"iteration:{step},loss:{loss},w:{w},b:{b}")
#返回最后一次的w,b
return [b,w]
#主训练函数实现
def main():
#加载训练集数据,这些数据是通过真实模型添加观测误差采样得到的
#学习率
lr = 0.001
#初始化b为0
initial_b = 0
#初始化w为0
initial_w = 0
num_iterations = 1000
#循环优化1000次,返回最优w*,b*和训练loss的下降过程
[b,w] = gradient_descent(data,initial_b,initial_w,lr,num_iterations)
#计算最优数值解w,b上的均方差
loss = mse(b,w,data)
print(f'Final loss:{loss},w:{w},b:{b}')
# 调用主函数
if __name__ == "__main__":
main()
运行结果:
3.分类问题
手写体训练:
import os
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers,optimizers,datasets
(x,y),(x_val,y_val) = datasets.mnist.load_data()
x = 2*tf.convert_to_tensor(x,dtype=tf.float32)/255.-1
y = tf.one_hot(y,depth=10)
print(x.shape,y.shape)
train_dataset = tf.data.Dataset.from_tensor_slices((x,y))
train_dataset = train_dataset.batch(512)
这段代码使用了 TensorFlow 和 Keras 库来加载和预处理 MNIST 数据集。MNIST 数据集是一个包含 60000 个训练样本和 10000 个测试样本的手写数字图像数据集,每个样本是一个 28x28 像素的灰度图像,对应一个 0 到 9 之间的数字标签。下面是对这段代码的详细解释:
```python
import os
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets
# 加载 MNIST 数据集
(x, y), (x_val, y_val) = datasets.mnist.load_data()
```
1. 导入必要的库:导入 `os` 库(尽管在这段代码中未使用),导入 TensorFlow 及其子模块 Keras,以及 Keras 中的 `layers`, `optimizers`, 和 `datasets`。
2. 加载 MNIST 数据集:使用 `datasets.mnist.load_data()` 函数加载 MNIST 数据集。该函数返回两个元组 `(x, y)` 和 `(x_val, y_val)`,分别表示训练数据和验证(测试)数据。
- `x` 和 `x_val` 是形状为 `(60000, 28, 28)` 和 `(10000, 28, 28)` 的 NumPy 数组,包含训练和验证样本的图像数据。
- `y` 和 `y_val` 是形状为 `(60000,)` 和 `(10000,)` 的 NumPy 数组,包含对应的标签。
```python
x = 2 * tf.convert_to_tensor(x, dtype=tf.float32) / 255. - 1
y = tf.one_hot(y, depth=10)
print(x.shape, y.shape)
```
3. 预处理训练数据:
- 归一化图像数据:将 `x` 转换为 TensorFlow 张量并进行归一化处理。归一化操作将像素值从范围 `[0, 255]` 缩放到 `[-1, 1]`。这有助于加速神经网络的训练并提高性能。
- `tf.convert_to_tensor(x, dtype=tf.float32)` 将 `x` 转换为 TensorFlow 张量,数据类型为 `tf.float32`。
- `2 ... / 255. - 1` 将像素值从 `[0, 255]` 缩放到 `[-1, 1]`。
- 标签数据 One-Hot 编码:将 `y` 转换为 one-hot 编码格式。这种格式在分类任务中很常用,其中每个标签表示为一个长度为 10 的向量,其中只有一个位置为 1,其余为 0。
- `tf.one_hot(y, depth=10)` 将标签转换为 one-hot 编码格式,10 表示分类数。
```python
train_dataset = tf.data.Dataset.from_tensor_slices((x, y))
train_dataset = train_dataset.batch(512)
```
4. 创建训练数据集:
- 使用 TensorFlow 的 `tf.data.Dataset` API 从张量中创建数据集对象。
- `tf.data.Dataset.from_tensor_slices((x, y))` 将图像数据 `x` 和标签数据 `y` 合并为一个数据集,其中每个样本是一个 `(image, label)` 对。
- 批处理数据:将数据集分批,每批包含 512 个样本。这有助于在训练神经网络时提高计算效率。
- `train_dataset.batch(512)` 将数据集分成大小为 512 的批次。
总结起来,这段代码的作用是加载 MNIST 数据集并对其进行预处理(包括归一化和 one-hot 编码),然后创建一个按批处理的数据集对象,为后续的模型训练做好准备。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets
# 加载 MNIST 数据集
(x, y), (x_val, y_val) = datasets.mnist.load_data()
x = 2 * tf.convert_to_tensor(x, dtype=tf.float32) / 255. - 1
y = tf.convert_to_tensor(y, dtype=tf.int64) # 确保标签是整数类型
# 创建数据集并批处理
train_dataset = tf.data.Dataset.from_tensor_slices((x, y))
train_dataset = train_dataset.batch(512)
# 定义模型
model = keras.Sequential([
layers.Dense(256, activation='relu'),
layers.Dense(256, activation='relu'),
layers.Dense(10)
])
# 定义优化器
optimizer = optimizers.Adam()
# 模型训练
for step, (x_batch, y_batch) in enumerate(train_dataset):
with tf.GradientTape() as tape:
# 打平操作,[b, 28, 28] => [b, 784]
x_batch = tf.reshape(x_batch, (-1, 28*28))
# 得到模型输出,[b, 784] => [b, 10]
out = model(x_batch)
# [b] => [b, 10]
y_onehot = tf.one_hot(y_batch, depth=10)
# 计算平方差损失,[b, 10]
loss = tf.square(out - y_onehot)
# 计算每个样本的平均误差
loss = tf.reduce_mean(loss)
# 计算参数的梯度
grads = tape.gradient(loss, model.trainable_variables)
# 应用梯度,更新网络参数
optimizer.apply_gradients(zip(grads, model.trainable_variables))
if step % 100 == 0:
print(f'Step {step}, Loss: {loss.numpy()}')
x = tf.random.normal([2,4])
w = tf.ones([4,3])
b = tf.zeros([3])
o = x@w+b
o
这段代码使用TensorFlow创建了一个简单的线性变换`wx + b`,其中`x`是一个随机生成的张量,`w`是一个全1的权重张量,`b`是一个全0的偏置张量。下面是对每行代码的解释:
1. **`x = tf.random.normal([2, 4])`**:
- 这一行创建了一个形状为`(2, 4)`的张量`x`,其中的元素从标准正态分布中随机抽取。这意味着`x`将包含2行4列的随机数。
2. **`w = tf.ones([4, 3])`**:
- 这一行创建了一个形状为`(4, 3)`的张量`w`,其中所有元素都是1。这意味着`w`将包含4行3列的1。
3. **`b = tf.zeros([3])`**:
- 这一行创建了一个形状为`(3,)`的张量`b`,其中所有元素都是0。这意味着`b`将包含3个0。
4. **`o = x @ w + b`**:
- 这一行计算了线性变换`wx + b`的结果,并将结果存储在张量`o`中。
- `x @ w`使用矩阵乘法运算符`@`来计算`x`和`w`的矩阵乘积。由于`x`的形状是`(2, 4)`,而`w`的形状是`(4, 3)`,所以它们的乘积将是`(2, 3)`的张量。
- `+ b`将张量`b`(形状为`(3,)`)广播到与乘积张量相同形状,即`(2, 3)`,然后进行逐元素相加。
5. **`o`**:
- 最终的张量`o`将是形状为`(2, 3)`的张量,其中每个元素是相应位置的`wx`乘积加上偏置`b`。
### 示例代码:
```python
import tensorflow as tf
# 创建一个形状为(2, 4)的张量,元素从标准正态分布中随机抽取
x = tf.random.normal([2, 4])
# 创建一个形状为(4, 3)的张量,所有元素都是1
w = tf.ones([4, 3])
# 创建一个形状为(3,)的张量,所有元素都是0
b = tf.zeros([3])
# 计算线性变换wx + b的结果
o = x @ w + b
# 输出结果张量
print("Resulting tensor o:", o.numpy())
```
当你运行这段代码时,它将输出形状为`(2, 3)`的张量`o`,其中的每个元素是相应位置的`wx`乘积加上偏置`b`。由于`x`中的元素是随机生成的,因此每次运行这段代码时,输出的张量`o`将会有所不同。