tf.nn.conv2d, tf.nn.bias_add, tf.nn.relu的可视化

      学习深度学习很长一段时间的时间了,也学习了CNN网络,可是总是对卷积核的实际计算不是太了解,按照很多的讲解都是讲解padding后能够整除步长的情况,后来发现有时padding在原始图像两个的宽度不一致,所以这次想研究研究到底是怎么实现的.另外根据计算的结果进行了画图研究,这样更加方便于理解.

import tensorflow as tf
input = tf.ones([1, 8, 8, 1], tf.float32)
a = [[[[1.]],[[-1]],[[-1]]],
     [[[1.]],[[1]],[[-2]]],
     [[[1.]],[[-2]],[[1]]] ]
filter = tf.Variable(a)
b = tf.constant([0.1])
op1 = tf.nn.conv2d(input, filter, strides=[1,3,3,1], padding='SAME')
op2 = tf.nn.bias_add(op1, b)
op3 = tf.nn.relu(op2) 
init = tf.initialize_all_variables() 
with tf.Session() as sess:
    sess.run(init)
    print("op1:",sess.run(op1))
    print("op2:",sess.run(op2))
    print("op3:",sess.run(op3))

这段代码的运行结果如下(为了便于观察,对结果的显示格式进行了调整,这不影响结果):

op1: [[[[-1.],[-1.],[ 1.]]
       [[-1.],[-1.],[ 1.]]
       [[-1.],[-1.],[ 2.]]]]

op2: [[[[-0.9],[-0.9],[ 1.1]]
       [[-0.9],[-0.9],[ 1.1]]
       [[-0.9],[-0.9],[ 2.1]]]]

op3: [[[[0. ],[0. ],[1.1]]
       [[
import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms from torch.utils.data import DataLoader import numpy as np import matplotlib.pyplot as plt import pandas as pd from thop import profile import time import os from torch.utils.tensorboard import SummaryWriter # 设备配置 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(f"使用设备: {device}") # 数据预处理 def get_cifar100_dataloaders(batch_size=128, resolution=32): """获取CIFAR-100数据集加载器""" transform_train = transforms.Compose([ transforms.Resize((resolution, resolution)), transforms.RandomCrop(resolution, padding=4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)) ]) transform_test = transforms.Compose([ transforms.Resize((resolution, resolution)), transforms.ToTensor(), transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)) ]) # 使用用户指定的路径 data_path = r'C:\Users\89373\Desktop\imagenet\cifar-100-python' train_set = torchvision.datasets.CIFAR100( root=data_path, train=True, download=False, transform=transform_train) test_set = torchvision.datasets.CIFAR100( root=data_path, train=False, download=False, transform=transform_test) train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=4, pin_memory=True) test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False, num_workers=4, pin_memory=True) return train_loader, test_loader # 深度可分离卷积模块 class DepthwiseSeparableConv(nn.Module): """深度可分离卷积实现""" def __init__(self, in_channels, out_channels, stride): super().__init__() # 深度卷积 (DW卷积) self.depthwise = nn.Sequential( nn.Conv2d(in_channels, in_channels, 3, stride, 1, groups=in_channels, bias=False), nn.BatchNorm2d(in_channels), nn.ReLU6(inplace=True) ) # 逐点卷积 (1x1卷积) self.pointwise = nn.Sequential( nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU6(inplace=True) ) def forward(self, x): x = self.depthwise(x) return self.pointwise(x) # 针对CIFAR-100调整的MobileNet v1 class MobileNetV1_CIFAR100(nn.Module): """针对CIFAR-100调整的MobileNet v1架构""" def __init__(self, alpha=1.0, num_classes=100): super().__init__() def c(channels): return int(channels * alpha) # 宽度乘数α控制通道数 # 针对32x32输入调整的网络结构 self.features = nn.Sequential( # 初始卷积层 (调整stride为1以适应小尺寸图像) nn.Conv2d(3, c(32), 3, 1, 1, bias=False), nn.BatchNorm2d(c(32)), nn.ReLU6(inplace=True), # 深度可分离卷积层 (减少下采样次数) DepthwiseSeparableConv(c(32), c(64), 1), DepthwiseSeparableConv(c(64), c(128), 2), DepthwiseSeparableConv(c(128), c(128), 1), DepthwiseSeparableConv(c(128), c(256), 2), DepthwiseSeparableConv(c(256), c(256), 1), DepthwiseSeparableConv(c(256), c(512), 1), # 调整为stride=1 *[DepthwiseSeparableConv(c(512), c(512), 1) for _ in range(2)], # 减少层数 DepthwiseSeparableConv(c(512), c(1024), 2), DepthwiseSeparableConv(c(1024), c(1024), 1), nn.AdaptiveAvgPool2d(1) ) self.classifier = nn.Linear(c(1024), num_classes) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) return self.classifier(x) # 标准卷积网络用于比较 class StandardConvNet(nn.Module): """标准卷积网络用于与深度可分离卷积比较""" def __init__(self, num_classes=100): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 32, 3, 1, 1, bias=False), nn.BatchNorm2d(32), nn.ReLU6(inplace=True), nn.Conv2d(32, 64, 3, 1, 1, bias=False), nn.BatchNorm2d(64), nn.ReLU6(inplace=True), nn.Conv2d(64, 128, 3, 2, 1, bias=False), nn.BatchNorm2d(128), nn.ReLU6(inplace=True), nn.Conv2d(128, 128, 3, 1, 1, bias=False), nn.BatchNorm2d(128), nn.ReLU6(inplace=True), nn.Conv2d(128, 256, 3, 2, 1, bias=False), nn.BatchNorm2d(256), nn.ReLU6(inplace=True), nn.Conv2d(256, 256, 3, 1, 1, bias=False), nn.BatchNorm2d(256), nn.ReLU6(inplace=True), nn.Conv2d(256, 512, 3, 1, 1, bias=False), nn.BatchNorm2d(512), nn.ReLU6(inplace=True), nn.Conv2d(512, 512, 3, 1, 1, bias=False), nn.BatchNorm2d(512), nn.ReLU6(inplace=True), nn.Conv2d(512, 1024, 3, 2, 1, bias=False), nn.BatchNorm2d(1024), nn.ReLU6(inplace=True), nn.Conv2d(1024, 1024, 3, 1, 1, bias=False), nn.BatchNorm2d(1024), nn.ReLU6(inplace=True), nn.AdaptiveAvgPool2d(1) ) self.classifier = nn.Linear(1024, num_classes) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) return self.classifier(x) # 训练函数 def train_model(model, train_loader, test_loader, epochs=100, lr=0.01, experiment_name="baseline"): """训练并评估模型""" # 创建日志目录 log_dir = f"logs/{experiment_name}_{time.strftime('%Y%m%d_%H%M%S')}" os.makedirs(log_dir, exist_ok=True) writer = SummaryWriter(log_dir) model = model.to(device) optimizer = optim.RMSprop(model.parameters(), lr=lr, momentum=0.9, weight_decay=1e-5) scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'max', patience=5, factor=0.5, verbose=True) criterion = nn.CrossEntropyLoss() best_acc = 0.0 history = {'train_loss': [], 'test_acc': []} for epoch in range(epochs): model.train() running_loss = 0.0 for i, (images, labels) in enumerate(train_loader): images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if (i + 1) % 100 == 0: print(f'Epoch [{epoch + 1}/{epochs}], Step [{i + 1}/{len(train_loader)}], Loss: {loss.item():.4f}') # 计算平均训练损失 avg_train_loss = running_loss / len(train_loader) history['train_loss'].append(avg_train_loss) writer.add_scalar('Loss/train', avg_train_loss, epoch) # 验证评估 model.eval() total, correct = 0, 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, preds = torch.max(outputs, 1) total += labels.size(0) correct += (preds == labels).sum().item() acc = 100 * correct / total history['test_acc'].append(acc) writer.add_scalar('Accuracy/test', acc, epoch) print(f'Epoch {epoch + 1}/{epochs} | Train Loss: {avg_train_loss:.4f} | Test Acc: {acc:.2f}%') # 更新学习率 scheduler.step(acc) # 保存最佳模型 if acc > best_acc: best_acc = acc torch.save(model.state_dict(), f"{log_dir}/best_model.pth") writer.close() return best_acc, history # 评估函数 def evaluate_model(model, test_loader): """评估模型性能""" model.eval() total, correct = 0, 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, preds = torch.max(outputs, 1) total += labels.size(0) correct += (preds == labels).sum().item() return 100 * correct / total # 计算模型复杂度和性能 def calculate_model_stats(model, input_size=(1, 3, 32, 32)): """计算模型参数和FLOPs""" input_tensor = torch.randn(input_size).to(device) model = model.to(device) # 计算FLOPs和参数 flops, params = profile(model, inputs=(input_tensor,), verbose=False) flops_m = flops / 1e6 # 百万FLOPs params_m = params / 1e6 # 百万参数 return flops_m, params_m # 生成实验结果表格 def generate_results_table(): """生成论文中的实验表格""" results = [] train_loader, test_loader = get_cifar100_dataloaders(resolution=32) # 实验1: 标准卷积 vs 深度可分离卷积 print("\n实验1: 标准卷积 vs 深度可分离卷积") # 标准卷积模型 std_model = StandardConvNet() std_flops, std_params = calculate_model_stats(std_model) std_acc = train_model(std_model, train_loader, test_loader, epochs=50, experiment_name="std_conv")[0] # 深度可分离卷积模型 ds_model = MobileNetV1_CIFAR100(alpha=1.0) ds_flops, ds_params = calculate_model_stats(ds_model) ds_acc = train_model(ds_model, train_loader, test_loader, epochs=50, experiment_name="ds_conv")[0] results.append({ '实验': '卷积类型比较', '模型': '标准卷积', '准确率(%)': std_acc, '参数(M)': f'{std_params:.2f}', 'FLOPs(M)': f'{std_flops:.1f}' }) results.append({ '实验': '卷积类型比较', '模型': '深度可分离', '准确率(%)': ds_acc, '参数(M)': f'{ds_params:.2f}', 'FLOPs(M)': f'{ds_flops:.1f}' }) # 实验2: 宽度乘数α的影响 print("\n实验2: 宽度乘数α的影响") for alpha in [1.0, 0.75, 0.5, 0.25]: model = MobileNetV1_CIFAR100(alpha=alpha) flops, params = calculate_model_stats(model) # 实际训练获取准确率 acc = train_model(model, train_loader, test_loader, epochs=50, experiment_name=f"alpha_{alpha}")[0] results.append({ '实验': '宽度乘数α', '模型': f'α={alpha}', '准确率(%)': acc, '参数(M)': f'{params:.2f}', 'FLOPs(M)': f'{flops:.1f}' }) # 实验3: 分辨率乘数β的影响 print("\n实验3: 分辨率乘数β的影响") base_model = MobileNetV1_CIFAR100(alpha=1.0) for resolution in [32, 24, 16]: # 加载不同分辨率的数据 res_train_loader, res_test_loader = get_cifar100_dataloaders(resolution=resolution) # 创建新模型实例 model = MobileNetV1_CIFAR100(alpha=1.0) flops, params = calculate_model_stats(model, input_size=(1, 3, resolution, resolution)) # 实际训练获取准确率 acc = train_model(model, res_train_loader, res_test_loader, epochs=50, experiment_name=f"res_{resolution}")[0] results.append({ '实验': '分辨率乘数β', '模型': f'β={resolution}', '准确率(%)': acc, '参数(M)': '1.00', # 参数数量不变 'FLOPs(M)': f'{flops:.1f}' }) return pd.DataFrame(results) # 可视化实验结果 def visualize_results(results_df): """可视化实验结果""" plt.figure(figsize=(15, 10)) # 卷积类型比较 plt.subplot(2, 2, 1) conv_df = results_df[results_df['实验'] == '卷积类型比较'] plt.bar(conv_df['模型'], conv_df['准确率(%)'], color=['blue', 'green']) plt.title('卷积类型比较 - 准确率') plt.ylabel('准确率(%)') # 宽度乘数影响 plt.subplot(2, 2, 2) alpha_df = results_df[results_df['实验'] == '宽度乘数α'] plt.plot(alpha_df['模型'], alpha_df['准确率(%)'], 'o-', label='准确率') plt.plot(alpha_df['模型'], alpha_df['参数(M)'].astype(float), 's--', label='参数(M)') plt.plot(alpha_df['模型'], alpha_df['FLOPs(M)'].astype(float), 'd-.', label='FLOPs(M)') plt.title('宽度乘数α的影响') plt.legend() # 分辨率乘数影响 plt.subplot(2, 2, 3) res_df = results_df[results_df['实验'] == '分辨率乘数β'] plt.plot(res_df['模型'], res_df['准确率(%)'], 'o-', label='准确率') plt.plot(res_df['模型'], res_df['FLOPs(M)'].astype(float), 's--', label='FLOPs(M)') plt.title('分辨率乘数β的影响') plt.legend() # 准确率-FLOPs权衡 plt.subplot(2, 2, 4) plt.scatter(results_df['FLOPs(M)'].astype(float), results_df['准确率(%)'], s=100) for i, row in results_df.iterrows(): plt.annotate(row['模型'], (float(row['FLOPs(M)']), row['准确率(%)']), xytext=(5, 5), textcoords='offset points') plt.xlabel('FLOPs(M)') plt.ylabel('准确率(%)') plt.title('准确率-FLOPs权衡') plt.tight_layout() plt.savefig('mobilenet_cifar100_results.png') plt.show() # 主函数 def main(): # 生成结果表格 results_df = generate_results_table() # 保存结果 results_df.to_csv('mobilenet_cifar100_results.csv', index=False) print(results_df) # 可视化结果 visualize_results(results_df) print("实验完成!结果已保存到mobilenet_cifar100_results.csv和mobilenet_cifar100_results.png") if __name__ == '__main__': main() D:\anaconda\python.exe D:\杨杏丽作业\pythonProject\ImageNet.py 2025-06-18 10:19:16.836858: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`. 2025-06-18 10:19:18.662333: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`. 使用设备: cpu Traceback (most recent call last): File "D:\杨杏丽作业\pythonProject\ImageNet.py", line 399, in <module> main() File "D:\杨杏丽作业\pythonProject\ImageNet.py", line 386, in main results_df = generate_results_table() ^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\杨杏丽作业\pythonProject\ImageNet.py", line 264, in generate_results_table train_loader, test_loader = get_cifar100_dataloaders(resolution=32) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\杨杏丽作业\pythonProject\ImageNet.py", line 40, in get_cifar100_dataloaders train_set = torchvision.datasets.CIFAR100( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\anaconda\Lib\site-packages\torchvision\datasets\cifar.py", line 69, in __init__ raise RuntimeError("Dataset not found or corrupted. You can use download=True to download it") RuntimeError: Dataset not found or corrupted. You can use download=True to download it 进程已结束,退出代码为 1
最新发布
06-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值