news 2026/4/27 11:19:19

AI 入门 30 天挑战 - Day 19 费曼学习法版 - GAN 生成对抗网络

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI 入门 30 天挑战 - Day 19 费曼学习法版 - GAN 生成对抗网络

🌟 完整项目和代码

本教程是AI 入门 30 天挑战系列的一部分!

  • 💻GitHub 仓库: https://github.com/Lee985-cmd/AI-30-Day-Challenge
  • 📖CSDN 专栏: https://blog.csdn.net/m0_67081842?type=blog
  • 欢迎 Star 支持!

Week 3 第三天:AI 也能搞创作!
从识别到创造,这是质的飞跃!
每个概念都解释!每行代码都说明白!
预计时间:3-4 小时(含费曼输出练习)


📖 第 1 步:快速复习昨天的内容(30 分钟)

费曼输出 #0:考考你

合上教程,尝试回答:

□ 图像分割和目标检测的核心区别是什么?用例子说明 □ 语义分割和实例分割各有什么特点? □ U-Net 的结构是什么样的?为什么叫 U-Net? □ 跳跃连接是怎么工作的?有什么作用? □ 如果要分割医学 CT 片中的肿瘤,你会怎么设计系统?

⏰ 时间:25 分钟

如果能答出 80% 以上,我们开始今天的 AI 创作之旅!如果不够,花 5 分钟翻一下 Day16 的笔记。


🤔 第 2 步:GAN 到底是什么?(50 分钟)

故事时间 📚

造假币的人 vs 警察

有一个造假币的人 (生成器 G) 和一个警察 (判别器 D) 剧情发展: 第 1 幕:新手阶段 造假者:做的假币一眼假 ❌ 警察:轻松识破 ✅ 结果:造假者被抓 第 2 幕:互相学习 造假者:研究哪里露馅了,改进技术 🔧 警察:学习新的识别技巧 🔍 结果:两个都在进步 第 3 幕:高手对决 造假者:能以假乱真 🎭 警察:火眼金睛 👁️ 结果:达到平衡 这就是 GAN 的本质!
生活中的例子:模仿秀比赛 生成器 = 参赛选手 → 目标:模仿明星,以假乱真 → 一开始模仿得很烂 → 逐渐改进,越来越像 判别器 = 评委 → 目标:找出谁在模仿 → 一开始很容易 → 后来越来越难分辨 对抗训练 = 比赛过程 → 选手越演越好 → 评委眼光越来越高 → 最后都成了高手

GAN 的核心组件

生成器 (Generator): ✓ 输入:随机噪声(看不出规律) ✓ 输出:一张像模像样的图片 ✓ 目标:骗过判别器 就像魔术师: 输入:一把沙子(噪声) 输出:一只鸽子(清晰图片) 判别器 (Discriminator): ✓ 输入:真实图片 or 生成的图片 ✓ 输出:真 or 假的概率 ✓ 目标:准确识别真假 就像鉴宝专家: 输入:古董 输出:真品/赝品判断

GAN 能做什么?

真实应用场景:

1. 图像生成 - 生成不存在的人脸 (thispersondoesnotexist.com) - 生成动漫角色 - 生成艺术品 2. 图像修复 - 老照片修复 - 去除水印 - 填补缺失部分 3. 风格转换 - 把照片变梵高风格 - 把白天变黑夜 - 把夏天变冬天 4. 数据增强 - 生成更多训练数据 - 解决数据不足问题 5. 超分辨率 - 把模糊图片变清晰 - 把小图变大图

🎯 费曼输出 #1:解释 GAN

任务 1:向小学生解释

场景:有个小朋友问你:"GAN 是什么?"

要求:

  • 不用"生成器"、"判别器"、"对抗训练"这些专业术语
  • 用画画、模仿秀、捉迷藏等生活场景比喻
  • 让小学生能听懂

参考模板:

"GAN 就像______一样。 有两个角色: 一个是______, 一个是______。 他们玩______游戏, 一个要______, 一个要______。 最后______!"

⏰ 时间:15 分钟


💡 卡壳检查点

如果你在解释时卡住了:

□ 我说不清楚生成器和判别器的关系 □ 我不知道如何解释"对抗"的概念 □ 我只能说"互相竞争",但不能说明白怎么竞争

这很正常!标记下来,回去再看上面的内容,然后重新尝试解释!

提示:

  • 生成器 = 造假的人
  • 判别器 = 打假的人
  • 对抗 = 猫鼠游戏

🔥 第 3 步:DCGAN 实战(90 分钟)

什么是 DCGAN?

DCGAN = Deep Convolutional GAN 就是用卷积神经网络做的 GAN 特点: ✓ 用卷积层代替全连接层 ✓ 生成效果更好 ✓ 训练更稳定 ✓ 适合生成图片 架构: 生成器:从噪声逐渐放大成图片 判别器:从图片逐渐压缩成判断

完整代码实现

import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision import datasets, transforms import matplotlib.pyplot as plt import numpy as np import os print("=" * 60) print("🎨 DCGAN 生成手写数字 - 从零开始") print("=" * 60) # ============================================================================ # 第 1 步:准备数据 # ============================================================================ print("\n【1. 准备 MNIST 数据集】") """ MNIST 数据集是什么? - 60000 张手写数字图片 (0-9) - 每张图片 28x28 像素 (黑白) - AI 界的"Hello World",新手必学 就像小学生用的数字字帖,让 AI 学习认数字 """ # 数据预处理 transform = transforms.Compose([ transforms.Resize((64, 64)), # 放大到 64x64 (方便卷积操作) transforms.ToTensor(), # 转成 Tensor transforms.Normalize([0.5], [0.5]) # 归一化到 [-1, 1] ]) # 下载并加载数据 print("正在下载 MNIST 数据集...") print("提示:第一次运行会自动下载,大概 10MB") train_dataset = datasets.MNIST( root='./data/mnist', # 数据存放位置 train=True, # 用训练集 download=True, # 自动下载 transform=transform # 预处理 ) # 创建数据加载器 batch_size = 128 # 一次看 128 张图片 dataloader = DataLoader( dataset=train_dataset, batch_size=batch_size, shuffle=True, # 打乱顺序 num_workers=0 # Windows 用户设为 0 ) print(f"✓ 数据加载完成!") print(f" - 总图片数:{len(train_dataset)}") print(f" - 批次大小:{batch_size}") print(f" - 批次数:{len(dataloader)}") # ============================================================================ # 第 2 步:创建生成器 G - "造假币的人" # ============================================================================ print("\n" + "=" * 60) print("【2. 创建生成器 G - "造假币的人"】") print("=" * 60) class Generator(nn.Module): """生成器网络""" def __init__(self): super(Generator, self).__init__() # 输入:随机噪声向量 (100 维) # 输出:64x64 的单通道图片 # 第一步:从 100 维噪声到一个小方块 (4x4) self.layer1 = nn.Sequential( # 输入:(batch_size, 100, 1, 1) nn.ConvTranspose2d( in_channels=100, # 输入通道数 (噪声维度) out_channels=512, # 输出通道数 (特征图数量) kernel_size=4, # 卷积核大小 4x4 stride=1, # 步长 padding=0 # 填充 ), # 输出:(batch_size, 512, 4, 4) nn.BatchNorm2d(512), # 批归一化 nn.ReLU(True) # 激活函数 ) # 第二步:从 4x4 放大到 8x8 self.layer2 = nn.Sequential( # 输入:(batch_size, 512, 4, 4) nn.ConvTranspose2d(512, 256, 4, 2, 1), # kernel_size=4, stride=2, padding=1 # 输出尺寸计算公式:(输入 -1)*stride - 2*padding + kernel_size # = (4-1)*2 - 2*1 + 4 = 8 nn.BatchNorm2d(256), nn.ReLU(True) # 输出:(batch_size, 256, 8, 8) ) # 第三步:从 8x8 放大到 16x16 self.layer3 = nn.Sequential( nn.ConvTranspose2d(256, 128, 4, 2, 1), nn.BatchNorm2d(128), nn.ReLU(True) # 输出:(batch_size, 128, 16, 16) ) # 第四步:从 16x16 放大到 32x32 self.layer4 = nn.Sequential( nn.ConvTranspose2d(128, 64, 4, 2, 1), nn.BatchNorm2d(64), nn.ReLU(True) # 输出:(batch_size, 64, 32, 32) ) # 第五步:从 32x32 放大到 64x64,变成单通道图片 self.layer5 = nn.Sequential( nn.ConvTranspose2d(64, 1, 4, 2, 1), nn.Tanh() # 输出:(batch_size, 1, 64, 64) # Tanh 把值限制在 [-1, 1],和我们的数据范围一致 ) def forward(self, x): # x shape: (batch_size, 100) # 需要变成 (batch_size, 100, 1, 1) x = x.view(-1, 100, 1, 1) # 逐层通过 x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.layer5(x) return x # 创建生成器 G = Generator() print("✓ 生成器创建完成") print(f"\n生成器结构:") print(G) # 计算参数量 total_params = sum(p.numel() for p in G.parameters()) trainable_params = sum(p.numel() for p in G.parameters() if p.requires_grad) print(f"\n总参数量:{total_params:,}") print(f"可训练参数:{trainable_params:,}") # 测试一下 test_noise = torch.randn(1, 100) # 随机噪声 fake_image = G(test_noise) print(f"\n测试生成器:") print(f" 输入形状:{test_noise.shape}") print(f" 输出形状:{fake_image.shape}") print(f" ✓ 成功生成一张 {fake_image.shape[2]}x{fake_image.shape[3]} 的图片") # ============================================================================ # 第 3 步:创建判别器 D - "警察" # ============================================================================ print("\n" + "=" * 60) print("【3. 创建判别器 D - "警察"】") print("=" * 60) class Discriminator(nn.Module): """判别器网络""" def __init__(self): super(Discriminator, self).__init__() # 输入:64x64 的单通道图片 # 输出:一个概率值 (0-1 之间,表示真实的概率) # 第一步:从 64x64 压缩到 32x32 self.layer1 = nn.Sequential( # 输入:(batch_size, 1, 64, 64) nn.Conv2d(1, 64, 4, 2, 1), # kernel_size=4, stride=2, padding=1 # 输出:(batch_size, 64, 32, 32) nn.LeakyReLU(0.2, inplace=True) # LeakyReLU:允许负值,避免神经元死亡 ) # 第二步:从 32x32 压缩到 16x16 self.layer2 = nn.Sequential( nn.Conv2d(64, 128, 4, 2, 1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True) # 输出:(batch_size, 128, 16, 16) ) # 第三步:从 16x16 压缩到 8x8 self.layer3 = nn.Sequential( nn.Conv2d(128, 256, 4, 2, 1), nn.BatchNorm2d(256), nn.LeakyReLU(0.2, inplace=True) # 输出:(batch_size, 256, 8, 8) ) # 第四步:从 8x8 压缩到 4x4 self.layer4 = nn.Sequential( nn.Conv2d(256, 512, 4, 2, 1), nn.BatchNorm2d(512), nn.LeakyReLU(0.2, inplace=True) # 输出:(batch_size, 512, 4, 4) ) # 第五步:从 4x4 压缩到 1x1,输出一个值 self.layer5 = nn.Sequential( nn.Conv2d(512, 1, 4, 1, 0), nn.Sigmoid() # 输出:(batch_size, 1, 1, 1) # Sigmoid 把值压缩到 (0, 1),表示概率 ) def forward(self, x): # x shape: (batch_size, 1, 64, 64) # 逐层通过 x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.layer5(x) # 展平,变成 (batch_size,) return x.view(x.size(0)) # 创建判别器 D = Discriminator() print("✓ 判别器创建完成") print(f"\n判别器结构:") print(D) # 计算参数量 total_params = sum(p.numel() for p in D.parameters()) trainable_params = sum(p.numel() for p in D.parameters() if p.requires_grad) print(f"\n总参数量:{total_params:,}") print(f"可训练参数:{trainable_params:,}") # 测试一下 real_image = torch.randn(1, 1, 64, 64) # 随机图片 prediction = D(real_image) print(f"\n测试判别器:") print(f" 输入形状:{real_image.shape}") print(f" 输出形状:{prediction.shape}") print(f" 预测概率:{prediction.item():.4f}") print(f" ✓ 成功判断图片的真假") # ============================================================================ # 第 4 步:定义损失函数和优化器 # ============================================================================ print("\n" + "=" * 60) print("【4. 定义损失函数和优化器】") print("=" * 60) # 二元交叉熵损失 (Binary Cross Entropy) # 专门用于二分类问题 (真/假) criterion = nn.BCELoss() # 优化器 optimizer_G = optim.Adam(G.parameters(), lr=0.0002, betas=(0.5, 0.999)) optimizer_D = optim.Adam(D.parameters(), lr=0.0002, betas=(0.5, 0.999)) print(f"损失函数:BCELoss (二元交叉熵)") print(f"优化器:Adam (学习率=0.0002)") print(f"Betas: (0.5, 0.999) - GAN 常用的参数") # ============================================================================ # 第 5 步:训练 GAN # ============================================================================ print("\n" + "=" * 60) print("【5. 开始训练 GAN】") print("=" * 60) # 训练参数 num_epochs = 50 fixed_noise = torch.randn(1, 100) # 固定噪声,用于观察生成效果 # 记录训练过程 G_losses = [] D_losses = [] generated_images = [] print(f"开始训练,共 {num_epochs} 轮...") print("提示:GAN 训练比较慢,请耐心等待\n") for epoch in range(num_epochs): G_total_loss = 0 D_total_loss = 0 for batch_idx, (real_images, _) in enumerate(dataloader): batch_size = real_images.size(0) # ==================== # 训练判别器 D # ==================== D.zero_grad() # 1. 用真实图片训练 real_labels = torch.ones(batch_size) # 真实标签 = 1 output_real = D(real_images) loss_real = criterion(output_real, real_labels) # 2. 用假图片训练 noise = torch.randn(batch_size, 100) # 随机噪声 fake_images = G(noise) fake_labels = torch.zeros(batch_size) # 假标签 = 0 output_fake = D(fake_images.detach()) # detach: 不让梯度传到 G loss_fake = criterion(output_fake, fake_labels) # 3. 总损失 = 真实损失 + 假损失 loss_D = loss_real + loss_fake loss_D.backward() optimizer_D.step() # ==================== # 训练生成器 G # ==================== G.zero_grad() # 目标:骗过判别器 # 所以把假图片的标签设为 1 (真的) labels_g = torch.ones(batch_size) output_g = D(fake_images) loss_G = criterion(output_g, labels_g) loss_G.backward() optimizer_G.step() # 记录损失 G_total_loss += loss_G.item() D_total_loss += loss_D.item() # 计算平均损失 avg_G_loss = G_total_loss / len(dataloader) avg_D_loss = D_total_loss / len(dataloader) G_losses.append(avg_G_loss) D_losses.append(avg_D_loss) # 每 10 轮打印一次 if (epoch + 1) % 10 == 0: print(f'Epoch [{epoch+1}/{num_epochs}]: ' f'G Loss: {avg_G_loss:.4f}, D Loss: {avg_D_loss:.4f}') # 生成一张图片看看效果 with torch.no_grad(): fake = G(fixed_noise).squeeze().numpy() generated_images.append(fake) print("\n✅ 训练完成!") # ============================================================================ # 第 6 步:可视化训练过程 # ============================================================================ print("\n" + "=" * 60) print("📊 可视化训练过程") print("=" * 60) # 画损失曲线 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6)) # 左图:G 的损失 ax1.plot(G_losses, 'b-', linewidth=2, label='Generator Loss') ax1.set_title('Generator Training Loss', fontsize=14) ax1.set_xlabel('Epoch') ax1.set_ylabel('Loss') ax1.legend() ax1.grid(True, alpha=0.3) # 右图:D 的损失 ax2.plot(D_losses, 'r-', linewidth=2, label='Discriminator Loss') ax2.set_title('Discriminator Training Loss', fontsize=14) ax2.set_xlabel('Epoch') ax2.set_ylabel('Loss') ax2.legend() ax2.grid(True, alpha=0.3) plt.tight_layout() plt.show() # 画生成效果 if len(generated_images) > 0: fig, axes = plt.subplots(1, len(generated_images), figsize=(15, 5)) if len(generated_images) == 1: axes = [axes] for i, ax in enumerate(axes): if i < len(generated_images): img = generated_images[i] ax.imshow(img, cmap='gray') ax.set_title(f'Epoch {(i+1)*10}', fontsize=12) ax.axis('off') plt.tight_layout() plt.show() print("\n🎊 恭喜!你完成了 GAN 训练!") print("=" * 60)

按 Shift + Enter 运行整个项目!


🎯 费曼输出 #2:解释代码含义

逐行解释给小白听

任务:假装你在教一个完全不懂编程的人

要解释清楚:

1. 生成器是怎么从噪声变成图片的? 2. 判别器是怎么判断真假的? 3. 为什么要训练两次(一次 D,一次 G)? 4. 损失函数 BCELoss 是什么意思?

要求:

  • 不用"张量"、"卷积"、"梯度"等术语
  • 用生活化的比喻
  • 每行代码都要说明白

参考思路:

"ConvTranspose2d 就像是______" "Sigmoid 就像是______" "BCELoss 就像是______" "detach() 就像是______"

⏰ 时间:30 分钟


💡 卡壳检查点

□ 我解释不清 GAN 的训练流程 □ 我说不明白为什么要分开训练 □ 我不能用生活中的例子说明

提示:

  • ConvTranspose2d= 放大的工具
  • Sigmoid= 把值变成概率(0-1 之间)
  • BCELoss= 衡量猜得准不准
  • detach()= 暂时分开,不互相影响

🎉 今日费曼总结(30 分钟)⭐

完整的费曼学习流程

第 1 步:回顾今天的内容(5 分钟)

□ GAN 的核心思想(猫鼠游戏) □ 生成器和判别器的作用 □ DCGAN 的架构 □ 训练流程和技巧 □ 实际应用场景

第 2 步:合上教程,尝试完整教授(15 分钟)⭐

任务:假装你在给一个完全不懂的人上第十七堂课

要覆盖:

  1. GAN 的基本原理(用至少 2 个比喻)
  2. 生成器和判别器各做什么工作
  3. 为什么叫"对抗"训练
  4. 演示一个实际的生成应用

方式:

  • 📝 写一篇 800 字左右的文章
  • 🎤 录一段 10-15 分钟的视频
  • 👥 找个朋友,给他讲一遍

第 3 步:标记卡壳点(5 分钟)

我今天卡壳的地方: □ _________________________________ □ _________________________________ □ _________________________________

第 4 步:针对性复习(5 分钟)

回到教程中卡壳的地方,重新学习,然后再次尝试解释!


📝 费曼学习笔记模板

╔═══════════════════════════════════════════════════╗ ║ Day 17 费曼学习笔记 ║ ╠═══════════════════════════════════════════════════╣ ║ 日期:__________ ║ ║ 学习时长:__________ ║ ╠═══════════════════════════════════════════════════╣ ║ ║ ║ 1. 我向小白解释了: ║ ║ _______________________________________________ ║ ║ _______________________________________________ ║ ║ ║ ║ 2. 我卡壳的地方: ║ ║ □ _____________________________________________ ║ ║ □ _____________________________________________ ║ ║ ║ ║ 3. 我的通俗比喻: ║ ║ • GAN 就像 ______ ║ ║ • 生成器就像 ______ ║ ║ • 判别器就像 ______ ║ ║ • 对抗训练就像 ______ ║ ║ ║ ║ 4. 我还想知道: ║ ║ _______________________________________________ ║ ║ ║ ╚═══════════════════════════════════════════════════╝

📊 今日总结

✅ 你今天学到了:

1. GAN 基础

  • 生成器 vs 判别器
  • 对抗训练的思想
  • 实际应用价值

2. DCGAN 架构

  • 转置卷积放大
  • 卷积压缩判断
  • 完整的训练流程

3. 实践能力

  • 搭建 GAN 模型
  • 训练和调试
  • 可视化生成效果

4. 费曼输出能力

  • 能用比喻解释 GAN
  • 能向小白说明对抗训练
  • 能完整讲解代码逻辑

🎁 明日预告

明天你将学习:

主题:Transformer 架构 内容: ✓ 改变世界的架构 ✓ Attention is All You Need ✓ 并行处理序列 ✓ BERT、GPT 的基础 ✓ 自注意力机制详解 需要准备: ✓ 复习今天的 GAN 概念 ✓ 了解 attention 的思想 ✓ 保持好奇心!

🆘 常见问题

Q1: GAN 为什么难训练?

原因 1:两个网络要平衡 → G 太强:D 跟不上,学不到东西 → D 太强:G 总是失败,失去信心 → 要找平衡点 原因 2:模式崩溃 → G 发现某个方法总能骗过 D → 就一直用这个方法 → 生成的都一样 原因 3:梯度消失 → D 太厉害,一眼看出假的 → G 得不到有效反馈 → 无法改进 解决方案: - 用好的架构(DCGAN、WGAN) - 调整学习率 - 耐心调参

Q2: GAN 和 VAE 有什么区别?

GAN (生成对抗网络): ✓ 生成效果好(清晰) ✗ 训练困难 ✗ 不能控制生成内容 VAE (变分自编码器): ✓ 训练稳定 ✓ 可以控制生成 ✗ 生成较模糊 选择: - 追求质量 → GAN - 追求可控 → VAE - 两者结合 → VQ-VAE

Q3: GAN 除了生成图片还能做什么?

文本生成: → 写诗、写文章 → 聊天机器人 音乐生成: → 作曲 → 编曲 视频生成: → 预测下一帧 → 视频修复 数据增强: → 生成训练数据 → 解决数据不足 其他: → 药物发现 → 材料设计 → 天气预报

💪 最后的鼓励

第十七天完成了!🎉

你已经掌握了: ✓ Week 1: 机器学习基础 ✓ Week 2: 深度学习入门 ✓ Week 3: 进阶深度学习(3/7) 这是质的飞跃! 从今天起: ✓ 你能做 AI 创作了 ✓ 你能解释 GAN 了 ✓ 你能训练生成模型了 ✓ 你能创造生动的比喻了 记住这个成就感! 每天都在进步! 每天都在变强! 继续加油!明天学习 Transformer!💪 记住: "创造比识别更难" 你现在有了这种创造的能力, 可以做更多有趣的事情了! 加油!我相信你一定可以的!✨

📞 打卡模板

日期:___________ 学习时长:_______ 小时 费曼输出次数:_______ 次 今天学会了: 遇到的卡壳点: 如何用比喻解释的: 明天的目标:

明天见!继续加油!


🔗 相关链接

🌐 项目资源

  • 💻GitHub 仓库: https://github.com/Lee985-cmd/AI-30-Day-Challenge
  • 📖CSDN 专栏: https://blog.csdn.net/m0_67081842?type=blog
  • 如果觉得有帮助,请给 GitHub 仓库 Star 支持!

本教程属于 AI 入门 30 天挑战 系列


🎉 恭喜你完成今天的学习!

💬 互动时间

思考题:今天的知识点中,哪个让你印象最深刻?为什么?

欢迎在评论区分享你的想法或疑问!👇

❤️ 如果有帮助

  • 👍点赞:让更多人看到这篇教程
  • Star GitHub:获取完整代码和项目
  • 关注专栏:不错过后续更新
  • 🔄分享给朋友:一起学习进步

明天见!继续 Day 18 的学习~🚀


📱 关于作者 & 获取更多资源

本教程由Lee(职场宝爸)创建,记录从零基础到独立完成 AI 项目的真实历程。


💡学习建议

如果本篇教程对你有帮助,欢迎:

  1. Star GitHub 项目:https://github.com/Lee985-cmd/AI-30Days-Challenge
  2. 留言交流你的学习困惑

一起学习,一起进步!🤝

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 11:16:50

基于安卓的网约车安全行程分享系统毕业设计源码

博主介绍&#xff1a;✌ 专注于Java,python,✌关注✌私信我✌具体的问题&#xff0c;我会尽力帮助你。一、研究目的本研究旨在设计并实现一种基于安卓平台的网约车安全行程分享系统以应对当前智能出行领域中日益突出的安全与隐私挑战。随着移动互联网技术的普及及网约车服务模式…

作者头像 李华
网站建设 2026/4/27 11:14:19

从iPhone 15到千元安卓机:我的小程序自定义导航栏全机型适配踩坑实录

从iPhone 15到千元安卓机&#xff1a;我的小程序自定义导航栏全机型适配踩坑实录 作为一名长期奋战在一线的小程序开发者&#xff0c;最近接手了一个需要高度定制UI的项目&#xff0c;其中自定义导航栏和底部Tabbar的适配成了最棘手的难题。本以为按照文档配置就能轻松搞定&…

作者头像 李华
网站建设 2026/4/27 11:13:20

AI助手集成YouTube下载技能:基于Agent Skills的智能视频获取方案

1. 项目概述&#xff1a;一个为AI助手打造的智能YouTube下载器如果你经常和Claude、Cursor这类AI编程助手打交道&#xff0c;并且有下载YouTube视频的需求&#xff0c;那么你很可能已经厌倦了在终端和浏览器之间来回切换&#xff0c;手动输入一长串yt-dlp命令的繁琐过程。yaniv…

作者头像 李华