导读部分 返回列表
👋 哈喽,各位小伙伴!我是你们的学长小杰~ 最近好多朋友私信我说:「学长,我听说深度学习特别牛,但一看各种公式和论文就头大,有没有什么简单一点的上手方法?」 💡 其实我特别理解你,因为我当年也是文科转...
正文内容
👋 哈喽,各位小伙伴!我是你们的学长小杰~
最近好多朋友私信我说:「学长,我听说深度学习特别牛,但一看各种公式和论文就头大,有没有什么简单一点的上手方法?」
💡 其实我特别理解你,因为我当年也是文科转AI的,最开始看到反向传播、梯度下降这些名词的时候,也是一脸懵。不过别担心!今天咱们一起来操作一下,用Python从零搭建一个能识别手写数字的简单神经网络。相信我,等你跑起来的那一刻,你会觉得「原来深度学习也没那么难嘛!」

📍 第一步:环境准备——装好Python和必要的库
咱们先检查一下有没有Python环境。打开你的终端(CMD或Terminal),输入:
python --version
✅ 如果能看到版本号(比如Python 3.8+),那就没问题啦。如果没有,先去 python.org 下载安装,记得安装时勾选「Add Python to PATH」。
然后安装我们需要的几个库,建议用豆瓣源加速:
pip install numpy matplotlib scikit-learn -i https://pypi.douban.com/simple
🎉 搞定!这些库分别是处理数据、画图和机器学习的工具包。放心,我帮你试过了,这样安装没问题。
📍 第二步:加载数据——先认识一下MNIST手写数字集
咱们用的数据集叫MNIST,里面是0~9的手写数字图片,每张是28×28像素的灰度图。这个数据集太经典了,就像深度学习界的「Hello World」。
下面我们用scikit-learn来加载它:
from sklearn.datasets import fetch_openml
import numpy as np
# 加载MNIST数据集(第一次会自动下载,大约12MB)
mnist = fetch_openml('mnist_784', version=1, as_frame=False)
X, y = mnist.data.astype(np.float32) / 255.0, mnist.target.astype(np.int64)
print(f"数据形状: {X.shape}") # (70000, 784) —— 7万张图片,每张784个像素
print(f"标签形状: {y.shape}") # (70000,)
💡 注意:我们把像素值除以255,归一化到0~1之间,这样神经网络训练起来更稳定。
然后我们划分训练集和测试集:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=10000, random_state=42)
print(f"训练集: {X_train.shape}, 测试集: {X_test.shape}")
📍 第三步:构建神经网络——动手写一个最简单的网络
我们要建的是一个「单隐层神经网络」,结构长这样:输入层(784个神经元) → 隐藏层(100个神经元) → 输出层(10个神经元)。
咱们一步一步来写类定义:
class SimpleNN:
def __init__(self, input_size=784, hidden_size=100, output_size=10, lr=0.01):
# 随机初始化权重和偏置
self.W1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * 0.01
self.b2 = np.zeros((1, output_size))
self.lr = lr
def relu(self, x):
return np.maximum(0, x)
def softmax(self, x):
exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
def forward(self, X):
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = self.relu(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.softmax(self.z2)
return self.a2
def cross_entropy_loss(self, y_pred, y_true):
m = y_true.shape[0]
log_likelihood = -np.log(y_pred[range(m), y_true] + 1e-8)
return np.sum(log_likelihood) / m
def backward(self, X, y_true_one_hot, y_pred):
m = X.shape[0]
# 输出层梯度
dz2 = y_pred - y_true_one_hot
dW2 = np.dot(self.a1.T, dz2) / m
db2 = np.sum(dz2, axis=0, keepdims=True) / m
# 隐藏层梯度
da1 = np.dot(dz2, self.W2.T)
dz1 = da1 * (self.z1 > 0) # ReLU导数
dW1 = np.dot(X.T, dz1) / m
db1 = np.sum(dz1, axis=0, keepdims=True) / m
# 更新参数
self.W2 -= self.lr * dW2
self.b2 -= self.lr * db2
self.W1 -= self.lr * dW1
self.b1 -= self.lr * db1
def train(self, X, y, epochs=50, batch_size=64):
m = X.shape[0]
y_one_hot = np.eye(10)[y] # 转为one-hot编码
for epoch in range(epochs):
# 打乱数据
indices = np.random.permutation(m)
X_shuffled = X[indices]
y_one_hot_shuffled = y_one_hot[indices]
for i in range(0, m, batch_size):
X_batch = X_shuffled[i:i+batch_size]
y_batch = y_one_hot_shuffled[i:i+batch_size]
y_pred = self.forward(X_batch)
self.backward(X_batch, y_batch, y_pred)
# 每个epoch计算损失
y_pred_all = self.forward(X)
loss = self.cross_entropy_loss(y_pred_all, y)
if epoch % 10 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
def predict(self, X):
y_pred = self.forward(X)
return np.argmax(y_pred, axis=1)
def accuracy(self, X, y):
preds = self.predict(X)
return np.mean(preds == y)
🔥 这段代码你可能觉得有点长,但别紧张!核心其实就是3个公式:
- 前向传播:输入×权重+偏置 → 激活 → 输出概率
- 反向传播:计算每个权重对误差的贡献,然后沿着梯度下降
- 参数更新:权重 = 权重 – 学习率×梯度
我刚开始学的时候也是抄了一遍又一遍才理解的,你先跟着跑起来再说~
📍 第四步:训练模型——让神经网络学会认数字
现在咱们实例化网络并训练:
model = SimpleNN(input_size=784, hidden_size=100, output_size=10, lr=0.1)
model.train(X_train, y_train, epochs=30, batch_size=128)
# 看下训练集准确率
train_acc = model.accuracy(X_train, y_train)
print(f"训练集准确率: {train_acc*100:.2f}%")
💪 如果一切顺利,你应该能看到损失从2.3左右逐渐下降到0.3附近,准确率能到95%以上!注意:第一次跑可能会有点慢(大概几十秒),喝杯咖啡等它跑完~
📍 第五步:测试——看看它到底学会了没
test_acc = model.accuracy(X_test, y_test)
print(f"测试集准确率: {test_acc*100:.2f}%")
# 随机显示几个预测结果
import matplotlib.pyplot as plt
sample_idx = np.random.choice(len(X_test), 10)
fig, axes = plt.subplots(2, 5, figsize=(10,4))
for i, idx in enumerate(sample_idx):
ax = axes[i//5][i%5]
ax.imshow(X_test[idx].reshape(28,28), cmap='gray')
pred = model.predict(X_test[idx:idx+1])[0]
ax.set_title(f"Pred: {pred}")
ax.axis('off')
plt.tight_layout()
plt.show()
🎉 怎么样,是不是很神奇!你亲自写的神经网络已经能识别手写数字啦~
如果想继续进阶,可以试试:
- 增加隐藏层深度(变成深层网络)
- 使用更高级的优化器(如Adam)
- 用Keras或PyTorch框架,几行代码就能实现一样的网络
对了,如果你还想了解如何用这个网络做一个完整的Web应用,推荐看看站内这篇 豆包MarsCode教程,以及 DeepSeek实战指南,里面有很多实战经验分享。
💪 好了,今天的动手时间就到这儿啦!快去试试看,如果遇到报错,记得先检查是不是库没装全,或者代码复制时有没有缺了空格。有任何问题欢迎留言交流~ 加油!
本文出自 AI一族,原文链接:https://www.aiyizu.cn/?p=3706
转发请注明出处,禁止未经允许用于任何商业用途。