深度学习算法原理实现——线性分类器
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)
输出: