<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Anpier</title><description>Blog</description><link>https://anpier.cn/</link><language>zh_CN</language><item><title>远程服务器用 aliyunpan 备份 checkpoints</title><link>https://anpier.cn/posts/serveraliyunpanbackup-checkpoints/</link><guid isPermaLink="true">https://anpier.cn/posts/serveraliyunpanbackup-checkpoints/</guid><description>数据盘不够用，把训练工程和 checkpoints 打包上传到阿里云盘。</description><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;远程服务器的数据盘太小，又不想直接删训练工程和 checkpoints ，所以把这些文件打包传到阿里云盘里备份一下。&lt;/p&gt;
&lt;p&gt;用的是 &lt;code&gt;tickstep/aliyunpan&lt;/code&gt;，流程很简单：登录阿里云盘，建备份目录，压缩，上传。&lt;/p&gt;
&lt;h2&gt;准备 aliyunpan&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cd ~
wget https://github.com/tickstep/aliyunpan/releases/download/v0.3.9/aliyunpan-v0.3.9-linux-amd64.zip
unzip aliyunpan-v0.3.9-linux-amd64.zip
cd aliyunpan-v0.3.9-linux-amd64
chmod +x aliyunpan
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;./aliyunpan
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;aliyunpan &amp;gt; login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;终端会给一个登录链接，复制到浏览器里打开。它会先授权一次，再扫码一次，弄完之后回到终端按 &lt;code&gt;Enter&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;授权链接就不放原文了，每次生成都不一样，有效时间比较短。&lt;/p&gt;
&lt;h2&gt;建备份目录&lt;/h2&gt;
&lt;p&gt;登录成功后，在阿里云盘里建一个按项目和日期分开的目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;aliyunpan:/ 你的账号名(备份盘)$ mkdir /备份
创建文件夹成功: /备份

aliyunpan:/ 你的账号名(备份盘)$ mkdir /备份/2026-6-8
创建文件夹成功: /备份/2026-6-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样之后找文件会方便一点。&lt;/p&gt;
&lt;h2&gt;打包 checkpoints&lt;/h2&gt;
&lt;p&gt;服务器上先装一下 &lt;code&gt;zstd&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt update
apt install -y zstd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这次要备份的目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CKPT_DIR=自己填
OUT=自己填
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;tar --zstd -cvf &quot;$OUT&quot; \
  -C &quot;$(dirname &quot;$CKPT_DIR&quot;)&quot; \
  &quot;$(basename &quot;$CKPT_DIR&quot;)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;上传&lt;/h2&gt;
&lt;p&gt;回到 &lt;code&gt;aliyunpan&lt;/code&gt; 里面上传：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;upload 压缩包地址 /备份/2026-6-8 -ui
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传完之后进目录看一眼：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /备份/2026-6-8
ls
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>RSRefSeg2 环境搭建与实验复现（RTX A800）</title><link>https://anpier.cn/posts/deep_learning_rsrefseg2_environment/</link><guid isPermaLink="true">https://anpier.cn/posts/deep_learning_rsrefseg2_environment/</guid><description>记录一下环境搭建的过程</description><pubDate>Sat, 14 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note
要复现论文的github：&lt;a href=&quot;https://github.com/KyanChen/RSRefSeg2&quot;&gt;&lt;strong&gt;RSRefSeg2&lt;/strong&gt;&lt;/a&gt;
:::&lt;/p&gt;
&lt;h1&gt;下载并安装 Miniconda&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

# 非代理服务器用下面这个
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;bash Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Do you wish the installer to initialize Miniconda3? yes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;创建干净环境（Python 3.10）&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;conda create -n rsrefseg2 python=3.11
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;conda activate rsrefseg2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装 A800 的 PyTorch&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 -f https://mirrors.aliyun.com/pytorch-wheels/cu121/
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装 &lt;a href=&quot;https://mmcv.readthedocs.io/en/latest/get_started/installation.html&quot;&gt;MMCV2.2.x&lt;/a&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install -U openmim
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;mim install mmcv==2.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装其他依赖项&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install deepspeed==0.17.2  
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install transformers==4.53.1 datasets==2.16.1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install -U ipdb braceexpand mat4py pycocotools shapely ftfy scipy terminaltables wandb prettytable torchmetrics importlib_metadata einops peft
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install hydra-core iopath
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;拉取 RSRefSeg 2 工程&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/KyanChen/RSRefSeg2.git
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd RSRefSeg2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载 &lt;a href=&quot;https://huggingface.co/datasets/JessicaYuan/RefSegRS/tree/main&quot;&gt;RefSegRS&lt;/a&gt; 数据集&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;export HF_ENDPOINT=https://hf-mirror.com
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install hf_transfer
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;export HF_HUB_ENABLE_HF_TRANSFER=1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download JessicaYuan/RefSegRS \
	--repo-type dataset \
	--local-dir /home/ubuntu/RSRefSeg2/datasets/refsegrs
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install unzip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;unzip RefSegRS.zip -d /home/ubuntu/RSRefSeg2/datasets/refsegrs
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;RSRefSeg2/datasets/refsegrs
├── images/
├── masks/
├── output_phrase_test.txt
├── output_phrase_train.txt
├── output_phrase_val.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载 &lt;a href=&quot;https://github.com/Lsan2401/RMSIN&quot;&gt;RRSIS-D&lt;/a&gt; 数据集&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download \
  --repo-type dataset VoyageWang/rrsis-d \
  --local-dir /home/ubuntu/RSRefSeg2/datasets/rrsis_d 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;unzip JPEGImages.zip -d /home/ubuntu/RSRefSeg2/datasets/rrsis_d/images
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;ann_split 自行下载
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;unzip ann_split.zip -d /home/ubuntu/RSRefSeg2/datasets/rrsis_d/images
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;RSRefSeg2/datasets/rrsis_d
├── rrsisd
│   ├── refs(unc).p
│   └── instances.json
├── images
    └── rrsisd
        ├── JPEGImages/
        └── ann_split/
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载官方 checkpoint&lt;/h1&gt;
&lt;p&gt;自己创建文件夹 &lt;code&gt;/home/ubuntu/RSRefSeg2/checkpoints&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Refsegrs&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download KyanChen/RSRefSeg2 \
  --local-dir /home/ubuntu/RSRefSeg2/checkpoints \
  --local-dir-use-symlinks False \
  --include &quot;refsegrs.pth&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;RRSIS-D&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download KyanChen/RSRefSeg2 \
  --local-dir /home/ubuntu/RSRefSeg2/checkpoints \
  --local-dir-use-symlinks False \
  --include &quot;rrsisd.pth&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;验证实验&lt;/h1&gt;
&lt;h2&gt;Refsegrs&lt;/h2&gt;
&lt;p&gt;修改 &lt;code&gt;/home/ubuntu/RSRefSeg2/configs_RSRefSeg2/refsegrs_infer.py&lt;/code&gt; 中的数据集与保存路径&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;work_dir = &apos;/home/ubuntu/RSRefSeg2/work_dirs/refsegrs&apos;
data_root = &apos;/home/ubuntu/RSRefSeg2/datasets/refsegrs/images&apos;
cache_dir = &apos;/home/ubuntu/.cache/hf_models&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;python tools_mmseg/test.py configs_RSRefSeg2/refsegrs_infer.py checkpoints/refsegrs.pth
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;02/14 05:06:32 - mmengine - INFO - per class results:
02/14 05:06:32 - mmengine - INFO - 
+------------+-------+-------+---------+---------+---------+---------+---------+
|   class    |  cIoU |  gIoU | seg_0.5 | seg_0.6 | seg_0.7 | seg_0.8 | seg_0.9 |
+------------+-------+-------+---------+---------+---------+---------+---------+
| background | 98.80 | 98.67 |  100.0  |  99.94  |  99.89  |  99.61  |  98.29  |
|    mask    | 81.21 | 77.36 |  88.11  |  82.94  |  73.97  |  60.81  |  34.40  |
+------------+-------+-------+---------+---------+---------+---------+---------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;RRSIS-D&lt;/h2&gt;
&lt;p&gt;修改 &lt;code&gt;/home/ubuntu/RSRefSeg2/configs_RSRefSeg2/rrsisd_infer.py&lt;/code&gt; 中的数据集与保存路径&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;work_dir = &apos;/home/ubuntu/RSRefSeg2/work_dirs/rrsis_d&apos;
data_root = &apos;/home/ubuntu/RSRefSeg2/datasets/rrsis_d/images/JPEGImages&apos;
cache_dir = &apos;/home/ubuntu/.cache/hf_models&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;python tools_mmseg/test.py configs_RSRefSeg2/rrsisd_infer.py checkpoints/rrsisd.pth
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;02/14 05:27:16 - mmengine - INFO - per class results:
02/14 05:27:16 - mmengine - INFO - 
+------------+-------+-------+---------+---------+---------+---------+---------+
|   class    |  cIoU |  gIoU | seg_0.5 | seg_0.6 | seg_0.7 | seg_0.8 | seg_0.9 |
+------------+-------+-------+---------+---------+---------+---------+---------+
| background | 98.90 | 98.85 |  100.0  |  99.94  |  99.80  |  99.37  |  97.80  |
|    mask    | 79.66 | 69.06 |  80.03  |  75.64  |  65.18  |  50.59  |  31.08  |
+------------+-------+-------+---------+---------+---------+---------+---------+
``&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>SAMWISE 环境搭建与实验复现（RTX 5090）</title><link>https://anpier.cn/posts/deep_learning_samwise_environment/</link><guid isPermaLink="true">https://anpier.cn/posts/deep_learning_samwise_environment/</guid><description>记录一下环境搭建的过程</description><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note
要复现论文的github：&lt;a href=&quot;https://github.com/ClaudiaCuttano/SAMWISE&quot;&gt;&lt;strong&gt;SAMWISE&lt;/strong&gt;&lt;/a&gt;
:::&lt;/p&gt;
&lt;h1&gt;下载并安装 Miniconda&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;bash Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Do you wish the installer to initialize Miniconda3? yes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;创建干净环境（Python 3.10）&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;conda create -n samwise python=3.10
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;conda activate samwise
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装 RTX5090 必须的 PyTorch（Nightly cu128）&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install --pre torch torchvision torchaudio \
  --index-url https://download.pytorch.org/whl/nightly/cu128
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;验证 GPU 是否正确支持&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;python - &amp;lt;&amp;lt;&apos;PY&apos;
import torch
print(&quot;torch:&quot;, torch.__version__)
print(&quot;cuda runtime:&quot;, torch.version.cuda)
print(&quot;gpu available:&quot;, torch.cuda.is_available())
print(&quot;gpu name:&quot;, torch.cuda.get_device_name(0))
PY
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;拉取 SAMWISE 工程&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/ClaudiaCuttano/SAMWISE.git
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd SAMWISE
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装依赖&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install -U pip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先删除 &lt;code&gt;requirements.txt&lt;/code&gt; 中的 &lt;code&gt;pyav&lt;/code&gt; ，之后单独装&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install -y ffmpeg libavdevice-dev libavfilter-dev libavformat-dev libavcodec-dev libswscale-dev libswresample-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install av==12.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;快速 sanity check&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;from models.samwise import build_samwise; print(&apos;SAMWISE import OK&apos;)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载Ref-DAVIS17数据集&lt;/h1&gt;
&lt;p&gt;Downlaod the DAVIS2017 dataset from the &lt;a href=&quot;https://davischallenge.org/davis2017/code.html&quot;&gt;website&lt;/a&gt;. Note that you only need to download the two zip files &lt;code&gt;DAVIS-2017-Unsupervised-trainval-480p.zip&lt;/code&gt; and &lt;code&gt;DAVIS-2017_semantics-480p.zip&lt;/code&gt;. Download the text annotations from the &lt;a href=&quot;https://www.mpi-inf.mpg.de/departments/computer-vision-and-machine-learning/research/video-segmentation/video-object-segmentation-with-language-referring-expressions&quot;&gt;website&lt;/a&gt;. Then, put the zip files in the directory as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SAMWISE
├── data
│   ├── ref-davis
│   │   ├── DAVIS-2017_semantics-480p.zip
│   │   ├── DAVIS-2017-Unsupervised-trainval-480p.zip
│   │   ├── davis_text_annotations.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://data.vision.ee.ethz.ch/csergi/share/davis/DAVIS-2017-Unsupervised-trainval-480p.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://data.vision.ee.ethz.ch/csergi/share/davis/DAVIS-2017_semantics-480p.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://www.mpi-inf.mpg.de/fileadmin/inf/d2/khoreva/davis_text_annotations.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unzip these zip files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unzip -o davis_text_annotations.zip
unzip -o DAVIS-2017_semantics-480p.zip
unzip -o DAVIS-2017-Unsupervised-trainval-480p.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Preprocess the dataset to Ref-Youtube-VOS format. (Make sure you are in the main directory)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python tools/data/convert_davis_to_ytvos.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, unzip the file &lt;code&gt;DAVIS-2017-Unsupervised-trainval-480p.zip&lt;/code&gt; again (since we use &lt;code&gt;mv&lt;/code&gt; in preprocess for efficiency).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unzip -o DAVIS-2017-Unsupervised-trainval-480p.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载 Ref-DAVIS17 Model&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;SAMWISE
├── pretrain
│   ├── final_model_mevis.pth
│   ├── final_model_ytvos.pth  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内网无法访问 google drive，自行下载到电脑上后，上传至服务器&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Total Parameters&lt;/th&gt;
&lt;th&gt;Trainable Params&lt;/th&gt;
&lt;th&gt;J&amp;amp;F&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Zip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MeViS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;210 M&lt;/td&gt;
&lt;td&gt;4.9 M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;49.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/1Molt2up2bP41ekeczXWQU-LWTskKJOV2/view?usp=sharing&quot;&gt;Weights&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/10gnlVzFyPWa6pKk37eljKAR_7gJDcg72/view?usp=drive_link&quot;&gt;Zip&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MeViS - valid_u&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;210 M&lt;/td&gt;
&lt;td&gt;4.9 M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;57.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/1Molt2up2bP41ekeczXWQU-LWTskKJOV2/view?usp=sharing&quot;&gt;Weights&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ref-Youtube-VOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;210 M&lt;/td&gt;
&lt;td&gt;4.9 M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;69.2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/17Ei9XU678tCiiV14c-9EB9ZqXVrj4qEw/view?usp=drive_link&quot;&gt;Weights&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/1bkO8lyR6Vyk6lHIcQqscvlDPYRiVMQJs/view?usp=drive_link&quot;&gt;Zip&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ref-Davis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;210 M&lt;/td&gt;
&lt;td&gt;4.9 M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70.6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://drive.google.com/file/d/17Ei9XU678tCiiV14c-9EB9ZqXVrj4qEw/view?usp=drive_link&quot;&gt;Weights&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1&gt;验证 Ref-DAVIS17 实验数据&lt;/h1&gt;
&lt;p&gt;由于我用的是5090，所以 &lt;code&gt;cuda&lt;/code&gt; 和 &lt;code&gt;torch&lt;/code&gt; 版本都不太一样&lt;/p&gt;
&lt;p&gt;先修改文件 &lt;a href=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/inference_davis.py&quot;&gt;&lt;code&gt;/SAMWISE/inference_davis.py&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我的服务器连接不上 &lt;code&gt;huggingface.co&lt;/code&gt; ，所以重定向到国内镜像网站 &lt;code&gt;hf-mirror.com&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export HF_ENDPOINT=https://hf-mirror.com
export HF_HUB_ENABLE_HF_TRANSFER=0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开始验证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 inference_davis.py --resume=/root/SAMWISE/pretrain/final_model_ytvos.pth --name_exp Ref-DAVIS17-evaluate  --HSA --use_cme_head
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>aerial-d 环境搭建与实验复现（RTX 5090）</title><link>https://anpier.cn/posts/deep_learning_aerial-d_environment/</link><guid isPermaLink="true">https://anpier.cn/posts/deep_learning_aerial-d_environment/</guid><description>记录一下环境搭建的过程</description><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note
要复现论文的github：&lt;a href=&quot;https://github.com/luispl77/aerial-d&quot;&gt;&lt;strong&gt;aerial-d&lt;/strong&gt;&lt;/a&gt;
:::&lt;/p&gt;
&lt;h1&gt;下载并安装 Miniconda&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;bash Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Do you wish the installer to initialize Miniconda3? yes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;创建干净环境（Python 3.12）&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;conda create -n aerial python=3.12
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;conda activate aerial
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装 RTX5090 必须的 PyTorch（Nightly cu128）&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install --pre torch torchvision torchaudio \
  --index-url https://download.pytorch.org/whl/nightly/cu128
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;验证 GPU 是否正确支持&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;python - &amp;lt;&amp;lt;&apos;PY&apos;
import torch
print(&quot;torch:&quot;, torch.__version__)
print(&quot;cuda runtime:&quot;, torch.version.cuda)
print(&quot;gpu available:&quot;, torch.cuda.is_available())
print(&quot;gpu name:&quot;, torch.cuda.get_device_name(0))
PY
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;拉取 SAMWISE 工程&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/luispl77/aerial-d.git
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd aerial-d
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;安装依赖&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install -U pip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;这两句添加注释
# torch==2.7.1
# torchvision==0.22.1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;pip install -i https://pypi.org/simple -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;快速 check&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0)); print(torch.cuda.get_device_capability(0))&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载数据集&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~/aerial-d
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download luisml77/aerial-d --repo-type dataset --local-dir datagen/dataset
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cd ~/aerial-d/datagen/dataset
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install unzip
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;unzip aeriald.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;下载 checkpoint&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~/aerial-d/rsrefseg
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;huggingface-cli download luisml77/rsrefseg \
  --repo-type model \
  --local-dir models
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;验证实验数据&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;cd ~/aerial-d
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;python test.py \
  --model_name rsrefseg_combined \
  --dataset_type aeriald \
  --sam_model facebook/sam-vit-large
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Cloudflare Turnstile 为静态博客添加「无感」人机验证</title><link>https://anpier.cn/posts/blogfuwaricloudflare-turnstile/</link><guid isPermaLink="true">https://anpier.cn/posts/blogfuwaricloudflare-turnstile/</guid><description>给自己的网站加一个人机验证</description><pubDate>Mon, 09 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Cloudflare 就是神，不接受反驳&lt;/h1&gt;
&lt;p&gt;Cloudflare 就是神，不接受反驳&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;创建 Turnstile 组件&lt;/h1&gt;
&lt;p&gt;进入 &lt;a href=&quot;https://www.cloudflare.com/zh-cn/application-services/products/turnstile/&quot;&gt;&lt;strong&gt;Cloudflare Turnstile&lt;/strong&gt;&lt;/a&gt; 官网，创建组件&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/3259b53a238063cec3c70c631b41c254.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/1b0d33b24718121307c4a1a8488a0ab8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
&lt;strong&gt;配置建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模式&lt;/strong&gt;：Managed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;域名&lt;/strong&gt;：你的站点域名&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预先许可（Cookie）&lt;/strong&gt;：关闭（我们自己控制）
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/484f177e1213f9d077ea12b4f90c866e.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建完成之后可以看到页面跳转，得到两个值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Site Key&lt;/strong&gt;（前端用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret Key&lt;/strong&gt;（服务端用）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/4fce00132c7ba86def2fd8af68f72ed4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;在 Pages 中配置 Secret Key&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/073e6b907221fa3b701c57be6049439d.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/ccfebf099107070ddbdd04eaaf65b8e7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: TURNSTILE_SECRET（一个字母都不能变）&lt;/li&gt;
&lt;li&gt;Value: xxxxxxxx（Secret Key）
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/e30d04592df603187928404ae4a991da.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;创建 gate 页面（前端）&lt;/h1&gt;
&lt;p&gt;新建文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/pages/gate.astro
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一个 &lt;strong&gt;自动检测 token → 自动跳转&lt;/strong&gt; 的代码（YOUR_SITE_KEY自行修改）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
const siteKey = &quot;YOUR_SITE_KEY&quot;;
const next = Astro.url.searchParams.get(&quot;next&quot;) ?? &quot;/&quot;;
---

&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang=&quot;zh-CN&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Human verification&amp;lt;/title&amp;gt;
    &amp;lt;script src=&quot;https://challenges.cloudflare.com/turnstile/v0/api.js&quot; async defer&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;

  &amp;lt;body class=&quot;gate&quot;&amp;gt;
    &amp;lt;main class=&quot;card&quot;&amp;gt;
      &amp;lt;h1&amp;gt;正在验证&amp;lt;/h1&amp;gt;
      &amp;lt;p class=&quot;desc&quot;&amp;gt;正常用户将自动通过，请稍候…&amp;lt;/p&amp;gt;
      &amp;lt;div class=&quot;cf-turnstile&quot; data-sitekey={siteKey}&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/main&amp;gt;

    &amp;lt;script define:vars={{ next }}&amp;gt;
      const timer = setInterval(async () =&amp;gt; {
        const tokenEl = document.querySelector(
          &apos;input[name=&quot;cf-turnstile-response&quot;]&apos;
        );
        const token = tokenEl?.value;
        if (!token) return;

        clearInterval(timer);

        const res = await fetch(&quot;/api/turnstile-verify&quot;, {
          method: &quot;POST&quot;,
          headers: { &quot;content-type&quot;: &quot;application/json&quot; },
          body: JSON.stringify({ token, next }),
        });

        if (res.ok) {
          const data = await res.json();
          location.replace(data.redirect || &quot;/&quot;);
        }
      }, 400);
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;服务端校验 Turnstile（Pages Functions）&lt;/h1&gt;
&lt;p&gt;新建文件（ &lt;code&gt;functions&lt;/code&gt; 文件夹在根目录下自行创建）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;functions/api/turnstile-verify.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// @ts-nocheck

export const onRequestPost = async (ctx) =&amp;gt; {
  const { token, next } = await ctx.request.json().catch(() =&amp;gt; ({}));

  if (!token) {
    return new Response(&quot;missing token&quot;, { status: 400 });
  }

  const form = new FormData();
  form.append(&quot;secret&quot;, ctx.env.TURNSTILE_SECRET);
  form.append(&quot;response&quot;, token);

  const ip = ctx.request.headers.get(&quot;CF-Connecting-IP&quot;);
  if (ip) form.append(&quot;remoteip&quot;, ip);

  const verify = await fetch(
    &quot;https://challenges.cloudflare.com/turnstile/v0/siteverify&quot;,
    {
      method: &quot;POST&quot;,
      body: form,
    }
  );

  const result = await verify.json();
  if (!result.success) {
    return new Response(&quot;verification failed&quot;, { status: 403 });
  }

  const redirect =
    typeof next === &quot;string&quot; &amp;amp;&amp;amp; next.startsWith(&quot;/&quot;) ? next : &quot;/&quot;;

  const cookie =
    &quot;cf_human=1; Path=/; Max-Age=43200; HttpOnly; Secure; SameSite=Lax&quot;;

  return new Response(JSON.stringify({ redirect }), {
    headers: {
      &quot;content-type&quot;: &quot;application/json&quot;,
      &quot;set-cookie&quot;: cookie,
    },
  });
};

&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;全站拦截（Middleware）&lt;/h1&gt;
&lt;p&gt;新建文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;functions/_middleware.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// @ts-nocheck

export const onRequest = async (ctx) =&amp;gt; {
  const url = new URL(ctx.request.url);
  const path = url.pathname;

  if (
    path.startsWith(&quot;/gate&quot;) ||
    path.startsWith(&quot;/api/turnstile-verify&quot;) ||
    path.startsWith(&quot;/_astro/&quot;) ||
    path.startsWith(&quot;/assets/&quot;) ||
    path.startsWith(&quot;/favicon&quot;)
  ) {
    return ctx.next();
  }

  const cookie = ctx.request.headers.get(&quot;Cookie&quot;) || &quot;&quot;;
  const passed = /(?:^|;\s*)cf_human=1(?:;|$)/.test(cookie);

  if (!passed) {
    const next = encodeURIComponent(path + url.search);
    return Response.redirect(`${url.origin}/gate?next=${next}`, 302);
  }

  return ctx.next();
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;部署与测试&lt;/h1&gt;
&lt;p&gt;将修改后的代码 &lt;code&gt;push&lt;/code&gt; 到 &lt;code&gt;github&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;测试流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;无痕窗口访问首页 → 自动跳 &lt;code&gt;/gate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;正常浏览器 → 页面一闪直接回首页&lt;/li&gt;
&lt;li&gt;VPN / 异常环境 → 出现 Turnstile 勾选&lt;/li&gt;
&lt;li&gt;验证成功后：
&lt;ul&gt;
&lt;li&gt;Cookie：&lt;code&gt;cf_human=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;12 小时内全站免验证&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>威联通 NAS + ROG 八爪鱼 + Nextcloud：家庭私有网盘</title><link>https://anpier.cn/posts/homelabqnapnasnextcloudrog/</link><guid isPermaLink="true">https://anpier.cn/posts/homelabqnapnasnextcloudrog/</guid><description>家里的 NAS 放了很久，官方软件的界面太难用了，正好家里有公网ip，统一搞一下</description><pubDate>Sat, 07 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;家里的威联通 NAS 放了很久，说实话一直有点&lt;strong&gt;吃灰&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;官方应用功能不少，但：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;界面复杂&lt;/li&gt;
&lt;li&gt;使用路径不直观&lt;/li&gt;
&lt;li&gt;更像“系统”，而不是“网盘”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最近正好家里有 &lt;strong&gt;公网 IPv4&lt;/strong&gt;，路由器是 &lt;strong&gt;ROG 八爪鱼&lt;/strong&gt; ，所以想实现：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;像用网盘一样用 NAS，但数据完全在自己家里。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最终方案是：&lt;br /&gt;
&lt;strong&gt;WireGuard + Nextcloud&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;我的网络与硬件环境&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;NAS：&lt;strong&gt;威联通 QNAP 464C&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;路由器：&lt;strong&gt;ASUS ROG 八爪鱼&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;网络：
&lt;ul&gt;
&lt;li&gt;公网 IPv4&lt;/li&gt;
&lt;li&gt;WireGuard 作为唯一远程入口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;系统部署方式：&lt;strong&gt;Container Station（Docker）&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;:::note
不暴露公网端口，只通过 VPN 访问私有云服务。
:::&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Nextcloud 应用拉取&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260207154548326.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;镜像源使用了国内镜像站，解决拉取超时问题。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260207154805080.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以下是我使用的，仅供参考：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &quot;3.8&quot;

services:
  nextcloud-db:
    image: docker.1ms.run/library/mariadb:10.11
    container_name: nextcloud-db
    environment:
      MYSQL_ROOT_PASSWORD: &quot;自行设置密码&quot;
      MYSQL_DATABASE: &quot;nextcloud&quot;
      MYSQL_USER: &quot;nextcloud&quot;
      MYSQL_PASSWORD: &quot;自行设置密码&quot;
      TZ: &quot;Asia/Shanghai&quot;
    volumes:
      - /share/Container/nextcloud/db:/var/lib/mysql
    restart: unless-stopped
    networks: [nextcloud-net]

  nextcloud:
    image: docker.1ms.run/linuxserver/nextcloud:latest
    container_name: nextcloud
    ports:
      - &quot;家里NAS的本地IP地址:8383:80&quot;
    volumes:
      - /share/Container/nextcloud/config:/config
      - /share/Container/nextcloud/data:/data
    environment:
      PUID: &quot;1000&quot;
      PGID: &quot;1000&quot;
      TZ: &quot;Asia/Shanghai&quot;
    restart: unless-stopped
    networks: [nextcloud-net]
    depends_on:
      - nextcloud-db
      - onlyoffice

  onlyoffice:
    image: docker.1ms.run/onlyoffice/documentserver:latest
    container_name: onlyoffice
    environment:
      TZ: &quot;Asia/Shanghai&quot;
      JWT_ENABLED: &quot;true&quot;
      JWT_SECRET: &quot;自行设置密码&quot;
      ALLOW_PRIVATE_IP_ADDRESS: &quot;true&quot;
      DB_TYPE: &quot;postgres&quot;
      DB_HOST: &quot;onlyoffice-postgresql&quot;
      DB_PORT: &quot;5432&quot;
      DB_NAME: &quot;onlyoffice&quot;
      DB_USER: &quot;onlyoffice&quot;
      DB_PWD: &quot;自行设置密码&quot;
      AMQP_URI: &quot;amqp://onlyoffice:自行设置密码@onlyoffice-rabbitmq&quot;
    ports:
      - &quot;家里NAS的本地IP地址:8888:80&quot;
    volumes:
      - /share/Container/onlyoffice/logs:/var/log/onlyoffice
      - /share/Container/onlyoffice/data:/var/www/onlyoffice/Data
      - /share/Container/onlyoffice/lib:/var/lib/onlyoffice
      - /share/Container/onlyoffice/db-cache:/var/lib/onlyoffice/documentserver/App_Data/cache/files
      - /share/Container/fonts:/usr/share/fonts/truetype/custom:ro
    restart: unless-stopped
    networks: [nextcloud-net]
    depends_on:
      - onlyoffice-postgresql
      - onlyoffice-rabbitmq

  onlyoffice-postgresql:
    image: docker.1ms.run/library/postgres:12
    container_name: onlyoffice-postgresql
    environment:
      POSTGRES_DB: &quot;onlyoffice&quot;
      POSTGRES_USER: &quot;onlyoffice&quot;
      POSTGRES_PASSWORD: &quot;自行设置密码&quot;
      TZ: &quot;Asia/Shanghai&quot;
    volumes:
      - /share/Container/onlyoffice/pgsql:/var/lib/postgresql/data
    restart: unless-stopped
    networks: [nextcloud-net]

  onlyoffice-rabbitmq:
    image: docker.1ms.run/library/rabbitmq:3
    container_name: onlyoffice-rabbitmq
    environment:
      TZ: &quot;Asia/Shanghai&quot;
      RABBITMQ_DEFAULT_USER: &quot;onlyoffice&quot;
      RABBITMQ_DEFAULT_PASS: &quot;自行设置密码&quot;
    volumes:
      - /share/Container/onlyoffice/rabbitmq:/var/lib/rabbitmq
    restart: unless-stopped
    networks: [nextcloud-net]

networks:
  nextcloud-net:
    driver: bridge

&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;初始化 Nextcloud&lt;/h1&gt;
&lt;p&gt;第一次访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://NAS内网IP:8383
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;初始化页面需要注意 &lt;strong&gt;数据库主机&lt;/strong&gt; 这一项：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库类型：MySQL / MariaDB
数据库用户：nextcloud
数据库密码：******
数据库名：nextcloud
数据库主机：nextcloud-db:3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/e978c7aedb165e3bb82045cd97fc9efc.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
&lt;strong&gt;不要填 localhost&lt;/strong&gt;&lt;br /&gt;
因为 Nextcloud 和数据库在不同容器中。
:::&lt;/p&gt;
&lt;p&gt;等待5min后（有概率504，不要管），重新进入该网址，可以看到初始化成功：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/zF77pUZ0pMYjohBq1YGN0k.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;路由器配置 DDNS&lt;/h1&gt;
&lt;p&gt;进入路由器配置界面，我这台路由器的默认本地 &lt;strong&gt;IP&lt;/strong&gt; 是 &lt;strong&gt;192.168.50.1&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260207155113834.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我这里使用的是 &lt;a href=&quot;https://www.noip.com/&quot;&gt;&lt;strong&gt;NOIP&lt;/strong&gt;&lt;/a&gt; 的免费服务，每一个账号享有一个，太感谢了！！&lt;/p&gt;
&lt;p&gt;自行注册账号并添加：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260207155804378.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;strong&gt;NOIP&lt;/strong&gt; 添加好之后，在路由器界面填写自己注册的信息，点击 &lt;strong&gt;应用本页面设置&lt;/strong&gt; ，等待几分钟后，看到注册成功，即成功添加&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;添加 WireGuard VPN 服务&lt;/h1&gt;
&lt;p&gt;进入路由器配置界面
&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260207160224233.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建新的 &lt;strong&gt;VPN&lt;/strong&gt; 客户端，在手机上或者电脑上下载软件 &lt;strong&gt;WireGuard&lt;/strong&gt; ，扫描二维码或者导入配置添加设备&lt;/p&gt;
&lt;p&gt;之后哪怕在外面，没有连接到家里的局域网，开启 &lt;strong&gt;VPN&lt;/strong&gt; 也可以用本地 &lt;strong&gt;IP&lt;/strong&gt; 连接到 &lt;strong&gt;路由器&lt;/strong&gt; 和&lt;strong&gt;NAS&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;折腾这一圈，其实NAS 不是不好用，只是以前用法不对。&lt;/p&gt;
&lt;p&gt;把复杂的东西都藏在后面，只留下 Nextcloud 这个“入口”，&lt;br /&gt;
再用 WireGuard 把访问方式收紧，整个体验一下子就顺了。&lt;/p&gt;
&lt;p&gt;现在用起来就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在外面先连一下 WireGuard&lt;/li&gt;
&lt;li&gt;打开 Nextcloud&lt;/li&gt;
&lt;li&gt;跟用普通网盘没什么区别&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还不得不感叹一句，华硕的八爪鱼真NB，不愧是钞能力&lt;/p&gt;
</content:encoded></item><item><title>配置 Vscode + Git + Github</title><link>https://anpier.cn/posts/vscodegitgithub/</link><guid isPermaLink="true">https://anpier.cn/posts/vscodegitgithub/</guid><description>我原来的电脑被我格式化了，环境都需要从头开始配，顺便记录一下</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Github 注册&lt;/h1&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;h1&gt;下载 Vscode&lt;/h1&gt;
&lt;p&gt;下载网站：&lt;a href=&quot;https://code.visualstudio.com/download&quot;&gt;Click!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下载完成后，在 &lt;strong&gt;Vscode&lt;/strong&gt; 中登录自己的 &lt;strong&gt;Github&lt;/strong&gt;账号&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111172954454.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;下载 &amp;amp; 安装 Git&lt;/h1&gt;
&lt;p&gt;下载网站：&lt;a href=&quot;https://git-scm.com/install/windows&quot;&gt;Click!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下载相应版本的 &lt;strong&gt;Git&lt;/strong&gt; ，可以得到:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111170836463.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击安装：&lt;/p&gt;
&lt;p&gt;:::note
没有展示的图片都是默认
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111171028945.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111171103927.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111171133209.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111171159119.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;配置 Git&lt;/h1&gt;
&lt;p&gt;打开 &lt;strong&gt;Git&lt;/strong&gt; 终端&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111171545060.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;用自己 &lt;strong&gt;github&lt;/strong&gt; 的 &lt;strong&gt;用户名&lt;/strong&gt; 和 &lt;strong&gt;邮箱&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global user.name &quot;John Doe&quot; 
git config --global user.email johndoe@example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我用的是 &lt;strong&gt;V2ray&lt;/strong&gt; 作为梯子，他的代理端口默认显示在最下方：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111172344851.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如上图可见，我这边的代理端口是10809，接着在 &lt;strong&gt;Git&lt;/strong&gt; 终端中输入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global http.proxy http://127.0.0.1:10809 
git config --global https.proxy http://127.0.0.1:10809
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可设置代理，提高连接速度&lt;/p&gt;
&lt;h1&gt;Push 至 Github&lt;/h1&gt;
&lt;p&gt;如果不经过配置，会出现如下报错：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111173213322.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;经检查发现，当开启了“保持邮箱私有（Keep my email addresses private）”选项时，如果本地 Git 使用的是真实邮箱地址进行提交，GitHub 为了保护你的隐私会拦截这次推送&lt;/p&gt;
&lt;p&gt;故输入如下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global user.email &quot;你的ID+用户名@users.noreply.github.com&quot;
git commit --amend --reset-author --no-edit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;邮箱可在 &lt;strong&gt;Github&lt;/strong&gt; 主页找到：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20260111174234427.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;即可成功解决&lt;/p&gt;
</content:encoded></item><item><title>ESP32 + 自己编写的组件陈列</title><link>https://anpier.cn/posts/esp32zujian/</link><guid isPermaLink="true">https://anpier.cn/posts/esp32zujian/</guid><description>都是自己写的组件</description><pubDate>Mon, 15 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;板载 RGB&lt;/h1&gt;
&lt;h2&gt;board_rgb&lt;/h2&gt;
&lt;p&gt;点击下载 : &lt;a href=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/Board_RGB.zip&quot;&gt; Click! &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;下载官方 RGB 组件&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213151219064.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213151321516.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213151353211.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;可以在工程中看到已经导入的组件, 如下图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213151438239.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;添加组件&lt;/h2&gt;
&lt;p&gt;见 &lt;a href=&quot;https://anpier.cn/posts/esp32addzujian/&quot;&gt; ESP32S3 + 组件添加教程 &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;在 main.c 中使用&lt;/h2&gt;
&lt;p&gt;可看到板载 &lt;strong&gt;RGB&lt;/strong&gt; 以红光闪烁&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;math.h&amp;gt;
#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;
#include &quot;driver/gpio.h&quot;
#include &quot;esp_log.h&quot;
#include &quot;esp_err.h&quot;
#include &quot;board_rgb.h&quot;

static const char *TAG = &quot;main&quot;;

static void hsv_to_rgb(float h, float s, float v,
                       uint8_t *r, uint8_t *g, uint8_t *b)
{
    float c = v * s;
    float x = c * (1 - fabsf(fmodf(h / 60.0f, 2) - 1));
    float m = v - c;

    float rf = 0, gf = 0, bf = 0;
    
    if (h &amp;lt; 60) {
        rf = c; gf = x; bf = 0;
    } else if (h &amp;lt; 120) {
        rf = x; gf = c; bf = 0;
    } else if (h &amp;lt; 180) {
        rf = 0; gf = c; bf = x;
    } else if (h &amp;lt; 240) {
        rf = 0; gf = x; bf = c;
    } else if (h &amp;lt; 300) {
        rf = x; gf = 0; bf = c;
    } else {
        rf = c; gf = 0; bf = x;
    }
    
    *r = (uint8_t)((rf + m) * 255);
    *g = (uint8_t)((gf + m) * 255);
    *b = (uint8_t)((bf + m) * 255);

}

void app_main(void)
{
    board_rgb_t rgb = {0};

    ESP_ERROR_CHECK(board_rgb_init(&amp;amp;rgb, 48)); // 我的 RGB LED 连接到 GPIO 48
    
    ESP_LOGI(TAG, &quot;Start rainbow RGB effect&quot;);
    
    float hue = 0.0f;
    uint8_t r, g, b;
    
    while (1) {
        hsv_to_rgb(hue, 1.0f, 0.3f, &amp;amp;r, &amp;amp;g, &amp;amp;b); // 0.3 比较柔和，不刺眼
        ESP_ERROR_CHECK(board_rgb_set(&amp;amp;rgb, r, g, b));
    
        hue += 2.0f;          // 调整这个值控制“转得快不快”
        if (hue &amp;gt;= 360.0f) {
            hue = 0.0f;
        }
    
        vTaskDelay(pdMS_TO_TICKS(20)); // 越小越顺
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;GPIO 初始化重写&lt;/h1&gt;
&lt;h2&gt;gpio_setup&lt;/h2&gt;
&lt;p&gt;点击下载 : &lt;a href=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/gpio_setup.zip&quot;&gt; Click! &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;添加组件&lt;/h2&gt;
&lt;p&gt;见 &lt;a href=&quot;https://anpier.cn/posts/esp32addzujian/&quot;&gt; ESP32S3 + 组件添加教程 &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;在 main.c 中使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;
#include &quot;driver/gpio.h&quot;
#include &quot;esp_log.h&quot;
#include &quot;esp_err.h&quot;
#include &quot;gpio_setup.h&quot;

void app_main(void)
{
    static const gpio_config_item_t gpio_init_table[] = {
        {
            .gpio_num = GPIO_NUM_48,
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = false,
            .pull_down_en = false,
            .level = 0,
            .intr_type = GPIO_INTR_DISABLE,
        },
        {
            .gpio_num = GPIO_NUM_0,
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = true,
            .pull_down_en = false,
            .level = 0,
            .intr_type = GPIO_INTR_DISABLE,
        },
    };

    gpio_setup_init(
        gpio_init_table,
        sizeof(gpio_init_table) / sizeof(gpio_init_table[0])
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;u8g2库 点亮 OLED&lt;/h1&gt;
&lt;h2&gt;修改 &lt;code&gt;main\idf_component.yml&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;:::note
不能用 &lt;code&gt;tab&lt;/code&gt; 来缩进, 不然会报错
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dependencies:
  ## Required IDF version
  idf:
    version: &apos;&amp;gt;=4.1.0&apos;
+ u8g2:
+   git: https://github.com/olikraus/u8g2.git
+ u8g2-hal-esp-idf:
+   git: https://github.com/mkfrey/u8g2-hal-esp-idf.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译结束后可在 &lt;code&gt;managed_components&lt;/code&gt; 中看到下载好的组件&lt;/p&gt;
&lt;h2&gt;在 main.c 中使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;math.h&amp;gt;
#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;
#include &quot;driver/gpio.h&quot;
#include &quot;esp_log.h&quot;
#include &quot;esp_err.h&quot;
#include &quot;u8g2.h&quot;
#include &quot;u8g2_esp32_hal.h&quot;

#define PIN_SDA   GPIO_NUM_4 
#define PIN_SCL   GPIO_NUM_5 
#define OLED_I2C_ADDRESS 0x3C

u8g2_t u8g2;

void init_display(void)
{
    u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT;
    u8g2_esp32_hal.bus.i2c.sda = PIN_SDA;
    u8g2_esp32_hal.bus.i2c.scl = PIN_SCL;
    u8g2_esp32_hal_init(u8g2_esp32_hal);
    
    u8g2_Setup_ssd1306_i2c_128x64_noname_f(
        &amp;amp;u8g2, U8G2_R0,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure

    u8x8_SetI2CAddress(&amp;amp;u8g2.u8x8, OLED_I2C_ADDRESS * 2);
    
    u8g2_InitDisplay(&amp;amp;u8g2);
    u8g2_SetPowerSave(&amp;amp;u8g2, 0);
    u8g2_ClearBuffer(&amp;amp;u8g2);
    
    u8g2_SetFont(&amp;amp;u8g2, u8g2_font_ncenB10_tr);
}

// 绘制函数示例
void draw_content(void) {
    u8g2_FirstPage(&amp;amp;u8g2);
    do {
        u8g2_DrawStr(&amp;amp;u8g2, 0, 15, &quot;S3 OLED Demo!&quot;);
        u8g2_DrawStr(&amp;amp;u8g2, 0, 30, &quot;Adrian!&quot;);
    } while (u8g2_NextPage(&amp;amp;u8g2));
}

void app_main(void)
{
    init_display();
    
    while(1) {
       draw_content();
       vTaskDelay(pdMS_TO_TICKS(5));
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;OLED 0.96寸 函数封装&lt;/h1&gt;
&lt;h2&gt;oled_iic_0.96&lt;/h2&gt;
&lt;p&gt;点击下载 : &lt;a href=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/oled_iic_0.96.zip&quot;&gt; Click! &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;添加组件&lt;/h2&gt;
&lt;p&gt;见 &lt;a href=&quot;https://anpier.cn/posts/esp32addzujian/&quot;&gt; ESP32S3 + 组件添加教程 &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;在 main.c 中使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;u8g2.h&quot;
#include &quot;u8g2_esp32_hal.h&quot;

#define PIN_SDA   GPIO_NUM_4 
#define PIN_SCL   GPIO_NUM_5 
#define OLED_I2C_ADDRESS 0x3C

u8g2_t u8g2;

void init_display(void)
{
	//设置一下使用的引脚
    u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT;
    u8g2_esp32_hal.bus.i2c.sda = PIN_SDA;
    u8g2_esp32_hal.bus.i2c.scl = PIN_SCL;
    u8g2_esp32_hal_init(u8g2_esp32_hal);
    
    // 针对不同的屏幕使用不同的初始化函数
    u8g2_Setup_ssd1306_i2c_128x64_noname_f(
        &amp;amp;u8g2, U8G2_R0,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
        
    // 0x3c -&amp;gt; 0x78 (I2C 地址乘以 2)
    u8x8_SetI2CAddress(&amp;amp;u8g2.u8x8, OLED_I2C_ADDRESS * 2); // **已修正：确保乘以 2**
    
    u8g2_InitDisplay(&amp;amp;u8g2);     // send init sequence to the display
    u8g2_SetPowerSave(&amp;amp;u8g2, 0); // wake up display
    u8g2_ClearBuffer(&amp;amp;u8g2);
    
    // 建议设置一个默认字体
    u8g2_SetFont(&amp;amp;u8g2, u8g2_font_ncenB10_tr);
}

// 绘制函数示例
void draw_content(void) {
    u8g2_FirstPage(&amp;amp;u8g2);
    do {
        u8g2_DrawStr(&amp;amp;u8g2, 0, 15, &quot;S3 OLED Demo!&quot;);
        u8g2_DrawStr(&amp;amp;u8g2, 0, 30, &quot;Adrian!&quot;);
    } while (u8g2_NextPage(&amp;amp;u8g2));
}

void app_main(void)
{
    init_display();
    
    while(1) {
       draw_content();
       vTaskDelay(pdMS_TO_TICKS(5));
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;oled_iic_0.96.h&quot;

void app_main(void)
{
    oled_iic_096_init(4, 5, 0x3C, NULL);
    //oled_iic_096_demo(&quot;Adrian&quot;);
    u8g2_t *u8g2 = oled_iic_096_get_u8g2();
    
    while(1)
    {
        u8g2_ClearBuffer(u8g2);
        u8g2_DrawStr(u8g2, 38, 18, &quot;Adrian&quot;);
        u8g2_SendBuffer(u8g2);
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;HCSR04 超声波传感器&lt;/h1&gt;
&lt;h2&gt;hscr04&lt;/h2&gt;
&lt;p&gt;点击下载 : &lt;a href=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/hcsr04.zip&quot;&gt; Click! &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;添加组件&lt;/h2&gt;
&lt;p&gt;见 &lt;a href=&quot;https://anpier.cn/posts/esp32addzujian/&quot;&gt; ESP32S3 + 组件添加教程 &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;在 main.c 中使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;hcsr04.h&quot;
#include &quot;oled_iic_0.96.h&quot;

void app_main(void)
{
     hcsr04_config_t cfg = {
        .trig_gpio = 18,          
        .echo_gpio = 17,          
        .sound_speed_m_s = 343.0f,
        .timeout_us = 10000,
    };
    ESP_ERROR_CHECK(hcsr04_init(&amp;amp;cfg));

    while(1)
    {
        u8g2_ClearBuffer(u8g2);
        int16_t mm = 0;
        esp_err_t err = hcsr04_read_mm(&amp;amp;mm);

        char line1[32];
        char line2[32];

        if (err == ESP_OK)
        {
            float cm = mm / 10.0f;
            snprintf(line1, sizeof(line1), &quot;mm: %d&quot;, (int)mm);
            snprintf(line2, sizeof(line2), &quot;cm: %.1f&quot;, cm);
            u8g2_DrawStr(u8g2, 30, 35, line1);
            u8g2_DrawStr(u8g2, 30, 51, line2);
        } 
        else 
        {
            snprintf(line1, sizeof(line1), &quot;Read failed&quot;);
            snprintf(line2, sizeof(line2), &quot;%s&quot;, esp_err_to_name(err));
            u8g2_DrawStr(u8g2, 30, 35, line1);
            u8g2_DrawStr(u8g2, 30, 51, line2);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Astro 和 Fuwari 的部署优化指南</title><link>https://anpier.cn/posts/blogfuwarirefine/</link><guid isPermaLink="true">https://anpier.cn/posts/blogfuwarirefine/</guid><description>Fuwari框架的使用指南</description><pubDate>Sun, 14 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;添加友链&lt;/h1&gt;
&lt;h2&gt;添加友链页面文件&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;src\content\spec&lt;/code&gt;目录下新建文件&lt;code&gt;friends.md&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;src\types\config.ts&lt;/code&gt;文件约41行位置添加以下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export enum LinkPreset {
    Home = 0,
    Archive = 1,
    About = 2,
+   Friends = 3,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;国际化i18n翻译&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;src\i18n\i18nKey.ts&lt;/code&gt;文件约35行位置添加以下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    author = &quot;author&quot;,
    publishedAt = &quot;publishedAt&quot;,
    license = &quot;license&quot;,
+   friends = &apos;friends&apos;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按照自己的语言，在 &lt;code&gt;src\i18n\languages&lt;/code&gt; 目录中编辑相应语言文件,以 &lt;code&gt;zh_CN.ts&lt;/code&gt; 为例，在约 38 行位置添加内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    [Key.author]: &quot;作者&quot;,
    [Key.publishedAt]: &quot;发布于&quot;,
    [Key.license]: &quot;许可协议&quot;,
+   [Key.friends]: &apos;友链&apos;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;src\constants\link-presets.ts&lt;/code&gt; 文件约 18 行位置添加内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	[LinkPreset.Archive]: {
        name: i18n(I18nKey.archive),
        url: &quot;/archive/&quot;,
    },
+   [LinkPreset.Friends]: {
+       name: i18n(I18nKey.friends),
+       url: &apos;/friends/&apos;,
+   },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;创建和配置页面的Astro文件并创建卡片效果友链&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;src\pages&lt;/code&gt;目录下复制原本的&lt;code&gt;about.astro&lt;/code&gt;文件，重命名为&lt;code&gt;friends.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
import MainGridLayout from &apos;../layouts/MainGridLayout.astro&apos;
import { getCollection } from &apos;astro:content&apos;
import { i18n } from &apos;../i18n/translation&apos;
import I18nKey from &apos;../i18n/i18nKey&apos;
import Markdown from &apos;@components/misc/Markdown.astro&apos;

const specPosts = await getCollection(&apos;spec&apos;)
const friendsPost = specPosts.find(post =&amp;gt; post.id === &apos;friends.md&apos;)
const { Content } = await friendsPost.render()

const items = [
  {  
    title: &apos;Astro&apos;,  
    imgurl: &apos;https://avatars.githubusercontent.com/u/44914786?s=48&amp;amp;v=4&apos;,  
    desc: &apos;The web framework for content-driven websites. ⭐️ Star to support our work!&apos;,  
    siteurl: &apos;https://github.com/withastro/astro&apos;,  
    tags: [&apos;&apos;],  
  },
 
]
---
&amp;lt;MainGridLayout title={i18n(I18nKey.friends)} description={i18n(I18nKey.friends)}&amp;gt;
    &amp;lt;div class=&quot;flex w-full rounded-[var(--radius-large)] overflow-hidden relative min-h-32&quot;&amp;gt;
        &amp;lt;div class=&quot;card-base z-10 px-9 py-6 relative w-full &quot;&amp;gt; 
            &amp;lt;div class=&quot;grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-8 my-4&quot;&amp;gt;
                {items.map((item) =&amp;gt; (   
                    &amp;lt;div class=&quot;flex flex-nowrap items-stretch h-28 gap-4 rounded-[var(--radius-large)]&quot;&amp;gt;
                        &amp;lt;div class=&quot;w-28 h-28 flex-shrink-0 rounded-lg overflow-hidden bg-zinc-200&quot;&amp;gt;
                            &amp;lt;img src={item.imgurl} alt=&quot;站点头像&quot; class=&quot;w-full h-full object-cover&quot;&amp;gt;
                        &amp;lt;/div&amp;gt;
                        &amp;lt;div class=&quot;grow w-full&quot;&amp;gt;
                            &amp;lt;div class=&quot;font-bold transition text-lg text-neutral-900 mb-1&quot;&amp;gt;{item.title}&amp;lt;/div&amp;gt;
                            &amp;lt;div class=&quot;text-50 text-sm font-medium&quot;&amp;gt;{item.desc}&amp;lt;/div&amp;gt;
                            &amp;lt;div class:list={[&quot;items-center&quot;, {&quot;flex&quot;: true, &quot;hidden md:flex&quot; : false}]}&amp;gt;
                                &amp;lt;div class=&quot;flex flex-row flex-nowrap items-center&quot;&amp;gt;
                                    {(item.tags &amp;amp;&amp;amp; item.tags.length &amp;gt; 0) &amp;amp;&amp;amp; item.tags.map((tag,i) =&amp;gt; (  
                                    &amp;lt;div class:list={[{&quot;hidden&quot;: i==0}, &quot;mx-1.5 text-[var(--meta-divider)] text-sm&quot; ]}&amp;gt;
                                        /
                                    &amp;lt;/div&amp;gt;  
                                    &amp;lt;span class=&quot;transition text-50 text-sm font-medium&quot;&amp;gt;
                                        {tag}
                                    &amp;lt;/span&amp;gt;))}
                                    {!(item.tags &amp;amp;&amp;amp; item.tags.length &amp;gt; 0) &amp;amp;&amp;amp; &amp;lt;div class=&quot;transition text-50 text-sm font-medium&quot;&amp;gt;{i18n(I18nKey.noTags)}&amp;lt;/div&amp;gt;}
                                &amp;lt;/div&amp;gt;
                            &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                        &amp;lt;a href={item.siteurl} target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;class=&quot;flex btn-regular w-[3.25rem] rounded-lg bg-[var(--enter-btn-bg)] hover:bg-[var(--enter-btn-bg-hover)] active:bg-[var(--enter-btn-bg-active)] active:scale-95&quot;&amp;gt;
                            &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; aria-hidden=&quot;true&quot; role=&quot;img&quot; class=&quot;transition text-[var(--primary)] text-4xl mx-auto iconify iconify--material-symbols&quot; width=&quot;1em&quot; height=&quot;1em&quot; viewBox=&quot;0 0 24 24&quot;&amp;gt;
                                &amp;lt;path fill=&quot;currentColor&quot; d=&quot;M12.6 12L8.7 8.1q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.6 4.6q.15.15.213.325t.062.375t-.062.375t-.213.325l-4.6 4.6q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7z&quot;&amp;gt;&amp;lt;/path&amp;gt;
                            &amp;lt;/svg&amp;gt;
                        &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;
                ))}
            &amp;lt;/div&amp;gt;  
            &amp;lt;Markdown class=&quot;mt-2&quot;&amp;gt; 
                &amp;lt;Content /&amp;gt;
            &amp;lt;/Markdown&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/MainGridLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;在导航栏中添加友链页面&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;src\config.ts&lt;/code&gt; 文件约 &lt;code&gt;48&lt;/code&gt; 行位置添加内容，注意要在 &lt;code&gt;LinkPreset.About&lt;/code&gt; 末尾添加&lt;code&gt;,&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export const navBarConfig: NavBarConfig = {
  links: [
    LinkPreset.Home,
    LinkPreset.Archive,
+   LinkPreset.About,
+   LinkPreset.Friends,
    {
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;新窗口/新标签页打开&lt;/h1&gt;
&lt;h2&gt;安装/更新 &lt;code&gt;rehype-external-links&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;pnpm add rehype-external-links
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;修改 &lt;code&gt;astro.config.mjs&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;rehypePlugins: [
  rehypeKatex,
  rehypeSlug,
  [
+   rehypeExternalLinks,
+   {
+     target: &quot;_blank&quot;,
+     rel: [&quot;noopener&quot;, &quot;noreferrer&quot;],
+   },
+ ],
  // 后面的 rehypeComponents / rehypeAutolinkHeadings 保持不动
  ...
]

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Github + PicGo 搭建图床教程</title><link>https://anpier.cn/posts/bloggithubimagebed/</link><guid isPermaLink="true">https://anpier.cn/posts/bloggithubimagebed/</guid><description>24年1月1日后腾讯云的URL只能下载, 没有备案的域名不能预览了 QAQ</description><pubDate>Sat, 13 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;创建 Github 仓库&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150148976.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;创建 Token&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;进入账号 Settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150342716.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;左侧栏最下方 Developer settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150447771.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;选择创建 classic Token&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150552371.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内容填写如下&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150700640.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
务必记住 &lt;strong&gt;Token&lt;/strong&gt; 的内容,只会出现一次
:::&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;编辑 Picgo&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213150842394.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;即搭建完成&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>ESP32S3 + 组件添加教程</title><link>https://anpier.cn/posts/esp32addzujian/</link><guid isPermaLink="true">https://anpier.cn/posts/esp32addzujian/</guid><description>网上类似资料信息比较少, 记录一下, 防止忘记</description><pubDate>Sat, 13 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;组件修改流程&lt;/h1&gt;
&lt;h2&gt;组件结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;your_project/
├─ CMakeLists.txt          ← 根 CMake，不用改
├─ main/
│  ├─ CMakeLists.txt       ← 根 CMake，需要修改
│  └─ main.c
└─ components/
   └─ COMPONENT_NAME/      ← COMPONENT_NAME 为组件名字
      ├─ CMakeLists.txt
      ├─ COMPONENT_NAME.c
      └─ include/
         └─ COMPONENT_NAME.h
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;添加组件&lt;/h2&gt;
&lt;p&gt;下载或者自行编写 &lt;strong&gt;组件&lt;/strong&gt; 文件, 将其放入 &lt;strong&gt;components&lt;/strong&gt; 文件夹中&lt;/p&gt;
&lt;p&gt;:::note
&lt;strong&gt;components&lt;/strong&gt;可能需要自行创建
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251213152749474.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;修改工程 CMakeLists.txt&lt;/h2&gt;
&lt;p&gt;:::note
注意, 是 &lt;code&gt;main\CMakeLists.txt&lt;/code&gt;
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215000617007.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;修改如下, 将名为 components 的目录添加到额外的组件搜索路径中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;idf_component_register(
    SRCS &quot;main.c&quot;
    INCLUDE_DIRS &quot;.&quot;
+   REQUIRES board_rgb 添加自己组件.h的名字
)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>腾讯云COS对象存储 + PicGo 搭建图床教程</title><link>https://anpier.cn/posts/blogtencent-cospicgo/</link><guid isPermaLink="true">https://anpier.cn/posts/blogtencent-cospicgo/</guid><description>记录一下图床搭建的过程, 以供之后参考</description><pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;PicGo 安装&lt;/h1&gt;
&lt;p&gt;给出官方GitHub网站, 自行下载&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Molunerfinn/PicGo&quot;}&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;创建存储桶&lt;/h1&gt;
&lt;p&gt;来到腾讯云&lt;a href=&quot;https://console.cloud.tencent.com/cos&quot;&gt;对象存储&lt;/a&gt;控制台，创建存储&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-38.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;访问权限选择 &lt;strong&gt;公有读私有写&lt;/strong&gt; ，否则图片无法读取，其他的根据自己往下填写就可以。 地域建议离你所在的位置越近越好。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-41.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../../assets/post-images/index-40.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;创建密钥&lt;/h1&gt;
&lt;p&gt;腾讯云头像–&amp;gt;&lt;a href=&quot;https://console.cloud.tencent.com/cam/overview&quot;&gt;访问管理&lt;/a&gt;–&amp;gt; &lt;a href=&quot;https://console.cloud.tencent.com/cam/capi&quot;&gt;API密钥管理&lt;/a&gt;，创建密钥，就会生成 &lt;strong&gt;APPID、SecretId和SecretKey&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-42.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-44.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
请务必保存好自己的密钥
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-45.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PicGo设置&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-49.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-46.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-47.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;配置完即可顺利上传了, 还有很多功能自行探索&lt;/p&gt;
</content:encoded></item><item><title>STM32解析富斯i6遥控器和FS-iA6B接收机的ibus通信</title><link>https://anpier.cn/posts/stm32flysky_i6ia6b/</link><guid isPermaLink="true">https://anpier.cn/posts/stm32flysky_i6ia6b/</guid><description>挺好玩的，比赛也有需要</description><pubDate>Sat, 01 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;对码&lt;/h1&gt;
&lt;p&gt;具体观看该视频：&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1BL4y1M7p6&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;接线&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-35.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;STM32接线略&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;程序&lt;/h1&gt;
&lt;p&gt;下载 &lt;strong&gt;remote.c&lt;/strong&gt; 与 &lt;strong&gt;remote.h&lt;/strong&gt; 文件：&lt;a href=&quot;https://image-bed-1326946071.cos.ap-shanghai.myqcloud.com/remote&quot;&gt; Click! &lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;现象&lt;/h1&gt;
&lt;h2&gt;帧模式&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-36.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;STM32 Debug&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-37.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>STM32H743XIH6 + HAL库 + CubeMX配置</title><link>https://anpier.cn/posts/stm32h743xih6_mode/</link><guid isPermaLink="true">https://anpier.cn/posts/stm32h743xih6_mode/</guid><description>记录一下遇到的问题和解决办法，省的自己过段时间全忘了</description><pubDate>Wed, 29 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;CubeMX配置&lt;/h1&gt;
&lt;p&gt;芯片选择STM32H743XIH6，TFBGA 240封装&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-16.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;RCC配置&lt;/h2&gt;
&lt;p&gt;HSE高速时钟使用外部晶振，其他采用默认设置。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来配置时钟&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://so.csdn.net/so/search?q=GPIO&amp;amp;spm=1001.2101.3001.7020&quot;&gt;GPIO&lt;/a&gt;配置&lt;/h2&gt;
&lt;p&gt;我这块板子上默认是PC13作为LED灯控制引脚：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;DEBUG配置&lt;/h2&gt;
&lt;p&gt;:::note
该项一定要配置！！！
:::&lt;/p&gt;
&lt;p&gt;我采用SW模式进行下载和调试程序：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;生成代码&lt;/h2&gt;
&lt;p&gt;部分设置如图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-21.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-22.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最后点击 &lt;strong&gt;GENERATE CODE&lt;/strong&gt; 生成代码&lt;/p&gt;
&lt;h1&gt;Keil5&lt;/h1&gt;
&lt;h2&gt;Target配置&lt;/h2&gt;
&lt;p&gt;打开 &lt;strong&gt;Target&lt;/strong&gt; 选项卡：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-23.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;框中选项 &lt;strong&gt;必须&lt;/strong&gt; 勾选，否则串口重定向后无法使用printf函数，程序会卡死：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-25.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;框中选项 &lt;strong&gt;必须&lt;/strong&gt; 勾选，以便程序可以右键跳转到函数或变量定义处：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-26.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;框中选择自己使用的仿真器，我用的是ST-Link，点击Settings后如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-27.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-28.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;框中选项 &lt;strong&gt;必须&lt;/strong&gt; 勾选&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-29.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-31.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Configuration配置&lt;/h2&gt;
&lt;p&gt;打开 &lt;strong&gt;Configuration&lt;/strong&gt; 选项卡：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-33.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我习惯于使用 &lt;strong&gt;UTF-8&lt;/strong&gt; 格式，并且加上代码补全提示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/index-34.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>深度学习工程模板</title><link>https://anpier.cn/posts/deep_learning_demo_project/</link><guid isPermaLink="true">https://anpier.cn/posts/deep_learning_demo_project/</guid><description>Deep learning Demo Project</description><pubDate>Sun, 26 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Import&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import os
import cv2
import PIL
import torch
import torchvision
import numpy as np
from torch import nn
from torch.utils.data import DataLoader
from torchvision.models import VGG16_Weights
from torch.utils.tensorboard import SummaryWriter
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;GPU训练&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;device = torch.device(&quot;cuda&quot; if torch.cuda.is_available() else &quot;cpu&quot;)
print(&quot;使用设备：{}&quot;.format(device))
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;准备&amp;amp;加载数据集&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;# 准备数据集
train_dataset = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;,
    train       = True,
    download    = True,
    transform   = torchvision.transforms.ToTensor()
)
train_dataset_size = len(train_dataset)
  
test_dataset = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;,
    train       = False,
    download    = True,
    transform   = torchvision.transforms.ToTensor()
)
test_dataset_size  = len(test_dataset)

print(&quot;----数据集导入成功----&quot;)
print(&quot;训练集大小：{}&quot;.format(train_dataset_size))
print(&quot;测试集大小：{}&quot;.format(test_dataset_size))


# 加载数据集
train_dataloader = DataLoader(
    dataset     = train_dataset,
    batch_size  = 64,
    shuffle     = True,
    num_workers = 0,
    drop_last   = False
)

test_dataloader = DataLoader(
    dataset     = test_dataset,
    batch_size  = 64,
    shuffle     = True,
    num_workers = 0,
    drop_last   = False
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;创建网络模型&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1      = nn.Conv2d(
            in_channels     = 3, 
            out_channels    = 32, 
            kernel_size     = 5, 
            padding         = 2
        )
        self.maxpool1   = nn.MaxPool2d(
            kernel_size = 2,
        )
        self.conv2      = nn.Conv2d(
            in_channels     = 32, 
            out_channels    = 32, 
            kernel_size     = 5, 
            padding         = 2
        )
        self.maxpool2   = nn.MaxPool2d(
            kernel_size = 2,
        )
        self.conv3      = nn.Conv2d(
            in_channels     = 32, 
            out_channels    = 64, 
            kernel_size     = 5, 
            padding         = 2
        )
        self.maxpool3   = nn.MaxPool2d(
            kernel_size = 2,
        )
        self.flatten    = nn.Flatten()
        self.linear1    = nn.Linear(
            in_features    = 64 * 4 * 4,    
            out_features   = 64
        )
        self.linear2    = nn.Linear(
            in_features    = 64,
            out_features   = 10
        )
        self.seq        = nn.Sequential(
            self.conv1,
            self.maxpool1,
            self.conv2,
            self.maxpool2,
            self.conv3,
            self.maxpool3,
            self.flatten,
            self.linear1,
            self.linear2
        )
    
    def forward(self, input):
        output = self.seq(input)
        return output
    
my_model = My_Model()
my_model = my_model.to(device)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;损失函数&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;优化器&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;Learnig_rate = 0.002
optim = torch.optim.Adam(
    params      = my_model.parameters(),
    lr          = Learnig_rate
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;设置训练参数&amp;amp;开始训练&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;total_train_step = 0 # 记录训练的次数
total_test_step  = 0 # 记录测试的次数
epoch = 10          # 训练轮数
writer = SummaryWriter(&quot;./logs&quot;)  # TensorBoard 日志保存路径

for i in range(epoch):
    print(&quot;--------第 {} 轮训练开始--------&quot;.format(i + 1))
    
    # 训练步骤
    my_model.train()
    for data in train_dataloader:
        imgs, targets = data
        imgs    = imgs.to(device)
        targets = targets.to(device)
        
        outputs = my_model(imgs)
        loss = loss_fn(outputs, targets)

        optim.zero_grad()   # 清空上一步的残余更新参数值
        loss.backward()     # 反向传播，计算参数更新值
        optim.step()       # 更新参数

        total_train_step += 1
        if total_train_step % 100 == 0:
            print(&quot;训练次数：{}，Loss：{}&quot;.format(total_train_step, loss.item()))
            writer.add_scalar(&quot;train_loss&quot;, loss.item(), total_train_step)

    torch.save(my_model.state_dict(), &quot;./My_Model/model_{}.pth&quot;.format(i))
    print(&quot;模型已保存&quot;)

    # 测试步骤
    my_model.eval()
    total_test_loss = 0
    total_accuracy  = 0
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            imgs    = imgs.to(device)
            targets = targets.to(device)

            outputs = my_model(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss += loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy += accuracy

    print(&quot;整体测试集上的Loss：{}&quot;.format(total_test_loss))
    print(&quot;整体测试集上的正确率：{}&quot;.format(total_accuracy / test_dataset_size))
    writer.add_scalar(&quot;test_loss&quot;, total_test_loss, total_test_step)
    writer.add_scalar(&quot;test_accuracy&quot;, total_accuracy / test_dataset_size, total_test_step)
    total_test_step += 1
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>配置 ESP32 + VScode + ESP-IDF 环境</title><link>https://anpier.cn/posts/esp32vscode/</link><guid isPermaLink="true">https://anpier.cn/posts/esp32vscode/</guid><description>在Window11上配置ESP32开发环境</description><pubDate>Thu, 23 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;VScode下载&lt;/h1&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;离线安装 ESP-IDF 环境&lt;/h1&gt;
&lt;h2&gt;IDF 下载&lt;/h2&gt;
&lt;p&gt;IDF离线下载网址：&lt;a href=&quot;https://dl.espressif.cn/dl/esp-idf/&quot;&gt;https://dl.espressif.cn/dl/esp-idf/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;IDF 安装&lt;/h2&gt;
&lt;p&gt;:::note
安装时必须关闭VSCode!
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20003931.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20004011.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20004016.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20004024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20004120.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-23%20004129.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
在安装期间会弹出是否安装驱动的提示框，选择安装或者同意即可
:::&lt;/p&gt;
&lt;h2&gt;安装并配置 IDF 插件&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/f4ac58b041f0b3c9c893ffd92de50862.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;随后等待安装完成即可&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-22%20235357.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;上图即为安装成功&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;新建工程并测试&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;随后右下角会提示【工程已经创建完毕，是否用新窗口打开工程？】，打开即可&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;烧录后，&lt;strong&gt;输出&lt;/strong&gt; 提示如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;终端&lt;/strong&gt; 提示如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/index-15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;即环境安装成功&lt;/p&gt;
&lt;h1&gt;配置参数&lt;/h1&gt;
&lt;p&gt;:::note
这个每一个 &lt;code&gt;ESP32&lt;/code&gt; 都不一样, 请根据自己买的型号修改
我买的是&lt;code&gt;S3 N16R8&lt;/code&gt;
:::&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215135031073.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215135307489.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215135350130.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215135445153.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20251215135428216.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
如需要转移环境使用工程，请删除 &lt;code&gt;build&lt;/code&gt; 文件夹后再尝试编译
:::&lt;/p&gt;
</content:encoded></item><item><title>深度学习常用库</title><link>https://anpier.cn/posts/deep_learning_common_libraries/</link><guid isPermaLink="true">https://anpier.cn/posts/deep_learning_common_libraries/</guid><description>Deep learning used libraries</description><pubDate>Tue, 21 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;All Import&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import os
import cv2
import torch
import torchvision
import numpy as np
from PIL import Image
from torch import nn
from torch.utils.data import Dataset 
from torch.utils.data import DataLoader  
from torch.utils.tensorboard import SummaryWriter
from torch.nn import functional as F
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Data&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import torch
from torch.utils.data import Dataset 
from torch.utils.data import DataLoader 
import os
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Dataset&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Dataset??       #查看Dataset类的官方介绍  
help(Dataset)   #查看Dataset类的官方介绍
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;from torch.utils.data import Dataset 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;class MyDataSet(Dataset):
    def __init__(self, root_dir, label_dir):
        self.root_dir       = root_dir
        self.label_dir      = label_dir
        self.path           = os.path.join(self.root_dir, self.label_dir)
        self.img_path_list  = os.listdir(self.path)

    def __len__(self):
        return len(self.img_path_list)
        
    def __getitem__(self, idx):
        img_name    = self.img_path_list[idx]
        img_path    = os.path.join(self.path, img_name)
        img         = Image.open(img_path)
        label       = self.label_dir
        
        return img, label
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;my_dataset = MyDataSet(&quot;root_dir&quot;, &quot;label_dir&quot;)
print(len(my_dataset))
img, label = my_dataset[idx]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Dataloader&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from torch.utils.data import DataLoader 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 加载 CIFAR10 测试集，应用 ToTensor 转换
test_dataset = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;, 
    train       = False, 
    download    = True, 
    transform   = torchvision.transforms.ToTensor()
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 创建测试集 DataLoader
test_loader = DataLoader(
    dataset     = test_dataset, 
    batch_size  = 64, 
    shuffle     = True, 
    num_workers = 0, 
    drop_last   = False
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 测试 DataLoader
writer = SummaryWriter(&quot;CIFAR10_DataLoader&quot;)

for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        # print(imgs.shape)      # torch.Size([4, 3, 32, 32])
        # print(targets)         # tensor([6, 9, 2, 4])
        writer.add_images(&quot;Epoch:{}&quot;.format(epoch), imgs, step)
        step += 1


writer.close()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;CV2 &amp;amp; Image&lt;/h1&gt;
&lt;h2&gt;Image&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from PIL import Image
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 打开图片
img = Image.open(&quot;test.jpg&quot;)

# 显示图片
img.show()

# 转换格式
img = img.convert(&quot;L&quot;)   # 转为灰度图

# 调整大小
img = img.resize((200, 200))

# 保存图片
img.save(&quot;out.png&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CV2&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;pip install opencv-python
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;import cv2
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 读取图片
img = cv2.imread(&quot;test.jpg&quot;)

# 显示图片
cv2.imshow(&quot;Image&quot;, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 转为灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 图像处理
blur = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blur, 100, 200)

# 保存结果
cv2.imwrite(&quot;edges.jpg&quot;, edges)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TensorBoard&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;pip install tensorboard
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Tensorboard??      #查看Tensorboard类的官方介绍  
help(Tensorboard)   #查看Tensorboard类的官方介绍
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;import numpy as np
from torch.utils.tensorboard import SummaryWriter
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer = SummaryWriter(&quot;My_TensorBoard&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;writer.add_image()&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;img_path = &quot;Relative_Image_Path&quot;
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
print(type(img_array))
print(img_array.shape)  # (512, 768, 3)
                        # HWC---------------------------------------
                        #                                          |
writer.add_image(&quot;Ant Image from PIL&quot;, img_array, 0, dataformats=&apos;HWC&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;writer.add_scalar()&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# y = 2x 
for i in range(100):
    writer.add_scalar(&quot;y=2x&quot;, 2*i, i)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer.close()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;启动&lt;/h2&gt;
&lt;p&gt;本地启动TensorBoard（ &lt;strong&gt;logdir=事件文件所在文件夹名&lt;/strong&gt; ）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tensorboard --logdir=My_TensorBoard --port=6007
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Transform&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;from torchvision import transforms
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer = SummaryWriter(&quot;My_TensorBoard&quot;)

# 跨平台路径 + 确保RGB
img_path = os.path.join(&quot;dataset&quot;, &quot;hymenoptera_data&quot;, &quot;train&quot;, &quot;ants&quot;, &quot;0013035.jpg&quot;)
img_PIL = Image.open(img_path).convert(&quot;RGB&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/0013035.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;transforms.ToTensor&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#img PIL -&amp;gt; tensor
img_tensor = transforms.ToTensor()(img_PIL)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer.add_image(&quot;PIL IMG&quot;, img_tensor, 0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(1).png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;transforms.Resize&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#img PIL -&amp;gt; Resize -&amp;gt; tensor
img_resize_PIL = transforms.Resize((256, 256))(img_PIL)
img_resize_tensor = transforms.ToTensor()(img_resize_PIL)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer.add_image(&quot;Resize IMG&quot;, img_resize_tensor, 0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/1%201.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;transforms.RandomCrop&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Random Crop（若不确定原图尺寸，考虑换 RandomResizedCrop(256)）
for i in range(5):
    img_random_crop_PIL = transforms.RandomCrop((256, 256))(img_PIL)
    img_random_crop_tensor = transforms.ToTensor()(img_random_crop_PIL)
    writer.add_image(&quot;Random Crop IMG&quot;, img_random_crop_tensor, i)
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(1)%201.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/imageData.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(2).png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(3).png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;transforms.Normalize&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Tensor -&amp;gt; Normalize（训练用）；可视化时要反归一化
img_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])(img_tensor)
img_norm_vis = img_norm * 0.5 + 0.5        # 仅用于可视化
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer.add_image(&quot;Normalize IMG (for view)&quot;, img_norm, 0)
writer.add_image(&quot;Normalize IMG (for view)&quot;, img_norm_vis, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(4).png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;transforms.Compose&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Compose: resize -&amp;gt; tensor -&amp;gt; normalize
transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
img_composed = transform(img_PIL)

# 可视化时反归一化
img_composed_vis = img_composed * 0.5 + 0.5
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;writer.add_image(&quot;Tensor IMG (composed, for view)&quot;, img_composed, 0)
writer.add_image(&quot;Tensor IMG (composed, for view)&quot;, img_composed_vis, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/imageData%20(5).png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Torchvision&lt;/h1&gt;
&lt;h2&gt;Download &amp;amp; Use Dataset&lt;/h2&gt;
&lt;p&gt;数据集下载官网： &lt;a href=&quot;https://docs.pytorch.org/vision/stable/generated/torchvision.datasets.CIFAR10.html?highlight=cifar#torchvision.datasets.CIFAR10&quot;&gt;CIFAR10&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# transform 预处理
dataset_transform = torchvision.transforms.Compose([
    torchvision.transforms.Resize((32, 32)),
    torchvision.transforms.ToTensor()
])
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 官方数据集导入 &amp;amp; 使用
train_set = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;, 
    train       = True, 
    download    = True, 
    transform   = dataset_transform
)


test_set = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;, 
    train       = False,
    download    = True, 
    transform   = dataset_transform
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;img, label = train_set[idx]
print(train_set[idx])
img.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;print(f&quot;类别名称: {train_set.classes}&quot;)
print(f&quot;类别名称与索引映射: {train_set.class_to_idx}&quot;)

print(f&quot;图像尺寸: {img.size}, 图像类型: {type(img)}, 标签: {label}&quot;, f&quot;标签名称: {train_set.classes[label]}&quot;)

print(f&quot;训练集样本数: {len(train_set)}&quot;)
print(f&quot;测试集样本数: {len(test_set)}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;NN&lt;/h1&gt;
&lt;p&gt;官网介绍：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/nn.html&quot;&gt;NN&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 加载 CIFAR10 测试集，应用 ToTensor 转换
test_dataset = torchvision.datasets.CIFAR10(
    root        = &quot;./dataset/CIFAR10&quot;,
    train       = False,
    download    = True,
    transform   = torchvision.transforms.ToTensor()
)

# 创建测试集 DataLoader
test_loader = DataLoader(
    dataset     = test_dataset,
    batch_size  = 64,
    shuffle     = True,
    num_workers = 0,
    drop_last   = False
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Class&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;class Model(nn.Module):
    def __init__(self) -&amp;gt; None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;My_model = Model()
X = torch.tensor([1.0, 2.0, 3.0])
output = My_model(X)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Convolution Layers&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from torch import nn
import torch.nn.functional as F
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Conv2d ()&lt;/h3&gt;
&lt;p&gt;官方介绍：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/generated/torch.nn.Conv2d.html#torch.nn.Conv2d&quot;&gt;Conv2d()&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;动图解释：&lt;a href=&quot;https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md&quot;&gt;Click!&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;函数式调用&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;torch.nn.functional.conv2d( input, 
							weight, 
							bias     = None, 
							stride   = 1, 
							padding  = 0, 
							dilation = 1, 
							groups   = 1)

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])

kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;input = torch.reshape(input, (1, 1, 5, 5))  # (N, C, H, W)
kernel = torch.reshape(kernel, (1, 1, 3, 3))  # (out_C, in_C, kH, kW)

print(&quot;input shape:&quot;, input.shape)    
print(&quot;kernel shape:&quot;, kernel.shape)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;output = F.conv2d(input, kernel, stride=1, padding=0)

print(&quot;output shape:&quot;, output.shape) # (1, 1, 3, 3)
print(output)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;output = F.conv2d(input, kernel, stride=2, padding=0)

print(&quot;output shape:&quot;, output.shape) # (1, 1, 2, 2)
print(output)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;output = F.conv2d(input, kernel, stride=1, padding=1)

print(&quot;output shape:&quot;, output.shape) # (1, 1, 5, 5)
print(output)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;模块化层（推荐）&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = torch.nn.Conv2d(
            in_channels     = 3,
            out_channels    = 16,
            kernel_size     = 3,
            stride          = 1,
            padding         = 1
        )

    def forward(self, x):
        x = self.conv1(x)
        return x
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wrtiter = SummaryWriter(&quot;CIFAR10_Conv2d&quot;)

step = 0

My_model = My_Model()

for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        output = My_model(imgs)

        # print(&quot;input shape:&quot;, imgs.shape)
        # print(&quot;output shape:&quot;, output.shape)

        wrtiter.add_images(&quot;Input:{}&quot;.format(epoch), imgs, step)

        output = output[:, :3, :, :]  # 只取前3个通道，方便可视化
        wrtiter.add_images(&quot;Onput:{}&quot;.format(epoch), output, step)

        step += 1

print(&quot;Done.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;MaxPool Layers&lt;/h2&gt;
&lt;p&gt;官方介绍：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html#torch.nn.MaxPool2d&quot;&gt;MaxPool2d()&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.maxpool1 = torch.nn.MaxPool2d(
            kernel_size     = 3, 
            ceil_mode       = True,
            stride          = 2,
            padding         = 1
        )

    def forward(self, x):
        x = self.maxpool1(x)
        return x
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wtriter = SummaryWriter(&quot;CIFAR10_NN_MaxPool2d&quot;)

My_model = My_Model()
step = 0
for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        output = My_model(imgs)

        # print(&quot;input shape:&quot;, imgs.shape)
        # print(&quot;output shape:&quot;, output.shape)

        wtriter.add_images(&quot;Input:{}&quot;.format(epoch), imgs, step)
        wtriter.add_images(&quot;Output:{}&quot;.format(epoch), output, step)

        step += 1

print(&quot;Done.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Non Linear Layers&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.ReLU1 = torch.nn.ReLU()
        self.sigmoid1 = torch.nn.Sigmoid()

    def forward(self, x):
        # x = self.ReLU1(x)
        x = self.sigmoid1(x)
        return x
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;wtriter = SummaryWriter(&quot;CIFAR10_NN_Non_Linear_Act&quot;)

My_model = My_Model()
step = 0
for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        output = My_model(imgs)

        # print(&quot;input shape:&quot;, imgs.shape)
        # print(&quot;output shape:&quot;, output.shape)

        wtriter.add_images(&quot;Input:{}&quot;.format(epoch), imgs, step)
        wtriter.add_images(&quot;Output:{}&quot;.format(epoch), output, step)

        step += 1

print(&quot;Done.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Linear Layers&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.linear1 = torch.nn.Linear(
            in_features    = 3 * 32 * 32, 
            out_features   = 10
        )

    def forward(self, input):
        output = self.linear1(input) 
        return output
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;My_model = My_Model()
step = 0
for epoch in range(1):
    step = 0
    for data in test_loader:
        imgs, targets = data
        print(&quot;imgs shape before flatten:&quot;, imgs.shape)

        #imgs = imgs.view(imgs.size(0), -1)  # 展平操作
        imgs = torch.flatten(imgs, start_dim=1)  # 另一种展平操作
        print(&quot;imgs shape after flatten:&quot;, imgs.shape)

        output = My_model(imgs)
        print(&quot;output shape:&quot;, output.shape)

        step += 1

print(&quot;Done.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Sequential&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;class My_Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(
            in_channels     = 3, 
            out_channels    = 32, 
            kernel_size     = 5, 
            padding         = 2
        )

        self.maxpool1 = nn.MaxPool2d(
            kernel_size = 2,
        )

        self.conv2 = nn.Conv2d(
            in_channels     = 32, 
            out_channels    = 32, 
            kernel_size     = 5, 
            padding         = 2
        )

        self.maxpool2 = nn.MaxPool2d(
            kernel_size = 2,
        )

        self.conv3 = nn.Conv2d(
            in_channels     = 32, 
            out_channels    = 64, 
            kernel_size     = 5, 
            padding         = 2
        )

        self.maxpool3 = nn.MaxPool2d(
            kernel_size = 2,
        )

        self.flatten = nn.Flatten()

        self.linear1 = nn.Linear(
            in_features    = 64 * 4 * 4,    
            out_features   = 64
        )

        self.linear2 = nn.Linear(
            in_features    = 64,
            out_features   = 10
        )

        self.seq = nn.Sequential(
            self.conv1,
            self.maxpool1,
            self.conv2,
            self.maxpool2,
            self.conv3,
            self.maxpool3,
            self.flatten,
            self.linear1,
            self.linear2
        )
    
    def forward(self, input):
        output = self.seq(input)
        return output
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;my_model = My_Model()
print(my_model)

input = torch.randn(64, 3, 32, 32)
print(&quot;input shape:&quot;, input.shape)
print(&quot;input:&quot;, input)

output = my_model(input)
print(&quot;output shape:&quot;, output.shape)
print(&quot;output:&quot;, output)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Loss Function&lt;/h2&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/nn.html#loss-functions&quot;&gt;Click !&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; # 定义损失函数
criterion = nn.CrossEntropyLoss()
        
# 计算损失
loss = criterion(outputs, targets)

#具体其他的损失函数及其参数可翻阅文档查看
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Backward &amp;amp; Optimizer&lt;/h2&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/autograd.html#module-torch.autograd&quot;&gt;Backward&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://docs.pytorch.org/docs/stable/optim.html#module-torch.optim&quot;&gt;Optim&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;optim = torch.optim.SGD(
    params      = my_model.parameters(),
    lr          = 0.01,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;for epoch in range(20):
    running_loss = 0.0

    for data in train_loader:
        imgs, targets = data
        outputs = my_model(imgs)
        
        # 定义损失函数
        criterion = nn.CrossEntropyLoss()
        
        # 计算损失
        loss = criterion(outputs, targets)
      
        optim.zero_grad()  # 清零梯度
        loss.backward()
        optim.step()       # 更新参数

        running_loss += loss.item()

    print(f&quot;epoch {epoch} finished!&quot;)    
    print(&quot;loss:&quot;, running_loss)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;模型保存与使用&lt;/h1&gt;
&lt;p&gt;以VGG16为例，这个模型数据集150G，就别下载了···&lt;/p&gt;
&lt;h2&gt;载入模型&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from torchvision.models import VGG16_Weights
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 模型文件保存路径
os.environ[&apos;TORCH_HOME&apos;] = r&apos;E:\Deep_Learning\project\dataset\ImageNet&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 不加载权重
VGG16_MODEL_False = torchvision.models.vgg16(weights = None)

# 加载 ImageNet 预训练权重
VGG16_MODEL_True = torchvision.models.vgg16(weights=VGG16_Weights.IMAGENET1K_V1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;修改模型&lt;/h2&gt;
&lt;h3&gt;例：CIFAR-10（10类）&lt;/h3&gt;
&lt;p&gt;只需替换最后的全连接层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import torch.nn as nn
import torchvision

# 不加载预训练权重（如果你想从头训练）
model1 = torchvision.models.vgg16(weights=None)

# 修改分类器最后一层
model1.classifier[6] = nn.Linear(in_features=4096, out_features=10)

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;例：迁移学习（加载预训练参数）&lt;/h3&gt;
&lt;p&gt;如果想用 &lt;strong&gt;ImageNet 预训练权重&lt;/strong&gt; 来提升收敛速度和准确率，可以改为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from torchvision.models import VGG16_Weights

model1 = torchvision.models.vgg16(weights=VGG16_Weights.IMAGENET1K_V1)
# 冻结特征层参数
for param in model1.features.parameters():
    param.requires_grad = False

# 修改最后一层分类器
model1.classifier[6] = nn.Linear(4096, 10)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::note
这样，模型只会训练最后几层，全卷积层保持 ImageNet 学到的通用特征，适合小数据集。
:::&lt;/p&gt;
&lt;h2&gt;保存模型&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;VGG16_MODEL = torchvision.models.vgg16(weights = None)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 保存整个模型（不推荐做法）
torch.save(VGG16_MODEL, &quot;./My_Model/VGG16_no_weights_All_Model.pth&quot;)

# 仅保存模型参数（推荐做法）
torch.save(VGG16_MODEL.state_dict(), &quot;./My_Model/VGG16_no_weights_state_dict.pth&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用模型&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 直接加载整个模型（不推荐做法）
model = torch.load(&quot;./My_Model/VGG16_no_weights_All_Model.pth&quot;, weights_only = False)
print(model)
  
# 仅加载模型参数（推荐做法）
model = torchvision.models.vgg16(weights = False)  
model.load_state_dict(torch.load(&quot;./My_Model/VGG16_no_weights_state_dict.pth&quot;))
print(model)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>配置 Conda + Pytorch + d2l 环境</title><link>https://anpier.cn/posts/anacondapytorchd2l/</link><guid isPermaLink="true">https://anpier.cn/posts/anacondapytorchd2l/</guid><description>在Window11上配置李沐深度学习相关环境</description><pubDate>Sun, 05 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;软件安装&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Anaconda&lt;a href=&quot;https://www.anaconda.com/download&quot;&gt;官网下载&lt;/a&gt;，或者按照该博客来安装下载&lt;a href=&quot;https://blog.csdn.net/qq_44000789/article/details/142214660&quot;&gt;安装下载&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vscode&lt;a href=&quot;https://code.visualstudio.com/Download&quot;&gt;官网下载&lt;/a&gt;，或者按照该博客来&lt;a href=&quot;https://blog.csdn.net/weixin_60915103/article/details/131617196&quot;&gt;安装下载&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;也可按照该视频配置&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Fo46e3EAZ&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;环境配置&lt;/h2&gt;
&lt;p&gt;:::note
如果想要使用GPU进行深度学习模型的训练，就需要安装CUDA，我用的是Nvidia的GPU.
:::&lt;/p&gt;
&lt;h3&gt;安装CUDA以及cudnn&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;检查自己电脑支持的CUDA版本：打开cmd执行.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;nvidia-smi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-10%20010239.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;前往&lt;a href=&quot;https://developer.nvidia.com/cuda-toolkit-archive&quot;&gt;官网&lt;/a&gt;下载自己电脑支持版本的 CUDA ，我选择12.8.0版本.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;下载时选择自定义，勾选下载全部选项，并记住安装路径.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-20%20235111%201.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检验是否安装成功：打开cmd执行.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;nvcc -V
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-05%20051145.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;前往&lt;a href=&quot;https://developer.nvidia.com/rdp/cudnn-archive&quot;&gt;官网&lt;/a&gt;下载对应版本的 cudnn 压缩包，后进行解压，我选择8.9.7版本.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入指定目录（上文记住的安装路径），如C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8，将bin，include，lib三个文件夹拖入进行替换.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;创建虚拟环境并配置pytorch&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开Anaconda Prompt，创建环境：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda create -n ENV_NAME python=3.9
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;激活环境：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda activate ENV_NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看环境是否创建成功：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda env list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-10%20004807.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装Pytorch命令复制网址： &lt;a href=&quot;https://pytorch.org/get-started/locally/&quot;&gt;https://pytorch.org/get-started/locally&lt;/a&gt;  选择自己版本的选项，在环境激活的情况下，复制命令并安装.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-10-05%20052503.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
下载的包会比较大，如我的是3.5G，如比较小可能不是安装的GPU版本
:::&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建.py文件，并将conda中刚刚安装环境中的python作为解释器，具体教程看:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Fo46e3EAZ&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;运行下列代码，不报错即安装成功:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import torch
print(torch.__version__)
print(torch.cuda.is_available())
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;退出环境：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda deactivate
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;删除环境：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda remove --name ENV_NAME --all
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;软件配置&lt;/h2&gt;
&lt;h3&gt;Jupyter Notebook&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开Anaconda Prompt，激活环境后，执行：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pip install jupyter
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;下载完后，执行，查看Jupyter的配置路径，只需看到路径，终端中输入 &quot;N&quot; 即可：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;jupyter notebook --generate-config
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;进入路径，打开 &quot;jupyter_notebook_config&quot; 文件，搜索：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;The directory to use
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;修改如下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    ## The directory to use for notebooks and kernels.
    #  Default: &apos;&apos;
-   # c.ServerApp.root_dir = &apos;&apos;
+   c.ServerApp.root_dir = &apos;默认打开路径&apos;

&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;打开Anaconda Prompt，激活环境后，执行：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conda install ipykernel
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;将环境写入内核：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;python -m ipykernel --user --name 你创建环境的名字 --display-name &quot;你创建环境的名字&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;d2l库安装&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开Anaconda Prompt，激活环境后，执行：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pip install d2l
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;运行下列代码，不报错即安装成功:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import torch
from d2l import torch as d2l
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>圆形LED点阵屏幕</title><link>https://anpier.cn/posts/stm32led_dianzhen/</link><guid isPermaLink="true">https://anpier.cn/posts/stm32led_dianzhen/</guid><description>看到了国外大佬做的，觉得挺有意思，自己也想复刻了一个</description><pubDate>Tue, 11 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;2月11日更新&lt;/h1&gt;
&lt;p&gt;在刷Youtube的时候看到了一个大佬做出的开源项目，简单来说就是用led贴片贴出来一个小屏幕，觉得很有意思。但虽说是开源的，但是资料并不完全，就想着自己从头开始把他复刻一遍，正好寒假里时间充裕，也算是自己做的第一个小项目。&lt;/p&gt;
&lt;p&gt;具体的链接如下：&lt;a href=&quot;https://mitxela.com/projects/fluid-pendant&quot;&gt;https://mitxela.com/projects/fluid-pendant&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;由于我打算做出来的点阵屏幕有点小，并且只用两层板来打样，所以发现用74HC595这个芯片好像位置不太够，再加上想在这块板子上加上控制芯片和mpu6050来实现一些好玩的效果，就去搜了搜有没有用很少IO口就能控制很多LED灯的方法，还真有。&lt;/p&gt;
&lt;p&gt;方法的名字叫做“查理复用”（Charlieplexing），是一种LED显示器多路复用的方法，主要使用到了IO口输出的三种状态：高电平、低电平，高阻态。&lt;/p&gt;
&lt;p&gt;所谓“高阻态”，是指GPIO对外部电路表现出极大的阻抗。因阻抗很大，几乎不会吸入电流，也不会对外输出电流。而我们就可以让其中两个IO口分别呈现高低电平，而其他的所有都为高阻态的方式，来实现对led的控制。具体的化简电路图如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250211174224800.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;比如我想让 &lt;strong&gt;LED5&lt;/strong&gt; 亮起，就给 &lt;strong&gt;GPIO_1&lt;/strong&gt; 低电平，&lt;strong&gt;GPIO_2&lt;/strong&gt; 高阻态，&lt;strong&gt;GPIO_3&lt;/strong&gt; 高电平就能实现。这样算下来，n个IO口就能控制n*(n+1)个LED灯，可以大大节省IO口的资源。但是一个时间只能亮一个LED灯，所以需要用到视觉暂留原理，让每一行的每一个LED灯快速的亮起又灭掉，采用逐行扫描的方法，一次扫描完所有LED灯的频率大于60HZ，就能实现在我们看来很多灯在同一时刻亮的现象，但这同时也需要对控制芯片的时钟要求比较高。&lt;/p&gt;
&lt;h2&gt;PCB&lt;/h2&gt;
&lt;p&gt;首先需要解决LED灯布线的问题，想到了一种方法，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250211174410029.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;通过对角线这样的走线方法，能够实现用16个IO口控制240（15*16）个led灯，且能保证布线不会很混乱，每一条总线都是斜向上或者斜向下，与其他总线平行的排布。由于要排成圆形的阵列，我删去了一些LED灯，最后留下了208个，最为最终的排列，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250211174509088.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;把这张原理图转换到PCB图，并且排列好，连好线，如下图所示：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250211174626268.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250211174654957.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;p&gt;这样的连线可以为主控的放置节省非常多的空间，背面只存在一些过孔，非常NICE。&lt;/p&gt;
&lt;p&gt;随后就是绘制主控的电路图了，最后还是选择 &lt;strong&gt;Stm32f103c8t6&lt;/strong&gt; ，芯片比较小，算力也够。从网上随便扒了个原理图复制下来，画了PCB，如下图所示：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250211174836891.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250211174931009.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/20250211175000657.png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/20250211175015992.png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;之后想了想，发现不需要自己焊mpu6050，直接用现成的模块就可以了，还方便且不容易出错，稍微改动了一下PCB，并且把引出的引脚焊盘都扩大了一点，如下图所示:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/20250211175115375.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;顺便把钢网也开了&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;2月28日更新&lt;/h1&gt;
&lt;p&gt;终于，在一万年后，我终于终于终于把这块板子焊好了，实物图如下，并进行了上机检测，在keil中可以识别到芯片，&lt;strong&gt;WIN!&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250228202854499.jpg&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250228202911673.jpg&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250228202931289.jpg&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/20250228203054634.png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1&gt;3月1日更新&lt;/h1&gt;
&lt;p&gt;测试了一下焊完的电路，发现了原本电路图中的两处问题，问题修改后如下图所示，LED灯正负反转一下是最简单的解决方法，具体更合理的优化到之后再改一改。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/post-images/20250302004618016.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;3月2日更新&lt;/h1&gt;
&lt;p&gt;本来想着之后慢慢弄，但转念一想，干都干了，不如今天把大部分事情都搞完，随后就开始在keil中写屎山了··· 感觉之后写一个上位机会方便很多，但这都是后话了···&lt;/p&gt;
&lt;p&gt;高低电平采用推挽输出，高阻态只需要将引脚模式改成输入就可以了。每次初始化亮一个灯，通过频率非常高的切换，让我们的眼睛看起来全都在亮。之后又发现总有两条斜线的灯不亮QAQ，&lt;strong&gt;红温了&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250302032415593.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;经过排查之后发现是PB3和PB4这两个引脚在上电后默认配置为JTAG功能，如若需要恢复正常的输入输出模式，需要添加GPIO的复用。之后就又是枯燥的复制粘贴写代码&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250302032755579.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src=&quot;../../../assets/post-images/20250302032817216.png&quot; alt=&quot;&quot; /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;../../../assets/post-images/20250302032857613.png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Adrian-Pierre/anpier_blog_image/main/src/20250302032948100.png&quot; alt=&quot;&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;至此，这个小项目最基础的部分已经完成了，已经可以做一些小的屏幕展示。之后会继续在mpu6050模块的基础上开发一些更好玩的东西: )&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;5月13日更新&lt;/h1&gt;
&lt;p&gt;好久没推进这个项目了，实在是有点忙，出来冒个泡，顺便把项目开源了   &lt;strong&gt;:)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Adrian-Pierre/LED_Project&quot;&gt;https://github.com/Adrian-Pierre/LED_Project&lt;/a&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>