import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
def model(inputs):
return tf.matmul(inputs, W) + b
def square_loss(targets, predictions):
per_sample_losses = tf.square(targets - predictions)
return tf.reduce_mean(per_sample_losses)
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
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)
inputs = np.vstack((negative_samples, positive_samples)).astype(np.float32)
targets = np.vstack((np.zeros((num_samples_per_class, 1), dtype="float32"),
np.ones((num_samples_per_class, 1), dtype="float32")))
plt.scatter(inputs[:, 0], inputs[:, 1], c=targets[:, 0])
plt.show()
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,)))
for step in range(40):
loss = training_step(inputs, targets)
print(f"Loss at step {step}: {loss:.4f}")
predictions = model(inputs)
plt.scatter(inputs[:, 0], inputs[:, 1], c=predictions[:, 0] > 0.5)
plt.show()
x = np.linspace(-1, 4, 100)
y = - 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)
plt.show()
效果图:
【代码分析】
这段代码实现了一个简单的线性分类器,用于二分类问题。主要使用了 TensorFlow 库进行实现。
以下是代码的主要部分和它们的功能:
1. 定义模型:model 函数定义了一个线性模型,输入乘以权重 W 加上偏置 b。
2. 定义损失函数:square_loss 函数定义了平方损失函数,计算目标值和预测值之间的差的平方的均值。
3. 定义训练步骤:training_step 函数定义了一步训练过程,包括前向传播、计算损失、反向传播和更新权重。
4. 生成训练数据:生成了两类样本,每类样本1000个,分别从两个二维正态分布中采样。
5. 初始化模型参数:初始化了权重 W 和偏置 b。
6. 训练模型:进行了40轮训练,每轮训练都会计算损失并更新权重。
7. 测试模型:使用训练数据对模型进行了测试,并绘制了分类结果。
8. 绘制决策边界:计算了决策边界的方程,并在图中绘制了决策边界。
这段代码的主要目的是展示如何使用 TensorFlow 实现一个简单的线性分类器,并用它进行二分类问题的训练和测试。
【该分类器和svm的区别】
这个线性分类器和支持向量机(SVM)都是用于进行二分类任务的模型,但它们在模型构造和优化目标上有一些不同:
1. 模型构造:这个线性分类器是一个简单的线性模型,它直接将输入特征与权重相乘,然后加上偏置,得到预测结果。而 SVM 不仅包括线性 SVM,还有非线性 SVM,非线性 SVM 通过使用核函数将输入特征映射到高维空间,然后在高维空间中找到最优的分割超平面。
2. 优化目标:这个线性分类器使用的是平方损失函数,优化目标是最小化预测值与真实值之间的平方差。而 SVM 使用的是合页损失函数,优化目标是最大化分类间隔,即找到一个超平面使得距离超平面最近的样本点(支持向量)到超平面的距离最大。
3. 决策边界:这个线性分类器的决策边界是由所有样本共同决定的,每个样本的改变都可能影响决策边界。而 SVM 的决策边界只由支持向量决定,非支持向量的样本即使有所改变,也不会影响决策边界。
4. 鲁棒性:由于 SVM 只关注支持向量,因此对于噪声和异常值具有较好的鲁棒性。而这个线性分类器由于使用的是平方损失函数,对于远离决策边界的样本(可能是噪声或异常值)会给予较大的权重,因此鲁棒性较差。
总的来说,这个线性分类器和 SVM 在一些基本概念上是相似的,但在具体的实现和优化目标上有所不同。
我们看下预测predictions的值:
tf.Tensor(
[[-0.09647062]
[ 0.16270795]
[ 0.2278583 ]
...
[ 1.1228456 ]
[ 1.0326965 ]
[ 0.79803073]], shape=(2000, 1), dtype=float32)
可以看到,类似一个回归,而不是严格的分类(结果为0和1)!
还记得svm的预测代码吗?
def predict(self, X):
return self.h(X, self.w, self.b)
def h(self, X, w, b):
return np.sign(np.dot(w.T, X.T) + b).astype(int)
详见:机器学习算法原理实现——跟着gpt学习svm求解的SMO算法
为了对比和使用原生keras的效果,如下:
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
def model(inputs):
return tf.matmul(inputs, W) + b
def square_loss(targets, predictions):
per_sample_losses = tf.square(targets - predictions)
return tf.reduce_mean(per_sample_losses)
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
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)
inputs = np.vstack((negative_samples, positive_samples)).astype(np.float32)
targets = np.vstack((np.zeros((num_samples_per_class, 1), dtype="float32"),
np.ones((num_samples_per_class, 1), dtype="float32")))
plt.scatter(inputs[:, 0], inputs[:, 1], c=targets[:, 0])
plt.show()
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,)))
for step in range(40):
loss = training_step(inputs, targets)
print(f"Loss at step {step}: {loss:.4f}")
predictions = model(inputs)
plt.scatter(inputs[:, 0], inputs[:, 1], c=predictions[:, 0] > 0.5)
print(predictions)
plt.show()
x = np.linspace(-1, 4, 100)
y = - 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)
plt.show()
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
import matplotlib.pyplot as plt
def square_loss(y_true, y_pred):
return tf.reduce_mean(tf.square(y_true - y_pred))
# 定义模型
model = Sequential([
Dense(1, input_dim=2, activation=None)
])
model.compile(optimizer=SGD(learning_rate=0.1), loss=square_loss)
# 编译模型
# model.compile(optimizer=SGD(learning_rate=0.1), loss='mse')
# 训练模型
model.fit(inputs, targets, epochs=40, batch_size=len(inputs))
# 测试模型
predictions = model.predict(inputs)
# 绘制结果
plt.scatter(inputs[:, 0], inputs[:, 1], c=predictions[:, 0] > 0.5)
plt.show()
# 获取权重和偏置
weights, biases = model.layers[0].get_weights()
# 打印权重和偏置
print("Weights:\n", weights)
print("Biases:\n", biases)
print("Customized model weight:", W, "b:", b)
输出:
Weights:
[[ 0.18331909]
[-0.11702461]]
Biases:
[0.36755753]
Customized model weight: <tf.Variable 'Variable:0' shape=(2, 1) dtype=float32, numpy=
array([[ 0.18086615],
[-0.11948624]], dtype=float32)> b: <tf.Variable 'Variable:0' shape=(1,) dtype=float32, numpy=array([0.37705055], dtype=float32)>
二者的w和b基本上没有差别!