AlexNet 模型Demo

一 代码实现

#导入必要
import torch
import torch.nn as nn #神经网络模块
import torch.optim as optim #优化器模块
import torch.nn.functional as F #函数神经网络操作
from torchvision import datasets, transformer, models #计算视觉相关模块
from torch.utils.data import DataLoader, Dataset #数据加载和处理
import numpy as np #数值计算
import matplotlib.pyplot as plt #数据可视化
import time #时间相关操作
import os #操作系统接口
from tqdm import tqdm #进度条显示

#定义AlexNet模型
class AlexNet(nn.Module):
/*
AlexNet 模型实现
ImageNet Classification with deep convolutional Neural Networks
*/
def __init__(self, num_classes=1000, dropout=0.5):
/*
初始化AlexNet模型
参数num_classes 分类类别数量ImageNet默认1000
dropout Dropout概率用于防止过拟合
*/
#调用父类nn.Module初始化方法
super(AlexNet, self).__init__()
#保存参数
self.num_classes = num_classes
#特征提取部分 卷积层
#第一层卷积层
self.conv2 = nn.Conv2d(
    in_channels=3, #输入通道(RGB图像为3通道)
    out_channels=96, #输出通道数 卷积核数量
    kernel_size=11, #卷积核大小 11x11
    stride=4, #卷积步长每次移动4像素
    padding=2, #边缘填充 保持特征大小
)

#第一层激活函数 - ReLU
#ReLU函数 f(x) = max(0, x) 用于增加非线性
self.relu1 = nn.ReLU(inplace=True)

#第一层最大池化层
self.pool1 = nn.MaxPool2d(
    kernel_size=3, #池化窗口大小3x3
    stride=2, #池化步长
)

#第二层卷积层
self.conv2 = nn.Conv2d(
    in_channels=96, #输入通道数来自上一层输出
    out_channels=256,#输出通道数
    kernel_size=5, #卷积核大小 5x5
    padding=2, #边缘填充
)

#第二层激活函数
self.relu2 = nn.ReLU(inplace=True)
#第二层最大池化层
self.pool2 = nn.MaxPool2d(
    kernel_size=3, #池化窗口大小
    stride=2, #池化步长
)
#第三层卷积层
self.conv3 = nn.Conv2d(
    in_channels=256, #输入通道数
    out_channels=384, #输出通道数
    kernel_size=3, #卷积核大小3x3
    padding=1,#边缘填充
)
#第三层激活函数
self.relu3 = nn.ReLU(inplace=True)
#第四层卷积层
self.conv4=nn.Conv2d(
in_channels=384, #输入通道数
out_channels=384,#输出通道数
kernel_size=3, #卷积核大小3x3
padding=1, #边缘填充
)
#第四层激活函数
self.relu4 = nn.ReLU(inplace=True)
#第五层卷积层
self.conv5=nn.Conv2d(
    in_channels=384,#输入通道数
    out_channels=256,#输出通道数
    kernel_size=3, #卷积核大小 3x3
    padding=1,#边缘填充    
)

#第五层激活函数
self.relu5 = nn.ReLU(inplace=True)
#第五层最大池化层
self.pool5 = nn.MaxPool2d(
    kernel_size=3, #池化窗口大小
    stride=2, #池化步长
)
#分类部分(全连接层)
#Dropout -随机丢弃一部分神经元防止过拟合
self.dropout = nn.Dropout(p = dropout)

#第一个全连接层 FC6
#计算输入尺寸经过5卷积池化后特征大小6x6
#输入特征256通道 * 6 * 6 = 9216
self.fc6 = nn.Linear(
    in_features=256 * 6 * 6, #输入特征维度
    out_features=4096, #输出特征维度
)

#第一个全连接层激活函数
self.relu6 = nn.ReLU(inplace=True)

#第二个连接层FC7
self.fc7 = nn.Linear(
    in_features=4096,#输入特征维度
    out_features=4096,#输出特征维度
)

#第二个全连接激活函数
self.relu7 = nn.ReLU(inplace=True)

#第三个连接层FC8 - 输出层
self.fc8 = nn.Linear(
    in_features=4096, #输出特征维度
    out_features=num_classes, #输出类别
)
#初始化权重
self._initialize_weights()
#打印模型结构信息
print(f"AlexNet模型初始化完成,分类类别数: {num_classes}")

def _initialize_weights(self):
/*
初始化模型权重
使用Xavier初始化方法初始化卷积层连接权重
*/
#遍历所有模块
for m in self.modules():
    #卷积进行初始化
    if isinstance(m, nn.Conv2d):
        #使用Xavier均匀分布初始化权重
        nn.init.xavier_uniform_(m.weight)
        #如果偏置初始化0
        if m.bias is not None:
            nn.init.constant_(m.bias, 0)
        
        #全连接进行初始化
        elif isinstance(m, nn.Linear):
            #使用Xavier均匀分布初始化权重
            nn.init.xavier_uniform_(m.weight)
            #偏置初始化0
            nn.init.constant_(m.bias, 0)
        print("模型权重初始化完成")
    def forward(self, x):
    /*
    前向传播函数
    参数
    x 输入张量形状batch_size, 3, 224, 224
    返回output 输出张量形状为batch_size, num_classes
    */
    #保存原始输入形状用于调试
    batch_size = x.shape[0]
    #卷积层部分
    #第一层卷积 + ReLU + 池化
    x = self.conv1(x) #输出形状batch_size, 96, 55, 55
    x = self.relu1(x) #保持形状不变
    x = self.pool1(x) #输出形状 batch_size, 96, 27, 27
    
    #第二层卷积 + ReLU + 池化
    x = self.conv2(x) #输出形状batch_size, 256, 27, 27
    x = self.relu2(x) #保持形状不变
    x = self.pool2(x) #输出形状 batch_size, 256, 13, 13
    
    #第三层卷积 + ReLU
    x = self.conv3(x) #输出形状 batch_size, 384, 13, 13
    x = self.relu3(x) #保持形状不变
    
    #第四层卷积 + ReLU
    x = self.conv4(x) #输出形状batch_size, 384, 13, 13
    x = self.relu4(x) #保持形状不变
    
    #第五层卷积 + ReLU + 池化
    x = self.conv5(x) #输出形状batch_size, 256, 13, 13
    x = self.relu5(x) #保持形状不变
    x = self.pool5(x) #输出形状batch_size, 256, 6, 6
    
    #全连接层部分
    #将特征展平一维向量
    #batch_size 256, 6 ,6展平 batch_size, 256 * 6 * 6
    x = x.view(batch_size, -1) #-1表示自动计算维度大小
    
    #第一个连接层 + ReLU + Dropout
    x = self.fc6(x) #输出形状, batch_size, 4096
    x = self.relu6(x) #保持形状不变
    x = self.dropout(x) #随机丢弃一部分神经
    
    #第二个连接层 + ReLU + Dropout
    x = self.fc7(x) #输出形状 batch_size, 4096
    x = self.relu7(x) #保持形状不变
    x = self.dropout(x) #随机丢弃一部分神经元
    
    #第三个全连接层 输出层
    x = self.fc8(x) #输出形状batch_size, num_classes
    #注意不在这里应用softmax,因为PyTorchCrossEntropyLoss内部处理
    reutrn x
 def get_deature_maps(self, x, layer_index):
     /*
         获取制定层特征
         参数x 输入张量
         layer_index 索引
         返回feature_map 特征
     */
    features = []
    #第一层
    x = self.conv1(x)
    x = self.relu1(x)
    if layer_index == 1:
        return x
    x = self.pool1(x)
    
    #第二层
    x = self.conv2(x)
    x = self.relu2(x)
    if layer_index == 2:
        return x
    x = self.pool2(x)
    
    #第三层
    x = self.conv3(x)
    x = self.relu3(x)
    if layer_index == 3:
        return x
    #第四层
    x = self.conv4(x)
    x = self.relu4(x)
    if layer_index == 4:
        return x
    #第五层
    x = self.conv5(x)
    x = self.relu5(x)
    if layer_index == 5:
        return x
    return None
#定义AlexNet简化版本(适用于CIFAR-10等小数据集)
class AlexNetSmall(nn.Module):
/*
适用于小尺寸图像CIFAR-1032x32 AlexNet简化版本
修改了第一层卷积参数适应小图像
*/
def __init__(self, num_classes=10):
    /*
    初始化简化版AlexNet
    参数num_classes 分类类别CIFAR-1010
    super(AlexNetSmall, self).__init__()
    */
    #修改第一层卷积适应32x32输入
    self.features = nn.Sequential(
    #第一层卷积32x32x3 -> 32x32x64
        nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2), #32x32->16x16
    #第二层卷积:16x16x64->16x16x192
        nn.Conv2d(64, 192, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2), #16x16->8x8
        
    #第三层卷积 8x8x192->8x8x384    
        nn.Conv2d(192, 384, kernel_size=3, padding=1),
        nn.ReLU(inplace=True)
    
    #第四层卷积 8x8x384->8x8x256
        nn.Conv2d(384, 256, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        
    #第五层卷积:8x8x256 -> 8x8x256
        nn.Conv2d(256, 256, kernel_size, padding=1)
        nn.ReLU(inplace=True)
        nn.MaxPool2d(kernel_size=2, stride=2)                    
    )
    #分类部分
    self.classifier = nn.Sequential(
        nn.Dropout(p=0.5),
        nn.Linear(256 * 4 * 4, 4096), #4x4x256 ->4096
        nn.ReLU(inplace=True),
        nn.Dropout(p=0.5),
        nn.Linear(4096, 4096),
        nn.ReLU(inplace=True),
        nn.Linear(4096, num_classes),
    )
    #初始化权重
    self._initialize_weights()
def _initialize_weights(self):
    /*初始化权重*/
    for m in self.modules()
        if isinstance(m, nn.Conv2d):
            nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            if m.bias is not None:
                nn.init.constant_(m.bias, 0)
         elif isinstance(m, nn.Linear):
             nn.init.normal_(m.weight, 0, 0.01)
            nn.init.constant_(m.bias, 0)
def forward(self, x):
/*前向传播*/
    x = self.features(x) #卷积特征提取
    x = x.view(x.size(0), -1)#展平
    x = self.classifier(x) #分类
    return x
    
   #数据准备加载 
def prepare_cifar10_data(batch_size=128, data_dir='./data'):
/*
准备CIFAR-10数据集
参数
    batch_size 批次大小
    data_dir 数据存储目录
返回
    train_loader 训练数据加载
    test_loader 测试数据加载
    classes 类别名称列表    
*/        
#定义数据转换数据增强归一化
transformer_train = transforms.Compose([
    transformer.RandomCrop(32, padding=4), #随机裁剪数据增强
    transformer.RandomHorizontalFlip(), #随机水平翻转数据增强
    transformer.ToTensor(), #转换张量[0, 1]
    transformer.Normalize( #归一化[-1, 1]
        mean=[0.485, 0.456, 0.406] #ImageNet均值
        std=[0.229, 0.224, 0.225] #ImageNet标准差
    )
])
  
transform_test = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(
        mean = [0.485, 0.456, 0.406],
        std = [0.229, 0.224, 0.225]
    )
])   
#下载加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(
    root=data_dir,
    train=True,
    download=True,
    transform = transform_train
)     

test_dataset = datasets.CIFAR10(
    root=data_dir,
    train=False,
    download=True,
    transform=transform_test
)
#创建数据加载
train_loader = DataLoader(
    train_dataset,
    batch_size=batch_size,
    shuffle=True, #训练打乱数据
    num_workers=2, #使用2工作进程加载数据
    pin_memory=True #使用内存加速数据转移
)
 
test_loader = DataLoader(
    test_dataset,
    batch_size = batch_size,
    shuffle = False, #测试不打乱数据
    num_workers=2,
    pin_memory=True
)               

#CIFAR-10类别名称
classes = ('plane', 'car', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck')
print(f"训练集大小: {len(train_dataset)}")
print(f"测试集大小: {len(test_dataset)}")
return train_lodaer, test_loader, classes

#训练函数
def train_model(model, train_laoder test_loader, device, epochs=50, lr=0.001)
/*
训练模型
参数model 要训练模型
    train_loader 训练数据加载器
    test_loader 测试数据加载器
    device 训练设备
    epochs 训练轮数
    l学习率
返回
    model 训练好模型
    history 训练历史记录
*/
#模型移动指定设备
model = model.to(device)
#定义损失函数-交叉墒损失适用于多分类问题
criterion = nn.CrossEntropyLoss()
#定义优化器-随机梯度下降SGD
optimizer = optim.SGD(
    model.parameters(),
    lr=lr,
    momentum=0.9, #动量加速收敛
    weight_decay=5e-4 #权重衰减(L2正则化,防止过拟合)
)
#定义学习率 调度器 -30学习 乘以0.1
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.)1
#记录训练历史
history={
    'train_loss': [],
    'train_acc': [],
    'test_loss': [],
    'test_acc': [],
    'learning_rate': []
}

#训练循环
for epoch in range(epochs):
    print(f"\nEpoch {epoch+1}/{epochs}")
    #训练阶段
    model.train() #设置模型训练模式
    train_loss=0.0
    correct=0
    total=0
    #使用tqdm显示进度条
    pbar = tqdm(train_loader, desc='训练')
    for batch_idx, (inputs, targets) in enumerate(pbar):
        #数据移动设备
        inputs, targets = inputs.to(device), targets.to(device)
        #清空梯度
        optimizer.zero_grad()
        #前向传播
        outputs = model(inputs)
        #计算损失
        loss = criterion(outputs, targets)
        #反向传播
        loss.backward()
        #更新参数
        optimizer.step()
        #统计训练信息
        train_loss += loss.item()
        _, predicted = outputs.max(1) #获取预测类别
        total += targets.size(0)
        correct += predicted.eq(targets).sum().item()
        #更新进度
        pbar.set_postfix({
            'loss': train_loss/(batch_idx+1),
            'acc': 100.*correct/total
        })
        #计算训练准确率
        train_acc = 100 * correct / total
        avg_train_loss = train_loss / len(train_loadaer)
        #测试阶段
        model.eval() 设置模型评估模式
        test_loss = 0.0
        correct = 0
        total = 0
        #禁用梯度计算 节省内存计算时间
        with torch.no_grad():
            for inputs, targets in test_loader:
                inputs, targets = inputs.to(device), targets.to(device)
                outputs = model(inputs)
                loss = criterion(outputs, targets)
                
                test_loss += loss.item()
                _, predicted = outputs.max(1)
                total += targets.size(0)
                correct += predicted.eq(targets).sum().item()
                
        #计算测试准确率
        test_acc = 100 * correct / total
        avg_test_loss = test_loss / len(test_loader)
        #更新学习率
        scheduler.step()
        current_lr = optimizer.param_groups[0]['lr']
        #记录历史
        history['train_loss'].append(avg_train_loss)
        history['train_acc'].append(train_acc)
        history['test_loss'].append(avg_test_loss)
        history['test_acc'].append(test_acc)
        history['learning_rate'].append(current_lr)
        
        #打印结果
        print(f"训练损失: {avg_train_loss:.4f}, 训练准确率: {train_acc:.2f}%")
        print(f"测试损失: {avg_test_loss:.4f}, 测试准确率: {test_acc:.2f}%")
        print(f"学习率: {current_lr:.6f}")
    
    print("训练完成!")
        return model, history
    #可视化函数
def visualize_results(history, model_name="AlexNet")
/*
可视化训练结果
参数
history 训练历史记录
model_name 模型名称
*/
    fig, axe = plt.subplots(2, 2, figsize=(12, 8))
    #绘制训练预测损失
    axes[0, 0].plot(history['train_loss'], label='训练损失', linewidth=2)
    axes[0, 0].plot(history['test_loss'], label='测试损失', linewidth=2)
    axes[0, 0].set_xlabel('Epoch')
    axes[0, 0].set_ylabel('损失')
    axes[0, 0].set_title(f'{model_name} - 训练和测试损失')
    axes[0, 0].legend()
    axes[0, 0].grid(True)
    
    #绘制训练测试准确率
    axes[0, 1].plot(history['train_acc'], label='训练准确率', linewidth=2)
    axes[0, 1].plot(history['test_acc'], label='测试准确率', linewidth=2)
    axes[0, 1].set_xlabel('Epoch')
    axes[0, 1].set_ylabel('准确率 (%)')
    axes[0, 1].set_title(f'{model_name} - 训练和测试准确率')
    axes[0, 1].legend()
    axes[0, 1].grid(True)
    
    #绘制学习率变化
    axes[1, 0].plot(history['learning_rate'], 'r-', linewidth=2)
    axes[1, 0].set_xlabel('Epoch')
    axes[1, 0].set_ylabel('学习率')
    axes[1, 0].set_title(f'{model_name} - 学习率变化')
    axes[1, 0].grid(True)
    
    #绘制训练测试损失对比
    axes[1, 1].plot(history['train_loss'], alpha=0.7, label='训练损失')
    axes[1, 1].plot(history['test_loss'], alpha=0.7, label='测试损失')
    axes[1, 1].set_xlabel('Epoch')
    axes[1, 1].set_ylabel('损失')
    axes[1, 1].set_title(f'{model_name} - 损失对比 (对数坐标)')
    axes[1, 1].set_yscale('log')
    axes[1, 1].legend()
    axes[1, 1].grid(True)
    
    plt.tight_layout()
    plt.show()
    
def visualize_feature_maps(model, test_loader, device, num_images=5):
/*
可视化卷积层特征
参数
    model:训练模型
    test_loader: 测试数据加载器
    device 设备
    num_images: 要可视化图像数量
*/
print("可视化特征图...")
    #获取一批测试数据
    data_iter = iter(test_loader)
    images, labels = next(data_iter)
    #只取结构图像
    images = images[:num_images].to(device)
    #设置模型评估模式
    model.eval()
    #创建图形
    fig, axes = plt.subplots(num_images, 6, figsize=(15, num_images * 2.5))
    #如果只有一张图像调整axes维度
    if num_images == 1:
        axes = axes.reshape(1, -1)
    for i in range(num_images):
        #获取单张图像
        img = images[i:i+1]
        #显示原始图像
        img_np = img.cpu().squeeze().numpy()
        #归一化
        img_np = np.transpose(img_np, (1, 2, 0))
        img_np = img_np * np.array([0.229, 0.224, 0.225]) + np.array([0.485, 0.456, 0.406])
        img_np = np.clip(img_np, 0, 1)
        
        axes[i, 0].imshow(img_np)
        axes[i, 0].set_title(f"原始图像")
        axes[i, 0].axis('off')
        
        #获取显示每一层特征图
        for layer_idx in range(1, )6
            with torch.no_grad():
                #获取特征图
                feature_map = model.get_feature_maps(img, layer_idx)
                #获取前几个通道特征图
                feature_map = feature_map.cpu().numpy()
                #显示特征图
                #提取3通道所有通道平均值
                if feature_map.shape[1] >= 3:
                #前三个通道
                    fm_show = feature_map[0, :3, :, :]
                    fm_show = np.transpose(fm_show, (1,2,0))
                else:
                    #获取所有通道平均值
                    fm_show = feature_map[0].mean(0)
                axes[i, layer_idx].imshow(fm_show, cmap='viridis')
                axes[i, layer_idx].set_title(f"卷积层 {layer_idx}")
                axes[i, layer_idx].axis('off')
    plt.suptitle("AlexNet特征图可视化")
    plt.tight_layout()
    plt.show()
 #模型评估函数
 def evaluate_model(model, test_loader, device, classes):
 /*
 评估模型能
 参数model 评估模型
 test_loader 测试数据加载器
 device 设备
 classes :类别名称
 返回
     overall_accuracy 总体准确率
     class_accuracy 每个类别准确率
     confusion_matrix 混淆矩阵
 */   
 model.eval()
 model = model.to(device)
 #初始化统计变量
 class_correct = list(0, for _in range(len(classes)))
 class_total = list(0. for _in range(len(classes)))
 #初始化混淆矩阵
 confusion_matrix = np.zeros((len(classes), len(classes)), dtype=int)
 #禁用梯度计算
 with torch.no_grad():
     for inputs, targets in test_loader:
         inputs, targets = inputs.to(device), targets.to(device)
     #前向传播
     outputs = model(inputs)
     _, predicted = outputs.max(1)
     
     #同级每个类别的预测结果
     for i in range(len(targets)):
         label = targets[i]
         pred = predicted[i]
         confusion_matrix[label][pred] += 1
         
         class_total[label] += 1
         if label == pred:
            class_correct[label] += 1
    #计算总体准确率
    overall_accuracy = 100 * sum(class_correct)/sum(class_total)
    #计算每个类别的准确率
    class_accuracy = []
    for  i in range(len(classes)):
        if class_total[i] > 0:
            acc = 100 * class_correct[i] / class_total[i]
        else:
            acc = 0.0
        class_accuracy.append(acc)
 # 打印结果
    print(f"总体准确率: {overall_accuracy:.2f}%")
    print("\n每个类别的准确率:")
    for i in range(len(classes)):
        print(f"  {classes[i]}: {class_accuracy[i]:.2f}%")
    
    return overall_accuracy, class_accuracy, confusion_matrix
#主函数
def main:
/*
主函数训练评估AlexNet模型
print("=" * 60)
    print("AlexNet模型演示")
    print("=" * 60)
*/    
    #设置随机种子确保结果可重复
    torch.manual_seed(42)
    np.random.seed(42)
    #检查是否可用GPU
   device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(f"使用设备: {device}")
    
    #参数设置
    batch_size = 128
    epochs = 50
    learning_rate = 0.001
    num_classes = 10 #CIFAR-1010类别
    
    #准确数据
    print("\n1. 准备数据...")
    train_loader, test_loader, classes = prepare_cifar10_data(batch_size)
    
    # 2. 创建模型
    print("\n2. 创建模型...")
    # 使用简化版AlexNet(适用于CIFAR-10的小图像)
    model = AlexNetSmall(num_classes=num_classes)
    
    # 打印模型结构
    print("\n模型结构:")
    print(model)

二 模型逻辑

输入层

输入图像尺寸:227x227x3( RGB 图像)

卷积层

第一层 (C1):包含 96 个 11x11 的卷积核,步长为 4,没有填充(padding),输出尺寸为 55x55x96。

第二层 (C2):包含 256个5x5 的卷积核,步长为 1,使用 2 的填充,输出尺寸为 27x27x256。

第三层 (C3):包含 384个3x3 的卷积核,步长为 1,使用 1 的填充,输出尺寸为 13x13x384。

第四层 (C4):包含 384个3x3 的卷积核,步长为 1,使用 1 的填充,输出尺寸为 13x13x384。

第五层 (C5):包含 256个3x3 的卷积核,步长为 1,使用 1 的填充,输出尺寸为 13x13x256。

池化层

在第一层和第二层卷积层后,分别有一个最大池化层,池化窗口大小为 3x3,步长为 2,这样减少了特征图的尺寸,同时保留了重要特征。

第五层卷积层后也有一个最大池化层,同样使用 3x3 的窗口和步长 2。

全连接层

第一个全连接层 (FC6):将前一层的输出展平为一维向量,然后通过一个含有 4096 个神经元的全连接层。

第二个全连接层 (FC7):同样含有 4096 个神经元。

第三个全连接层 (FC8):输出层,含有 1000 个神经元,对应 ImageNet 数据集中的 1000 个类别。

激活函数

在每个卷积层和全连接层之后,使用 ReLU(Rectified Linear Unit)作为激活函数,ReLU 函数可以增加网络的非线性表达能力,同时也加速了训练过程。

特殊层

局部响应归一化 (Local Response Normalization, LRN):在网络的前面几层中使用,以增强特征的鲁棒性。LRN对每个位置上的特征进行标准化,使得响应较大的特征更加突出,类似于生物视觉系统中的侧抑制效应。

训练技巧

使用重叠的最大池化(Overlapping Pooling)来减少过拟合。

在全连接层中使用 Dropout 技术来进一步防止过拟合。

数据增强,包括随机裁剪和水平翻转,以及颜色抖动,以增加模型的泛化能力。

并行处理

AlexNet 最初是在两个 GPU 上训练的,网络被分割成两半,每半在单独的 GPU 上处理,然后在最后合并结果。

以上就是 AlexNet 的完整结构,它的设计和训练方法为后来的深度学习研究者提供了许多有价值的思路和实践指导。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值