纯numpy数值微分法实现手写数字识别的完整攻略如下:
1. 数据集准备
首先,我们需要准备手写数字的数据集。可以使用MNIST数据集,该数据集包含60,000个训练图像和10,000个测试图像,每个图像都是28x28像素的灰度图像。可以使用numpy的load函数加载数据集。
import numpy as np
# 加载MNIST数据集
train_data = np.load('mnist_train_data.npy')
train_labels = np.load('mnist_train_labels.npy')
test_data = np.load('mnist_test_data.npy')
test_labels = np.load('mnist_test_labels.npy')
2. 模型定义
接下来,我们需要定义一个简单的神经网络模型。该模型包含一个输入层、一个隐藏层和一个输出层。输入层有784个神经元,隐藏层有128个神经元,输出层有10个神经元,分别对应0-9的数字。
class NeuralNetwork:
def __init__(self):
self.input_size = 784
self.hidden_size = 128
self.output_size = 10
self.learning_rate = 0.1
# 初始化权重和偏置
self.W1 = np.random.randn(self.input_size, self.hidden_size)
self.b1 = np.zeros((1, self.hidden_size))
self.W2 = np.random.randn(self.hidden_size, self.output_size)
self.b2 = np.zeros((1, self.output_size))
def forward(self, X):
# 前向传播
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = np.tanh(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = np.exp(self.z2) / np.sum(np.exp(self.z2), axis=1, keepdims=True)
return self.a2
def backward(self, X, y, y_hat):
# 反向传播
delta3 = y_hat
delta3[range(len(X)), y] -= 1
delta2 = np.dot(delta3, self.W2.T) * (1 - np.power(self.a1, 2))
dW2 = np.dot(self.a1.T, delta3)
db2 = np.sum(delta3, axis=0, keepdims=True)
dW1 = np.dot(X.T, delta2)
db1 = np.sum(delta2, axis=0)
# 更新权重和偏置
self.W2 -= self.learning_rate * dW2
self.b2 -= self.learning_rate * db2
self.W1 -= self.learning_rate * dW1
self.b1 -= self.learning_rate * db1
def train(self, X, y):
y_hat = self.forward(X)
self.backward(X, y, y_hat)
def predict(self, X):
y_hat = self.forward(X)
return np.argmax(y_hat, axis=1)
3. 数值微分法实现
接下来,我们需要实现数值微分法来计算梯度。数值微分法是一种近似计算导数的方法,它通过计算函数在某个点的两个近似值之间的差异来计算导数。在神经网络中,我们可以使用数值微分法来计算梯度,然后使用梯度下降法来更新权重和偏置。
class NumericalGradient:
def __init__(self, model):
self.model = model
def compute_gradients(self, X, y):
# 计算梯度
grads = {}
h = 1e-4
for param in ['W1', 'b1', 'W2', 'b2']:
theta = getattr(self.model, param)
grad = np.zeros_like(theta)
# 计算梯度
it = np.nditer(theta, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
ix = it.multi_index
old_value = theta[ix]
# 计算f(x+h)
theta[ix] = old_value + h
fxh1 = self.model.loss(X, y)
# 计算f(x-h)
theta[ix] = old_value - h
fxh2 = self.model.loss(X, y)
# 计算梯度
grad[ix] = (fxh1 - fxh2) / (2 * h)
# 恢复原值
theta[ix] = old_value
it.iternext()
grads[param] = grad
return grads
4. 训练模型
现在,我们可以使用数值微分法来训练我们的神经网络模型。我们可以使用随机梯度下降法来更新权重和偏置,每次迭代使用一个随机的训练样本。
# 创建神经网络模型
model = NeuralNetwork()
# 创建数值微分法对象
grad = NumericalGradient(model)
# 训练模型
for i in range(1000):
# 随机选择一个训练样本
idx = np.random.randint(len(train_data))
X = train_data[idx]
y = train_labels[idx]
# 计算梯度
grads = grad.compute_gradients(X, y)
# 更新权重和偏置
for param in ['W1', 'b1', 'W2', 'b2']:
getattr(model, param) -= 0.1 * grads[param]
# 打印损失函数值
if i % 100 == 0:
loss = model.loss(train_data, train_labels)
print('Iteration %d, loss = %f' % (i, loss))
5. 测试模型
最后,我们可以使用测试数据集来测试我们的模型。我们可以计算模型的准确率,即正确分类的样本数除以总样本数。
# 测试模型
y_pred = model.predict(test_data)
accuracy = np.mean(y_pred == test_labels)
print('Accuracy:', accuracy)
示例
下面是两个示例,第一个示例展示了如何使用数值微分法计算梯度,第二个示例展示了如何使用随机梯度下降法训练模型。
示例1:计算梯度
# 创建神经网络模型
model = NeuralNetwork()
# 创建数值微分法对象
grad = NumericalGradient(model)
# 计算梯度
grads = grad.compute_gradients(train_data[:10], train_labels[:10])
# 打印梯度
for param in ['W1', 'b1', 'W2', 'b2']:
print(param, grads[param])
示例2:训练模型
# 创建神经网络模型
model = NeuralNetwork()
# 创建数值微分法对象
grad = NumericalGradient(model)
# 训练模型
for i in range(1000):
# 随机选择一个训练样本
idx = np.random.randint(len(train_data))
X = train_data[idx]
y = train_labels[idx]
# 计算梯度
grads = grad.compute_gradients(X, y)
# 更新权重和偏置
for param in ['W1', 'b1', 'W2', 'b2']:
getattr(model, param) -= 0.1 * grads[param]
# 打印损失函数值
if i % 100 == 0:
loss = model.loss(train_data, train_labels)
print('Iteration %d, loss = %f' % (i, loss))
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:纯numpy数值微分法实现手写数字识别 - Python技术站