cs231n Assignment1 实战指南:用NumPy从零实现神经网络

简介:本资源是斯坦福大学CS231n《计算机视觉中的卷积神经网络》课程Assignment 1的完整实践包,面向深度学习初学者与计算机视觉入门者,聚焦KNN、SVM、Softmax分类器及两层全连接网络的原理实现与调参训练。压缩包共54个文件,含17个核心Python源码(如layers.py、solver.py)、7个Jupyter Notebook(knn.ipynb、two_layer_net.ipynb等)、7个编译缓存文件及配套数据集(cifar-10-python.tar、data_batch_*等),另有Shell脚本、Markdown说明与IDE配置文件,整体结构清晰,开箱即用。资源大小为561.98MB,已支持Anaconda+Jupyter环境直接运行,无需额外下载依赖或手动解压数据。目前已有2005人学习下载,读者可一次性获得作业题目、参考实现、完整数据集、提交工具(collect_submission.py)及可视化辅助模块(vis_utils.py),显著降低环境配置门槛,加速从理论到代码落地的学习闭环。

1. 这不是一份“交完就扔”的作业:cs231n assignment1 是你亲手搭起第一个神经网络的脚手架

想象一下:你刚学完反向传播的数学推导,公式写满三页草稿纸,但心里还是发虚——那些 ∂L/∂W 真的能在内存里跑起来吗?梯度真的会按链式法则一层层回传,而不是在某处突然炸成 nan 或缩成 0 吗?cs231n assignment1 就是那个“必须亲手拧紧每一颗螺丝”的实战关卡。它用纯 NumPy 实现 Softmax 分类器、两层全连接网络、带 Dropout 和 BatchNorm 的完整训练流程,不依赖 PyTorch 的自动求导黑匣子,逼你把 forward、backward、weight update 拆成可调试、可断点、可 print 的 Python 函数。它适合所有想甩掉“调包侠”标签的人:新手靠它建立对 loss、grad、update 的肌肉记忆;老手拿它当探针,去验证自己对优化器行为、初始化策略、数值稳定性的直觉是否成立。这不是课程配套练习,这是你深度学习工程能力的第一次压力测试——跑通不难,但想让 train_acc > 55%、val_acc > 48%、loss 曲线平滑下降,每一步都得亲手校准。


2. 环境与数据准备:从零拉起一个可复现的 NumPy 深度学习沙盒

2.1 依赖安装与版本锁定:为什么 conda + pinned requirements 是血泪经验

cs231n assignment1 对环境极其敏感。我见过太多人卡在numpy 1.24+的np.float64类型变更上——softmax函数里np.exp(x - np.max(x))因为广播规则微调直接返回全 0;也有人用matplotlib 3.8+导致visualize_grid报AxesSubplot属性错误。正确做法是严格复刻原始环境:

# 创建干净环境(推荐 conda,避免 pip 混乱) conda create -n cs231n-a1 python=3.7 conda activate cs231n-a1 # 安装课程指定版本(来自 assignment1 原始 repo 的 requirements.txt) pip install numpy==1.19.5 matplotlib==3.3.4 pillow==8.1.0

提示:不要跳过python=3.7。assignment1 的data_utils.py里大量使用urllib.request.urlretrieve下载 CIFAR-10,而新版 urllib 在 Python 3.8+ 中对 SSL 上下文处理更严格,容易触发URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]>。用 3.7 可绕过此坑,且与课程原始运行环境完全一致。

2.2 数据集下载与结构解析:CIFAR-10 不只是 50000 张图

assignment1 使用 CIFAR-10 数据集,但它的加载逻辑藏在cs231n/data_utils.py中。关键点在于:数据不是以原始 PNG/JPG 形式存在,而是序列化为 Python pickle 格式。当你运行get_CIFAR10_data()时,它会:

  1. 检查cs231n/datasets/cifar-10-batches-py/是否存在;
  2. 若不存在,自动从官方服务器下载cifar-10-python.tar.gz(约 170MB);
  3. 解压后,将 5 个训练 batch(data_batch_1 ~ data_batch_5)和 1 个测试 batch(test_batch)合并为X_train,y_train,X_test,y_test;
  4. 最关键的预处理:对图像数据执行X_train = X_train.astype(np.float64)并除以 255.0 归一化,但不减均值、不除标准差——这与后续作业不同,是 assignment1 的设计特征。

目录结构必须严格如下(否则data_utils.py会报FileNotFoundError):

cs231n/ ├── data_utils.py # 加载核心逻辑 ├── datasets/ │ └── cifar-10-batches-py/ # 解压后的文件夹,含 data_batch_1~5, test_batch, batches.meta ├── classifiers/ │ ├── __init__.py │ ├── softmax.py # Softmax 分类器实现 │ └── neural_net.py # 两层神经网络实现 ├── layers.py # 全连接、ReLU、Softmax loss 层 └── solver.py # 训练循环控制器

2.3 验证数据加载:三行代码确认你的沙盒已就绪

别急着跑训练,先用最小代码验证数据流是否通畅:

import numpy as np from cs231n.data_utils import get_CIFAR10_data # 加载数据(首次运行会触发下载) data = get_CIFAR10_data(num_training=49000, num_validation=1000, num_test=1000) print("X_train shape:", data['X_train'].shape) # 应为 (49000, 32, 32, 3) print("y_train shape:", data['y_train'].shape) # 应为 (49000,) print("Class names:", data['class_names']) # ['plane', 'car', ..., 'truck']

如果输出X_train shape: (49000, 32, 32, 3),恭喜——你的数据管道已打通。此时data['X_train']是float64类型的四维数组,每个像素值在[0.0, 1.0]区间,这是后续所有层计算的起点。


3. 核心模块拆解:从 softmax.py 到 neural_net.py 的逐层实现逻辑

3.1 Softmax 分类器:理解loss与grad如何共生于同一函数

cs231n/classifiers/softmax.py中的softmax_loss_naive是 assignment1 的第一道硬坎。它不追求速度,只求逻辑清晰。我们来拆解其loss和grad计算如何耦合:

def softmax_loss_naive(W, X, y, reg): # W: (D, C), X: (N, D), y: (N,) N = X.shape[0] loss = 0.0 dW = np.zeros_like(W) # 初始化梯度矩阵 for i in range(N): # Step 1: 计算第 i 个样本的得分向量 scores = X[i].dot(W) # (C,) # Step 2: 数值稳定化:减去最大值(防止 exp 溢出) scores -= np.max(scores) # Step 3: 计算 softmax 概率 exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores) # (C,) # Step 4: 计算单样本 loss(交叉熵) correct_logprob = -np.log(probs[y[i]]) loss += correct_logprob # Step 5: 计算单样本梯度 dW(关键!) # 对于正确类别 j=y[i]:dL/dW[:,j] = X[i] * (probs[j] - 1) # 对于错误类别 j≠y[i]:dL/dW[:,j] = X[i] * probs[j] for j in range(W.shape[1]): if j == y[i]: dW[:, j] += X[i] * (probs[j] - 1) else: dW[:, j] += X[i] * probs[j] # Step 6: 平均 loss & 加正则项 loss /= N loss += 0.5 * reg * np.sum(W * W) # Step 7: 平均梯度 & 加正则梯度 dW /= N dW += reg * W return loss, dW

逻辑说明与参数意义:

  • reg是 L2 正则化强度(如1e-3),它惩罚大权重,防止过拟合。0.5 * reg * np.sum(W*W)是正则 loss,reg * W是正则梯度;
  • scores -= np.max(scores)是数值稳定化的黄金操作,避免np.exp(1000)这类溢出;
  • 梯度计算dW[:, j] += X[i] * (probs[j] - (j==y[i]))是核心:(probs[j] - 1)当j是正确类,否则probs[j]—— 这正是交叉熵对 softmax 输出的导数;
  • dW /= N是因为 loss 是平均值,梯度也需平均。

注意:这个函数是“naive”版,时间复杂度 O(N×C),仅用于验证逻辑。后续softmax_loss_vectorized用广播机制优化到 O(N+C),但梯度本质相同。

3.2 两层神经网络:neural_net.py中的前向与反向传播链

cs231n/classifiers/neural_net.py实现了一个带 ReLU 激活的两层全连接网络。其loss函数是整个 assignment1 的心脏,它串联了layers.py中的原子操作:

def loss(self, X, y=None): # X: (N, D), y: (N,) or None (预测模式) W1, b1 = self.params['W1'], self.params['b1'] # (D, H), (H,) W2, b2 = self.params['W2'], self.params['b2'] # (H, C), (C,) # --- Forward Pass --- # Layer 1: affine -> ReLU a1, cache_a1 = affine_forward(X, W1, b1) # a1 = X @ W1 + b1 h1, cache_h1 = relu_forward(a1) # h1 = max(0, a1) # Layer 2: affine -> softmax loss scores, cache_scores = affine_forward(h1, W2, b2) # scores = h1 @ W2 + b2 if y is None: return scores # 预测模式,只返回得分 # --- Compute Loss --- loss, dscores = softmax_loss(scores, y) # dscores: (N, C), 损失对 scores 的梯度 # --- Backward Pass --- # Layer 2 backward dh1, dW2, db2 = affine_backward(dscores, cache_scores) # dh1: (N, H) # Layer 1 backward (ReLU -> affine) da1 = relu_backward(dh1, cache_h1) # da1: (N, H) dX, dW1, db1 = affine_backward(da1, cache_a1) # dX: (N, D), 通常丢弃 # --- Regularization --- loss += 0.5 * self.reg * (np.sum(W1*W1) + np.sum(W2*W2)) dW1 += self.reg * W1 dW2 += self.reg * W2 grads = {'W1': dW1, 'b1': db1, 'W2': dW2, 'b2': db2} return loss, grads

关键设计点:

  • cache_*是前向过程中的中间变量(如X, W1, b1),供反向时复用,避免重复计算;
  • softmax_loss返回dscores,即损失对最后一层输出的梯度,这是反向传播的起点;
  • affine_backward和relu_backward是layers.py中定义的原子反向函数,它们接收dout(上游梯度)和cache,返回dx, dW, db;
  • 梯度累加顺序不可逆:必须先算dh1,再用dh1算da1,最后算dW1/db1。任何一步中断,梯度链就断裂。

3.3 Solver 训练器:solver.py如何把 loss 函数变成可收敛的模型

solver.py是 assignment1 的“胶水”模块,它封装了完整的训练循环。其train()方法核心逻辑如下:

def train(self): num_train = self.X_train.shape[0] iterations_per_epoch = max(num_train // self.batch_size, 1) num_iterations = self.num_epochs * iterations_per_epoch for t in range(num_iterations): # 1. Mini-batch sampling batch_mask = np.random.choice(num_train, self.batch_size) X_batch = self.X_train[batch_mask] y_batch = self.y_train[batch_mask] # 2. Forward & backward pass loss, grads = self.model.loss(X_batch, y_batch) self.loss_history.append(loss) # 3. Update parameters (SGD with momentum) for p, w in self.model.params.items(): dw = grads[p] config = self.optim_configs[p] next_w, next_config = sgd_momentum(w, dw, config) # 核心更新函数 self.model.params[p] = next_w self.optim_configs[p] = next_config # 4. Epoch end: compute train/val accuracy if t % iterations_per_epoch == 0: train_acc = self.check_accuracy(self.X_train, self.y_train) val_acc = self.check_accuracy(self.X_val, self.y_val) self.train_acc_history.append(train_acc) self.val_acc_history.append(val_acc)

参数说明与调试技巧:

  • self.batch_size默认 200,太小导致梯度噪声大,太大显存不够(但 assignment1 是 CPU 训练,主要影响收敛速度);
  • sgd_momentum是带动量的 SGD,config中的momentum默认 0.9,learning_rate默认1e-3——这是 assignment1 最易调参的两个超参;
  • check_accuracy每 epoch 跑一次,但注意:它用的是全量训练集,所以train_acc会随 epoch 缓慢上升,而val_acc才是泛化能力指标;
  • 如果val_acc卡在 40% 不动,大概率是learning_rate太大(loss 振荡)或太小(收敛极慢),建议在1e-3~5e-3间网格搜索。

4. 避坑指南:我在 assignment1 上踩过的 5 个真实翻车现场

4.1 现象:softmax_loss_naive返回loss=inf或nan

原因:scores -= np.max(scores)未在每个样本内独立执行,而是对整个scores矩阵取了最大值。例如scores是(N, C),np.max(scores)返回标量,但若未用axis=1,会导致所有样本减同一个值,部分样本仍可能溢出。
解决:确保scores -= np.max(scores, axis=1, keepdims=True),keepdims=True保持维度以便广播。

4.2 现象:neural_net训练时loss初期下降,随后突然飙升至1e10

原因:W1,W2初始化过大(如np.random.randn(D,H)未缩放),导致第一层a1 = X @ W1 + b1输出极大,ReLU后h1极大,第二层scores = h1 @ W2 + b2溢出,softmax计算失败。
解决:严格使用课程初始化:W1 = np.random.randn(D, H) * weight_scale,其中weight_scale=1e-3或1e-2。weight_scale是 assignment1 的隐藏超参,调它比调lr更有效。

4.3 现象:val_acc始终低于train_acc15% 以上,且不随 epoch 改善

原因:忘记在Solver.train()中对验证集做与训练集相同的预处理。X_val加载后是[0,255]整数,但X_train已归一化为[0.0,1.0],直接喂给模型会导致数值范围错乱。
解决:检查get_CIFAR10_data()返回的data['X_val']是否已除以 255.0。若未处理,在Solver.__init__()中手动补:self.X_val = self.X_val.astype(np.float64) / 255.0。

4.4 现象:sgd_momentum更新后W的范数持续增大,最终nan

原因:dW未除以batch_size。softmax_loss和neural_net.loss中的梯度dW是 mini-batch 的和,但sgd_momentum函数默认将其当作平均梯度处理。若dW是 sum,lr * dW就会爆炸。
解决:确认loss函数中dW /= N(N 是 batch_size)已执行。neural_net.py的loss函数末尾有dW1 += self.reg * W1,但前面必须有dW1 /= self.batch_size—— 这个除法常被忽略。

4.5 现象:visualize_grid显示的权重图全黑或全白

原因:W1是(D, H),D=3072(32×32×3),但visualize_grid期望输入是(H, D)或(H, 32, 32, 3)。直接传W1.T会错位。
解决:正确 reshape:w = self.params['W1'].T.reshape(-1, 3, 32, 32).transpose(0,2,3,1),再传入visualize_grid(w)。transpose(0,2,3,1)将(N, C, H, W)转为(N, H, W, C)以匹配 matplotlib。


5. 二次开发实战:如何把 assignment1 改造成你的个人深度学习实验台

5.1 添加 Batch Normalization:三步注入现代训练技巧

assignment1 原生不支持 BatchNorm,但它是提升小网络性能的关键。我们可以在neural_net.py的loss函数中插入:

# 在 forward pass 中,Layer 1 后添加 BN a1, cache_a1 = affine_forward(X, W1, b1) # 新增:BN forward a1_bn, cache_bn = batchnorm_forward(a1, gamma1, beta1, bn_param1) # gamma1/beta1 是新参数 h1, cache_h1 = relu_forward(a1_bn) # 在 backward pass 中,Layer 1 backward 前添加 BN backward dh1 = relu_backward(dh1, cache_h1) # 注意:dh1 现在是 BN 输入的梯度 da1_bn, dgamma1, dbeta1 = batchnorm_backward(dh1, cache_bn) # 新增 da1, dW1, db1 = affine_backward(da1_bn, cache_a1) # 输入改为 da1_bn

关键改造点:

  • bn_param1是字典{'mode': 'train'},训练时需在Solver.train()中设为'train',预测时设为'test';
  • gamma1,beta1是可学习参数,需加入self.params并在Solver的optim_configs中初始化(如gamma1 = np.ones(H));
  • batchnorm_forward/backward需自行实现或从layers.py补充——其核心是计算mu = np.mean(x, axis=0),var = np.var(x, axis=0),再标准化。

5.2 替换优化器:用 Adam 替代 SGD Momentum 的 5 行代码

sgd_momentum是基础,但 Adam 更鲁棒。只需修改solver.py中的update_rule:

# 替换 sgd_momentum 调用为 adam next_w, next_config = adam(w, dw, config) # config 需含 'm', 'v', 't' # adam 函数(放在 solver.py 顶部) def adam(w, dw, config=None): if config is None: config = {} config.setdefault('learning_rate', 1e-3) config.setdefault('beta1', 0.9) config.setdefault('beta2', 0.999) config.setdefault('epsilon', 1e-8) config.setdefault('m', np.zeros_like(w)) config.setdefault('v', np.zeros_like(w)) config.setdefault('t', 0) config['t'] += 1 config['m'] = config['beta1'] * config['m'] + (1 - config['beta1']) * dw config['v'] = config['beta2'] * config['v'] + (1 - config['beta2']) * (dw**2) m_hat = config['m'] / (1 - config['beta1']**config['t']) v_hat = config['v'] / (1 - config['beta2']**config['t']) next_w = w - config['learning_rate'] * m_hat / (np.sqrt(v_hat) + config['epsilon']) return next_w, config

效果对比:在相同learning_rate=1e-3下,Adam 通常比 SGD Momentum 快 2~3 倍收敛,且对lr不敏感——这是你后续实验的“后悔药”。

5.3 可视化增强:用 TensorBoard 记录 loss/acc 曲线(无需改模型)

assignment1 是纯 NumPy,但你可以用tensorboardX(轻量级 TensorBoard 接口)记录训练过程:

# 在 solver.py 开头 from tensorboardX import SummaryWriter writer = SummaryWriter('runs/cs231n_a1') # 在 train() 循环中,epoch 结束时 writer.add_scalar('Loss/train', loss, t) writer.add_scalar('Accuracy/train', train_acc, t) writer.add_scalar('Accuracy/val', val_acc, t) # 记录权重分布(诊断梯度消失) writer.add_histogram('Weights/W1', self.model.params['W1'], t)

运行tensorboard --logdir=runs/cs231n_a1,即可在浏览器查看动态曲线。这比plt.plot()更适合长期实验追踪。

从那以后我每次启动新实验,都强制走一遍tensorboard日志初始化 +git commit -m "init: baseline run"。不是为了留痕,而是因为 assignment1 教会我:可复现性不是终点,而是你每天开工的第一行代码。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

YOLOv8扑克牌识别与计数系统全流程实战解析

YOLOv8扑克牌识别与计数系统全流程实战解析

市场上打着“一条龙”旗号的CV项目源码很多&#xff0c;但真正能做到数据集、训练、部署、前端全链路打通&#xff0c;还经得起落地的并不多。扑克牌识别与计数这套系统&#xff0c;表面看是个YOLOv8目标检测的常规应用&#xff0c;实际却把深度学习视觉落地中最容易踩坑的几个…

2026/10/21 2:58:04 阅读更多 →
Stable Diffusion炼丹实战:LoRA微调全流程与参数详解

Stable Diffusion炼丹实战:LoRA微调全流程与参数详解

先把结论放在前面&#xff1a;玩 Stable Diffusion 的人里&#xff0c;十有七八开口就是“炼丹”&#xff0c;但真正把“丹”练明白的人不多。大多数情况是从网上抄了一套参数&#xff0c;丢进脚本里跑十几个小时&#xff0c;出来一看不是过拟合就是五官崩坏&#xff0c;然后就…

2026/10/21 2:58:04 阅读更多 →
tinyLora:更轻量的LoRA微调,低显存也能高效训练

tinyLora:更轻量的LoRA微调,低显存也能高效训练

搞大模型微调的朋友&#xff0c;应该都对LoRA不陌生了。这个以“低秩适配”为核心思想的技术&#xff0c;几乎成了个人开发者微调大模型的默认选项。我最初接触的时候也觉得很方便&#xff0c;一张消费级显卡就能动辄百亿参数的大模型做定制&#xff0c;放在几年前想都不敢想。…

2026/10/21 2:58:04 阅读更多 →

最新新闻

DSC压缩标准与C Model源码解析:从PPS参数到编码器调试

DSC压缩标准与C Model源码解析:从PPS参数到编码器调试

简介&#xff1a;面向显示接口、芯片及驱动开发者的VESA DSC&#xff08;Display Stream Compression&#xff09;标准与参考实现合集&#xff0c;集中解决高分辨率、高刷新率场景下显示链路带宽不足的问题。压缩包共32个文件&#xff0c;其中4个PDF覆盖DSC v1.1至v1.2b各版本规…

2026/10/21 3:42:29 阅读更多 →
双层记忆架构:破解智能体对话失忆难题

双层记忆架构:破解智能体对话失忆难题

做过智能体开发的朋友应该都有这种体验&#xff1a;上一轮对话里用户刚刚确认好的配置项&#xff0c;换个话题聊几句&#xff0c;再切回来时智能体已经把关键信息忘得一干二净。对话记录明明还在上下文里&#xff0c;模型却像得了"失忆症"一样&#xff0c;不是答非所…

2026/10/21 3:42:29 阅读更多 →
基于STM32的智能宠物自动喂食器设计:从硬件选型到代码实现

基于STM32的智能宠物自动喂食器设计:从硬件选型到代码实现

简介&#xff1a;面向嵌入式课程设计与STM32入门学习者的自动喂食器完整项目&#xff0c;基于STM32F401微控制器实现定时喂食、状态显示与电机控制&#xff0c;可作为课设参考或入门实践。资源包共201个文件&#xff0c;压缩后约11.75MB&#xff0c;核心为C/H源码、Keil工程、P…

2026/10/21 3:42:29 阅读更多 →
WDM-PON:5G回传的物理层解压阀与波长级资源分配

WDM-PON:5G回传的物理层解压阀与波长级资源分配

1. 项目概述&#xff1a;WDM-PON 不是“升级版光纤”&#xff0c;而是5G回传的底层重构逻辑你可能已经听过PON&#xff08;无源光网络&#xff09;&#xff0c;比如家里装的千兆宽带用的就是GPON或XGSPON。但当某运营商在城郊新建5G基站时&#xff0c;发现传统方案卡在了三个地…

2026/10/21 3:42:29 阅读更多 →
短剧出海全链路AI Agent自动化闭环实战详解

短剧出海全链路AI Agent自动化闭环实战详解

短剧出海最近两年已经卷成红海了&#xff0c;但真正卡住团队的不是内容本身&#xff0c;而是“翻译分发”这条链路。我见过不少团队&#xff0c;手里握着不错的剧本和成片&#xff0c;结果卡在字幕翻译靠人工、多语言版本靠重复剪辑、平台分发靠手动上传&#xff0c;一部剧从拿…

2026/10/21 3:42:29 阅读更多 →
DevExpress Winform登录跳转主窗体:窗体生命周期与架构实践

DevExpress Winform登录跳转主窗体:窗体生命周期与架构实践

1. 登录窗体与主窗体的职责边界划分很多刚接触 DevExpress Winform 的朋友&#xff0c;拿到"登录跳转主窗体"这个需求时&#xff0c;第一反应往往是打开 Visual Studio&#xff0c;拖一个登录窗体&#xff0c;再拖一个主窗体&#xff0c;然后在登录按钮里写一句new M…

2026/10/21 3:41:28 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →