CS231n实践项目:图像分类作业深度解析

CS231n实践项目:图像分类作业深度解析

【免费下载链接】cs231n.github.io Public facing notes page 【免费下载链接】cs231n.github.io 项目地址: https://gitcode.com/gh_mirrors/cs/cs231n.github.io

本文深度解析了CS231n课程中的三个核心实践项目:Assignment 1涵盖了kNN、SVM和神经网络的实现,重点介绍了向量化编程和超参数调优;Assignment 2深入探讨了卷积网络、批归一化和Dropout等现代深度学习技术;Assignment 3则扩展到RNN、Transformer和GAN在视觉语言任务和生成模型中的应用。

Assignment 1:kNN、SVM和神经网络实现

CS231n课程的第一个实践项目Assignment 1是深度学习和计算机视觉的入门基石,它系统性地引导学习者从最简单的k近邻算法逐步过渡到支持向量机和神经网络。这个作业不仅教授算法原理,更重要的是培养向量化编程思维和超参数调优能力。

k近邻分类器实现

k近邻(k-Nearest Neighbor, kNN)算法是Assignment 1的第一个任务,它采用基于实例的学习方法,通过计算测试样本与训练样本之间的距离来进行分类。

距离度量函数实现

def compute_distances_two_loops(X, X_train):
    """
    使用双重循环计算L2距离(欧几里得距离)
    """
    num_test = X.shape[0]
    num_train = X_train.shape[0]
    dists = np.zeros((num_test, num_train))
    
    for i in range(num_test):
        for j in range(num_train):
            # 计算L2距离的平方
            dists[i, j] = np.sqrt(np.sum((X[i] - X_train[j]) ** 2))
    return dists

def compute_distances_one_loop(X, X_train):
    """
    使用单循环向量化实现
    """
    num_test = X.shape[0]
    num_train = X_train.shape[0]
    dists = np.zeros((num_test, num_train))
    
    for i in range(num_test):
        # 向量化计算第i个测试样本与所有训练样本的距离
        dists[i, :] = np.sqrt(np.sum((X[i] - X_train) ** 2, axis=1))
    return dists

def compute_distances_no_loops(X, X_train):
    """
    完全向量化的实现,使用广播机制
    """
    # 使用公式: (a - b)^2 = a^2 + b^2 - 2ab
    test_sum = np.sum(X**2, axis=1, keepdims=True)
    train_sum = np.sum(X_train**2, axis=1)
    inner_product = np.dot(X, X_train.T)
    
    dists = np.sqrt(test_sum + train_sum - 2 * inner_product)
    return dists

kNN分类器核心算法

class KNearestNeighbor:
    def __init__(self):
        self.X_train = None
        self.y_train = None
    
    def train(self, X, y):
        self.X_train = X
        self.y_train = y
    
    def predict(self, X, k=1, num_loops=0):
        if num_loops == 0:
            dists = self.compute_distances_no_loops(X)
        elif num_loops == 1:
            dists = self.compute_distances_one_loop(X)
        else:
            dists = self.compute_distances_two_loops(X)
        
        return self.predict_labels(dists, k=k)
    
    def predict_labels(self, dists, k=1):
        num_test = dists.shape[0]
        y_pred = np.zeros(num_test)
        
        for i in range(num_test):
            # 获取最近的k个邻居的索引
            closest_y = self.y_train[np.argsort(dists[i])[:k]]
            # 投票决定类别
            y_pred[i] = np.argmax(np.bincount(closest_y))
        
        return y_pred

超参数调优流程

mermaid

支持向量机实现

支持向量机(Support Vector Machine, SVM)是Assignment 1的第二个核心任务,它引入了参数化模型和损失函数的概念。

多类SVM损失函数

SVM的铰链损失(Hinge Loss)函数数学表达式为:

$$ L_i = \sum_{j\neq y_i} \max(0, s_j - s_{y_i} + \Delta) $$

其中 $\Delta$ 是边界参数,通常设置为1.0。

def svm_loss_naive(W, X, y, reg):
    """
    非向量化的SVM损失函数实现
    """
    dW = np.zeros(W.shape)  # 梯度初始化
    num_classes = W.shape[0]
    num_train = X.shape[1]
    loss = 0.0
    
    for i in range(num_train):
        scores = W.dot(X[:, i])
        correct_class_score = scores[y[i]]
        
        for j in range(num_classes):
            if j == y[i]:
                continue
            margin = scores[j] - correct_class_score + 1  # delta = 1
            if margin > 0:
                loss += margin
                dW[j, :] += X[:, i]  # 错误类别的梯度
                dW[y[i], :] -= X[:, i]  # 正确类别的梯度
    
    # 平均损失
    loss /= num_train
    dW /= num_train
    
    # 添加L2正则化
    loss += 0.5 * reg * np.sum(W * W)
    dW += reg * W
    
    return loss, dW

def svm_loss_vectorized(W, X, y, reg):
    """
    向量化的SVM损失函数实现
    """
    num_train = X.shape[1]
    scores = W.dot(X)
    
    # 获取正确类别的分数
    correct_class_scores = scores[y, np.arange(num_train)]
    
    # 计算边界
    margins = np.maximum(0, scores - correct_class_scores + 1)
    margins[y, np.arange(num_train)] = 0  # 忽略正确类别
    
    loss = np.sum(margins) / num_train
    loss += 0.5 * reg * np.sum(W * W)
    
    # 计算梯度
    binary = margins
    binary[margins > 0] = 1
    col_sum = np.sum(binary, axis=0)
    binary[y, np.arange(num_train)] = -col_sum
    
    dW = binary.dot(X.T) / num_train
    dW += reg * W
    
    return loss, dW

SVM训练优化过程

mermaid

两层神经网络实现

Assignment 1的第四个任务实现了完整的双层神经网络,这是深度学习的基础架构。

神经网络前向传播

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, std=1e-4):
        self.params = {}
        self.params['W1'] = std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)
    
    def loss(self, X, y=None, reg=0.0):
        # 前向传播
        W1, b1 = self.params['W1'], self.params['b1']
        W2, b2 = self.params['W2'], self.params['b2']
        N, D = X.shape
        
        # 第一层: ReLU激活
        hidden_layer = np.maximum(0, np.dot(X, W1) + b1)
        scores = np.dot(hidden_layer, W2) + b2
        
        if y is None:
            return scores
        
        # 计算损失
        scores_shift = scores - np.max(scores, axis=1, keepdims=True)
        exp_scores = np.exp(scores_shift)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
        
        correct_logprobs = -np.log(probs[np.arange(N), y])
        data_loss = np.sum(correct_logprobs) / N
        reg_loss = 0.5 * reg * (np.sum(W1*W1) + np.sum(W2*W2))
        loss = data_loss + reg_loss
        
        # 反向传播
        grads = {}
        dscores = probs.copy()
        dscores[np.arange(N), y] -= 1
        dscores /= N
        
        grads['W2'] = np.dot(hidden_layer.T, dscores) + reg * W2
        grads['b2'] = np.sum(dscores, axis=0)
        
        dhidden = np.dot(dscores, W2.T)
        dhidden[hidden_layer <= 0] = 0  # ReLU梯度
        
        grads['W1'] = np.dot(X.T, dhidden) + reg * W1
        grads['b1'] = np.sum(dhidden, axis=0)
        
        return loss, grads

神经网络训练超参数优化

超参数典型值范围影响说明
隐藏层大小50-500模型容量和表达能力
学习率1e-4 to 1e-1梯度下降步长
正则化强度1e-5 to 1e-1控制过拟合程度
训练迭代次数1000-10000收敛性和训练时间

神经网络架构可视化

mermaid

性能对比与分析

三种算法在CIFAR-10数据集上的性能表现对比如下:

算法验证集准确率测试集准确率训练时间预测速度
kNN27-34%25-32%
线性SVM35-39%33-37%中等
两层神经网络48-52%46-50%

关键学习要点

  1. 向量化编程:从双重循环到完全向量化的实现,性能提升数百倍
  2. 超参数调优:通过交叉验证寻找最佳超参数组合
  3. 正则化技术:L2正则化有效防止过拟合
  4. 梯度检查:确保反向传播实现的正确性
  5. 学习率调度:动态调整学习率加速收敛

通过Assignment 1的实践,学习者不仅掌握了三种基础分类算法的实现,更重要的是建立了深度学习系统开发的完整思维框架,为后续的卷积神经网络和现代深度学习架构奠定了坚实基础。

Assignment 2:卷积网络与批归一化实践

在CS231n的第二个作业中,我们将深入探索现代深度学习的核心组件:卷积神经网络(CNN)和批归一化技术。这个作业不仅要求你理解这些概念的理论基础,更重要的是通过实践编码来掌握它们的实现细节。

卷积神经网络架构解析

卷积神经网络是专门为处理图像数据而设计的深度学习架构。与传统的全连接网络不同,CNN通过局部连接和参数共享机制大幅减少了模型参数数量,同时保持了强大的特征提取能力。

mermaid

卷积层核心实现

卷积层的数学本质是在输入数据上滑动滤波器进行局部特征提取。每个滤波器在整个输入空间上共享参数,这种设计既减少了参数量,又增强了模型的平移不变性。

import numpy as np

def conv_forward_naive(x, w, b, conv_param):
    """
    卷积层前向传播的简单实现
    """
    N, C, H, W = x.shape
    F, _, HH, WW = w.shape
    stride, pad = conv_param['stride'], conv_param['pad']
    
    # 计算输出尺寸
    H_out = 1 + (H + 2 * pad - HH) // stride
    W_out = 1 + (W + 2 * pad - WW) // stride
    out = np.zeros((N, F, H_out, W_out))
    
    # 对输入进行零填充
    x_padded = np.pad(x, ((0,0), (0,0), (pad,pad), (pad,pad)), mode='constant')
    
    for n in range(N):  # 遍历每个样本
        for f in range(F):  # 遍历每个滤波器
            for i in range(H_out):
                for j in range(W_out):
                    # 计算感受野区域
                    h_start = i * stride
                    h_end = h_start + HH
                    w_start = j * stride
                    w_end = w_start + WW
                    
                    # 执行卷积操作
                    region = x_padded[n, :, h_start:h_end, w_start:w_end]
                    out[n, f, i, j] = np.sum(region * w[f]) + b[f]
    
    cache = (x, w, b, conv_param)
    return out, cache
卷积参数计算表
参数描述典型值计算公式
输入尺寸 (W₁ × H₁ × D₁)输入特征图的维度32×32×3-
滤波器数量 (K)输出特征图的深度16, 32, 64超参数
滤波器尺寸 (F)感受野大小3×3, 5×5超参数
步长 (S)滑动步幅1, 2超参数
填充 (P)边界零填充1, 2超参数
输出尺寸 (W₂ × H₂ × D₂)输出特征图维度计算得出W₂ = (W₁ - F + 2P)/S + 1

批归一化技术深度实践

批归一化(Batch Normalization)是深度学习中最重要的技术创新之一,它通过标准化每层的输入分布来加速训练过程并提高模型稳定性。

批归一化算法原理

批归一化在训练时对每个mini-batch进行标准化,在测试时使用运行平均值:

def batchnorm_forward(x, gamma, beta, bn_param):
    """
    批归一化前向传播
    """
    mode = bn_param['mode']
    eps = bn_param.get('eps', 1e-5)
    momentum = bn_param.get('momentum', 0.9)
    
    N, D = x.shape
    running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
    running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))
    
    if mode == 'train':
        # 计算当前batch的均值和方差
        sample_mean = np.mean(x, axis=0)
        sample_var = np.var(x, axis=0)
        
        # 更新运行平均值
        running_mean = momentum * running_mean + (1 - momentum) * sample_mean
        running_var = momentum * running_var + (1 - momentum) * sample_var
        
        # 标准化
        x_hat = (x - sample_mean) / np.sqrt(sample_var + eps)
        out = gamma * x_hat + beta
        
        cache = (x, gamma, beta, x_hat, sample_mean, sample_var, eps)
        
    elif mode == 'test':
        # 测试时使用运行平均值
        x_hat = (x - running_mean) / np.sqrt(running_var + eps)
        out = gamma * x_hat + beta
        cache = None
        
    else:
        raise ValueError('Invalid forward batchnorm mode "%s"' % mode)
    
    bn_param['running_mean'] = running_mean
    bn_param['running_var'] = running_var
    
    return out, cache
批归一化反向传播
def batchnorm_backward(dout, cache):
    """
    批归一化反向传播
    """
    x, gamma, beta, x_hat, mu, var, eps = cache
    N, D = dout.shape
    
    # 计算梯度
    dbeta = np.sum(dout, axis=0)
    dgamma = np.sum(dout * x_hat, axis=0)
    
    dx_hat = dout * gamma
    dvar = np.sum(dx_hat * (x - mu) * -0.5 * (var + eps

【免费下载链接】cs231n.github.io Public facing notes page 【免费下载链接】cs231n.github.io 项目地址: https://gitcode.com/gh_mirrors/cs/cs231n.github.io

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值