今天和同学聚了一下,但是不能拉下学习进度,继续看第三章
本来要在昨天发了,太晚了有点麻了就没继续往后看了
使用Tensorflow中的GradientTape API,我们能够实现对一个输入张量进行一些计算,然后就可以检索计算结果相对于输入的梯度。
1-1 使用GradientTape
input_var = tf.Variable(initial_value=3.)
with tf.GradientTape() as tape:
result = tf.square(input_var)
gradient = tape.gradient(result, input_var)
如果要监视常数张量,我们必须对其调用tape.watch(),手动将其标记为被监视的张量
1-2 对常数张量输入使用GradientTape
input_const = tf.constant(3.)
with tf.GradientTape() as tape:
tape.watch(input_const)
result = tf.square(input_const)
gradient = tape.gradient(result, input_const)
1-3 利用GradinetTape实现求解二阶梯度
time = tf.Variable(0.)
with tf.GradientTape() as outer_tape:
with tf.GradientTape() as outer_tape:
position = 4.9 * time ** 2 // 相当于二分之一重力加速度乘时间的平方
speed = inner_tape.gradient(position, time)
acceleration = outer_tape.gradient(speed, time)
相当于一个求一阶导一个求二阶导
2-1 首先我们需要在二维平面上随机生成两个类别的点
num_samples_per_class = 1000
negative_samples = np.random.multivariate_normal(
mean=[0,3],
cov=[[1, 0.5],[0.5, 1]],
size=num_samples_per_class)
// 生成一千个随机点
positive_samples = np.random.multivariate_normal(
mean=[3,0],
cov=[[1, 0.5],[0.5, 1]],
size=num_samples_per_class)
//两个点阵的协方差相同,均值不同
2-2 接着我们将两个类别堆叠成一个形状为(2000,2)的数组
inputs = np.vstack((negative_samples, positive_samples)).astype(np.float32)
2-3 生成目标标签
targets = np.vstack((np.zeros((num_samples_per_class, 1), dtype="float32"),
np.ones((num_samples_per_class, 1), dtype="float32")))
2-4 绘制两个点类的图像
import matplotlib.pyplot as plt
plt.scatter(inputs[:, 0], inputs[:, 1], c = targets[:,0])
plt.show()
构建好了这两个类别的点集后,我们接下来就要通过创建一个线性分类器来学习划分这两个类别。
prediction = w * input + b 通过对模型进行训练,更新参数值,由此来使得预测值与目标值之差的平方最小化
2-5 创建线性分类器的变量
input_dim = 2
output_dim = 1
W = tf.Variable(initial_value=tf.random.uniform(shape=(input_dim, output_dim)))
b = tf.Variable(initial_value=tf.zeros(shape=(output_dim,)))
2-6 前向传播函数
def model(inputs):
return tf.matmul(inputs, W) + b
此处我们案例中的点集都只有x,y两个坐标,输入都是二维输入,所以W权重包含W1,W2。而b则是一个标量系数。所以我们的结果计算式应该是:
prediction = [ [w1], [w2] ] * [x, y] + b = w1 * x + w2 * y + b
2-7 均方误差损失函数
def square_loss(targets, predictions):
per_sample_losses = tf.square(targets - predictions)
return tf.reduce_mean(per_sample_losses)
per_sample_losses和targets、predictions变量的形状相同,所以在最后我们利用reduce_mean将损失值转换为了标量损失值
2-8 训练步骤函数
learning_rate = 0.1
def training_step(inputs, targets):
with tf.GradientTape() as tape:
predictions = model(inputs)
loss = square_loss(targets, predictions)
grad_loss_wrt_W, grad_loss_wrt_b = tape.gradient(loss, [W, b])
W.assign_sub(grad_loss_wrt_W * learning_rate)
b.assign_sub(grad_loss_wrt_b * learning_rate)
return loss
在梯度带作用域内进行前向传播,随后便可在外通过调用gradient来获取当前损失值相对于不同参数的梯度值,并在随后通过梯度和学习率更新参数值
2-9 批量训练循环
for step in range(40):
loss = training_step(inputs, targets)
print(f"Loss at step {step}: {loss:.4f}")
在训练几轮发现损失值稳定在某个值时,我们就可以绘制一下根据predictions得到的结果分布图
2-10 绘图
predictions = model(inputs)
plt.scatter(inputs[:,0], inputs[:, 1], c=predictions[:, 0] > 0.5)
plt.show()
如果属于第一类的概率大于0.5就归类为类别1,此时c=1;同理在另外一种情况归类为类别0
最后我们可以得到类别0和类别1在此处的数学定义
类别0:w1*x+w2*y+b<0.5 类别2: w1*x+w2*y+b > 0.5
那么我们便发现这其实是一条二维平面上的直线,我们要做的就是找到这条直线完成在直线两侧的分类
2-11 绘制直线
x = np.linespace(-1,4,100)
t = -W[0] / W[1] * x + (0.5 - b) / W[1]
plt.plot(x,y, "-r")
plt.scatter(inputs[:,0], inputs[:,1], c=predictions[;, 0] > 0.5)
由此绘制出了一条红色直线,并将预测结果的散点图绘制在了图中
通过这个案例进一步促进了我对分类器的工作原理了解