<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>polar-bear～Blog</title>
  
  <subtitle>欢迎来到我の小窝</subtitle>
  <link href="https://polar-bear.eu.org/atom.xml" rel="self"/>
  
  <link href="https://polar-bear.eu.org/"/>
  <updated>2026-05-10T17:16:24.834Z</updated>
  <id>https://polar-bear.eu.org/</id>
  
  <author>
    <name>Ziyourufeng</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>BTRFS与Timeshift</title>
    <link href="https://polar-bear.eu.org/2026/05/10/btrfs-yu-timeshift/"/>
    <id>https://polar-bear.eu.org/2026/05/10/btrfs-yu-timeshift/</id>
    <published>2026-05-10T16:53:47.355Z</published>
    <updated>2026-05-10T17:16:24.834Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装">安装</h2><p><a href="https://www.wooveep.com/posts/ubuntu-desktop24.04-use-btrfs/">https://www.wooveep.com/posts/ubuntu-desktop24.04-use-btrfs/</a></p><h2 id="更新initramfs和GRUB">更新initramfs和GRUB</h2><p>安装了BTRFS后，若更换磁盘导致id变化，需要重新生成initramfs和GRUB。</p><p>例如，调整efi分区。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/05_11/share_1778461246833_ccc9fa906bfe5f99e32fb4d2524f9267.jpeg" alt=""></p><p>找不到设置的磁盘分区导致超时90s.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[   13.099878] input: sof-hda-dsp HDMI/DP,pcm=5 as /devices/pci0000:00/0000:00:1f.3/skl_hda_dsp_generic/sound/card0/input28</span><br><span class="line">[   13.122121] i915 0000:00:02.0: [drm] Selective fetch area calculation failed <span class="keyword">in</span> pipe A</span><br><span class="line">[  100.252860] audit: <span class="built_in">type</span>=1400 audit(1778418880.812:2): apparmor=<span class="string">&quot;STATUS&quot;</span> operation=<span class="string">&quot;profile_load&quot;</span> profile=<span class="string">&quot;unconfined&quot;</span> name=4D6F6E676F444220436F6D70617373 pid=1676 <span class="built_in">comm</span>=<span class="string">&quot;apparmor_parser&quot;</span></span><br><span class="line">[  100.252883] audit: <span class="built_in">type</span>=1400 audit(1778418880.812:3): apparmor=<span class="string">&quot;STATUS&quot;</span> operation=<span class="string">&quot;profile_load&quot;</span> profile=<span class="string">&quot;unconfined&quot;</span> name=<span class="string">&quot;balena-etcher&quot;</span> pid=1681 <span class="built_in">comm</span>=<span class="string">&quot;apparmor_parser&quot;</span></span><br><span class="line">[  100.252909] audit: <span class="built_in">type</span>=1400 audit(1778418880.812:4): apparmor=<span class="string">&quot;STATUS&quot;</span> operation=<span class="string">&quot;profile_load&quot;</span> profile=<span class="string">&quot;unconfined&quot;</span> name=<span class="string">&quot;buildah&quot;</span> pid=1685 <span class="built_in">comm</span>=<span class="string">&quot;apparmor_parser&quot;</span></span><br><span class="line">[  100.252931] audit: <span class="built_in">type</span>=1400 audit(1778418880.812:5): apparmor=<span class="string">&quot;STATUS&quot;</span> operation=<span class="string">&quot;profile_load&quot;</span> profile=<span class="string">&quot;unconfined&quot;</span> name=<span class="string">&quot;QtWebEngineProcess&quot;</span> pid=1677 <span class="built_in">comm</span>=<span class="string">&quot;apparmor_parser&quot;</span></span><br><span class="line">[  100.252965] audit: <span class="built_in">type</span>=1400 audit(1778418880.812:6): apparmor=<span class="string">&quot;STATUS&quot;</span> operation=<span class="string">&quot;profile_load&quot;</span> profile=<span class="string">&quot;unconfined&quot;</span> name=<span class="string">&quot;1password&quot;</span> pid=1674 <span class="built_in">comm</span>=<span class="string">&quot;apparmor_parser&quot;</span></span><br></pre></td></tr></table></figure><p>使用ubuntu安装盘进入’安装或试用‘Live 环境。</p><p>创建挂载点并挂载子卷</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建挂载点目录</span></span><br><span class="line">sudo <span class="built_in">mkdir</span> -p /mnt/ubuntu</span><br><span class="line"></span><br><span class="line"><span class="comment"># 挂载 btrfs 根子卷 @</span></span><br><span class="line">sudo mount -t btrfs -o subvol=@ /dev/nvme0n1p6 /mnt/ubuntu</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证挂载是否成功（应该看到 /mnt/ubuntu 下有 bin, etc, home 等目录）</span></span><br><span class="line"><span class="built_in">ls</span> /mnt/ubuntu</span><br></pre></td></tr></table></figure><p>挂载 EFI 分区</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 挂载 EFI 分区到 /boot/efi(根据fstab查看对应分区)</span></span><br><span class="line">sudo mount /dev/nvme0n1p1 /mnt/ubuntu/boot/efi</span><br></pre></td></tr></table></figure><p>挂载虚拟文件系统</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 挂载必要的系统目录</span></span><br><span class="line">sudo mount --<span class="built_in">bind</span> /dev /mnt/ubuntu/dev</span><br><span class="line">sudo mount --<span class="built_in">bind</span> /proc /mnt/ubuntu/proc</span><br><span class="line">sudo mount --<span class="built_in">bind</span> /sys /mnt/ubuntu/sys</span><br><span class="line"></span><br><span class="line"><span class="comment"># 绑定 efivars（用于 UEFI 引导修复）</span></span><br><span class="line">sudo mount --<span class="built_in">bind</span> /sys/firmware/efi/efivars /mnt/ubuntu/sys/firmware/efi/efivars 2&gt;/dev/null || <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>进入 chroot 环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="built_in">chroot</span> /mnt/ubuntu</span><br></pre></td></tr></table></figure><p>在 chroot 中重新生成 initramfs 和 GRUB</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 重新生成 initramfs</span></span><br><span class="line">update-initramfs -u</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重新安装 GRUB（UEFI 方式）</span></span><br><span class="line">grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu --recheck</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新 GRUB 配置</span></span><br><span class="line">update-grub</span><br><span class="line"></span><br><span class="line"><span class="comment"># 退出 chroot</span></span><br><span class="line"><span class="built_in">exit</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 卸载所有挂载</span></span><br><span class="line">sudo umount -R /mnt/ubuntu</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启系统（记得拔掉 U 盘）</span></span><br><span class="line">sudo reboot</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">安装
https://www.wooveep.com/posts/ubuntu-desktop24.04-use-btrfs/
[https://www.wooveep.com/posts/ubuntu-desktop24.04-use-btrfs/]

更新INITRAMFS和GRUB
安装了BTRFS后，若更换磁盘导致id变化，需要重新生成initramfs和GRUB。

例如，调整efi分区。</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Onedrive下载</title>
    <link href="https://polar-bear.eu.org/2026/03/06/onedrive-xia-zai/"/>
    <id>https://polar-bear.eu.org/2026/03/06/onedrive-xia-zai/</id>
    <published>2026-03-06T17:10:03.616Z</published>
    <updated>2026-03-06T09:26:17.316Z</updated>
    
    <content type="html"><![CDATA[<h2 id="rclone">rclone</h2><p>在终端</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wget https://downloads.rclone.org/v1.73.2/rclone-v1.73.2-linux-amd64.zip</span><br><span class="line">unzip rclone-v1.73.2-linux-amd64.zip</span><br><span class="line">./rclone-v1.73.2-linux-amd64/rclone config</span><br></pre></td></tr></table></figure><ul><li><strong>输入</strong> <strong>n</strong> <strong>(New remote)。</strong></li><li><strong>名字随便起，比如</strong> <strong>onedrive</strong>。</li><li><strong>Type 选择</strong> <strong>onedrive</strong> <strong>(输入数字即可，通常是41，41 / Microsoft OneDrive\ (onedrive))。</strong></li><li><strong>client_id</strong> <strong>和</strong> <strong>client_secret</strong> <strong>直接留空（回车）。</strong></li><li><strong>region，一般E5 账号都是 Global 国际版，选1即可</strong></li><li><strong>tenant</strong>，<strong>直接跳过，这是给服务主体/Service Principal 用的，普通 E5 账号登录不需要填这个</strong></li><li><strong>Edit advanced config?</strong> <strong>选</strong> <strong>n</strong>。</li><li><strong>关键点：</strong> <strong>Use auto config?</strong> <strong>选y使用浏览器登陆，没有浏览器使用n，粘贴token</strong></li><li><strong>token：填入下面获取的token</strong></li><li><strong>config_type：选择1， OneDrive 个人或商业版</strong></li><li><strong>config_driveid：会列出你账户下面的OneDrive默认即可</strong></li><li><strong>Found drive …</strong> <strong>-&gt; 选</strong> <strong>y</strong></li><li><strong>Keep this … remote?</strong> <strong>-&gt; 选</strong> <strong>y</strong>。</li><li><strong>最后输入 q退出。</strong></li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_07/image_a825be0abcee9b50f1e59ba0163d0cbf.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_07/image_751b95c53c0404e53720f0f71ebe2751.png" alt=""></p><h3 id="复制配置文件">复制配置文件</h3><p>在本地按照上面的方法配置好后，可以直接</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rclone config show</span><br></pre></td></tr></table></figure><p><strong>你会看到一段类似下面的内容，<strong>完整复制它</strong>（包括</strong> <strong>[onedrive]</strong> <strong>那一行）：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[onedrive]</span><br><span class="line">type = onedrive</span><br><span class="line">token = &#123;&quot;access_token&quot;:&quot;eyJh...（超级长）...&quot;,&quot;token_type&quot;:&quot;Bearer&quot;,&quot;refresh_token&quot;:&quot;...&quot;,&quot;expiry&quot;:&quot;...&quot;&#125;</span><br><span class="line">drive_id = b!.......</span><br><span class="line">drive_type = business</span><br></pre></td></tr></table></figure><p>拷贝这个配置文件到服务器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p ~/.config/rclone/</span><br><span class="line"></span><br><span class="line">## 编辑或者直接拷贝文件</span><br><span class="line">nano ~/.config/rclone/rclone.conf</span><br><span class="line"></span><br><span class="line">## 检查验证配置</span><br><span class="line">rclone lsd onedrive:</span><br></pre></td></tr></table></figure><h3 id="获取token">获取token</h3><p>在本地同样下载rclone</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rclone authorize &quot;onedrive&quot;</span><br></pre></td></tr></table></figure><p>在弹出的web页面授权onedrive登陆，之后即可获得access_token。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_07/image_57439590c862a2a1b65922c932805307.png" alt=""></p><p>获取{}包裹的完整token后，可以到上面进行认证。</p><h3 id="下载">下载</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># 语法: rclone copy 源路径 本地路径 [参数]</span><br><span class="line"># -P: 显示实时进度。</span><br><span class="line"># --transfers=16: 同时下载 16 个文件</span><br><span class="line"># --multi-thread-streams=4: 大文件会分成 4 个线程并发下载</span><br><span class="line"># --buffer-size=64M: 增加内存缓存，减少 IO 瓶颈。</span><br><span class="line"></span><br><span class="line">rclone copy onedrive:/你的文件夹/ /home/download/ \</span><br><span class="line">  -P \</span><br><span class="line">  --transfers=16 \</span><br><span class="line">  --buffer-size=64M \</span><br><span class="line">  --multi-thread-streams=4</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">RCLONE
在终端

1
2
3


wget https://downloads.rclone.org/v1.73.2/rcl</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>D-FINE--基于Transformer架构的实时目标检测模型</title>
    <link href="https://polar-bear.eu.org/2026/03/01/d-fine-ji-yu-transformer-jia-gou-de-shi-shi-mu-biao-jian-ce-mo-xing/"/>
    <id>https://polar-bear.eu.org/2026/03/01/d-fine-ji-yu-transformer-jia-gou-de-shi-shi-mu-biao-jian-ce-mo-xing/</id>
    <published>2026-03-01T23:19:31.956Z</published>
    <updated>2026-04-08T21:58:10.071Z</updated>
    
    <content type="html"><![CDATA[<h2 id="D-FINE">D-FINE</h2><p>D-FINE 是一个强大的实时目标检测器，将 DETR 中的边界框回归任务重新定义为了细粒度的分布优化（FDR），并引入全局最优的定位自蒸馏（GO-LSD），在不增加额外推理和训练成本的情况下，实现了卓越的性能。</p><p><a href="https://github.com/Peterande/D-FINE">Peterande/D-FINE: D-FINE: Redefine Regression Task of DETRs as Fine-grained Distribution Refinement [ICLR 2025 Spotlight]</a></p><p><a href="https://opendatalab.com/OpenDataLab/Objects365">数据集-OpenDataLab</a></p><p><a href="https://blog.csdn.net/2301_80344847/article/details/146165224">D-FINE 论文理解_dfine-CSDN博客</a></p><p><a href="https://zhuanlan.zhihu.com/p/21152714767">D-FINE：实时目标检测的“速度与激情”，精准又高效！ - 知乎</a></p><h2 id="训练">训练</h2><h3 id="数据集准备">数据集准备</h3><p>准备数据集</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br></pre></td><td class="code"><pre><span class="line">import json</span><br><span class="line">import random</span><br><span class="line">import xml.etree.ElementTree as ET</span><br><span class="line">from pathlib import Path</span><br><span class="line"></span><br><span class="line">IMG_EXTS = [&quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.png&quot;, &quot;.bmp&quot;, &quot;.webp&quot;]</span><br><span class="line"></span><br><span class="line"># ==========================</span><br><span class="line"># Hardcoded runtime settings</span><br><span class="line"># ==========================</span><br><span class="line">SETTINGS = &#123;</span><br><span class="line">    &quot;images_dir&quot;: &quot;coco/images&quot;,</span><br><span class="line">    &quot;xml_dir&quot;: &quot;coco/Annotations&quot;,</span><br><span class="line">    &quot;output_dir&quot;: &quot;coco/converted&quot;,</span><br><span class="line">    &quot;train_ratio&quot;: 0.8,</span><br><span class="line">    &quot;val_ratio&quot;: 0.1,</span><br><span class="line">    &quot;test_ratio&quot;: 0.1,</span><br><span class="line">    &quot;seed&quot;: 42,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def parse_xml(xml_path: Path):</span><br><span class="line">    root = ET.parse(xml_path).getroot()</span><br><span class="line">    filename = (root.findtext(&quot;filename&quot;) or &quot;&quot;).strip()</span><br><span class="line">    size = root.find(&quot;size&quot;)</span><br><span class="line">    if size is None:</span><br><span class="line">        return None</span><br><span class="line"></span><br><span class="line">    w = int(float(size.findtext(&quot;width&quot;, default=&quot;0&quot;)))</span><br><span class="line">    h = int(float(size.findtext(&quot;height&quot;, default=&quot;0&quot;)))</span><br><span class="line">    if w &lt;= 0 or h &lt;= 0:</span><br><span class="line">        return None</span><br><span class="line"></span><br><span class="line">    objs = []</span><br><span class="line">    for obj in root.findall(&quot;object&quot;):</span><br><span class="line">        name = (obj.findtext(&quot;name&quot;) or &quot;&quot;).strip()</span><br><span class="line">        box = obj.find(&quot;bndbox&quot;)</span><br><span class="line">        if not name or box is None:</span><br><span class="line">            continue</span><br><span class="line"></span><br><span class="line">        xmin = float(box.findtext(&quot;xmin&quot;, default=&quot;0&quot;))</span><br><span class="line">        ymin = float(box.findtext(&quot;ymin&quot;, default=&quot;0&quot;))</span><br><span class="line">        xmax = float(box.findtext(&quot;xmax&quot;, default=&quot;0&quot;))</span><br><span class="line">        ymax = float(box.findtext(&quot;ymax&quot;, default=&quot;0&quot;))</span><br><span class="line">        if xmax &lt;= xmin or ymax &lt;= ymin:</span><br><span class="line">            continue</span><br><span class="line">        objs.append((name, xmin, ymin, xmax, ymax))</span><br><span class="line"></span><br><span class="line">    if not objs:</span><br><span class="line">        return None</span><br><span class="line">    return filename, w, h, objs</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def find_img(images_dir: Path, stem: str):</span><br><span class="line">    for ext in IMG_EXTS:</span><br><span class="line">        p = images_dir / f&quot;&#123;stem&#125;&#123;ext&#125;&quot;</span><br><span class="line">        if p.exists():</span><br><span class="line">            return p</span><br><span class="line">    return None</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def to_coco(samples, cls2id):</span><br><span class="line">    images, annotations = [], []</span><br><span class="line">    ann_id = 1</span><br><span class="line">    for img_id, s in enumerate(samples, start=1):</span><br><span class="line">        images.append(&#123;</span><br><span class="line">            &quot;id&quot;: img_id,</span><br><span class="line">            &quot;file_name&quot;: s[&quot;file_name&quot;],</span><br><span class="line">            &quot;width&quot;: s[&quot;width&quot;],</span><br><span class="line">            &quot;height&quot;: s[&quot;height&quot;],</span><br><span class="line">        &#125;)</span><br><span class="line">        for cls_name, xmin, ymin, xmax, ymax in s[&quot;objects&quot;]:</span><br><span class="line">            w = xmax - xmin</span><br><span class="line">            h = ymax - ymin</span><br><span class="line">            annotations.append(&#123;</span><br><span class="line">                &quot;id&quot;: ann_id,</span><br><span class="line">                &quot;image_id&quot;: img_id,</span><br><span class="line">                &quot;category_id&quot;: cls2id[cls_name],</span><br><span class="line">                &quot;bbox&quot;: [xmin, ymin, w, h],</span><br><span class="line">                &quot;area&quot;: w * h,</span><br><span class="line">                &quot;iscrowd&quot;: 0,</span><br><span class="line">            &#125;)</span><br><span class="line">            ann_id += 1</span><br><span class="line"></span><br><span class="line">    categories = [</span><br><span class="line">        &#123;&quot;id&quot;: cid, &quot;name&quot;: name, &quot;supercategory&quot;: &quot;object&quot;&#125;</span><br><span class="line">        for name, cid in sorted(cls2id.items(), key=lambda x: x[1])</span><br><span class="line">    ]</span><br><span class="line">    return &#123;&quot;images&quot;: images, &quot;annotations&quot;: annotations, &quot;categories&quot;: categories&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def dump_json(path: Path, data):</span><br><span class="line">    path.parent.mkdir(parents=True, exist_ok=True)</span><br><span class="line">    path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def dump_lines(path: Path, lines):</span><br><span class="line">    path.parent.mkdir(parents=True, exist_ok=True)</span><br><span class="line">    path.write_text(&quot;\n&quot;.join(lines) + &quot;\n&quot;, encoding=&quot;utf-8&quot;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">    if abs(SETTINGS[&quot;train_ratio&quot;] + SETTINGS[&quot;val_ratio&quot;] + SETTINGS[&quot;test_ratio&quot;] - 1.0) &gt; 1e-6:</span><br><span class="line">        raise ValueError(&quot;train/val/test ratio sum must be 1.0&quot;)</span><br><span class="line"></span><br><span class="line">    images_dir = Path(SETTINGS[&quot;images_dir&quot;]).resolve()</span><br><span class="line">    xml_dir = Path(SETTINGS[&quot;xml_dir&quot;]).resolve()</span><br><span class="line">    out_dir = Path(SETTINGS[&quot;output_dir&quot;]).resolve()</span><br><span class="line"></span><br><span class="line">    xml_files = sorted([p for p in xml_dir.glob(&quot;*.xml&quot;) if not p.name.startswith(&quot;.&quot;)])</span><br><span class="line">    if not xml_files:</span><br><span class="line">        raise FileNotFoundError(f&quot;No xml files found in &#123;xml_dir&#125;&quot;)</span><br><span class="line"></span><br><span class="line">    samples = []</span><br><span class="line">    cls_names = set()</span><br><span class="line">    skipped = 0</span><br><span class="line"></span><br><span class="line">    for xp in xml_files:</span><br><span class="line">        parsed = parse_xml(xp)</span><br><span class="line">        if parsed is None:</span><br><span class="line">            skipped += 1</span><br><span class="line">            continue</span><br><span class="line"></span><br><span class="line">        filename, w, h, objs = parsed</span><br><span class="line">        stem = Path(filename).stem if filename else xp.stem</span><br><span class="line">        img_path = find_img(images_dir, stem)</span><br><span class="line">        if img_path is None:</span><br><span class="line">            skipped += 1</span><br><span class="line">            continue</span><br><span class="line"></span><br><span class="line">        cls_names.update([o[0] for o in objs])</span><br><span class="line">        samples.append(&#123;</span><br><span class="line">            &quot;file_name&quot;: img_path.name,</span><br><span class="line">            &quot;width&quot;: w,</span><br><span class="line">            &quot;height&quot;: h,</span><br><span class="line">            &quot;objects&quot;: objs,</span><br><span class="line">            &quot;abs_path&quot;: img_path.as_posix(),</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">    if not samples:</span><br><span class="line">        raise RuntimeError(&quot;No valid samples generated&quot;)</span><br><span class="line"></span><br><span class="line">    cls2id = &#123;name: i for i, name in enumerate(sorted(cls_names))&#125;</span><br><span class="line"></span><br><span class="line">    random.Random(SETTINGS[&quot;seed&quot;]).shuffle(samples)</span><br><span class="line">    n = len(samples)</span><br><span class="line">    n_train = int(n * SETTINGS[&quot;train_ratio&quot;])</span><br><span class="line">    n_val = int(n * SETTINGS[&quot;val_ratio&quot;])</span><br><span class="line"></span><br><span class="line">    train = samples[:n_train]</span><br><span class="line">    val = samples[n_train:n_train + n_val]</span><br><span class="line">    test = samples[n_train + n_val:]</span><br><span class="line"></span><br><span class="line">    ann_dir = out_dir / &quot;annotations&quot;</span><br><span class="line">    split_dir = out_dir / &quot;splits&quot;</span><br><span class="line"></span><br><span class="line">    dump_json(ann_dir / &quot;train.json&quot;, to_coco(train, cls2id))</span><br><span class="line">    dump_json(ann_dir / &quot;val.json&quot;, to_coco(val, cls2id))</span><br><span class="line">    dump_json(ann_dir / &quot;test.json&quot;, to_coco(test, cls2id))</span><br><span class="line"></span><br><span class="line">    dump_lines(split_dir / &quot;train.txt&quot;, [x[&quot;abs_path&quot;] for x in train])</span><br><span class="line">    dump_lines(split_dir / &quot;val.txt&quot;, [x[&quot;abs_path&quot;] for x in val])</span><br><span class="line">    dump_lines(split_dir / &quot;test.txt&quot;, [x[&quot;abs_path&quot;] for x in test])</span><br><span class="line"></span><br><span class="line">    ultralytics_yaml = out_dir / &quot;ultralytics_data.yaml&quot;</span><br><span class="line">    ultralytics_yaml.write_text(</span><br><span class="line">        &quot;\n&quot;.join([</span><br><span class="line">            f&quot;train: &#123;(split_dir / &#x27;train.txt&#x27;).as_posix()&#125;&quot;,</span><br><span class="line">            f&quot;val: &#123;(split_dir / &#x27;val.txt&#x27;).as_posix()&#125;&quot;,</span><br><span class="line">            f&quot;test: &#123;(split_dir / &#x27;test.txt&#x27;).as_posix()&#125;&quot;,</span><br><span class="line">            f&quot;nc: &#123;len(cls2id)&#125;&quot;,</span><br><span class="line">            f&quot;names: &#123;[name for name, _ in sorted(cls2id.items(), key=lambda x: x[1])]&#125;&quot;,</span><br><span class="line">        ]) + &quot;\n&quot;,</span><br><span class="line">        encoding=&quot;utf-8&quot;,</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    summary = &#123;</span><br><span class="line">        &quot;images_total&quot;: n,</span><br><span class="line">        &quot;train&quot;: len(train),</span><br><span class="line">        &quot;val&quot;: len(val),</span><br><span class="line">        &quot;test&quot;: len(test),</span><br><span class="line">        &quot;classes&quot;: sorted(cls_names),</span><br><span class="line">        &quot;num_classes&quot;: len(cls_names),</span><br><span class="line">        &quot;skipped_files&quot;: skipped,</span><br><span class="line">        &quot;output_dir&quot;: out_dir.as_posix(),</span><br><span class="line">    &#125;</span><br><span class="line">    dump_json(out_dir / &quot;summary.json&quot;, summary)</span><br><span class="line">    print(json.dumps(summary, ensure_ascii=False, indent=2))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == &quot;__main__&quot;:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure><p>创建自定义配置文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"># 单目标 volleyball 实验配置：S 模型 + Objects365 预训练迁移</span><br><span class="line"># 用法（在 D-FINE 目录下执行）：</span><br><span class="line"># python train.py -c ../config/volleyball_s_transfer.yml --use-amp --seed 0 -t weights/dfine_s_obj365.pth</span><br><span class="line"></span><br><span class="line">__include__: [</span><br><span class="line">  &#x27;../D-FINE/configs/dfine/custom/objects365/dfine_hgnetv2_s_obj2custom.yml&#x27;,</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"># 实验输出目录（相对 D-FINE 工作目录）</span><br><span class="line">output_dir: ./output/exp_s_transfer_obj_aug</span><br><span class="line"></span><br><span class="line"># 数据集设置：单类别，且不做 COCO80 类别重映射</span><br><span class="line">num_classes: 1</span><br><span class="line">remap_mscoco_category: False</span><br><span class="line"></span><br><span class="line"># ============ 数据增强配置 ============</span><br><span class="line"># 启用更激进的数据增强来改进小数据集性能</span><br><span class="line">train_dataloader:</span><br><span class="line">  collate_fn:</span><br><span class="line">    # 多尺度训练</span><br><span class="line">    base_size: 640</span><br><span class="line">    base_size_repeat: 10</span><br><span class="line">    stop_epoch: 56</span><br><span class="line">    ema_restart_decay: 0.9999</span><br><span class="line">    type: BatchImageCollateFunction</span><br><span class="line">  dataset:</span><br><span class="line">    img_folder: C:/Users/Rick/Desktop/python/ObjectDetection/coco/images</span><br><span class="line">    ann_file: C:/Users/Rick/Desktop/python/ObjectDetection/coco/converted/annotations/train.json</span><br><span class="line">    return_masks: False</span><br><span class="line">    type: CocoDetection</span><br><span class="line">  drop_last: True</span><br><span class="line">  num_workers: 4</span><br><span class="line">  shuffle: True</span><br><span class="line">  total_batch_size: 32</span><br><span class="line">  type: DataLoader</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">val_dataloader:</span><br><span class="line">  collate_fn:</span><br><span class="line">    type: BatchImageCollateFunction</span><br><span class="line">  dataset:</span><br><span class="line">    img_folder: C:/Users/Rick/Desktop/python/ObjectDetection/coco/images</span><br><span class="line">    ann_file: C:/Users/Rick/Desktop/python/ObjectDetection/coco/converted/annotations/val.json</span><br><span class="line">    return_masks: False</span><br><span class="line">    # 验证集使用最小增强</span><br><span class="line">    transforms:</span><br><span class="line">      type: Compose</span><br><span class="line">      ops:</span><br><span class="line">        # 只进行必需的变换，不做随机增强</span><br><span class="line">        - type: Resize</span><br><span class="line">          size: [640, 640]</span><br><span class="line">        - type: ConvertPILImage</span><br><span class="line">          dtype: float32</span><br><span class="line">          scale: True</span><br><span class="line">        - type: ConvertBoxes</span><br><span class="line">          fmt: cxcywh</span><br><span class="line">          normalize: True</span><br><span class="line">    type: CocoDetection</span><br><span class="line">  drop_last: False</span><br><span class="line">  num_workers: 4</span><br><span class="line">  shuffle: False</span><br><span class="line">  total_batch_size: 64</span><br><span class="line">  type: DataLoader</span><br><span class="line"></span><br><span class="line"># 每 N 轮额外保存一次 checkpointxxxx.pth（last/best 仍会按训练逻辑保存）</span><br><span class="line">checkpoint_freq: 6  # 从12改为6，保存更频繁</span><br><span class="line"></span><br><span class="line"># 训练总轮次</span><br><span class="line">epochs: 160  # 从120增加到160，更长的训练</span><br><span class="line"></span><br><span class="line"># ========== 额外优化参数 ==========</span><br><span class="line"># 学习率预热</span><br><span class="line">lr_warmup_scheduler:</span><br><span class="line">  type: LinearWarmup</span><br><span class="line">  warmup_duration: 500  # 预热500步</span><br><span class="line"></span><br><span class="line"># EMA模型平滑</span><br><span class="line">ema:</span><br><span class="line">  type: ModelEMA</span><br><span class="line">  decay: 0.9999</span><br><span class="line">  start: 0</span><br><span class="line">  warmups: 2000</span><br><span class="line"></span><br><span class="line"># 梯度裁减</span><br><span class="line">clip_max_norm: 0.1</span><br><span class="line"></span><br><span class="line"># 同步批归一化（多卡训练）</span><br><span class="line">sync_bn: True</span><br></pre></td></tr></table></figure><h3 id="训练-v2">训练</h3><p>参考<a href="https://github.com/51hhh/D-FINE_train">51hhh/D-FINE_train: D-FINE 自定义配置训练</a></p><h4 id="r-resume-和-t-tuning">-r (resume) 和 -t (tuning)</h4><table><thead><tr><th>-r (resume)</th><th>恢复全部状态：模型权重 + 优化器 + last_epoch + lr_scheduler</th></tr></thead><tbody><tr><td>-t (tuning)</td><td>只加载模型权重，epoch 从 0 开始，优化器全新</td></tr></tbody></table><table><thead><tr><th></th><th>-r (resume)</th><th>-t (tuning)</th></tr></thead><tbody><tr><td>模型权重</td><td>加载</td><td>加载</td></tr><tr><td>优化器状态</td><td>恢复</td><td>全新</td></tr><tr><td>last_epoch</td><td>恢复 (=58)</td><td>从 -1 开始</td></tr><tr><td>lr_scheduler</td><td>恢复旧状态</td><td>全新</td></tr><tr><td>EMA 状态</td><td>恢复</td><td>全新</td></tr></tbody></table><p>load_tuning_state() line 249-274 的逻辑：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">def load_tuning_state(self, path):</span><br><span class="line">    # 1. 加载 checkpoint</span><br><span class="line">    state = torch.load(path)</span><br><span class="line">    pretrain_state_dict = state[&quot;ema&quot;][&quot;module&quot;]</span><br><span class="line"></span><br><span class="line">    # 2. 尝试调整 head 参数（处理 num_classes 不匹配）</span><br><span class="line">    adjusted_state_dict = self._adjust_head_parameters(</span><br><span class="line">        module.state_dict(), pretrain_state_dict</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    # 3. 形状匹配的参数全部加载，不匹配的跳过</span><br><span class="line">    stat, infos = self._matched_state(module.state_dict(), adjusted_state_dict)</span><br><span class="line">    module.load_state_dict(stat, strict=False)</span><br></pre></td></tr></table></figure><p>关键：_adjust_head_parameters 只在 num_classes 不同时才调整/丢弃检测头。</p><p>注意按照机器核心调整num_workers，以便达到最佳性能。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_07/image_393bac449dc650522ab6dcd98dc515b5.png" alt=""></p><p>开始训练</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">cd D-FINE</span><br><span class="line"></span><br><span class="line">python train.py -c ../config/volleyball_s_transfer.yml --use-amp --seed 0 -t weights/dfine_s_obj365.pth</span><br><span class="line">python train.py -c ../config/volleyball_s_transfer.yml --use-amp --seed 0 -r output/exp_s_transfer/last.pth</span><br><span class="line"></span><br><span class="line">+ -c 接config配置文件路径</span><br><span class="line"> + -t 从预训练模型路径迁移tuning</span><br><span class="line"> + -r 从last模型开始继续训练resume</span><br></pre></td></tr></table></figure><h2 id="分析和评估">分析和评估</h2><h3 id="分析">分析</h3><p>对于单目标排球训练，使用900张少量数据集迁移。</p><ul><li>exp_s_transfer：obj365预训练模型迁移</li><li>exp_s_transfer_obj_aug：obj预训练模型+数据增强</li><li>exp_s_transfer_obj2coco_aug：obj2coco预训练模型+数据增强</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">`Test/coco_eval_bbox_0`（Precision：AP50:95-all）</span><br><span class="line">`Test/coco_eval_bbox_1`（Precision：AP50）</span><br><span class="line">`Test/coco_eval_bbox_2`（Precision：AP70）</span><br><span class="line">`Test/coco_eval_bbox_3`（Precision：0.50:0.95-small）</span><br><span class="line">`Test/coco_eval_bbox_4`（Precision：0.50:0.95-medium）</span><br><span class="line">`Test/coco_eval_bbox_5`（Precision：0.50:0.95-large）  </span><br><span class="line">`Test/coco_eval_bbox_6`（Recall：0.50:0.95-all-maxDets=1）</span><br><span class="line">`Test/coco_eval_bbox_7`（Recall：0.50:0.95-all-maxDets=10）</span><br><span class="line">`Test/coco_eval_bbox_8`（Recall：0.50:0.95-all-maxDets=100）</span><br><span class="line">`Test/coco_eval_bbox_9`（Recall：0.50:0.95-small-maxDets=100）</span><br><span class="line">`Test/coco_eval_bbox_10`（Recall：0.50:0.95-medium-maxDets=100）</span><br><span class="line">`Test/coco_eval_bbox_11`（Recall：0.50:0.95-large-maxDets=100）</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_02/image_c368e74a61b9d2ffd9a55276871b69a8.png" alt=""></p><p>收敛：蓝色曲线的 AP（<code>coco_eval_bbox_0</code>）在大约 60 个 Epoch 前迅速上升，随后进入平台期</p><p>红色曲线 <code>exp_s_transfer_obj_aug</code> 前期训练loss抖动，而且AP/AR无法快速上升（后续没啥问题，都能用），疑似数据集过小问题，停止训练。<code>obj</code> 数据集里确实有“排球”这个类别（Class 240），但是COCO 的标注更为精准，且包含大量小目标。obj2coco数据集的质量和多样性更好。（<s>官方说Objects365 预训练模型泛化性最好，其实差不多，感觉Objects365+COCO更好</s>）</p><p>无法收敛：橙黄色曲线 <code>exp_s_transfer</code>obj365预训练模型，在训练了120Epoch后依旧无法收敛，表明900+数据集过小。</p><p>小目标缺失： <code>coco_eval_bbox_3/9</code>（代表 Small 尺寸的 AP/AR）。表示数据集中没有配置好小目标。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_02/image_3c0fddc516929a8dc23ad6c0df074fe3.png" alt=""></p><p>Loss 曲线在现代优化器（如 AdamW + Cosine Annealing）的加持下，通常都会表现良好，一般数据集没有问题，不会出现问题。主要查看AP/AR曲线即可。</p><h4 id="数据集标注错误问题">数据集标注错误问题</h4><p>标注数据集没有紧密贴合物体，模型无法正确收敛。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_07/image_5091da501fdf0b26802d7e894aa4b68b.png" alt=""></p><h4 id="预训练模型迁移和从零开始对比">预训练模型迁移和从零开始对比</h4><p>exp_s_transfer_objtococo_aug_2000为在obj2coco模型迁移微调，exp_s_transfer_aug_2000为从零开始训练，收敛需要更长时间。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_08/image_b8012235872069d7f6449b1efaf578c2.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_08/image_ddfb3dc34262d4291a483daedafd3c9c.png" alt=""></p><h4 id="查询过激活">查询过激活</h4><table><thead><tr><th>术语</th><th>含义</th></tr></thead><tbody><tr><td><strong>Query Over-Activation</strong>（查询过激活）</td><td>DETR 系列中，预训练的 learned queries 在微调后仍保留对非目标物体的定位能力，导致错误激活</td></tr><tr><td><strong>False Activation</strong>（假激活）</td><td>D-FINE Issue #277 中使用的原词，指模型对非目标物体产生高置信度检测</td></tr><tr><td><strong>Objectness-Classification Conflation</strong></td><td>目标性与分类的混淆——单类分类头退化为&quot;是否有物体&quot;而非&quot;是否是目标类别&quot;</td></tr><tr><td><strong>Class Collapse</strong>（类别坍缩）</td><td>多类预训练模型微调为单类后，分类维度坍缩，丧失类别区分能力</td></tr></tbody></table><p><strong>DETR 系列架构（D-FINE / RT-DETR）</strong></p><p>D-FINE 基于 RT-DETR 改进，属于 DETR（DEtection TRansformer）家族。核心架构：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">输入图像</span><br><span class="line">  │</span><br><span class="line">  ▼</span><br><span class="line">┌──────────────┐</span><br><span class="line">│   Backbone   │  HGNet-v2 (特征提取)</span><br><span class="line">│  (Encoder)   │</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │  多尺度特征图</span><br><span class="line">       ▼</span><br><span class="line">┌──────────────┐</span><br><span class="line">│  Hybrid      │  高效混合编码器</span><br><span class="line">│  Encoder     │  (特征融合 + 自注意力)</span><br><span class="line">└──────┬───────┘</span><br><span class="line">       │</span><br><span class="line">       ▼</span><br><span class="line">┌──────────────────────────────────┐</span><br><span class="line">│      Transformer Decoder         │</span><br><span class="line">│                                  │</span><br><span class="line">│  300 个 Learned Object Queries   │ ◄── 问题根源</span><br><span class="line">│         ×                        │</span><br><span class="line">│  Cross-Attention (查询 × 特征)   │</span><br><span class="line">│         ×                        │</span><br><span class="line">│  6 层 Decoder Layer              │</span><br><span class="line">└──────────┬───────────────────────┘</span><br><span class="line">           │</span><br><span class="line">     ┌─────┴─────┐</span><br><span class="line">     ▼           ▼</span><br><span class="line">┌─────────┐ ┌──────────┐</span><br><span class="line">│ 分类头   │ │  回归头   │</span><br><span class="line">│ scores  │ │  boxes   │</span><br><span class="line">│ labels  │ │ (x1,y1,  │</span><br><span class="line">│         │ │  x2,y2)  │</span><br><span class="line">└─────────┘ └──────────┘</span><br></pre></td></tr></table></figure><ul><li>D-FINE 使用 <strong>300 个可学习的查询向量</strong>（query embeddings）</li><li>每个 query 在训练过程中&quot;专攻&quot;检测特定位置和类型的物体</li><li>在 COCO 预训练中，这 300 个 query 学会了定位 80 类物体（人、车、椅子、球…）</li><li>推理时，每个 query 通过 cross-attention 与图像特征交互，输出一个检测结果</li></ul><p>D-FINE输出层（单类）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">P(class_i | query_j) = softmax([logit_volleyball, logit_no_object])</span><br><span class="line"></span><br><span class="line">其中 softmax 只有两个类别：</span><br><span class="line">  logit_volleyball  → &quot;是排球&quot;</span><br><span class="line">  logit_no_object   → &quot;没有目标&quot;</span><br><span class="line"></span><br><span class="line">对于非排球物体（如人）：</span><br><span class="line">  query 的 cross-attention 被物体特征强激活</span><br><span class="line">  logit_volleyball 被推高（因为query认为&quot;这里有东西&quot;）</span><br><span class="line">  logit_no_object 被压低</span><br><span class="line">  P(volleyball) ≈ 0.85  → 超过阈值，误检！</span><br></pre></td></tr></table></figure><p>解决方法：</p><ul><li>方案 A：空标注图片加入训练<a href="https://github.com/Peterande/D-FINE/issues/277">Issue #277</a>必须打 Issue #247 补丁防止死锁</li><li>方案 B：训练策略调整</li></ul><table><thead><tr><th>参数</th><th>当前值</th><th>建议值</th><th>说明</th></tr></thead><tbody><tr><td>预训练权重</td><td>Obj365+COCO</td><td><strong>无 / 仅 Objects365</strong></td><td>单类简单场景从头训更好</td></tr><tr><td><code>eos_coefficient</code></td><td>0.1（默认）</td><td><strong>0.3-0.5</strong></td><td>增大 no-object 损失权重，抑制假激活</td></tr><tr><td><code>num_queries</code></td><td>300</td><td><strong>50-100</strong></td><td>减少 query 数量，降低过激活概率</td></tr><tr><td>学习率</td><td>-</td><td>transformer 1e-4, backbone 1e-5</td><td>过高导致训练崩溃</td></tr><tr><td><code>auxiliary_loss</code></td><td>-</td><td><code>True</code></td><td>每层 decoder 都加监督，学会正确的目标数量</td></tr></tbody></table><ul><li>方案 C：Denoising 区域负样本</li></ul><p><a href="https://github.com/Peterande/D-FINE/issues/277">Issue #277</a></p><p>原理：利用 D-FINE 已有的 contrastive denoising 机制，在非目标区域注入负样本，强制 query 学会抑制。不需要额外数据，但需要修改 <code>src/zoo/dfine/denoising.py</code>。</p><h5 id="空标注微调">空标注微调</h5><p>添加空标注图片样本作为负样本。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_13/image_dd1b84a0e65cbf6abfccdbf6e060d283.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_13/image_b7e3b6c8a743f7629e057eeff5fa02bb.png" alt=""></p><p>从左上，右上，左下，右下依次为：</p><p>exp_s_finetune_neg_aug                   exp_s_finetune_neg_objtococo_aug</p><p>exp_s_transfer_aug_2000                  exp_s_transfer_objtococo_aug_2000</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_13/image_c8d17c2082529512646723e2c0b0ffca.png" alt=""></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">┌────────────────────────────┬──────────┬────────────┬───────────┬───────────┬───────────┬────────┬────────────┐</span><br><span class="line">│            模型            │  预训练  │ 负样本微调 │ FPPI @0.3 │ FPPI @0.5 │ FPPI @0.7 │ Max FP │ Clean @0.3 │</span><br><span class="line">├────────────────────────────┼──────────┼────────────┼───────────┼───────────┼───────────┼────────┼────────────┤</span><br><span class="line">│ transfer_aug               │ obj      │ 否         │ 2.15      │ 0.83      │ 0.33      │ 0.930  │ 0%         │</span><br><span class="line">├────────────────────────────┼──────────┼────────────┼───────────┼───────────┼───────────┼────────┼────────────┤</span><br><span class="line">│ transfer_objtococo_aug     │ obj+coco │ 否         │ 1.11      │ 0.48      │ 0.32      │ 0.938  │ 27.7%      │</span><br><span class="line">├────────────────────────────┼──────────┼────────────┼───────────┼───────────┼───────────┼────────┼────────────┤</span><br><span class="line">│ finetune_neg_aug           │ obj      │ 是         │ 2.36      │ 0.68      │ 0.22      │ 0.885  │ 0%         │</span><br><span class="line">├────────────────────────────┼──────────┼────────────┼───────────┼───────────┼───────────┼────────┼────────────┤</span><br><span class="line">│ finetune_neg_objtococo_aug │ obj+coco │ 是         │ 0.93      │ 0.45      │ 0.18      │ 0.925  │ 36.6%      │</span><br><span class="line">└────────────────────────────┴──────────┴────────────┴───────────┴───────────┴───────────┴────────┴────────────┘</span><br></pre></td></tr></table></figure><table><thead><tr><th>FPPI @阈值（False Positives Per Image）</th><th>在置信度阈值下，平均每张背景图的误检数量</th></tr></thead><tbody><tr><td>Max FP（最大误检置信度）</td><td>所有背景图中，最严重误检的置信度值</td></tr><tr><td>Clean @阈值（干净图片比例）</td><td>在置信度阈值下，完全没有任何误检的背景图占比</td></tr></tbody></table><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">                  obj365 路线          obj2coco 路线</span><br><span class="line">                  ──────────          ─────────────</span><br><span class="line">无负样本:          2.15 FPPI           1.11 FPPI</span><br><span class="line">                     ↓ 负样本微调         ↓ 负样本微调</span><br><span class="line">有负样本:          2.36 FPPI (更差!)    0.93 FPPI (改善)</span><br></pre></td></tr></table></figure><p>负样本微调有效，效果有限，原因是负样本只有101张，对于2000+数据集太少。</p><p>负样本微调让更多 query 的分数集中到 0.3-0.5区间，低置信度误检反而变多了，但高置信度误检减少了</p><h5 id="DN随机负样本">DN随机负样本</h5><blockquote><p>在 <code>denoising.py</code> 中，在与图片原有目标没有交集的区域随机生成框，将其标签视为背景类参与分类损失</p></blockquote><p>原理：利用 D-FINE 已有的 contrastive denoising 机制，在非目标区域注入负样本，强制 query 学会抑制。不需要额外数据，但需要修改 <code>src/zoo/dfine/denoising.py</code>。</p><p>参考<a href="https://github.com/51hhh/D-FINE_train/tree/a285f6a7ab2cfa11bb381f0161289e0b4e83f876">51hhh/D-FINE_train at a285f6a7ab2cfa11bb381f0161289e0b4e83f876</a></p><ol><li>每张图随机生成有限数量（如 50 个）的框</li><li>过滤掉与 GT 框重叠的（IoU &gt; 0.3）</li><li>剩余框标记为 background 类（<code>class_id = num_classes</code>，即 padding index）</li><li>这些框<strong>只参与分类 loss</strong>（推向 no-object），<strong>不参与回归 loss</strong></li><li>通过 DN 机制注入训练，无需额外数据</li></ol><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_14/image_74004111722bd40648cb404e44174da6.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_14/image_f759892d9667f055f5a6ea305df3f9f4.png" alt=""></p><p>上图为exp_s_obj2coco_neg_d，下图为exp_s_obj2coco_neg_d_q100</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_14/image_1185479fa46d36fe2c5e6638778c0712.png" alt=""></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">┌───────────────────┬──────────┬──────────┬────────────────┬──────────┬──────────┬────────────────┐</span><br><span class="line">│       模型        │   策略   │ FPPI@0.3 │ Clean Rate@0.3 │ Max Conf │ FPPI@0.5 │ Clean Rate@0.5 │</span><br><span class="line">├───────────────────┼──────────┼──────────┼────────────────┼──────────┼──────────┼────────────────┤</span><br><span class="line">│ obj2custom (基准) │ 无       │ 1.109    │ 27.7%          │ 0.938    │ 0.475    │ 58.4%          │</span><br><span class="line">├───────────────────┼──────────┼──────────┼────────────────┼──────────┼──────────┼────────────────┤</span><br><span class="line">│ finetune_neg_aug  │ 无D      │ 0.931    │ 36.6%          │ 0.925    │ 0.446    │ 60.4%          │</span><br><span class="line">├───────────────────┼──────────┼──────────┼────────────────┼──────────┼──────────┼────────────────┤</span><br><span class="line">│ neg_d             │ A+D      │ 0.040    │ 96.0%          │ 0.417    │ 0.000    │ 100%           │</span><br><span class="line">├───────────────────┼──────────┼──────────┼────────────────┼──────────┼──────────┼────────────────┤</span><br><span class="line">│ neg_d_q100        │ A+D+Q100 │ 0.050    │ 96.0%          │ 0.698    │ 0.010    │ 99.0%          │</span><br><span class="line">└───────────────────┴──────────┴──────────┴────────────────┴──────────┴──────────┴────────────────┘</span><br></pre></td></tr></table></figure><p>neg_d 最优的：</p><ul><li>FPPI@0.3 = 0.040（相比基准 1.109 下降 96.4%）</li><li>Clean Image Rate@0.3 = 96%（几乎没有误检）</li><li>Max Confidence = 0.417（远低于其他模型的 0.9+）</li><li>FPPI@0.5 = 0.0（零高置信度误检）</li></ul><h5 id="添加bg-loss配置和训练中评估">添加bg_loss配置和训练中评估</h5><p>exp_s_obj2coco_neg_d/对比exp_s_obj2coco_neg_d_bg2/</p><p>bg2添加了：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># ============ 背景 loss 权重（放大背景查询的 VFL loss 梯度）============</span><br><span class="line">DFINECriterion:</span><br><span class="line">  bg_loss_weight: 2.0</span><br><span class="line"></span><br><span class="line"># ============ Over-Activation 训练中评估 ============</span><br><span class="line">eval_overactivation: True</span><br><span class="line">negative_img_dir: &quot;../coco/images/negative_samples&quot;</span><br><span class="line">oa_conf_threshold: 0.3</span><br><span class="line">oa_ap_tolerance: 0.005  # stg2 AP下降≤0.5%时，若OA改善则保存best_oa.pth跳过rollback</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>解决exp_s_obj2coco_neg_d实际部署依旧会存在误检测情况。（上图D-FINE Query Over-Activation Analysis (Negative Images)指标不对，训练<code>exp_s_obj2coco_neg_d</code>时候<code>negative_samples</code>已经存在训练集中，导致评估指标时候表现良好。）</p><p><strong>！！！</strong></p><p><strong>注意negative_samples评估数据需要与训练中negative_samples不同，测评指标才具有参考价值。</strong></p><p><strong>Over-Activation 训练中评估开启后需要在test中对negative_samples数据集检验测评，因为oa保存best模型原因与训练不能并行，会导致每次epoch增加10s（具体取决于negative_samples大小和算力大小）</strong></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_15/image_c13cc7d186c1186b019453814acf4981.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_15/image_e881ba35c3a8689c608e8ba822e786d0.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_15/image_7ee173b136a47650af3105e094a8326f.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_15/image_3ba41442257f78f1d2d0393a431a83fe.png" alt=""></p><p><code>Test/oa_fppi</code> — False Positives Per Image</p><p><strong>每张负样本图的平均误检数</strong>（置信度 &gt;= <code>oa_conf_threshold</code>）</p><table><thead><tr><th>值</th><th>含义</th></tr></thead><tbody><tr><td>0.04</td><td>100 张背景图共 4 个误检，几乎无误检（生产级）</td></tr><tr><td>2.15</td><td>100 张背景图共 215 个误检，严重过激活</td></tr></tbody></table><ul><li>值域：0 → ∞</li><li>理想值：&lt; 0.05</li><li>趋势期望：随训练<strong>持续下降</strong></li></ul><p><code>Test/oa_clean_rate</code> — Clean Image Rate</p><p><strong>完全无误检的负样本图片比例</strong></p><table><thead><tr><th>值</th><th>含义</th></tr></thead><tbody><tr><td>0.96</td><td>100 张中 96 张完全干净，4 张有误检</td></tr><tr><td>0.00</td><td>所有图片都有至少一个误检（最差情况）</td></tr></tbody></table><ul><li>值域：0.0 → 1.0</li><li>理想值：&gt; 0.95</li><li>趋势期望：随训练<strong>持续上升</strong></li></ul><p><code>Test/oa_max_score</code> — Max Detection Score</p><p><strong>所有负样本图中最高的单个误检置信度</strong></p><table><thead><tr><th>值</th><th>含义</th></tr></thead><tbody><tr><td>0.417</td><td>最严重误检置信度 41.7%，用 0.5 阈值可完全过滤（安全）</td></tr><tr><td>0.930</td><td>最严重误检置信度 93%，模型对误检极度自信（危险）</td></tr></tbody></table><ul><li>值域：0.0 → 1.0</li><li>理想值：&lt; 0.5</li><li>趋势期望：随训练<strong>持续下降</strong></li></ul><h4 id="边界框质量">边界框质量</h4><p>D-FINE 将边界框回归重新定义为概率分布的精细化过程，而非直接回归坐标：</p><p>传统 DETR：query → [x, y, w, h]（4个确定值）<br>D-FINE：   query → [P(x), P(y), P(w), P(h)]（4个概率分布）<br>每个分布有 N 个离散 bin</p><p>这使得 D-FINE 的边界框质量更高</p><h3 id="评估">评估</h3><p>主要查看COCO 评估指标能够准确判断模型情况。</p><p>D-FINE默认提供了模型在不同 <strong>IoU 阈值</strong> 和 <strong>目标尺寸</strong> 下的精度（Precision）和召回率（Recall）等参数。</p><ul><li><strong>IoU (Intersection over Union):</strong> 预测框与真实框的重叠度</li><li><strong>AP (Average Precision):</strong> 精确率曲线下的面积。</li><li><strong>AR (Average Recall):</strong> 召回率，即模型找全目标的能力。</li></ul><table><thead><tr><th><strong>术语</strong></th><th><strong>全称</strong></th><th><strong>含义</strong></th><th><strong>预测情况</strong></th></tr></thead><tbody><tr><td><strong>TP</strong></td><td><strong>True Positive</strong></td><td><strong>真正例</strong></td><td>模型说是正类，实际<strong>也是</strong>正类</td></tr><tr><td><strong>TN</strong></td><td><strong>True Negative</strong></td><td><strong>真负例</strong></td><td>模型说是负类，实际<strong>也是</strong>负类</td></tr><tr><td><strong>FP</strong></td><td><strong>False Positive</strong></td><td><strong>假正例</strong></td><td>模型说是正类，实际<strong>却是</strong>负类</td></tr><tr><td><strong>FN</strong></td><td><strong>False Negative</strong></td><td><strong>假负例</strong></td><td>模型说是负类，实际<strong>却是</strong>正类</td></tr></tbody></table><p><strong>精确率 (Precision)</strong></p><p><strong>定义：</strong> 在模型<strong>所有预测为正类</strong>的样本中，真正是对的占比</p><p>$$Precision = \frac{TP}{TP + FP}$$</p><p>高精确率 (High Precision)表示模型检测到10个目标，有9个是正确的，检测精准正确。<strong>可能在很有把握才识别，容易漏识别，即低Recall</strong></p><p><strong>召回率 (Recall)</strong></p><p><strong>定义：</strong> 在<strong>所有实际为正类</strong>的样本中，模型成功找出的占比</p><p>$$Recall = \frac{TP}{TP + FN}$$</p><p>高召回率 (High Recall)表示模型在10个真正目标中，检测到9个，很少漏检，<strong>可能过于自信，检测到假目标，即低Precision</strong></p><p>精确率和召回率往往是<strong>此消彼长</strong>的（Trade-off），可以使用<strong>F1-Score</strong> 来平衡这两者</p><h3 id="主要查看指标">主要查看指标</h3><p><strong><code>AP @[ IoU=0.50:0.95 ] </code></strong> ：单个类别的平均精度,这是最重要的综合指标。它计算了 IoU 从 0.5 到 0.95（步长 0.05）的平均值：0.5:0.05:0.95</p><p><strong><code>mAP @[ IoU=0.50:0.95 ] </code></strong> ：多个类别平均精度的平均值，模型检测各个class的AP的平均。</p><p><strong><code>AP @[ IoU=50/75]</code></strong>：IoU 阈值为 X 时的 AP，预测框和真实框的 <strong>IoU &gt; 0.5</strong>，就认为它是 TP，较为宽容，而75则更为严格，要求模型的预测框必须与真实框<strong>高度重合</strong>。</p><p><strong><code>area=small/medium/large</code></strong> 测试集中目标大小得分</p><h2 id="可视化">可视化</h2><p>使用 <code>fiftyone</code>可视化。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br></pre></td><td class="code"><pre><span class="line">import json</span><br><span class="line">import sys</span><br><span class="line">from collections import defaultdict</span><br><span class="line">from pathlib import Path</span><br><span class="line"></span><br><span class="line">import fiftyone as fo</span><br><span class="line">import fiftyone.core.labels as fol</span><br><span class="line">import torch</span><br><span class="line">import torchvision.transforms as T</span><br><span class="line">from PIL import Image</span><br><span class="line">from tqdm import tqdm</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># ==========================</span><br><span class="line"># Hardcoded runtime settings</span><br><span class="line"># ==========================</span><br><span class="line"># 修改这里即可，无需命令行传参</span><br><span class="line">SETTINGS = &#123;</span><br><span class="line">    &quot;repo_dir&quot;: &quot;./D-FINE&quot;,</span><br><span class="line">    &quot;config&quot;: &quot;./config/volleyball_s_transfer.yml&quot;,</span><br><span class="line">    &quot;checkpoint&quot;: &quot;./D-FINE/output/exp_s_transfer_obj2coco_aug/best_stg1.pth&quot;,  # 最新的最佳权重</span><br><span class="line">    &quot;img_root&quot;: &quot;./coco/images&quot;,</span><br><span class="line">    &quot;ann_file&quot;: &quot;./coco/converted/annotations/val.json&quot;,</span><br><span class="line">    &quot;dataset_name&quot;: &quot;volleyball-val-s-b1&quot;,</span><br><span class="line">    &quot;eval_key&quot;: &quot;eval&quot;,</span><br><span class="line">    &quot;device&quot;: &quot;cuda:0&quot;,</span><br><span class="line">    &quot;input_size&quot;: 640,</span><br><span class="line">    &quot;conf_thres&quot;: 0.25,</span><br><span class="line">    &quot;limit&quot;: 0,  # 0 = all</span><br><span class="line">    &quot;overwrite&quot;: True,</span><br><span class="line">    &quot;no_app&quot;: False,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def load_dfine_model(repo_dir: Path, config_path: str, checkpoint_path: str, device: str):</span><br><span class="line">    sys.path.insert(0, str(repo_dir.resolve()))</span><br><span class="line">    from src.core import YAMLConfig</span><br><span class="line"></span><br><span class="line">    safe_config_path = prepare_windows_readable_config(Path(config_path))</span><br><span class="line">    try:</span><br><span class="line">        cfg = YAMLConfig(str(safe_config_path), resume=checkpoint_path)</span><br><span class="line">    finally:</span><br><span class="line">        cleanup_temp_config(safe_config_path, Path(config_path))</span><br><span class="line">    if &quot;HGNetv2&quot; in cfg.yaml_cfg:</span><br><span class="line">        cfg.yaml_cfg[&quot;HGNetv2&quot;][&quot;pretrained&quot;] = False</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line">        checkpoint = torch.load(checkpoint_path, map_location=&quot;cpu&quot;, weights_only=True)</span><br><span class="line">    except TypeError:</span><br><span class="line">        checkpoint = torch.load(checkpoint_path, map_location=&quot;cpu&quot;)</span><br><span class="line">    except Exception:</span><br><span class="line">        checkpoint = torch.load(checkpoint_path, map_location=&quot;cpu&quot;)</span><br><span class="line">    state = checkpoint[&quot;ema&quot;][&quot;module&quot;] if &quot;ema&quot; in checkpoint else checkpoint[&quot;model&quot;]</span><br><span class="line">    cfg.model.load_state_dict(state, strict=False)</span><br><span class="line"></span><br><span class="line">    model = cfg.model.deploy().to(device).eval()</span><br><span class="line">    postprocessor = cfg.postprocessor.deploy().to(device).eval()</span><br><span class="line">    return model, postprocessor</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def prepare_windows_readable_config(config_path: Path) -&gt; Path:</span><br><span class="line">    &quot;&quot;&quot;</span><br><span class="line">    D-FINE&#x27;s yaml loader opens files without explicit encoding.</span><br><span class="line">    On Windows this can default to GBK and fail on UTF-8 comments.</span><br><span class="line">    This helper creates a GBK-readable temporary copy in the same directory.</span><br><span class="line">    &quot;&quot;&quot;</span><br><span class="line">    if not config_path.exists():</span><br><span class="line">        raise FileNotFoundError(f&quot;Config file not found: &#123;config_path&#125;&quot;)</span><br><span class="line"></span><br><span class="line">    text = None</span><br><span class="line">    for enc in (&quot;utf-8-sig&quot;, &quot;utf-8&quot;, &quot;gbk&quot;):</span><br><span class="line">        try:</span><br><span class="line">            text = config_path.read_text(encoding=enc)</span><br><span class="line">            break</span><br><span class="line">        except UnicodeDecodeError:</span><br><span class="line">            continue</span><br><span class="line">    if text is None:</span><br><span class="line">        raise RuntimeError(f&quot;Cannot decode config file: &#123;config_path&#125;&quot;)</span><br><span class="line"></span><br><span class="line">    # Build an ASCII-only temporary config so both UTF-8 and GBK default decoders can read it.</span><br><span class="line">    safe_text = text.encode(&quot;ascii&quot;, errors=&quot;ignore&quot;).decode(&quot;ascii&quot;)</span><br><span class="line">    tmp_path = config_path.parent / f&quot;.fo_tmp_&#123;config_path.stem&#125;.yml&quot;</span><br><span class="line">    tmp_path.write_text(safe_text, encoding=&quot;utf-8&quot;)</span><br><span class="line">    return tmp_path</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def cleanup_temp_config(tmp_path: Path, original_config_path: Path):</span><br><span class="line">    # Do not remove if it&#x27;s exactly the original file path</span><br><span class="line">    if tmp_path.resolve() == original_config_path.resolve():</span><br><span class="line">        return</span><br><span class="line">    try:</span><br><span class="line">        if tmp_path.exists():</span><br><span class="line">            tmp_path.unlink()</span><br><span class="line">    except Exception:</span><br><span class="line">        pass</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def load_coco(ann_file: Path):</span><br><span class="line">    data = json.loads(ann_file.read_text(encoding=&quot;utf-8&quot;))</span><br><span class="line">    images = data[&quot;images&quot;]</span><br><span class="line">    annotations = data[&quot;annotations&quot;]</span><br><span class="line">    categories = data[&quot;categories&quot;]</span><br><span class="line"></span><br><span class="line">    anns_by_image = defaultdict(list)</span><br><span class="line">    for ann in annotations:</span><br><span class="line">        anns_by_image[ann[&quot;image_id&quot;]].append(ann)</span><br><span class="line"></span><br><span class="line">    cat_id_to_name = &#123;c[&quot;id&quot;]: c[&quot;name&quot;] for c in categories&#125;</span><br><span class="line">    return images, anns_by_image, cat_id_to_name</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def clamp01(x):</span><br><span class="line">    return max(0.0, min(1.0, x))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def coco_bbox_to_fo_detection(bbox_xywh, w, h, label, confidence=None):</span><br><span class="line">    x, y, bw, bh = bbox_xywh</span><br><span class="line">    nx = clamp01(x / w)</span><br><span class="line">    ny = clamp01(y / h)</span><br><span class="line">    nw = clamp01(bw / w)</span><br><span class="line">    nh = clamp01(bh / h)</span><br><span class="line">    kwargs = dict(label=label, bounding_box=[nx, ny, nw, nh])</span><br><span class="line">    if confidence is not None:</span><br><span class="line">        kwargs[&quot;confidence&quot;] = float(confidence)</span><br><span class="line">    return fol.Detection(**kwargs)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def xyxy_abs_to_fo_detection(box_xyxy, w, h, label, confidence):</span><br><span class="line">    x1, y1, x2, y2 = box_xyxy</span><br><span class="line">    x1 = clamp01(float(x1) / w)</span><br><span class="line">    y1 = clamp01(float(y1) / h)</span><br><span class="line">    x2 = clamp01(float(x2) / w)</span><br><span class="line">    y2 = clamp01(float(y2) / h)</span><br><span class="line">    bw = clamp01(x2 - x1)</span><br><span class="line">    bh = clamp01(y2 - y1)</span><br><span class="line">    return fol.Detection(</span><br><span class="line">        label=label,</span><br><span class="line">        bounding_box=[x1, y1, bw, bh],</span><br><span class="line">        confidence=float(confidence),</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def unpack_predictions(pred_output):</span><br><span class="line">    &quot;&quot;&quot;</span><br><span class="line">    Support both formats:</span><br><span class="line">    1) deploy mode tuple: (labels, boxes, scores), each shape [B, Q, ...]</span><br><span class="line">    2) training/eval mode list[dict]: [&#123;&#x27;labels&#x27;,&#x27;boxes&#x27;,&#x27;scores&#x27;&#125;, ...]</span><br><span class="line">    Returns tensors for a single sample: labels_1d, boxes_2d, scores_1d</span><br><span class="line">    &quot;&quot;&quot;</span><br><span class="line">    # deploy tuple</span><br><span class="line">    if isinstance(pred_output, (tuple, list)) and len(pred_output) == 3 and torch.is_tensor(pred_output[0]):</span><br><span class="line">        labels_b, boxes_b, scores_b = pred_output</span><br><span class="line">        return labels_b[0], boxes_b[0], scores_b[0]</span><br><span class="line"></span><br><span class="line">    # list of dicts</span><br><span class="line">    if isinstance(pred_output, list) and len(pred_output) &gt; 0 and isinstance(pred_output[0], dict):</span><br><span class="line">        first = pred_output[0]</span><br><span class="line">        return first[&quot;labels&quot;], first[&quot;boxes&quot;], first[&quot;scores&quot;]</span><br><span class="line"></span><br><span class="line">    raise TypeError(f&quot;Unsupported prediction output type: &#123;type(pred_output)&#125;&quot;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">@torch.no_grad()</span><br><span class="line">def run():</span><br><span class="line">    cfg = SETTINGS</span><br><span class="line">    repo_dir = Path(cfg[&quot;repo_dir&quot;])</span><br><span class="line">    img_root = Path(cfg[&quot;img_root&quot;])</span><br><span class="line">    ann_file = Path(cfg[&quot;ann_file&quot;])</span><br><span class="line"></span><br><span class="line">    if fo.dataset_exists(cfg[&quot;dataset_name&quot;]):</span><br><span class="line">        if cfg[&quot;overwrite&quot;]:</span><br><span class="line">            fo.delete_dataset(cfg[&quot;dataset_name&quot;])</span><br><span class="line">        else:</span><br><span class="line">            raise RuntimeError(</span><br><span class="line">                f&quot;Dataset &#x27;&#123;cfg[&#x27;dataset_name&#x27;]&#125;&#x27; already exists. Set SETTINGS[&#x27;overwrite&#x27;]=True to replace it.&quot;</span><br><span class="line">            )</span><br><span class="line"></span><br><span class="line">    images, anns_by_image, cat_id_to_name = load_coco(ann_file)</span><br><span class="line">    if cfg[&quot;limit&quot;] and cfg[&quot;limit&quot;] &gt; 0:</span><br><span class="line">        images = images[: cfg[&quot;limit&quot;]]</span><br><span class="line"></span><br><span class="line">    model, postprocessor = load_dfine_model(</span><br><span class="line">        repo_dir, cfg[&quot;config&quot;], cfg[&quot;checkpoint&quot;], cfg[&quot;device&quot;]</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    tfm = T.Compose(</span><br><span class="line">        [</span><br><span class="line">            T.Resize((cfg[&quot;input_size&quot;], cfg[&quot;input_size&quot;])),</span><br><span class="line">            T.ToTensor(),</span><br><span class="line">        ]</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    dataset = fo.Dataset(cfg[&quot;dataset_name&quot;])</span><br><span class="line"></span><br><span class="line">    for img_info in tqdm(images, desc=&quot;Building FiftyOne dataset&quot;):</span><br><span class="line">        image_id = img_info[&quot;id&quot;]</span><br><span class="line">        file_name = img_info[&quot;file_name&quot;]</span><br><span class="line">        width = img_info[&quot;width&quot;]</span><br><span class="line">        height = img_info[&quot;height&quot;]</span><br><span class="line">        image_path = img_root / file_name</span><br><span class="line"></span><br><span class="line">        if not image_path.exists():</span><br><span class="line">            # Skip missing files instead of hard failing</span><br><span class="line">            continue</span><br><span class="line"></span><br><span class="line">        sample = fo.Sample(filepath=str(image_path.resolve()))</span><br><span class="line"></span><br><span class="line">        # Ground truth</span><br><span class="line">        gt_dets = []</span><br><span class="line">        for ann in anns_by_image.get(image_id, []):</span><br><span class="line">            cat_id = ann[&quot;category_id&quot;]</span><br><span class="line">            label = cat_id_to_name.get(cat_id, str(cat_id))</span><br><span class="line">            gt_dets.append(coco_bbox_to_fo_detection(ann[&quot;bbox&quot;], width, height, label))</span><br><span class="line">        sample[&quot;ground_truth&quot;] = fol.Detections(detections=gt_dets)</span><br><span class="line"></span><br><span class="line">        # Prediction</span><br><span class="line">        image = Image.open(image_path).convert(&quot;RGB&quot;)</span><br><span class="line">        tensor = tfm(image).unsqueeze(0).to(cfg[&quot;device&quot;])</span><br><span class="line">        orig_target_sizes = torch.tensor(</span><br><span class="line">            [[width, height]], dtype=torch.float32, device=cfg[&quot;device&quot;]</span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        outputs = model(tensor)</span><br><span class="line">        pred_output = postprocessor(outputs, orig_target_sizes)</span><br><span class="line">        labels_t, boxes_t, scores_t = unpack_predictions(pred_output)</span><br><span class="line"></span><br><span class="line">        labels = labels_t.detach().cpu().tolist()</span><br><span class="line">        boxes = boxes_t.detach().cpu().tolist()</span><br><span class="line">        scores = scores_t.detach().cpu().tolist()</span><br><span class="line"></span><br><span class="line">        pred_dets = []</span><br><span class="line">        for label_id, box, score in zip(labels, boxes, scores):</span><br><span class="line">            if score &lt; cfg[&quot;conf_thres&quot;]:</span><br><span class="line">                continue</span><br><span class="line"></span><br><span class="line">            # Handle both 0-based and 1-based label id conventions</span><br><span class="line">            if label_id in cat_id_to_name:</span><br><span class="line">                label_name = cat_id_to_name[label_id]</span><br><span class="line">            elif (label_id + 1) in cat_id_to_name:</span><br><span class="line">                label_name = cat_id_to_name[label_id + 1]</span><br><span class="line">            else:</span><br><span class="line">                label_name = str(label_id)</span><br><span class="line"></span><br><span class="line">            pred_dets.append(xyxy_abs_to_fo_detection(box, width, height, label_name, score))</span><br><span class="line"></span><br><span class="line">        sample[&quot;predictions&quot;] = fol.Detections(detections=pred_dets)</span><br><span class="line">        dataset.add_sample(sample)</span><br><span class="line"></span><br><span class="line">    results = dataset.evaluate_detections(</span><br><span class="line">        &quot;predictions&quot;,</span><br><span class="line">        gt_field=&quot;ground_truth&quot;,</span><br><span class="line">        eval_key=cfg[&quot;eval_key&quot;],</span><br><span class="line">        compute_mAP=True,</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    try:</span><br><span class="line">        print(f&quot;mAP: &#123;results.mAP():.6f&#125;&quot;)</span><br><span class="line">    except Exception:</span><br><span class="line">        print(&quot;mAP: unavailable&quot;)</span><br><span class="line">    print(f&quot;Dataset: &#123;dataset.name&#125;&quot;)</span><br><span class="line">    print(f&quot;Samples: &#123;len(dataset)&#125;&quot;)</span><br><span class="line">    print(&quot;Use FiftyOne sidebar to inspect FP/FN and per-sample errors.&quot;)</span><br><span class="line"></span><br><span class="line">    if not cfg[&quot;no_app&quot;]:</span><br><span class="line">        session = fo.launch_app(dataset)</span><br><span class="line">        session.wait()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ == &quot;__main__&quot;:</span><br><span class="line">    run()</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_02/image_9411406b7f4a9f3933e9e58be2ed5b51.png" alt=""></p><p>手工标注的数据集与实际目标边缘存在较大误差，实测模型识别得更为精准。可以更新数据集，再次训练使得AP继续上升。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/03_02/image_d30c90a1fab7e18569032117e7338e4c.png" alt=""></p><p>可以将图片添加为负样本继续微调。</p><h3 id="负样本微调">负样本微调</h3><p>咕咕咕。。。</p><h2 id="部署">部署</h2><p>咕咕咕。。。</p>]]></content>
    
    
    <summary type="html">D-FINE
D-FINE 是一个强大的实时目标检测器，将 DETR
中的边界框回归任务重新定义为了细粒度的分布优化（FDR），并引入全局最优的定位自蒸馏（GO-LSD），在不增加额外推理和训练成本的情况下，实现了卓越的性能。

Peterande/D-FINE: D-FINE: Redefine Regression Task of DETRs as Fine-grained
Distribution Refinement [ICLR 202 [https://github.com/Peterande/D-FINE]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Orin NX 的种种</title>
    <link href="https://polar-bear.eu.org/2026/01/24/orin-nx-de-chong-chong/"/>
    <id>https://polar-bear.eu.org/2026/01/24/orin-nx-de-chong-chong/</id>
    <published>2026-01-24T00:22:31.356Z</published>
    <updated>2026-04-15T19:07:22.563Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Orin-NX">Orin NX</h2><h3 id="link">link</h3><p><a href="https://developer.nvidia.com/nsight-systems">Nsight 系统 |NVIDIA 开发者</a></p><h2 id="开始配置">开始配置</h2><h3 id="NoMachine">NoMachine</h3><p><a href="https://download.nomachine.com/download/?id=30&amp;platform=linux&amp;distro=arm">Downloads – Download</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo apt update</span><br><span class="line">sudo apt upgrade -y</span><br><span class="line">sudo dpkg -i nomachine_*_arm64.deb</span><br></pre></td></tr></table></figure><p><strong>配置启动</strong></p><ol><li><p>配置服务器以允许远程连接</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl start nxserver</span><br></pre></td></tr></table></figure></li><li><p>设置<code>NoMachine</code>为开机启动：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl enable nxserver</span><br></pre></td></tr></table></figure></li><li><p>设置<code>EGL Capture</code> 为<code>yes</code>，这是<code>NoMachine</code>提供的一个屏幕捕获功能，主要用于改善在特定显示服务器环境下的远程桌面体验：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo /etc/NX/nxserver --eglcapture yes</span><br></pre></td></tr></table></figure><p>该命令重启后生效，可使用以下命令二次确认，当出现<code>EGL Capture has been enabled</code>则表示该功能已写入配置文件。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if [ -f &quot;/usr/lib/systemd/user/org.gnome.Shell@wayland.service&quot; ] &amp;&amp; grep -q &quot;nxpreload.sh&quot; &quot;/usr/lib/systemd/user/org.gnome.Shell@wayland.service&quot; &amp;&amp; [ -f &quot;/usr/share/applications/org.gnome.Shell.desktop&quot; ] &amp;&amp; grep -q &quot;nxpreload.sh&quot; &quot;/usr/share/applications/org.gnome.Shell.desktop&quot; &amp;&amp; [ -f &quot;/usr/NX/etc/node.cfg&quot; ] &amp;&amp; grep -q &quot;EnableEGLCapture 1&quot; &quot;/usr/NX/etc/node.cfg&quot;; then echo &quot;EGL Capture has been enabled&quot;; else echo &quot;Not enabled&quot;; fi</span><br></pre></td></tr></table></figure></li><li><p>重启<code>NoMachine</code>服务:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl restart nxserver</span><br></pre></td></tr></table></figure></li></ol><p>重启</p><h3 id="snap版本">snap版本</h3><p>刷机后snap版本是2.7.0，Jetson内核与snap2.7.0不兼容，所以用snap2.7.0安装chrome/firefox后，有问题</p><p><strong>修复方法</strong>：回退到与 Jetson 兼容的旧版本 Snap</p><p>执行以下命令即可（安装Snap 2.68.5并锁定，使其不会被snap或apt更新）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">snap download snapd --revision=24724</span><br><span class="line">sudo snap ack snapd_24724.assert</span><br><span class="line">sudo snap install snapd_24724.snap</span><br><span class="line">sudo snap refresh --hold snapd</span><br></pre></td></tr></table></figure><p>由于orin是arm架构因此无法安装x86 版本的chrome，只能安装 chromium，具体命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo add-apt-repository ppa:a-v-shkop/chromium</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install chromium-browser</span><br></pre></td></tr></table></figure><h3 id="GPIO">GPIO</h3><p>如果要在 Jetson 中使用硬件 PWM，则需要修改 Pinmux 表来多路复用。Jetpack 提供了一个名为 jetson-io 的工具，它允许创建和更新可以使用 PWM 的 dtb。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo /opt/nvidia/jetson-io/jetson-io.py</span><br></pre></td></tr></table></figure><p>选择 <code>Configure Jetson 40pin Header</code> &gt; <code>Configure header pins manually</code> ， pwm7(32)选择并 <code>Back</code>，<code>Save pin changes</code> ，<code>Save and reboot to reconfigure pins</code>，按下任意键后重启，即可完成设置。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_89d49b57e394cd280017bed2e8569450.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_b7c8a9c2cff97fdee735459cf5de1274.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_a3dd1c1526ea7a211df07c808a7f0574.png" alt=""></p><h4 id="libgpiod">libgpiod</h4><p><strong>在使用第三方载板时，jetson-io工具无法确定载板型号。需要手动配置引脚复用。</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ sudo <span class="built_in">cat</span> /sys/kernel/debug/gpio | grep PG.06</span><br><span class="line"> gpio-389 (PG.06               |usbhub_power_en     ) out lo </span><br><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ ^C</span><br><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ sudo <span class="built_in">cat</span> /sys/kernel/debug/gpio | grep PH.00</span><br><span class="line"> gpio-391 (PH.00               |m2_KeyB_power_en    ) out lo </span><br><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ </span><br><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ sudo <span class="built_in">cat</span> /sys/kernel/debug/gpio | grep PN.01</span><br><span class="line"> gpio-433 (PN.01               )</span><br><span class="line">nvidia@tegra-ubuntu:/sys/class/pwm/pwmchip4$ sudo <span class="built_in">cat</span> /sys/kernel/debug/gpio | grep PCC.00</span><br><span class="line"> gpio-328 (PCC.00              |user-led            ) out lo </span><br></pre></td></tr></table></figure><p>但是载板并没有引出PWM引脚，使用GPIO模拟。</p><p>sudo apt-get install libgpiod-dev</p><p>sudo gpioinfo</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_9a31e601aaa13bca627a8773b0eb1bc4.png" alt=""></p><p>设置 GPIO 高低：sudo gpioset --mode=wait gpiochip0 106=1</p><p>sudo gpioset --mode=wait gpiochip0 106=0</p><h4 id="GPIO占用">GPIO占用</h4><p>Orin NX Super 设备树路径: <code>/bus@0/i2c@c250000/gpio@24</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看当前状态</span></span><br><span class="line">fdtget /boot/dtb/kernel_tegra234-p3768-0000+p3767-0000-nv-super.dtb \</span><br><span class="line">    /bus@0/i2c@c250000/gpio@24/j16-30 status</span><br><span class="line"><span class="comment"># 输出: okay</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 备份 DTB</span></span><br><span class="line">sudo <span class="built_in">cp</span> /boot/dtb/kernel_tegra234-p3768-0000+p3767-0000-nv-super.dtb \</span><br><span class="line">       /boot/dtb/kernel_tegra234-p3768-0000+p3767-0000-nv-super.dtb.bak</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用 j16-30 hog (gpiochip2 line 7)</span></span><br><span class="line">sudo fdtput -t s /boot/dtb/kernel_tegra234-p3768-0000+p3767-0000-nv-super.dtb \</span><br><span class="line">    /bus@0/i2c@c250000/gpio@24/j16-30 status disabled</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证修改</span></span><br><span class="line">fdtget /boot/dtb/kernel_tegra234-p3768-0000+p3767-0000-nv-super.dtb \</span><br><span class="line">    /bus@0/i2c@c250000/gpio@24/j16-30 status</span><br><span class="line"><span class="comment"># 输出: disabled</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启生效</span></span><br><span class="line">sudo reboot</span><br></pre></td></tr></table></figure><p><strong>重启后验证</strong>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sudo gpioinfo gpiochip2</span><br><span class="line"><span class="comment"># line 7 应显示 &quot;unused&quot; 而非 &quot;[used]&quot;</span></span><br><span class="line"></span><br><span class="line">sudo gpioget gpiochip2 7</span><br><span class="line"><span class="comment"># 应输出 0 (成功) 而不是 &quot;Device or resource busy&quot;</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>恢复方法</strong>: <code>sudo cp /boot/dtb/...nv-super.dtb.bak /boot/dtb/...nv-super.dtb &amp;&amp; sudo reboot</code></p></blockquote><h3 id="opencv">opencv</h3><p><a href="https://jishuzhan.net/article/2013776823067918337">https://jishuzhan.net/article/2013776823067918337</a></p><p>需要手动编译OpenCV 以支持 CUDA 加速</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_37110d1b7d09855223ee5c4fee539f99.png" alt=""></p><p>一键安装脚本，修改<code>version</code> (OpenCV 版本)，<code>ARCH_BIN</code> (CUDA 算力架构)，<code>PYTHON_VERSION_NUM</code> (Python 版本)</p><table><thead><tr><th><strong>Jetson 设备型号</strong></th><th><strong>架构代号</strong></th><th><strong>ARCH_BIN 修改值</strong></th><th><strong>备注</strong></th></tr></thead><tbody><tr><td><strong>Jetson AGX Orin</strong></td><td>Ampere</td><td><strong>“8.7”</strong></td><td>脚本默认值</td></tr><tr><td><strong>Jetson Orin NX</strong></td><td>Ampere</td><td><strong>“8.7”</strong></td><td>与 AGX Orin 相同</td></tr><tr><td><strong>Jetson Orin Nano</strong></td><td>Ampere</td><td><strong>“8.7”</strong></td><td>与 AGX Orin 相同</td></tr><tr><td><strong>Jetson AGX Xavier</strong></td><td>Volta</td><td><strong>“7.2”</strong></td><td></td></tr><tr><td><strong>Jetson Xavier NX</strong></td><td>Volta</td><td><strong>“7.2”</strong></td><td></td></tr><tr><td><strong>Jetson TX2</strong></td><td>Pascal</td><td><strong>“6.2”</strong></td><td></td></tr><tr><td><strong>Jetson Nano (B01)</strong></td><td>Maxwell</td><td><strong>“5.3”</strong></td><td>老款 Nano 请填这个</td></tr></tbody></table><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Copyright (c) 2024.</span></span><br><span class="line"><span class="comment"># Modified for Jetson Orin NX (CUDA Arch 8.7)</span></span><br><span class="line"><span class="comment"># Based on instructions for OpenCV 4.10.0</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ================= 配置区域 (Config Area) =================</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. OpenCV 版本</span></span><br><span class="line">version=<span class="string">&quot;4.10.0&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. CUDA 算力架构 (重要!)</span></span><br><span class="line"><span class="comment"># Orin 系列 (AGX Orin, Orin NX, Orin Nano) -&gt; 8.7</span></span><br><span class="line"><span class="comment"># Xavier 系列 -&gt; 7.2</span></span><br><span class="line"><span class="comment"># Nano/TX1 -&gt; 5.3</span></span><br><span class="line">ARCH_BIN=<span class="string">&quot;8.7&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. Python 版本 (根据你的系统修改)</span></span><br><span class="line"><span class="comment"># 运行 &#x27;python3 --version&#x27; 查看</span></span><br><span class="line"><span class="comment"># Jetpack 5 (Ubuntu 20.04) 通常是 3.8</span></span><br><span class="line"><span class="comment"># Jetpack 6 (Ubuntu 22.04) 通常是 3.10</span></span><br><span class="line">PYTHON_VERSION_NUM=<span class="string">&quot;3.10&quot;</span> </span><br><span class="line"></span><br><span class="line"><span class="comment"># 工作目录</span></span><br><span class="line">folder=<span class="string">&quot;workspace&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># =========================================================</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">set</span> -e</span><br><span class="line"></span><br><span class="line"><span class="comment"># ---------------------------------------------------------</span></span><br><span class="line"><span class="comment"># 0. 清理旧版本交互</span></span><br><span class="line"><span class="comment"># ---------------------------------------------------------</span></span><br><span class="line"><span class="keyword">for</span> (( ; ; ))</span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Do you want to remove the default OpenCV (yes/no)?&quot;</span></span><br><span class="line">    <span class="built_in">read</span> rm_old</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> [ <span class="string">&quot;<span class="variable">$rm_old</span>&quot;</span> = <span class="string">&quot;yes&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;** Remove other OpenCV first&quot;</span></span><br><span class="line">        sudo apt -y purge *libopencv*</span><br><span class="line">        <span class="built_in">break</span></span><br><span class="line">    <span class="keyword">elif</span> [ <span class="string">&quot;<span class="variable">$rm_old</span>&quot;</span> = <span class="string">&quot;no&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">break</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Install requirement (1/4)&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line">sudo apt-get update</span><br><span class="line"><span class="comment"># 安装基础编译工具</span></span><br><span class="line">sudo apt-get install -y build-essential cmake git pkg-config unzip curl</span><br><span class="line"></span><br><span class="line"><span class="comment"># 图像/视频编解码库</span></span><br><span class="line">sudo apt-get install -y libavcodec-dev libavformat-dev libswscale-dev</span><br><span class="line">sudo apt-get install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev</span><br><span class="line">sudo apt-get install -y libv4l-dev v4l-utils qv4l2</span><br><span class="line"></span><br><span class="line"><span class="comment"># 图片格式库</span></span><br><span class="line">sudo apt-get install -y libjpeg-dev libpng-dev libtiff-dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># TBB 并行库 (兼容处理: Ubuntu 22.04 使用 libtbb12, 旧版使用 libtbb2)</span></span><br><span class="line">sudo apt-get install -y libtbb-dev</span><br><span class="line"><span class="keyword">if</span> apt-cache search --names-only <span class="string">&#x27;^libtbb2$&#x27;</span> | grep -q libtbb2; <span class="keyword">then</span></span><br><span class="line">    sudo apt-get install -y libtbb2</span><br><span class="line"><span class="keyword">elif</span> apt-cache search --names-only <span class="string">&#x27;^libtbb12$&#x27;</span> | grep -q libtbb12; <span class="keyword">then</span></span><br><span class="line">    sudo apt-get install -y libtbb12</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># GUI 支持</span></span><br><span class="line">sudo apt-get install -y libgtk2.0-dev </span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Download opencv <span class="variable">$&#123;version&#125;</span> (2/4)&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$folder</span></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$&#123;folder&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 下载 OpenCV 源码 (增加防重复下载判断)</span></span><br><span class="line"><span class="keyword">if</span> [ ! -f <span class="string">&quot;opencv-<span class="variable">$&#123;version&#125;</span>.zip&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Downloading OpenCV source...&quot;</span></span><br><span class="line">    curl -L https://github.com/opencv/opencv/archive/<span class="variable">$&#123;version&#125;</span>.zip -o opencv-<span class="variable">$&#123;version&#125;</span>.zip</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;opencv-<span class="variable">$&#123;version&#125;</span>.zip already exists.&quot;</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 下载 Contrib 源码</span></span><br><span class="line"><span class="keyword">if</span> [ ! -f <span class="string">&quot;opencv_contrib-<span class="variable">$&#123;version&#125;</span>.zip&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Downloading OpenCV Contrib source...&quot;</span></span><br><span class="line">    curl -L https://github.com/opencv/opencv_contrib/archive/<span class="variable">$&#123;version&#125;</span>.zip -o opencv_contrib-<span class="variable">$&#123;version&#125;</span>.zip</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;opencv_contrib-<span class="variable">$&#123;version&#125;</span>.zip already exists.&quot;</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 解压</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Unzipping...&quot;</span></span><br><span class="line">unzip -o opencv-<span class="variable">$&#123;version&#125;</span>.zip &gt; /dev/null</span><br><span class="line">unzip -o opencv_contrib-<span class="variable">$&#123;version&#125;</span>.zip &gt; /dev/null</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理压缩包(可选，这里保留以免重试时需要重新下载，如果空间不足可取消注释)</span></span><br><span class="line"><span class="comment"># rm opencv-$&#123;version&#125;.zip opencv_contrib-$&#123;version&#125;.zip</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> opencv-<span class="variable">$&#123;version&#125;</span>/</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Build opencv <span class="variable">$&#123;version&#125;</span> (3/4)&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">mkdir</span> -p release</span><br><span class="line"><span class="built_in">cd</span> release/</span><br><span class="line"></span><br><span class="line"><span class="comment"># CMake 配置</span></span><br><span class="line"><span class="comment"># 注意：Orin NX 使用 8.7 架构</span></span><br><span class="line">cmake -D WITH_CUDA=ON \</span><br><span class="line">      -D WITH_CUDNN=ON \</span><br><span class="line">      -D CUDA_ARCH_BIN=<span class="string">&quot;<span class="variable">$&#123;ARCH_BIN&#125;</span>&quot;</span> \</span><br><span class="line">      -D CUDA_ARCH_PTX=<span class="string">&quot;&quot;</span> \</span><br><span class="line">      -D OPENCV_GENERATE_PKGCONFIG=ON \</span><br><span class="line">      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-<span class="variable">$&#123;version&#125;</span>/modules \</span><br><span class="line">      -D WITH_GSTREAMER=ON \</span><br><span class="line">      -D WITH_LIBV4L=ON \</span><br><span class="line">      -D BUILD_opencv_python3=ON \</span><br><span class="line">      -D BUILD_opencv_gapi=OFF \</span><br><span class="line">      -D BUILD_TESTS=OFF \</span><br><span class="line">      -D BUILD_PERF_TESTS=OFF \</span><br><span class="line">      -D BUILD_EXAMPLES=OFF \</span><br><span class="line">      -D CMAKE_BUILD_TYPE=RELEASE \</span><br><span class="line">      -D CMAKE_INSTALL_PREFIX=/usr/local ..</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Compiling... This may take a while.&quot;</span></span><br><span class="line">make -j$(<span class="built_in">nproc</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Install opencv <span class="variable">$&#123;version&#125;</span> (4/4)&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line">sudo make install</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置环境变量到 .bashrc</span></span><br><span class="line"><span class="comment"># 判断是否已经存在，避免重复写入</span></span><br><span class="line"><span class="keyword">if</span> ! grep -q <span class="string">&quot;export LD_LIBRARY_PATH=/usr/local/lib&quot;</span> ~/.bashrc; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&#x27;export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH&#x27;</span> &gt;&gt; ~/.bashrc</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 根据 Python 版本路径配置 PYTHONPATH</span></span><br><span class="line">SITE_PACKAGES_PATH=<span class="string">&quot;/usr/local/lib/python<span class="variable">$&#123;PYTHON_VERSION_NUM&#125;</span>/site-packages&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ! grep -q <span class="string">&quot;export PYTHONPATH=<span class="variable">$&#123;SITE_PACKAGES_PATH&#125;</span>&quot;</span> ~/.bashrc; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;export PYTHONPATH=<span class="variable">$&#123;SITE_PACKAGES_PATH&#125;</span>/:\$PYTHONPATH&quot;</span> &gt;&gt; ~/.bashrc</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 提示用户手动 source</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;------------------------------------&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Install opencv <span class="variable">$&#123;version&#125;</span> successfully&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** IMPORTANT: Please run the following command to apply changes:&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;   source ~/.bashrc&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;** Bye :)&quot;</span></span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_24/image_aa0ca5227789878bd1252910e7d90f5f.png" alt=""></p><h3 id="MVS">MVS</h3><p>到下载页面下载：</p><p><a href="https://www.hikrobotics.com/cn/machinevision/service/download/?module=0">海康机器人-机器视觉-下载中心</a></p><p>机器视觉工业相机SDK Runtime组件包（Linux）V4.7.0</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/04_01/image_d8e0f39b21c35a0b69b06d1c26b82171.png" alt=""></p><p>MvCamCtrlSDK_Runtime-4.7.0_aarch64_20251113.deb</p><h3 id="TensorRT">TensorRT</h3><p>添加工具软链接</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="built_in">ln</span> -s /usr/src/tensorrt/bin/trtexec /usr/local/bin/trtexec</span><br></pre></td></tr></table></figure><h3 id="cuda-toolkit">cuda-toolkit</h3><p>安装</p><p><code>sudo apt-get install cuda-toolkit</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/04_04/image_0559d6242dc0a41f0fae36228f50a707.png" alt=""></p><p>在~/.bashrc文件末尾添加</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> LD_LIBRARY_PATH=<span class="variable">$LD_LIBRARY_PATH</span>:/usr/local/cuda-12.6/lib64</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:/usr/local/cuda-12.6/bin</span><br><span class="line"><span class="built_in">export</span> CUDA_HOME=<span class="variable">$CUDA_HOME</span>:/usr/local/cuda-12.6</span><br></pre></td></tr></table></figure><h2 id="使用检索">使用检索</h2><h3 id="trtexec使用">trtexec使用</h3><p>pt导出onnx(动态纬度)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yolo <span class="built_in">export</span> model=best.pt format=onnx dynamic=True opset=12</span><br></pre></td></tr></table></figure><p>转换模型</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">trtexec \</span><br><span class="line">--onnx=best.onnx \</span><br><span class="line">--saveEngine=yolo11n.engine \</span><br><span class="line">--fp16 \</span><br><span class="line">--minShapes=images:1x3x640x640 \</span><br><span class="line">--optShapes=images:1x3x640x640 \</span><br><span class="line">--maxShapes=images:1x3x640x640 \</span><br><span class="line">--memPoolSize=workspace:4096 \</span><br><span class="line">--verbose</span><br></pre></td></tr></table></figure><p>导出batch2模型</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">trtexec \</span><br><span class="line">--onnx=best.onnx \</span><br><span class="line">--saveEngine=yolo11n_batch2.engine \</span><br><span class="line">--fp16 \</span><br><span class="line">--minShapes=images:2x3x640x640 \</span><br><span class="line">--optShapes=images:2x3x640x640 \</span><br><span class="line">--maxShapes=images:2x3x640x640 \</span><br><span class="line">--verbose</span><br></pre></td></tr></table></figure><h3 id="MVS使用">MVS使用</h3><h2 id="开始">开始</h2><h3 id="DLA推理">DLA推理</h3><p>纯 DLA 推理 yolo26 模型时，两个 attention 模块（<code>model.10</code> 和 <code>model.22</code>）在 DLA 上耗时极高，<br>nsys profiling 显示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ForeignNode[2] (model.10 attention body): 4.56ms  28.0%  ← 瓶颈</span><br><span class="line">ForeignNode[4] (model.22 attention body): 4.59ms  28.2%  ← 瓶颈</span><br><span class="line">两者合计: 9.15ms = 56% of total 16.26ms</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">model.0-model.9   : Backbone (Conv + C3k2 blocks)      [DLA 兼容]</span><br><span class="line">model.10           : C2PSA block (含 PSA attention)      [DLA 兼容但慢]</span><br><span class="line">model.11-model.21  : Neck (SPPF + Upsample + C3k2)     [DLA 兼容]</span><br><span class="line">model.22           : C2PSA block (含 PSA attention)      [DLA 兼容但慢]</span><br><span class="line">model.23           : Detection Head (Conv + Concat + decode) [DLA 兼容]</span><br></pre></td></tr></table></figure><p>模型结构</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;Layers&quot;: [</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.0/conv/Conv + PWN(PWN(/model.0/act/Sigmoid), PWN(/model.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.0/conv/Conv + PWN(PWN(/model.0/act/Sigmoid), PWN(/model.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.1/conv/Conv + PWN(PWN(/model.1/act/Sigmoid), PWN(/model.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.2/cv1/conv/Conv + PWN(PWN(/model.2/cv1/act/Sigmoid), PWN(/model.2/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.2/Split_1&quot;,</span><br><span class="line">    &quot;/model.2/m.0/cv1/conv/Conv + PWN(PWN(/model.2/m.0/cv1/act/Sigmoid), PWN(/model.2/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.2/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.2/m.0/cv2/act/Sigmoid), PWN(/model.2/m.0/cv2/act/Mul)), PWN(/model.2/m.0/Add))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 1 to /model.2/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.2/m.0/cv2/act/Sigmoid), PWN(/model.2/m.0/cv2/act/Mul)), PWN(/model.2/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.2/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.2/m.0/cv2/act/Sigmoid), PWN(/model.2/m.0/cv2/act/Mul)), PWN(/model.2/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.2/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.2/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.2/m.0/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.2/cv2/conv/Conv + PWN(PWN(/model.2/cv2/act/Sigmoid), PWN(/model.2/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.3/conv/Conv + PWN(PWN(/model.3/act/Sigmoid), PWN(/model.3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.4/cv1/conv/Conv + PWN(PWN(/model.4/cv1/act/Sigmoid), PWN(/model.4/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.4/Split_4&quot;,</span><br><span class="line">    &quot;/model.4/m.0/cv1/conv/Conv + PWN(PWN(/model.4/m.0/cv1/act/Sigmoid), PWN(/model.4/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.4/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.4/m.0/cv2/act/Sigmoid), PWN(/model.4/m.0/cv2/act/Mul)), PWN(/model.4/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.4/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.4/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.4/m.0/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.4/cv2/conv/Conv + PWN(PWN(/model.4/cv2/act/Sigmoid), PWN(/model.4/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.5/conv/Conv + PWN(PWN(/model.5/act/Sigmoid), PWN(/model.5/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/cv1/conv/Conv + PWN(PWN(/model.6/cv1/act/Sigmoid), PWN(/model.6/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/cv1/conv/Conv + PWN(PWN(/model.6/m.0/cv1/act/Sigmoid), PWN(/model.6/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/m/m.0/cv1/conv/Conv + PWN(PWN(/model.6/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.6/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/m/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.6/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.6/m.0/m/m.0/cv2/act/Mul)), PWN(/model.6/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/m/m.1/cv1/conv/Conv + PWN(PWN(/model.6/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.6/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/m/m.1/cv2/conv/Conv + PWN(PWN(PWN(/model.6/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.6/m.0/m/m.1/cv2/act/Mul)), PWN(/model.6/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/cv2/conv/Conv + PWN(PWN(/model.6/m.0/cv2/act/Sigmoid), PWN(/model.6/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/m.0/m/m.1/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.6/m.0/cv3/conv/Conv + PWN(PWN(/model.6/m.0/cv3/act/Sigmoid), PWN(/model.6/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.6/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.6/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.6/cv2/conv/Conv + PWN(PWN(/model.6/cv2/act/Sigmoid), PWN(/model.6/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.7/conv/Conv + PWN(PWN(/model.7/act/Sigmoid), PWN(/model.7/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/cv1/conv/Conv + PWN(PWN(/model.8/cv1/act/Sigmoid), PWN(/model.8/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/cv1/conv/Conv + PWN(PWN(/model.8/m.0/cv1/act/Sigmoid), PWN(/model.8/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/m/m.0/cv1/conv/Conv + PWN(PWN(/model.8/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.8/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/m/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.8/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.8/m.0/m/m.0/cv2/act/Mul)), PWN(/model.8/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/m/m.1/cv1/conv/Conv + PWN(PWN(/model.8/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.8/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/m/m.1/cv2/conv/Conv + PWN(PWN(PWN(/model.8/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.8/m.0/m/m.1/cv2/act/Mul)), PWN(/model.8/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/cv2/conv/Conv + PWN(PWN(/model.8/m.0/cv2/act/Sigmoid), PWN(/model.8/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/m.0/m/m.1/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.8/m.0/cv3/conv/Conv + PWN(PWN(/model.8/m.0/cv3/act/Sigmoid), PWN(/model.8/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.8/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.8/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.8/cv2/conv/Conv + PWN(PWN(/model.8/cv2/act/Sigmoid), PWN(/model.8/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.9/cv1/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.9/m/MaxPool&quot;,</span><br><span class="line">    &quot;/model.9/m_1/MaxPool&quot;,</span><br><span class="line">    &quot;/model.9/m_2/MaxPool&quot;,</span><br><span class="line">    &quot;/model.9/cv1/conv/Conv_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.9/m/MaxPool_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.9/m_1/MaxPool_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.9/cv2/conv/Conv + PWN(PWN(/model.9/cv2/act/Sigmoid), PWN(/model.9/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.10/cv1/conv/Conv + PWN(PWN(/model.10/cv1/act/Sigmoid), PWN(/model.10/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.10/Split_13&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/qkv/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Reshape&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Split&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Split_16&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/MatMul&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Softmax&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Split_18&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Reshape_2&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/MatMul_1&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/Reshape_1&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/pe/conv/Conv + /model.10/m/m.0/attn/Add&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.10/m/m.0/attn/proj/conv/Conv + /model.10/m/m.0/Add&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/attn/proj/conv/Conv + /model.10/m/m.0/Add&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/ffn/ffn.0/conv/Conv + PWN(PWN(/model.10/m/m.0/ffn/ffn.0/act/Sigmoid), PWN(/model.10/m/m.0/ffn/ffn.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/ffn/ffn.1/conv/Conv + /model.10/m/m.0/Add_1&quot;,</span><br><span class="line">    &quot;/model.10/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.10/m/m.0/Add_1_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.10/cv2/conv/Conv + PWN(PWN(/model.10/cv2/act/Sigmoid), PWN(/model.10/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.11/Resize&quot;,</span><br><span class="line">    &quot;/model.11/Resize_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.13/cv1/conv/Conv + PWN(PWN(/model.13/cv1/act/Sigmoid), PWN(/model.13/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/cv1/conv/Conv + PWN(PWN(/model.13/m.0/cv1/act/Sigmoid), PWN(/model.13/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/m/m.0/cv1/conv/Conv + PWN(PWN(/model.13/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.13/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/m/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.13/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.13/m.0/m/m.0/cv2/act/Mul)), PWN(/model.13/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/m/m.1/cv1/conv/Conv + PWN(PWN(/model.13/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.13/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/m/m.1/cv2/conv/Conv + PWN(PWN(PWN(/model.13/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.13/m.0/m/m.1/cv2/act/Mul)), PWN(/model.13/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/cv2/conv/Conv + PWN(PWN(/model.13/m.0/cv2/act/Sigmoid), PWN(/model.13/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/m.0/m/m.1/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.13/m.0/cv3/conv/Conv + PWN(PWN(/model.13/m.0/cv3/act/Sigmoid), PWN(/model.13/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.13/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.13/cv2/conv/Conv + PWN(PWN(/model.13/cv2/act/Sigmoid), PWN(/model.13/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.14/Resize&quot;,</span><br><span class="line">    &quot;/model.14/Resize_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.16/cv1/conv/Conv + PWN(PWN(/model.16/cv1/act/Sigmoid), PWN(/model.16/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.16/m.0/cv1/conv/Conv + PWN(PWN(/model.16/m.0/cv1/act/Sigmoid), PWN(/model.16/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Output Tensor 0 to /model.16/m.0/cv1/conv/Conv + PWN(PWN(/model.16/m.0/cv1/act/Sigmoid), PWN(/model.16/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.16/m.0/m/m.0/cv1/conv/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to PWN(PWN(/model.16/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.16/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.16/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.16/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.16/m.0/m/m.0/cv2/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.16/m.0/m/m.0/cv2/conv/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to PWN(PWN(PWN(/model.16/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.0/cv2/act/Mul)), PWN(/model.16/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 1 to PWN(PWN(PWN(/model.16/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.0/cv2/act/Mul)), PWN(/model.16/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;PWN(PWN(PWN(/model.16/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.0/cv2/act/Mul)), PWN(/model.16/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.16/m.0/m/m.1/cv1/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.16/m.0/m/m.1/cv1/conv/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to PWN(PWN(/model.16/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.16/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.16/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.16/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.16/m.0/m/m.1/cv2/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.16/m.0/m/m.1/cv2/conv/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to PWN(PWN(PWN(/model.16/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.1/cv2/act/Mul)), PWN(/model.16/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;PWN(PWN(PWN(/model.16/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.1/cv2/act/Mul)), PWN(/model.16/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Output Tensor 0 to PWN(PWN(PWN(/model.16/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.16/m.0/m/m.1/cv2/act/Mul)), PWN(/model.16/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.16/m.0/cv2/conv/Conv + PWN(PWN(/model.16/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.16/m.0/cv2/conv/Conv + PWN(PWN(/model.16/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Output Tensor 0 to /model.16/m.0/cv2/conv/Conv + PWN(PWN(/model.16/m.0/cv2/act/Sigmoid), PWN(/model.16/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.16/m.0/cv3/conv/Conv + PWN(PWN(/model.16/m.0/cv3/act/Sigmoid), PWN(/model.16/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.16/m.0/cv3/conv/Conv + PWN(PWN(/model.16/m.0/cv3/act/Sigmoid), PWN(/model.16/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.16/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.16/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.16/cv2/conv/Conv + PWN(PWN(/model.16/cv2/act/Sigmoid), PWN(/model.16/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.17/conv/Conv + PWN(PWN(/model.17/act/Sigmoid), PWN(/model.17/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.13/cv2/act/Mul_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.19/cv1/conv/Conv + PWN(PWN(/model.19/cv1/act/Sigmoid), PWN(/model.19/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/cv1/conv/Conv + PWN(PWN(/model.19/m.0/cv1/act/Sigmoid), PWN(/model.19/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/m/m.0/cv1/conv/Conv + PWN(PWN(/model.19/m.0/m/m.0/cv1/act/Sigmoid), PWN(/model.19/m.0/m/m.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/m/m.0/cv2/conv/Conv + PWN(PWN(PWN(/model.19/m.0/m/m.0/cv2/act/Sigmoid), PWN(/model.19/m.0/m/m.0/cv2/act/Mul)), PWN(/model.19/m.0/m/m.0/Add))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/m/m.1/cv1/conv/Conv + PWN(PWN(/model.19/m.0/m/m.1/cv1/act/Sigmoid), PWN(/model.19/m.0/m/m.1/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/m/m.1/cv2/conv/Conv + PWN(PWN(PWN(/model.19/m.0/m/m.1/cv2/act/Sigmoid), PWN(/model.19/m.0/m/m.1/cv2/act/Mul)), PWN(/model.19/m.0/m/m.1/Add))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/cv2/conv/Conv + PWN(PWN(/model.19/m.0/cv2/act/Sigmoid), PWN(/model.19/m.0/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/m.0/m/m.1/Add_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.19/m.0/cv3/conv/Conv + PWN(PWN(/model.19/m.0/cv3/act/Sigmoid), PWN(/model.19/m.0/cv3/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.19/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.19/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.19/cv2/conv/Conv + PWN(PWN(/model.19/cv2/act/Sigmoid), PWN(/model.19/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.20/conv/Conv + PWN(PWN(/model.20/act/Sigmoid), PWN(/model.20/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.10/cv2/act/Mul_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.22/cv1/conv/Conv + PWN(PWN(/model.22/cv1/act/Sigmoid), PWN(/model.22/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.22/Split_34&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.0/cv1/conv/Conv + PWN(PWN(/model.22/m.0/m.0.0/cv1/act/Sigmoid), PWN(/model.22/m.0/m.0.0/cv1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.0/cv2/conv/Conv + PWN(PWN(PWN(/model.22/m.0/m.0.0/cv2/act/Sigmoid), PWN(/model.22/m.0/m.0.0/cv2/act/Mul)), PWN(/model.22/m.0/m.0.0/Add))&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/qkv/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Reshape&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Split&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Split_38&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/MatMul&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Softmax&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Split_40&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Reshape_2&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/MatMul_1&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/Reshape_1&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/pe/conv/Conv + /model.22/m.0/m.0.1/attn/Add&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.22/m.0/m.0.1/attn/proj/conv/Conv + /model.22/m.0/m.0.1/Add&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/attn/proj/conv/Conv + /model.22/m.0/m.0.1/Add&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/ffn/ffn.0/conv/Conv + PWN(PWN(/model.22/m.0/m.0.1/ffn/ffn.0/act/Sigmoid), PWN(/model.22/m.0/m.0.1/ffn/ffn.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/ffn/ffn.1/conv/Conv + /model.22/m.0/m.0.1/Add_1&quot;,</span><br><span class="line">    &quot;/model.22/Split_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.22/Split_output_1 copy&quot;,</span><br><span class="line">    &quot;/model.22/m.0/m.0.1/Add_1_output_0 copy&quot;,</span><br><span class="line">    &quot;/model.22/cv2/conv/Conv + PWN(PWN(/model.22/cv2/act/Sigmoid), PWN(/model.22/cv2/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv2.2/cv2.2.0/conv/Conv + PWN(PWN(/model.23/cv2.2/cv2.2.0/act/Sigmoid), PWN(/model.23/cv2.2/cv2.2.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv2.2/cv2.2.1/conv/Conv&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.23/cv2.2/cv2.2.1/act/Sigmoid), PWN(/model.23/cv2.2/cv2.2.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv2.2/cv2.2.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/cv3.2/cv3.2.0/cv3.2.0.0/conv/Conv + PWN(PWN(/model.23/cv3.2/cv3.2.0/cv3.2.0.0/act/Sigmoid), PWN(/model.23/cv3.2/cv3.2.0/cv3.2.0.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.2/cv3.2.0/cv3.2.0.1/conv/Conv + PWN(PWN(/model.23/cv3.2/cv3.2.0/cv3.2.0.1/act/Sigmoid), PWN(/model.23/cv3.2/cv3.2.0/cv3.2.0.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.2/cv3.2.1/cv3.2.1.0/conv/Conv + PWN(PWN(/model.23/cv3.2/cv3.2.1/cv3.2.1.0/act/Sigmoid), PWN(/model.23/cv3.2/cv3.2.1/cv3.2.1.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.2/cv3.2.1/cv3.2.1.1/conv/Conv + PWN(PWN(/model.23/cv3.2/cv3.2.1/cv3.2.1.1/act/Sigmoid), PWN(/model.23/cv3.2/cv3.2.1/cv3.2.1.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.2/cv3.2.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/Reshape_2&quot;,</span><br><span class="line">    &quot;/model.23/Reshape_2_copy_output&quot;,</span><br><span class="line">    &quot;/model.23/cv2.1/cv2.1.0/conv/Conv + PWN(PWN(/model.23/cv2.1/cv2.1.0/act/Sigmoid), PWN(/model.23/cv2.1/cv2.1.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv2.1/cv2.1.1/conv/Conv&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.23/cv2.1/cv2.1.1/act/Sigmoid), PWN(/model.23/cv2.1/cv2.1.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv2.1/cv2.1.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/cv3.1/cv3.1.0/cv3.1.0.0/conv/Conv + PWN(PWN(/model.23/cv3.1/cv3.1.0/cv3.1.0.0/act/Sigmoid), PWN(/model.23/cv3.1/cv3.1.0/cv3.1.0.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.1/cv3.1.0/cv3.1.0.1/conv/Conv + PWN(PWN(/model.23/cv3.1/cv3.1.0/cv3.1.0.1/act/Sigmoid), PWN(/model.23/cv3.1/cv3.1.0/cv3.1.0.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.1/cv3.1.1/cv3.1.1.0/conv/Conv + PWN(PWN(/model.23/cv3.1/cv3.1.1/cv3.1.1.0/act/Sigmoid), PWN(/model.23/cv3.1/cv3.1.1/cv3.1.1.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.1/cv3.1.1/cv3.1.1.1/conv/Conv + PWN(PWN(/model.23/cv3.1/cv3.1.1/cv3.1.1.1/act/Sigmoid), PWN(/model.23/cv3.1/cv3.1.1/cv3.1.1.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.1/cv3.1.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/Reshape_1&quot;,</span><br><span class="line">    &quot;/model.23/Reshape_1_copy_output&quot;,</span><br><span class="line">    &quot;/model.23/cv2.0/cv2.0.0/conv/Conv + PWN(PWN(/model.23/cv2.0/cv2.0.0/act/Sigmoid), PWN(/model.23/cv2.0/cv2.0.0/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.23/cv2.0/cv2.0.1/conv/Conv&quot;,</span><br><span class="line">    &quot;/model.23/cv2.0/cv2.0.1/conv/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to PWN(PWN(/model.23/cv2.0/cv2.0.1/act/Sigmoid), PWN(/model.23/cv2.0/cv2.0.1/act/Mul))&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.23/cv2.0/cv2.0.1/act/Sigmoid), PWN(/model.23/cv2.0/cv2.0.1/act/Mul))&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Input Tensor 0 to /model.23/cv2.0/cv2.0.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/cv2.0/cv2.0.2/Conv&quot;,</span><br><span class="line">    &quot;Reformatting CopyNode for Output Tensor 0 to /model.23/cv2.0/cv2.0.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/cv3.0/cv3.0.0/cv3.0.0.0/conv/Conv + PWN(PWN(/model.23/cv3.0/cv3.0.0/cv3.0.0.0/act/Sigmoid), PWN(/model.23/cv3.0/cv3.0.0/cv3.0.0.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.0/cv3.0.0/cv3.0.0.1/conv/Conv + PWN(PWN(/model.23/cv3.0/cv3.0.0/cv3.0.0.1/act/Sigmoid), PWN(/model.23/cv3.0/cv3.0.0/cv3.0.0.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.0/cv3.0.1/cv3.0.1.0/conv/Conv + PWN(PWN(/model.23/cv3.0/cv3.0.1/cv3.0.1.0/act/Sigmoid), PWN(/model.23/cv3.0/cv3.0.1/cv3.0.1.0/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.0/cv3.0.1/cv3.0.1.1/conv/Conv + PWN(PWN(/model.23/cv3.0/cv3.0.1/cv3.0.1.1/act/Sigmoid), PWN(/model.23/cv3.0/cv3.0.1/cv3.0.1.1/act/Mul))&quot;,</span><br><span class="line">    &quot;/model.23/cv3.0/cv3.0.2/Conv&quot;,</span><br><span class="line">    &quot;/model.23/Reshape&quot;,</span><br><span class="line">    &quot;/model.23/Reshape_copy_output&quot;,</span><br><span class="line">    &quot;PWN(/model.23/Sigmoid)&quot;,</span><br><span class="line">    &quot;/model.23/Constant_12_output_0 + ONNXTRT_Broadcast_117&quot;,</span><br><span class="line">    &quot;/model.23/Constant_10_output_0&quot;,</span><br><span class="line">    &quot;PWN(/model.23/Add_1)&quot;,</span><br><span class="line">    &quot;/model.23/Constant_9_output_0&quot;,</span><br><span class="line">    &quot;PWN(/model.23/Sub)&quot;,</span><br><span class="line">    &quot;PWN(/model.23/Sub_1)&quot;,</span><br><span class="line">    &quot;PWN(PWN(/model.23/Add_2), PWN(/model.23/Constant_11_output_0 + ONNXTRT_Broadcast_115, PWN(/model.23/Div_1)))&quot;,</span><br><span class="line">    &quot;/model.23/Div_1_output_0 copy&quot;,</span><br><span class="line">    &quot;PWN(/model.23/Mul_2)&quot;,</span><br><span class="line">    &quot;/model.23/Mul_2_output_0 copy&quot;</span><br><span class="line">  ],</span><br><span class="line">  &quot;Bindings&quot;: [</span><br><span class="line">    &quot;images&quot;,</span><br><span class="line">    &quot;output0&quot;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Q-A">Q&amp;A</h2><h3 id="Errors-were-encountered-while-processing-nvidia-l4t-bootloader报错">Errors were encountered while processing: nvidia-l4t-bootloader报错</h3><p><a href="https://blog.csdn.net/weixin_29190169/article/details/159672010">Jetson升级踩坑实录：nvidia-l4t-bootloader报错终极解决方案（附完整命令）-CSDN博客</a></p><h3 id="Jetson-Orin-NX-性能检测工具指南">Jetson Orin NX 性能检测工具指南</h3><p>Jetson Orin NX 上可用于 TensorRT / CUDA / DLA 性能分析的核心工具：</p><table><thead><tr><th>工具</th><th>用途</th><th>安装状态</th></tr></thead><tbody><tr><td><code>nsys</code> (Nsight Systems)</td><td>GPU/DLA/CPU timeline profiling</td><td>自带 (2024.5.4)</td></tr><tr><td><code>trtexec</code></td><td>TensorRT engine benchmark &amp; layer profiling</td><td>自带 (TRT 10.3)</td></tr><tr><td><code>tegrastats</code></td><td>实时 GPU/DLA/CPU/内存/温度监控</td><td>自带</td></tr><tr><td><code>jtop</code></td><td>交互式系统资源监控</td><td>pip install jetson-stats</td></tr><tr><td><code>nvpmodel</code></td><td>功耗/性能模式切换</td><td>自带</td></tr><tr><td><code>jetson_clocks</code></td><td>锁定最高频率</td><td>自带</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<code>nvvp</code> (Visual Profiler) 在 JetPack 6.x 已废弃，由 <code>nsys</code> 替代。</p></blockquote><h4 id="1-nsys-Nsight-Systems">1. nsys (Nsight Systems)</h4><h5 id="1-1-基本用法">1.1 基本用法</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 版本确认</span></span><br><span class="line">nsys --version</span><br><span class="line"><span class="comment"># NVIDIA Nsight Systems version 2024.5.4.34-...</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 基础 profiling (应用级)</span></span><br><span class="line">nsys profile -o my_report ./my_application</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定采样选项</span></span><br><span class="line">nsys profile \</span><br><span class="line">    -t cuda,nvtx,osrt \        <span class="comment"># 追踪 CUDA, NVTX markers, OS Runtime</span></span><br><span class="line">    --duration=10 \             <span class="comment"># 采集 10 秒</span></span><br><span class="line">    --stats=<span class="literal">true</span> \              <span class="comment"># 生成统计摘要</span></span><br><span class="line">    -o profile_output \</span><br><span class="line">    ./my_application</span><br></pre></td></tr></table></figure><h5 id="1-2-TensorRT-DLA-Profiling">1.2 TensorRT + DLA Profiling</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 对 trtexec DLA engine 进行 profiling</span></span><br><span class="line">nsys profile \</span><br><span class="line">    --stats=<span class="literal">true</span> \</span><br><span class="line">    -o dla_profile \</span><br><span class="line">    /usr/src/tensorrt/bin/trtexec \</span><br><span class="line">        --loadEngine=model/yolo26_dla0_int8_640.engine \</span><br><span class="line">        --iterations=200 \</span><br><span class="line">        --warmUp=2000 \</span><br><span class="line">        --dumpProfile</span><br></pre></td></tr></table></figure><h5 id="1-3-关键输出解读">1.3 关键输出解读</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># nsys stats 输出示例:</span><br><span class="line">CUDA API Statistics:</span><br><span class="line">  Time(%)  Total Time  Calls  Average  Name</span><br><span class="line">   45.2%   234.5ms     200    1.17ms   cudaStreamSynchronize</span><br><span class="line">   22.1%   114.8ms     200    0.57ms   cudaLaunchKernel</span><br><span class="line">   ...</span><br><span class="line"></span><br><span class="line">CUDA Kernel Statistics:</span><br><span class="line">  Time(%)  Total Time  Instances  Average  Name</span><br><span class="line">   28.0%    45.6ms     200        0.23ms   ForeignNode[2]   ← DLA subgraph</span><br><span class="line">   ...</span><br></pre></td></tr></table></figure><h5 id="1-4-报告查看">1.4 报告查看</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 命令行统计</span></span><br><span class="line">nsys stats my_report.nsys-rep</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出为 JSON (便于脚本处理)</span></span><br><span class="line">nsys <span class="built_in">export</span> --<span class="built_in">type</span>=json --output=report.json my_report.nsys-rep</span><br><span class="line"></span><br><span class="line"><span class="comment"># GUI 查看 (在 Windows/Linux PC 上安装 Nsight Systems GUI)</span></span><br><span class="line"><span class="comment"># 下载: https://developer.nvidia.com/nsight-systems</span></span><br><span class="line"><span class="comment"># 从 NX 拷贝 .nsys-rep 文件到 PC 打开</span></span><br><span class="line">scp nvidia@192.168.31.56:/path/to/report.nsys-rep .</span><br></pre></td></tr></table></figure><hr><h4 id="2-trtexec">2. trtexec</h4><h5 id="2-1-Engine-构建">2.1 Engine 构建</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">TRTEXEC=/usr/src/tensorrt/bin/trtexec</span><br><span class="line"></span><br><span class="line"><span class="comment"># GPU FP16</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --saveEngine=model_gpu_fp16.engine \</span><br><span class="line">    --fp16 --memPoolSize=workspace:4096MiB</span><br><span class="line"></span><br><span class="line"><span class="comment"># GPU INT8 (需要校准数据或 PTQ)</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --saveEngine=model_gpu_int8.engine \</span><br><span class="line">    --int8 --fp16 --memPoolSize=workspace:4096MiB</span><br><span class="line"></span><br><span class="line"><span class="comment"># DLA INT8 (DLA core 0, 允许 GPU fallback)</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --saveEngine=model_dla0_int8.engine \</span><br><span class="line">    --useDLACore=0 --allowGPUFallback --int8 --fp16 \</span><br><span class="line">    --memPoolSize=workspace:4096MiB</span><br><span class="line"></span><br><span class="line"><span class="comment"># DLA-GPU Hybrid (指定层设备)</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --saveEngine=model_hybrid.engine \</span><br><span class="line">    --useDLACore=0 --allowGPUFallback --int8 --fp16 \</span><br><span class="line">    --memPoolSize=workspace:4096MiB \</span><br><span class="line">    --layerDeviceTypes=<span class="string">&quot;/model.10/m/m.0/attn/MatMul:GPU,/model.10/m/m.0/attn/Softmax:GPU&quot;</span></span><br></pre></td></tr></table></figure><h5 id="2-2-Engine-Benchmark">2.2 Engine Benchmark</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 基本推理测试</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --loadEngine=model.engine --iterations=500 --warmUp=3000</span><br><span class="line"></span><br><span class="line"><span class="comment"># 带 layer profiling 的详细测试</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --loadEngine=model.engine --iterations=200 \</span><br><span class="line">    --dumpProfile --exportProfile=profile.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关键输出指标:</span></span><br><span class="line"><span class="comment">#   Throughput: xxx qps          ← 吞吐量</span></span><br><span class="line"><span class="comment">#   GPU Compute Time: mean=x.xxms  ← 单帧 GPU 计算时间</span></span><br><span class="line"><span class="comment">#   Total Host Walltime: x.xxms    ← 总延迟(含 H2D/D2H)</span></span><br></pre></td></tr></table></figure><h5 id="2-3-Layer-信息导出">2.3 Layer 信息导出</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 导出层级信息 (JSON)</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --useDLACore=0 --allowGPUFallback --int8 --fp16 \</span><br><span class="line">    --memPoolSize=workspace:4096MiB \</span><br><span class="line">    --dumpLayerInfo --exportLayerInfo=layers.json --skipInference</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出层级 timing profile</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --loadEngine=model.engine --iterations=100 \</span><br><span class="line">    --dumpProfile --exportProfile=timing.json</span><br></pre></td></tr></table></figure><h5 id="2-4-DLA-GPU-Hybrid-层控制">2.4 DLA-GPU Hybrid 层控制</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># --layerDeviceTypes 语法: &quot;layerName:GPU&quot; 或 &quot;layerName:DLA&quot;</span></span><br><span class="line"><span class="comment"># 多层用逗号分隔</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例: 将注意力层强制到 GPU</span></span><br><span class="line"><span class="variable">$TRTEXEC</span> --onnx=model.onnx --useDLACore=0 --allowGPUFallback --int8 --fp16 \</span><br><span class="line">    --layerDeviceTypes=<span class="string">&quot;/model.10/m/m.0/attn/qkv/conv/Conv:GPU,\</span></span><br><span class="line"><span class="string">/model.10/m/m.0/attn/Split:GPU,\</span></span><br><span class="line"><span class="string">/model.10/m/m.0/attn/Transpose:GPU,\</span></span><br><span class="line"><span class="string">/model.10/m/m.0/attn/MatMul:GPU,\</span></span><br><span class="line"><span class="string">/model.10/m/m.0/attn/Softmax:GPU&quot;</span> \</span><br><span class="line">    --saveEngine=hybrid.engine</span><br></pre></td></tr></table></figure><hr><h4 id="3-tegrastats">3. tegrastats</h4><h5 id="3-1-基本用法">3.1 基本用法</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 实时监控 (1 秒刷新)</span></span><br><span class="line">tegrastats</span><br><span class="line"></span><br><span class="line"><span class="comment"># 自定义刷新间隔 (毫秒)</span></span><br><span class="line">tegrastats --interval 500</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出到文件</span></span><br><span class="line">tegrastats --interval 1000 --logfile /tmp/tegra_log.txt &amp;</span><br></pre></td></tr></table></figure><h5 id="3-2-输出字段说明">3.2 输出字段说明</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">RAM 6543/15823MB   ← 内存使用/总量</span><br><span class="line">GR3D_FREQ 76%     ← GPU 利用率</span><br><span class="line">NVDLA0_FREQ 100%  ← DLA0 利用率</span><br><span class="line">NVDLA1_FREQ 85%   ← DLA1 利用率</span><br><span class="line">CPU [20%@2201]     ← CPU 使用率@频率(MHz)</span><br><span class="line">tj: 52C            ← 芯片结温(Thermal Junction)</span><br><span class="line">VDD_CPU_GPU_CV 4500mW  ← CPU/GPU/CV 功耗</span><br></pre></td></tr></table></figure><hr><h4 id="4-nvpmodel-jetson-clocks">4. nvpmodel &amp; jetson_clocks</h4><h5 id="4-1-性能模式">4.1 性能模式</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看当前模式</span></span><br><span class="line">nvpmodel -q</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置为最高性能 (MAXN_SUPER for Orin NX)</span></span><br><span class="line">sudo nvpmodel -m 0</span><br><span class="line"></span><br><span class="line"><span class="comment"># 可用模式查看</span></span><br><span class="line">nvpmodel -p --verbose</span><br></pre></td></tr></table></figure><h5 id="4-2-频率锁定">4.2 频率锁定</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 锁定所有时钟到最高频率 (benchmark 必须)</span></span><br><span class="line">sudo jetson_clocks</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看当前频率状态</span></span><br><span class="line">sudo jetson_clocks --show</span><br><span class="line"></span><br><span class="line"><span class="comment"># 恢复默认 (dynamic scaling)</span></span><br><span class="line">sudo jetson_clocks --restore</span><br></pre></td></tr></table></figure><hr><h4 id="5-VPI-Profiling">5. VPI Profiling</h4><h5 id="5-1-VPI-Python-基准测试">5.1 VPI Python 基准测试</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> vpi, numpy <span class="keyword">as</span> np, time</span><br><span class="line"></span><br><span class="line">W, H = <span class="number">1280</span>, <span class="number">720</span></span><br><span class="line">src = vpi.asimage(np.random.randint(<span class="number">0</span>, <span class="number">255</span>, (H, W), dtype=np.uint8))</span><br><span class="line">warp = vpi.WarpMap(vpi.WarpGrid((W, H)))</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> backend <span class="keyword">in</span> [vpi.Backend.CUDA, vpi.Backend.VIC]:</span><br><span class="line">    <span class="comment"># warmup</span></span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">30</span>):</span><br><span class="line">        <span class="keyword">with</span> backend:</span><br><span class="line">            out = src.remap(warp)</span><br><span class="line">        out.cpu()</span><br><span class="line">    <span class="comment"># benchmark</span></span><br><span class="line">    times = []</span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">200</span>):</span><br><span class="line">        t0 = time.perf_counter()</span><br><span class="line">        <span class="keyword">with</span> backend:</span><br><span class="line">            out = src.remap(warp)</span><br><span class="line">        out.cpu()</span><br><span class="line">        times.append((time.perf_counter() - t0) * <span class="number">1000</span>)</span><br><span class="line">    times.sort()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;backend&#125;</span>: avg=<span class="subst">&#123;<span class="built_in">sum</span>(times)/<span class="built_in">len</span>(times):<span class="number">.3</span>f&#125;</span>ms min=<span class="subst">&#123;times[<span class="number">0</span>]:<span class="number">.3</span>f&#125;</span>ms&quot;</span>)</span><br></pre></td></tr></table></figure><h5 id="5-2-VPI-支持的后端">5.2 VPI 支持的后端</h5><table><thead><tr><th>后端</th><th>硬件</th><th>说明</th></tr></thead><tbody><tr><td><code>VPI_BACKEND_CUDA</code></td><td>GPU CUDA Cores</td><td>通用计算，延迟最低</td></tr><tr><td><code>VPI_BACKEND_PVA</code></td><td>PVA (Programmable Vision Accelerator)</td><td>图像处理专用，功耗低</td></tr><tr><td><code>VPI_BACKEND_VIC</code></td><td>VIC (Video Image Compositor)</td><td>视频处理专用，带宽优化</td></tr><tr><td><code>VPI_BACKEND_NVENC</code></td><td>NVENC (Video Encoder)</td><td>编码专用</td></tr><tr><td><code>VPI_BACKEND_CPU</code></td><td>CPU</td><td>最慢，调试用</td></tr></tbody></table><blockquote><p><strong>Remap 操作支持</strong>: CUDA, VIC, CPU（不支持 PVA）</p></blockquote><h5 id="5-3-VPI-在-Pipeline-中的硬件分配">5.3 VPI 在 Pipeline 中的硬件分配</h5><p>当前 stereo_3d_pipeline 中的 VPI 调用：</p><table><thead><tr><th>操作</th><th>后端</th><th>硬件</th><th>延迟</th></tr></thead><tbody><tr><td>Remap (双目校正) L+R</td><td>CUDA</td><td>GPU</td><td>~2.8ms (dual)</td></tr><tr><td>ConvertImageFormat (NV12→Gray)</td><td>CUDA</td><td>GPU</td><td>~0.1ms</td></tr><tr><td>TemporalNoiseReduction</td><td>CUDA</td><td>GPU</td><td>~0.5ms (如启用)</td></tr></tbody></table><hr><h4 id="6-常用-Benchmark-流程">6. 常用 Benchmark 流程</h4><h5 id="完整性能测试流程">完整性能测试流程</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 设置最高性能模式</span></span><br><span class="line">sudo nvpmodel -m 0</span><br><span class="line">sudo jetson_clocks</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 预热系统 (运行 5 秒空闲)</span></span><br><span class="line"><span class="built_in">sleep</span> 5</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. TRT Engine benchmark</span></span><br><span class="line">/usr/src/tensorrt/bin/trtexec --loadEngine=model.engine \</span><br><span class="line">    --iterations=500 --warmUp=3000 --avgRuns=10</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. Pipeline 全链路测试</span></span><br><span class="line"><span class="built_in">cd</span> /home/nvidia/NX_volleyball/stereo_3d_pipeline</span><br><span class="line"><span class="built_in">timeout</span> 15 ./build/stereo_pipeline -c config/pipeline_triple.yaml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. nsys 全链路 profiling</span></span><br><span class="line">nsys profile --stats=<span class="literal">true</span> -o pipeline_profile \</span><br><span class="line">    <span class="built_in">timeout</span> 10 ./build/stereo_pipeline -c config/pipeline_triple.yaml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 同时监控系统状态</span></span><br><span class="line">tegrastats --interval 200 --logfile /tmp/bench_tegra.log &amp;</span><br></pre></td></tr></table></figure><h5 id="Benchmark-注意事项">Benchmark 注意事项</h5><ol><li><strong>始终锁定频率</strong>：<code>jetson_clocks</code> 必须在测试前执行，否则 DVFS 导致结果不稳定</li><li><strong>充分预热</strong>：TRT engine 首次推理较慢（JIT 优化），至少 warmUp 2-3 秒</li><li><strong>温度影响</strong>：长时间运行会导致 thermal throttling，关注 <code>tj</code> 温度</li><li><strong>DLA 独立计时</strong>：DLA 延迟不反映在 <code>GPU Compute Time</code> 中，需要用 <code>nsys</code> 或 <code>--dumpProfile</code> 查看</li><li><strong>内存带宽竞争</strong>：DLA 和 GPU 共享 LPDDR5 带宽，同时使用会互相影响</li></ol><h3 id="jtop-JetPack-版本识别修复指南">jtop JetPack 版本识别修复指南</h3><p>jtop JetPack 版本识别修复指南</p><p><strong>问题描述</strong></p><p>在 Jetson Orin NX（JetPack 6.2, L4T R36.4.7）上运行 <code>jtop</code> 时，JetPack 版本显示为 <strong>MISSING</strong>。<br>系统实际已正确安装 <code>nvidia-jetpack 6.2.1+b38</code>。</p><p><strong>根因分析</strong></p><p><code>jtop</code>（jetson-stats 4.3.2）使用内部映射表将 L4T 版本号映射到 JetPack 版本。<br>映射表位于：</p><p>/usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">该表包含 `&quot;36.4.3&quot;: &quot;6.2&quot;` 等条目，但 **缺少 `&quot;36.4.7&quot;` 对应条目**。</span><br><span class="line">当 L4T 版本为 R36.4.7 时，查表失败，显示 MISSING。</span><br><span class="line"></span><br><span class="line">## 验证步骤</span><br><span class="line"></span><br><span class="line">```bash</span><br><span class="line"># 1. 确认 L4T 版本</span><br><span class="line">cat /etc/nv_tegra_release</span><br><span class="line"># 应输出: # R36 (release), REVISION: 4.7, ...</span><br><span class="line"></span><br><span class="line"># 2. 确认 JetPack 已安装</span><br><span class="line">dpkg -l | grep nvidia-jetpack</span><br><span class="line"># 应显示: nvidia-jetpack 6.2.1+b38</span><br><span class="line"></span><br><span class="line"># 3. 检查 jtop 映射表</span><br><span class="line">grep &quot;36.4&quot; /usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py</span><br><span class="line"># 如果只有 &quot;36.4.3&quot;: &quot;6.2&quot;，没有 &quot;36.4.7&quot;，则确认问题</span><br></pre></td></tr></table></figure><p><strong>修复方法</strong></p><p>向映射表中添加 <code>&quot;36.4.7&quot;: &quot;6.2&quot;</code> 条目：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 备份原文件</span></span><br><span class="line">sudo <span class="built_in">cp</span> /usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py \</span><br><span class="line">       /usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py.bak</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在 &quot;36.4.3&quot;: &quot;6.2&quot; 之前插入 &quot;36.4.7&quot;: &quot;6.2&quot;</span></span><br><span class="line">sudo python3 -c <span class="string">&quot;</span></span><br><span class="line"><span class="string">path = &#x27;/usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py&#x27;</span></span><br><span class="line"><span class="string">with open(path, &#x27;r&#x27;) as f:</span></span><br><span class="line"><span class="string">    content = f.read()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">old = &#x27;\&quot;36.4.3\&quot;: \&quot;6.2\&quot;&#x27;</span></span><br><span class="line"><span class="string">new = &#x27;\&quot;36.4.7\&quot;: \&quot;6.2\&quot;,\n    \&quot;36.4.3\&quot;: \&quot;6.2\&quot;&#x27;</span></span><br><span class="line"><span class="string">content = content.replace(old, new)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">with open(path, &#x27;w&#x27;) as f:</span></span><br><span class="line"><span class="string">    f.write(content)</span></span><br><span class="line"><span class="string">print(&#x27;Patched successfully&#x27;)</span></span><br><span class="line"><span class="string">&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启 jtop 服务</span></span><br><span class="line">sudo systemctl restart jtop.service</span><br></pre></td></tr></table></figure><p><strong>验证修复</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 检查映射是否已添加</span></span><br><span class="line">grep <span class="string">&quot;36.4.7&quot;</span> /usr/local/lib/python3.10/dist-packages/jtop/core/jetson_variables.py</span><br><span class="line"><span class="comment"># 应输出包含 &quot;36.4.7&quot;: &quot;6.2&quot; 的行</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行 jtop 确认</span></span><br><span class="line">jtop</span><br><span class="line"><span class="comment"># JetPack 应显示为 6.2 而非 MISSING</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">ORIN NX
LINK
Nsight 系统 |NVIDIA 开发者 [https://developer.nvidia.com/nsight-systems]

开始配置
NOMACHINE
Downloa
[https://download.nomachine.com/download/?id=30&amp;platform=linux&amp;distro=arm]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>cloudflare加速onedrive文件下载</title>
    <link href="https://polar-bear.eu.org/2025/12/27/cloudflare-jia-su-onedrive-wen-jian-xia-zai/"/>
    <id>https://polar-bear.eu.org/2025/12/27/cloudflare-jia-su-onedrive-wen-jian-xia-zai/</id>
    <published>2025-12-27T05:52:03.010Z</published>
    <updated>2025-12-27T06:07:21.475Z</updated>
    
    <content type="html"><![CDATA[<h2 id="cloudflare加速onedrive文件下载">cloudflare加速onedrive文件下载</h2><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_4c4fda2a95235a50b6c6a570f0aa8746.png" alt=""></p><p><a href="https://github.com/lyc8503/onedrive-cf-index-ng">lyc8503/onedrive-cf-index-ng: Another OneDrive public directory listing on Docker / Cloudflare Workers, forked from onedrive-vercel-index.</a></p><h3 id="开始">开始</h3><p>首先fork仓库到本地，fork后不可转私有，可以先download下再自建私有库。</p><p>快速开始<a href="https://ovi.swo.moe/docs/getting-started">Getting started - OneDrive Vercel Index</a>（注：该配置文档为OneDrive-Vercel-Index项目，现在配置项目onedrive-cf-index-ng为该项目二开，具体配置差异以onedrive-cf-index-ng文档为主。）</p><p>修改<code>config/site.config.js</code></p><ul><li><code>userPrincipalName</code>- 用于验证你的身份,需要与认证的onedrive用户名一致。</li><li><code>baseDirectory</code>使用 OneDrive-vercel-index 共享的基础文件夹，设置共享目录可防止其他文件在互联网上公开。</li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_a02a4d5e37e6d2e97dd5d34e0b9f2f40.png" alt=""></p><p>修改<code>config/api.config.js</code></p><p>如果你是 <strong>OneDrive 国际版用户</strong>（不是 OneDrive 商务或教育版，也不是 SharePoint 用户，也不是 Microsoft 365 E5 用户），你可以忽略这一步，保持不动。</p><ul><li>OneDrive 世纪互联用户的 API 路由与我们通常使用的不同，你需要更改并：<code>authApi``driveApi</code></li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_9aa9baf1256c1138bd4a7ddcd15ac4e2.png" alt=""></p><p>把它们改成：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">authApi: &quot;https://login.partner.microsoftonline.cn/common/oauth2/v2.0/token&quot;,</span><br><span class="line">driveApi: &quot;https://microsoftgraph.chinacloudapi.cn/v1.0/me/drive&quot;,</span><br></pre></td></tr></table></figure><ul><li>OneDrive 商务、教育账户和 E5 订阅账户需要确认<strong>是否有管理员权限</strong></li></ul><p>配置可访问<a href="https://ovi.swo.moe/docs/advanced#using-your-own-clientid-and-clientsecret-1">Advanced - OneDrive Vercel Index</a></p><p>开始配置Azure应用</p><ul><li><a href="https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade">Microsoft Azure 应用注册</a>（适用于 OneDrive 国际版、OneDrive 商务版或教育版），或者…</li><li><a href="https://portal.azure.cn/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade">Microsoft Azure.cn 应用注册</a> （OneDrive 世纪互联版本）</li></ul><p>参考密钥配置文档：<a href="https://ovi.swo.moe/docs/advanced#using-your-own-clientid-and-clientsecret-1">高级版 - OneDrive Vercel 索引</a></p><p>用你的 Microsoft 账户登录，选择<em>新注册</em>。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_203f783e71d0caf23add7e73543cb57e.png" alt=""></p><p>创建应用随意名称<code>my-onedrive-vercel-index</code></p><p>将<em>支持账户类型</em>设置为：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Accounts <span class="keyword">in</span> any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)</span><br><span class="line">任何组织目录(任何 Microsoft Entra ID 租户 - 多租户)中的帐户和个人 Microsoft 帐户(例如 Skype、Xbox)</span><br></pre></td></tr></table></figure><p>将重定向URI（可选）设置为<code>Web</code>和（URL）<code>http://localhost</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_d39f4752a605b0b0de7203a008f09b87.png" alt=""></p><p>获取你的客户身份证和密钥</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_acc6954b9a0fc4deba0d8935b9a90065.png" alt=""></p><p>应用程序(客户端) ID即为配置<code>config/api.config.js</code>中的<code>module.exports/clientId</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_2f1534e13a4e79637e44afc07bc01b2b.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_298ea3096438ae4384a4e4e2426845bb.png" alt=""></p><p>创建密钥，时间尽量拉长，最后，点击<em>添加</em>，复制client_secret的值（你只有这一次复制机会）。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_ed45f434b948b22ac10d7c25694d831b.png" alt=""></p><p>将得到的密钥在<a href="https://ovi.swo.moe/docs/advanced#modify-configs-in-apiconfigjs">高级版 - OneDrive Vercel 索引</a>中加密，得到类似于<code>U2FsdGVkX1830zo3/pFDqaBCVBb37iLw3WnBDWGF9GIB2f4apzv0roemp8Y+iIxI3Ih5ecyukqELQEGzZlYiWg==</code>的值。</p><p>该值即为配置<code>config/api.config.js</code>中的<code>module.exports/obfuscatedClientSecret</code></p><h3 id="cloudflare部署">cloudflare部署</h3><p><a href="https://github.com/lyc8503/onedrive-cf-index-ng/wiki/Getting-Started">入门 ·lyc8503/onedrive-cf-index-ng 维基</a></p><p>进入 Cloudflare Dashboard</p><ul><li><a href="">https://dash.cloudflare.com</a></li></ul><p>创建 Pages 项目（注意是pages不是woker）</p><ul><li>左侧菜单 → <strong>Workers &amp; Pages</strong> → <strong>Create application</strong> → <strong>Connect to Git</strong></li><li>选择你的 Fork 仓库（如 <code>yourname/onedrive-cf-index-ng</code>）</li><li>分支：<code>main</code></li><li>构建设置：设置为Next.js即可</li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_28/image_753714905e00fef925d69299d95dfcdb.png" alt=""></p><p>部署完成后应该会显示：<code>xxx.pages.dev``Error: Could not access built-in Node.js modules. Please make sure that your Cloudflare Pages project has the 'nodejs_compat' compatibility flag set.</code></p><p>需要添加标志和KV</p><ul><li>兼容性标志：设置为<code>nodejs_compat</code></li><li>创建KV储存库并且绑定</li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_28/image_79fddf5601fb0cc264cee50cade679ee.png" alt=""></p><p>完成配置后重新部署即可</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_28/image_4781a52a96414055fc589212772360e6.png" alt=""></p><p>重新部署后应该能够正确访问，接下来是OneDrive绑定认证</p><p><a href="https://ovi.swo.moe/docs/getting-started#step-1---preparations">Getting started - OneDrive Vercel Index</a></p>]]></content>
    
    
    <summary type="html">CLOUDFLARE加速ONEDRIVE文件下载
[https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/12_27/image_4c4fda2a95235a50b6c6a570f0aa8746.png]

lyc8503/onedrive-cf-index-ng: Another One
[https://github.com/lyc8503/onedrive-cf-index-ng]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>RDK S100P的种种</title>
    <link href="https://polar-bear.eu.org/2025/12/27/rdk-s100p-de-chong-chong/"/>
    <id>https://polar-bear.eu.org/2025/12/27/rdk-s100p-de-chong-chong/</id>
    <published>2025-12-27T00:27:09.891Z</published>
    <updated>2026-01-24T00:22:14.419Z</updated>
    
    <content type="html"><![CDATA[<h2 id="资料">资料</h2><p>dtop</p><p><a href="https://forum.d-robotics.cc/t/topic/31957">Jetson有Jtop,Linux有Htop,RDK也有Dtop！ - 板卡使用 - 地瓜机器人论坛</a></p><p><a href="https://toolchain.d-robotics.cc/guide/tune_content/performance_tune.html">模型性能调优 - OpenExplorer</a></p><p>参考教程</p><p><a href="https://www.cnblogs.com/SkyXZ/p/18981362">万字长文，学妹吵着要学的RDKS100模型量化及部署，你确定不学？ - SkyXZ - 博客园</a></p><p>官方示例猴子脚本</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/Ultralytics_YOLO/x86/export_monkey_patch.py">rdk_model_zoo_s/samples/Vision/Ultralytics_YOLO/x86/export_monkey_patch.py at s100 · D-Robotics/rdk_model_zoo_s</a></p><p>官方示例量化脚本</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/Ultralytics_YOLO/x86/mapper.py">rdk_model_zoo_s/samples/Vision/Ultralytics_YOLO/x86/mapper.py at s100 · D-Robotics/rdk_model_zoo_s</a></p><p>官方示例量化配置yaml</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/ultralytics_YOLO_Detect/source/reference_yamls/config_ultralytics_YOLO_Detect_YUV420SP_NV12.yaml">rdk_model_zoo_s/samples/Vision/ultralytics_YOLO_Detect/source/reference_yamls/config_ultralytics_YOLO_Detect_YUV420SP_NV12.yaml at s100 · D-Robotics/rdk_model_zoo_s</a></p><h2 id="环境部署">环境部署</h2><p><a href="https://blog.csdn.net/xiongqi123123/article/details/149303286">万字长文，学妹一看就会的RDKS100模型量化及部署_rdk s100-CSDN博客</a></p><p>不推荐手动部署，建议直接<code>bash ./run_docker.sh data/</code></p><h2 id="模型量化">模型量化</h2><p>这部分容易出错，建议先跑跑官方示例练练手。</p><p>需要着重注意量化配置中，各种输入输出格式，颜色通道。</p><h3 id="yolov8模型量化-示例">yolov8模型量化(示例)</h3><p>待完善。。。</p><p><a href="https://www.cnblogs.com/SkyXZ/p/18981362">万字长文，学妹吵着要学的RDKS100模型量化及部署，你确定不学？ - SkyXZ - 博客园</a></p><h3 id="yolov11模型量化">yolov11模型量化</h3><p>首先准备yolov11模型</p><p>转onnx</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># yolo11_to_onnx.py</span></span><br><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载你训练好的 YOLOv11 模型</span></span><br><span class="line">pt_file = <span class="string">&quot;best.pt&quot;</span></span><br><span class="line"></span><br><span class="line">model = YOLO(pt_file)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出 ONNX（RDK S100 兼容模式）</span></span><br><span class="line">model.export(</span><br><span class="line">    <span class="built_in">format</span>=<span class="string">&quot;onnx&quot;</span>,</span><br><span class="line">    imgsz=<span class="number">640</span>,          <span class="comment"># 必须和训练时一致</span></span><br><span class="line">    batch=<span class="number">1</span>,            <span class="comment"># 固定 batch=1（RDK 推荐）</span></span><br><span class="line">    opset=<span class="number">11</span>,           <span class="comment"># 必须为 11！</span></span><br><span class="line">    dynamic=<span class="literal">False</span>,      <span class="comment"># 关闭动态 shape（避免 BPU 不支持）</span></span><br><span class="line">    simplify=<span class="literal">True</span>,      <span class="comment"># 优化图（移除冗余节点）</span></span><br><span class="line">    nms=<span class="literal">False</span>,          <span class="comment"># 先不带 NMS（RDK BPU 可能不支持 NonMaxSuppression）</span></span><br><span class="line">    device=<span class="string">&quot;cpu&quot;</span>        <span class="comment"># 导出时用 CPU 避免 GPU 干扰</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;✅ YOLOv11 ONNX 已生成: <span class="subst">&#123;pt_file.replace(<span class="string">&#x27;.pt&#x27;</span>, <span class="string">&#x27;.onnx&#x27;</span>)&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="hb-compile算子检测">hb_compile算子检测</h3><p>使用hb_compile检测BPU算子支持,<code>S100 用 nash-e，S100P 用 nash-m</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">hb_compile \</span><br><span class="line">  --march nash-m \</span><br><span class="line">  --model ./best.onnx \</span><br><span class="line">  --input-shape images 1x3x640x640</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_02/b77e3754-3183-4ec3-ba69-dc21e0d50ac1_45aaa282398fb73bfc29faa6998fb828.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_02/826d7586-ca26-4c8e-8355-8ea8d1e38482_b9cf867ceed7616ab0fbf3125cdaf83d.png" alt=""></p><p>算子测试表格中需要查看是否所有算子都被BPU，VPU支持，<code>--</code>表示算子被前后融合计算，是正常情况，需要留意的是是否存在CPU算子，性能损失见<a href="https://toolchain.d-robotics.cc/guide/tune_content/performance_tune.html">模型性能调优 - OpenExplorer</a></p><h3 id="算子不支持">算子不支持</h3><p><a href="https://toolchain.d-robotics.cc/guide/tune_content/performance_tune.html">模型性能调优 - OpenExplorer</a></p><p><a href="https://toolchain.d-robotics.cc/guide/appendix/supported_op_list/operator_constraints_bpu/torch_operator_constraints_list_j6em.html">S100 Torch算子BPU约束列表 - OpenExplorer</a></p><p>算子不支持是BPU常态，若退回CPU执行，将会导致模型性能严重降低。</p><ul><li>CPU算子处于模型中部<br>对于CPU算子处于模型中部的情况，建议您优先尝试参数调整、算子替换或修改模型。</li><li>CPU算子处于模型首尾部<br>对于CPU算子处于模型首尾部的情况，请参考以下示例，下面以量化/反量化节点为例：</li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_03/image_e392b838b8b29956072f0e1273fdf7f7.png" alt=""></p><h4 id="邪恶C2PSA算子">邪恶C2PSA算子</h4><p>例如在yolov11中，模型架构为</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># YOLO11n backbone</span></span><br><span class="line">backbone:</span><br><span class="line">  <span class="comment"># [from, repeats, module, args]</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">64</span>, <span class="number">3</span>, <span class="number">2</span>]] <span class="comment"># 0-P1/2</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">128</span>, <span class="number">3</span>, <span class="number">2</span>]] <span class="comment"># 1-P2/4</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">256</span>, <span class="literal">False</span>, <span class="number">0.25</span>]]</span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">256</span>, <span class="number">3</span>, <span class="number">2</span>]] <span class="comment"># 3-P3/8</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">512</span>, <span class="literal">False</span>, <span class="number">0.25</span>]]</span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">512</span>, <span class="number">3</span>, <span class="number">2</span>]] <span class="comment"># 5-P4/16</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">512</span>, <span class="literal">True</span>]]</span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">1024</span>, <span class="number">3</span>, <span class="number">2</span>]] <span class="comment"># 7-P5/32</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">1024</span>, <span class="literal">True</span>]]</span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, SPPF, [<span class="number">1024</span>, <span class="number">5</span>]] <span class="comment"># 9</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C2PSA, [<span class="number">1024</span>]] <span class="comment"># 10</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># YOLO11n head</span></span><br><span class="line">head:</span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, nn.Upsample, [<span class="literal">None</span>, <span class="number">2</span>, <span class="string">&quot;nearest&quot;</span>]]</span><br><span class="line">  - [[-<span class="number">1</span>, <span class="number">6</span>], <span class="number">1</span>, Concat, [<span class="number">1</span>]] <span class="comment"># cat backbone P4</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">512</span>, <span class="literal">False</span>]] <span class="comment"># 13</span></span><br><span class="line"></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, nn.Upsample, [<span class="literal">None</span>, <span class="number">2</span>, <span class="string">&quot;nearest&quot;</span>]]</span><br><span class="line">  - [[-<span class="number">1</span>, <span class="number">4</span>], <span class="number">1</span>, Concat, [<span class="number">1</span>]] <span class="comment"># cat backbone P3</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">256</span>, <span class="literal">False</span>]] <span class="comment"># 16 (P3/8-small)</span></span><br><span class="line"></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">256</span>, <span class="number">3</span>, <span class="number">2</span>]]</span><br><span class="line">  - [[-<span class="number">1</span>, <span class="number">13</span>], <span class="number">1</span>, Concat, [<span class="number">1</span>]] <span class="comment"># cat head P4</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">512</span>, <span class="literal">False</span>]] <span class="comment"># 19 (P4/16-medium)</span></span><br><span class="line"></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">1</span>, Conv, [<span class="number">512</span>, <span class="number">3</span>, <span class="number">2</span>]]</span><br><span class="line">  - [[-<span class="number">1</span>, <span class="number">10</span>], <span class="number">1</span>, Concat, [<span class="number">1</span>]] <span class="comment"># cat head P5</span></span><br><span class="line">  - [-<span class="number">1</span>, <span class="number">2</span>, C3k2, [<span class="number">1024</span>, <span class="literal">True</span>]] <span class="comment"># 22 (P5/32-large)</span></span><br><span class="line"></span><br><span class="line">  - [[<span class="number">16</span>, <span class="number">19</span>, <span class="number">22</span>], <span class="number">1</span>, Detect, [nc]] <span class="comment"># Detect(P3, P4, P5)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其中的C2PSA正是导致模型算子不能被bpu完全支持，对于处于中部的邪恶C2PSA算子只能使用替换模型的方式。</p><p>C2PSA（Cross Stage Partial with Pyramid Squeeze Attention）是YOLO11新增的核心模块，结合CSP结构与注意力机制：</p><ul><li><strong>CSP 结构 (Cross Stage Partial)****：特征分流，一部分走深层网络，一部分直接连接。 -&gt;</strong> <strong>所有方案都通过</strong> <strong>C3k2</strong> <strong>实现了这一点。</strong></li><li><strong>Pyramid (金字塔/多尺度感知)</strong>：原模型通过不同核大小的卷积或分层处理来获取不同感受野。</li><li><strong>PSA (Position-Sensitive Attention)</strong>：位置敏感注意力，关注“哪里是重点”以及“哪个通道是重点”。</li></ul><p><strong>替换方案</strong></p><h5 id="纯-C3k2-方案">纯 C3k2 方案</h5><p><strong>结构</strong>：<strong>[-1, 3, C3k2, [1024, True]]</strong></p><p><strong>优点</strong>：速度最快，完全无缝兼容 BPU。</p><p><strong>缺点</strong>：<strong>严重缺失注意力机制</strong>。它只是单纯加深了网络，依靠卷积层的堆叠来“隐式”地学习特征，没有显式地告诉网络“去关注某个位置”。</p><p><strong>还原度</strong>：<strong>50%</strong>。只保留了 CSP 和卷积提取，丢失了 C2PSA 的灵魂（Attention）。</p><h5 id="C3k2-CBAM-方案">C3k2 + CBAM 方案</h5><p><strong>结构</strong>：<strong>C3k2</strong> <strong>+</strong> <strong>CBAM(k=7)</strong></p><p><strong>优点</strong>：CBAM 包含 <strong>CAM (通道注意力)</strong> <strong>和</strong> <strong>SAM (空间注意力)</strong>。其中 SAM 使用 7x7 卷积，能够提供较好的局部空间感知。</p><p><strong>缺点</strong>：CBAM 的空间注意力是基于 <strong>7x7 局部窗口</strong> <strong>的，它能看到周围一圈，但很难像 PSA 那样捕捉</strong>长距离（Long-range） <strong>的依赖关系。</strong></p><p><strong>还原度</strong>：<strong>80%</strong>。补全了空间和通道注意力，但在“全局位置感知”上略逊一筹。</p><h5 id="C3k2-CoordAtt-方案-理论最佳匹配">C3k2 + CoordAtt 方案 (理论最佳匹配)</h5><p><strong>结构</strong>：<strong>C3k2</strong> <strong>+</strong> <strong>CoordAtt</strong></p><p><strong>核心优势</strong>：<strong>C2PSA</strong> <strong>的核心词是</strong> <strong>“Position-Sensitive” (位置敏感)</strong>。</p><p><strong>CoordAtt 的原理</strong>：它通过分别对 <strong>X 轴</strong> <strong>和</strong> <strong>Y 轴</strong> <strong>进行全局池化，将</strong>全局的空间信息<strong>编码进两个方向的向量中。</strong></p><p><strong>对比 PSA</strong>：这与 PSA 试图建立长距离位置依赖的目标<strong>高度一致</strong>。相比 CBAM 的 7x7 局部视野，CoordAtt 拥有<strong>全图视野 (Global View)</strong>，能更好地感知物体在画面中的绝对位置。</p><p><strong>BPU 兼容性</strong>：极佳（Pool + 1x1 Conv）。</p><p><strong>还原度</strong>：<strong>90%</strong>。这是在功能原理上最接近 PSA 的 BPU 友好型算子。</p><h5 id="C3k2-DWConvblock-CBAM-方案-结构最全">C3k2 + DWConvblock + CBAM 方案 (结构最全)</h5><p><strong>结构</strong>：<strong>C3k2</strong> <strong>(特征) +</strong> <strong>DWConv(7x7)</strong> <strong>(大感受野) +</strong> <strong>CBAM</strong> (注意力)</p><p><strong>核心优势</strong>：这个组合是<strong>物理级堆叠</strong>。</p><p><strong>用</strong> <strong>C3k2</strong> 还原 CSP。</p><p><strong>用</strong> <strong>DWConvblock(7x7)</strong> 还原 <strong>Pyramid</strong> (大卷积核模拟多尺度/大感受野)。</p><p><strong>用</strong> <strong>CBAM</strong> 还原 <strong>Attention</strong>。</p><p><strong>缺点</strong>：<strong>太重了</strong>。Backbone 末端本身通道数就大 (1024)，再串联三个模块，计算量（FLOPs）和延迟（Latency）会显著增加。虽然功能最全，但可能导致 FPS 下降较多。</p><p><strong>还原度</strong>：<strong>95%</strong> <strong>(功能上最全，但效率最低)。</strong></p><p>替换算子后模型全部支持BPU运算。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_03/831a4a86822e5b9b4f83a3a76d5d22ea_831a4a86822e5b9b4f83a3a76d5d22ea.png" alt=""></p><h3 id="替换模型后onnx导出">替换模型后onnx导出</h3><p>更换部分算子后，需要手动添加ultralytics不包含的class，由于ultralytics不包含手动修改的算子，所以需要修改前面的onnx导出代码。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> types</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">import</span> torch.nn.functional <span class="keyword">as</span> F</span><br><span class="line"><span class="keyword">import</span> torchvision</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> itertools</span><br><span class="line"><span class="keyword">import</span> einops</span><br><span class="line"><span class="keyword">from</span> einops <span class="keyword">import</span> rearrange</span><br><span class="line"><span class="keyword">from</span> timm.models.layers <span class="keyword">import</span> trunc_normal_</span><br><span class="line"></span><br><span class="line"><span class="comment"># 假设你需要用到 Conv 和 autopad，如果报错找不到，这里做一个简单的 mock</span></span><br><span class="line"><span class="comment"># 或者你可以从 ultralytics 导入它们</span></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">from</span> ultralytics.nn.modules.conv <span class="keyword">import</span> Conv, autopad</span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line">    <span class="comment"># 简单的 fallback 实现，防止报错</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">autopad</span>(<span class="params">k, p=<span class="literal">None</span>, d=<span class="number">1</span></span>):</span><br><span class="line">        <span class="keyword">if</span> d &gt; <span class="number">1</span>:</span><br><span class="line">            k = d * (k - <span class="number">1</span>) + <span class="number">1</span> <span class="keyword">if</span> <span class="built_in">isinstance</span>(k, <span class="built_in">int</span>) <span class="keyword">else</span> [d * (x - <span class="number">1</span>) + <span class="number">1</span> <span class="keyword">for</span> x <span class="keyword">in</span> k]</span><br><span class="line">        <span class="keyword">if</span> p <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            p = k // <span class="number">2</span> <span class="keyword">if</span> <span class="built_in">isinstance</span>(k, <span class="built_in">int</span>) <span class="keyword">else</span> [x // <span class="number">2</span> <span class="keyword">for</span> x <span class="keyword">in</span> k]</span><br><span class="line">        <span class="keyword">return</span> p</span><br><span class="line"></span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">Conv</span>(nn.Module):</span><br><span class="line">        <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, c1, c2, k=<span class="number">1</span>, s=<span class="number">1</span>, p=<span class="literal">None</span>, g=<span class="number">1</span>, d=<span class="number">1</span>, act=<span class="literal">True</span></span>):</span><br><span class="line">            <span class="built_in">super</span>().__init__()</span><br><span class="line">            self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), dilation=d, groups=g, bias=<span class="literal">False</span>)</span><br><span class="line">            self.bn = nn.BatchNorm2d(c2)</span><br><span class="line">            self.act = nn.SiLU() <span class="keyword">if</span> act <span class="keyword">is</span> <span class="literal">True</span> <span class="keyword">else</span> (act <span class="keyword">if</span> <span class="built_in">isinstance</span>(act, nn.Module) <span class="keyword">else</span> nn.Identity())</span><br><span class="line">        <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">            <span class="keyword">return</span> self.act(self.bn(self.conv(x)))</span><br><span class="line"></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 1. 在这里粘贴你提供的所有 Attention 类定义 (为了节省篇幅，我只列出 CoordAtt)</span></span><br><span class="line"><span class="comment">#    请务必把你上面发给我的那一大段代码完整粘贴替换下面的区域！</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># --------------- 粘贴开始 ---------------</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里必须包含 h_swish 和 h_sigmoid，因为 CoordAtt 用到了</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">h_sigmoid</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inplace=<span class="literal">True</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(h_sigmoid, self).__init__()</span><br><span class="line">        self.relu = nn.ReLU6(inplace=inplace)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="keyword">return</span> self.relu(x + <span class="number">3</span>) / <span class="number">6</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">h_swish</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inplace=<span class="literal">True</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(h_swish, self).__init__()</span><br><span class="line">        self.sigmoid = h_sigmoid(inplace=inplace)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="keyword">return</span> x * self.sigmoid(x)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 你的 CoordAtt 类</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CoordAtt</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inp, reduction=<span class="number">32</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(CoordAtt, self).__init__()</span><br><span class="line">        self.pool_h = nn.AdaptiveAvgPool2d((<span class="literal">None</span>, <span class="number">1</span>))</span><br><span class="line">        self.pool_w = nn.AdaptiveAvgPool2d((<span class="number">1</span>, <span class="literal">None</span>))</span><br><span class="line"></span><br><span class="line">        mip = <span class="built_in">max</span>(<span class="number">8</span>, inp // reduction)</span><br><span class="line"></span><br><span class="line">        self.conv1 = nn.Conv2d(inp, mip, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line">        self.bn1 = nn.BatchNorm2d(mip)</span><br><span class="line">        self.act = h_swish()</span><br><span class="line"></span><br><span class="line">        self.conv_h = nn.Conv2d(mip, inp, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line">        self.conv_w = nn.Conv2d(mip, inp, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        identity = x</span><br><span class="line"></span><br><span class="line">        n, c, h, w = x.size()</span><br><span class="line">        x_h = self.pool_h(x)</span><br><span class="line">        x_w = self.pool_w(x).permute(<span class="number">0</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">        y = torch.cat([x_h, x_w], dim=<span class="number">2</span>)</span><br><span class="line">        y = self.conv1(y)</span><br><span class="line">        y = self.bn1(y)</span><br><span class="line">        y = self.act(y)</span><br><span class="line"></span><br><span class="line">        x_h, x_w = torch.split(y, [h, w], dim=<span class="number">2</span>)</span><br><span class="line">        x_w = x_w.permute(<span class="number">0</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">        a_h = self.conv_h(x_h).sigmoid()</span><br><span class="line">        a_w = self.conv_w(x_w).sigmoid()</span><br><span class="line"></span><br><span class="line">        out = identity * a_w * a_h</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> out</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DWConvblock</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;Depthwise conv + Pointwise conv&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_channels, out_channels, k, s</span>):</span><br><span class="line">        <span class="built_in">super</span>(DWConvblock, self).__init__()</span><br><span class="line">        self.p = k // <span class="number">2</span></span><br><span class="line">        self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=k, stride=s, padding=self.p, groups=in_channels,</span><br><span class="line">                               bias=<span class="literal">False</span>)</span><br><span class="line">        self.bn1 = nn.BatchNorm2d(in_channels)</span><br><span class="line">        self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>, bias=<span class="literal">False</span>)</span><br><span class="line">        self.bn2 = nn.BatchNorm2d(out_channels)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = self.conv1(x)</span><br><span class="line">        x = self.bn1(x)</span><br><span class="line">        x = F.relu(x)</span><br><span class="line">        x = self.conv2(x)</span><br><span class="line">        x = self.bn2(x)</span><br><span class="line">        x = F.relu(x)</span><br><span class="line">        <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># ... (请务必把 EMA, SimAM 等其他所有你可能用到的类都粘在这里，以防万一) ...</span></span><br><span class="line"><span class="comment"># 如果你确定只用了 CoordAtt，那上面这些就够了。如果不确定，建议全部粘贴。</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># --------------- 粘贴结束 ---------------</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 2. 核心欺骗步骤：构造虚拟模块</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建一个虚拟的 module 对象</span></span><br><span class="line">fake_attention_module = types.ModuleType(<span class="string">&#x27;ultralytics.nn.modules.attention&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将定义好的类挂载到这个虚拟 module 上</span></span><br><span class="line">fake_attention_module.CoordAtt = CoordAtt</span><br><span class="line">fake_attention_module.h_swish = h_swish</span><br><span class="line">fake_attention_module.h_sigmoid = h_sigmoid</span><br><span class="line"><span class="comment"># 如果还有其他类，例如 fake_attention_module.EMA = EMA</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 将虚拟 module 注入系统 sys.modules</span></span><br><span class="line"><span class="comment"># 这样 PyTorch 加载模型时寻找 &#x27;ultralytics.nn.modules.attention&#x27; 就会找到这里</span></span><br><span class="line">sys.modules[<span class="string">&#x27;ultralytics.nn.modules.attention&#x27;</span>] = fake_attention_module</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 导入 DWConvblock 到 ultralytics.nn.modules.block 中</span></span><br><span class="line"><span class="keyword">import</span> ultralytics.nn.modules.block</span><br><span class="line">ultralytics.nn.modules.block.DWConvblock = DWConvblock</span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 3. 正常执行 YOLO 导出逻辑</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    <span class="comment"># 加载你训练好的 YOLOv11 模型</span></span><br><span class="line">    pt_file = <span class="string">&quot;model/yolo11_C2PSAtoC3k2_DWConvblock_CBAM-RGB/best.pt&quot;</span>  <span class="comment"># ← 改成你的 .pt 路径</span></span><br><span class="line"></span><br><span class="line">    model = YOLO(pt_file)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 导出 ONNX（RDK S100 兼容模式）</span></span><br><span class="line">    model.export(</span><br><span class="line">        <span class="built_in">format</span>=<span class="string">&quot;onnx&quot;</span>,</span><br><span class="line">        imgsz=<span class="number">640</span>,          <span class="comment"># 必须和训练时一致</span></span><br><span class="line">        batch=<span class="number">1</span>,            <span class="comment"># 固定 batch=1（RDK 推荐）</span></span><br><span class="line">        opset=<span class="number">11</span>,           <span class="comment"># ⚠️ 必须为 11！</span></span><br><span class="line">        dynamic=<span class="literal">False</span>,      <span class="comment"># 关闭动态 shape（避免 BPU 不支持）</span></span><br><span class="line">        simplify=<span class="literal">True</span>,      <span class="comment"># 优化图（移除冗余节点）</span></span><br><span class="line">        nms=<span class="literal">False</span>,          <span class="comment"># 先不带 NMS（RDK BPU 可能不支持 NonMaxSuppression）</span></span><br><span class="line">        device=<span class="string">&quot;cpu&quot;</span>        <span class="comment"># 导出时用 CPU 避免 GPU 干扰</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;✅ YOLOv11 ONNX 已生成: <span class="subst">&#123;pt_file.replace(<span class="string">&#x27;.pt&#x27;</span>, <span class="string">&#x27;.onnx&#x27;</span>)&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="生成校验数据">生成校验数据</h3><p>注意此处生成校验数据容易出错，请仔细核对。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> cv2</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> glob</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">preprocess_image</span>(<span class="params">image_path, target_size=(<span class="params"><span class="number">640</span>, <span class="number">640</span></span>)</span>):</span><br><span class="line">    <span class="comment"># 1. 读取 (BGR, 0-255)</span></span><br><span class="line">    img = cv2.imread(image_path)</span><br><span class="line">    <span class="keyword">if</span> img <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 2. Resize</span></span><br><span class="line">    img = cv2.resize(img, target_size)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 3. 转换色空间 BGR -&gt; RGB </span></span><br><span class="line">    <span class="comment"># (YOLO需要RGB，我们在脚本里转好，然后在 YAML 里告诉工具这是 RGB)</span></span><br><span class="line">    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) </span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 4. HWC 转 CHW (Layout: NCHW)</span></span><br><span class="line">    img = img.transpose(<span class="number">2</span>, <span class="number">0</span>, <span class="number">1</span>)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 5. 要除以 255.0！保持 0-1 的数值范围</span></span><br><span class="line">    <span class="comment"># 归一化</span></span><br><span class="line">    img = img.astype(np.float32) / <span class="number">255.0</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> img</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建保存目录</span></span><br><span class="line">save_dir = <span class="string">&quot;./calibration_data&quot;</span></span><br><span class="line">os.makedirs(save_dir, exist_ok=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取图片</span></span><br><span class="line">all_images = glob.glob(os.path.join(<span class="string">&quot;./&quot;</span>, <span class="string">&quot;*.jpg&quot;</span>)) <span class="comment"># 确保路径对</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 随机选取 </span></span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(all_images) &gt; <span class="number">100</span>:</span><br><span class="line">    image_list = random.sample(all_images, <span class="number">100</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    image_list = all_images</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Start processing <span class="subst">&#123;<span class="built_in">len</span>(image_list)&#125;</span> images...&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i, img_path <span class="keyword">in</span> <span class="built_in">enumerate</span>(image_list):</span><br><span class="line">    processed_data = preprocess_image(img_path)</span><br><span class="line">    <span class="keyword">if</span> processed_data <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="comment"># 保存</span></span><br><span class="line">        np.save(os.path.join(save_dir, <span class="string">f&quot;<span class="subst">&#123;i&#125;</span>.npy&quot;</span>), processed_data)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Done.&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="hb-compile量化工具">hb_compile量化工具</h3><p>直接量化，快速性能评测模式（开启fast-perf），会转为int8-NV12模型。（建议还是添加校验数据的手动校准，详细参考官方文档）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">hb_compile --fast-perf \</span><br><span class="line">           --model /open_explorer/data/best.onnx \</span><br><span class="line">           --march nash-m \</span><br><span class="line">           --input-shape images 1x3x640x640</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_02/32ce319e825ab08b25354d05b30e9200_32ce319e825ab08b25354d05b30e9200.png" alt=""></p><p>自定义量化</p><p>创建<code>yolo11_quantize.yaml</code></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 模型参数组</span></span><br><span class="line"><span class="attr">model_parameters:</span></span><br><span class="line">  <span class="attr">onnx_model:</span> <span class="string">&quot;best.onnx&quot;</span></span><br><span class="line">  <span class="attr">march:</span> <span class="string">&quot;nash-m&quot;</span>                     <span class="comment"># S100P 用 nash-m，S100 用 nash-e</span></span><br><span class="line">  <span class="attr">output_model_file_prefix:</span> <span class="string">&quot;yolo11_bgr&quot;</span></span><br><span class="line">  <span class="attr">working_dir:</span> <span class="string">&quot;./model_output&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 输入信息参数组</span></span><br><span class="line"><span class="attr">input_parameters:</span></span><br><span class="line">  <span class="attr">input_name:</span> <span class="string">&quot;images&quot;</span>                <span class="comment"># ONNX 模型的输入节点名（用 netron 查看）</span></span><br><span class="line">  <span class="attr">input_type_train:</span> <span class="string">&quot;rgb&quot;</span>             <span class="comment"># 校准数据是rgb</span></span><br><span class="line">  <span class="attr">input_type_rt:</span> <span class="string">&quot;bgr&quot;</span>                <span class="comment"># 运行时也用 BGR（关键！）</span></span><br><span class="line">  <span class="attr">input_layout_train:</span> <span class="string">&quot;NCHW&quot;</span>          <span class="comment"># YOLOv8/v11 通常是 NCHW</span></span><br><span class="line">  <span class="attr">input_shape:</span> <span class="string">&quot;1x3x640x640&quot;</span>          <span class="comment"># 根据你的模型实际输入改</span></span><br><span class="line">  <span class="attr">input_batch:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">mean_value:</span> <span class="string">&quot;0 0 0&quot;</span>                 <span class="comment"># 如果训练时没减均值，就设为 0</span></span><br><span class="line">  <span class="attr">scale_value:</span> <span class="string">&quot;0.003921568627451&quot;</span>    <span class="comment"># = 1/255，如果训练时归一化到 [0,1]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 校准参数组</span></span><br><span class="line"><span class="attr">calibration_parameters:</span></span><br><span class="line">  <span class="attr">cal_data_dir:</span> <span class="string">&quot;./calibration_data&quot;</span>        <span class="comment"># 必须存在且包含校准图片（BGR 格式）</span></span><br><span class="line">  <span class="comment"># 强制指定一种校准方法，不要让它搜索</span></span><br><span class="line">  <span class="attr">calibration_type:</span> <span class="string">&#x27;max&#x27;</span>     <span class="comment"># 对于检测任务，max 通常最稳</span></span><br><span class="line">  <span class="attr">max_percentile:</span> <span class="number">0.99995</span></span><br><span class="line">  <span class="attr">per_channel:</span> <span class="literal">False</span>          <span class="comment"># YOLO 通常不需要逐通道量化，False 更快且兼容性好</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 编译参数组</span></span><br><span class="line"><span class="attr">compiler_parameters:</span></span><br><span class="line">  <span class="attr">compile_mode:</span> <span class="string">&quot;latency&quot;</span></span><br><span class="line">  <span class="attr">core_num:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">optimize_level:</span> <span class="string">&quot;O2&quot;</span></span><br><span class="line">  <span class="attr">jobs:</span> <span class="number">4</span>                     <span class="comment"># 并行编译线程数</span></span><br></pre></td></tr></table></figure><p>允许<code>hb_compile --config yolo11_quantize.yaml</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_03/d1159ecc2e38255db1f6708897cb3be7_d1159ecc2e38255db1f6708897cb3be7.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_03/a6cfe09773af20e414ec7b059fe1bb75_a6cfe09773af20e414ec7b059fe1bb75.png" alt=""></p><ul><li>Calibrated Cosine表示优化后模型（optimized_float_model.onnx）与校准后模型（calibrated_model.onnx）对应节点（Node）/输出Tensor（Output Tensor）的余弦相似度结果。</li><li>Quantized Cosine表示优化后模型（optimized_float_model.onnx）与模型量化后生成的定点模型（quantized_model.bc）对应节点（Node）/输出Tensor（Output Tensor）的余弦相似度结果。</li></ul><p><strong>注意此处余弦相似度，一般情况需要大于95%，若出现30%等异常低值，请检查测试集生成是否正确(图像通道对应，归一化对应，图片质量)</strong></p><h3 id="量化进阶">量化进阶</h3><p>官方示例位于开发板<code>/app/cdev_demo/bpu/02_detection_sample/02_ultralytics_yolo11</code>路径下，使用的默认coco模型结构如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">2026-01-04 15:21:09,745 INFO <span class="comment">############# Model input/output info #############</span></span><br><span class="line">2026-01-04 15:21:09,745 INFO NAME      TYPE   SHAPE            DATA_TYPE</span><br><span class="line">2026-01-04 15:21:09,745 INFO --------- ------ ---------------- ---------</span><br><span class="line">2026-01-04 15:21:09,745 INFO images_y  input  [1, 640, 640, 1] UINT8</span><br><span class="line">2026-01-04 15:21:09,745 INFO images_uv input  [1, 320, 320, 2] UINT8</span><br><span class="line">2026-01-04 15:21:09,745 INFO output0   output [1, 80, 80, 80]  FLOAT32</span><br><span class="line">2026-01-04 15:21:09,745 INFO 499       output [1, 80, 80, 64]  INT32</span><br><span class="line">2026-01-04 15:21:09,745 INFO 513       output [1, 40, 40, 80]  FLOAT32</span><br><span class="line">2026-01-04 15:21:09,745 INFO 521       output [1, 40, 40, 64]  INT32</span><br><span class="line">2026-01-04 15:21:09,745 INFO 535       output [1, 20, 20, 80]  FLOAT32</span><br><span class="line">2026-01-04 15:21:09,745 INFO 543       output [1, 20, 20, 64]  INT32</span><br></pre></td></tr></table></figure><p>输入为<code>MIPI 摄像头/ISP 输出的原始视频流 NV12 (YUV420sp)</code></p><p>输出为<code>原始特征图。 Box: DFL 分布 (64通道),Cls: 分类概率</code></p><p>切其最后检测头的原因可能是，YOLO 的 Detect 头包含大量的 <strong>Transpose</strong>（维度变换）、<strong>Softmax</strong>（指数运算）和巨大的 <strong>Concat</strong>（拼接）。不适宜BPU结构运算而且数值极度敏感不适合量化。</p><h4 id="查看官方模型">查看官方模型</h4><p>参考教程</p><p><a href="https://www.cnblogs.com/SkyXZ/p/18981362">万字长文，学妹吵着要学的RDKS100模型量化及部署，你确定不学？ - SkyXZ - 博客园</a></p><p>官方示例猴子脚本</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/Ultralytics_YOLO/x86/export_monkey_patch.py">rdk_model_zoo_s/samples/Vision/Ultralytics_YOLO/x86/export_monkey_patch.py at s100 · D-Robotics/rdk_model_zoo_s</a></p><p>官方示例量化脚本</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/Ultralytics_YOLO/x86/mapper.py">rdk_model_zoo_s/samples/Vision/Ultralytics_YOLO/x86/mapper.py at s100 · D-Robotics/rdk_model_zoo_s</a></p><p>官方示例量化配置yaml</p><p><a href="https://github.com/D-Robotics/rdk_model_zoo_s/blob/s100/samples/Vision/ultralytics_YOLO_Detect/source/reference_yamls/config_ultralytics_YOLO_Detect_YUV420SP_NV12.yaml">rdk_model_zoo_s/samples/Vision/ultralytics_YOLO_Detect/source/reference_yamls/config_ultralytics_YOLO_Detect_YUV420SP_NV12.yaml at s100 · D-Robotics/rdk_model_zoo_s</a></p><p>为了保持与官方示例一致，我们查看官方模型</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hb_model_info yolo11n_detect_nashe_640x640_nv12.hbm</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_04/ab1e1338400d2a08f9393a3ed7f0618f_ab1e1338400d2a08f9393a3ed7f0618f.png" alt=""></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">2026-01-04 16:39:47,687 INFO <span class="comment">############# Model input/output info #############</span></span><br><span class="line">2026-01-04 16:39:47,687 INFO NAME      TYPE   SHAPE            DATA_TYPE</span><br><span class="line">2026-01-04 16:39:47,687 INFO --------- ------ ---------------- ---------</span><br><span class="line">2026-01-04 16:39:47,687 INFO images_y  input  [1, 640, 640, 1] UINT8</span><br><span class="line">2026-01-04 16:39:47,687 INFO images_uv input  [1, 320, 320, 2] UINT8</span><br><span class="line">2026-01-04 16:39:47,687 INFO output0   output [1, 80, 80, 80]  FLOAT32</span><br><span class="line">2026-01-04 16:39:47,687 INFO 499       output [1, 80, 80, 64]  INT32</span><br><span class="line">2026-01-04 16:39:47,687 INFO 513       output [1, 40, 40, 80]  FLOAT32</span><br><span class="line">2026-01-04 16:39:47,688 INFO 521       output [1, 40, 40, 64]  INT32</span><br><span class="line">2026-01-04 16:39:47,688 INFO 535       output [1, 20, 20, 80]  FLOAT32</span><br><span class="line">2026-01-04 16:39:47,688 INFO 543       output [1, 20, 20, 64]  INT32</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br></pre></td><td class="code"><pre><span class="line">sunrise@ubuntu:~/main/2026/test_hbm/build$ ./test_hbm_info /opt/hobot/model/s100/basic/yolo11n_detect_nashe_640x640_nv12.hbm</span><br><span class="line">[UCP]: <span class="built_in">log</span> level = 3</span><br><span class="line">[UCP]: UCP version = 3.7.3</span><br><span class="line">[VP]: <span class="built_in">log</span> level = 3</span><br><span class="line">[DNN]: <span class="built_in">log</span> level = 3</span><br><span class="line">[HPL]: <span class="built_in">log</span> level = 3</span><br><span class="line">[UCPT]: <span class="built_in">log</span> level = 6</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  UCP HBM模型测试工具</span><br><span class="line">============================================================</span><br><span class="line">  模型路径: /opt/hobot/model/s100/basic/yolo11n_detect_nashe_640x640_nv12.hbm</span><br><span class="line">  测试推理: 否</span><br><span class="line">  测试内存: 否</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 1: 加载模型</span><br><span class="line">============================================================</span><br><span class="line">[BPU][[BPU_MONITOR]][281472937720128][INFO]BPULib verison(2, 1, 2)[0d3f195]!</span><br><span class="line">[DNN] HBTL_EXT_DNN <span class="built_in">log</span> level:6</span><br><span class="line">[DNN]: 3.7.3_(4.2.11 HBRT)</span><br><span class="line">  ✓ 模型加载成功, 耗时: 349 ms</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 2: 获取模型名称列表</span><br><span class="line">============================================================</span><br><span class="line">  模型数量: 1</span><br><span class="line">  模型[0]: yolo11n_detect_nashe_640x640_nv12</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 3: 获取模型句柄</span><br><span class="line">============================================================</span><br><span class="line">  ✓ 已获取模型句柄: yolo11n_detect_nashe_640x640_nv12</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 4: 获取输入输出数量</span><br><span class="line">============================================================</span><br><span class="line">  输入张量数量: 2</span><br><span class="line">  输出张量数量: 6</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 5: 获取输入张量详细属性</span><br><span class="line">============================================================</span><br><span class="line">  输入名称[0]: images_y</span><br><span class="line"></span><br><span class="line">  [输入 Tensor 0]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 640, 640, 1)</span><br><span class="line">  → 张量类型: 3 - HB_DNN_IMG_TYPE_NV12 (NV12图像格式)</span><br><span class="line">  → 量化类型: 0 - NONE (无量化)</span><br><span class="line">  → 量化轴: 0</span><br><span class="line">  → 对齐后字节大小: -1 bytes</span><br><span class="line">  → Stride信息: (-1, -1, 1, 1)</span><br><span class="line">  → 元素总数: 409600</span><br><span class="line">  输入名称[1]: images_uv</span><br><span class="line"></span><br><span class="line">  [输入 Tensor 1]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 320, 320, 2)</span><br><span class="line">  → 张量类型: 3 - HB_DNN_IMG_TYPE_NV12 (NV12图像格式)</span><br><span class="line">  → 量化类型: 0 - NONE (无量化)</span><br><span class="line">  → 量化轴: 0</span><br><span class="line">  → 对齐后字节大小: -1 bytes</span><br><span class="line">  → Stride信息: (-1, -1, 2, 1)</span><br><span class="line">  → 元素总数: 204800</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 6: 获取输出张量详细属性</span><br><span class="line">============================================================</span><br><span class="line">  输出名称[0]: output0</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 0]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 80, 80, 80)</span><br><span class="line">  → 张量类型: 7 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span><br><span class="line">  → 量化类型: 0 - NONE (无量化)</span><br><span class="line">  → 量化轴: 0</span><br><span class="line">  → 对齐后字节大小: 2048000 bytes</span><br><span class="line">  → Stride信息: (2048000, 25600, 320, 4)</span><br><span class="line">  → 元素总数: 512000</span><br><span class="line">  输出名称[1]: 499</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 1]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 80, 80, 64)</span><br><span class="line">  → 张量类型: 8 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数)</span><br><span class="line">  → 量化类型: 1 - SCALE (缩放量化)</span><br><span class="line">  → 量化轴: 3</span><br><span class="line">  → 量化缩放信息:</span><br><span class="line">    缩放数据长度: 64</span><br><span class="line">    缩放数据 (前10个): 0.000601, 0.000602, 0.000556, 0.000525, 0.000421, 0.000437, 0.000292, 0.000345, 0.000311, 0.000240 ...</span><br><span class="line">    零点偏移长度: 64</span><br><span class="line">    零点偏移数据 (前10个): 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ...</span><br><span class="line">  → 对齐后字节大小: 1638400 bytes</span><br><span class="line">  → Stride信息: (1638400, 20480, 256, 4)</span><br><span class="line">  → 元素总数: 409600</span><br><span class="line">  输出名称[2]: 513</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 2]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 40, 40, 80)</span><br><span class="line">  → 张量类型: 7 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span><br><span class="line">  → 量化类型: 0 - NONE (无量化)</span><br><span class="line">  → 量化轴: 0</span><br><span class="line">  → 对齐后字节大小: 512000 bytes</span><br><span class="line">  → Stride信息: (512000, 12800, 320, 4)</span><br><span class="line">  → 元素总数: 128000</span><br><span class="line">  输出名称[3]: 521</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 3]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 40, 40, 64)</span><br><span class="line">  → 张量类型: 8 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数)</span><br><span class="line">  → 量化类型: 1 - SCALE (缩放量化)</span><br><span class="line">  → 量化轴: 3</span><br><span class="line">  → 量化缩放信息:</span><br><span class="line">    缩放数据长度: 64</span><br><span class="line">    缩放数据 (前10个): 0.000665, 0.000668, 0.000629, 0.000470, 0.000367, 0.000359, 0.000328, 0.000411, 0.000298, 0.000340 ...</span><br><span class="line">    零点偏移长度: 64</span><br><span class="line">    零点偏移数据 (前10个): 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ...</span><br><span class="line">  → 对齐后字节大小: 409600 bytes</span><br><span class="line">  → Stride信息: (409600, 10240, 256, 4)</span><br><span class="line">  → 元素总数: 102400</span><br><span class="line">  输出名称[4]: 535</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 4]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 20, 20, 80)</span><br><span class="line">  → 张量类型: 7 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span><br><span class="line">  → 量化类型: 0 - NONE (无量化)</span><br><span class="line">  → 量化轴: 0</span><br><span class="line">  → 对齐后字节大小: 128000 bytes</span><br><span class="line">  → Stride信息: (128000, 6400, 320, 4)</span><br><span class="line">  → 元素总数: 32000</span><br><span class="line">  输出名称[5]: 543</span><br><span class="line"></span><br><span class="line">  [输出 Tensor 5]</span><br><span class="line">  --------------------------------</span><br><span class="line">  → 有效形状 (validShape):</span><br><span class="line">    维度数量: 4</span><br><span class="line">    形状: (1, 20, 20, 64)</span><br><span class="line">  → 张量类型: 8 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数)</span><br><span class="line">  → 量化类型: 1 - SCALE (缩放量化)</span><br><span class="line">  → 量化轴: 3</span><br><span class="line">  → 量化缩放信息:</span><br><span class="line">    缩放数据长度: 64</span><br><span class="line">    缩放数据 (前10个): 0.000820, 0.000811, 0.000706, 0.000627, 0.000631, 0.000693, 0.000700, 0.000729, 0.000585, 0.000458 ...</span><br><span class="line">    零点偏移长度: 64</span><br><span class="line">    零点偏移数据 (前10个): 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ...</span><br><span class="line">  → 对齐后字节大小: 102400 bytes</span><br><span class="line">  → Stride信息: (102400, 5120, 256, 4)</span><br><span class="line">  → 元素总数: 25600</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">  Step 7: 获取模型描述信息</span><br><span class="line">============================================================</span><br><span class="line">  描述类型: HB_DNN_DESC_TYPE_JSON</span><br><span class="line">  描述大小: 1628 bytes</span><br><span class="line">  描述内容 (前500字符):</span><br><span class="line">  &#123;<span class="string">&quot;BUILDER_VERSION&quot;</span>: <span class="string">&quot;3.3.11&quot;</span>, <span class="string">&quot;HBDK_VERSION&quot;</span>: <span class="string">&quot;4.1.17&quot;</span>, <span class="string">&quot;HBDK_RUNTIME_VERSION&quot;</span>: null, <span class="string">&quot;HORIZON_NN_VERSION&quot;</span>: <span class="string">&quot;2.1.9&quot;</span>, <span class="string">&quot;CAFFE_MODEL&quot;</span>: null, <span class="string">&quot;PROTOTXT&quot;</span>: null, <span class="string">&quot;ONNX_MODEL&quot;</span>: <span class="string">&quot;/open_explorer/ws_0508/ws_yolo11n/yolo11n.onnx&quot;</span>, <span class="string">&quot;MARCH&quot;</span>: <span class="string">&quot;nash-e&quot;</span>, <span class="string">&quot;LAYER_OUT_DUMP&quot;</span>: <span class="string">&quot;False&quot;</span>, <span class="string">&quot;LOG_LEVEL&quot;</span>: null, <span class="string">&quot;WORKING_DIR&quot;</span>: <span class="string">&quot;/open_explorer/ws_0508/ws_yolo11n/bpu_outputs&quot;</span>, <span class="string">&quot;MODEL_PREFIX&quot;</span>: <span class="string">&quot;yolo11n_detect_nashe_640x640_nv12&quot;</span>, <span class="string">&quot;OUTPUT_NODES&quot;</span>: <span class="string">&quot;&quot;</span>, <span class="string">&quot;REMOVE_NODE_TYPE&quot;</span>: <span class="string">&quot;&quot;</span>, <span class="string">&quot;REMOVE_NODE_NAME&quot;</span>: <span class="string">&quot;/model.23/cv2.0/cv2.0.2/Conv;/mod</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string">  Step 8: 格式分析</span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">----------------------------------------</span></span><br><span class="line"><span class="string">  NV12输入格式分析</span></span><br><span class="line"><span class="string">----------------------------------------</span></span><br><span class="line"><span class="string">  ✓ 检测到NV12输入格式</span></span><br><span class="line"><span class="string">  → 模式: 分离NV12 (Y和UV在不同tensor中)</span></span><br><span class="line"><span class="string">  → Y平面 (Tensor 0):</span></span><br><span class="line"><span class="string">      尺寸: 640x640</span></span><br><span class="line"><span class="string">      大小: 409600 bytes</span></span><br><span class="line"><span class="string">  → UV平面 (Tensor 1):</span></span><br><span class="line"><span class="string">      尺寸: 320x320x2</span></span><br><span class="line"><span class="string">      大小: 204800 bytes</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">----------------------------------------</span></span><br><span class="line"><span class="string">  YOLO输出格式分析</span></span><br><span class="line"><span class="string">----------------------------------------</span></span><br><span class="line"><span class="string">  ✓ 检测到6输出YOLO格式 (可能是YOLOv8/v11 检测模型)</span></span><br><span class="line"><span class="string">  → 典型布局: [cls_80x80, bbox_80x80, cls_40x40, bbox_40x40, cls_20x20, bbox_20x20]</span></span><br><span class="line"><span class="string">  → 输出[0]: (1, 80, 80, 80) → 类别分数 (80 classes) @ 80x80 特征图 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span></span><br><span class="line"><span class="string">  → 输出[1]: (1, 80, 80, 64) → bbox回归 (DFL, 4x16) @ 80x80 特征图 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数) (量化)</span></span><br><span class="line"><span class="string">  → 输出[2]: (1, 40, 40, 80) → 类别分数 (80 classes) @ 40x40 特征图 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span></span><br><span class="line"><span class="string">  → 输出[3]: (1, 40, 40, 64) → bbox回归 (DFL, 4x16) @ 40x40 特征图 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数) (量化)</span></span><br><span class="line"><span class="string">  → 输出[4]: (1, 20, 20, 80) → 类别分数 (80 classes) @ 20x20 特征图 - HB_DNN_TENSOR_TYPE_F16 (16位浮点)</span></span><br><span class="line"><span class="string">  → 输出[5]: (1, 20, 20, 64) → bbox回归 (DFL, 4x16) @ 20x20 特征图 - HB_DNN_TENSOR_TYPE_S32 (有符号32位整数) (量化)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string">  Step 9: 释放资源</span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string">  ✓ 资源释放完成</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string">  测试完成</span></span><br><span class="line"><span class="string">============================================================</span></span><br><span class="line"><span class="string">  所有测试通过！</span></span><br></pre></td></tr></table></figure><p>其去除Detect头，并且保留p3,p4,p5输出精度，由cpu进行后处理。所以在导出onnx模型基础上，我们需要手动添加一步去除detect头部分，以保证Detect精度。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> types</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">import</span> torch.nn.functional <span class="keyword">as</span> F</span><br><span class="line"><span class="keyword">import</span> torchvision</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> itertools</span><br><span class="line"><span class="keyword">import</span> einops</span><br><span class="line"><span class="keyword">from</span> einops <span class="keyword">import</span> rearrange</span><br><span class="line"><span class="keyword">from</span> timm.models.layers <span class="keyword">import</span> trunc_normal_</span><br><span class="line"><span class="keyword">from</span> ultralytics.nn.modules <span class="keyword">import</span> Detect</span><br><span class="line"></span><br><span class="line"><span class="comment"># Forward 函数，切去Detect层的cat和decode部分</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">split_head_forward</span>(<span class="params">self, x</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    修改后的 Detect 层 Forward 函数。</span></span><br><span class="line"><span class="string">    不进行 cat 和 decode，直接输出每个 stride 的 cls 和 box 特征图。</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    results = []</span><br><span class="line">    <span class="comment"># x 是 backbone/neck 输出的特征图列表 (P3, P4, P5 或 P3, P4)</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(self.nl): </span><br><span class="line">        <span class="comment"># 输入特征 x[i]</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 1. Cls 分支 (Classification)</span></span><br><span class="line">        <span class="comment"># cls: [B, nc, H, W] → [B, H, W, nc] (NHWC)</span></span><br><span class="line">        cls_feat = self.cv3[i](x[i]).permute(<span class="number">0</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">1</span>).contiguous()</span><br><span class="line">  </span><br><span class="line"></span><br><span class="line">        <span class="comment"># 2. Box 分支 (Regression)</span></span><br><span class="line">        <span class="comment"># bbox: [B, 64, H, W] → [B, H, W, 64] (NHWC)</span></span><br><span class="line">        box_feat = self.cv2[i](x[i]).permute(<span class="number">0</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">1</span>).contiguous()</span><br><span class="line"></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 将两个分支加入结果</span></span><br><span class="line">        <span class="comment"># 注意顺序：官方示例看起来是先 Cls 后 Box，或者反过来</span></span><br><span class="line">        <span class="comment"># 根据你的日志: output0(80ch float) 是 Cls, 499(64ch int32) 是 Box</span></span><br><span class="line">        <span class="comment"># 所以我们按这个顺序返回</span></span><br><span class="line">        results.append(cls_feat)</span><br><span class="line">        results.append(box_feat)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 返回扁平化的列表，导出 ONNX 时会变成多个输出节点</span></span><br><span class="line">    <span class="keyword">return</span> results</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 假设你需要用到 Conv 和 autopad，如果报错找不到，这里做一个简单的 mock</span></span><br><span class="line"><span class="comment"># 或者你可以从 ultralytics 导入它们</span></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">from</span> ultralytics.nn.modules.conv <span class="keyword">import</span> Conv, autopad</span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line">    <span class="comment"># 简单的 fallback 实现，防止报错</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">autopad</span>(<span class="params">k, p=<span class="literal">None</span>, d=<span class="number">1</span></span>):</span><br><span class="line">        <span class="keyword">if</span> d &gt; <span class="number">1</span>:</span><br><span class="line">            k = d * (k - <span class="number">1</span>) + <span class="number">1</span> <span class="keyword">if</span> <span class="built_in">isinstance</span>(k, <span class="built_in">int</span>) <span class="keyword">else</span> [d * (x - <span class="number">1</span>) + <span class="number">1</span> <span class="keyword">for</span> x <span class="keyword">in</span> k]</span><br><span class="line">        <span class="keyword">if</span> p <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            p = k // <span class="number">2</span> <span class="keyword">if</span> <span class="built_in">isinstance</span>(k, <span class="built_in">int</span>) <span class="keyword">else</span> [x // <span class="number">2</span> <span class="keyword">for</span> x <span class="keyword">in</span> k]</span><br><span class="line">        <span class="keyword">return</span> p</span><br><span class="line"></span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">Conv</span>(nn.Module):</span><br><span class="line">        <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, c1, c2, k=<span class="number">1</span>, s=<span class="number">1</span>, p=<span class="literal">None</span>, g=<span class="number">1</span>, d=<span class="number">1</span>, act=<span class="literal">True</span></span>):</span><br><span class="line">            <span class="built_in">super</span>().__init__()</span><br><span class="line">            self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), dilation=d, groups=g, bias=<span class="literal">False</span>)</span><br><span class="line">            self.bn = nn.BatchNorm2d(c2)</span><br><span class="line">            self.act = nn.SiLU() <span class="keyword">if</span> act <span class="keyword">is</span> <span class="literal">True</span> <span class="keyword">else</span> (act <span class="keyword">if</span> <span class="built_in">isinstance</span>(act, nn.Module) <span class="keyword">else</span> nn.Identity())</span><br><span class="line">        <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">            <span class="keyword">return</span> self.act(self.bn(self.conv(x)))</span><br><span class="line"></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 1. 在这里粘贴你提供的所有 Attention 类定义 (为了节省篇幅，我只列出 CoordAtt)</span></span><br><span class="line"><span class="comment">#    请务必把你上面发给我的那一大段代码完整粘贴替换下面的区域！</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里必须包含 h_swish 和 h_sigmoid，因为 CoordAtt 用到了</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">h_sigmoid</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inplace=<span class="literal">True</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(h_sigmoid, self).__init__()</span><br><span class="line">        self.relu = nn.ReLU6(inplace=inplace)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="keyword">return</span> self.relu(x + <span class="number">3</span>) / <span class="number">6</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">h_swish</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inplace=<span class="literal">True</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(h_swish, self).__init__()</span><br><span class="line">        self.sigmoid = h_sigmoid(inplace=inplace)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="keyword">return</span> x * self.sigmoid(x)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 你的 CoordAtt 类</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CoordAtt</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, inp, reduction=<span class="number">32</span></span>):</span><br><span class="line">        <span class="built_in">super</span>(CoordAtt, self).__init__()</span><br><span class="line">        self.pool_h = nn.AdaptiveAvgPool2d((<span class="literal">None</span>, <span class="number">1</span>))</span><br><span class="line">        self.pool_w = nn.AdaptiveAvgPool2d((<span class="number">1</span>, <span class="literal">None</span>))</span><br><span class="line"></span><br><span class="line">        mip = <span class="built_in">max</span>(<span class="number">8</span>, inp // reduction)</span><br><span class="line"></span><br><span class="line">        self.conv1 = nn.Conv2d(inp, mip, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line">        self.bn1 = nn.BatchNorm2d(mip)</span><br><span class="line">        self.act = h_swish()</span><br><span class="line"></span><br><span class="line">        self.conv_h = nn.Conv2d(mip, inp, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line">        self.conv_w = nn.Conv2d(mip, inp, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        identity = x</span><br><span class="line"></span><br><span class="line">        n, c, h, w = x.size()</span><br><span class="line">        x_h = self.pool_h(x)</span><br><span class="line">        x_w = self.pool_w(x).permute(<span class="number">0</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">        y = torch.cat([x_h, x_w], dim=<span class="number">2</span>)</span><br><span class="line">        y = self.conv1(y)</span><br><span class="line">        y = self.bn1(y)</span><br><span class="line">        y = self.act(y)</span><br><span class="line"></span><br><span class="line">        x_h, x_w = torch.split(y, [h, w], dim=<span class="number">2</span>)</span><br><span class="line">        x_w = x_w.permute(<span class="number">0</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">        a_h = self.conv_h(x_h).sigmoid()</span><br><span class="line">        a_w = self.conv_w(x_w).sigmoid()</span><br><span class="line"></span><br><span class="line">        out = identity * a_w * a_h</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> out</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DWConvblock</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;Depthwise conv + Pointwise conv&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_channels, out_channels, k, s</span>):</span><br><span class="line">        <span class="built_in">super</span>(DWConvblock, self).__init__()</span><br><span class="line">        self.p = k // <span class="number">2</span></span><br><span class="line">        self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=k, stride=s, padding=self.p, groups=in_channels,</span><br><span class="line">                               bias=<span class="literal">False</span>)</span><br><span class="line">        self.bn1 = nn.BatchNorm2d(in_channels)</span><br><span class="line">        self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=<span class="number">1</span>, stride=<span class="number">1</span>, padding=<span class="number">0</span>, bias=<span class="literal">False</span>)</span><br><span class="line">        self.bn2 = nn.BatchNorm2d(out_channels)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = self.conv1(x)</span><br><span class="line">        x = self.bn1(x)</span><br><span class="line">        x = F.relu(x)</span><br><span class="line">        x = self.conv2(x)</span><br><span class="line">        x = self.bn2(x)</span><br><span class="line">        x = F.relu(x)</span><br><span class="line">        <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># ... (请务必把 EMA, SimAM 等其他所有你可能用到的类都粘在这里，以防万一) ...</span></span><br><span class="line"><span class="comment"># 如果你确定只用了 CoordAtt，那上面这些就够了。如果不确定，建议全部粘贴。</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 2. 核心欺骗步骤：构造虚拟模块</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建一个虚拟的 module 对象</span></span><br><span class="line">fake_attention_module = types.ModuleType(<span class="string">&#x27;ultralytics.nn.modules.attention&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将定义好的类挂载到这个虚拟 module 上</span></span><br><span class="line">fake_attention_module.CoordAtt = CoordAtt</span><br><span class="line">fake_attention_module.h_swish = h_swish</span><br><span class="line">fake_attention_module.h_sigmoid = h_sigmoid</span><br><span class="line"><span class="comment"># 如果还有其他类，例如 fake_attention_module.EMA = EMA</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 将虚拟 module 注入系统 sys.modules</span></span><br><span class="line"><span class="comment"># 这样 PyTorch 加载模型时寻找 &#x27;ultralytics.nn.modules.attention&#x27; 就会找到这里</span></span><br><span class="line">sys.modules[<span class="string">&#x27;ultralytics.nn.modules.attention&#x27;</span>] = fake_attention_module</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 导入 DWConvblock 到 ultralytics.nn.modules.block 中</span></span><br><span class="line"><span class="keyword">import</span> ultralytics.nn.modules.block</span><br><span class="line">ultralytics.nn.modules.block.DWConvblock = DWConvblock</span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># 3. 正常执行 YOLO 导出逻辑</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    <span class="comment"># 加载你训练好的 YOLOv11 模型</span></span><br><span class="line">    pt_file = <span class="string">&quot;model/yolo11_C2PSAtoC3k2_DWConvblock_CBAM-RGB/best.pt&quot;</span>  <span class="comment"># ← 改成你的 .pt 路径</span></span><br><span class="line"></span><br><span class="line">    model = YOLO(pt_file)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 替换 Detect 层的 forward 方法</span></span><br><span class="line">    Detect.forward = split_head_forward</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 导出 ONNX（RDK S100 兼容模式）</span></span><br><span class="line">    model.export(</span><br><span class="line">        <span class="built_in">format</span>=<span class="string">&quot;onnx&quot;</span>,</span><br><span class="line">        imgsz=<span class="number">640</span>,          <span class="comment"># 必须和训练时一致</span></span><br><span class="line">        batch=<span class="number">1</span>,            <span class="comment"># 固定 batch=1（RDK 推荐）</span></span><br><span class="line">        opset=<span class="number">11</span>,           <span class="comment"># ⚠️ 必须为 11！</span></span><br><span class="line">        dynamic=<span class="literal">False</span>,      <span class="comment"># 关闭动态 shape（避免 BPU 不支持）</span></span><br><span class="line">        simplify=<span class="literal">True</span>,      <span class="comment"># 优化图（移除冗余节点）</span></span><br><span class="line">        nms=<span class="literal">False</span>,          <span class="comment"># 先不带 NMS（RDK BPU 可能不支持 NonMaxSuppression）</span></span><br><span class="line">        device=<span class="string">&quot;cpu&quot;</span>        <span class="comment"># 导出时用 CPU 避免 GPU 干扰</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;✅ YOLOv11 ONNX 已生成: <span class="subst">&#123;pt_file.replace(<span class="string">&#x27;.pt&#x27;</span>, <span class="string">&#x27;.onnx&#x27;</span>)&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p><code>P3 (Small / 80x80)</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_04/image_804e0cf9f75fd49bb671c9697afc086f.png" alt=""></p><p><code>P4 (Medium / 40x40)</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_04/image_6a46aebd9c5adc623cbe39702157e4c0.png" alt=""></p><p><code>P5 (Large / 20x20)</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_04/image_b0678cd9b165c2e257f2e385a1472616.png" alt=""></p><h4 id="工具链量化">工具链量化</h4><p><strong>检查数据集</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line">cal_dir = <span class="string">&quot;./calibration_data&quot;</span></span><br><span class="line">files = <span class="built_in">sorted</span>([f <span class="keyword">for</span> f <span class="keyword">in</span> os.listdir(cal_dir) <span class="keyword">if</span> f.endswith(<span class="string">&#x27;.npy&#x27;</span>)])</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Total calibration files: <span class="subst">&#123;<span class="built_in">len</span>(files)&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(files) == <span class="number">0</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;❌ ERROR: No calibration files found!&quot;</span>)</span><br><span class="line">    exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查前3个文件</span></span><br><span class="line"><span class="keyword">for</span> i, fname <span class="keyword">in</span> <span class="built_in">enumerate</span>(files[:<span class="number">3</span>]):</span><br><span class="line">    data = np.load(os.path.join(cal_dir, fname))</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;\nFile <span class="subst">&#123;i&#125;</span>: <span class="subst">&#123;fname&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Shape: <span class="subst">&#123;data.shape&#125;</span>&quot;</span>)           <span class="comment"># 应该是 (3, 640, 640)</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Dtype: <span class="subst">&#123;data.dtype&#125;</span>&quot;</span>)           <span class="comment"># 应该是 float32</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Value range: [<span class="subst">&#123;data.<span class="built_in">min</span>():<span class="number">.2</span>f&#125;</span>, <span class="subst">&#123;data.<span class="built_in">max</span>():<span class="number">.2</span>f&#125;</span>]&quot;</span>)  <span class="comment"># 应该是 [0, 255]</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  Mean per channel (RGB): R=<span class="subst">&#123;data[<span class="number">0</span>].mean():<span class="number">.1</span>f&#125;</span>, G=<span class="subst">&#123;data[<span class="number">1</span>].mean():<span class="number">.1</span>f&#125;</span>, B=<span class="subst">&#123;data[<span class="number">2</span>].mean():<span class="number">.1</span>f&#125;</span>&quot;</span>)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 验证值范围</span></span><br><span class="line">    <span class="keyword">if</span> data.<span class="built_in">min</span>() &lt; <span class="number">0</span> <span class="keyword">or</span> data.<span class="built_in">max</span>() &gt; <span class="number">1</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;  ⚠️ WARNING: Value range incorrect!&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> data.shape != (<span class="number">3</span>, <span class="number">640</span>, <span class="number">640</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;  ⚠️ WARNING: Shape incorrect!&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> data.dtype != np.float32:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;  ⚠️ WARNING: Dtype incorrect!&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;\n✅ Verification complete&quot;</span>)</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_05/a5445f9fa089d70bc785d3d97891cdb4_a5445f9fa089d70bc785d3d97891cdb4.png" alt=""></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 模型参数组</span></span><br><span class="line"><span class="attr">model_parameters:</span></span><br><span class="line">  <span class="attr">onnx_model:</span> <span class="string">&quot;best.onnx&quot;</span></span><br><span class="line">  <span class="attr">march:</span> <span class="string">&quot;nash-m&quot;</span>                     <span class="comment"># S100P 用 nash-m，S100 用 nash-e</span></span><br><span class="line">  <span class="attr">output_model_file_prefix:</span> <span class="string">&quot;yolo11&quot;</span></span><br><span class="line">  <span class="attr">working_dir:</span> <span class="string">&quot;./model_output&quot;</span></span><br><span class="line">  <span class="comment"># remove_node_name: &quot;474;494;514&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 输入信息参数组</span></span><br><span class="line"><span class="attr">input_parameters:</span></span><br><span class="line">  <span class="attr">input_name:</span> <span class="string">&quot;images&quot;</span>                <span class="comment"># ONNX 模型的输入节点名（用 netron 查看）</span></span><br><span class="line">  <span class="attr">input_type_train:</span> <span class="string">&quot;rgb&quot;</span>             <span class="comment"># 校准数据是rgb</span></span><br><span class="line">  <span class="attr">input_type_rt:</span> <span class="string">&quot;rgb&quot;</span>                <span class="comment"># 运行时也用 BGR（关键！）</span></span><br><span class="line">  <span class="attr">input_layout_train:</span> <span class="string">&quot;NCHW&quot;</span>          <span class="comment"># YOLOv8/v11 通常是 NCHW</span></span><br><span class="line">  <span class="attr">input_shape:</span> <span class="string">&quot;1x3x640x640&quot;</span>          <span class="comment"># 根据你的模型实际输入改</span></span><br><span class="line">  <span class="attr">input_batch:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">scale_value:</span> <span class="string">&quot;0.003921568627451&quot;</span>    <span class="comment"># = 1/255，如果训练时归一化到 [0,1]</span></span><br><span class="line">  <span class="attr">norm_type:</span> <span class="string">&#x27;data_scale&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 校准参数组</span></span><br><span class="line"><span class="attr">calibration_parameters:</span></span><br><span class="line">  <span class="attr">calibration_type:</span> <span class="string">&#x27;default&#x27;</span></span><br><span class="line">  <span class="attr">cal_data_dir:</span> <span class="string">&quot;./calibration_data&quot;</span>        <span class="comment"># 必须存在且包含校准图片</span></span><br><span class="line">  <span class="attr">cal_data_type:</span> <span class="string">&#x27;float32&#x27;</span></span><br><span class="line">  <span class="attr">quant_config:</span> &#123;<span class="attr">&quot;op_config&quot;:</span> &#123;<span class="attr">&quot;softmax&quot;:</span> &#123;<span class="attr">&quot;qtype&quot;:</span> <span class="string">&quot;int8&quot;</span>&#125;&#125;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 编译参数组</span></span><br><span class="line"><span class="attr">compiler_parameters:</span></span><br><span class="line">  <span class="attr">extra_params:</span> &#123;<span class="attr">&#x27;input_no_padding&#x27;:</span> <span class="literal">True</span>, <span class="attr">&#x27;output_no_padding&#x27;:</span> <span class="literal">True</span>&#125;</span><br><span class="line">  <span class="attr">compile_mode:</span> <span class="string">&quot;latency&quot;</span></span><br><span class="line">  <span class="attr">core_num:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">optimize_level:</span> <span class="string">&quot;O2&quot;</span></span><br><span class="line">  <span class="attr">jobs:</span> <span class="number">16</span>                     <span class="comment"># 并行编译线程数</span></span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2026/01_05/ef5241a0b5911848ba6716e9f4747f0d_ef5241a0b5911848ba6716e9f4747f0d.png" alt=""></p><h2 id="模型推理">模型推理</h2><p><a href="https://github.com/51hhh/RDK-S100p-BPU-yolo/tree/main">51hhh/RDK-S100p-BPU-yolo: RDK</a></p>]]></content>
    
    
    <summary type="html">资料
dtop

Jetson有Jtop,Linux有Htop,RDK也有Dtop！ - 板卡使用 - 地瓜机器人论坛
[https://forum.d-robotics.cc/t/topic/31957]

模型性能调优 - OpenExplorer
[https://toolchain.d-robotics.cc/guide/tune_content/performance_tune.html]

参考教程</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>wsl安装isaac gym</title>
    <link href="https://polar-bear.eu.org/2025/11/12/wsl-an-zhuang-isaac-gym/"/>
    <id>https://polar-bear.eu.org/2025/11/12/wsl-an-zhuang-isaac-gym/</id>
    <published>2025-11-12T03:04:44.842Z</published>
    <updated>2025-11-30T01:41:04.586Z</updated>
    
    <content type="html"><![CDATA[<h3 id="安装wsl2-ubuntu20-04">安装wsl2 ubuntu20.04</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wsl --install -d Ubuntu-20.04</span><br></pre></td></tr></table></figure><h3 id="安装conda">安装conda</h3><p><a href="https://www.anaconda.com/download/success#">Download Success | Anaconda</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> ~/download</span><br><span class="line"><span class="built_in">cd</span> ~/download</span><br><span class="line">wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bash ./Miniconda3-latest-Linux-x86_64.sh</span><br></pre></td></tr></table></figure><p>一路默认安装即可</p><p>激活环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><h3 id="安装CUDA">安装CUDA</h3><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_2dab3eef8e3d841d83cf16e8638c856f.png" alt=""></p><p>选择与window相同版本的cuda_12.1.0</p><p>需要安装历史存档，CUDA版本低于12.1.0</p><p><a href="https://developer.nvidia.com/cuda-toolkit-archive">CUDA Toolkit Archive | NVIDIA Developer</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.0-1_all.deb</span><br><span class="line">sudo dpkg -i cuda-keyring_1.0-1_all.deb</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get -y install cuda</span><br></pre></td></tr></table></figure><p>查看仓库中所有可安装的 CUDA 版本（以<code>cuda-</code>开头）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt list | grep -E <span class="string">&#x27;^cuda-[0-9]&#x27;</span></span><br></pre></td></tr></table></figure><p>安装该版本 CUDA：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get -y install cuda-12-1</span><br></pre></td></tr></table></figure><p>安装nvcc</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install cuda-toolkit-12-1</span><br></pre></td></tr></table></figure><p>打开配置文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nano ~/.bashrc</span><br></pre></td></tr></table></figure><p>在文件最末尾添加以下两行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PATH=/usr/local/cuda-12.1/bin:<span class="variable">$PATH</span></span><br><span class="line"><span class="built_in">export</span> LD_LIBRARY_PATH=/usr/lib/wsl/lib/:<span class="variable">$LD_LIBRARY_PATH</span></span><br></pre></td></tr></table></figure><p>保存退出（按 <code>Ctrl+O</code> 回车保存，按 <code>Ctrl+X</code> 退出）。</p><p>刷新环境变量使其立即生效：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">nvidia-smi</span><br><span class="line"></span><br><span class="line"><span class="comment">## 查看CUDA版本</span></span><br><span class="line">nvcc --version</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_d4ab3a5c0705e030102a7ae23f68a975.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_33520508b2f53c8cf7e58c412d288d35.png" alt=""><img src="" alt=""></p><p>这里的CUDA版本表示GPU 支持的最高 CUDA 版本，并非nvcc版本。</p><h3 id="创建conda环境">创建conda环境</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">conda create -n rl python=3.8.10</span><br><span class="line">conda activate rl</span><br></pre></td></tr></table></figure><p>安装对应cuda版本pytorch</p><p>在pytorch查询对应cuda版本的pytorch，<a href="https://pytorch.org/get-started/previous-versions/">之前的PyTorch版本</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda install pytorch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 pytorch-cuda=12.1 -c pytorch -c nvidia</span><br></pre></td></tr></table></figure><p>验证pytorch</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="built_in">print</span>(torch.__version__)</span><br><span class="line"><span class="built_in">print</span>(torch.cuda.is_available())</span><br></pre></td></tr></table></figure><p>安装依赖</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">pip install torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install pyquaternion -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install pyyaml -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install pexpect -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install einops -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install tqdm -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install packaging -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install h5py -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install ipython -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install getkey -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install wandb -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install chardet -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install numpy==1.23.2 -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install h5py_cache -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install tensorboard -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">pip install onnxruntime</span><br></pre></td></tr></table></figure><h3 id="配置ssh">配置ssh</h3><p>Ubuntu20.04子系统自带的ssh服务无法连接，需卸载后重新安装。</p><p>卸载ssh服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt remove openssh-server</span><br></pre></td></tr></table></figure><p>重装ssh服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt install openssh-server</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nano /etc/ssh/sshd_config</span><br></pre></td></tr></table></figure><p>确保以下配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Port 22                   <span class="comment"># 默认端口</span></span><br><span class="line">ListenAddress 0.0.0.0     <span class="comment"># 允许所有 IP 连接</span></span><br><span class="line">PasswordAuthentication <span class="built_in">yes</span> <span class="comment"># 启用密码登录</span></span><br><span class="line">PermitRootLogin <span class="built_in">yes</span>       <span class="comment"># 允许 root 登录（按需调整）</span></span><br><span class="line"><span class="comment"># X11</span></span><br><span class="line">X11Forwarding <span class="built_in">yes</span></span><br><span class="line">X11UseLocalhost no</span><br></pre></td></tr></table></figure><p>重启ssh服务</p><p><code>sudo service ssh restart</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_12/image_5e732ad245b2779b674719d04adede88.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_12/image_e4ce0ca403ff94e49f67b84e01307347.png" alt=""></p><h3 id="安装vulkan">安装vulkan</h3><p>教程：<a href="https://zhuanlan.zhihu.com/p/576320322">【记录】在WSL2中部署Vulkan开发环境（2022年版） - 知乎</a></p><p><a href="https://www.cnblogs.com/erbws/p/18888083#vulkan">在 WSL2 上配置 Isaac Gym 宇树机器人强化学习环境 - ErBW_s - 博客园</a></p><p>使用命令<code>sudo apt-get install xfce4</code> 安装xfce4桌面环境</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_6d7b2daef9cca6b4f0eacc6a316ac40e.png" alt=""></p><p>选择gdm3即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nano ~/.bashrc</span><br></pre></td></tr></table></figure><p>将以下命令添加到bashrc文件末尾：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> DISPLAY=$(awk <span class="string">&#x27;/nameserver / &#123;print $2; exit&#125;&#x27;</span> /etc/resolv.conf 2&gt;/dev/null):0</span><br><span class="line"><span class="built_in">export</span> LIBGL_ALWAYS_INDIRECT=1</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><p>完成后使用命令<code>sudo xfce4-session</code> 启动xfce4桌面环境</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_87beae51c649860a679b6c8fde6e34fc.png" alt=""></p><p><strong>注意：之后的操作都要在xfce桌面终端执行</strong></p><p>安装Vulkan</p><p><a href="https://packages.lunarg.com/#">LunarG VulkanSDK Packages</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -</span><br><span class="line">sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.3.283-focal.list https://packages.lunarg.com/vulkan/1.3.283/lunarg-vulkan-1.3.283-focal.list</span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt install vulkan-sdk</span><br></pre></td></tr></table></figure><p>这时运行 <code>vulkaninfo --summary</code> 会发现在使用 CPU (llvmpipe) 而不是 NVIDIA GPU，这是因为 WSL2 内置的 mesa 是 CPU 实现，我们需要使用第三方 mesa 源来启用 GPU</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_12/image_09ba32c0501305a7c742f57be2adb0dd.png" alt=""></p><p>在xfce4终端执行以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo add-apt-repository ppa:kisak/kisak-mesa</span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt upgrade</span><br></pre></td></tr></table></figure><p>如果缺失<code>dzn_icd.x86_64.json</code>可以尝试更换ppa源,但是速度较慢</p><p><a href="https://forums.developer.nvidia.com/t/vulkan-fails-to-detect-nvidia-gpu-on-wsl2-ubuntu-24-04-dzn-driver-files-missing-tested-on-multiple-systems/342142/4">Vulkan Fails to Detect NVIDIA GPU on WSL2 Ubuntu 24.04 - `dzn` Driver Files Missing (Tested on multiple systems) - Graphics / Linux / Linux - NVIDIA Developer Forums</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo add-apt-repository ppa:kisak/turtle</span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt upgrade</span><br></pre></td></tr></table></figure><p>在当前版本命令执行时应该会显示mesa需要更新，更新时速度较慢，耐心等待更新完成后理论上你可以在<code>ls /usr/share/vulkan/icd.d/</code>下找到4个json文件：</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_12/image_dbea394c1cad797e71a6f648ea9c4364.png" alt=""></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/dzn_icd.x86_64.json vulkaninfo</span><br></pre></td></tr></table></figure><p>现在查看<code>vulkaninfo --summary</code>,Vulkan运行时才算是真正调度起了GPU</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_12/image_2b766026a256c2de9193cd272dbd7521.png" alt=""></p><h3 id="安装Isaac-gym">安装Isaac gym</h3><p>下载并且解压<a href="https://developer.nvidia.com/isaac-gym/download">Isaac Gym - Download Archive | NVIDIA Developer</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -zxvf IsaacGym_Preview_4_Package.tar.gz</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/isaac-sim/IsaacGymEnvs.git</span><br></pre></td></tr></table></figure><p>安装依赖</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pip install -e ./isaacgym/python</span><br><span class="line">pip install -e ./IsaacGymEnvs</span><br></pre></td></tr></table></figure><p>验证isaacgym</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import isaacgym</span><br><span class="line">quit()</span><br></pre></td></tr></table></figure><p>可能遇到无法找到或加载其运行所需的 NVIDIA CUDA 动态链接库 (<code>libcuda.so</code> 或类似文件) 以及 PhysX 物理引擎库</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_ebc2ee4918ede07f5d6a02c2bfb61721.png" alt=""></p><p>寻找对应的库文件并复制到 <code>/usr/lib/x86_64-linux-gnu</code> 文件夹中</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">find / -name libpython3.8.so.1.0</span><br><span class="line">sudo <span class="built_in">cp</span> /home/rick/miniconda3/envs/rl/lib/libpython3.8.so.1.0 /usr/lib/x86_64-linux-gnu</span><br></pre></td></tr></table></figure><p>没有PhysX 物理引擎库，意思是没有安装 Vulkan，安装 Vulkan即可。</p><p>测试倒立摆</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python ./IsaacGymEnvs/isaacgymenvs/train.py task=Cartpole</span><br></pre></td></tr></table></figure><h3 id="mujoco">mujoco</h3><p><a href="https://blog.csdn.net/weixin_41231535/article/details/124974794">在WSL上安装MuJoCo和mujoco_py_error: opengl version 1.5 or higher required-CSDN博客</a></p><p>安装</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> ~/.mujoco</span><br><span class="line"><span class="built_in">cd</span> ~/.mujoco</span><br><span class="line">wget https://mujoco.org/download/mujoco210-linux-x86_64.tar.gz</span><br><span class="line">tar -zxvf mujoco210-linux-x86_64.tar.gz</span><br><span class="line"><span class="built_in">export</span> LD_LIBRARY_PATH=~/.mujoco/mujoco200/bin/</span><br></pre></td></tr></table></figure><p>运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ./mujoco210/bin</span><br><span class="line">./simulate ../model/humanoid.xml</span><br></pre></td></tr></table></figure><p>不出意外会缺少openGL</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_c65d69f8605441a96cc61922c97f09eb.png" alt=""></p><p>安装即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install libgl1-mesa-dev freeglut3-dev libglu1-mesa-dev</span><br><span class="line">sudo apt install libsoil-dev libglm-dev libassimp-dev libglew-dev libglfw3-dev libxinerama-dev libxcursor-dev libxi-dev</span><br></pre></td></tr></table></figure><p>测试</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install x11-apps mesa-utils</span><br><span class="line">glxgears</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_25ec2b6493ab3b750984ee3eebcbf199.png" alt=""></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nano ~/.bashrc</span><br></pre></td></tr></table></figure><p>添加配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> MESA_GL_VERSION_OVERRIDE=3.3</span><br><span class="line"><span class="built_in">unset</span> LIBGL_ALWAYS_INDIRECT</span><br></pre></td></tr></table></figure><p>生效</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><p>再次运行<code>mujoco</code>即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./simulate ../model/humanoid.xml</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/11_30/image_dd6b2136b9c0603fce36eaf01696975b.png" alt=""></p>]]></content>
    
    
    <summary type="html">安装WSL2 UBUNTU20.04
1


wsl --install -d Ubuntu-20.04


安装COND</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>exo</title>
    <link href="https://polar-bear.eu.org/2025/08/26/exo/"/>
    <id>https://polar-bear.eu.org/2025/08/26/exo/</id>
    <published>2025-08-26T23:08:40.988Z</published>
    <updated>2025-08-26T23:10:11.414Z</updated>
    
    <content type="html"><![CDATA[<h2 id="exo日常设备在家中运行您自己的-AI-集群">exo日常设备在家中运行您自己的 AI 集群</h2><p><a href="https://github.com/exo-explore/exo">exo-explore/exo：使用日常设备📱💻 🖥️⌚在家中运行您自己的 AI 集群</a></p><p>EXO 根据当前的网络拓扑和可用设备资源对模型进行最佳拆分。这使您能够运行比在任何单个设备上运行更大的模型。</p><h3 id="先决条件">先决条件</h3><ul><li>Python&gt;=3.12.0 是必需的，因为以前版本中的 <a href="https://github.com/exo-explore/exo/issues/5">asyncio 存在问题</a>。</li><li>对于支持 NVIDIA GPU 的 Linux（仅限 Linux，如果不使用 Linux 或 NVIDIA，请跳过）：<ul><li>NVIDIA 驱动程序 - 使用<code>nvidia-smi</code></li><li>CUDA 工具包 - 从 NVIDIA CUDA 指南安装，使用<code>nvcc --version</code></li><li>cuDNN 库 - 从 <a href="https://developer.nvidia.com/cudnn-downloads">NVIDIA cuDNN 页面</a>下载，按照<a href="https://docs.nvidia.com/deeplearning/cudnn/latest/installation/linux.html#verifying-the-install-on-linux:~:text=at%20a%20time.-,Verifying%20the%20Install%20on%20Linux,Test%20passed!,-Upgrading%20From%20Older">以下步骤</a>验证安装</li></ul></li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_27/image_260defdd8a71c380aced268401ebe54d.png" alt=""></p><p>确保nvidia-smi，nvcc，cuDNN配置正确，缺一不可。</p><ul><li>运行 exo 的唯一要求是所有设备上都有足够的内存，以便将整个模型放入内存中。例如，如果您运行的是 llama 3.1 8B （fp16），则所有设备都需要 16GB 内存。以下任何配置都可以工作，因为它们的内存总数超过 16GB：<ul><li>2 个 8GB M3 MacBook Air</li><li>1 x 16GB NVIDIA RTX 4070 Ti 笔记本电脑</li><li>2 个 Raspberry Pi 400，每个 4GB RAM（在 CPU 上运行）+ 1 个 8GB Mac Mini</li></ul></li><li>EXO 旨在在具有异构功能的设备上运行。例如，您可以让一些设备配备强大的 GPU，而其他设备则配备集成 GPU 甚至 CPU。添加功能较差的设备会减慢单个推理延迟，但会增加集群的整体吞吐量。</li></ul><h3 id="从docker开始">从docker开始</h3><p>从最简基础镜像nanozoo/python3.12开始</p><p><code>docker pull nanozoo/python3.12:3.12--d46ab4d</code></p><p>启动临时容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name exo_builder_temp \</span><br><span class="line">  python:3.12 \</span><br><span class="line">  bash</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><code>-it</code>: 启动一个交互式（<code>i</code>）终端（<code>t</code>）。</li><li><code>--name exo_builder_temp</code>: 给这个临时容器一个易于识别的名称。</li><li><code>python:3.12</code>: 使用我们指定的基础镜像。</li><li><code>bash</code>: 启动容器后直接进入 Bash shell。</li></ul><h3 id="配置exo">配置exo</h3><p>进入容器，安装必要的系统工具</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">apt-get update</span><br><span class="line">apt-get install -y --no-install-recommends \</span><br><span class="line">    git \</span><br><span class="line">    build-essential \</span><br><span class="line">    cmake \</span><br><span class="line">    ca-certificates \</span><br><span class="line">    libffi-dev \</span><br><span class="line">    libssl-dev \</span><br><span class="line">    libgl1</span><br></pre></td></tr></table></figure><p>清理 apt 缓存，减小最终镜像大小</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -rf /var/lib/apt/lists/*</span><br></pre></td></tr></table></figure><p>创建工作目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /exo</span><br><span class="line"><span class="built_in">cd</span> /exo</span><br></pre></td></tr></table></figure><p>克隆 EXO 仓库</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/exo-explore/exo.git</span><br><span class="line"><span class="built_in">cd</span> exo</span><br></pre></td></tr></table></figure><p>安装 EXO 及其 Python 依赖,<code>--no-cache-dir</code> 用于避免在容器内部创建不必要的pip缓存</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install -e . --no-cache-dir</span><br></pre></td></tr></table></figure><p>退出容器</p><p><code>exit</code></p><p>提交容器状态为镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker commit \</span><br><span class="line">  -c <span class="string">&#x27;WORKDIR /app/exo&#x27;</span> \</span><br><span class="line">  -c <span class="string">&#x27;CMD [&quot;exo&quot;]&#x27;</span> \</span><br><span class="line">  exo_builder_temp \</span><br><span class="line">  exo:20250827</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HF_ENDPOINT=https://hf-mirror.com exo</span><br></pre></td></tr></table></figure><p>可以在启动命令前添加环境变量访问hf镜像站</p><h3 id="创建macvlan网络">创建macvlan网络</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 macnet</span><br></pre></td></tr></table></figure><p><code>docker network create</code> 命令创建了一个新的 Docker 网络，使用了 <code>macvlan</code> 驱动。<code>macvlan</code> 网络允许您将容器连接到物理网络，就像它们是网络上的独立主机一样。您为这个网络指定了以下参数：</p><ul><li><code>-d macvlan</code>：指定网络驱动为 <code>macvlan</code>。</li><li><code>--subnet=192.168.1.0/24</code>：指定网络的子网掩码为 <code>192.168.1.0/24</code>。</li><li><code>--gateway=192.168.1.1</code>：指定网络的网关地址为 <code>192.168.1.1</code>。</li><li><code>-o parent=eth0</code>：指定父接口为 <code>eth0</code>，这是混杂模式下配置的物理网络接口。</li><li><code>macnet</code>：是新创建的 Docker 网络的名称。</li><li><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_27/image_35fbe10cc942a1e452bd856067ef1ed6.png" alt=""></li><li><strong>确保您选择的子网地址没有被路由器、交换机或其他网络设备使用。如果网关地址已被占用，容器将无法正常通信。</strong></li></ul><p>使用<code>ifconfig</code>查看网络设备</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_27/image_8db440f18f9fc8df47b314b4ee5a5517.png" alt=""></p><p>查看子网下设备避免冲突，<code>sudo arp-scan -I enp4s0 --localnet</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_27/image_1d00d89d4de5c4cd070c5a5be2ca613d.png" alt=""></p><h3 id="启动容器">启动容器</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 运行带有 macvlan 网络、GPU 支持和 tinygrad CUDA 环境变量的 EXO 容器</span></span><br><span class="line">docker run -it  \</span><br><span class="line">    --name exo-node-1 \</span><br><span class="line">    --ip 192.168.124.56 \</span><br><span class="line">    --network macnet \</span><br><span class="line">    --gpus all \</span><br><span class="line">    -e CUDA=1 \</span><br><span class="line">    exo:20250827</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">EXO日常设备在家中运行您自己的 AI 集群
exo-explore/exo：使用日常设备📱💻 🖥️⌚在家中运行您自己的 AI 集群
[https://github.com/exo-explore/exo]

EXO 根据当前的网络拓扑和可用设备资源对模型进行最佳拆分。这使您能够运行比在任何单个设备上运行更大的模型。

先决条件
 * Python&gt;=3.12.0 是必需的，因为以前版本中的</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Qwen-image</title>
    <link href="https://polar-bear.eu.org/2025/08/17/qwen-image/"/>
    <id>https://polar-bear.eu.org/2025/08/17/qwen-image/</id>
    <published>2025-08-17T18:42:39.301Z</published>
    <updated>2025-08-20T18:24:46.496Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Qwen-image">Qwen-image</h2><h3 id="docker部署">docker部署</h3><h4 id="安装魔搭社区的modelscope模型管理工具">安装魔搭社区的modelscope模型管理工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install -i https://pypi.tuna.tsinghua.edu.cn/simple modelscope</span><br></pre></td></tr></table></figure><h4 id="下载docker镜像">下载docker镜像</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">modelscope download --model inkcoi/ComfyUI-Qwen-Image --local_dir /home/user/#下载文件位置</span><br></pre></td></tr></table></figure><blockquote><p>镜像文件约40GB,请留有充足储存空间</p></blockquote><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_18/image_23e4ad76b1fec2bf84a57968f7d34241.png" alt=""></p><h4 id="加载Docker镜像">加载Docker镜像</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker load -i ./comfyui-qwen-image-latest.tar</span><br></pre></td></tr></table></figure><p>加载镜像为<code>comfyui-qwen-image      latest     1c856fa3dfd8   10 days ago     42.5GB</code></p><h4 id="运行docker容器">运行docker容器</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --gpus all -d --name comfyui-qwen -p 8188:8188 comfyui-qwen-image:latest python3 main.py --listen 0.0.0.0 </span><br></pre></td></tr></table></figure><p>挂载目录</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">docker run --gpus all -d --name comfyui-qwen -p 8188:8188 \</span><br><span class="line">  -v /home/edzhao/Qwen-image/comfyui_data/models:/ComfyUI/models \</span><br><span class="line">  -v /home/edzhao/Qwen-image/comfyui_data/output:/ComfyUI/output \</span><br><span class="line">  -v /home/edzhao/Qwen-image/comfyui_data/custom_nodes:/ComfyUI/custom_nodes \</span><br><span class="line">  -v /home/edzhao/Qwen-image/comfyui_data/input:/ComfyUI/input \</span><br><span class="line">  comfyui-qwen-image:latest python3 main.py --listen 0.0.0.0</span><br></pre></td></tr></table></figure><p>如果没有GPU，可以添加<code>--cpu</code>参数：</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_18/image_149056b0bb8faf0bc1bb6bc4fe831f48.png" alt=""></p><h2 id="手动处理">手动处理</h2><p>如何遇到依赖错误导致docker容器直接无法启动</p><p><strong>基于这个新的自定义镜像，启动一个临时的、只运行 shell 的容器</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name comfyui_fix_shell_temp --entrypoint /bin/bash comfyui_my_custom_state:latest</span><br></pre></td></tr></table></figure><p><code>-it</code>: 交互式模式。</p><p><code>--name comfyui_fix_shell_temp</code>: 给这个临时容器命名，方便识别。</p><p><code>--entrypoint /bin/bash</code>: 覆盖镜像的默认启动命令，直接启动 shell 环境。</p><p><code>comfyui_my_custom_state:latest</code>: 使用您刚才创建的自定义镜像。</p><p>在**<code>comfyui_fix_shell_temp</code> **中完成修复后，将容器打包为镜像。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker commit f6b773f8bcc7 comfyui_my_custom_state_fixed_final:latest</span><br></pre></td></tr></table></figure><p>之后从镜像启动即可。</p><h3 id="端口转发和监听">端口转发和监听</h3><p>容器需要转发端口，<code>-p 8188:8188</code></p><p>comfyui启动需要<code>python3 main.py --listen 0.0.0.0</code></p>]]></content>
    
    
    <summary type="html">QWEN-IMAGE
DOCKER部署
安装魔搭社区的MODELSCOPE模型管理工具
1


pip install -i h</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>ESP CSI 动作分类</title>
    <link href="https://polar-bear.eu.org/2025/08/14/esp-csi-dong-zuo-fen-lei/"/>
    <id>https://polar-bear.eu.org/2025/08/14/esp-csi-dong-zuo-fen-lei/</id>
    <published>2025-08-14T00:50:57.461Z</published>
    <updated>2025-08-18T01:07:45.798Z</updated>
    
    <content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="这个密码看着不太对, 请再试试." data-whm="抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.">  <script id="hbeData" type="hbeData" data-hmacdigest="b88024b0d4623a7a79f4c7144f1e53beb86230782da4aeb305d06f65748b2b94">9b315a3d4c3d18cdcacd57aca3d553cc671da0c43fafcb7b9343eac2d650ee3698f5107972fda9502e22caa9d67f583bb9d00ec1449c33774068b2f9d5ac954e697041c9f42d436fec9ba5c6482a62ca56e9f4169228e721e3b1a9765f3c278b3bd28fd4cadf5c30dd75657fad8680fadfa7b984f7a93e6b2a4fe32f79586680b8bb4377eefc1531d17b06a3d61b0c41219d31bdab8058e8061975cf4bc277c3270dab7fff1f23c217eb15a281588ab26a0a4d3c79d448e06cbfe9bf611dd7b8d7a448f1539a5a30e73f99417d2ac3f97a0702cf66a639d12ead5c2d92a8f50633ec6c6ab1388f0fab008cd4215e608a5912d7ed6155b3b759f7df8268beb4df223b3f80d30b19fc9f240444f8273e517c256d795cd3e36f589f5d36a9610f48fb2f70a0772ce4662780ca147c135f5d5f2d578f7f3ec635b74d65afe38cc450dfe3c5a8f304dea389b13196c65df49e43a907e6803f5512bcea67f63891824e8a6bf4f6bac954cc1743d3f4be620b7ad09230fd37127b42400527c49df0cc382684b81b17c4100d31374bcb69e0eb0c68fb91dc0fe4a3ddd9c33f75d64552d7c6a4133fcf3dd23f555e6975969edbe25e12b7841a3f5a8f26dac9ed5d0dc12a2601947722ea5cedd5be090fea97f4be00aeccc687a2c385f2e121c6397b84783400332780ee5f8a1e41a38b2a67ea9af2660ffe39f4fb0a364a547a65522c07fd79bd22893d74bdf9def14215f582e667727d7b6a3c7384f6b5c7231084cfbde5a82587e5c547d4a4bc4f3459d3053346effbd12934af538dc7e7019ff977f4d5d20ce1947916371dc9d675705f91d2d9449fe4240c9d91023df7e6302c2eebe422ee47fa62cb0db25997fba7b5fc35dc91ae87ad437dacde610661e25884bce928ec32314b6dd9b6a6998d697dd18aae6784f104c180f2e5a72639e7da291a013d0f7bf16e5c0f9a616e09107463bc9846725c6be272b89788d823fc3c9e8ec9cfd2069671c6d615bddb37fa1e9f1a083f72fc3baa1c48cbe372eb5b5efadd629c427f205bdf6bafb5eea0e1980d6a8aefe567c92417e0fd25e936349a7af9831ba0b1dac0096973001bc8e76a8dd6fc78d46ff9959252dde75b6cec07f3def856f62428f80ec0acc72cd2bfd213b56483033285af8cd4938cf76e6c0ace25278527b8b066068b75c8d88b3811abfb249b3129d8244d8ffbc55f8a4dadcdd569a2f4ce130847f0c5d8b73ce6a0d4e4e35e318c2b613335e7546bd59f2827245acb08b7933abd30cdaaa78dc98f0173ca1f945ec99beb22b5d0e341c15ebf1896fa31b56529880a7fb64f3e3887e0df8b846729f3612dcd9bf184349847235990ea0e42ce27f2854bdfef131000ee158efab35d8cb64cbf1d85611f978fb52bf299c02cff5f981929f839548c31f7f8b5c27cf55050421f9d202d7dbc0c9c48b4bcdc3a770461003cbf5e45cf3e207f706a6103798a6e3b461e8b4a73232d20cd0747862748c97152fd6d5e587d3784bcead60312fe9e852433c6f59a0bfe96d3f68ca1695832304dccff7c2bd707e870e960e3d56fd48813642a1d06eb09b6a4848ac050122ec09bc0bdfabe241b48929e45b927274e8faf5291fece65bc8de21cd31885369b63b787056fdd987b374e39335e2d755de5de2a675e5300131f08975721ed80c4ba1737220ae9a3fdc6277d64db378215643169c1449a95107a56877ffb1f09b0569e64b7ba11366a6ac576917635c0fc60b9f19500b9978ca2c504f304ddba7098e122d00b089703d116f978ee692d7c32b5d50f170eadd9f342c1ebb7a6f2d2168a7f9e00daedbccd82e75391c6892a5994909dc58e6f8f558be18f41bd5dafe1d0652852c77136af23fe262e3b732f5a35e8f8f22e2782f53c005b9fa6c6c0d3f3566ede49e83b66ec7592a0a2e7190fbac2efcc8a9bc1510a95107dea58d6e803dc9970d27423a8e432b77122bf232fe3d711c544ed26d5b6f1e2c0e24e9a36ddee0d7232f0c65d13aba05ec0023edf0ee32b3ef0271bc95d359448a21dbb452ae8ec2c3eb4f91de7119aab61a393050d35c4c67526a79fe868affe40df0a569ebcaba5379ed2dbd6145d5f1310705a8a1bccd7a1eb7ba9a6f7bfa2ca78b312344f555811b243a02fd2afb8a23b6e0daa1dca8a260d06efaa509aa0f1eb3a3fdb400fbf9f67f644acdffcaa5c9261e9a40099d5afc56e79cda4914d089b1642a38c5a3098be52e748bb03cc25a812388425b47eee2f9f38c2ffb5b2db2f8c2fa68edc892ee5befa06b6ef578a46f801e98b90a38ec871921b38db5c6a5b3d996ec56b5d8833702e834a9c7b03deca70c75e7ca574e9b3a66223b1ec2cd44b0dbed4253492ec1e6016df2c2bfbbeee4e50953dd2bb248a329b416e2c4fdf2808bda100eee378aee3bf9010464d3e99bd35ba0c0eee863d56c93ed6e7e09f65bf91affaa2ed28926ce3ef1bd87a79dc410d23de369666f59ea361e5e9763257f32ae7d51dd890286ed527234aad4ab97ddd751c0c1531c73a2ad84750573b8a0678449f4cca3764f28c3f60a53ff85e1d91a9f7332acc97a4646a66aedc5162decf60af1c2d9125f587f6bd20c474b051ce4331c192c92407e634d3dd9466424e242389775556259fecd121dd1a4e601aa5cdc2c2862cfb90d156ad3259854bff819d71ee64e95b8d165d558814fbab36afbc9c024b7617854fa5d70af91ff12e549780784ff3c53b4202270b8f2435884b80992d744920b84a537784c5796618a6209f6953620fb98434b89dce60e728098d86447e53fa52854fa820e5b8682b70008a5893d9013d69c859a081828aeca2711d62527198295704732858aa9a53b10e57a2dce87c32a4bcd18c34a8921540a448bc9795885883b4f26a300cab57d0fce70cd09b0f17b3e681edeec6a150d8f4a88813f1cc8442b0a06093836480a77b99726217b8a56ed353688d0e7660b3e1fc764e7e4d3cffc252d9ce6443bf120fc32652b17e30bd39ba5cd84779325681957a61320b33386f6f283036049f645954defa88527c258a900df21af52aad8de48cb8db360129aa9f3a44794b72d5400b02dacc62b164cdd0072e3ceec6487522777e3a2420b48e0e907505ed21831fc54af4543f86f7eadbf899c293df2efcdbd3d5682d11af22646bbbbe6dd76831b0495dd02dfe3d9c32c5b90b62164fd3122c896caf91028f1f0802dd756a95035c11362b1e66198acaba28d725aa92c0cb3a7df495a6721b9e447ba821406f448ee7db53215140f22dfc34baa647ec67c0b1a6b2df4f07f3d780fec16065c745777109c0b3b2e5d9b9eff9bc3c6e8830f1cc14c590b2c1a8aa90a552b7ef7c6b5918d445492fb476001a9d16b2c057fecbd5fd2c92c4a3694f07f3851afd8d16a824ea4ba8c54e461bd742ea42bc5744268003529cca7a44c3602adc25c0dd20f9d7e233a2fdab96a462bd4fdfac3ec06b821369ed38744ab091ffb24cd0ceec1166605103652e76472f32c0a6f76131432438f7c812044e82ceef7dbbb37bfb1b76c1ca2bb3b913467c651b64f13fa2be946e082e901fe71b9a1e149de6d5c297d65ec0c2d3e772c9cb2505db1e413e95f43b8a68c6837938225c3cdcc0ee75f92a89174e2f52eb599e444bea36fa43c53c377f5bcac073f54fbf15e481c7ee7e4b1233751a7ce467d1f2a79b79fbb71208329ff410c4d8c9990bec21931224b40fa17eeb4464b3c0bf25ae30f4a6c670f03d12af54ba11b58cfb91b64123f8e9509e4ab9f26e4b553d7f4f47e65763cfd0b6c0ab9477b7b2ecf0fd1d92a9bdda705cdc6c59df6bb5247e885703655d7da6c7e2408bd0822ee3ed4b4d1ea59182e08f9754ac6c051242d096d4f423d46b465fbef7171d7aebda2204908b01eabeb17664939a9f90de3fa9b1b892a6da6efc6cfef86c14df59a6de057e225cf442dba931f843df7b070340855cf57f761fd381bd076c8a76015854c377058d343b7b825a42bd9b3876de7713498e852d7ee8b6ca6c5c2ecab0799bec58770960d7e16a8ebbb08cb115918437e35a07a8aeacced76ff7f0d882886a563a34e908f60d452eb6077f3234adc8693ee62de5987c74132396282de526cca5165a757184e54ee58e9e24dd80c41121ec36d8356ce084ac2c51da90d8018e22d41ed27d57f9a5e0b6f89c23f7bb1204999b395bec46db49f8772043eae67056c666561974d251728ce44292e2c8eb28931481c5ea05154d6e01effd5271c6f42bb7b40f8b256ce3fe883688d8946a1c7c244a54267cddebb9000a75935d47863f2a3017c7c961616dac230d282f0ac38c0f15c14662c7f0a38eff068394659d6586d4e5cf7e9abd55a787875f997f60c8c8bce4aec4619a6df6465bb150a173d024a831cc472963bdd0ad760ebc4b075a76bf3188f57386af9545e8f0fd3f981f32a14c640974586738aedf8a204a080142c513d5d941c2c28a61afa50cace253aa9600b6d07ecfda7b9e2137b0c4098bd04dc2ed2a16f8f15dd124cc7be68319067599bc83dcb8136a85ecef1f9782e6fc4116a8c8c171c74e15bb1724468533462ddb8f5caff3e6513301fecbf94a8d839f56e5b67bfd0930078866dbd8caafe39846b485bde0f0ba48f008b45554f9ecc9818e54ea7ab21f74f12f354c16c615e951ffcd3f3da1cdc3cfb70bde2eb69529c1d291d2761c85ea86e94ebc77e67426c4b97c685a6b3593805a9ee63c7bb4dd12ebd199d5f9106a35b1e88cb7ced0bda4683c0d51932e160f01f49dd6ae68654d979e1729193996e68548b097baf0d211f4b611afdbd58a75b2fdc41b45bff2c8fd68e1138fcbd571774dacd7385ebd87f38eadcfe3924274852ed794d6d8e2ce0b7e3f0a05a7d2c683af6d0f7ee0d7426da9fe051e89dd37a99a646b7df8a3172f05b69c7ef807248aab6fbe74f0ea4b0f674500f4e54d627dc1a1f8889e73ef7aaaeffe75849af7a176985bfc4570f356bf219259f11ca96bde4b9a64b43bfb5f458f345894d8e6d9bf4413313ef7be95bad032f27be87a2bba260ab2fcf1b0aa061aebd935d385e9da85621100113a591fe86e748e57e91387e297f5ca4f0145c0c050dcdaa5944e8d6668056b8076f50cbd28f664e17aff84b657376fb773c3e289fdcca53caa8e44a94c499b0e409ddea34e231322d76d96fc71b56d2e33176cb1fa03895b9d628050a3f6b185feacaa3668575d6a95d72e3ea0eaf09103b1c6c6642a821a2bb8f39d0afdf7076776b672438ff9f9b8624320075d4c69bc7cdcf4284bdf7f71b6e7d1ab9069ddb86624d7caf24ebae03bb94cc6b53a70bbb37d67a9b6c5a5c98103d5a72009750bc3b0e77aedafd36be7b6382eb5fd49dfe12bd64ee1e97bbb521dcab3e1db752cf446050c06a4a05819770a7e64e2dea9ddec292093112a7f5dddd9c8915758cb2d1f19af2e07e46da5321d0cea5bd5bf04bf48c048ca3a0d381f22d04073f074b42946253ca5f2951a86b119b60bae28666b8255bd8a8f879c1baa106e6c77f22d86fa42a6da754ce1618e1926c103810e66c77a2f21152aad184229d5072e2279ff23078acbee2811bbc348f715a52a11c96e1a5494585ace2bff0b8821158dd95d5c7c6ac7599db35938621616b93c75ed38f00ed27acc07207ef7173592a413869cbb19ce60e6af7f611e4b4daa7ced5a3fe1cab416af80e69b9f615dc705f2599a9f2f35c3823a2bbe67443c120036f1b4609112c4af73affb925f5b8b66de54cd4bd258892b409d7eccc07d919120e79d63519bb66af404fada79d38c2d944f56ba8b0453445e410fcf85a95faa7891c13fc30097df2a7885a5c668b02bb3d9e3f57b8a99350093f7284a622789fe11353dbc49f8c49fd2f03bc002a454f32781cf964a323e58a669d7b5c1348fdb59e463301b4922f268d4508a643f96f249b0147d34b83e37967722ba6c569acde27fc8a03ad0d1c7db4309c2facf22001682a013d22a95fd0d421f73841eae8d37377e4df733cb92f21a03811629087eb71c021c4de2d22d2502200864534033587b69617843f0730f1bf6ae94527dc594c5acf53587ed504203f5d96a906b3f7459984e5e42571e23acb0f538fa48d603c5e90e1be1965294b6b67eb293271f179490afaf04af10bce6fe57453bbb4b703c0bb84f38357336a0d5327a695641d75a70f9eb18b0676ec97d6727548fc76e4ca98ca58e859ce380c6d917b06d626795b02515239c3812e63e037a1574024248153f74906b367216e1aa0b0e87da5949aee0576fcea10f2bc1d44177e57028b97ccf12bf983b3699fe00e1e32cb76e75df2f2e78f596ccd40836cc10bbc194221a54af9a09177004bc929f82628d32cee920403b6072d2b1c0dacbf1f4c9d342589ee8f3ec2f415584009426128f456df7385ef4611e82c630197b6068ba55263372aa0ff8706eab498264959789a383df40ea192d11c40d9796652c8788592a3a246ccc2e12ed7a7f16a6f05bdff35e70007a40c704e99a06d70c969824c1821571c94fcbb99c5e944a0effe77771968866411b9784b67ddd86f02b62832bf1bcacc5f7e4f0de142c5ee5311405b33f0955d993c25903148562f039b76da3ad163f6dfda80a3cc2c9ffd44b98dc8607ea4de5855aef6b5ac282842b1cca5ba2d699d43307c452055d5cc58e7089a7be8d073c815970dbef28c4682f86c4db4e682571dfc760bfc422e3e91b0a69508d8b2b6a71f946d104323debe39d117d50ef004cb90b66e02a00e887d19036b13b36a25598f202425d1fd90e8ec52d79c7540b4e8f4c9f9a6a3b9da6a3d01539ac62895fea1eb65942547fb868d8910906c8c76321a057408d7b48d2278d5412437662335ac261fdc42ee4280791b18dba14776f0bebf02e2e984f412ec601e7dbd02797435140b566428f0654102f25d611021845e1f205fea2bab7a6c73aa28f157abe7b86bcc64af7d80b148d5d70172922a520f5662f64db2a47618f63ad59fbe55f01a06a824a91045b60d7de66f36a27ca8f9d0da17f136f16896575b05d696c8174c0a1e789433515294f1d9245d42b1cd07cff3aea94a35fab1b9d9c5d7f3bc45452ed28bec86bb0c797da7a950c682fc6c32fb57455e89ad830a198340e1b74235cb63ea73ef088f4425ae4c9057494ff710135ae573497679baa8c91e6bbe9a6fa744b71638d3914cb8faa04a01a109bc7574ccdf1f1d987217d25940d028b9cb804a91be007278ff408ad7110d3995dd7707606e033f0f19a884c9ce350b0d35870d3a846a0e42fa96696dc255bf5e763756d9a5213d4450285f78c36e3943e607e834c510e05fd2270573d5ef63fb3fd8a8e11a9a3e7deb46aa0361fba67060bb2e7d19098b0c92ef7d82c7fdc3e48ac31b1d25e6585ba6b531e238e8d19976bebbe5e98805bcf5b21c387547e2ffaad0c338533e621a5ccfa805527c8b976d639f319cf1668bff54f0ff9a967451e960113888f96442b6d662ba4de3449cc3c491f08e39ca2043564b8c066909a900f8b51994aa29c7c9015dee9d4269770332c75d2fc8f621fc5d8180ea977119647084c66cc9b7e5879e0bacc6197edc97d153c85235c5947f0937203f6215b371a66a35e60e4b9dd1b8076c6e5f48843522133de9b21f93c5dab754f00d40538073ff80d9c47d1dae1ade5a4665e369e615729ce3c55c97c27dcf33a80c28e8c91f81a621bc822b85ba36eb8f534207e1abf3848eb51c044e6c17a6317b07c369e5bcadd137e244b4cfee8cb8c98bb01ec9bc3074120888b06c4ad93296739415b413f8aaa4143cecb11dc9b5a3caeff9aad2390a52a251fb4f34682397e24b031709c7ca7d57d67ed71d13ad84fae2d73b88c287fa2559b4b8e83489e9476e621bbe11cd3b22c74a44c8cfb763735ad8dcbb8ac6dfa39a4e35a3f107ce7b2c029d29745d9d8b6095f46a238b2bd09a3974ad4de5b5f030ff613e3d1da35b134569d0b53f85ad49e7858119fcb7b7841435c43872696f468d27ef8efeebe77de044f09156e500f6141c099d7d3731fe20297158306d01a528d36a09f745e51f10eaeaeb0b04d732acf1d2d3fa01d41c6549984fd00a1c76543d84b547512974472283ad8c563ebb34cb28b306db6df06c384153f3ee536759d69e35f6cf384dc7b822e85222f5692905ddd1cf74a44a053ebf91ce156a98bef272c69ef4a03125895a39d930aff0eb8aafcc45fa634ffd65fd9101a20e78d72ee8af662291abb2154370de9bfe1889bc102c6974616579ade3d422804a163a9a98aff0dbef000b88fea6c7de6311aecd4d545f525b6834761b2162a57699e476ad38cabb08a917acac27881ba1b01c49403233bad8232fc7ed58ad86d1bca289f8440fea4baefd3216e6737d7307c2ead565746ebc5f77d2672dd2cbfe7ff70a77c4586bebbebd52bdd1637247741bcd30108282b23f1534a95f7464dbd6d2a774d1865f7dd88688d0af5543263c6d3f3f2e31cf841fa77199f80a9aa4ed21ca7046917afe1d8e6a9dd77de5b53dbed28ce95595427db31c10f9b4591b4a84167879b9510fc14c700fdf3427ad811a3b717b58f213eccd179839242f0b6283cb72f49165b07b7e287188a2022c7a8fbf4d221e85f73e1ee1be0ff49a94b74284570cb62aca4fc47a4c91df8c019af5f231b07c05ac936d5eefd6dd7efdeaf21f51650ef2baa3dce90ef800d7be92ed5bf014228391b99aa83b2c963aaf64df900106743f6f16a3cf95a79723aae531d6d962adda102815259ae0bbecf3221fa4670cbd287167cca6d8cb9aae0387d4635a214aec7a1b18c0e46ad334f2c1ac8292889befb0d48a38e656d683a75c6bc1c4f8ce2272ecde20bd05158b9c5f770778d713b955283b4a8ec6e0dded19d6db3bac277e9e07121d27d647c4bd57200b4b27390e15de47217a5fc8eb928a5777993d621f01c5b0798b28df6343fa1a71be85bf3478fac31944c53e91793d3e398c32b1b57ff81bc65c46ecbad4c2a00c1f7b2547ba9147ddeefcaec9e3bcec09c6bbb6c0e9e7e49a723a886b51fb9941eee98eb76725521943525091fb97f8fc4e93d09b35dac576d9d5177dcbdea1719a2fd30f39ac70e8f8bfe4806c5f7eb5baa0b8036d69414192418831b90f5406035ca33ebfee063d3c8838653f8f10e1d5b55f29d0b6c131a4be85eae68b2dacc648502b28e0de3e88632434d5a6cc7146956a4f31aa3a66c406a206b56ba780cdd8055166c06989df9c24cb34a7147bf60af4ae6c4b51cdcf7e53022fc0352f2f72b673d51f4ccd6d545320755ba335334ba36888bc67585c518b4eabf5ceb38424f23be6a35336e0dfb9cace89ec246b7e7897b73d7619608b47e22b43fae10f233d5bc91fc07974778d0f2216cc2adfda7cf79091ab1b27e6c1cc00f7be1b280b4caec8f1d55e264f7456454dc5b6e211bf9af46cb37a0cb73eaf560127ca738cea9a3c0ae6cffb25766be5106b565968f7b59de873afce93aa1db0c0c58fba80165e33673a1ee20a9aa70ede068c0861238fb2f07f48ad094374ed11b1e94d2b063d20b35a2c99f6942732622a868d5dff7a17f1a00804f250dddb88a24d3bd0bfbaf904d413245f84bc8636f7afcc885e30da4dd3d8907b00a4be560d3969c9ec17fdce4ab4b67346d56f6779419de0bcbb92d7361ce32229598c6123398bcf2c5aa05c8fc4f430c0e6c9d3e99569131bfa2713d4fa2f4e48babdc0f6453a7238ca7a10521070933116562f2fc36c1b9e26b4c3a5f684dd6bf8c4cff2704b76071bbddc37b817072e48ff2ae314f284b66e6338877f61d2e9c5f865f6246313ae90ca69e5c9e2bac38c3208b86d3d136fb12d00a9ed6222cefbc1b50a9d81eec83cb890ed4e6afa37e38c4ca762f150ce2594a5c2253266ae509b751f230a1bc1326d4152eb19faca5e796d22e79d70ac81d3a19249ca6894cad7945101e5a3aee5fc6487a30e70626fb602d056d22f1ba2fa67849f11e1b0d72ae3077ecf5c41c33412a12dad35c9250f04eb4f77fe8cd4742eb77178a167ac6cdf4d9d8c9b8d07f5c867fbe1da9c828ba803c9b6ababc2c6fb5c2b5a547c3ddd5feeb69ea26ccfd012510ff3fad4247faba5b9cf17b5ec02b6e7f0dc88db5d3fba9f5cd99e09ebd85d1fe680b13320e425088d04fb5f79dc0d9ff87f334fb8df6f8351a88f775f03d174a4ebd210e93e98819569d7c299934f2cb476ad0c3749bca44354028c67d6ca191ce23e7869f5b03d8df5c22aa22b5c07869cf3bd5f7710dee9d09ad6cfe2fa30bf6a095400840b523e4c93d28eb44ac211ec25e3ffdd16535fff0e3488e9f797d305e2e3a54dd4aa96f62b7981dd567458d20f125628b623c53adf741a8667044d799731436cdf6454df97aae204793a50d2a93885164d11fc1da55fd0d3eef2c535a607f60f4d0926b41b9b03fde0f22f5a1d1c17b182d3128927de3ed5fc447ee430289aded36c3e9d6e67d5fe9b8d0e7c9feaf926e8fc73d6d041e92bdefdebf644f29a789bce27dbea4b8970cf5c48506fb2cf036d685e210570918fa438b568564a347a9d6878b3c4797ea59733e3ca94c5c4ef531d51082201fdfa1ae2daa00578e3199f85e132d9ef77ef796037ee1033481f74a0873494be09fc86c08b823e0fb8cf8822a24862da9959a83685f366e2aa3df9a5229178717d1dabb733571389b2b32231de6e66313a8e7e4f501ff4ec48d579822ca8fb1c8bd111b465a2c09e13c0e9c9b3e3d7ef336deb2f0af46e5b311425c2a8e44b33c86180cdf40dc1009bf9e77e89375cfb2947203047a7a6e59d52e469dd8c3211e549043d6975f43003f6df4413561b09b6eec18c733cdf391061f8224d416e520557a54da7d1275b5e3f98db2376a5ea5bb5c64f24b60cc5e0e2fe979f571936cfead69ce3992161b7f36cd7282160f2cc15e205bcbdf88d29eff25ecab3966b33af1fa59a16daaaa3bdd29f88be7dd5facf1abe4f74ed518302bbe653313a7bd85f6bb0537df6eeb4972237e6483bc31aeae626f4f805922f9e9cea3fe245bbcd8423be6c341872f26a16460ba6699330ae12f5ab2a5b3deb4a5053b4a38a59408fdaf4889b75b052fb042adf83818244a83bc3453fc995d95947cb7fb1d7bfa7d03bd6202d7d5198cf0d1847c1f346d3b3a26a70730a9e4ca7b9704a5cbe2b0b160648ca7b065ba8847c5fea1cb5ff5fbc68e84177c2ddbe02a637e9e8ccecabd44a6d62c5e1def89458824f0ca78edca264850cbeaa092733b393753fe4a677e0f356af15c7e9f8bf25f6a3bdd68c889183fa318f9c5439fb4a64afee7bc3fc77842e056bdb53a50304c7361639f1fbe7acda5976c9d05487323d2feb8e5381b94835f5b8b64553611fcbd6e3adb5aed1542219e84481c3bc7e9b0b6102b1a369746b11e3002d9afc0a99eb2ee98ad4837a148721c0d3570f713e213d050a50217db9b74d765c341f480e5d5000b832688410eed835c5b8d2f91c5932a8bd0164f43b8f24b438172ac778526da3f8adc1fd849dbce950dcb57a11b7bf329b7b5e6d3a5e87e12e847fd53775b55f0d8ea32f946615496d997b7f86432a1266e62e9695f911ac04a6c119b470bcfb910567426ff8452632dafb613404b27353a1d10a68fa503eaced1ada12064437cd2a988bda24eae2b838f6fb5ce2009b6684bdd336740e979424dcf7cf05b51df009540dd2fae2b39ebadf099f61f6c139de28fc344a80a056a5031ca978050f40677df4a757860bf3dc0a084e298f083b4dda4ff6b9155ce4ebe40123ec7d8cf37e32f2c774bd388a677f8e3fd8ceb680a741115de661b80b1a4b97060f92ad59c58ef3642c0e387b9b419055c716c3ba88ed170cc2b596dea3ab6f436fbe4588a8a7b7c96b2f26f4725ce6821c8e46e261d84345446f6706d06ae3ed811bfa7c9d092880dc010b23f38d4d75b12c935d0aa06fe8d9a2aa067fc3455d3c4ac8a040e33e0cdc45fd45125715a662884a22d83dc6b3b9ea92f4b8862799ee2f4bbeb18da79bfc3bd0f6d2d1e95659ea81e0fe71817b113618338549b3931950869f8995f89950a8d1e366a8371601cbf903a03b4506b5c5465eb3533c191de9f67b17fb60ea7cfb2174bf2102b711a45bc8680024984f65936cb25ca288d7e33b846e03dd6544961772cf8e0c537b9d07cee80af4dab2e2c9e4c7744985e8708cf5b3d000693a96a6811206bf978cbdcfe460b2f33926aaee06f648ccdaa0d36e336648f656ca9af04d4ab75adccd583beeda42734166716697c26b9958379b25a8b49418892e665f81903137c8e754eecb1ccd9dce0672ad2f1f0718d956f08667fd442215d348719787a9609f975fbf981fa3226aae3302f67a8774dea1faf3965fbacf835fbd6087dbf182d735a19b7a9e45f756d2ac1a9c57dba40887cc899142d6db68c6840223498ee4ad1f26f7459786fc37e522e397ecd82bcaf65f587858329a910db0c04fea9fbaae216affe0b20eefef1efec63c927e2735cfbaacd798d9a5f30672c88561dde95bcde864a8ab7d924f9fbf12ea9e753d62fb69d5401094296ac572a158bb5189764915845efd5a1c58b162c134ef54072d79f2093b56401183c11c25387e1c1c639e618f60ea35d54d18d4d231e919a4441127529e25f4c39d25337b6b0796c05881ba7a1a835043bd3f15ae9f49538e94bbaf12240051fd3e30f0f8a44bb785c2bc1f2c8e902720073565e0906da9ba03e06e4c5fe2d53f1f8ca01f56893567e88e8f91febe0536dfec13d2743e26027b0652ad832671a348cd48b99b34e27bae8d02b6aeaeceb8f898807da6aa376acb869b93c39b6913b01af74e74b45fe70e71e6993306cda5984159741be9bd181e834ec31263437668a1ace44160f1d04f1cd0997dbde754e262390ac243829f34e8ae069607523a38b97a6f0e3a97f93b0585655b490fcba6d0ae9af767d802f190ff908945bc5ecb51b3d00b6cfd34278a9ae732b3696b00b714d76013dc77629e6459c983ceffd33e8801fb1ead4269cb270056f0142a3f4a9962571af174a4c8d0a41f29a12fc09247d053bf14ae37222d1eaf39ddc9e6d1da9f38be751ba4b07de4653f44032edc8c031ff107f99af9b6f9c5b11e5f9547b6a03255e6d2d33f6c50c69867b5f5c7981dee762a733c1d24355d86ce2c37d2401c8aa96fcded245eda6014a7ecdd464e5f2f548404cd5f76068c8fabfbb18ffaae80594d09b652ebf7d0af94c70daab29fb468e4d29998067f51a41472f1322b12a8c4530c242f402180ca789fe47ac8af8d274b21626512472d8c4d0c09578fa425a3a63ade6f3df6398a05057350ff129a86f0aff749edd7e4f70814742a0c9a4e22b829e703711fc9726a9709b7c93a0ffcd0f50711d806aa4ab3709525146b9c363a32942aad244a47a9ab8b7b712389f5040b0508ac34d2b3dd93ded31cd850a70d0b9d7d9353d1471688e9745b3912fc601f1c0405807c33885545ce2bc07fde855aa751d57b066418cb8c060cb2c5d9bf525bbd45c58e7867c0a1da88ff8cb7471622ff37efc73eb18ae9fecaa054e5f8fca45aca0e747b6bf4a215809257ff06f33821dda53bcf23368500b9575c1c0a2ae964123ec5e2d58569474024c8080f7a449f074bbdc5df962804c7f461572bac86b978b8164644484659c8b17155e5fc8331a67c36b5e55eafff9d7b2952859aa7eba7ff0574df427aa3dc5814cb45192515e4ea7fa5daf275286997957e18c58dcef3518d9b14ca49460d72d8371451b6147c4b4c74c2286b93c6107c9518fb43d16ef814a28de62901fc5a8466733dd2f1528a059235075bbe4c2818882b5db6dc29a831a0ee8507f939c842bad7f7d4dce71614b1c03f50fb293b26e8d83f1e9dbb4ca5d486305fb626e209f692cf0f86200eb82e813cfe432f8aa4e2ec60eb8729270fe49b7cfd123b818211d76384fbbb317a9760c0b720d898f042efd7600c5b92c0bf10002917616ac535836263a20e13bdb8e282dc219b25cad796acebe9871ca70fc7d398e97a8009b15ca092403531a6196c9914a6ad3d2fb7ccdea7dc6a4ccb7acda6c7d1d7337b0323d89c28ae5216082b25552259911a4a8e1bf5a6334fe4e4814dd4c5295c3192dc1b55947ff00e8216e38919a83e5e4c43f81611b2050319f7a353f92ecb0892fe0c7fab6d19c7792126789e668e8900808b21b1295b3b7481954332839c6d10e1e3d4952d4b6407a8a5e0b8f67218049e26cc93f205c77e3af332cf594109d7c01a2a72d528daf77b9de7f0eabc3b1652e14fa2c8be4777bf0d32f68e3c600be1650c69970effd33e68f00f3b866459e7ab0f8798c8647ba72422b60a9fe2e78da7b995446bf7887e1cf24d7581755d6b8feaa2cf6dbdf6b9c1a06f3e2d2afb77403ebc4e93a0ba3bbda123dff899191e5142e1a2663474ec649b24568f999669ce8207391cbbe5cbb1238f6d1532e8c1bcb70344437d8d4edd1935e8d2e929a67ccd10282df968508886b053fb4866649a411874e95265802e85017f310b1ba868c344a710c858213696a2d07099ec6e6dde9d36951c7652e7a45acc13dde0b270ffa71880061a2220682fec3f25ff9a4cbf32f6141758f3bfe90de40d24d000fadda8608cd1fc4c79662ebd1f0f2d5864f95ce423165c172bb60d64b5daf5f20df08d90e728493dd1ffdfdd941842c60f7b59e261ac5d9873596688bcf2a2682486a361a3c4953bd377d43a4e1e2389c68555298fcd6cb51906f5d32fb9174f206e397fea73cb13e6b2b049ef72f2599706c953139684411a5c4da9a2986ee5cb163d747cdd2e6cef7bb681a0229183e2bbeb2643abb863bfc2e4f707e42011ae0173168543ef42bf39b64df5ca67ac10463ae4b0acbe2dae6961b9cea4751242eaf965ec17d097f69f4d6cfb1f3afec2fa3d19e2bb9ef2427daf02f7f40a95ddad98ab44bc6d428b5635471ab08d24b5f70da2487536a4a0712b86c327d24e984b32699b125ad31d40e281c593ac70329995cab109a2c3b13388f50daf4c8fba5ea20df1a3e140c92093165ff8f2c2902fc0e62bc2adf52009e3a1afacf0d46c563f6f0052de7ea616afcde0976ba2843a21f75e903e3d4f8d6b13548a64cea67d5edf0b2b3769df6216905d1b7f9dac1ae55717e85f417762d6a963085b14c547414a30ce7ffa8e67bf66d8b8d85c203dd34daab5315c74c9b36ba42dc2008d038d2a4dd7c6c01031069456531623dc3aeea001b37367aaeed517d18342e6415bc2faecfaab3ba4597038fed9e7b586dbef3ad79fcd743d1fb874bf144f7a40e6e01bcc700ab658f41bceaf969e41fd645f3b2b2e6b87cd06260ca891a1c1207d7212814a3d70d96c5b2c0c7177afa36744a0b346d09b7c3e8add0196fc2f3b840909de92c6869367fa8ace30707320a99d6e50a0121da095528139380aef405613bba7d3ac1087815adadb156911a49ea58dedd480765425a2bb7a0b6f05fdf397333541fc156d8cac052b5618221b9361e7ed4862af954c8d9b2ced2cac60ee1141594fd483f58a2df113bde2e4ee1de31188dae8a9e277166748b347089f71b655ebe578d36c5a06d1314dfe9caa7c0e4fc283f54becfe315122e5f4b9fa8d8a9967ff33ab0cb2f6b4c0ef3576197bdc67417726536e1930c18545dfb42d33059af2ea4a5b1d537fc274e60df51a90dffe1d8f21d4837283269cc3af5106d4028b84cc92bd91821c32e7ccfc08b2f27f4a4fe27e31eac9fd5bb56819ae3f8f27fd12276e48d16e08cd7825f053ebc5ddbe7f4b4900fcc6751b54cf4349363ae133663c5e9c92c8058d2c880d3e3f20cf5ed45432456f1d8ff11e35033a63feb5c8d2c41030a83bea205f63e9b5e7880f0a542668ad376dc21fb6601702d039ff6986283011e467439fd90fed4a76c695160574716578d000f5da15e5dbcd4e50680f4fac0106c41cda85d784b2824abd4356369d935c10cbcae70a702982da961aed1aa1e89459b7e4b202f70f70ad52870f99e281b443cb2a991f4336353c057bbd60deacb0eb4e00076be054cfd6263ac6abb961b5691fdda01348d9ee081d69fe17b961ff7bdbcf1a89d602a3ae15004dc503c91e724b32f053336ad0de2a0b06390bb5ab1b6a65c7beb7913e2f5d3354ce0f5372b004e24404e722f6d0e95eab16d8bdf1a1bc9c6cf2e314be285478f3756505e1ce97264dac61b04718fa50f75e0f7e209d93ba7a5ca46aaea69c68b9f9f818e48450ed1e040a3cd128bd13aad73e9f13afc8bac707537300f04112b72d232f50bc6b666a9143441bd751199648aa456ded335e6355bac065d575a5bde28e7082984eae6c347d5e752da20c144053176dacd174953a3c0548b39761f3c925f6287f4043ecdf19b036dd0c53c49b20a0b0e027a63739dd5a105b0a1417f87d7caa0c3480e72eeebd69f110409d986f037025e6b673eb0ef1baa9c022aa18f5b64499a5da2906140d43b029fd94ba28d45bd0f4c3cd6d6f262ed26867b87c5c79aba018fe68d288ba35f84fc230b576f092e358c084113319c6631938ec46ce6d1a236e3cc24b3e4ae5cbc0ff3db51296dbb819ef82b0ab9ce769de3ffea665216fdfc395dbf6f206fce7dc36ef8693455765bc9c4f3d5008ce83900740e20c44d328ab0dfda3bf234e3b588b94f18113eda0f78b565d2b186201c4834352fce48b98f7eb4e0e36c8d3d8ffb9789c9d4e4cbaf3fba1f1a42121a624aad615a0ea39ca9ddccaed4de652b3903a53b23830fae24badfeeeeac194e0b98b038e2c9f060ad6f1cfcf0554883c4fab9e785bb1c96cc3e857824f62923ff1e90de01febe5070c68fae496eb37a1c343a0cda3e13a43941a36fb77f27da4839c21ae61afa47d25fb1ecfe094a6ff2179e3fae82e04482e6fedd837ab08fbe065129c6d509ecc50b6c7fc4582356064106c7e731d4902edb77d276dfaafce70d597b24bc7ae61647b0cd6e6e5c553848c76e21e62df324e369751beda83f057478417d1d57ecfb43bb6a532dcb7737fdb9416714b00bf870ddd2f4cb07f0b5cfa7f3e7d0900172e9b9c1b086724ab740b7816a4817095f37c81a16a5c27e64f789dacbb52f7d34ab94b493952aebb9ade9b952f589bdaa4036712c0df7b6451db8d8aafae5d48bf30f826065e29c1aca8849dc371de0fcae8422b865c89587ab16e13cd71a9713320a003aeb19b5cd1afa24862439cceb6bd0b64b2d7a9527644973aac7bf1e9c042c5bb3ce70b17054429cfa8153fa5a8e75d6cdbb171392efa68b2defc050fc8b8e72121571ef6b8907fb0b4df699076a586f8b8d5475f18161d17146f44095c4a78bf429864e966e69a639155b8b4ae9e7a8759fb4bd6fdbebb4204aa295e5745ab098564aa71d34b4175f52b8beafd795fb0dfe691601a22bb2126e852f75c6bfff9da50a63af66a6b5b3c11eb75efb0bedb9a082342833fe2a544cea243bff42d7f8b3f14137b796c6c2358341b3725b8785e998a1d2179a51d02f6181b3394798f0e355a28fa01fa7e52a98caf8bbb9a1dcffa94956af9593239a6a8425493bdd8bdf84e42b15074752b518982e50623d3577311f9746a8901c1f7fe24b17a58a0e6fe8ff1c29e352c312c625947177ef3ace7393e2c07e052c02be4a257f1b1a6c8a3b5edb382331524d3e005553942d83d8d449c9b82dd9a67c4974a67c58f6feb569b513b57044b74cce06ca7015162a5ea2dce803d06b0caef86eef2306c509fd0dea02e31d953fda775b582fe553943217f30485ccfee721d63bfccf5da5059852e207151e8325bf2f178e300af310ab20cc9e826bfe1388a91edf61dc2d43758ef969aacd138f0d391514df1b49e1feef3eab34f56ec0a59625cad3b455deac795bc27fbc8e1af93115cd4a47c9edfb5cfe1cb242b188959738aa7f34b41094009b75c8d1d776b2f040a57380435a2181e519e85b54dc79f67cc3bc99a1e2ac52b8f3c9df4261b10b76ad45b913291a73488d1c310f488336217a621d2b669e09ca1c6fe26fe5bbfaf35f657718c8567a38e33532d6f54fe7f6b32a5d8e81875884cf426855e67417fd221309ca7301e9771ca2ae6e33f18bbe21e8e74084c01eca6149df1805a3e0a045709486f504b46c787374baa731a10bc7115bad7586e3f041123344e4d0834deed87333ff4d5ce37249bbace582676d9887a018aa7920f15f15478ffbfb66bae68c7e1c4e5b4af604783cd9e73c009516887d584b2281c26c58d1808ce6b0d80c2f0990f68720cdef3ff1bfd0fb818e5a198f3371aa3cddd98dc6a846c7ca775f08222dc044add9692576af448a0196e8c42a0fcd14ec57c9eb26fd7d03cd9329ae99eca5997c2a157dcddbaed131c33f0ce698c61a9fcafbae980b8ea07a00197c8012d9754bee81f874f1d18bb32473047aca4df575b726f83c32e1744337dbdede4ca5b16b6416b40a7fc977ef7a545c1c7c0e5078d604bb53a7e345ce1730d8ce23e8d432633324f8ee1b80ed20f23c5ef34d2081b382762bab59cef49cbf38cb39f14f8c8f56144d4e447e2df7352a2be4dc7658d16c99228c525b4a02f886c4996fa2dcf37d0bb268daa0239bd8ee8841f95d094d149f270e84e28bd083bdb6b06044412b11eecf945d26cbd5a0a8ddc20d7bc4c96141b0a1180d1bc73400a3fe405043361ac19444b5583eb3a8b009a5c2aaf0d240100e3f1bff24596e6038783e0293f1f35b143d0645df8768736de322c7b2b9189bc6cb41d0a5ab550d4d9c3fab9e2cd3948128e64bddd55f587ebe3dc6c5207efc66eba17ff149b32ef2f48ddd8cac4619b01e678c19b4f0616af46b1be7d3d7d4f72a68758d16be8e4662bd9ce93483958638bb022092fe03be971fc7e015417affbc4479a7bf3864943efdc4b623ef103c34ed03101771143cf231653326c8c1be473bfd716010e95d8058f50a34dec29cd1dbbc49da57bedda62da4dc14173cf350dc96168788ec825b89dce90544f48b8382168aa17b62837deab1956307fde6f97272dc7e1cf9265c034f8438c4290a21163a4c266e326e4408b2dca545dd315f9bf1318151e74d304605e452aa4d26c4eaa7af45673fc42d1eefec8811ded23c5c7fe517d479708d4f0e3d8f25d8ee97f8b86136b1c7fa8203c826c38da348bdfd371ddf27216cc93819017b4f926dd1aad996aec35ff636e59892f6aeb9b062fc1650bd7093965138d8b2ac1225b1ad165164b19857066e9724cb6287eae18350387f4caba7cbf2036132a43fc082bdcc757780653a4d5c9ce27f683c993df8c8782d0690f0d8bf4254a6f8249338be510f23b70baa3e52aa941a14e7d83826904e30aa737e6b06e9d095726d550b35565547cd293c7b4521748c596ca91b6ffc650693e1d6060630445f7ac3ffdc443ec04b637bf06f33a1b32517d43733294de8dcd24b3800bc062c7290d93fa80501fe449f6c312f217dc8fd6baa0f5810936cae7cd9979745e7b2e57aa5f3cad950768afeb2ae694889971a6a8c702055dfc71aab48eb43e76ed9cf84d9f944107872f1056a2b6220c5dbad1c46d2addc866021b81ca211e134abe9cd3196879154e58018c72e612a94ad3b181ebe04f177cea0176a6bc8e7f9311b563bbe7721aeb2ed8f03ae80f9f73414affb14e77dcc73706d256a388ed8ba8f4d0c613f70f576d3cee27fdc43a5f0bc45d19ab3eb523320827dd7d5e4a596ba0db86499e339222acdd0785c678bd4ca74ff02db16825d59a24c36af034077244e9cb358cc1f99c9c759265056058858699fae1185dc4be683e38d44e59c09c3770306e9fd710e8b710d43a9ac7fe7302d047240bd94a4f427674395bc4daef12ba2d69378e79e63a93d9b164e30a3e881cd6db5b7cce04090f499f46bbad1ed841ea14dc6a12b21a7b21b34d5f13cf59fa41ebf0dc07767c163b85e6b5f8ab5d508cd7708aba3c35aed821a401db4dbcbc8e0caae91fb729009b809eed53bdecfc668779367463e914bc9697c994f5160fc7543d0af88bdbb113478345673d98f93d38d817527993636953b22add9a6c29f27e379e936f8ff6640023fd07fe6d407374c8ed6749fdced321c87f121c856c5c1fcc040f391c4ce93946dec67d59e6411427631db8013515175a9c2e5108d1f4b493bfe19ef6b6d5372ffab7c28e8fc17a2ea162ca156cf1262f1eb9c8caf19d48fce3cf6d3f875f7f39b7a0cf2330f3a9a7e98563a6dd766a756411fea9b09551006f90e7bc1626ecff4b04aac8c52c188c3534f5104a1c8e66461a794285731a2439d67cd214598ea7a1666ae90e44943e9b543cb9096a9a215152aefa12352ed714051dc6aaf5ca37e1ba5cfdaf315818bd1e069b9edf2290f26b4575dfef615f630ec9e5c19fb6c91f71e0a84dc594b84618febb55154c5855dc177080bacc9f5420a4a59194dfba1d6c2a509504f1396751c6c7865ea120ab350a5e28b15ebe3d94a9d498000feb3e1f728dc94396c4109a74b52942cba50d122d8fe4ca81de4ea1708f19d105b733d90660e723cb9364f19ee1c708f2aa78bf9a40666cf253f6ed7d3deee031669cfd075c6d91d89a1b739daf6b85dada9a64f3d0798e76f9acf0a4d7122911611da717499dba5304857f0a886cfaaded86f32204479ed597d79e8fa4511805bf7b2a0cf41b5456058d422585ef09f516c496441e392b1ae500af0fccc9f33fb14acfc37d40e985e44d499fb90813c190d4c5fe0efa556d187cdd720d7df5fa3aa4833b66089ba789897134188b35f0f7aaa671cbd86253e757ff61d566ec02d42769cfe110f165a418aa39347f0d84a61515cf82adf81ecb0ced0496dd790216a01ad4d82972d4c697688f3dcba21815752f63e48adaf8d472d066f89dd681a8bd4997a9b6cb62677de546e23ee49c69a479f91889113b573c2b6774c576d7f1fb5bdcca01b32283979c293f471f23fc3fa8086bcbb8ba44244669a51a1e661186fb8371f8f1e8a85123825ed52902e9fcbbce1e1bc3ecd012edd4ff39da2be551c8ccc11537c6fb11647f7999fff1466e507b37972f18d9f762f1c38a4014f546f8699859cfbf33e1a10c47447612b2a3617c5ab506cd18b37241f508f480a3a2328a871c089aa7c1e7b650f587840b137a049d8df4d1a1c2357b3861395ea9be0a1039ba73247e4b33ee374469d6c8f52a04f278f81dff207a20d461c94948de7bdf8e2b5a0bcad25b67bf04953dcf9d7c3006c6db92fe6c2a1f53f6bbfa0a6471cc5e5814d8ed0a2ddd4b810563999d7879e3fda7165ea51ece74fe77594e23d479e0ef76c7c61f98e12018c6e8b71cd194c65660f86e9359ca2afcbd95f6e0dd7acc612e33f7f5a686c34ed51ddd2f7f83e9485cee8a81705caaf49d2598f942839c5ba321097baabb004ba6fbf6a12c429cabfe3e532532a119528e653dcabbe4af2625dd4af41dd6eb1e62c6bc6927f443d27bfed3fcf5f19d628723f795585983e5cf46bb904b18fc7d02b151e2cc0e66c85333fae17a897749147e2cd319ceb13b75080657df0e115d79fd1202444e2493dfb2be241bca1f12b1b4116e0897346a40855c0b2b84bed7ba94d25e53564d20be2d1ce427c8552232455ce2220784149a8e56dcb84f179612351c8cca6f2835a3fd70bb8834aabff78810d88c0b593755e86fd930956ddf8f92ac7ffd7c82d970a7e9557745156cc97cc383ba40a207748099cc22cd819ce4c7da40d19d3f68fb1568faf19f88c6a669d85f509a0d5e86d848f063dc57f7f409cf1c7d696e77705c26329413add334124692996f515b302b78a6968d0d104ab317e9548297c6b58792179bec68d67bdd32c95211192cfcf9b02f03e1e178b0621a45813f237fb1510dc325cec9a2321d5419082dcf1f99e343f18e4e56cde3835d16a47fd2eb17b072d94cdb76b7793fd4b4c95d3a7fa2494c2f3bf292ce6a8ab098d05a2e2e4fce00d2d75f93a6ddf09b4ee6ccb553952d414fa649e6fddd722c22130be9e5be8b3c59154ab33a33afcbe69b2d1ff580085db054f0af4f34fee45f606c9c1b68b6f34c023823ddcca95129312b2f7e41af15d445cbf6d5afc6956354f03bc83890ae7cb35577fb55fb720f640eeef0e968885275cd16fea87b20d2d6d808af4980ab79efcd9300c0d4ad3cbd36caefc85ed2a073a7962e643498be4a089d962d85e085e2cfda90bb0fb27dcdb391b9018ede0038501d66ae35f23b9c32c082fe5de8aba32019f6df9e2a4a19df0810937bb173e2603f1bb369505f441c2001933d29b71a470543e9acef380012398051657de3d57a409c622b5207983e57886d840bf0bfdc6cd3254dbc3c2f2cb2123d657a4d0232c287dfe0b63a612ee23427dd62755f9c5a6f8312f987980c2e2969c6454e20945983308a82190caa8a160b765589d1c1ad6e088e2683f7d56c730a789de1909957429c699330549d56f7a87685d48b03ccbe27ddb745bba3994de1719ba0358561380aab9212b9f7da8f4480ab42d933919a28505b87eaed3941eb7a40dd81fccdcc704586489e96704081e495a0082ee0ca36e5149d20979b1b946161ca4fb82d76f99c8ee077058efaeda7a41f248e82e5f47585a1a61aeccfa2a0b46040dd0facd65d982f9ab12aebd804b25216f83adf434293588f85301cb5f1a7c90ba754963cedf4330a189b9fe137d7069f96fd2eb2920985050923936b8cc9336b54c34dc23f9fda1c3f7e8e90909c4a622c1642643589edbb4fad243329e7b1480872d2f7243a4361ab4f18fb306e182cd313a6eaaef1d0f370741161a6667c8cd230deb3d20d4ec926d68133b8f455b9bba1ff01a24ed0d1edda90c84a933ca6d6521a2eb481aec8bc6693362aa497280b7ab10afeb6ed42d628665d1cb07ea20d2127ea0bc7c75066aa969d5b5e2b6b786d9a4c17035b129ba5a7e9fce8709ca2698206496850c653cbd2b4c07176a482a9955045781281a9dc80fed029726f0dc18e67b808514771c86d2917860b1db1a8d92453a8a438b05aa6fea0fb688c528da6a5c9e579c33a54ab97e6b1eb5ffe8e67aff4e40b2f7d6360155c1f8d65ef486fc61636ead8dc0079046c01789466157c29e6a01b696c25dae6754c974e32990913249f88383cad55e835585e46d26677e785770f09e66c223ceeda744918562b7f83fe40f03b5e198638022744c4691e19eff6d2dc823b8754e76bc56cdb7bca9729ee3324760fb4f9b67d8965355163262395f8c408935a6b4aeb0b3dae08212c88e6b0c600cd5f8f8fd057bff1ab880aea9130a37ac73e79c62edb88cd53c265f4ea6009976cda13877fbce29a5e6dd24a7e50180ca9c1cf6bfe002dd59bb0a9211c94f83717df44e8711a4127a2a8b8d077e12ff2b186270c628a8afb6fc997a4aa0bb7aeecfb8d4aee2f35e4a11e7099ebcb7cf938f32d6de40a8057a119e81a77720dfbf3334bbee71819ae1e85ecb4e2a64db4eac7192161c271aa8ee4597a8de6d2b75687b0cbea47c405363de22b64e4b022fa0c9fd8a1b88f5cc848b8b75164ae4656936d57e9382191d0617217a2477c8aeb22959f5305f966a3e50a18f2e0151cc21d9cf07328c1a357cd6446d3eb15db950151915e2e512398fac1fde23f312fe6a0512ff392b5ee182d4a8320c2eea5981b944862751990fa926c10b092477950757d2e6b1bef9d08058b323e19060aab5b4b438559743ad27628b124961621ba1a7f938cae48da40a612a86d990201d5ffbee95302e09f7e574858a4657ece7549843771a3971b4b4412ef78e76807ba27e6ec33509783f526261540c744b7755e35e6f664e93c3077909a4d804f5851ea4c0983598562e1fc4a6fc74d4a5d582889ccf064d5f7440130c7bd7f5297db7f7857ca1cee0fc1074e7dbdb4acac135a2d26aa454200cbc39cf39edb278f7f58b06c9b9b57aa5d3881198e2b8d26777ceaa0bde8b3031b3c2fcf653ea45e1a48fce18161819300b5be2f9cdd755c32f480b8fe9a7a34bce2bbf784ab738640eddba9f6589bcb0035e21f8c86faf32ecdfd0b19f8b88392bbc6e3326ec19f03086c49e6cac69771290abe0857711b9a2d972b0ac182aaf36308d26e2521aef419c2bf380e27c5f8b803e5b70aea7362ab74b0988199b5acb45a42e18e9bcd5eead90ec07118ca3c73f8e5e0bde03555d48c324a5cfab4988ec8cc414f2ea0402477c499e370a7a91fd2fc7c938c139abb943e29429b9f9e959ad18a9d84cbe407679fea04cfc9b703555da46d99cf3b383990b3f56a6cbe4102a838cbc2b7737d74fd010e352e23c36fe2dd08ecfd37c602a366320196b2c693a5511452c05add61bb88237f60f1dd70c05ee05b2c23b9baabbb63c56387f363e7a9c5906da4a0498c5656c6af3ab521dcf9a55defb9c0f4f572394c914ce95c223d704e6cd0e751b042e69dbb9089ccd4b27a6b7925447b247ef44e068c3d042d74a6a1aea76bde30abf52d24d3fee0c15a31378390d50d65c49074d3e9f8a2f414578bee9e9ee31d64ecf382c539be11469cb82c9454a16ce0dc2828068624af47387cbc9efbaacfff770323b0095018e418732fadc0671aee36a00efd72af4c36f7df2a540eb24e40f067b2852eb5409ef31f05b437f00ee52aceee17254a38afd2775d7c443e695fd3de220d8f4e8e9842e3d8775b68c361be119d1d9987170c3d01609428216caa6845b48a6a52030514b0b7f2ad8fb80ee870cb84f6912527a1ccce06adb2289c1f86a88dd8dcb1d32600eeaffc6d843b3dc801707b5a3f7a0eceb3b1e4ae108b0963a616a0d3c2b573139abb4974a517acbf83f204a8c6e56366074f04f65a2fd7cd086ff8f70a7ea8262fd8136101415904ed4f013c5b22ab0aa323c5cdb27112641b29cc4b10192f624dc9ab7fe3abaccd70f05a3cea561bc998a796f353083bcfdb44d7e06826f5a67d786960e5734a1fccbe9c3d5db573faedb4c5b09f509609a87f5afb17934dde3a6ee8720a1b3e2bf7d2b30726cef9b1da2daf18158c7021a3aae57109cb3b2d68a64253ba8c41df952638d194d34ce2b79e77712d0a695a8956e3aa4a733585d28372e6b9330105f7d885cd6d4303cabffdb8ce4f0d92bb2a8ed0ff6ede06df9d4decb52fc49a6e6d31043c698c3de87d6014d5d3dc87c03073f20f586bc30d8039e1782d8d75550b09aa455cf7196204f62098fc98c75e5793aa8c1ae7e04291db62ad56397f60998cccc060cdceee8bb34cff8a9058bf22ab98070ebc2835f34d3e1c9492f64827734dcf4aff3e02db3d75dd58a16bd260ff3dcecbf56fe54506423345ed64902238b4fb1dfb6177fc2a1d5b9131b22d09105f13565e6514164d91f0503acf1e979ad96bf7a523e96aedf17521f9798cb9ee1170ac4fb7650d32005668bad68b5505664e0e5775fe1a36b8eac3474a80da11c3aeb79be3b27d55f73de04c2f758fc334baae5d4f84c58a697db56508df95c7c7033b815d033c5ae6c8f1441c0e18084ca92b7f4583b1f991ed34b66657d1d2ec718eb83c4a36623c1470514c239ef8e1a1894df1c81ceece6e7f547e004819b3327afedf30d57a781407531cc7c98af31a3f92aad69476c3ecea2c3ff253b4ca6479eb440d138ccd21b45b48430ae3ef6d6d9966121cd657d7389fe92e8790102974cb7a86bd8d132fa1ca3738c4ae77d62d510260ee73f1e3c574c9acca06686d6335e9a526edebc680c6a2be9555b5fa9791603107eaa4026d68a9282f8e454df6e4251dff32db31472f18e9ad27f250946167609e81eb6a5059cbfe9ddf4782445b02f5edba8aa483baf2b70a99bf0b67fdd047d915da7d05e1cd83e590892340204cdbe9f619366d25a2cebd08326762bdb70e6b86da84cc19bd1ae44a45633eb6d70f37cc470b8ac19d29eca646ac2662a57866c0526eeaccb66911175946cbc58136b9b7f9f074b2a6b7ce09ff703caffe8a3a903411a319591b64ec80c40e4f754c086c85bab1a9062c5b70e7130c0971c4ed203ecb06eb0daf43ecba809f40761281d6f903479cc2c56c8c57c32d00c81a8a3f1a8c956b325902bafca23d0fae168df0686b90695053060aa3ed9d3ef9f91b7671ff19c21ddda8f0c73fbcc39eb7bade56aee98ad50d998acb485cf1fa744ee3dc0a7d263bf7a7809cff51b2dc8ce4db57e608d622006e254807659b5810edd71d26b225ff0b23a50f86930bcc9792736046d9fe6b4e48fad81f66ed374c63ba85a83f7be18125779c6b35ff27169653a0bf69c2afaf4b168140b09c299d34eb92ab214bfd3eaaafa547c3b99b7ed43e594bf0242eb5f2c3058c93912987340e16f03fe4ea47530516d598b14c30e6337aee7ab4d4a5dd9171e1f0163228ef0695c99eb4ffda5fed66305d8d066820ebf092fbcdcc2cf601c311b41155d0c48a7e3086ad3f7e51b086dfa5a87c7ce45cdf92ac2498661ae224a57a423e1cde7a241cf4dfb7dc93adbaddc7d68eb73839e00ef967f4ce4aa9d0d0c4ffbd0e2ec13e71ce024090541a985953c1d3ae99c4ad66bceae370a7ae8f28f13563e1256524f8eca0cf4fa2d5f68d927c2fcbc97f64ac872b3ebb501e67285e6668e971bc69f9644b4a13d63936e4854b522518f7712a5f8a767212f2f762ec95bf4de62d095f4923cfec77454b089460658870d19b011c065f7ab40a220a2e7f48648d93b9f4407b2c5f12e274479b99e67518d8ba52aee6ad9a5ac1caa24e5204d4bd27edbc4e5ebf678a4bb59ed21762a46bfc77edc6f00713b39d2af045c53ecf8ef78cb6d5a1efadcb4fe102db971a3ff768720b73e683885117c3372f40893a763563e9a72bf2a8adea10c6a96138953a3ebbb76b32ee97add6b959b57c44e5cc66cf16fb1a708716a9bbd110c9d03503c14cf1eeeba2943d9454dec206d966fb303eb499303aa89f78c4b75d5d716ff42929042c028911b45a26659e505a683207372b824db787d89122ea851a45e87649d4492f464e9dee94fc5fa054d44fb8dd2e53533f9fff2476e62edf59d845c9d58bfd7447820eac9ed3d207025d1a5b9de2e2a28891cf373dfdcaae3f4152deb86dd2f08f0bcb8945b300bb729f5dc48c7de61d9f68a7285a9ee6f580d1ae2f4b5417eecaa9edb8311becf17948fa433743e82227c313d0a0c2043386a91a488ae0749d0204272c91ec9fe327f884bb0b48ec479adb2d0a15e0a83672aa00c80435fe7fb2582027c07bb7e4e15805234afc0ca5d0bfaa4e44bab9b97d9ca1988bf8624db09770d9c48f2ce5420b365e51dba346e4a02fb39d4a25b2c6b76675500a29540446a9992f27c2ccd8b63f11887f20c7d2f328df9f19f702b162928d74115665914a62289847214706148006c4f927a9c64a0cbb5bd9d1cb8bbe185b30f2a73b1db86c67018b5f7054becba90f50502e23f9dc1df1d063cd31fcca927eed5e536c07574931e14c2352980291a1f650b3a6321a88b0704c9fd28ceea87d7fa58afb5e981aef8099135d93130c3298cb78869cc25a3cad0479d599d1934501fa391158857b847434d01031cef22dfb55c704f4d60444c1c34c9c052decad875a0df71767c3dbf5ddd35e3a9c2aba0e716da514d7a8f1e97b9d3595ecd6234a0951a144c2fb95ba6842d6601aecab08e6541abfbcd609ba1c766e034dfa891862ca8d1947a349f048d1036a673ae9914b7e592a91d62efcd365ebf979d148178e80611d0a43f1be4787e968f4ef4135dcdaddfb66127c78217733907d15224579c6826ddca0fe3e8f392a7ed31f7c2f6b0258a790469d45fcb6a76d687d7ab9fa41f0d124f626c6321da6e87e74180bff56b876333ddb1d8f0435fd1c3a895de4dce61ac76f300f65f6c8d0d8e623b727d3b3b22f43288e11c669b244ac07ba30f0d099b6198768b9caea5aa190e436e3cb68663b2c07786e058957888c9f4a00099450dbbe9aadc38d5422f611630dfa2b3b358de9f2e6cfb57dc420fdcd8cfbf0321aca9f33f377b9b1166338fe47b94ebe1ffd92eb06b5e3590190a9b150ee7ae210f816f2e7ba786b8d50d81f93c45387cf434ef97b506aac8225d510fdf41e98b3c46356495ad5fc171e9d77b2102fbdc886b46c3fb4a32d051d3ba15941ecb676baa39a604bd5c647c9164aa454e29bef801da817d0f71cb93989dbc46b947bfe9aae077bd54ad80170f6edfbe93ad296e0b32e24f5997b173de1e231a02e365485c1443796dcc12aa7676dc7133d58580d4cefcafc529f18b706cb90eb1f1adbf568f0764a58cbd003cbc6bc2f8bcbb650c26dd55aef60d3bc5249aa43b78df027d97ba0d9cdddf824c13295c8bfeeec57ec7bc96c5c19f19c3eb3385f6fdbdbe30098dfc7d2c537f12129f4570a797a38fc5144d287b58913c603006497e2ddd1a1a23639aeeff8822ae19d55910338873a5c977b8e253296dba7419ca6b8c41c3c7afc0d1913ef7de8a8f2b17b84816b57f6fa79e1b8ef07dc651844479bddd184c665e31f3c218655333d9bd23aaffc2cadf8489247eaa2ebf193c31696ce854092241981a6dec1b64f8299b5824a84aedb15a6a9e80a9c75d600029e1d50870c654695654f2ed3343a99fc4599de4b968634527ae1f29b21e4f5c6675ebcdc6228228db1eef43f4ac3393e515dfe6dfe4d4fa9ab62ff51cb63211df2575206d1e2701dd10ce6c1c65fa7968b9e595d6438207f743fc89635535b2c2d26c37ffd4e053d6bef8c5771d2d77c0ec57a16df5deaec223184ca54eb0bc43dce35042ee4a656ca494a0650b80b8feefda5133d6b7289b9d3884f63df924395538eb8519102d0870aa00a8c129db5df184eb35a36fa2872518f74ce2abd6255b1f5a844bc25a2d2956cd96556db2f2b1beb5ee6648050e743f589e96c4b63a15a9424a74379cb115e6e32869dc448fdfdeb0d6137f04560761172e95fac9251485e9afa64526084b9eed7b9352de1c19a15a26e8e54d621b9c47ddeda138eb5a2b7ae17d2eb2027fd9c0bfa36563a50b0fe3f6173071b70391dd9cf0cd165a2ddfdc4a23ec44af74ebf09c173cac35d608157da91454143448714ca38389a1583bdea429fc87cc8b4721bbdccc5492dd91dab48767baab1bfbf4f06fe80530abcb97ea70eccef38d792fc6c3268220612fe4dabf15ac9d3779dd2d950f9f9f7c24337216f0833cd3632b1ba4105f281276576027b8cfeaeca689f6b7ea5b9bc45f29917747732e7eb515086db4c34f0cfb9f6dacc291e3705b1b54227f9eb22873b18b4e8a688a98cf79de987b89422bfc8f4fc219d90737f5cd833fa88d854a8526ac9af42e0451f0aae342705c0c10f0a88ae47748103b2ec40890b3fa9517eb79c398cead008a9bbd4c4b7ffcd67f61543242217104daca7f46e28b366196bc51a048782f5bbb0eb3654ec32e729b0bcc40ab6b3474701c266c5e29c22be70ca2d0c3bb4b98d4ff816a072a1c820a954fa1bcc370a4810599bff094f64262a42fdba8b22a4b84c671e085545c45b14cae5068c1561f8fa8d42c22610dcc78b692ddfdde6197e5cd5f218dec9f111be0459bc6934a9f0bcb51111b32d7d9b2fe11264c112b4517d85ba0541078eadd3a54d70f76cfc24337d909f6a4e0762d8828678d09549b580a0866d69f7ad1e55b6b0d6a816ae78f103bb9ce51533f59ff41b9099bad678f124948766f5ae56dd5defecd433025fa50455a2e89e8ef1766af3227373b744dd91831494dd087a0f4953f6349de2fb2f3ac8ae8bdf485aed575c673efb0763a0f300c8d5ef82798577265f7c7c3c62e6234d3414af49b2f4d44a65282b6e83b60c9f62f2d93427c96cace76f63a5ba018a38d952677b8e6530d289ca4d2ca2179ae74a441eb46f8b958c5173d17ec90969d2b54a1086cb9513d1b833228c52ca7a57dd31f50d407ad1ba21c4b1db420619e536c45ea094f6c6554a6b0c6cc1c410ca79eb49b1f150408b6ee46800e422fbddb74cfba753f99102b6c560e9c93d8daf9e658fd2aea716e3ba13410656d05a3e3c6be499731e44f292647e1f5e6ace4f3f6e46b8e0924c22b6d956ab897301b4d8fe5d7104b10a31eac01f7aaf5d825fde94365f0de2192fc32e8824a6ee2ab12c9f141e09d9cb2bbd49143988dbbe431abde1c7fdf3e634bfb8282d125521314756162c01f7338428d0afeea6d0471f7a45913b4210b29a03d4a81395822774b9471f03ca80d2ee0c6172cddc6a0e8e4ee11f1b024351ab95314aaac313ca475f9beda4254a547438bee76a2919ca76312c4762aa2661631d28f4d380e6fbebe4824c7a27b3a3c793075ba7ec848001869606dec43e46e382b09c1245358f6c1c5bbde77ef5a62dcc7043b8d4ac729bde48652b689ca7982ecdfd437d7b159f1850561042622bc4e556e91e0177a18edc321c4a09f7e3f6e81a07abb5364feec12288c49af563c14506c439e1d4a71d9d259f2683744b15951c4747923c139a917761d808274cb38ebbcd1dc50faed30178695708e4a1cd367f34397622b64ecb1c5f23f20a772c6fdb1768d0d5a38d8b00e9e7615e7322ab2a39d9cab535ba179d1449fe4baf8a030f4addadce0998417284a7aab984ec4dd4fa5e0acc6a493513442acecb3432a925a716e3192ad1c9282bf53ce335dba8be7c040c2ae40469de53a8a882a09c89037adf78d34399646f415be6f1ed9d8a40a9a33b3f30cb6c2e506857836692f4e98af49296f49ecda7e17464a41a4d86f02688596cf3efe03547324765fce83ca82274071532a91fe72af5502178cd299d3ac2207b02eecfb217412a62c46722b258723e9617f10d98beba613853b2de7c0e3379cf2e6361acc060cd45cfe8edf5a390149db051393cfc7d738647a0b6f6f487442b2af118369cc8b0b68bbb341f5f1cfcaac0dc5d5ed506c739599c095f77188424b36e9b5c49219d2045b17dd78977f4a749b47382de6ec28e9ac4fbe4c49633efcdbb249b3e1d7250d3939b8a140fc3684abcaf806cac32bacf8a1e3e8c85882a72ecb0731ec7ab9686d428514e3ee49ddd2f0cb723b29ba459294c3d0ce76d3d0392ebea4ac72cf3ac102345392b551a45a111ec5828a3c6cf1a597ec08bb1a0084cc2d28b3bd9cae9d462aa245c67a668019f4eab26521ffa60c0d4af623a764aea0b2aa987b96e46979cf056cbd26b8dfab03302b5586beb2775533609aa1e4766d41580e3c3faa79ee86f44837ab8ed756f6a536c53391394a0280cfb53a3558a2054866bad4b48af8f0f5924f342c7492f01106e122fec61e1c1edf058252c7c79ec88d933aa5083fec98ff0c5832c1814e6671d69d2737aaf79d480230c3be5eb31028736b3157e8ddd828cf3296642eb806318e9125bb2474f581439ff5aa20113d89b2939417b06c2df5bc44494c7b458df8b32892f100e71eb5020168fcd601820b411b61eb048f42eadd96a29e03ef9a115d1c65ebb5d3a5c852235714111fde1b12092d7ac8ba9e96aea592ba05261afc1094bd77644b382969eba6677c53e8e9bdbe75e6867a64a23cfed9964982b55637ab8a84e3932e7edec53530098fc33ccd4f2241598412c5f15869ad46daceb1b12a50f38384b9ba3f6ccd89d107afdb99ada841a5370fade540ec05a18430ecc126711adcf77f3ecc41ba12ba70636081414bf927b870157240601da0035e243a99e794a4d97dadd17fdafc00478f924ca0b2ca2f4f4e2f015c4a4c35a26d30f3fba74c4a51141c8ad63b6f5a32729ec28245b10d4d0c48ea3c1d0b828666135363a9aac198df18ff69a22608d7dbb6b326d146bcfa23c9e9581512d8556d53540aae5a4366e94fcc8b9a58a8ee8a4edd082526f0ce3840d205be976f00f507d8d3a374723dfe6c84cbd5e920cdb763d82effb169088dc81da6fabffcef03642f835c4ef87ec5bb8e925f07e7718d47591928e7103c72d26415011e3d1e9025e21da530961c256b81e073bf041cfbb7945cbde744768c25ddc3cf1db7330da983c06ee745193720aafa9f48f88e6b758533cd143a3a50c54f72f498d9b595274b0ec8ea2119515c200245685cda55da7f07d04d9ea6345eff58cc268fd91631bd59ba08bd555efb12357d85045c2f6b212d77ff26a09eafaa13885c3ae107a7b9c7d57a7e3eca876404a81ff0098ef45544641581a5b1dddff12e383893ba53c80cc48d2483f94ee44e58ae89a4083b73e180d7f442e185a8a7eda4de4ad6e8034b2fc3031f46a76e599d65772b912fc9ecbb88a13c5e76931429324e0043ab3de03fc31b48171b6e9260646caa73da31b1a12ee9bc66aa7f37a3c2cf81fa20a2d701ffb5c0b285f5d3cb532eed672675b5d220855362675cae0dc1e0d71244abb2d1f6458b3bdf205a7529bcb109e62403a336db87e8b2f809d0c74ab1d8f1ee55f9bbde3e1796ea1abaf5ce9c208b9882a247b46baaa9bef941fba0229a337035dbdaee4e969bafa6d06119055e79effbb2205a564221e1f7eb128148ba2008ef4d219f5bfadda8286a44814c65da717dde337879e1bb2aa030419ab050518073019d107ef73c19619b81d05a4b0b0a5fb92d5c2cb932b8b809c0cda4db30eb5bb7f8dd216757ca3cbfe563a50422d5354d23985630f1fe4c46dfb8c6147f61f019b4708af5a9cc3ecc74ed433528e57be8f68913860d8685321d886ddb3509cc19ce60676e3c34e0b24f6a9632a9ab1d4523096130e78dd4e212b07a19a4e6601a9393f7915fb51d5cf7e06c030babf39bb8032ac02218c71b3aef7b47eb4288d85ae6d5459ad6b6da5210739a3558736d4b7db6fb803bbab514598dae2a6f75e5e61b07634f53561e66234a46100f6938bae284178d27fb50cf508e3024c6bb5e203f7e742d2edc247d462ffd4411ec41ddbe46498b72753f41f6047ec91a460bff6589a73c09eea274488472489c2af08453fd0babe3e191095bb5aece9638d535082baa466a587d2eda62b572e1ef49b7e6084875e828d0215729afc3daf063dc8fb6ecc67ea23cbff49537113999257483ec8174c0d20df65e85126fae09a99051bc96aa0f25c1a4ab3f7b731c24b37ae720f1e116986c648818298b543fc1154c5a2fa4c0e7339b1622f86187556e9980a4de13fe4659546ca7de097b552bc81dc5c57b448cfe55205bddbc84f3f80cc4ab7721117df89f85c50d3383636eb392d95127846ac8406759c8f7f0a946820da03a0cca00eb9b80869c77e8f3bf829e62cd87df4b62c48f4c719899d5954cb0046e8a9b5458b88df72882507ae79402b62e26cc37e861e08a6f7feadf7f545805969cf4c874dd4c964a493b31cc63b1f43b8db403df3e33059a09cf26934470d035f9eb03876dba3904094ecee59b1cb8be541f49d08b6450979cfde20c2a543ffbd371b241e33b87b3ca8b0c77c15493ebe25af8edce1eabbfce4480ad2f6ca6c7e60ddd32bdb752449615df414f4a5ee39b039c3e001b38ba501e0e22d993ed87f9c17fa41e208b026c17b53be9c18e6b8a9eb686db75dbfb2ab0073b50223d4fa9f600219ee4a795b244b4fd95632dfa16d728eecd31bb6b55a22a65b1a61f625723d1f2aa1657b82c14e04e0685a0e9ebb0145fc80b8d49291554989b8a5a82dd2ab27ce120b292513cbff447851881ac3d47bdf558566653b58c131399c8385cdb7cc7491b27923c08fdc0914d7b731cec0baf6a9d5f6efa45aa9d557d3b601e690e9f419229f40fa5999e5755f19f9626c27c2b7d93243e1bd3206e1f65dde6b02a6eb40e7956d4681089b011fb9d2cd2c858a0f8febb6f9e889464815e6210ed1395655e2a07f0ebbe7eefcdb121ccde4d631377e779d3c33907405791bed41102f014a59e062babbd1ed3b1f21fe4210cf2dc64cf43439049bf3fa0a7173aeac8d69b5648718e7013dcd4d4d5202417a6886d9d0d6775f7111f0e561d0c658d4f6c3f3be438881849a876d19e33fef13253dcfd3d6cfafb45d141f8f8831aab0a8ec226018c84c53098c8b3cd2af0ee3dfd3fd3d30216eff5a066aec50f25c6ed1db277b8001613969835274022ddb03163bdfb406c3e478463cb7ae676e3cee2ea74444fc58658d49daf7b6b31bb9baf767dcf1ba0227c702e60c20e5e8e65cf7430c05e01859cd9a2fbc0d282c1373630b1a0cd8a708c6e662c94b79aa8a258a846418c336e1cde451de2815285cb96543f49550bf416b8fb3649d51ebc7077fd5f92c13301b491bfc9a36cfd62188f8a84da7fb1bf68019b3a8745035794d56e0958e8ed5ad4829925e66df36fe57a6c4473e8c057f1acf78ae60c9e2238a273cb036fae96f3d0f1a704b5f701ba98037ff5ca6e5f441a12b75dbc1ef4c5cc2711ed7b8a80ea7afb2a4ad23d35af957d5e763dad61c4d1317f1aee7a9cabadaef77cef3f5f68020abff5fc919ad1415e8ba3c4a931db4a9c24c09f7e0c50bbedd4d54f2c70aceeb99bdfcf2e1b46e172ce71ce0e08af766b13ae21c44838f175da6dae8ea66c3b8b688030270546e16265dede29d66b5f2788d47229810044d88365739b8350061a28fba0d70f35955e3d5d81031ba50664f9972f26f82ecf797461b45d869124d9aebcdb464538ec858f07a83fd31beeca18ef426e32faafc30ee3a631c2809793a0a14b5f24600ba18bd30fa0f7c865e9ce84a92f61f8cbf2d4226f723aa920dd33b5c669269ec5ae7ed35c3310d24678ab908fb787df5fd5c60e77ccfc712c1e40d520f558b45255a9c722f0c05edd39bb264a11fe3f28572d1317568caa0e33690c1f250fe959e7db92e69a80efd0b71a61a6b0d4f162e836280f6c70a6f8e0e2517591c660bb5841ed5ca08c5cfe0bd72716ba77bd6a9318fb940e85a3db87bb5e68d3576499b1cf509847f4db5e7a3c94dab66dcfb49738a7888f9f85d63f0b303ee8fc2d09cab9995b7c4beb51e1c7ed2956a10df70c1696300448c469212c97f934ce9fdac7dc926bbb7707d1e97c5225fa12390843473b41fb6bfa876e5efa0e29add9900493706d3359b67d36b1d875631b17913d8e55ed916584d3246546b6a6071c138518a7ddc0e8d454c1545939b9dee48a1dbd4c0f763b63fa575c6e9107c91ffef4591133061da77fb8d739f7d5fc4afe11367ae46d0ea89b3d0aba68a9a16615731ce66da6b46e2ca4b1ddedc08e32ccc12168f81c6361e381daa9ac4920096b67ee17ef5a0d2e0ac5013b269d5125b9017943077586703007599a9ea8ae2a3998a129e6e4459e49041fde5a999b7d766ce43e9f45ce42cad54234ba73f05e1314aea7c95db508fb7e0edee08ef8bbe0cddfc08589798306e7bccb8c4a54fb4d8a2281aa38f1800dd32cc54fbad4f76d96d4fd0039da759baef349d45843808ec4d9e98d90b932f9fba1dee0a9338308238cd528f6347a4361de154f81d2cbcca994712103086478ee053eb3fbb007ca59f00b85d88dfa3dadbf267218cbba9b9de7dbb33e56b1554b0fdde26066673371871c50ede1e38d5196dd646b2004b493a7b389f8025be57ad8582cc7c271a0dc13a76533076c7894733c1d4db272a78962eae62c1f6578952e0819951f48e6773269c971e651f439bdad938df99f3c3a7ef353f7f6bff74e04a4b34378390742951c1056ac6f131625f96db5e813a3da2381204b87c8c39b57a3f55661174e5f4d74cbf9f3523b18eac564cd1e33946236f39ec486a3fce8594f0238750fadf881d2142ead6daf1fbf557af30802547692ba596b7f085452a96f003b0703fe6c2a1d2de4bf978ff58e1d4722b8958223e2627354b6fd2728977619c58d3d5c143878e6623426e2e56b34d0f33606d71d2450c817e5f2a2d7a825d7290be0e321b1c54322bb0428e8e8a7247f71a9022aa4f99c6a796e540003f3578e9c752f8ccc83eb25b2d8bdd2751b7fdf04f2e018e411beffa3d5ff7cda1354edfb1b1958a18e884c2f1ee219513e5a2d5eae948fee71b6974fe796068539461b4d9cd2beb34e933c55e79c34e3468dd1c8395fa08efb15167b3c3c35381e0c3194d1d32a10bb25852d464082c13ecb41b382b16de435cb952fa82bfbe3e93843c33fe1ba702f280875c1b4a4801da9b8242d2f183789dd8b5b5fcaddfbbd47bfd9ba0f9743ec16f232159942bb4682253340c7a159b446d9c5ecd1666bd28257f017d237fc82c9e7e6260fcc4b1c1a2c282350b6cf98c8717261384c760e8a31fbee2595f8715c5e95cfa4b94f4df8bc270a8b66a32418bc5af8d7a2c041044f18190565243ea1e46d5e2ae4be47c4cc0b750a527f6019f7bb97e9d4d129435260d7a8febbb1d781f34ba54931cd966894f151a5c77cb88bf2b72f43fe05bb83c7a1005be40941b4d96521339d6c8f7ad41106651a8e940b7975d3b737401f861d910958fb53abeda6f3a7261244c55ad1cc68dc857e5eee3efd04c6a96dc382035a0dfe3b642781eefa4246cab287b56fa6e6ed47c7193df0ffc7b1b48b9c5508ee0fbe2de52e3ab7f80ab3ee6f1de578cda14bbd988d205210d2ff4c3a12110ee9358504fd3fb7d29842bfeb51dbe8dea72ae631ce0fc7e201fdb560a3bbb2cb34d72d900c555b365e4fc1d2c6a10b7c4b1516e5b0ac253f558ef664f4a37485e33bdb56d23e6ceaceb670c96cc8bbfa23947e739ab50d7c78856f60c3933f8e6222cde75987b6ab47c1e7fcdcc2350222a6d7a258805c7af3bf0ef1df89e8a30df98fb588537ac0c6ca40aa45d60188acc390a2b524e323e5baf34de1de700a31056a26796a2b31719ccb5d060cafa41bba282e0d4d72f167bdcf445adcf66712e63586dafce2b1ffc3f55e7e5b016092ec1abecaeaee8fc410856edae3f7d9da22368759d319bfa0a81e3e5360c4b721710784f9603609e28fd4c5e30eda3bfe7ee70aeb5b26bfb2e717dd24fba848574b0d9a1658a8a599dc5a90bc7ff5e83f697acbf4183ec58d3b9b512b784c94a6dcea833916a01bf21fae0deddefc744b5793a52d9212aae12aae91c44c615d2462d4212f8066092b34fed6e32be59fdb8e139fb9bf12b7c76d5e34c9bc5983e4e5518095f7f845ae35945b2854efefef3b5c220c3e47a74314b1af341da87c4e2643a458d4f559cc26a092cc97ceb3720e79fbe220f85ecbcd9281b2451e4a94d146e091f7e9cd7216179e911bc37eec7ee76e2d83e42ff3da6840140ddb3c459631ee2fd6d16cfa203ee310a46bed64c06f9e4a897891a4bd5932961448f8fa1a752635c065d5e97567b931b1469197ce644bd6ca881d9dab83e6e38381fe91a2c8c17717c3963ce6e2865899e0b81dc41298923bb5aff433eea168b01351d7592b6e78388c24d0e4a9eea0fa35d97308854cfde55463133cac709cf599881277f863983cb8e0d5668f925090e15192b25eefb5001703584cc01150e50108503d07c79de44aaf3809e610644cdd8a7566d9adb3fbaf7ef2e140ff2abb2effed0663bcc7b515fe6e89b41a6fd72917e30fe394c40775ea4d1ce2fcdc6d52762c61163a4f2884955c2f55a653d5fe0269a0f7db86fc51ccce627460b4e5a87245fefa21b989f50af912377da2d5d7e50fb779b90abbd60db0355ce14067a87dc9386ea3ac85ca0db8c0bb979c5a217d6e7bc04ede9533c854da430ef10c4f6bb718b2a31a8df8dcc4d13d766110f625285ef7246188ce629a6c8807328d8515610eebbe1264bb5396f6f7bf873aeccd8b8f5506b8f696c0fb82fcbb20098763bfa26719ce5207a86216fe466e55ef4d676c7b2ef50261db632fc9b546c1e0f443726d870bd18f86e14619134dcfff3d97e3d211d53b7243c6fe7e953bf0ec21c593d76aec2e399fddb02ff10b43022c93d65a0c44dd6602047254777ecb1379933b22f0b61bb54285e0b46b4f7ccbc2bf0d611f49cc739a5d1a6dfd574c062b424a852d491c22febf2abac6bc3828c1f87c7304000c8d1cd2c36183a7a29902fa59ec7a89dcd669c81629994be29f6b0e07eca8f52e1b07067ed6644af3ef9b7c7e1cd1f379d76e1aa72ba5706d4a6fb839926cba870d67e13515e825a8f26e006860cac76004813a794dabf0f9777746f7d84c63906894785b0baaa066e1092b2ce47d7b59ca31471a8d2ddc40446579fbcc8e85c6f4508cd742ff7e82d66b2d94a54adbca22c206f097292316670ceeec857f3e12ad4758b716998cca39f06b18b1ec0a1fe01410b9cbf4ba10e9289aaa4439d4db94b8b80ea8e6c30fd64d836b6ed57e88cb82da0c71fab8c8c2b710bea318d3aab15997994d2faffdf37235fe73ca299167f6301b9dcf8fda67fc69865ce36b517b8399fa751bef9b176aa80a86d8ad1781e4db7e3fb8ea587420ead2089b587663f5f34175901174bfc63f4299e69556265ecbf45ee356675adb8f9aa8b32274842a8ed043d4b0a66c021d458a735686553383236e671e598fd344bf749d5a8d6c701761c4404e34e2ae2a200d49bad509f77ddf8fd808d90fad3534c2d9ea78d97dfee4a319331c44ff5b17de6bc1a0d523080d9eff28c3ba7f4754b591bec082fc9d39fa32a3151e8f23b792561a1e0322ab65b26066eb370bfc7c16eec422ac2a32f725083776713d1889f8b8ee43bdf0b79456a65eef245797b364e193467cd363b0d11363f7f2e7bdf1252e81aff9a030ae8ab3cc31f8e389c1cbbd65d81d14e6f9dd3810d8b01f499343cf3083ec480cb24156ca8a8f4b32d97594c78ffd99620df7bb9abf001eeaa9a534df834d82ab11b6caeec00ce749a880c8c70fa2e6e383356d822abba8331926335135de12ed0b075a063d4487bc1d88d1eeaf00b9b3938f35528c1a7aaafdb261194443e01aba72e8100a26ebfe605059886254f1b21d16190bbc6e10ed22e0b235a7e92d5b9e97984cdef86762ead928e1764b5840423e492adad56b60e9c896ef3fbe09263ab458c318fd6a53623cce1161d24630769f914ca347dbaa5d63a936d9479f7b5e71ef741f32517ab716402628dd70e4f23389a4468aab25cd75466f0255c30e4deec1480614023cac6f627fce4df103240408bec1d558d57272b799e9c08262b1502d027f3c79f2e1f2e04b5f03c3a269d8fe493c9aa0b70edd9fd1f5e15305d6f4eba6972de5ac66b9922b80ad26212ef9c2b3a389b4f0273c4ef9114f87e8c221a24aaa0f3c211058f16d49fe7893270149c1b85eacd5cb947464847badb1dc26baede0b880943dca256b9666328b01ee3ead82da835513f2d2f92d899c30d153c93fe25ed1b53d3d0c5a592d219b4584008c0031abb9fbcd10e55eb0acfa38a913c7e6d06d02e8d7008ce0a5dbcd951c2d3953f7157ab47d68390a3dd80be35d70cf2e58bf526c0215bb06cd6f95526b04ab89984144e452ed5eb902e25601d545585bfd15c19dd0cc288920c81c12945e1478ffdac375ae5354ee508f3bb7d4e32bb1fabb6050aaf866fe689cfb174d3c4ed462cb751eca21e0ca549052f46dcd66821bb7b60fbabbf86388ee3a2161fd5d43daee46daf7bb76185cb74fb157afb354b6ad35081b411ccf49381e8e5e21361c3a1489f03689e5c7a480b04ec9fb9a8406ee27fc2348ff52b91693ddc2829c87c541677309587fa281d0371e5e655033d04cbba4da92ec9317c2b0a5eda8e8ea9b9920eeb1600618c8f99a062a60adb46c6f77a3899cc8219d218b4ee885178b10d9227258ee8c8962e3a08febb28e4cdd78f082a5c3b05e4e53a2177c800c3e4be2d269e9a1b75b506b186582a8c18dee5822d2d64450fcbacfaef50ab1978b3cf7b2cbda58baf6db68768a90361df60f22b56165a0b63cade1c82494a96b5a5594f60de8729312a619e95ca16edfcf7a03c35e1a8af032a8240f680e0d6ba37558a4b2316af36a0a08247e77474b09ab96dd34bf7235349e98641d9b1754885be83830147e2697f92614cfb7892d2726e702f2aa9a56634a7cd65bb9e47c40c9047d7ea4691fff86e2eed6c640cd8bc48c77e650cec97d5412628861f91f0f83e6012ace56e2ddb6ae4a465512d7bdbfdd25936c2d158be3dd0892ab3e70731ca94c21754aef82b3f186657a649dffcb363871526d2e05d83a4a00b80f191865658e2e490dc3e086957d1b2aec68f5ccbbe436a75de4fc233baffae5477b9cc7a86fa98fbaad1b0e63205c416ec2b7ccb3c7904df17703b39d5bd0e344af5fd19f5760837414e5e776c79ba539e1f6247e452cb14e880c4a37d346eb8c23a23b8049218e1127726677b82bc43d85a4071c66a89bfd4e68060d7250b9f21bd34489e32aff65f2ae60c9029e8e7a59ba4b48685fef4c749a3b06b4347e8331aa9e67ba482383f8c791c8b3dc4e6ab1d336e57fa3953b3c75b7739507b85f6cf25f64f3bebc7f3fc74b6da55162af9134382a110bb29a43eb8d37fdc0ef4345c92198d69d1e21778b0b5bd0eafbfb266bb92076ae49877a82014f10d10864683ea35465d3d4c68b7be36cd8d25291d8b58ba15abde9e35a70e72ff01c0db580452985b53b93f49c327ff54c96289f4ec05320b3629e03aeed0f5aa9a4f70d5b729f2c5c842e2c89a978d76c4b55ee1187ea6574a4b0aa2d953d62bbfffaf5f7e294823027b5d72cdc9b8550c4826156f9ac0b26a459b25b5dd9c4fd3fc501da600f28256920eb8e53f79512db1498b6d54ada93795394d34a1fc88156b24b13c0946dc10b8faee52387246a1220c77c547cb6032a9a425b7692b18e323e326b49ceeadb4dd422f81ff046ce52962f04e1693d2dec3a3fadaaa5964b082077162dac72618c6ed53d0c386d8420a950d011bc4fcf05e7bf454542a1793a4ce677bb5215965e21158862c15ccbe444dd75a8ff4b5bc6b34854a35008dbb9f1059f43628a0cc2e22717c6ee84cd934c94ff7398c401ad79f7a21bca01b8e020f97b00bbccd770fba3c0b69be6cceadec93b667ce416cd26b0f41863c35f4817a31a774b2835df15cc5eb50bee2ddd17f82b171e26d06bfe6d153c9f1428637b630c48e2df21b35b2f47271284fdb2699c53db76dae95b39b6b60d8b91b07c0bfaace7b089d53fced8bf36bdb1496b6254d0561e77ed39f87d48d16ff245f985b00421d79822dd5352052a15aa329319960cd0c4111bafde18e591a9c1b38d9ea2fb42fa670c8aa1cd1f7126f9de29bc4281005379eb6fc36d5e4e20212bb133bb836b8843107a3a5a86ee2ca26a762e1a529a52e9cc1e8babd14584692dccf9f0dc9b6476295c0f1af5d7eb7949f5d25929dd7ef5810c2876ffde75ecb9fd8ea7d42113c1aeabc232fed1cb78a7aae405d133321ba298b80dac3996bc080feb3f7d467ae5467055b413e47d150231a93eabe8134636a2dbbadc3ee8aef79b30222d276d4f49f1ea8bffec6e6b8bb2e6471922d9ff0e0a63502052b4010a61407c44b67f390468c043c6764de36b1cba422bf32aca272f3188c76a18459e71ea4420b3fc447ac6a0c044ea89b6ccacf898843ea16c823f2fcff3230d4d1812891b33f73db70faeb3d3968ce376043d1e1ae9bb30449979c417996324a91917d5feb990682e50e993f63e6857f778bf05192d0fd3843277759975bbc24a3baa10699cb092b833bb62ce8d9e2a979516d74bce29925a7cbec20453f5b4fa52a9f6a270d7251a45011c71e3a7b51c06baa2c135b65a1862aa38bed639d37a42bbc3f864c87274d483207be4f00bf0302db7012e05142f7e56fa4435bb4f6ff2b259cb792b59e49c5e840383b0ef3bcc922ff49651b5ff8b5156471769e41e4eb49ca3448c03f7976c983e7cc1872c2224192e982ee58566c92fadc076667cf9420cdd2529f499534ecaec0213a58c6a0bcfa3b6ba6e7f26ce34666e16a73388e473b17ec1abf5a1d2973825f8dd8c2f731260e187f6bdfa8274bc5d6d4f5b7f78e7e12c9f8ac6ac1f26f4533bf7a99f7b5eb2e21cd7114123c2cef24922eba1eeeb8f09589711e980f1e1ecc1cbbdaa124ae182f70470b335235400af6189ec8dd2bd7f413ce0f377f34e1decb9db7b30b177f6cb3b1897163ab1259b2597ebd052ec867bdebe5296c0e88e13ea1845b68c253a01b5b3c74c3414236119c517c7c4aa6ebf37a986922340dffcd63b68f041be9d5a457cf56ee0121b9dd78717b2e88695181d53ed756c6846c0c06c7aa6d928314c73c98bd41598698f1d12176f06938bda43d998d8b7e3997920c97e04d22519f62589f8f9aca85f0c758540b27314da7185eafdc070a838b7e2f8817a465a9e66ee7ef041731c8dc202be79b251f343e5f77728f91cab5d5769911953150e95677567cf3b80b17fa49a581af388dc305a60f2451de0ee0f6096a18652db8a977dc22351dad7de88de8a31d644f40fa4b5b1e9f2286fa46dcc5e00dc25cc89d8b4672c513c1a8414adc217f54c39ed23ac9a0ff39d681a2e9498c073b270ace91aa39f85c03ad1152c5dce0a71289815e948897420704cef23aaba229230cfbfdb7432e32752913585090673147741e340b647c12b05aa3e94b9818c4b030fb773e82fbc800835d89f1f4cde5c59a81e31531cf7db83755e97ede92f0a570a7706d6291f14347cd0e52d760d7708e5e017113446ac9fed8ee0727b9dd24b84c0a05193d40a66a122530e262504eeec1fd6e052b26030bc7381f7db4fb970618c040530231e568c5dbb9507099d2174e2419d0dcda7ddbc6c7637e0f984fd07e1ad21902acc6c21660516f3cd7f4b04b99ae182c2091ff3c7091cbb12dec94788f98cab6814c12eb3a2dbaf5e91ffda538fc330b355f822886006f0f4642c1ca29945b93afc44c3adf286d694e4417538fa688448e737b2e3082ee0a834e8e742149a341686dc4917fc4f0e4465e4006a0f08c27425aa5b46de610fc00cb36bc6005d9dc8e90325690c87422eeb57273abec2b2c28fcb91c6637f7957ecaf8cd05c277619c9ddd491a597e6a93e66aaf4e621c0be51005bcd5eb3cde631c48a406296facdca217ed64ac7a8f1a5cf20bf8e376bee79cc2e93231ff7e612a9290c58bde8bb76f1ca439344f11d320c3a22e5dd3c35616c8241e8b078c45e74186d6f5e4181907a532df642cbe25d2b1d5edced2983d94b505a39d6579235f7a8a07775788ba90f464bc112fd223bebb2c6dcc8412d8c4cc2202c117a5e62a8b48a04a339f3a1a8caaadc13b559bc3c844bd6c305773a247b1c5516d368675c3e33ca854891da3c62f7d7b8ada8499b9245e72854857f483a2f65847be148f0cc278887f9b93129708a853ffca8d61d7f64987a5d325c6da93c7d6c5bcb45ab6d3bb9669c699dd4c7e43a63e74a46ca5f8e2fb7c831c896a42b846407a1130edc27263d8adfe05748f85655774c9c44e2a2c3ae8be5ac58b0485facdad4b23a5a148eb346178aaa97240fa705727094a3b036a6df39a9efde68c1c3998c2ba38310fbf737da219125b6f12b31de5ec2310872e60e81db53987335ad2e51380e7fdc6b68fd1133adb7ea99c49d89db0edb0f6ada9c1c148eabdb2e581add0772b6a20f72d91764dcaf85029d1bce36f27f48e65f93d96b3f2be92dcaf1c88e3fda5b0c7beabde4f3e35c065877042a6c822f21cb5a5655093d50099d4367435fbe8ea4bad01f143486d91d895f716d2c3ebabd3c1391b32e21c21a7576f36e2645265cb8dfab59949149ec52ec547961d3f65cae8f50ebbd6c0b140b8445b050e246c084750b5da980132d790643b981d7442bba3f114a50e310c11205e05591703084ae19f691b5b8c2f61f095f785b39415e3d6fed0032a5276f66a5369c8b7add722d8fc46a111d50c5cb5d471b61dececf48ae8980ae878fb407c7dc03b73ec7495386373d4128593b2df98619828d9a76331d7694e8dee2c064f1d0f4d2d2b88a04207ad82f4b60f4ce99ea77ddd58c447a5993de3897b502ebe12d6dd89ab4d07641ba3d0a98455b3e8a23bce06ee21d877d5cb73093c73062247196d77c5162c659606b657ca0aa9629de24f3ce33ad9ddfdbe74c7904a387a1d98a47d33678abb5e6c5c17f6e2b5fe868eb84ca45a93b324b67c25dca1b43d57ef3c52c18733aa7ae21ea75078418a12c401eebcdcb65d58da10f380c6e9ddcfa969de0142bdfa6bcd0e1c9cb9f91a24fd727fa6bee949bb92a1f18efc55cecf7a068ffa3cb8b1dd0b7b4b0a89a35b8399d6839d623ca012ba4d75413bb46cf51c1f78b92e368cc9a58b78361b58a294352a4a4a9f2f7c943c78222a53823fc275e5b27afed1c3171b1d713b0c9480a6203336ae6dc872b05182a27a2db6cc6da97cbc3ab37c8d2022fbae8da67d10b2f9534ff115fc386f2b132cc36a6389ddf0ddf747f64160e814876e2e87273db59c20b583941d3b9dc1505dfe8134377cc460b819510418d7c312cbfd8ffd97ebbd2317bc8b7f94dbaf6aacd8f396d15ebea3e4577fb0697b497137b51a60cef7753144c6f26d5bd77561e95ea531a504446bf2e74013b1b4e0c69e7c68b76931f7f03a026b1a83e32b4f9ff767c8ce84abded83ae0cd422713cd5ece8f74fc1f6d3d73eeb0f9ac511e76b5dd3abd6c89ac0e52c029d844a63d567b384c75af7ea25e3a8e997c162f6299f32f45ac7c29beba3ec9ff6a64ef0097896811c8954a342c7ce43b8ec1d01bc3607646ae3b5e0e9096b0ea6cf49f308a971e89185433e5cf809d7bc2790d142ace0ca4f78fc62cd27d04d40f633b0a6ad779ba52b145f58857816a46bf43329994931c2477862ffb7be298fbbf761f9184572098afaed85c26dc580d1bad8754505edecbf775521359eeb18f7851290623a8a81c6f154cc4804646cb5b532a03c822aa49f69cb9d62adddbf619b18066845f2307741ff49e8e327525d0457dda224147e5b6a86eef998c6b800c2ea05f2ff6a3a82f018b81c76a7a1be53dcdb497945f83d98fd31c71ee411d5421c275bd4a3703da5ef96630cb9ba0cb5240e209b729a50d9abd7464a2cba4014f2eb257da110daba035b3b61c8f8f8a1c01a3e77b375a7ab313f72787563e1b3781df628a8d045f028e75f48b2272e4a1e2c39832f04e1dc38f9e873bc152d3ca42244dc6ef806378b6c0e0a9d2f6fb2bef1b53a084c71805fb456ccc1d5d876bb3a5e3c6adf52891488a72207131d7bc0bcc94d9e46a01267f823cf13ff932e6e8081b259a1426b33eac159194d2c2294f2d6dd908bd26455eb0eca1d7c5e8f03b78883bbc90eac08327574b795e9e7b8578651681d54f1c57b7b2ab6887305a25334e46584c24490ed709e1221b9e86ffe89ed5e52b5c79bb5c7abbe1e1bf0ed713249b78777d9fb400e894e1dc54b9dffa2aa1286b8535424a9869c197cdad92a26e76b17e52cfe0b221fdc7d88e4a6e343d11d0b174e2f77cd87475f6a930a61bf93de27a97e53dbdf28f20eae08d4876a2614b13ec2a37a7d3e83e15174584ea63a2c617bd1b5d8ad8c945659a323313d589a9bfa118f4a9afcc86a33f0b811acf40d83d1e5c7c7b292dda916b54bbe8389e3f646d767ca7fdbcd610b1f58bee9a106399713fd865ad894e1e58e21ff935122e10ea5f033393963347b324b4835dbeeb2d7fedcf9a69d322509efdac577d3684dcd51849e273a40d607188a283d1b1614011c0f3da7c3b061a8086dcfe8fe3dadde2e939ab450dbc300ac7fa33a23cf6dc786ac00054348f2587a4a035bf18c2287fcf5a886210e2cc76a032aaa56b6fb97b8e4660ae49585ea93d6b14958d4c3b98369cb3edf53bc221645793fd2390238ddc271da100539069593b8739af6535fae4ee2f5c5af0365c7b4e16d120501c5b29c6baae8e445f508f8dc3e9b54e9c3ccc15119c878364425bbc6652942fa956904080a6c94e0b3715199359f4020f95e5406daf2c93aed3d2c37d0746bdac4ccd7473aec1478512e6e9d3a2d51228c5b9cecaa8374850e786eee7df245d52885cdef16c7bdc0c97be982204135ed35a53449d43417fc5fb6951148c4d20494d2cad3db9212b1ec6fcc11f2ecc73cb4691aca1236aee29a2823f220fab6b6b6ab9f611a49ac54e2d0dc39973fb01fda1de61008b60de73763e0664150f844160d23225817646b48b60928708493eb4490d7baa2029779274bf90c6761f730758b091fa2e910308a09e34d808170a11a383aa2a1845bb45aa79bb3c3d5a84f3b3f27f4fe2786ebe59422a1a863ea5d081f5d17c3cf19bf36e3b9d7ea147be9a77161f6a8014a8fd2560ea65817b5dcfc5f291daa22d794d6abf462ea71c6b5fc881911b6d499e082a70f37d738fb849f640c325c17e54f028cf397cbbd1f84b21eb99708728460bd918616e2f58833f056acad608c47c7bd0cbdf4bd4b24682d5557c119aea6cea676f45393a1b21370e0df394360818688f6e5bb5b1f0cc7636323e44e9dfbcb18fd55939c1930c04b5f315c8eed9fdd83950c6c45b986fae5fe29534345ee47e91000cffde132ba9ea3e9b60ac4807f14a7983e5a2cb093f4ef52220a63112f0a86977165b7cbe9fdf44aaf5159bc80b17cef04c4e624e6ab48b86ce28a40508476fd5c0ac9147db6d4bb01324baae420ccdd4189095fd2c08a5e0925700c56fc7488ab3050f8e8ffaca6cce5dc53303c80dc6b118ebec5161507494afe4dc0539d220ca85466dd21fce22d9b34e419717cfca9bf0b2555711e4271edb79b8eb6459541047482add7d955031dd10be33bc9e5585c685175285c4117c57512b9f83efb6cc4c16387fa38bcb9bb441e7c656061064ac1ac54f88ed3cd2b9a0235aa4e27255bda7036622054c6a0f237ff902493432ba04b70cb9d45d05581f41c737e2727d4e2e30450a99191af39d73b547fe57ccca3396bffb746da9301489317b8cb52189b95f20e733f51e0db8c353aea058db545c8762080a56fc5d74cc2e12a6653987dc5c2d9252925af3caab5e039004acd6cf180f2e9723260ab4f4cf421c6f88245da5ac446e92d12d52e19c25f1aee6ff52756d76513f62a6210f8fd8d53025d81d0ac132d134ba9442d150f62dd7ae824a489d916c79a8f354f3ea7ab41da338ef757e087615022960894a7a3e99662fdb6dd641ae4f5ad509475b3daf01b0eea9955fdb6b60b3025a30099e3a87172d21dc728719c55f9bf2f1f5a1cdf0e40cedde227da790e3dd2dd3dffe4daa85d69c3393398da6694b1cd4156ef67bf4d5b412e43262618bd23f5a9c0708132e25c4633bf33143508cb4c721aa8c594e2c82a7831e568bb9ff6f69187a51bb0f4256d6ac8e766a79e8f495b7f675ea28d164e50f3f8a52a85dc14b3e97b609dcb98e5f344b933fe0543d6e845f913ff71f314b83eb2fcfdb9ad811e5057c32f5f0f307e3053a285152d6ea54040d4dfa0d3e95c57533fa6edf8166a10c5146f20f5f17ec6c2715f2fd2eda06eb0539d286084216b42093962c46fdc8a5f6dfa3e77acfde45d31b86fb302d001680365f459404ef8b701fde8e4c173cefe6b46e2f410b989c89d41b52f33718dd819775c5f60934d3b186051c50ace494af54c0a63ee23a5e09208eefe3e704b1445c871476173154b9172e6331f76c88e6da0e09bae6c0212d01d17c28b730030beff01c7acdfac694a8c520ef00f5a68bc40d10b93238f27f31893b95768216feb00d56ede5abbf9576281de5151e9f6982ee01d47535255c434fb70bbc412c3e29960fe2bffeb7bce3a216dd23e1af6178db48feae036de98ff33d697ae2e6b6d37f1050efd9ab0c5d4172650775281d7673670690f8878e6ecc56a36931513cd8eb632eead37dcc194a984c8532cc754211fa2655f99d5a34c433aace33883f60eb61aec2acf583ea318fbc81b202b8c122eb167db38da1920c1142edcc99b3e148cc18ef152f9351bc0da35bc92fbc4a172af609fc87ba297abb3d27cfabc59d8e9a4b5c07ad87ca8c79d572904e70c0d11fbf3d23eaf19139971d7f36528e77315dfcde44aee9f5241bafb2dffa907192da10a807f08727af00cde73e1cfaa6f4208c42ffbabb7ad6b4647697103cdd3089ae8b6c9309a34f00e60fde6106b12cb57857e6a3d4d0d44b52e94eb12fc45ef1e76bea308d3bb7257415681870dbeb2753e0da43e07e4d89f9cefc5a5c2770a3a34143e245b62854428644022da60cb7fd1028a0730e4b17b07089d385eaa0d8978e132207ff93c4f0e025488412ea4dbd73a60da34f08ad2ff352fd492ac0681d67c6faee3746e7515860d5159037425daf801c593220283b985b108f9d5e8f7a5bc7acd1cd14b5a80d70a3e13145ed159334f85166a80281e0fddbeb7d8266087fb6f84d2145fcfd25c74e625d64498b48bc274055d217325bfc25448cb7efdb7a5aa9ad91dedc2c8e93b05858cecbb50d2731fb3eb113f6ad1833aa968a058bf48176d40b65d10fc17479bc209bac6e55c01145cd3aceb68e8a02b3b31005e167e86938b03737395a8294c73ec2512e211991035cb762032e0343373076cb4f5b20fa3828608184c535b9398dbd3b05e847759e0e6f12e19ea9ce6bad89d832e878c65711a26120b8f443149e47658878084344ca490ad8e1157f227c63caad06f28e8c95dcb36583b5c118217b6202fb56899589234acaccd2062844cd4c48a24f241d6cbbfd559f5f83ffafc2b2d1dda1d2dd6fa3d39eee810cce9e7ad36da8b7e9cd69afa5e8b0af76d8ea6f6359b9075123df75f551ccf71e97639cc0683acb54a4cad361ad509bdaf0e594bcd787fd79935ea90bc388a5281dbef67a255fd089320d1b2b5039a29be107371387f6c228423fc1257f10efe35859a2f5d2032b107e745438fd65bf2157eb115d4ccab599ac8565e0f1ace7a14c9718b870ab47db367397c10e38a619eeb798d375def29cf5934f160f20113f05d912ca071035f031c4fc418dd5476e9e22da112c7b06abde006da5ba3d6ec7006d36b09bb356a21c03a358ad4da684d3351a37bf6433eac695283f11a3692f78c65ad0109c2fa5374ff1b1674984cec2aa5141fc0397688c1efd2ae69fabb50ac33cc90d1405a2e757fc6b93e1be86aa66dedf50e7624dfac45c4308c1f4508732fb4aa7ec7dde3ee2cb74f219d0194905047155a9322b0f64a65b43600a3e83164b0c0418e69391f4463533daac9ad6cd58f277d7654a0920bc9e107644fe41b0d5bbdc38d817e7e645c4f5af90e1ecc12c4c5237ff66d70dc0f858c3dcb02787ccc37ffc5a17ab12ebc8c782e0d567614ea5e48753e1bc1a18effe6b905d5b3a46b3fdf0cb8e1733617b6d28e34f9718c48f5803fc1314d3b2a895ca18a7b1aeccd4568fe82be2bf884913aa57b3190c27e5b5510d82573458f35adcb5021070b83bf7952584c99f6f9e734fbb1566400df1a88889edbca64334314800c6d11cdfcdcf6c904b46315f947d86e089735d01820d2d6945885dcf5404123fe7e3154fe58c834a6b6dad6f38474bbed755001438e47b86c87c32e5490bb34b4c4cc37d04556f964b55e6b26fa75b1ca6dd19ffa196897bf340ba1bcbcdf8dd9e511a9f3bd5f658c0ccdfaa7cca930987f36f4e14995e980c256770b3f95dba6ff54da21beb37acc563404eed6235f0218f609dbc5f72629678858921e0ddc924977b6308f2bba786c11d2f8e5ba053b5458e9bc0c4ae5fd95cb45820400bb8709d79f033f584078d3579cc599936a6a9ab08ff2b4389aac39e7bb85354e46c434b4b3160e698638929fdb9f8e16f7ce6ff2a7b50d7f4c7134f9a36344b9c99a6c9ff829d76d1b0175864dce1157bdbde8eea4c5949bb874c3bf416774f81d669736461a9a1cf89a96e778c360022c23ceb29e4c7fb45b5bf3a1ac6cb83b39ae8d3489989760247504da9b03d330f7ed04b1a33f87943f5c845e248b06bdf5c4e1cee362e73714ef2fe0971fb0932d54c2a22502298ae85a722a910fb49c60dd944afa72f0895b1c71626d5ff2b0ba53d87911f0b75351628e9898ba09d3b319dcc64190368c28ec062f840a2470bd44253494d3066525483c1f8c5acd60ad42e2f24968b81fa0669c24e076340b432563fd7c548411ce9249d10240aa28f824251d555eb48f5451bb82ba863168246911997b33248653a1078fae1eb7f64a03ec616f6862051c9daee0771c7a9063393f0db110c695ad966b5ea3297735507290e93764412fd7cef9ccde3416420ceb3bbbd8b52b04811f0a1ad6b3828fd8134937fd01e02c585005d80db8b66cad5957ebc73fab3ae4602aacbd25fc21c7979d65fc3b5477ee1e6b9af0baa4c3c69b95423726e0e5fd3f0febcfda9a3fb8975ffcd899c1ccba5078a82fb0d95c53110f373df1b7a82ec2a1cabba7b3a32106584f8fdaf4ebb2e5cdac57f0504fbbd358aa6c387a920368093daf9121fd828e19ef9927a04d1983f67e15c4b61bd846568dbe360bc49a67d32aefa63b829c65fbee35da8bf5669537ab8cfb247288daed8e2bdc84bb3550c026e42d99e3f776ecd18058aafc5343d7157e01ff80f5827e010e5ca234ae898ed1474e110fafe960646c5997791cf114932914ae518d6cd7d0589bb66a9cfb0e37d8e028bdaa15d9d45fd8b1e98c1fa5457662789360221e66bafb40e9e9056031737796b8e3074e03d8864d6bd750b37bf864ed08173ce580a9f6d089d84383951ab9ffb7e5f18c275a0e8ac9dff7e77fc32eff27fedd97edc3b3947d753c558483d9ffafffe3011412025103f9ddd9e1624e9c0b3f4f1729d60a97fcd9e9892f76fcec2fe97156d27183f9ae97938c1e52089309da7385cda72134225b0f6cdef1eb58dcff2d91d554c063365dd56ffd25d1e879c4705cfce483a15dd866a0344a3316a03775fe378f7a087fe78881e47c303609e73da54437d7b0e7c175c41f035d0d847f01cdc175764f14c7798cb1dba8fa72b4e92be5592c1b2740962cece954be863ce296c1c58582ba4a853527313c0e493f2c579d9343c517a5c76f8c9b5f8ec007d7a3462f44fbd694471abd79759d9ce3aabc22dd9c806a5671985abe2e0e4857d6671bac0c24f01b0f00bd62b7d47159c44a4f73bbedb284e135e1dce9337c27453d719e1fe1bacf9bca90a64120bd3335e49a04ae04617def6ccef3cfcfcd2b71c4ed16e4dbcbbc4c4baa4ce2669e54d4f783fed6b4a8a88f573dff90623fa234668acccb7dcc41d97ccfc09d0003ae78a84af6fcc3b0ff42a3dc8d5f2606286317bfab64c17b2a53aa9566f27522e7a16a4569c82a4b57eb7b63fccf8118bdca6acd9be20855e4fffe741cd9b53a43bfbfdc441c434f4be5b257156e2fb79283ecf586c4d509b9735c8f6b0ea42dae32f0d3c17faaf7c2e489b775f59e92b7362e91b4c0a6e4dc17469c78bfd9d7e9a5be9f86c760e6d7fc38102c04932662501357219d7e5613c0e152ad830bc3ff7729dca4a6a780469e79c8aa1e90097682f0a8774b4bcc16434876ef69b955171c5da29cae9b0aeea7169f316859c0e52110025828b3c90e01c371bd3d3afda1a39cf566207c973ac20b84dc5cee587b61e8340e12a3170ab5de07a7b72c0e9014b3c1cca4ff1de91e789c5d46e4cd108c7ea5c6de69d15b854655d8e44fa1db96d3f45f6c43caf9f302631c1f7f094d96db72c534a31a2c9531cae328f2925e8a18080bc403d4b7902246aa5b98417158dad96a4852fe4fcdec407d8dc147e58c78943161cf2d69c44920557b2f9ea711fdebb094c779a93644ebe0ee1ca6caf45aaf512c63c2e836bc7ab46f9710c495b41feee7dd51516464c997d80bbd4a6e5e53978e166aa028f0443476e4836940c49672208eb743a1a354cf7311838b9b67d8f047be2f9ad5e11248ac671ec8072ece3d8b6d4ac9d86a60309ab4ed3340e59c622b84ec833229d58bd9a0cf11bff87452b21e4c90313da5213566b6013f66f47dcc99d8aff5d431ddd0d564b14e79fb790db90161f8a3ac897bda2c7ff92dfacbc50a13a37b4ebed6b3030ad2772812bde920bbdb95b246b640852c75362c827866d78572342c211a5fbed89f2b552a6eb25c30c48e03b6bd5ae7db81e642898b8cc4237cbc7455d369f97f015d7a2dd8ccf8ff196a7218aee275d53c05bd54437143b3b50b1287532bd2cdebe6a33591cbd5b322404869ab25f2a1d575546dd2c998d6445a2d2af0ec14cda0dce93dd5ee2f2ff04cfcde5fedb21a4d16319e018472f23e9257dcbee194007b3fd090f3683d6e0b6135435ee3c58f8d178f1b58ef00169e5151cd6aba44b564c8b457e96dd0ab916687c0fdc7c3050b1583fb1e5500b842436ae73ebd3daddbcc1b6ca68c615ccfcc7db2ba0b34026cb9d2341eb110e6f9d22962f6bbea325ff8863507888931136e004588249d8b365110e1e354553dfcde822bb1772900e5934a7848c9992e667e498ab52f8980cc0e0177ea81d3962849b6589acbecbe55fb401ab3db7f54a9554256ef31e3947f7863c5acb772690e515db14b2b8bde3e2a7c06b68e24b30e6a94ba5c74b1539cacf4a5223c3e896859affd340ff6bd758ce7fabed5035ecdb8d659f1e5f3c2573c72081c992c9117a5a8cc48ef3810f23d4ed3d3b30fe7adc509dfe425220873a2e99130656b7426bc392dcd28389f9272d7916ea79ada649bfafa5d430497beb62b265d17519bbda6cf4775a64d6ea168eda4741e4b7378c1c21a9c1ebc79d1a6240fd91a2a445134b784199d1508df856dcc6f914fa553d3c448f577239f7620dfc6d131fa6b02f7a377177bc792cfa7a888199ea3621a7c4058db9c75c85cc45c10e6a22df0a772056a3cfd2baad2cd326fe15d067de7e96ce5ccf5e024aab00f0d018ed266faf2d8ba1196ab20a08e70023b02c4e332acd14f5efe973381f0c4f8ee8d8d25ea320bca30cfcc0df3bc9db7139dd6ccc237ed83145495443a1c853fc20aa7ce723db87ce996570c13e850c922d2d9cf4a3bc8f4c3d41c211b7708242eceab45acf0a082927c4b1a3e11ea4c2954847ca289e97d943fb2a50081375d11091fda45d8341f278c092110a53123925016e094953129478270ff478c22b94177ac99d979413df1ef4a5c8f38f3fb078db821f0ab86e48fc7fe90a135a4e2994544655085ac37d17316fcdce235849ad686357613c98ddd6f906019f849d0ba1de2d7e5d126be2f9443535b1ca8235d66e47ef27da55a490423513378af6eea9653256c1ff3aeeabd0ee45e350a5d46090ab578a904c43b2ca7454b9cc9396aa852ba6bd1726ad9800ba4163337355d3e225a5e5fb80ee6890c1de55ad49ab458fe2ae17e5bae9c0d0c46fe30cad9d3851b44cd1b08c7783b631aece658d68542f184fdc999d0c3692b8c2c8fb900c80420e602c7aaf1222e49dac3c94002248a959bf3fcf96c4e230b9645eb9ecb7df01e25bf75d051994f56600e7c1e5e7e9e2dc16ed9e9efef756d68c483ce1855c867df3385e19f1c5c9c5bb3dcc3d6a2c3063a173250e2de2c238f1f5616911d41690246d2f64f4e2ccc98d87fa286031688d8edd2b38349db6ccf8300ae805adecafd1b4544c52cf75342e2bf4203ec6b3569707edb07d9e7ce025e45dbe055cc6deeb6cee3eb0b60293049b143f5750281c06b3c6f03c8bae22455f2ce27edda298458867a2232962f348345c6dea71818722e5bf916af16ae25edf7ed7e1c66577c6763603ea27f989327613e798c7424afe3952ea82b66cec5f911615f76e658157d795015e574c987afdcb6f6ff4a5472503c5590f2dd697ed2530967ca8d799b3a623ac496bdb0a0d3ce7abad79935d1afd523808e95ca3f427976986dc84389468b2c8d4a0e115d4a619939615f227666fbcb53a485f15d1d2db1b235b11023e9d39e7ec01577659f1d2e66bcdb3e1aa6ec552952ce4a63c1ffc47d9a43ac4b9cb79ee5d228f6e609b35ac58b894f7bb8d0df4aeffd6deff6434b8c04dc9b2d8afa2ad5a029537472479d1bc3d77369b78a3a51e05944b963a693a820ccd5e0af9545dc43e470fc584b069f4f6d20bc2c92f4d1773c3660e280ddfac854c5c255b985cfe08937b8e5f6375cd056e2592787002d6b6ec9349fe2eec3a2376681629cf4c2fcad362153dc0d2052af31a1f875b07244ea7c5850404c0d961808007569888ac32e6a7da4a822629d7bdfd0bd4a0b67baf88f76f79b23682933377c1b2abe09d83fba437f1205063df2a57aa3da021514245aa3c463a27cd7e03abf503d6349946b435bd24b634239d91771469e1421833644e114900135578360e67a1e0f0ca8b15fa43cf9699e4e5f74376823982d33aa5694996af520a69f88615c5673c2870261b566c373d94e92d59b84dfe3257246a5efcb14f5939c6555eb5b646f05f44cb0902f8b402a9249194afa38a6f71c697313dd11e533459e6a28c240014f31f8af2b891653832c487fee9cdabfe1f33258196fe6b728f91e032d8b13acf67f92e8b2489c8b390b43d4561c479d38b254c415dddffb0a8502808aabdcdff721bc615217b688b87fbfa8a9fee4bc106229e1341a5b3dc9cd09668ea67301afb782902d89b1c8255eab339e55449f024bca90c68c02bb7822d38497989fd4b62517ed31f5aed51fbcd15de6f2817456c9aa6c195b7563c653ce56aaf0aad8bdc8158b4a4fe21e7749ff3a427b735836c23dadd9359f53df1809c444f8c36f740795c6e414d004085c192d421fae2508f71ab919d12beb25ba8949a4b9ddebac0f8daf22a9e373322576e5fe662586a35480155075334dda2751267439e63706613e21f2e7f26159c994d4d8759332bd07eb929b9fe8480e8efbd0f61f02af70cd71c3d69a7897b71d73d06fdf7a1793aa35251b19809d08955ad8b8a6dfc9f3d6ab03f57271a2e73d91eef48651b7a42b2242259e696092aca9930dc7fc67e7b32f628e59685ce82dc6510a4b5250bbec34f6e8de4fc4f35ffa74c699688604516a9377d0346570a4730fc28b903bf507d65ae85dc8ea64704574bb88e5874584acea598b975dd62224a1ecf64258a5aacf88bc2a243b9c3516fe4fe47d1616c9e648ccb33eafd4f7f20a43257a8447092120795cfe1f6eb9a34eed1f6dfaf2260017680bfe992f1b202a00f2aa7e3d27c0abee5c89b2c1a42c4234830409f82cc2987e1d2cd96d847b1095690a995cca12d5dd569dc78b6717232b2a39089960e7ada215b5e2ee2371dd142cd3f7918d780d050b177d2582b35d4b4bca103fced62a57bed631ee22376146dfd143805a575e182569478047c2963671bdb700d84b1d1b723aac9bf2235ae9763917d8fc07e66e13b8b4de72a66886cbd478de3b464d4bd1573abd2219c010518f7fa4081a55f633afa1189be1472279c3820c6976ff3ec5b75272c7a45fd030abbaf00d848267dc3e78f52f123e1c68f55dad78555f38418120d7200250ffe27d8ea0b33baa638f1fc2e02c77d48562333ec39007293cbb65cc426bc130ea621e9ea466960da4efdf74df1248e4395e0b0f2e4253b481f70c9535834c10e89377957067a70c66694ec4a503f68aba944a1c9c687ca54ac2ea035aea45cece4786c19ac39c9c358a5e164043bc00b3cb35b1df6d36c139bde22cffe47fe50b8b23d11fb3f2ee8d59f9a154565842409e62c21976084eeba62abc40eac884c6ae1cb578636ed4d7c749404ee4e0e4bd133aa46c1b5c4fce6dc407c0f03b63fc3ec7ba308d37bce2aea09734da1c227babb86b19f67ab1331a117af1fd05c3e6e697b17f319446e92fa9de5c6150b03f6f63f2f53027cae0f8886edc1ab624b80c25bda5be2a3f7b19053a30a59ce5bbed5ac8c2666edeb5056d89b3b935c9eb4ac1fbf522a55609b338d36f71c56a06e17aa16836472e82b56a236df8e73d09eb91c9f3c6725259a11ce80011b46239535ac519acf846face12995890cdd4fb9df904fd2354e3ad9f70c1237cfc0a58d99713cad68bb6db0bcf33f4782cd7d4d301b5fba88e2a4153ca863e9dcdd2802b77e293de0e3fe4d1f5f791f5659fbbe3aadc8a1971c26da28120de6507cba1707b3e7190eea62dcde22d25985b68b2bf4452aa1a6a25e37e50705223d790f96927c2d6e1f6d683602e20a99ebe036efdea58dbdc33ec4823975909b42afac2cc9e5acef39d59cf5861b54e6c44e631787f1ac3b2350606540e3dcddc93a0be123927d080de7f38aadcf1ccc91e97b8c002e019c61e649e23b7f1e0da075e9499be8d24a88718b76acb2aa1929ef06e35b3962363a5e7ef0a3aa41d49aa6095b96a88912d79d48a846cc67385ac07e04ce58b49a36b572219783fe1b1deda9e8f69855cb200b26c854212387da58cc7879f3c0d6bc4d5f8d3a7d51f1e98521e37e0cad1eeef495a620c42794c06833ae89a0e5899fddba776396effffbade7c04f5a8e20e13bef0fc37ecf0137c73c4efc995c3443284db7964e6a10564f7d30da5fccc210ffd7358e0a554d46a8c803bb1d0f0c75273218308f0443e70589755cb09fa327707ab17be39c8a22843c906c008d0f00d3a024e646bfdcfd08ef593ee514c951fa61698914f76f45b1c4d575b20605035f6bdd7b1cf45ee8d1a540fcde2e11004a8dd0debc471a11072645695c3068b09cb0f917ab032ea200b3518a53131575f99ece1848db00d6ede577d7f21e7d0618c1ef0f7faa54283321dd9f016a1f2d0b28ce450a0a81e20fb52ee6b1502d1365333dc58eb94954dee554db76d9ebb868b992263a44ff0c885a1c6defa4acd77451851d87688b8866bc5dcb7cad1b6b70045504b22a272bc48e8091c7204b7e16ad1bb475fd9d31b0cd79db86a64a8d140754ad597fe68e1a580411184f823528740115a9d6c5f5448bc284ea3c0c911f1e4dee49bc9280b7615759b0b89c70e8815ee4b797fe7582d4653513e8d9c43dc74eace0d1740ab04f1c4d57c913e14ecedbc143978c85f528e5d6f06c4ad5c5b243af300ba22b99f23c8a31cb17ac91a43466707a97aefc6f69bba0bdbf3227ca6ca148f7b6d141e112430d005a65b42f9044c2a6f0bf999383a38848b3ed6dccefcdbf756d591b60081ea4a6b5424a0b9605abadbd926523a05cbd65117b08f688944f5ee2689c643503a66a4cd27a8e61a89018287450eb15716d78e1a956e4dedf08a0d2004e7a857e59ca1044d92a748926db9b580e1c4099a2bb13b01e3534c34ecf4229c0366565d4adae7f93ac92f2622a2c944316612153482475bb6e8d1037165ea672fe1816e232ee8e6493b5f4c2f9719735d9b3fb866c47f2ec8c6298828751a2bf41974f99b523ab95e87a7e92b5703126ed983799c49693ca0b410c501a77c440e23ba80d2f324dd9de09647f1b0872947e0112906faf43df65fcdeba66f62d4aaf752da9707458b87a7c609620eefce5db95293bb1b160ad1822ff8fa32dc2c29ca7d8e240e69d7ea90ad5825d72e0059869e182945404e2f2d4814f9706f8d17046df264c863868b7348e54055d462629f62ad6909a404c12d4a5a4d15eb4796dec7f080e1a9f2ba737c198990d88c58b2c2d457de1a153d5b27fa876eb8407f17518fecc1fab7fb629ff0a14af65b53e21eb529a45214394b35e03b87729c276d3e57018382b3d7eb64313d4f87452e480569b902ab4918a97c8e59199bc227879721b2e2d1816cd5fc9e14ef159d520bae0fde8f1f4030eb020af4d2074648852f7574f1a53a6462a54fcca33784448042beb06fe9457c9cfd2eb2969415d39c62ad0e560c6fafe224d21e30930269499b3fb0d8f0ea7ec24919a9186482213898215bfaf60e33499b3d4262a7df5f47a2d0b495f94ddd7d880aee88427cc4abb6d137fb8afa2e654833f8276b9b86319509098c37d01bb5cf5858c9a04ab96bb3f1a5505caa487787f2a95b1f60931fde5b604106628e3206027acb43f0bad6f982fc86eb8307df835bdb889320f4d79fd949ec0e35a68235031ae064b8e9572706b31a94b227227bd9a4aed0e34ea34a6a23297ffcdf2e54e643284b8fda65ab4ed43500d2100dd34fdba09152ccc2e19e9fa9585adb6c8eeda4fd3aac7caa2cc520c9aa192a1ff2be52fec0f8532f6632cf7af9e46b8276265989ac1ed43efbdb63f92d6837e284f301e084b7b01e6316107287d608929a934c1c6d3e781e0539e542d215d8e31a029d5a7497f66abaf8b722ca0934ce3e4b45fc2bbf1883fa465cb73fd81dcfc918580b7593519010d572abf890985e9ab5dbba020789efd0f04db4bc9d937b89c74266b2538a78de787a5696667731931581555fce8c7d86edbc4620c7c3ea0ae45236bc0e5d46179cce45724da2c70ddeb6b777e55f2af777a9b20511fc0fd8bb5b2484f1b06ccfb9043f789576b21e4e22a55c4d7d731e32d171b2356b98bc9ff33da713d34afc654bcf0d2a8c2485502f7383272de12bc41117c45b94b46c8c380be833defb7add783ae5e41a446b89d38b4561798311ae6a6620089a4467555f9220da48945b546f38e6599b836dbd15f0cc5ba7b977f4361d32fb53ce260281cfece61bf282f03d6b814eec4f8aebdc040cf7c68e4a0c6d6ebb7f48d8e20dd414bdb9fd828ba7ec82d98324016c416c1c845fd69ec309293f99bd60597918d06941994e400a9bd989950b989f8cd70a0d5feba5bb86faafbde1683cee9f7558646b882be785b93020cf35b944fe1906444f214d2d5c1a4db04781cbc6516933bed9dba5cefdd9c44a607030121663b778b4cf05a21a615d3c6a530d758d68b5d5781d684d23bef954b39d8aea949b872db4c842d0931670e8db41233b9a04392bafc3a69435ec1481c06cd862f01d1f6d548d17e76900c3425607296a4c78b261e775e24b5ca71e3a3bc548db46150c63bab559aef1126f14e0bc2f89252872ed6ea0291d45c9d0d36c3e21b69adcd126992c4480cc37c35c2df17a774400735b69a5c12adfede3f54923a960e1895ebfb037413b78a781e3315ce020cb3b768811cd9452f7370d8a541727aefdf429297e6019f1bc974562a4e820bb1085ee99d2873609069503b82e18069270970ec9d6376692811c3b3e2c15045f02fc8ef5457344bf1efd3a5fe15d989c237722f9b8010566fe99e296e18ac3463889c1ec66e79540abbe42d67ce734bc07cecf02543c4b4473837d1c2728703535b093cbbbd5cabe6591a44763c810affd4a8ef9a9ef9baab17bc46ede3a7cb032ddeea4bddbb913110805bdfec591855b7f821ceca7aac8f1aeba55c91cad64d28a3305ed93ca5fce074f7d747aecc0523b69b0bb3458aa0d699861ed166b7153371e8962647996b043ae7e8fc0799b7b96330072e236f220d3c45f48904e4accc98ac52606eb6764c5c9971b769e792a2513a22894eb1764128ac0dc2ff79088bec343915aaebc8802e5f7f1e12a5362122d12b504c33d9d32c5d66c4d0c0ce9ce0e46cd7ea5bd0fbab4a1d7e20c471a0f119e1267cdc5116ec755bef6aba4f1ce645aaca8f12b85884b81436c9d0824348e54aca783f7dbf7b7b09e71fe7a8ffeca9fcc16508f61990f9d128164a52d022e625177f0eb726fbb1d5a66aad79b1f83fcb9bcba6491f0276050b92354b75d764ca26f1539a930b8f230fac35535ffdbba4a60700d1ce84e2dee90bcd91cbc561ae9173fbd175d7aae5d0842592353700f030f672fe362d98d49034ab8e536f1564d3b7a58ea15d20b006fe6816c4cfd7cc8427c1c1ef990750bd6b8883fd7474d403933e3d5964ac95e1d91a74ffda426866c829b68029197e2f2b27b405cdd925a7a7c040de6fb2b5fa0727554450cc2b2d303df8a0c840d02cbc46ba9950c7a15b6833d90eadd75ce5d5840827e04d79cede532f328c8a0e0129eca2f2e17a0f8dc5749a4552b82a6411604a067f3094084ba049d1718cec37d303c73791b5ec65e6fbceba532d8e3914ffd09701bfd4e7067920476c98379829b8ba4150cc4985b320f2f9541402fc847096749d434c1bc636401c5478c07ee5777ad5319761589f1b721b5ec6d71314ae4410c9a0c00e3e60d897d38a4062c3d898d3a46a1c386837bf4613061c5cb47380c68f73d899045fcdb6ec47380cd17817bcbe68748dfb81c10f5a6c5312dc079c4f0b60eaac69e52885cac108b2adf0955135a1ddfa9e14173fc11f858d48c220a92e346cfe2872fe6930bbb471aef7a3860042281a8b3da9701a9fbed9ade3bd77067fc1fb91682f00cfc955644099138dfa9138caebd4407e8f19e42667a68ef440040db158115b4901e2c0559f8c78d6f1a7382373164cf346c5dba45ab872f101a4541e893a66cd77d551fb52f3e96ceb06cc6e04b2c1588e94f83ecfebfb2bb5b5e93406662205f66d0543f8beb64a978679ab81a2b7058f9bef50d3b57882d89384650870dc0432087aee3bc6a41621f70ac2327799cd990d5b2dcd6412f39bd48e4bbd0465995aa6dafc9a2212a2d622c02a014de44e0f3478e3a56d7ea66eadf00e9ecf7a6174a9a59cd2f285ade3e4e5bb31f0a860f690eee4bc70bb2e01dcd398b54ea654e346b0524c4c83a4201c3ec3865a0c89f4563ae3b89dd21d0721dcc5311f083c872ae77aaa2bb0c0c87fab5408d1041d4d1efa7188b6169bc6e4ee4941909933a27a45b67770423239e5c1ec920832ca63b7949fddc9a807846f4e93f5b821a58d0db62b5f575e5d55d02e660ae369a5406a5bd37b6c82f0ad0c6f3418a7e5394c974a402e628384fd68a8ee836dd8b6db628a982c8009a3b0b7dbe12f49459b2a59660cb107b4d0e325372404fd8e4dcd5ff89af6a0d2a45e1b8030a77f0d6076dae96024be459371374f83c79607f07b7e3c0b29f10e5d4e90d0d7c6897ea2ef3ae9ee9aeeb1f5a85a54eb60e649256b22a361df9b0b1b6ae21f92589c94f2e6efb94f5e0d22c5f158644aa5bb8e28ea91153e243df4cf5ae9bd0b0748901a27a0036572d32baa0dd05522d0311532df1e878761ddaf564d093b9506c203e3798b10ca7020930dafbe939a81ac37092269390304e017cb15cbcff4f4471715b4fe4d92ee227cfceb46f49053e51fc458aa83dafad7b8b06d0e7c248cbbe462271b25359d87a532a75a2440f3970c55d4f3f8fe1d5aece81ade990e7205e2d620cd1bd1527d0814f291e2f3ca550124b4ab42a9f0a3a7a82997118726bebbee2b8aa62e9c6f94b418135e11aec4e11dd4ebb0b6011ba2b587c2b8ae396bb226bd12402fb07b9d6c3a55dacc988c342c2522e120c4267ccf0d91677126feb4313d545e597fe9826249aaeaa80fc33c940ab4f240ad8ca29cebafea0e2030daf3573ea9d1fcc04e41d09022afee16bfc550ead46c03c01c744b9bebc5b8696e850f2c60288fe4c670d12845cdd8afcff02152754c003c46579322b9d7700425274d82b54d210693b91a6e56a3abdfaf9ae520fc2930f1908b303fd9aebfaa4b1ecd1d58582abec88d15b6b8486ba5e017aedd55ba6857a96cd9a1d5d089f60e92188b4f56c9683fa474d93682429155870151069c2627479c51b37d9d3de163553842139c96ed591f6639dd6730bdfb9fe49fadcd5c096e188d88dc9968bbde0ce79b261f6a5872663d179c3286b0e9490ad73b82dddd62ed49e11eb3fbe71df45734ef9bd2ff27cfd4473dd2909c70e4f36c7f291daa8ea1b7159237b4f95aded544ce5ca1e0fba7ba8489038bb03d45795752b639f472467591a716d107af0bb8628e483e88f2622afc5f24741d5af82be40d2ea638eab48b24ba5f5bf1227cfe1317b33d9f892d43e0e2e692a59829b10967f85aca31178c0de0b9280c3e1129e1294ce54273b6f2c799246872812d25d39913d2abb1bb1de8a5869c98298eb98fe722d9e4b1f03e1d2d154c78ac082f65e97b3cd82ab62d5a941eccfb9ec223fe3df54d0be1fddd2de35da90c642029fa4496b13e1ca87979f8e46df12279c1b3424a9ef503e27a58f7eaf0ea11488d273dca21162195303a91da801433d759cd0066c23f371863316e1643f319e1ff9a8fea4f203604d871a9b4fcc7efbbad42b93ea1d833f948fe54a27797880040065ae8dc5383079d26a3a88a9cd132067aad9763f3daec51769726a41c16c61b35647b26fa9f022d798424c42e60ab66be66584570b6bee28921150ae4695cb79824dd28c2ec9b6145394768312b6bc2b0cfc2511767f6fa662a784bec68dce36f5df462329285b717ef303171de2bd1f2faa9169483bc37e9e26373bac923331e75d9223f7e77616bad4c5140d0be6d9001daf8fc54a12f0d2c747467d8a1d9e7df47308582285eb5b1f028f5adfddccacfbb604cc269cb0e9813826354e3c8ac666739fdb8a2811e047ab0dbf71848f96f8c9694eefc5e338687c562159ef30f0d3d6fc9d24d915d023e40e7d84b0dd26638371f6c53813bfec7a47ec09b8639d0c19b102960186939a06f0569f01e8680fc43305d92a9c2d81971a0d75646611f6af9a47644637bc804c374ec38dfe674fcb63a27f980be7caab697ad23e6af9cf8f109a6270c55682d9fabe9093437ca954dc2566ea50dcf9fe774da18716b8628a9d6fe23b910a0fb0642d1cf3bc08b11f06922e4bb0b3c51a0b00d4330b120fc83839183473b7e106266e0e1ff82b70315e61cfc4cdaaf078e274649610022dec0dc9dd962ab1dbaa3422d5a384e967f5d2b6346634971eef2fa311ed425f0af44f8c459f2642098a09eefa92ee869d07112e94b8a8831776dcebcf22cbdd321b83e50c49e1614b9d3311133380626d4ebc5616f0412ec819030422c39bc44f4dd8afdf532959c4d591789efa237ae42de10b7919bca40b93d0b53900fd3deec2ad42223fcd5cbe4c1be625fb7a2084668354e353be815c1dfcbbabe679856fedb3109861479ae4aadf51925165923279c2b790547d348f5b8f1ad6cbd8721a354aa814f1604e5768e86fa8bf21533e0e83e37f12b9453602aaa8f5ef3044900a4e16247be10bfb3273857fadeebf254c08a05011dbbe4cbe0f940c602eeda6be882754b20b07df795f373d99c1452a59ef81039acf1a9d929a8ffdb6f59a20bdb034046d4b32293a4b1075b2ca112d1d764f00dab2eef4ce35883bed35f6119391dc8716a3e538ed890965e3d15cc27ff163b7820f753c36f184079db177bab2bfa9e52e37999048bb6099ae0725c2e0a10dbed7390c7d778668aa528e5ab23780dca1c1c39c3fc1ddd4360eccfa372f1da92ca67eb3c188eb7787da00b0b7c019015116eeaf943a1f10b04b8d0c18c5d9e8c44154e6a3be11e4880369478549f04d628a8bde7c63d7335fdbf91ea2cddb7e5c8e2ec09080e25b5e4cba8d788bce92681cc97f1a24710e0be23c874957ac8cde060d81f33c8b608c8c3ee8c8b729a16d5865046ff9350d610b06e9ebf8040799f8273e863abbbcf46b218e558669f9b347914f89b170d2974937f5d098621b06b9054332fc29617e7d794cf0529f7c9e8dce89948dd84eb5dd96f3fe34b2722dece5ae8c306363c6e06b75203b3649b806e4a5586807842c0f52bfb14049f6231f1f93b971eb6c1a87a627622e4d9b033c57a1bb6b9315544628a4b3d383894b23f95dd2bfb6ad100ecd22dd3b3f0c568aefdf704e6353120efd08d7c66867c76ff6f0dc40533523164a899e5fc2ba3baf7ebd6aa144529f7384396365c606c85ad64d918f2dd71e25f5801c7eb1e28d98afeb1b691ae82b295a03b0cf2b0b2bf27c5a6cb45ae2c24330fb71e60e5efec8ca6978fce076ca844de2e025edb9a5a666fa2a1c010a0f2f9485602f9c19ad05718e4949234a2da9026486898098bb217e055c5a1b6775efff8d3913f800e7ed6f5e36153d8bf29f687a6218468c6b37570838c57049355549347b18746a5c9ba31c0bf88160338442207ce4cae622d8638bd16d3152383ac03889cb5dbb0ddd2a07a6f43fd254a300e8c3c18aa20fcb382fb72714c09cef03994ae0ec434228c002ce53ddf80b565b30fe3f3d86dfa01a3ae5f521f1c2384d223a8bf05696c653c05e2cfc62131f5453ca24bf582157fb4a509dae706cb84f74989e8562a41c4d23050cdfcbc36573fa1c87cb1c73cdc30f73fec37eece10f9f4fd12fa3de9840230884c93bfcce8282c469ceb12741942f97b627a5d476256d9d01591727f8ac92932a6736c1d21d87ca5bb7474681d4e0dde945303d571774bb14e5c8cd69c61d25becf4f282a82f1e5941753aac32e1e82ea4239a68dde00a7592693d5140de930f27469b406dbad9cbf96b1100d6033b595e2362e64e78819d9e70a38e50f4f3d0dacf30b3347c0a39f9c94039ebd567023854daf5c7667d35469a3aaa08ecf8011ef409f8d2193d3a451a35343c7d92cab21da528c2734ee128c6d0ddfe9a137fd905f47251e0ee1b73285e5507bfe82ebb5449f9b3b526453464544e3f165c9def72bfbc1517de99ac0e51a1c35e2ed092f9f45d33a2af75ffa3a238549a7bf9095dc76047c07eeef7cb863bc53b4c41fb11ba974d17614fe4dca90592739cffe0c2d9369d4f1b050b00a6a2dc7a4668ccd9fe38838b08a9d92771e1fbcf69101b04997b79b33ffa9dca3071bbe8cd23e03b0ea32973be0b094266de65b5debd93cc1a99c0ba4dee46dfa45c8592d7d2d96316a076ed20ad8a0f4c125abb8acbc635767e0f4386855c204d6a1546c50d7427ee17f2bdad1b881c8303964e18456b3bc193f6afc22f73be5613ee969f21a44e957b7bcfd8e1a41fdd52cd966265d9e308598e0118aabb797e63b66c2990933dd40f6862d487d75bf2cdb5a7ec5e8827753a9803b861d53de233cf20c1e12c372097307b681aef4e64d88571bed09991a580a9ab006b254604c09cdd1c2a07b0d4e4a46dcce750341824c0c29882bdad01366cb9389bdddfe370c76a3f21ed2eba9a0645b4ff0beed1b5f2e4cd9a50f680ead3d5e8ffde7cc30f27c05229d29eb3966d287ab8bfc0019519d961eb26cde40680617e8fdca57b47402efaf4aadd0e087fc48231cf907418fe7ce33e45d1ef4426624d786f4401c7e4b377d13710ad2e210eb656ce1c58d16164558e1f1ab408544ac9c06fdbc8dfc31f992b408d615192513032f55622f1fc67e568be94abc80a6d04ecfba53289e47a58bad4649ad8a686de5d1129f0db72dac1f4eedb77b457fbfed9835afe8365d6b8372ad54974705f68a7122afcfecf8eacf3c533f55d920fc12b1465b56959bd12ec7cbd5e7f8c5fada28ff8c7f2c8a236ac89381b8442794a9ce5208efe3c810d04f809caa81580b5c8373e45abcd29b0bc0a6dfde5b3a8222dc3cabfb7b5146b746707fb0bcb0529b270c6430871032d51d6fd4c175976073f384d1b5ce6fcb5de435edfad8f0e71d4bde2692bc649bcc058b0206eba06657849fa14dec2f4753c0b8d761a1a9143730bd5ffdc843964fa800ed8cb7b4c834b0ed2092af16ce4b027bf3073ad687d31eec9c1c43896ed7da140ccdd5db1d2f4c4860177f704b2409ed191ac1fb433f9277747cdc63138c0877935ddcbfd4e270f21f8b5d7f8b31bde877eac9c4c51ca11f83cfd5450e8a63c9e370f603180036980d34fc266d926b42500f9f072b8e8ad1c0d75eb8786aac33d8899fedc8b3ec6f71204955eed84344ba839af9ebe41977d20a485d53a838ca601726eac69913c693fd37b4c8d02fbfd4b91744788c22661f5f77681dc0823014ea0d9a54281027483e4d5cafaea01142439862b3f55ed24651bba531411d06cd2249ef3f02cd829b233263d6cf658d4cce6572060249afdb1807f3dd32225a5eb234d08bd9646d8fb2c664ee8c7562545ce5779ec5f572c8eb76c3632ea2c5cbd0daae5c6441cf9434c1b553fc5f80886f150c043eaf685b9f3054cc4579e4a1690f8c3656ed7799ac188bbf8a44d1abe553cb58a1df48f56fd27910471d75f1de711b7e334bba302353cf242904486d304a0f4f781f70eca1ba9042990b4127aa3bb181531dabcaf40740f8b7bd301b66466d2cce18080c0dec2012546a439c2d21c237d5ceb1619fd9c9c0e2209b536305a2aa46a25aec9067e5fe88668d51db01a7dd40c06c6aeb453d2f76d80b5db826fd6a6853c8cf22df5c537801d989f93ef263456ba82929adaf18b495cbd59d31b0250173a9f88c84c1df01bdceba04da77ba26d7d20a0d2421e0406ffa493602f5854ab373981ed4cc76db0cfa5c74ad3b57c25b1f7ec855383ad233e0ece260c5015ac556fe34226e094ca9fdbd612a5e5b5e851381514837f10484371d79b62b924dfe3e5335097ba4ef7bc0a2c4cc48d09b92b7ccdb3402af612dbca52742e54a3733a913d4415c50158b9b6e6c0d187cd9ecc59859b5091993e9b0ef3045b43369b17806a14edafb2d3eb00a74d389bac61226e5c761ae3161998c53aa0e413764c8e30bfaeee085d05144e002e1455aeb524a82b9960cf534893c94eeb91c99345b2829ce13f34480d9b93397d037c6d02a6686e50ac909129b236b03adcd9f58001f928e19b7451616240a2df24bb5fd2f6a31e4e086079e3214d72c1e9a229f8514ec642334db9748c3d5edc8a02d3d66eba62943d0b2cebfb42287d61ca01ebc41059c5d85fb559046acd313f12e584b15a6b42ea8f4723f03767aacc29923422ec4e75c6d67d185b4ee1e2fe29f4c0d94987838369d017f1a5daf3fa7155c37f622da2a469fedbb931204dc1721ad2d22db9502dd736c328014c34b3aa521014548d57659f7eaae5237c49e006c4e5f3b4928f82e03a8ff0bc62977fa23039ab379fcff081dd4a7a5d6c38953e0db81db7d656acd3cdf018779924b727a172e5b95aa2ce611f0e35682a5a4dfc7e32d8eb1f7e8476a66530e71556b416b9a57e8d67fd06e548147b0b1cb34ff4c3b6e29e73d3f06a2b4ca444f1fd6d70249da3f4ba9cb23075678549917b38039fa3eca0f6ae431ef841d1eaf6f1f938751a573f80a8d8464aeba8902d05c5a2b057365524c2147c72ba49276ec36b363559d1a5686ed4fa6c8e5e331b50fad0ec1245a7e9ee6f4636995092aaeee8748b1bae67415d32744cfca1b0dd5cdf2005bdd9d3940aa2a7f2b04baa36eb3f64cdb55f8eb26afc7c12122855d3e470ee638a2fcc214b88383dd489a4f3dc9443ccb28ab33ff8a12e8bf1e33247cc6b775366e5b266ad86ad5d74e47561df3640086fc8b87e9b2b1a0a6b12ab1c4058e5b4b7858064a2f5447d89714c29bbb7cd8d52a2e0bce856685cc0cc41f1a1888bac84d119526a272b3e37038376cc51abd89064346fef101cfffe3d64eed281a5f8f0675d3286f61345c008e92d229175c5ee1d8311175aac385d2b3cffe284eeb5c27472fdcf6f60d6e913bdde7cd60077be623536b3f71bcb2efaf56ab7b21f80ab40c2fc2f9925486de930610ba34b03b7becc6fc82943d14f620ebc2de5790b9ec3d2c8cab41c8c172c419c56daa0b050946837a250ab4a041491ee1e2bfd81ed8fd00244538c386d0eb57f5d57f3db38e6a1c0b88679a20899cc11c115fcfd88d52c7eedc2e8d740a8bc01a78862961f2b95c3dde793b80edc124c00154a5c949e198a793648a9a00a0e2729587816a5bc1ddb0575b928c0f48e06ff484bd338468ea05028cbf88de3739b9ed35eec85c393978a3d73e8e45561546127c07a46196d75a09cc3a0b4b43fe38b4b2419f32a2f38384240b683b05ca6eb753d7a64dc641b29a7249161df0bfc30d53f091f5b69bd353dd2e98b7e791f2af002e48a26ad1c4495e5cc0b67296b95b19f20586c783278e63fe5dc5680f9e1ccc5326526fc7584684fc179e8c0b5545789faf692803c5f39cdd4b6d70413a40b60e30072b170af9cd6b9065a9d89ec0b427a9af15d8360648301f47a10ab3d9179a432473c6a72ae78a14b4c73950f1005c27248764f8bed211f7325d73a5962e4a3a81fec5455e4ca39b1e2b7055d913a7b08cabf59abc962557fdd106093c6f501ea06f84d0e9cf4efb307ecf0eb77011d644d717ac5daa1b0e552c4ac1e7e1603dd07aefc6be5b129be19a2f2a5aad16152b5370b8129b4cbb0be3a0b096cd7f5c7b6ebedb80bce405d4a210f56e06d0a449dac759fcb7215f9ed0f87eb354939cb38c83fec819ee7b689ecd872261ad1e0379bcc55cd85be29e5d91b7b1d454549d5bd19ea1d472886e7370e493510f6487cce88e1317ad217361ffb7e7b69dfb5007c49fa775a33ad1c07591fdc4c6b61d5d0899a89ce27e36e7c1fb4ad4d2ea85e4af688c0f5e44a91d3b746ff2b0adbbeea0a23a83456f07f8e47229f9070829904ea5e5ce36c88f666e117276e43abef912f86458e6f6bc1d6493d40335de13bff5ebe1d76a811ff629cead6d0c3c27d67cd8f40b43cc0c1a5988f30824c9c85c7a6d3f8ff02b7736a4a909497ed1e27dd97fbe0d80a33f88359a657c9e6b0a8d37fcebf979b132b837126096a150a958973cef6c81f437c3cf4053fb316e5e8dee7e4e2e8d30872a2cc0831f833d984ed6965fdfc272b3e484aba17db98f25266da0292a06857713a42908527ee7536c931108a67609dc846961cd50dc07a92cc1c51ba2cb6105aede331ca3946f355d9a26e3c9be5bf405b5afabc0ef5ee161a193a5af25b231aa5e51ab3ed5da33e2b72d108566155e69c3e50176dc418bd40a713306226da79b0885907aa09d93143c35b6ab9950145241fdeb52f96c1365fe23ca3913545755952141e4161fc515a148e83a20765c0a62867847e4d438181031d161d5cd08a8b427eca89c7aaa61dca53d4cccd628f9056fd3e7acbae9127d89fbe7e45f201b7bf10da433cb25891fe5a20f478caeba39697683fd4ef7c7f4c50018c2767c85ace987a77a43f32f72377c551c24b8c61db8f02ba1bc313ed64f402670106384b96e9985e9e35248ee4dcd07f36552bdbf3b68b0794aa25344db498f82331cdd93e2a54aad0aa428bc2d14247920d16704e91d4c6dcc858544d10a8d6c02016e7e92fd99fa2a2019fbbe54f80a0fc56ca59bbe316ba93d5dac1893e82c15da3980e79f905646cdc0089b404061bc40ccdc4a47f1cb228ac5e0092089fd8d806ce3838b79a87cd1d6f6e1e8c248fd10f9bce087805bfe4e5cbfbd47554bf0dc345e54b26adf3c0cbd80fc4a6e8c2eec6f2550f9d39187fa034063737d622bf3d18db288799b9aeca34413d30f7343c07be822d3fdd4072ca7eb18ba2e193440ea575f25cbf1649bf24cc82f4857fac47b726dc2cb8ef4f3353c0b087a73d51d31fc9317c818441723677a97aa4cf105d46de26ae486899f8a386a46c856c3fee2b04bba83e55fb9a7762931c369c5e31320447cfe8441c38cbf6247a52a95a759be2472874619e46075ca70cc385c6e20a6e47ec84fda954567faf903c90c70599b151d3b46d33f60b9a1c2a8ffe13c32e049aa6621e5082e941ab51cea143c2b6947f5eeef6f0e2c2770ca0c32de9678be055b71832d293f5724eaa84cd070771457ad2e906c776b37cbd1665ea529c8108e2b1cc96ad7764e9c3c10603aaab75dbba481fbd46de0d3a928c1f1e5ce6d500c4b9612d178a369b0401d6afce455c5859aa76455d221301f040af625649e09c3a1ce7ac3cc7b89cf9057e5e5f9acb83d4e93761a79dbe2085a98f41e12b5a05892c1137e941332604a6e95d52e4c2d4c8e446527e29bfec45f83f87348228cd59fa61358550e398aba9756aaccbe4e1fd32a91d277274c432b19358225048ebedf48bb55e6a73b580ff2f253ef785c553de894210926c87cce9cb4093dbbc4361b2bd9b9aea5960aa1898d9333afab586f21912d53f01210457cc47824fec7a338e135f30cbdf7b0fb83e3b19fd7a6919d563caf140283fe61ebf9d65f72c32fc7c8526746974729796ceaf943771aa28f3f7f0c8c10de057d84706f4d7e4ab08e84176f10f9149c3b63bec9d1050ed50876135c9aec517a416574fc368102a5cd57af9d21327d702fdb5a40d00172d2cf5ee61d8a256e0e0f9420e6f6350f854f92ea2ff206bdf7f1727f0b14addc79d8cfb855ada3a004b01847725fb991fcf93f50721029292cb84f8988abfbf0390d9826b584a3093467ac94fe349d69355fa2d540dcfc4bfbc1cc463140af90b45af796a575544f060aefe5c9b45585d157b810f52768194b77421be2eb9499c32920db4786d8b281b4b0a533d9e13326672f63e39750ce64061374eb2d50445dc479e9830fb549f3e0285d7f29de2322b7c001a95800cd6f4bd02466570586f06d05f999120710ea2d3eebc500eb6f3c0a7e4897b8197fec652fdb7930054a2d0ba48e44b9688bba9484c6d74f51e7972ec371dc7d6447df432a193b9bfc4819c306280d631f7ef8808b17316a19945d3a2774bad180740364016978cc2f1b2dad0166a32b83484ae99ba6e5f20161171586b3023d3392864fc0a1a9ac23af250adb7a259b5eb0b0d18e117526d015328c7e00005f1eee8717deb428c41b726f6fef99c4deb7606152672f3be88bede250bb24fc7d44af4d42eae14a0ae6c708855a0c65e8ea25bf878caa81524a4988159419dd5f1b1201f13fedf573d82cd18ee6cfe1a103492f28384d0da5de3c02f03f4f1336079f3672b53258adf3b1aa84f903c540b122c1004b0403d707e714526bf9cefa6197d8731d9b1c2acbe5b055647f31590b7091945fbf72bb6c372f1b25c9c90c2d9170257f76f1fbc29c9b138c14f72f927432fea4c19507c0e5526fb6fdc623b966b130b44018fa6b5b132805e90c607ec2de5647404177807e24e6866124f1b2bd74864a97342378d8c36a41dc34b3feff471241a039767221b404168d03d16acb9181c9a6615d9bffaaa54fedc113905cfe0da3ca4aa3f3b9586f6dc0ae6141ba92686444c0b98d06499fb0d22174e40412473d6862123af00361211779465474dea8e70b7b9ce18285a5e23ab58457e7448bbeef3bd32a08be96fc629cc783c3e86f599e68ca82fc04203844391893d77102107c67168a77518a66656d2687be9cf4fc1de7f983c84d3c6d21ab8d8e6a9e19edb144e3b1b099054d2cbb55d483aff0c2dd791510b39bdf46cc56726520032e3a8896e9f81fdecf072678ffaaadedd45a4e087778e42a9637a1a3b2cb767daf6b6990c90f5717c68f4c94cb415b6c14893363219ba3955caf64f86f524186f64990b2e6e279f950af3b96cd68b4ed69c6869badd632b7dc2ac7a5a2d004832bfb6041115ff60548c065e43a703c31f121a08c5583e362e99dcc32d4eed79fbd4b73f62eea0dd3e15cf9c7dbc7d157281d22cc28936f646280838fb9578ddf04caffde8c774036b262958c9039353447ef79552ed9c67bbf719559e4aa9393abf9fb442c538c76e78c12427ff82263de6c7148bf06cb7889a607e157d01442fce260fd5dae0c98002a931cd72eac7d37b864e91b64353555c82123d60f4a21c9735a1dca52df7c2ae2456e0e61d2df8bb966724aced1709127b72ff5aa59fcfdc78afeb00720cc8eb200856e9193680edf67ab2891016e81ff4c51c34552f2b6779c1b72b2d20a2fdeda918b106f64054b197d7178a92c545627fcce120610307ccdd6cd1a9aa4a9009a53b3c2ea57b4fad6e43d48ff73eab11fd7587ec0815c8d42397fc530841f706d5a7c1e9092d7eec03b3fde7d5e8e0f894d37ff4bb834d2bb4dfcc2af72c1f738cf90726084187b14e9a144ebed804d19e58d51331346c8a7be6a0b84fbaa1dc04e96b5e404fd786a454416e4d3bfd3dc2966bdee1250375a3e048e7b1bc514b8346559d250ed4e3cae68b84569cdc11388ee33c3358234b718b85439a5e16bfc46b66220c34b9c78494aea251c1212250a740f49f25fb467aa480a7377b4b368dfb6258ab081216baec9c7afef805df1a2f73f61d15603fb3d373b350c9f5f07a4c2861fd3a78224f7476c69a998535026b1be0bdbee455f3523f6b58c07f552630d288ef58372913f49000bfe3fc996e384232fb85c9d83b2e6a4c699a35316a25ed1986ab3a926845ac0f1ea31dff87c0e9172de86cd99a12054d67cc9ab9b0cf89caae932d7840222a8b2bffd8734832954727242afdee8361886a86e54d968e200f2790e570402242635cf789aa28bc7301a18207e068da45ff6b282502082fd19c413cb224dc5f5fe250149f68538648fd15443a4ec0e6030d87afebaf77b7a2a8e2340bf47eba551d626e6f612e85d15c2b55528b77da89c8cb672c991494c39f1d254d089774dc284da116c1e1541a2ba71b09a174e97594a352ce7e2b48fa399d3eeab065a56930a81d90204c1bca7bbaefd3a899ab1e491a91259fad3c478bdd1c7798360239ff8f8424cf4fd571bd2d588c2823479aa59117464bec212ae90b1a32063314dd7bf9e8902282d13afeaa2baa59ac1c403eb6f1d482c00ac30bee1c5260ef4fd22e7492ca2124eba02e30a24bf297c4c115ee51ec3c63434d0a8c6a9b17e9dcb5e89f392f6c7715556f7038b8469dbff82cf79bb62f09a0777b81b01112815676b601365e4f322ddafd186c50615f17e289ace9cdf24ce7132de8c75fc599dcb39de8eb5f43e0f4ad7e260e95789624be5a2f38422a7a9e1fa8ec16acd5d0326152950ae53627c61807dc06fb319dccd363f008141d04bdd4d062391d891d94d7aeb81c36a52fc984b8dc0e553e40d4c29071de89d7a1ceb1ab56c597f14d0e464f8fa4f48930179c6377d755c3cf6f467e5a9ee25ccf42ce67ea0f81307e6f4844017a1638d8790170df7c33b56b0029117aef0455dc118da6bcd6cb94062ae82ad48b0bc9d94d804f2bc9892bcc38c3ee4c0cbfb9d6af39a0ac9313ca71abe180107f2bac56a26fd5cb3d3c70e887177c89b854f17400617491d402048c21ed56b7fb2ec9b9afcc0872118f5cd23bbd4b82ca87c0ed3614f3e3cf824f15e9e3385bbfafc2dee2ecb60c11353bb6a3b65f17adb617bb1bd0ca764236a51c632b6fb482497064f2f64dd0b5d11940d56f13f4b012fa320b81fff1dea8170c763a7fd38980e28ace1811de578677ab4fde2357bcc3b5d32d352fe277824521782e9af7171b2c1aa5b9a6a06d04c80ef2e93811d28e7f1540a3e21948cb9649788079b2b0190deec8b8860761cbfd852cd5a05c010779ea0f10536b901d0dfe65351530069b8ece48ee3f69ad12c531d856727992b75192b1f019efa328313faed3c4039fdaa94305144a39880b20b058a68ab11c90b25a747801e24a407890455f5c130e32f4e5678b78ddf933a7b0d0f5ed6aeebc7905fa42a0c974f456f75a6759e4347b61af4a37e6e6c655838e13da46db236a6e74e602b28536289d5e6733b4f6f0fb9c0a49275ddee6982fa7a41f08b82670c2f162c43428480deaf6521ee8eac17fd647677ce48334da65d05578f4eb721d9cda594b3077b2b0012feb14212ac59a9eed5b1110a0cc127f5c92814d4055f61122414b8740a56db34670c570bbc2a666ff54aa0e890fe76e42265bf8af8583d1787766db99085a4e29d10d7a256f22d51abe01f951142a02dbf0dd4643b07968a556086595c084cea09f0ec8322bf044c8bb1b71ce7ec772f53f87003a623fc47733f419b8b7117e3fad38f1ff8f5396521809151b733be844dab99be03b09b4b5fe623096aff93933e108be01ecba57603fc06f7efbcecd1ffddde5b69edb503cffdd16a1816ba45b199d4f3c6032b8b771a8761ff22884a022c8b0d69429ecec361a9088576126647cb0c566ec086ffb10b2b813fe2947d0974f250f6f3162c4fe597332f8ae510e0e18e53fa3985015ade14ee261b8eb488a2300d32938d07b35bbcdbefa8302d47b27cb03046a71d0da3ba6058aba7d7699924a5b4c9b6399c0135044c1565250c68b1d867aaf94dd8a33df62370fb011b2d2b4fe44e3eee3def87b8cb04529218007310540c883ca9fd16157d522a2595979be003102351f1d29ffdd077437ee61fa543a29d29a6944ac133fd903acc1e8ce48a3136985c57f7513d16dfb046db0ee2652afd8c30370828c7aa540b8501e200b343637d8ed3c805f3578dab980e35ae8f82238938717dace1cedd5a6225affbe8d74819d219fe5338c22e4d2262126b35254b0085a5d8c5dc2119605474a6ae2c2d523e0c22176afa1fd014893cb93a5f6ec55af986140a943d340f9e12dddb24b9077f400b96ec1d787e554706984f28f1e3dfbd52659d325a9c8c3043fc0869efed8a638caebea32fae4341b11ef3fba1164564054fd81c485547e695d331b3456c7a6b4f1979a3d3c4fdd306a99f6ed65fed78f126fe3bd428552d6a14408aa0048faf01d352c222c5baa0397da3423157cf6b0500c8f4109a72358c6042f4afc30d02443c4ac8418a941e9a4ea8ed4449d813f86dcab0f829ed71cfe0c5a1093150e9344fd82ced4fcd48aa3e37a0da88140e5351da474221cf4ebf384f776f63c8f6c10f4a4becc24752a6a594773371a5be3040eba430326e9e90a9c1457dead86e2e215f077d05cbb9e5cf65066358c3e1fba6a1693f3e2b6062f220ee23cb5847aedb1461c2cc608f89de0c236bffb92cb29794474f5547bfbd7317f29d9f77749a80fa3e1f11fbdd60ffd8d3c4610c319910e5a5b48f9ecf8c194dce619083f90ddb226c28ad8803cae3cca99caeb1258ac6f98399a6033b3256d04c9bf858e19c853e8334955eae0734844f54009cc618a91e92f0fa1bd00b1af266525af5f60d866d4b680d9543e039c529725f0b37e68fb79440b9086b6f15ae1959286c26292fdebad6a5dcbcf28e5d3114ceb45aa9aa83457889837453b481d5c1b8400751ea57ffecb75a511ba0414230b46e160678a1d816270e11451989c009e301ab65edffc27fa60d2cd981496a766d435666b5e62ed2d3cf4a25b0f9bbedc5a4f72ae359ff944309e2135c14daa376f9725d18242b98274ab0c1918a581182675c0e1fb47a7581a0d43fdcee5b0c31c1161d0204cb9c17223cb4ac6b9cc8c51ff73f39d20f289c25a1792f6d75e238b27240d82888d18fbe3fa85582aa359965eb57f012bbf6be6125ab1aeecd96886dd6c8277d6d1bba4c69ca36639c01cd9a928acd0c49e54dbf606b605462a5493bdc75e1915ef9c70fe300d5bd7fa190088ed181dfdef019d53bf05c0c4f051b04a685f59616ea59cfa9ff07a740b536c41f427a831f3447b49366acc39c7e45d55d79e65d386fd0da6a0e07a2bbf6a3a85a72dd7355aab6b5e1dbd652aa77966b6ded3b09bc0f183c0eec6672a9055b69370c6c94b30466270457712bf2b003d5fd145126035d0e67844d5ae682a056a6abc19548f7d62875d340263f2aa821153fdd73c23267da2dec4255613478126a2156c1e005419323944ff3013d6cbf3f6f1fb0bfa99e5978aba56e7d9fbfabd12072a827c188c98d722655818cd0a66712517738aec7469ca02f28a855ae4c4d6a30b7053ac12eff04eee82774d614c2470d3d515647e7096fba1ccea62289e0adec6275de5ff13e57fed9232c21cbc9bdc1951136a8d41711b39d48c275a597ca7475ba4f88e4bc84854afada921a34859a06689f4b30202e3a2b53f6d756b30769733a3fddf13d7c5fcc2ec2568556f304f8480bd759667d7f321062451eab31b7d1604f7b1378435204ad769927d52ecaa76193f7663a86d96f6a5b05715b239aa3181b652e6f2a7091959c2620d940553350c85a93781705f991e15de93d7ae636784aea33615547953574ad71b87c4d2a111ba17470f18dd1f36d213fad8bb8cc7dba660f5af9fb5343f25e9a0b32eaf5d1c0cb804c8c08687eb47d545f1f52a8cf8642bc971ab4e0770e4487428a75044430029f471e63db3b9bc7853747a49f45dad4cd61b6bb9bf764031279f6dbba0728f63b8e71d04d834a859fda16d67c69f31a0b14d4b6b5afd745acaef753385865e19963397d0aa0765ce94fe219757bf8594bd1e88e26031e82edd9f565f3c3278d3601edc6fed0863a75fadbf59d61616e5ff242273232adb33cc2d6931e9294000ff52561f8e7236dacdc2219c75a77078b31f034d16a3bc61e1d2a7b813b905af37d872a4617e0fc00bcf5c3dd688b02ebb0ed5cefeb64e4b446a1c1990ade8929b14dd5102656027ff8e092858582208fd0166006a7a8104dd17c81a402bd40dcc52ae1b127dbad44765fc738a910a33344b4ff65648f7e405cbf7b377b7736326988d9675db9a52281e95a5156e170a1dab2584c5a7137deb287dbffd8a4701d8fad901edbee16cc58f2f162fcaef30c743796434bb8d34a10dc4e490a84066c87413b698f09e0f807b22a78d64d8e78acf6a85c8daf74691d4e0852b1fa50c25cc117a4883e053fa6ec8ea05e662ddf3b74b9f65b733cd35bc0a37bc207e1ae687a8e329176fd0d16a571634e54daabf9927818e7b9f098477ce5501343e71735cc6af6f0d2f2403d5f587703d736c57863b28b5452a373961bfce73befc7d875619c26f3badf4bb28cd1714a98d90a7cf4baf847254152d5179f22343cf326ed0db64a9e1131e66633ea9012cafcde13942b3660baf9d724a6830773500ddcf8c73251bb2f1ed29554c887e2fc09c4dd9f6ea6e4d3733184e20b026170511a652dc41b98d146d97ff326ea9b50b926633cc802eaeacc26d9eb953efe15b12b8b9febb1d7474e18ea95582e9bf4fb434295c5dbaacaf64bb7281d28637bdb1502933a5c82bd8919e459d64b34f45431b8022c8a1c99ce25532cb5badf6c2f7596e8dd66c2418e854213e06f83d8d98d768521fde16f0bfca4c2ca3a74b48333b8bd7e761dcc7479400a617f548a4e6391e43fc5d6fbcb6fab6bcb7a2a5f46ab054b142d9373b2b299cc35d1114cee1bc876d5c72ab0f84767662a7d74ee6cfe1d52ca6073ba045488540ad0d29d8377525a033dec9789d89d8359f6cfc1404119138bf805e2e25c4a94b1bcf054fbab01ff0d649f903c405d8311b8907d1cae736b6131c269c0ad6d31b6234c10041584458a62fa8a33fa523b93f278b8d697401da3a41b2c79d8b771c9df27a25e5a60710528934c2b2b58dc42392c67ff33d8cfe24fc049b669392a8c69f9dc2b824afdbfb14ec9417ec5f6b98e6e5984c4699102e88ef0dc53136071eb19bc80e52ce0017eed58436b11f8533924a931949d244713cf6a8f354486d4636bcfd73b5c47458603ceaa70e45a49ec653712cded721f343fa32259d04d76cf5159e2970ffa4e7e78a054b26c8fbfc8179afa45aca1d1b6d0395bf821b5d60e60266491a9bdb5d44b74c6e236f4b6610efa8c13f4a6869d65f71ea23d277f04766062f4642c4d3681de936acda345da14a2b4a2e33545d66648491c8679e2e59c57b183bff81a9f3fa08bb876230b3fc612a96b54ca6542f5af3c1a6584979f571f8694367d77e5f7bd841785f4b483ecb3b6700139dcdde162776eb618ece2d7fdef7e0fff8fea57af3940395bc2d57854440734074ba95f9a79419e46b971f109cc1b7e8be2a6452d1a50bc7acc797536d261a6b93a71592ca4c15df69928b2c05048bfe1d2d97749c0e4eb19d04506a75fc88593389281054c41b9aba1e6d7cd839241b9a0a206c60c5823c062457d1f6207dab3c8561f4a72e040a777e03ce51aefc73de4ccae31879b52a9f732cba161712643752fd9de1ef816d020da843df80da68599fef790feac4794d047043e54174bd9d974650a63428edba389f27a19542795288a87a547df8529e7005eb1e566fce04c3de9e229d31a148252b3d00f4344f76749b1e9e6bc8cf11037d6daf18381190f6d695c147e09033fbfb9e37b840e21bf4eb260db79f9dbdf5f5a4aa6fb584786b17904d10bdd53cc96c0aa6fa14250136e5e6a7589e2cc4734f6ecc402ecc2aaa7fbe2c0f7765bc114a1e47dcc04c229f95d9437179ce724a68174fafadc4db8c6474f8c3af800e2c41aea06e503614e3e9015a2ff7f0b17cb3bb2a6e50e3a77f1620f505af9bb27f1387e4948ccec4c972cb0d3dedf2d24ecc973b039ec41724e5e5961227caccb5cc2f3dd911044a9950c1027f57297a61ccf731c13d71bcfcbcaf6b733aa64682e16774d3043712847b1feb1702818a034bcc64ad6628ab9d87d77e72bb92ee9f867e81632218330c0aeb1bf54a1797f5cb07e2a2143907a545951bc6f4f508e87d6e7ca301734e183dc67d0b7dce14285b527692903ac522d4090f5115432a8dac96a4233ea7b6e42d170bf8519e8850a7800170f1f55a71b5fb631da524a7b6fa104ada3c26fb8f3738cccf7876505b638473a232497608599b307143d5fe9eb0a92d529d5a51340ea9a4dc28111e4f2908806abbcf86cbaaf6b8cebc693c702f2512347ac89f0dcd928c60d6a6f5137c979c68142370848f2f17994ec6de3151bbafc5402c6d74bfa6068c9048f4f5288076058c5cfcaeb6cd5e0d332dd8e760a3949cd709c86a319403be24efe12655d198aa3387c18dea94e8fead06698926ae61d89d484acd0409a4a9b4323c1cff820d9a9558b9062dec02327e93d55d3c2fccf03738bb05eaf2ddaf8bcbcb90ed3aa8ee593a9aa288f87b0e3962ad23d32c9d56d02f9e201982d02e16772650c9c76192355e64833652f16c16aad940b66e9ab321b660d73ea48425566ba4e80a3d4c6c0dbcf0f4b29ddf7ba24b3b764f2c45160f2a3ca0933409bfd3fcc02a7d93854ae0c6bcf8b0cda2fcd20f63c4289a16332fbe8df381e26925529e4d60785bd2e82cf210b9a1448a927ccca45b9c7bf3319a0491cb4d26320a6e794f644f301c909de1c27cbdc9d5c76b106583c76414fdc86e3c10bb1b5e5cd9a6311a1331637c625080cba423cc1f39480a03a9077b21d4dd9830c09dc62fe7fa55963575795b1a4787e7d8bf0895e4648562655771fd54ed91b0802a532580967a8883e42db1c2d1fadad874cd96e28a8b6ce33ccdc33d6eafc88c68c9d3d2cb2f6dbd1f10710f1a7d26c0017169a0fa58ac27de570acd926ef97d44561c9eaee8dfba87b2b0159f477a260dc03a0007e8a07b91fd8bb8b08bb65cb60bfb3afc28bca0439a02e5105eaf6b07dccc5c7aaff67e0a7fdeab960fd2d70d8a5c50c59dbe6ff5cf0e46653dac6e8c82191ce2a1905f45284d08194e4265e689970ec978d15ba133700269684c518ac3e3b0454a6d18a32d05488fd2516b61e165b11bc4362b63b722e3dc1c21061e84e71d17a78d6d2262c1619ea7f5f9069a46d4cea70121b47b8988d6ba05a9b2db599c1bd5c7318ebfbd3f311d10b60ea16652d967093bc02856324771a347d6643fc127dd56295d5ad6fedd4e47acf8f5d75e03bdea0f1c44aaccdacd609d79a761d327a95fdd0184fdcf469f53023621d4f77b5627ee1c732ac0054a62b8dea27cfb4c7f09859e379f41eb7eec83d1430f8aa172c15e5c62adfe914863d2c6ff998d60b920a9e62ab939492f9800d3103c5fc8cd5835957e7c7a40a4f74968633f595157ba8182220c9ac4ebdd3d32611ae48c3b9b16e50aab9e459f5b894e103caa350a84033b9d3b50f1fe921c7dfeaf37426a98a5608e5bf8b552d55e7c0dc61a09a9e2c646fb6cbb2981913ca6ea02173ad8c346f0bfd213b61829e406550f5bc2747ab49aad1d9671f69c85f427cc1893c88bae3e8361ed52df4b7f234027a97984d72dff7f3e7b0fabd52ffbbaa968ac46062a14244d463497f9110baf3d14047eed21229ba60e803ac11063b412c1c58a3573a4a978d3d61c6f0421b784305db4b26d8e956ae91b575847673069cddb8f2c9bcfe45ed4d5846ee9f2ef97f65a1becd11cfdc3b9626a01a4a25fb1d45c598d9632d3ad89e754014340dc4796573e076bde839bd6fc83ca830aaeca968044080d4a89d615d4a4210f66429b1c63030ffe345551ee03bd652268fe67d8a3b2f0d63c06174185f5776b5aac6d68e4fe0fb76ac92ab4b0f4b732301ac74e50268447664b2c37ec0dfc68006b85d268fa8141ea4af3a3246cfda6b5e1c76e8770c52caebc92403e5ac8c1e3987438b697228d14b6712513a674011ecb311ef7d3a3d84231c3a7f3a871f06b21253919a39c152e2ebcd74cc388506340fd0f18c79e9c630829a1119f523bb835cefc485577a040b80e433f587b468c7d169c5a8c9cfed3a301fdb4ec710ae7beaad77614c834adb720a2b914f7a89d957cfa17867b45d95d81622ceafdef6be98291a839814f97289f7967257f080ba07e9d0ee638521bcb00efbe45bf4675aa82eb49d4ff7f9ccb8e18a4bef7c1407005d187bdef0afec69600f8b71c14c39c0517b7ed91079eab1221da4533ce421a04f5c928ea6e57e60b50536227826b31e62f0e06694da954a505abfc369dad687f78b26601eb18d73b06e45ef296ede3b9d89842c787c80c6e2c38f70329eb4e433420805f3ae6221632826fdb9a57ae11c866c71d54f2118da13cd2dbf0159297e7655e5628c2213e71a2e661d4211ad0fba274117e857168c66952397f4ef45c93c5cdad6afa01f72d09c203ddae858ac3a2f2bc59dd205e5de265193490116940173b6f6e109696572dfb6f50bc8e54bfc90da7f1f386e3c6e24c8d1baecbac67a1ee5985f02d595278dc1e70504b77567ac848d6eaef5d5e0876aa1844033c5f717995bdbec3002efdc68ced9cd76d19067b055856ee591075756856b37a934157dc75cb399c6ca2d223ab7d2d9f656a86646b898d9c374d96d65302e84bd75bc69fe1dbdc0f0c8d74855e1c827c0e4c7d1287bd03ad1ec1852c1144cde65e17e5b3b1b87ef93a40f95c4d822080118d9bb87eb451c33fc72ee3d957aa36fe9903fe4537ba56d489105250e2ba1958d943ca6f6c0f21bdda09d6415a71ddc5e698121a220c88af02267e4e432d5bf3cff474f479fcde8ebbb3a7a3228b998160244d8872c7ae4959cbe552912de718b2faa271973e9e8f247c3728174fb5e2b99a1e9022fe254c4490456ea66b44e6afe4b8fb9b9177fd148d5d1fca173a348a2331c1edf79f7d62477f03dbfa678fcb0d9bc6bb58fb10d789c7e49c9e8a46314d8d7d88457aa7f55201592f2dc913551df4f70ad2535d1f5fae646bf5ad5f9a624193bb1d872d912aeab9639e4c1ee15bd3cfeb962e6f98c40fa59d5f5d2cf874e2bb5c57a3ba3e4f9b2938455704276e8a5f4b82b231b375a7b6b9e3e4f4d7b9413624b76074a13e2ab9b10cd882b667ca8abfd64e649c291db63a50bef4af77a8e24f8afb3967370a004247e1b6b4835e120ccc53f2e4da9f419eeefcd29534078f27c2679427eab7b9a55c1a57397e32fd3cc922682043ac9033f89b340851474d76fec2e3262b088363e4f94c75165a33b6c865f81949241c4a9d69fc329f94f37a20d772a70120499dbc1478365582ecc0823e6c8c2e700ee3cf2d8beb6a97479cd8f5b715b45ba8adcafcc3e609f88a8ada46533caa889d988613851cd9f545d07276152e296cbf110b675d524c8c955e9320bfe1c0faa9cde230a54a524063d226a119fa8688ad618a9e529b3f7da24bd0650cd4800aef2634a4cfa5ec8fc3a78e2ab2f3baccd0916a4f014a554673d7ea25b7120d8e9db987f204ec35011203a05e1e67fb3f8e882978bc39bf393440b04ea065fa829bdb4342dd6f3c43ad6162dc88bdeb73b50d907e0069a1cab97f73e1711b16ea977bbee47e692db11a610a95fb3a2ada1a835ed70fa186316d6663c90896d97e76e279a9e33509776fdb31c71d619c90ebb62707a86b5bf846681c03148e7a4b9b1f99a0c1d6b07ea13fb96e677f16b11e1beb4a0da9a6f5dbb0c9dd3314dd4c97e5149a5adde91b5d1313982c84989642a0f75830621b04cbd5185325717626ebfe68b0759152932c4f29b27fcfdb6d78c3161ead3ecb3fd495253817195a554eb3513e88dd637a326b2d73d9dec0fe32b0423c16f4e1c09764db8c998fc7922c6d203f1a53e2574ab0035f04d7eaa5ede93c212738c5dd741dce95c9c14901bfff621ac0e084b1c6be87fe92a5ab6b5f7f254d3c984503f61a022f723ea85eaea229898bd564715c749ba5f73e9492b5b47d49cb02a50b1aaaf532d29f3aed81d9961d6e60e5a105e7a8498260deb7866db62fbb3c6974e34165fb77da20d6479977eda81e38e051d9bec5343d1aefcc9c98b3c6a1f188afe55ef119e27e757471f357ab28138e85d30d88d6af9b85de8108701835ae98f68a9e3fdbdbdb57d48d5697e8a8e59edeae543dbf5a5ca08609407b10a628e71f5f77393b43e97ed4e3cf0eeefcf11d251dbeda2f70a776659efdc844e866970d4ed614a7c4d5bcbfc960eff29086c8cd8c571427ed0ce6157edff5108f0eeeefa2fdce63e191799c4a3382963f0c45d6c1caa6d024c8f2d62e217594fe463101d0da8a4a3f10588e766d2f9555e5c754782d83e679bcb7ee2fea7d7c652ddbcdc47c2f0be2b21dd4d464d0914ebfa23190353c283212b19ec2a01c1ed4d90349b997637c83e23384e40c3fbfc2243b6088289fa1e40c6ba4cad183c6a7924d749e3e83a21d3e04ca976f91e48c5e249d2da866022c2ddec1b13f7b091d87bd7cfc1b2ac0ae0a5bd743a13f30c1ba515251bae6caa04fa1b23b45dae19bee39a89d46f5fb9e2cc0721290fcf998bfed2b0a9e5f737b435add30f07ceed611153e5657e8b0ca98b5a5c2a8d1b2afe9ebdc3e59a7e4b70eb9eb3725b39fb70e5fe2ca9f8770c4c66089d881348e75b29c0458ba25b0bca14653db7ad4f044a9f4366414443df7be2ce4e3cfae9f032443f9dfbed36b8cc254bbda7a35c5388d77ccb60b009164007c28b850ded7e9b4d017533f7a2d8e3b6448072aa42f80bab63c4c079988c64a3637c2fe558e8e3562a7b4d9d6d04365d3b41656cd7203cc034715a585ade37c9f867407fd4fc04a1d15763ad5e06565363ede72a3411f9dbe573e80f8136d576c0321dc43c2314974b9086c24021104ae6c3ec49ddd2c84ed7de835d59138d5048d40e28686651712ddd16bd6c814ff10e6638d1583d3f21f7b05c788242d070502dad26e041121c1bb81da46e2b6e50e6bba1a6519ed5cef43fff3ff08ca71436053c3346054bf2943e3577ee39f5815d3f59e61690e3429cb41034b35dd1053394edbe85f3c8a460a509bf5946b597b74acf7798aa55ca04d903769b4d6905277638ab8ddb5c47ff05d65c8001233fb71c4258eb94164074fe48c487bee947d11cce9f042464d99bcb8f171b4b75f6d4d93d4bd0243acc0ee201f589cfeb0f72446677935bc11424067e81d44c26f3204dd7b37aaff8ad86e975e28924a34bb986c2098d4dda57f2375e8cbb1fc7c496e1c3061ee692a182d3b042d33005170f2eb1f9ce5cc7b89f94c1e7194c0026c51ecec847f57a79a65e19a0acd703a74d629c42af131059968614e6f86af5cb72f8a587aec6d2938284301f6c9b63bb5f403682927575031de59fbb95424340dc9da494d21f59520cdb25793626cbb0e40cebc0a7331d529cf10a3cbad099b147e178b369027e0433ea1d8dadad13d6a932d38b8b849797eb9abaf6598b6a4dbebe1315853d017f6affb64d283574841602a67614f109ad95cc1b191cca4810c67bb521b60f704cc7e3773630b567a81de9d04f26f8b7df11fc7be63a4f73441a39ff7a3051f27dc82b8d8fe1f5152f2c19d42f385f77d123a4be2549b1bfe23c15f6a06168397dfe95da68f089f77f8a482393899c54fee08de52f56c1d62d246b7d518c6bb64206ca834c3929dc74e77318d106f0e473f014f7f7d5836a9cfb05dbc1a72ca6b152382bbfb9680769c69191f9fbaa015a807e3021cc3b8df343ca274aeec8980c5aec2ef3719e49de0b60f97ab087d9e6de28afa43f370d111cde56f7abe83f1a07d8482e5c3a8e231e5c6e40c94687879c9ca809c88c6fb2e75b2ebe1291ae7d363b3bcf9cd79130dabfc28949ca2988a101a9d6dc1546fd3633b41c1b1c5e64a89174602f0a46f3fe74eb5e9b18e02da7582d9415ffb6c7c5dd9be03774b6c6d7093112e955e83db6e9670ecf2ae2c7f8c45033e2db5b81934a2a23351177956eed3c9ff2b779e497a4b64c337b270bce9fb553000dc8254a75fc49092aeadc9019368ba4b5a1ab94a72b728fbd22797f4ba9ed5fcde7afd75f9f1cde6f44b1766b5354fc8247730376f3605a631768f11d177c3fc683dadd66aa639abf15d63194b7b8e52900a734b652388d6f76ca8b9d1bc34fd6e75567b177dde189f70aba1ca2ac19e0b613cab0906346a6ed4be361e62dd8f7e747a08dc48c7d49f167ab4066717ee9431262ffbfeac907c87bc3cb0ca3a1341b1b27f7c5f8bc3ab5d43c26e08cb26ff19f456589e060ab0e2b020405dc96fd6ec749264485119b04f468bce5a05694a90f8e4d77bcf33d59f7df0a6c76551a58d93444fd8efa50023135c3135b55f69c096ea6cd1a4d93229e8c680bf7ec7006f1f51493849ffba5eb7d71904d5bdb793119a51112d86b703ad0271208d486aa59040fcda157521c2799f863532f8da3bb1fbd21e7d07c4f988b934b80ba7b99b3af435ab97ceb9b35f34b1e72c75551db5c98b7de706db53a921ec684d7c8124b764d30311d6bace98136cae26e4ce33808ca20dc2c4821de8c9861fec950e4d07865436af9a69195622a1cc886ef4fd8ea59e4cb5bf37abb90ec185ee57488ca9cc84c8a376c28edd368d285f2914b89c1663ea5d9d99367ccbe1dbfb79171490330e5c693241d03dcfe8b0121c3f9780ea04218b8fb7c310eb5b866d04b359ff04a94914062336980e0047b6f5e53c54adb01916603bcde88573570e5f349b2b263d7e0d8bb06f76926fb8c0e28a258e6bbeb3f0d931b462ba11359f7114594a6018c4f51d7207afc651b34405b7f2302528afa584fbc6c7fba906fa29b85e9a7a18c589ed33fc4597969d3c41280d981df909280e512f25fa94e82adba497c740e451c5f33c7fb25d44f20d5f33019baecfc879fd1c81ba7b00ecb4e54edb80ab176c0e40c0aacbe5c6a87d2520c7c9890053a7a1c26621fb2ba4eff75567f2e2b8bc4cc71370e27be7161c72c4edad6eb00a748f3be061ea86f505b740752adcae1cdb2ed5e01d0901273666d451da1374f232338fcdcf2d173ad1504c3b9ea9433af4d2d9d746d82b7f7d86dd16819a91539a1e58b497219a4f3f8a6eecca653712663343fc3c5e51b47a0174bed8a1eb3f121a2ee749e9409db16e5e7fdc7cd3299dd6bde379824096c0c47e071509f32811fb0a9858f50cf7fe482468d9272959fb4e5144ff9248c2ef6df9c44e606fc2a87003243689f34fa5ce4434bc5e189247c4d33bf1538b4f35d3719614f48bfe93ed5134e5f2a20e53b67347bc00ce877c6f1a7a05e7895572252eef5242b66acd74661e78af98b459c23470e8892e898849bb314424c77ada3659b276164e930fd93bf3f6979017cb8701b357c1ace27da0e583ecfd37c78124f1d8e56f21d759fc1b9765d8ce0905a309d23d89e7ffa823deff516994524cf7ed2475fb53f6b84064c80987e4301e004e3edb8cbff01833ba7b3b04a5de4c029ddcd243604075fa7093801d5ba9342b9829bcd9bc5551f68c631de78a1ff7864e06679d2eda1deb211d549d5751e92a138c98925efbd42b07e92fbb5f5d6d5b9c43db56f779c4ea2f53b2e787475c343ad8c05715319f70d2ebc80732597edcd4b603d2ffbeb4200105d386e3972897ad11bf63d098f7102c00c9d91eee1f1d40105600f38eb2a07e8ebf1b7d2518316c713748397b62261645d7759dd2e4a02b971c53a8183f1cce3ae96dfa333a32b0208593add0ad5285f00a03279cb2484681db5a161be3ebadd2468d7b7220f48240c51798856545f7565fa9db734bf63adeff4e655d3a892d83183a2dbd193c0e1fdc8e4b6cc1aadeff406705e456dcbd6c4664d73ad370498333589cc4c5d11bffde82c07df008c03b178319d8cc2022eff2c0ff09cecd7788138855c084be1dd563ebd5420eb7b57414768503271ed50867ece79e151051890861125de2b7b52d0800aa836770adb7166bd2147b6fa0d4032829da164e8502fb1cb4a3a6493b584c0dbf2dc9369c5d6c20170c7d5fb76899ba0a1015a3477d0ed923dcf58a5a93c76a89b7f17f420e18518484b281ee53a2150f084ae26b6166e247130a6d5161943c2832aebc84459ca50359333e6156f6b5081e2b4c1f2837b6de496dc3584bdf5e589b65336cc205e80cb6f72d418ff4542c7e805d4a2f0f29876e1264a987be9bfcb7982e72de2353cb84e753cc1b74d732311f84cbf330d573b942c8efd31d079724273fcd369733ae709ae2745495ee5b74c261c55a7f9f82b31648ad43f284741134d7e70cd9a49e439eacb4a4441aafd8847fb8a2875682e67059f5582e3f822dfc224a20ed3894446de9ee591edb790f97cc3e3166bacdbb01196a7d3e7e623bc16a68d3f497c56ffe870fe13d1ba9b3c1c58853519f3a3da3ec085b92f1f77947df5f72ec0ab6e7aba011435b08d5ad07115918a0c33e422b0441b9669b05beeade7b53a7f7ee7522dc0b70c534b61daa878ea17472075711912a470574ef7a179f2473622f299d1ea5f00445112e031323980e9ca03819cc9998fbe36325f9013eb17ddcd2ae619754947968a46ea79b53184fcbfd6711540d6e7247e48386cd134544ab672f816ecbadf9ad8cecd8afceabb2c2c21319cd460481eceb709fa33dc98194f2779f040a690714f55e2eba8ff64ebc4f09f9d517b040078df87d6e205de3c0dbafb3d2bb2deedd029cc5c021baeaebecf92d6ddc43a0dd870384a0ef41db54efb07a0225a6774052cdd4bc573e2b6087744260e8c77fde60cc533cdc9c0d57f59308563d54f85ea8dd0d26ec73dc8fbd6f1294b7a2d89b2db04629fb336f9b2556dc0883748c95373730824f8214689ad0a2fd0f523ec3392fbc93143091b161b824c2dee3e64c1c5871a605d3116178f27b7f9f1ea3aa0a16443eccf8b2100b41e590a598459f19e7fec79396c564b5c05b2a351e8daf28a4e21e41d890365a31e9ba8d22f9ab6b335bd7322dd1da70af9723fefb2140fdc38911bcc3fe780af1fd28e3d1efccef93a239675c7ef3bd11adf80d3d7a81d56fd2449fb3c3639da47b7167f176a4662b1d65cbfa40f0446fe750137e37f8e590531fb12e1a0ef442b245284b51ef19276d8482423a3ebdb7255f0541511fb972043439545a747335bf47bf02a2a839878d78e64f14ff41acb4d0ef06e3690e0c8f322bce1fda713f8bb0735d7d1a6c77fbced5e4b1cc237e3a5dc0c2ba9b71c7be488c2b9a372ca53f77fb8c35fa9c40cc55d1d94d963dfc89ddfe66b049d22ca60c3d2d4bfb5116d0125fb7afd15c0cfc2c9dd601db5f4f47ec2e42b59c441f871dcc7eddee8f5a298805a053a27257cbfa67c9c1725f6aaffb116d1a3dcf4fe20827b00db7a9defe989f60b13b15183c0f97ef9d76b1fb5c9dac8ce6eb960c86d9cd884ca971c9eb3b56ecefcf651826d249c247caf195b53d75b84c78e0922325adf3151d94ae91946ad0d67ce31b740d073af08c32c915fadf528300f890a02a141f0ffe324927b5fee42d830c44e98ac61ae8470f518b30e7f94e096477ff9861bb96e4c7b492e14ea9cc901ac7ff218b3ba49323b8c4e1479ee6c4c7c87cb3ad405f6987e1b2d76712956c3a48a3d5c59ad44b4fe2a6a5a453f85f4c1fa71f8d4501da7fe22ceee953f9499441195d73f561ccfdabfe1261e6a25b55ab9903c26b1dc06d86833c13cc9bd782f9a37a8979396c03b3591252ce5cdd602408c29eb0c17e4f45dbb92d7abe8cf349c911f8d92cede61ca5ca2f7c633d3f898fc41967426fff342096f1cc7deb75033eabd3ecebfd1b2069d774aa2d981138ae748de6861462290bd0dc3239b9f08a6a6e72e35b0e4d5ac7f5386d20857b4a5cbd9054df99f6a4da48180c6031b8e4e00a598f8c0c31defc656abe10196b6bdb74a1db1572bfa98c8daa530315fc305767f81c71e8c0e501de72f1bb31ff164b17ea081e0c59a08a4856dff0654dbac1a59305a74f0aaf8f3e8b6435fcc3b0cc06c4237c4faa1acdc6589b880f5ce1faa0167aa277d35712e9f1640ecb9334505d32e1c2afbad63d9d0212f9c82fd55083ac91ba277ce0397a41e9a8beab668398e379dacfb6faf51d9f01205c79a0f8a5dd17d039d148853bcf0fac3d80d6838b87b8654249e19bf624d8a816c0c67da0d7d2ff384888e57b05f175fc2c98a5779a339ed3e79bd0e8ff2a71e88f602fc58888ae31c82b223a1144d3bc97535953433fd57d0b42dabcb5c0156ff0f2e06a986c0c38c21aa0389d9e43b5fd346d76eec9723d56855d47faee185de6b01facddc21e521f67da1d135d16d1a8a7aa4399e9ec0646656b6412b3df5f0788b69e37e4c2b86c12575a417e80e2a1491cc9760982d2d6e4a9f8013f3e443aef335b8be21046e1df3bb9e6512d01c2edc4655c5df310be5623b0e01f5604f9acd33b2d8f194263fcc779e98470d9e6961af9c24aa65112946570c3b17e0b42644de3f46efb6a9eb846c7a80cc84c11e603d274a7e695104b4f315c44a77cdf14c7137a2af9bce30099471427e6ca11dce87c1a209e08690352004085b28ad59c82f68475e8595c4d8592bad7d109fbf72f5342812cf021f07f30d498b21caec0f8d6093d6ebbc7382c4e50e0ffbb9eff795062b21945cb4d00482c10d0405d5fc9b15f65d9d99e02f0bdef8a8f603f067ca7c7d693ed0cabbc2d2bc69eb3e53572c38178a162748ab9013787591e67b8d23a8ac11a26e2bc32c60c1704b0665b0bedf42496c185f26870365d766ec8ab499f86a6c337b8bc675023cd9075b717226a2d077a2605a9962c608b339e09a9f8ba9263de67381aa763daf0cd78a874e1ef748ca1663b6b141fa5ccc5041a5dc59f9fbcddf7aeb1f5d2bc553d7f5ad0a536de5baeabc41c0d4d194a0866bf1822b38cc726606e997cf5c199bdf1e5a2a80155115c4dca809deeb6c1a1c1f8f2ed93ef48ae78f7bac69b27defaec1711d408cdbf63a87e9cc77f178cf3ae7e18a9c5a601fbbeb3974de0812fac5870d9d4d3d9a5160193adb1be87dde70b5c92face9f84a7e6d690a935141d1c19ac1683c49fcac6c7056f78489d21bc243eb9a0c6f9e29723272a4d37af9c5a6b36bf878fc6ebc5f0657d7cf656c63498ca97ecf5c237e4e5fe4b1759db9fe795836a9a9c0b1a46d170ceace16485562bf6d5d7894085db195f70229a138e2d0af4cf043a003101b35d8e0afeffab37858982f0ecb50c818a925fc9609aa41a0b60ef1686b8ed5ce350d7b47b36612735d86603456d2be9b796f0429dda74791222432ea6cfb3abc0dd11c2bd77d130f4910b491936ee2139ee3fa3b12c6c5edbf208d08cb6ca91b57d04eb45e9e514bd11a27e1bc9ac5c98cbaa6ed885f46bb1c65548ddb2b295cc7bdaeb17e3325c0c44209f010e5b4abf5ff42a578ad85216a40f5057ba87094469fe563b9f3e1458f01094bc96ac908ccd6d9718ec31f604176fa3188018993f8b62aab15bff7e0c3c71ec506433684ffd6bb966d836a3d045391a0ceb13d0750d0f9bfae52877ee534d8e274aa307903a0bbf7bf50d5151a739661d873c848a37d1bde396256196d333cdc63aa9de9a73ca5067febe111b4d4d7783d22d7bff3ef39bb13ea3fb05b6fd6201311137d131cafa2bcd3473f1be6599e8fe65421937734510fa83d23921c92b4519267138b5dd0155bc048ee76d89bf1ddcf5262ee396745812d5a9b4333d288c17bc2137ec2fc2f524acfab455205a95d38dbe3f1dcb4e675052330676f025e20d74bb7d35ec3465dcd5c7cf620e4f952b8df6f052f37ec5f0ce2c8e65c93218b9c193c3a06cdb304119c20ed82c2e4558b100e7d92fda9be162962ae7ade119902605ccd16e0d9a498498c1684551e878a1322e01e0a0e8bb20398fb0064f138e75905a3fcb95d19f6960783d2037008f719ca11290762b1292a328f71ec6a3a7201fb8b8ef8b983c47c578f595f503c60137e07681a5dd73c07df6915d36dd87d4ce1d1807fe6c748cb11c4777829a2b7a760a1a2db7c0df28ed7723891c061698ae17fda67c50e469fa0a3b7cbb6b78a89c16217743865630a241036141c94277841052359d42e0e38e09ce0cd0446a55ff74bb9dbbe00d01259d7b3a50f512d1ac2d94454dc82354418441647464631c85f5ca77fe9d8ce8f0455e675e643e22410f4af248ebb6bbc81336a5639dac672aab3a43225c8e499d98d74bf8ddc4679fa21ba10d5ac483047f9e507295858a15456422d7d32ff3040d5038d30d53752f69ffef3f4cf1dfba528d10d65fbdfe3209401d3ec6d35e8902495adf7d3888986bacd4ffb6782d420429a7b6baa59b3ed343038411a6f08d5199b1af87b9fb10956765e4f54bab1413d29a5a03e9e605f625c1193226feeb6ca84caaeafa5f28a5ba777c895e89e767dbe5cdaae48320e38f6d2adce664d78a68f8eb0d503888a2a81b92ece4c1fb8c832771e4ee5479c715581ebdc8aaa26aecc2aaaa6e84b62f6f3b73e31848590eebdc5d8f71b423549e76c3f2b488bd85e77dbe4e8eedd5f068c8643454e47bf1d028e2ff5ff15567c46ac53c051ac7575da7012254fe78e03e77944b22888b9c86e597ba4b382a937b12dc011d3ca3a48fa27de063ed5f309e05f4767b12bf37baf61a307fa04d28847e93f146914cc7c10bd246aa535ed52e53e2f7ef84badc095ac52c4962bae72adfea61d4e9f7acc71eb7637a2e6ebec81b9170ed5030bb276753a8547ea3dad251c1970acd731de74c1ce0352af0d1f7de392698d6db40f694d27ea44ea5d11315763baeb8d0cafbf2ec8cc5c28a5fd8f43101b665d584aa474f0f8c5c1a0c6ce1a8f2bc247f0fade5b1d0a41616e203a1f21ee4fb2bfdc588283ae2f662823c01b137219a6454b3b96016b214af7dfb0908708e77da229f1dc4dbe2d984a6db7ca4aaf930a44435fefd661066673e9af56583c8521e62c4eedc75fbe645383dcd3d4368cd16cb689c4e88c475e771b4c6ab0058dbee5f1967b401a002ff5ef84060a638384a9bcdf9c731409439548b3cf6574b75e32964edb041f27541383b60973aa2bfb1be687799080f2cb8c1577d782c1f994263957626ccdc67b14af4209225edb2bf9d626d45cf17bb5067a7f4aae77d94b96ec76c4725bdccb80081bfa1aa27f6470d51f08092a7c5c29651cffd6260d5ba34f46f47d45e172ef38cd308abd78bfe96474804ea6d0e1dab57deb82e6232d571b177b3bd8ade4be84c67f8c26538674086b1315a7b83741b355cd90b49c7e5c3ee485cf6cdb0cfe2c4255ef671bff64ccbe97ecb3ff9b8fdd82fe741c2bff35a381ad8dcb02ecfdc2678e7f4c3952ca8ef5d29d332e65ee516a6dfdff21d469f150ed09734652386d18b733d62a5fe8dba2069d49f343fe27529623c4f3a739c034496d1c47e2d3e5c6dadf105cc7c1fda8e13c1fc4d1b8b96fa11f2ef13e15a23cc222b5389b9ef2550c7d7b9716229cb9b27d7b526a47868109d0e1e72667f83b959bcd4354c791c99c688708a03de5bfd6d55defc904307bb54357c79a76babf0adddb3f2303342ed405e3a1aa61dfd5166ae94a0764e9fe5c7dd67798ad86e70167128e54021f9c649bda0bcbd5901b9b55b45a1a822773c734e7c7646b36aea816de2a83f0abbd555a2358e4a9a44d98b64937072903c819e6f2009e427ec1dd3617ca828a9c232f024a23cd5aa5dc562244a3029182caaeb633fa828b5eefb1d7e1154cc9496cd40dbd27a8b1988031696a81d24ddfc2d3532eee17a80fe8ad004d3f14647960118135421589970bd321b3eeaa005e1eb413ac13ce32c0d0f3a18240bd1d4b5563f4bc9536659c01408ca5a95ff3a6f16153fc684f715aa678b63b0a2c79920b70b19c6fb9b8aed2f3aaf0033daf69806141fe1bd86e3b0d0fb3f7de286b9248770d3318a2dae125d84d6bd0e55cd6b31b9e293da816ab8faf02a58bcb2e2634b7d65d7cc2a4050a3155b5f854dc8652dc5cb3ad7d394324a6c11fe550c14df1e2e108b78872a0bc3cc4c75795df81c01d6738520639084465526f2711ae7159161f0b7af1877351d319a4017f02200e5d8c0e51cbf47c934cfc03ac23b5b346a825f0b0c0442a9b09973e59fe00a846d17c0c17de07a5c57a76436a7d2b83d9d1843ecae3f1da71767f0d016faf11479a4c29288a19c799d0481c608135f1e3c7df267d5ba01b77912de9cf89f6a410e9187ff28ce7f072122992c82f9c4675d47a4b0b2e89ba1cb3b44e009bed044812fb68789d3e8f63c686affdb7be03d52409e0a26d318eaa8b2110c60f4926dab3d2bf46b34331b16b50cc4240e472000f213417c932c865368665db40bb2612cf533ed3ef835aac3211e56ae06b8ae5cb7258ee5bc92179f753f3afacc4dd341c9833099fab0800fc32ac047f39eb656e17ea6c1c3f794b17020192faa74dbf1ef23630be72b369d37fbb20985ef328defd593fd485371ef66cf2e15b019341e91db7e93e1f10fe6206f43448509b948e260b15b2798ac7acecb1212443521596f89d1f11402c7591e6c4aaa2034771ef062838601f49e9c77fd1671d50b090c55b33aa3c0ea247a9d3d75e3c70b3c54a5d0cb1cd543b452a501b65448c507d9ba067e1cab43639905e114450def3fe3eeaf2ad31ef912d8f7a24b982bfe97c3d91d32e942287c1331fc94a63e309b7fed4a46feecb128fa3d47eb10fce2d459cdb5ca34e10fa41c906ad9038863fe541d45116f5c19482f3612eec70e1bdc489f1859598ebc42db40a53a86f5326de13ec0d1b9867ab072fdedfa84e6af21406b8c4e8683660f53c1d58e8bed5c88b1dd3e1923048207bb988e8870d17724785788c302f9c9c5269c21841d5d1a19fb3fe910eb28938bfa7729855f32af326e26b1ee76a0b229e8b7e38b3bd532d04d5dc6e862c1f04a726e84d8b746f27e3f5d184e736fd682fcf68ece7cb2b14b643b5bb8fec19eaed240acdfcd39afd0e2021311bc11031220b3b24c383e475bf8ff6360a5271db4244343cf9f4bc138f3404671b5a7ed61403b8bc33c895d3db6608e50bab63cec521a6594d38c9f4f2fc74df08315e99b802947e9ca1c79ee904f23f5af7f1ad209e1cf4b0f09e2ae228c566ff8cebb26af8568ee03baf83d2c99dad73991d54f1688ebd53382c21a6b90d672fc49aa76009e0d3c7f918d8f66092e1440a307aec2958a3183b1140e28f655ea3366600c6b6fb2aad092dacc084ff6743d7b730fd0e194995f4e6bb35615898d0774046539a60a966733a466e24b4430988558658750c9c075c736018b17b21127362f7df1c7465a2eae529b634137974ac85d3b565cf18953e328b274488451895d6e78164b356a8b8f65f7372a8cca5eef5e483e6e4f898b242ec0b8d9380dfa9e7d0033edfcbed8f2efc5c05024f8c19bcc2f3244f17f623135119660f8e7e6e56afa0e08df879ff3ff9a717c36145b9fa861cf0f995337b169ccf2ff1c138530c2e4a80f46c53b9314ececdc6200a31eea2d7421f53ec73afa27954fe04647674eda650878357ca13b55534b7f44fb3e510ed8d0231f0dc1eaa347bbaf25273a24a45d9ae09df2b692565618762d145667a86759dc275f2fce020e2b26c9162be144c4c02b74cc8b3c37b8442f3c5996b37d1a501e1fe890e5485870e8a321224746ed73a264650f8706926d5ef42ce473fa38b45c8ad82f0a9609299afc1c8491015c8480b9fff8174781c22c80055098358e662dd3cd1c075d677ca6101fe652ee7056e1e49a8b27f127ed791c7a2e38ba76225f21b2894b3eb16ef0c9b0dcab18342eaa1cbf5b6922e5e62d158285c292cc35e1633f28ea662848e16daab60d760b3884072b7732978153bff601085e3d36aeb97b38a5e0350a7fc7b540d5a094c240bf6289b10acd43f56baeceb33e7c17cb52b6f01ab4b8fcd66f1d415b6377a2ff84980c644288a86a0f21841a41512fb12c1dcbb972203220b2ca0b260f2a46ee433939f3deb6ff311bf52df85c2d8bc6d08136f79440f1d7bd6d59b5a546f5a05ba95a8c58649fbd14b74c95fac81052f69c38dc47a1e355510f29e0d404995860c77ad7079e943c50f32126834d333c50fd09c3daaf07f8a3bb0d7a506cf236a2814783137d4875a591a9cb703852233667f10b79d3a2a5275b3486c069a7521cacccf8be1c112b2c58e5ef752e993073186e71d96b00b02c70d8b2ca78aa1d15d6d8cd888308f8f12961c0195a4f5fabe7241c9a791e9d3f1e42430b530bbbdc99c8676146a9530a6c21d33ff47234e671ce4ed4d17de2125b0f35909c3863560eb9f787da762c28d022c0a2bc051241efe35b1b0ecd309e3a39a8810f64c1d75c176a43e75a6c8218567e0037dfdc399e49dc742099d4913c074e32fa04f2a3fa98b8cf6c78e24d1cb760e8cd5270148c863c623de96fdb6f203374cb8f8bcd06bd99c8b81cf7bdf305017d279f161cfbb0bfd8f4d0b487c9a387e764dd2da420063476a84d8fc716d8b0d930a9a0a5387d87c7c00910b43924bbc8a1107cf59e6eed00c0e248232b746f1926fb1442eb01615e080338736478803c06b0c2e604d6e59191747be0b5b2dbd86c7a2c63b948e9ebe0d1c4daf4a29a74d4cef5df1b4407503578c1c13b043d81b68d46b9fe2ff8d79691353f9e52dae0e004174a4691956ecced5807cf29f21a8dfe45de8a2cfa0b1d76f859fcb31d2ade4b0924dca68128607fd2604c7a1b73381555d982942429f10df6d6ac47bd80b9e5124dc5542f26e05972960064a625ac8c30d31176022548b7ef11fb7b3aa7c230684e59477027785406c80d1d0791a8fa1d64d45fe68daa2c4ced55cd360e46fe4c3b3cef4cf8591a4baf00e4d49d5a0ddde916175664b9068556ff919a8f2e4113200167799b195ed02f7018637a7fefe825dc4ea19d90dc64a9b45a50d33670f66fc4186911638d51acf6cb891e72b85beb6d4b01819f9ac53065718c35c512fa18c3a1d313a6dfc4171e613e0b97ac4eb942828e549e813732ef0bcd6e37c6e18b00085d33b0cc82710b77ae384200e0964ce381dee20aa41be27474295a7e880b9df78c98df1558b33bff2bd2f9e1a92c3c6266a6f142525500f3e28bb76554e2a6c3c779c8f52074a3caa90e569b649bfe67f06ed8ec0fdf40ea6b57cc2daabb9cbb55c631c753248ab2b905344bdd817de14bd2c4bfa396cd13557f3ae7f1c25c5b7a8889d06aba580670835da7d8623dd93daaa198ecc8741b2225b44202fcb407b3fd6ed2c49acc399cba08010f3f1fb5cb3edb7d37a1b9933038308371e830fedd6299a6f8c15923c14975c37316227e700e4caf4f40c551690f08b8e67d0d60d2504a806d4812884b4e48820e159991538ef05655a11c99b4e0e2614c9676d42b167d85181fa6d0b4941dcf9a39a1497412a1810701f3e56448fc9580b6b9294673431d55ca206e1b5e5ddb425729b55c9cbfea15023c2cf79e745265cb8ea0a2b2497c3969c28c410cb5342b44140b9758d4abd3cd9c9b8c968539837612974a3033d0c30e79c2067a50764a9f2072ccd0fe0e6e3f1908a8204ed1948f32d85dfabfe31d44bc392d5d1fee0a4c4d21beaa2ea3648476e6a99a4649eae3170553597b70f7a9fe84370775339f7c7f8e604483c33865f1f4ed05f9f847868750e6038ace7d6240485f4298224056bbd5e2a594a6ae24bf435c95390b1f2c394c6295dddef602cde2782c97a9b81aef8b7a47152d58c9a805e39041e86df08b14cdc98667b3042cf3f2950e2107bd7e6c3b99c5a80e8f456b9681b51f21e6c6fb1927ac214c35b60ccb4aba0e3bc2cae6369800f5deeba4c439443591c6605169dff5bbf811fde79103246a64b51ef34c73d1d634fefdce759b5250c3f97e0bdc6fb01eac102e11e9da020788da841850a1752df1801b1d4e318f5298ae8676c589019ef64679f1d86c449e50b785a897f6d13feb4207b81d103d83c15de3ad22db6843bab3820063b5c9d8cc3357549ccc67882454adc257a4dd9d30ed1e2728f5def9258fcedf7071445c3edb69c677c1cd3b9d987ca8d04e57541224fd68f6a8b665cbbe8ab10bc54225ab29762b048fbf52a556de43bd865af3b30130cd9976b28b3f95c421cdde475770d4fe5866e65a6ed22244e1153735617e35e065fff8ff8a1bd07c30ec103c7a13ecf13c023a3c9a31e11816c236853945a749456bda6f16850a7ca748e0dd53861cf966e08e71b2c314dbf582b55a48db4dfb21c32509c0565b9c87bba1367b40f31f14232204d365be47d083d6f84da00f7ebb270626ea7f489eaa22120becbb1414f880ec4ee2fe26b5f3391b654bfb618159e29c8a11f40e48087ce88b0292246b9fc9fdd27b9595ea6c140abd5c34afe2e0b9f76f40d1992f115df5bbca953e41802776c5f4eee577703b52baf2d90b880d123e10578a25603b9746e0b88295c0961e811a8c68d60cf081dc87f01eb2cc61bd229549813f736cff30cfb90cf076fc3317c901b924f03ed629b47315ba29ddece1fa6abefbfa0308761656085ff891c17343ec57276796e3687a004133e545a088974e63a13ce545720aa881af2454553461f2ef3db749c559ff143f04fe83980dfeef7fe3f81ef24ef7cb47f8a9873c85f751c96e5bf5d219ee422abb270fe93525ee51d6b1ab3b5c516be1edfde427ee4611e420500c6b3430980e81bbda6e7698d8bfd98d3fb3d348b75034185768b3a3fb96eecb48cd55c1fa730f7a99928119353569b90797a53bb09eb19896aa673f73ac27b8ef9ef029c16f94963856d47e3b7cefd0294ba35feba3c8ce6508a7ef51e7f762ccbab27146748356c5225018d70c81a3209b5157129750e3cb8b060cc438312f895a1d46899ba3e09268234e44635ccc873e4d2adff70737b7fa6b56f2164f5ad4254483e32fc670c11e2934fb3b33a761627c01ff39709dc27eaae452dc569b751e06bbcc74213efe326ed79696aa73be1ec807323c968d0c27e166e5b8620b99fed77fd79e02d6534340ea49064e46589dcb1689eacae697ddebad38501656cf90a72c916f5b553d6f72e1095ef9c43a99adce227c254cbb4273c7deb883a8388c114ec6b1e3d6e8c48bf75151302b9bc8e41f6a1eee73eed6d7e51d76dcd7e3fd4a96557f0085bfaca3895e8c4d35e7d5c017691b0b075335763e88adbc47f0764032ac9a2df31570ae09f46e7e845f020704d295c6046bcd31bacb575cc5bd744fd56f43d63b1c69314cedbd1cd8f4ff684f032c09a585a403a53eb0b3ecbc651f8bf16705dc9d1ae3d69d59120f738197ce3c83cb0ca5d55eb53f92bcba7e26a66504e45ba315ba29d5ed68cb95228ab89e3c66d37eb4104a4528a05127ce10d96480250a684db75d30d98683d19e6cee1c36f31a6794bd2242dce1601fb7f17535c724634e26ee02c85cb436026d784dd5089bf1a86042ee6580efcb60059c163730feca1247d283d4fdfb2e0e841257e7645ec6a1f02fb4376798fee0b6b0372f2036175e56fa14c6fbfd0caabceba5ef9ae9a90703afae8f5b40ea033ca4edda0fc08091a89102ad42158b24c05569e9bdbde373837589652b9a88a2b1faf9e666c01ea0da57a9cc43ef3a69c03d47cf1b514a0d099a298737e88260797817c9c889f2f8a853183d6b44b5cf584a252be4a563dee24ada892f15be1fdfe0b623c5c492f75629bd88444631aeaf06524b04cf3845feeb344bd1a3f057e6602020c31b82feb14b04378b1a2e2ff9f71b3905328028372a59578bad7c018f697f1574eae717a0a7d08419c23e30df2262da2e6ff0420c3c5d21e9f238943b8ddb34278905c8e431739d34ec08536bdea4701d0760ed81c482cd2bfb30f3bef03f53aa7d95f6a5516c0493f1a005325c1725eedb531d6341b3fca3e237cbe8f1260c359fb2e87eb43998cd3b1f242df908e33d692c36ecb4ba7f0f7e388453c9c3b359b182d2ab609112e46de3e4442f31ee103a0690a5a286836d1d31a2c871d53f60a4ba95e6aa4a1131f13cd9078e1f25e3f26f7c2833315b1c7007111b3be3cf0d1815249aa4e100bdb7791763691e08688dc61744af6ee1c65b260a2351d0a6fd99871356d92c47b47a9005a00fc1f49a8934fe259c392b92088f1bf07d12d7d14aa889eb76f9fcf34386c903f0141a718c5a949a5c2d316d4948321976373b785dca239b6414d07a5a1894c3d29176eb3ee256cea4ad3182f18185a720916c31a24b885a933d0bb44eaed8667d13cf200892f0131576a84ef15ed61f2f27d244bbc224d1c17db311915f8497e1b53f9d696d3c147fe47a0ba70389e1a4a88b05c27db772b19f75dfc36074658171dd09151c301061eb66d4fa3b6011762a285235d255509ef0236a14b5abeca640e85334a27e37e551a29c8e9c6f4f6643d9dadf85fa10bf6ac4128f5f1ce70d7b1c9658daba9534c013db3648c8507ac4ed8f56512a928686fe3941fe656325859b0bf873e8311a762075030065fa8f7d2b94e93e6492a9ff8842b9e1260c431fd4110fe5517f7ae884cd4386025f539c5d5172ed60acf2751772e0dbba5df42c797d8113cfa1abcebe390074d20528db659e41d4ec9cdb6f2e21ee43fcf1ecedba3fa7173a4fe9cae63db325a26ee1b28c29e6c0057b210d4b464fa529cbcf093de8be15f4851f80d1f31da01578c1217f185a83cc72d158823d1f3cd6f501ccb17127dfc2dab38c0278a5245c432e5f986636d140f938a62e95cc012120784b8b049dd2d01113a82244d15379e27bdebe5aed461897eb3d68a30acd12822ba8fd091b581e56647bd0f2d618d6e55488dc8583f8032c137f5ca0654699f14f481a6cb348877670dcfd354bc1e426b8e287a1c7792d37cab42b298b7767e30a921faab1aa4b993bee0af0e79eebe154d0543ecbf2f02f671f91b04f80c72bab1544a9e26c78b5337d9ee8fcfdf328433a550caaf804945cc37337be22f55cec37c3e3de0c494bf346307f68ea7427ea02a135065283378e57b1703c74e70a649e78c61bb3e8ec4ebd3c383d9508481109db853f919da735df0cd386e0a2e744ce13f2513f0af67921049e9b4bccc911d1b4cb458cf6b0f7eedf67f8985fa981c18c5ced94edef1193f36b7989c6bd58f14a16d2c89b04b121fe67f26e2ff4d5ee6ce102dcf93c72e285c2f4c6b9986208d606e5cb2e3a7ad8c63e6f57b4cf7ec3955006c912d3a67995f4f0830679c3541de83dfaad8e522c72415168a1e1e99c0b62e82c12f9775c7ba81f8f174d17042668b6efc6435510d5045081161462866fd5a96bc0ec923012f9e5fa13e3a52d018ed9ebddd726b611ae46b18c483b74a4734d332f66b570bd5c776b7fa83ee7ee2760e9e7c6daa1458f81a9fe1c19d7ad08a9a030cc47ecb6ca500326e967ca5e768dfa2292d08adafc978560e9f7ee8849acaf734f99fe468f2f3e46b988cdd6d8e92e56230ca196cefd8b898f755ac469927446efccfcb16e70ed81663764723984bbc3b84bf61775a59b787daadcc36d2fe848bb5c62743102a401a2ebea31e78f85732c5f160d309a48c14c627317a90d20459bf49cec2cd1f0185bb6c7ce37ba5a4130d012d97e4aa37340c30c19cd006e102b7931184fdb9e7c04fc9e022d3d3b631c75216f76b46ea54c1ea33b3a4876d3d486017c53432fab3ef7c4c2418df4f8cf93c633d63b2aa2b71c9caf9d641002a3359424167916d04b6b67116fdf0298d5f307e87bf395115a1d9ecf21897ccd53a4dfce7aa4ebfb50a5fa7a21c7f5ede6ba43b02955c164657ff419bd27771fedcce398c2bca8d7757f2053e89236b5e50efc825a64851824ca58b1799f3967e284fe15137be154cdcfc8645ced6bf6299d758e4e1c2a9b1a222c52793b7a17059e2436ac2987506fefacb8c7d418435d1cb7606282d39d118eee189e5534071fff2545a924bf52cdfa0687de12c05cc91b0fd5cd17a46a6a9deb0b8e2b45579231cd199add8c7e795321453cc59bbe78950fbf72a4e8995b76ff8d8e4b21487bbb4877d9e398a1bfddb46c582ccdb9bf7646e182b746b54f56e63042e362afc3360bc6dacd61a9a89cab0c6c1636f9c5fa4e435bf54f1149681f609b18a5e243a5714b825b063702184bce6e752311bf989cefdf12e1afc22e0eee90139321a84b2f712932aeccaaf4010a3ba6871f91bf45a08585723697ab34f832369c17e6d647763311968bf7942b8b5313277a6e77ba49118c458abecfa51db7c30e07c4509e8e7df57a395c20684f2467e5e52a63e565b1cb7adb9cbc82bcb07a625aff128d7f0c072809d0e5bc3b7729d5bab77a98cb75d2d366990b0b5f1d0730a84d97287f7fa4d695b8db187d6edafcf38c7aa0cfd1be8d70245b41d78ab1209ad43ced770838927b2302806083bf71490659a7f3c9112f09f4b4f8bfe7ff0596a31b7ab50dbbbdef79217cebe4dc630172b8d4007f47cf0f74d0354a183bb1325d8be1b6164c3f002dabddc5717a10ef878837d53126cb8283678417c00f17fb0f4f425700bc9981ffd0737c4e162fc0711f36608f53e6e6ea4319a27e59a5aed0100ce5ccfa47bdd471d3cb696fb71c9144eeb0a2ce63517c5671122eaafc4f00802bf2e112147284e2b531e014486d81ff96b21d297edce0c9551cf46c49ae1e813af03559bc39bb60d686c9bb4fa1b91ba23678ca87bf26e3ba7cbf349c0e1d0b438a4731b0275559be164c06f4813967ae29e32e2a72488fdc103fbc04efd82ae96ae27bda45df0c01d47ceda5b45e6dcb7cfd59d277c960df6b769315d7be81121d9a919c89fb367295b43a7b6997a8d24eff28778db8ffc9d102a6586b39c24a07e387908c92b7e639a8b04ad1346f6beb1fc6eaa8124f9e3e3e2ced8c0bcbcf0162512e883aac1e3ae6351db63fbc131dae9333278dbbda866a7338d5fc654d9e839e7df4ee5688a5ab7ed3648f036af7391a31114899f8f379be16e34d8bd8a59e803718cea7ca50e96d657e7a48ed97c044e961d20fd484c2fe4a70f0d62acd255c940f7f110b8edae5e51525ad3448cb4b94bbb7164154bf16364cb38f301418e32835cbaeeadd1bceb6234be150a5d3385b25a21f330a6d1c51c2742623d938a29c0eb328a806472564f109d06ded02a3fe36e7503b3c0750944c33183e21134fd8ca79f9ff0e989a1b230c1348e24c502d35976c006c7b1cb1ddb82ab402c13807798b17f6904365333b55a73d229fa354b87f1b4fb68e2f80cd2aea383a0058c3e4b9806e0b16555f21c836f682015ef0922dcd5bd82f4a0f25bb61dc8c1ae2a6962ce6dd12d7f90958f3e11f248c55f3c09676dc2b6714e5fdb47b110bf9191cbcc7e25b085c799a410eb1c823c5ccf67fad33ee6138472a89fbed524d99ecc8edbba4a59c8ad1c03012def36a8c867574c1e60c8c7903a96ed4e25b1e580d1abdfa72a3b3bf9c43d7f77d9b747f429c96df034b424121af836aaf7c83bb33a5dd18545826148879257bba464f06bed339dec2ee4a295e26ca3f33ef493784f15fc9c59d9e7e68718a56c12c7d3f96901970136a0736cddcf97a2d41c0a99a17dcbe00cd0cb988eb2a890aebcc0e590dbf913cb0f0e5543be168a63335d05a6b47a46ea9cdfa18db206535be113c177e0990250937552ed1ec1ac14ba1aa99c8df727aacd96341e500ca0231a74d0646a66804e8cfda07013ce4f7e1d4324af390160083e16b8da51bf3fdff443527f5180c3cabbfe4f5e13babd39b1cab923d7b6b981826d3d5789ffa9f2ab3049d5c78c80080a1d127d7f25ca11f1c2eaa8e3fe376c286a154c37cf5947330c477bf446255e811297ce507d01bf49c11cafc3ad987e7710344720cd939d37d4d48f7b47087d19e999f3606b260b450b04cc58b383d213204fd1edb7c058b81e416348a034f9342d449ab4d2e6dea888765d9acff86d9fc2d577c69f4b32507a2712145773b6a86c2630a34e7e0bae68cf223db46273554d064d751bc5e4108a1b570fa8b4c695ede0c1ccf80cbbf0362d19410cd0d491bd4d22d0389bab8ae6fb10202db95554cc3e74e1cc4ac70d4d1e6d448dcd24665c2e02318d6b5cb7193c37b29820c122115c4a59f10157be851490866f6ff1cda613a645d11620e5d1bc6252d95ecb84edafd1f169c6490acae7640c571ac346f39ce56a1916b0ba2dff72362b0847f7e98f73860ca27b02453fc17de5f14d3d5b58dfb8f98c90e8d646d31de80ac0c99780b6c8722f9794ae281fbb0020e3ffcea6d8bc56208c654741cd709479a53ea0f6bbad3ce32c29dd390fff6e7b365e8ac8601c9743e47fa4259313f5327ddbdee9624a99f666e1e80f2023ef2ecd3198df9c108f0fc45cbee5e2a945e4c3d703d7f462351c3a1aa50f85a3247ea5c51101a578552937bbbaf610acfd624eabda39081131be0df22e2a747f031443ef7b2d05d260d940c118d8f0591d095163d7c27bc8b38c7961314658045ded29d6de6b0891ecba13b3bc291b321e9711dfa6f1e8f001d9a5b648658dd53d1a319a33f0c46dfd02da6fc2561a284f79444460e61f049c1e9e7d8b7bf898d8439db14c48d8ca916a97c1c8de1a47565130fc5d8bcd1dc0eff5aebbd98ef38566664207ca4e607596ca2a2dc7759bebfc81ed4220d860c087617f35d352c40a5aee0795d99a704ab0dcf1aa1460fb4611be3e9288f3116ee8be4908c5aedd85f10a1d6eff106e45144301b4c503a689d5962aff1badc94b1ba7fa4350b1e5328423d0f1d677ba71d7d2ebfffb7bab0cb07e1f44dab5dc5b1e7ad1d2fec032775823d185252f046cbb23720db66fe19466e3ed91b95cfdc043ef411623d22a1f95dbfae3c61475bb25826520b943b8a6acbdf6b6f67b498cd239258ea6203cc14ada7422800a8381b4d37773bb073e4690373d9a0daa177a11de73acdc90bf9e7c401d2ca825d600221614d0634944e3160582aeb079b7f0262ed1fd35270478a9fce72f8569ad000698609816fa6b50b3aa71bdff40913d4564eedc2de440b848085a244577509e704422016090537c430befab4f1a17ebc26c42fdfb48c85573087bbb6e6ca9485fc995cc1d2a0189d506ebfb5ef8183a1b756bfe206134253e55a7faadb263116d87c605bf49e57da6964951a8db4709f850aec14729796cb1b4159c72f6ba3c1089d2d03f11ed1bed80b7cf3ce06c98db2e9c1aa0bd4e821a1f9996167aba6693ce24cd124dcf4b0b3ed1dc54fd7bddc10a4564fabcefe9e75ab78e85407a5f422de711b38cb176063a865da345b0e40a24b56198f2a4b673c19bb2d2159b06e817befa7eac01b3be26cac7e8c657583862f8a073ce034f66cdb09e3d139d24851c569d03aa46784848edff4d85122a4f65e8ef97ed66a2160eb79fbefe46a276c356039766191ddaf1e4e4e36f2c50eeaf44bfd988ad9ee04dfffcf54dc1721c63262408a1b38d8c954aa7308b17f7e469578bb6ad2eb6a00fd2695ffd5e7d36a1148be08aa3b3b3885f5eb38c385798aae8b54815a230142c5a866f0d314fbdf2eb39884c7993489d5c82dcc6fbe323f01670a040f9d8e7fb88b1fd874e7d4482f216761e04d1d25bd39f201c07ba7201a9ff828e0b68156fcd42b2ea2d6b2af2ee81301e5b7a484aaa89b4498ff00409d9bd14d81b5ff1f61bc57d7ae3481c7e7ac76dcf4991125daeba31c44a91dc28aaefe64fe238f84dbb209ad7e6655f50eec6b0cf43e4fbd2ddbe6e30ff2ad472f38eabd141f9621d49bbad740e4250fe7644550fd7f8702240efa4b27bd2bee6dc0955b744210630395603e33e40dfc8418d8eade1c26ffddecbc8d054e766db901c00cda5ef6edc19558f09fc08c3f3775e3b36d5857f4211521245533496ecf2c90217af0eb4d90d403486cf63e459f4d26e0f429e573ccf2e92e0c6aab72775a7a017973fec65fa0c6a79ec1f5b79ce45773fbe0e400e30322401cf9ed7a6948cad9a12b3fa05ca431771621a6623de6a80212c44ace8e41ae6fc9cc29c2dde5155e6bbf5a80c0d834a7cf5cf85d8e5bdc48c5d02a2636d017db2f43801e2a99f8ecfe41ccac3f5bc7cec89e6d91a7ade0e32780fdd5ed19d8ef7047521b9df17ccf1d38593fef12e5c264663c6f70429e1b6d6c56c8d1bc7545cac84147ea395c618047b64be7de32d029ec7a271d7acf8053d22eab3314f80771c6e8ed339146b3939836b2ab39be3395fe4dfbfc2df3263277607a81102635af05984a9975497f6eec8040fb90b06413d6e2acdf530ab7026818804db272b0d0c96e8baf9274b2e3d7d4868319a0ec3062d6f38084fc4c6b8bd9c3cb8cbdeab5a60229344804b2abc4f2bb48d7f380fe321948a0f3730b2e8246ea6d2b559ef14e321bd993c0bfa6e9691f08d63eb39303e88cef4626978930b3650b38f3dc80c0f59393c3ddfffa7f1bcdb4d43ed981ebaf0c9e74a0c87b47e7b19f9fe94ca4adc7273e0afa3bef13516cd04542c8efbc2b0bc15c48b46e031b82d724b28c1cb0d3440de1adc08105e07507e988fb63c11a1632b95d69e32e5d594494131a56fe1665a4fcfbaa48b6d9cf6f0a2722537decaaa3a5ba4eb04e1dd324ad3635a1604b90a4ea26de399d645d1a1e31194896898d5b68f6017cc2d01e5fbacb56a95dd77cf9109f7d8e698322db0e21af3b8a510bdb238ebfced79a11e00d229e3f04bb5afcf55500695295cf1adffe5ec7b239c7464e73c87f7b600d86930c8f630fe1072fa73671fe4e89ccef9867dec8169a8570544cbf462712fc5f520e231869607b816adbee31388f61c761c16c4680fe3ed6f1ed5aaa031f77477d282abb973bdd7fb26036e871168b266f2b8799aa2016d952d46969a6f6b5bd8c7214c9d4b9e17540d5f6d8eb64b783326a79f3869332e46b97e2d5d69d732ee4785b4fa3288418c8e0a7f7d50ad4c3e29ab31f5f95a1376ae275a7c2fde85b9d179cd4744c61d2c75804e3ac69ba4159ce46e325000109de8fa452575c8446bdedd2b869cdf01c445546306cb119c2c57625aa038a6ce76673066a17badb1437e10327496cf0864a74079792ff7a90e672ad27c07fc305ad84067adf07f20125a629d3384eb2f039a48738cea5d5f0887587bd14f956b96966587cd1798a8785ebfae37338982faa1f9b7e3d3ae64d8f128763d110dda61a5f3c7e8a220948c2f8422b491edd6c7bd827831c658ec1a90b2e96b2aab3b8b2e755af9e98b0d39f54cd07504fee9946ad166f72b7896a064112969ed0ef79db1bb7b138a2c7cdaf7b48e393a8a7548d77dcac0beee6abea4b37a76959c884721846af172f38a87617f65f96a1a85c6aa05900e47b933f94dad564c6732e4410562d46e0e78fb95d861bb227dc061b42f0cff21f13c7b2a1166405c3111a332704705a5fc4605618afabd7cb2248f41a4ef1b1873e3b73913b67a268b5240b5811c6ed914497e7495a0fa21e8a0aceb2bb8f3c7d12bec306ff1a1db5202be0897e92fa14c9b475bb204486ab6a38de0f3679f2a68d819704d80886ce0bf86c135313fd6b507cfa49ddcf26d0fc64e0203e34d8fc721085de0620d98444aab0779d4307141968a123b89ce4029e5c3d48fe28e10d950b8584640f37ed0362a641465efc9b0677edbdc1241179c7dbc2559383b931f4da7660f97dfee181447191a030bb3939dc351ceb0220fcb03f2b35e825c31a7f96bb692f363efcdc14cc9150a7dc649eb8427166c2da9a432d8ffd53e20e7fdc1622fec278467f962ae4309f9197459e9f7649009c4f96e8b08cb35102bfd4e9bdc0a4d370a18c9bb06e0bfb7d0f6abae10b56c63a2a086bb457490fa0211c06a5f69d1bee24963de482347a6cbf8c53d16dd69e2b2faf842c4edd9fa1f3b22a571d532ccaa77849d78d7043ad978351147c4bf8ac3255a77fd1b593cabf4ec3848c318223578501013a15b05ae9fcfeb7599772ccdc5755b9e4e8fa14aa091b3711cd856ae70fec3046053c06fc4f10b102a28b9fd801dfc44f893bfe4582101337dc29782861598d35ca228ca7aff373fe40ecdcd2797e21761a309189214d1837a952cf5f1c3475dc7a3eb87713308b5311068da94be6849e9da81f2416f7ce2afed81fe2cf4cc4a6b9664f9e90ac147d3728b0c0a5c424046d59f7c65213d1140ebadda97f3f78354a1c0eb0bee920190bed205429de31b16a3f5601dff9bb88dd8a1e253b3a65e54c443f05c17d3c45e5ce47ba2efd07c1dbc4d49313914f91a0bbe32703102b0e902caa61e78131f8d7f8ccff70af135a6e48b2f53e25a4f92e41af93af01e8ab3b84fdab0bc9ce12d65e6641479330ca164634480fd743cbc21b38a6bd1fd1c367ab87d2551a7cd0322c167849d143dd2987fe6b1fa6cb3c57014f3cac2b29479a5e25e251bd8b436c716221a15e94be7c17f9f4eebc21462d8139191aaf2f1089ab76bde63511cf8fa7c649bb2a44b1e27eb53fbe7e27da6aa810e70ef0c2a0e34bdf9d20d05e737edb36d655407ddf4dd71e68d28fd539ef1e8278f5909b754aea4674433f40bea34d67a7198f0677761329ebfb273b9a5fb5f141e63fba3b839d58b01f24c2d259ece9348941d1eda4e5cadac8a483a44439d193e3a95d33b859d158bb8182a9481030c56597c89e03dd4e9c09cc3a9d94a80533be79b21aa36ead3265a65628172683eedbfa29020dc1bec4ab42a029f3ab4c5c20e1325085177ebc17ebbcb744435e71f586d1e8f93968455b4131d47cca24a6ee9ade7fdad30a12b08f794f52a0ad8642b3ab4fc1ed473e5488462e87f83caf26eaaacbcc6fd07f52dd5e4f6e75b4eb8767a22da2d924cbb8d0645717a88dff46c7a247d4e2e141d3d86ff86f9ad96a68238e72370e023b168319b01368bd02e8b830cf664d60b5b010604805e08033af3c91768842a1a34360fe8f3ced110fcd4d60795ee4f6b99f9bdd9f0f344e646d6f19c5899ad17b653db9538c583aa1dfb84d579f20f9833df301e074ebe204b5d013022a9b8f74f29a74ea489183a95ad857f384517030090ecba6783687e08a5a2829b2680c4f0fb38ae7e80b1c984646b8730c5a033675485f44e8c3663cb7169c959fd4ad41eca684fba6577046de3bd16c8afdb6111c1b869b90bc8944ef88836e3d0ad9491e71a6cb0e1442810dbe0a39e448c0d0a701d0d0ba94962d19af31fa7c59326eca00c7d4ba9569b3a8b97ef6508aa0507fe31fda75e46d702aa4e6ce2072b93b86ce7b199384083efec6d841d980145acdab9cd38bc63d487905cd739bb5d088920cd238cc0c552b8db7e3d2527ad9c647297b231b9879621b247162aaa6704759e763216e49d6bf1d23de4a7af1768aaf47674671453cbeec9ef3b41ba5560d6915d0b64421238cdbac14d1b2a65249550ed7245d512027511a5efeaff5965ff7e9739623edad8fa74214fb4ad2f5c28945a633704ae2eeb7b07760843db759a9b9aa9dea4552831c6ac0c0f95ed470f63692b0a61b6d2e0fe33578cf2aaca00840c3d4109fa787204cccd733790de0c956ac6a68564c4bfd8a26edad3309c8ab1f017146bdf67c2e3f230bb214d05f40ec17cb37333f07e9053bab3f48c65d3abd06d0ef54ae3bfe4a37832212a7e171659bf70f59312a09cd6e1eed5cc33097616ddec714f7756ad54fcc678e2b4c1b4aa92c763e3d92eb4e2e5f9ef36d805dec7d51c8a39902c1f789cdadd3d4959a75276b9c978bf33eee37607dbf9308a4286aa44c32b7d60b7513af95ea6f7e8199e56be44b4fde26c6a68985765d195d134ec227eecd22b143b84276cc2e3ff15e8f88119edee6949a298f80e6a81310e08aaad15350b7c8d5c600d916725d2d717a3f210f4d8949b9501cec60d725a856efda655b981437cf5bf578f1cba4a5989be13100e280af6fb6375870c0db147fd41163de5aa9ade4cd98c173ec057431ea8d1fa44cf4155cd65b8e18444956858b4a4ece5db6d87aee09958bc4602180599477365ac947855baa9405a305831b87bb5e0e205501bc2991d4038168b8d93f7f833fe1c7a61dc8450c4e9c2114452c473afe2296e4ad6ffb9ef6f61871c26c5989648977dbf80a3b122b60e3c17a697e23451a1bb00d385870bb392cd752e2b6682cda92469ac1022e30c30f5a66389faaceeed90920e9675bbf9a742fa586005d35ef3950c1fd79cd5c425f11b45e84043fd9f6c3d22d3c2236735cda7bd621365abb30244a47e95997e66150c1980fbed440381db9b079c8022aa822b03d768ec22d6d418d0154cf2eeb079bf7ee199d5e708dd0e2a714ed906bb465bdb8096e9fa71892d1de57792797ea4aab6bb67b04893965fb14e42478647e482dd4009d40b64280e3cbc72c432d979e932b7392903d8796c7e0fbec0cb24b2cd9ebc39207d334f9d3067ba460601cb5c53b97756135dee7d300c23c253ebc5eda82127fd6d47d379bc051aa7ecab7b5ce53ffdbfa5c359ac15f8b2f9de08acd2931f402c4da9e663d4606f149e2b2403a5f4f543876762de1d217ed384d830ff4ea42685b65c1d1aa1af22566f947f109298002ad8ed9e51ef19dee4a9ae91551c6be8c0cc3ca232da8c55e7cc24d744aa06980d5f0f67dde6bab5fb7b8efc7c890dbb47342b851acca6a50679dd1e6f5d595cc3e7438ce8f5a4f4ab9bec6e580bf0e061fa69a15852004bf50ce6d8cf6e390712005effe9ee610392adb30dea5dec6e4eef1cd8195bf91e39bdf8628f9650492f940beb1163d3489650d57d0dada129754faafa21a95ded8da7989cc3595de36342e19e62bccc4549c6fd5fec2ddf3f797b47a836a12e6f78c2c2c2950eea2abf9720758e95dbf1d824c0e368ea761687999098eb1cc1bb04351d01a2af1bf8c635cdf2cdbc7df5237b04b4588063275baebc724a1040d89a57c772e49057c44eac1d76eba0751f269f8140ba05e72ddcdeb6a9c589f2f0f635af1426d4fa0825714beedaa8e432b63581b88ad4a8e8812962bd6cc00647e5a543c933739d0d49e3fd6d1f09ece35358e2dd7479c20135a0f2eeb6ce3094dc53387861c6a8f2fa4c22d0258ce9cae48c01be5099c08d6bdc05d4dc2fc44ef1cd11e302e4a4fcc752033656e9e9458d1357c2617253fb3aed3a3cc4f02cd5a95c83f9cabe0bad170e5ef5bd251ac7aad9ab9b5ae54d958da14a1e5615fedd331320c1eb22fce5b54d56fbeadb31ec0d62543c6f8f96e21cd929a30f46ab6cb7d6b3649b7092ea1bb8a5d42c35e10c281b0c72dba3316d2a42c6e9546b9725cecdab032ec1836fe85a1d1bace0b168c3b53e973a372526d0199b2120396a08875312256bc071acc026639e57b5fb2272f9394724c5849dfad0e2fd2e851ad50523ff8a59b720813ca01210eb5435a2a85ec2e2708247dff646f189a448ecbe194830e1ed892a40175729272ab31134bda9fdd2ffe65e227c793b8eff1438a7542654dd8e2534a0505e37b9b43157fc6d4866f8790febbac853b03d5703420a7a21511bf57ab50ec513fe686a665f12c81d5db2b65eb04ea1489d9279da8fb9a68c5a61d80f732c2609b13d207eaa08239eabed95c5e22a5a9cddf9b21454d31955faae5092d9740f577195a242faa41f5a432c926d02635ac54f5392d0943d692e4d10e8d0abb3045d7a9a787971bdce58e146b8211d5052167fbca4456c6f1f22d46d11029531d1ced39b254161f46e052f2f35829efaf65319f3536c64fa30e68f6d92dd52d21d88e055436f313657b3648c94070030216b4bf63338262005511f4f451474dc4e141aec321204c879cc1e329c3a74dcb144ef27539254df2a989854dcd0ce4cf0527eee7a793c6ed5478ad2b038ebc8d2b01b5c6cb124f372568a64b9117a0abb5dc4b3f20c1e7de229a29d15aaece676a1d2ee34f5c71f42aadb5014f6c7455596334838e8b29aca65dbc1fbe858831fca49589ff55d784f4763d66d44d1c47ed7fe8fe1731ee0a3bd22494120bb0217a7790a46e9f5377784fb7337b84d0f9d6ddbb22b7913456bf7e88d6978277dc5e2559d359ba040d460fd24ecd5d89baaf4bb8c3ff6e2e29dea0bd04ad43a040cf0b1fd8ba18ff2d13693dffeb9d85143a9749d8c6f8144efe94688f4fe6232e91ed46acd9a616e8828d27b435311072134e171fcf2037135002bdaabdc48dfde8ce84c0fba4790eb58afc1b964e4de3edfd6b8b8de27593640057347a1b80c612c0d305bc06db5b270ebd05fb0b9b72b9c7909cf1b126369bbdd0064f00c43da0438355d0c01cf894e65e68cdf820350b977af09f4be756299b52272ae00096a65041230b74e39924e9c60e93ed57a621032d27c68e3669fa4d4e321dfd5873a0e54c1cac716bd60c507be8a5db114205456c4859830c3c184e97e3938250e5a77c13b4751310792d8ab07484cd91f1a49077e2e2572d09f6f4a2317d65c13bf52fedff6d52bf9203cf2360ba755118076d6a025af3505982433bbe7ff3b272ec73c3a51db3015c4c61dd5ac0c8cd5fa7b3914cc02fb143272cb42f303b403e839f68e69d5c585c6930b536418bf841d2682170a8389c6c103894df17ebec7a10005b1522fc9fdd125f8611799b411482d4af297a837a5a2e199d1d50d5fb2ce16e1a15ce0175852a974764909ce052fc0d22c9516628e1b61071e079231b035918aad270cf14e4458f96788ed80a0bd1ac97b47d1f78c5a59de2405a89b332b50025d23a8ca33d42315701620d115cb529eb14f7f760b4d9fe8e0bcd71ca2cdcdd3fbf34ed60102db07b3cdbef6554d03c491480172ef7f32a6f45834ad478f4232921dbe50fd0d4230917708dbcea2f8015521999d6f28f598747497bcf1efc4d746eb5e4364bf8103251d823b758302e9a79060124e1f74019e874a31ba6ec6de2ca8a9d5ce96e0c179e25542e5e6f5ff3ac4157707d2de99bc106f874aad8787fe98fc60e7f9cea6fc332a67a964c09299baa56633a962b9170900870c9c166091bcb02a4b8726d7c4b7648fecb473e97ddda3b2482115a088101fe07ef11a4f98bbc41bec40509b72bf909a7bfdfa6baf4b39c49e6d2563db76cfa8d5cc52a276ba197a4b779035e4617711d84c6b051993b7fc826e9bfeb0ed46d28aba8de6c22f8f3c17bbc4b1e05abe154dbbac769766d28a56817e9062e19d333f581d886e9d2e086dab6e7f2783ed22562d3520bedf508bcab5f6ae1cc7549e816bd526da3deed164306c4a2f45566daada5b0c4fa71dfd64f1530347517da62f068421d726a95b52dad0dccd5e90b877951bf42973ab573c052c4ad67f347147a40945913eb8bf26dc1c0a0343fe476291e9b7bd063649faa63a346e65675a5c609a9b39a5ae5c5bc9795e1fa55613f6eaf439e56df943edc9de1cf1f414ec93e2feca6af1acf66724f41b2e5ca8867b194fa94d81cfffce57a2e693bc04896e1c0889cfe7615bdda0ee7e3027140ce1857bf2d5ef314c4ede59ca5b884b686e356a1472eb552a1f763aee948a2ebd7d02fd22bc169f1a0622686fa83d070d49829fb8c8924559a04781aae3c927efe6bcf4b74f05f47c5cfaa9c3a80e968532c10084f38dd0fc36fe626a822342b2cb8c75e32b1a1bb977c361c71e8ebd0636768e2036102f0f8729c73360baf09c8a08381f13dc08fd6afe4ebea9afe0e15771de14e40c6b92c5bab167ef24e9d296dc6f74da514cd3004fa62808ae26731c82f5299e73c649fc58897f9b59da248ee9c13f11589664b50f37d79c98c355b1d0e65b269003b48b858be775d23c1704f8af11120ede4f73c1380166db366435bbe9eade595f4a839a65bae499ea74d2ad4fa3305de235e1b32f74ccf05cb46e2f61a7b68d010e1c4150a40c9948b28a6222a1391ad85e6ea13d38357d1f733d8ca15e615f819ab1786a70a3d0232673575fd65bf67d3f3806587dc7dca35da09c771187fd487867a50421c76de37a1134c9a03214baadf34f5c8e62df0c816ff40208c9894aa0e838e7f2f0d35a4d0aafda20582cecec3e423ef9a1a52c300564fcb11f7a3a3053ec471e5295402c2f6876eac7d7c8dc4d9bcbc36815a42513117a89b96d06258051be5aa602dfc21328c8b8e11612a76d919e11081fc78ba9eaff611355832ffe9b0ee099b19bca00545eb8cde489bc6920b465da6a101d81a3239b7f06d1aaac850fd54468d5e167fcfbd77807eca02d7da691843ee96680a136288981cca2049071c92949edc77eb966cb04942b9be981d8bac8106d112f6e9a536769d45452f08cd380ba0be7f92dda9e2e6aa5d3488cf9408c08b4f38ab56377c41bb854f787ac0fb42ee92fc0ea74a9a34e7f1063a0b60cb724b742e921ff975bb8b9bc963ef280eac103cd287a454474cee4fd80ad5785ce6039a2f59015422e6d913d8dd027eb7e4edb37f09aea2680a9684795bcbd4e1f2d1aa7dcdaf7b61321261f387d6c9264275ae69e129a41088dee0cede3147b156c54edb635c02a851aa720f6bc95b1be17738bbeb44647fbff20236087b02a4bfbda861111fc8019824edc0f3d6187ace2a0fc7d3a5b5295790424121abd38b3aec4a09a68ef7c56beb1e180fc8c4bc275c0a27b7091a30105d2042f34e4aceda29d17dad40feefdf578814e678028127156a17cb3550aa9f3708f43be1bef91cf43acf775e0960d417bbf19391da0d079ddc927239c25e6b2c3519834b1ac69927bcacb0030bc91b46e54f814f7405ddc5b4a96b9c6da49f9eeb66af7454286a5b5953d109159d7b2b5bbb29ab98fbd54bc44fa7f730fa55465b33b8bf895b71e8f59f3d9eceef621c0ccfe39dc12011ccbdee56ed4b58a957d29510893f571831a471e4f527874b9a0683c092895c19a3555fa29941aada765bce3d3204f5ab4a5d3471fa1ce207988e6b691244ec2b6a9431effab35fb86a828e3457bef007969e4d52da27066b29878305bfb64e92433e757a4749520a1d75c42de4606c02a97d5fc7f2386b027af33cbb80ea5c2991cc3780ac7c418c015555d01f72287d0a33a4d6a0da400cb4308527f400f8c687dca225e3e24d60d9ba40bb6b95b25a348aabd0c247d6516715cf9e368ad4f46f11c574f5c93c04f6566eef0c96a1d7b90a06b211bf2aaba1fd7fe1cc4d423b6f9076a9c6b64ee0d966d303cbb9f34fe62cbcf984c03de28a099e4817e2db4496179f833a589bb7b1af3ad2e1c4054a8c06e39b084b1215bdb3ff95092387670addc73807b12c55ebee8cd79a5a3152269c49e532e1ac917e69162707294df1ee30419ee7831ab91c126d88cd9923fc78b2703e7c30e7b6a3268dc44b17e4a3eb7d23012810e7fd033da0c131c162be9b81e2467158ac9cf4e49529d7f615d8a14d2cc07ae041f4a00e1938450adbe8fde4ffef5dbe88a7247bda3c00864be9021854e665a32aecc84987f47d4d10bc52d404f0d3f9770a130308019fe261090cd72e263d1fc838db6fa808445d5da39a2aef6df55c093af98fc2bd744dcbd80dbb275db339caa67189a91e86fe9d1beeb8c56b159c5d3a74238b98e5ebadc67650916156b5029f015ce145212109f35188794e6346bc8bb4b35775b8dfe9ccf294b3e2a776bc0cc8a524217a7c941164a855af9e057b6c80698ac12962f2d0eca060400eac0e8d58ab0c3ab7c52ebd661907c6b44cc2f397019f1e9be663158d8e797079a7080d9c63c90c286a178965e90607432dba91c416a68afd05bc8a32f41dd089b16b6f3015e0d6580b83dbb936e410da4a17ab03f6fb1852c288e661a6edc80412b7d2de3a1b2f98de8553ec7124bf00d36db918791fb449b88e9766a077e581ee998a888154bd5303d5e460d7995e6174a28f4cf9ab18227f15d89f6e105e4213b096169051b61dabf5c376a3b4fef80ffb0b434a5c1de4a4aec8d2acdaedd6c483ceb73a9737773cae6a938cab8130843d33f545a8533156ed3c07e08b5d7fabe798ed32ee52f7872bc9843ae0ac5a230daf5825eb3c49c60e36ff6a0ff40926e68aa36baa0e0ab62a72e7b00a2f283900322fdf5f6fe3c29f9c9506f11a71dee470aef32bde321e30d10511c10b90aa33ef94ccecef92b43169a9f8f1e16946dac7cebc58e5e82a24ee34ab29ada2a772f5a6899fc0c165d7d876cfcbc7c9e6a1653b63523b974b8d1f330e9903b2c7301f1ed8c5c6ff338cf987ef7be73b3527a4c0c5738cfc571752854a04a907cc4666baf3bea241fbc55ea4f7eefc8936f73df234bf737906d507382076556b15a113e9c7d21641ad46c64de49ebdf3adeaaee8bff0a77d728633054a377ca857dd3fba0cabd2d8fd463d2604d21b29ca1f6d2b0c35df94df763189022ccf645a95bb391def74a94c7291f50065046a1521303da7b9f5f3bd9ef8bceff8fe18a123bae79d7bd5126f5e40e20b95702e366ae17697165537d6dd8e6234137d699da1766599c9c07887df1c116193983c5b8e6120cc351ef34284bcc47ba240c9d68af29233160cb7145b4d1560aaf0c63a7027fa3c0e3ff7b15faf0cd6a5ba5e6b36264adbe7f0586379fb2220cb46bde52ae34e4d09b845f9666341302ae5f6708c4f7ffa505ea4a7402285208601e32033fe630f64f3f4c990f86450ccfebc280792b3e676e51d5000ddd777b2ba1ef3d15b1afca59592fae4416d282473973faa1ee760fa674278abfa8361c5bfabab329660f26ccfa535f74c5878c6953926b6a2ee776a7faeca57650e33eb3c5a46535d429bdacf6ec33f4887886cf9a59da1ef1e6c362d3c693c0c318aa4fe0edd22a2e50bf68f7eb28a9f111ac0e0fd63d947fef87ecea5333f22fd8fed989b57d55d5bc18a48673174a173b9aa5d85c673dc956fdca625149d45bcc04cdac408635c2eae00541fe4057f307bb2ed27c4ffbc78e2bf88de92747cb84ca3459dbfca8b69b7606b5b9e3518b243b2e390171829ccab487586b9dbb7af141e7e636dceece365473bb11fc227bccf03d318cd11ec176390689e74244e19aa26161909739d843be9efd1c39fdcd7c1623d609e0f85f0f27c139d9aeffd6a6f20a66390b5fb19cf19b71c8041bb36291fe350841d992c913f851d0f64b74bd3178e1631471d922d40dbaefb47ff214ff022ad354e1a6fac80461f880abc530da8b22a3df599ccee6483ef506b276e6d53c86666e0360d7a7322025aee55cca8d4d8c21aa061c9929e7e19f64d724b39ec97cbe7a84c219333bde68fe2164ea70e09838dd3957a0afc1d549ae7d962f2b4e4c3abea01dd2f050bb5a44bc699e2a334429dc1113eb4682163e7b919747e58b18d704d8f2bf3751174df11a2e76785939d1a64fd43a663bb6534702e79f07f8a0bb4a9f5315f6c083d6961d591bbe0bfd43ed0de6436db3f2a1e49b8f53b4a13897c2ac2c68c3d71c6fed1f5d0b301af46038e84a09dac27c1fdbe718b4df745de8ed609bf4a12eb303947d9dbf27bb95f8cdc56771e6ccd12529b3bea7a46a8c994025eeee9ce2c8c05056d656f2c5b223d76c8baa7d89ae55934528af11643e460148ffcbd743f4d2ec42d7197bf75f51f1eeb4d1470512996b22f50f63e2ddccd6eece42c131add86d03b28d680c45e43f4bd2a589aeda6e34864e7e2f822530bff3e76c591aa502a152848b1da2645b7745cbb2298ead38d498a3ee195aa8e74e4756a9cd61b145bfab7ffecff8673c6a87832c5eb325a8f7cc799b1c7987dba20f9780b075955460013ab4ecf8fac4de303636a0c81287bec2877b90e181497cf5b05439c43dfcb47da62fe589f222c80f74c9e8364d7fd286272f7bde081193f100d367ef3f5e997f316d42d01c345f352662dde9c4e271ecff7271e3f71ed7e5ffbf78d9fc33c482272d91acbc18621247ae24a0faa3b92defbe158d053956def740fb37f8df2b212894e00658284954015785c9e84ef8bf89d2fc868870e089161093b6daf8ad6fd7db265b877d391f0ad4918d3a870d4e7fe9ee0d64d2946734490674155043b42069d3ba55bec5419323e4457b8c5d9f02fabb47f2c9cab241bbac742684107c7eaffc35e9605f509c7b5028502b0b0813937007eab287b4cc332d6a5dd4efb3372460489fd87ce40667d8f33d33c809a26595af1cb67568a3774f20b4fad576e00c520d079c971c9876ed8ac276a4da229449b47789c7a9057d12341f17d76c62a881fa4250aa6fe5b25e2cdbcd0dcce98a5b88a82f759eb6554fff4e1fa475d7ba94b02077e6ff55e17eaa0976db70c2024098a73e28082122f847208431245ea6d500a09bd34350530535a75debb15f12170ea57001f60e995cb617a1716fdd96f7638b5836335ca79bd8a954c36d7f470f40d52a5431d85d241d4ab8c7987970ec40c37a13d8df845c93aa71269655b837a4e7d3a14defb90967bb841db847764fbcbf13210d789c57506b14d1e5990c12f5be4baa88ec81510725790beeb43d7c214ec02b7e08cc28cc21023ed5b23527dbeed41ba8bb4a1206563cd821c666af9b73fa156046fb578a07d34fab23e4cf3fd8595a0f60830f610226f37e1682a03bf52142c3f4240cfdb714519f50762b8240bf57d90f4d9af4d3965eb60e8df7e8e016b475ed373a18a459166ac287194dcc33a39bb1e7533a4eb0c31637bc3733b76f361d1d840312380e4cae32446b20a6b7f410ace19656cdc7870b070bf49c5318bc765ebe5e11c480d6d846b63513c6f63cca9a040e41deba663f97ecbcbbed91d27480acaa4756a28bc4fafe85848b6a0bc77c30088ffad50e10559b190552637b59f98f85bad3e1fd673c6789953a490bc9230161aef702db0d98985925d4815403c75639bf34d5dc331d0f477b72dc6ac73a3243e2fb99f903b0192fee63e8d7009a2bf2da2c6c3a7cf4e48929c9e60543213d00fcf104da508b2d55f3cf208dd2e3c5f0f59281a247fda9b6747f81b833f01d0b81292e00eab0035e8e7954f06a0168043ef080b3f77c88aa7dd38128eeaeb987cdf366003793d68b975b0d882d0a39e1502375bf22795a22aa0d12e394b14680b5e2a325aa5e68014f3c22de43ea16a58282ebc567d75bea2412ebfb464bfe9ed924b984da4bea6cf8d2c4da9e1c1eb36b057da2e49d6f49e2a11414991f8ab059412514c43b1764d7414bd3c7b49d4d2c9151274be7577d3180c2b3f33b850eeb033c57efb727da6e882cccf5bbd4df9555de1a0cdbed41949c5c92cc38c571262ef27e8a04f31cf1ba997a45be61de5732039b4f0ec9e87514a8a2553bd5af5d6552bc358d9edfd5cd5bcb91dc641d9f773e3507f639245928cbc079daf95a9c8a395aee8cdf4a72855df91da9b250eea691c435f8c5f432091c82b0a5510f36a487d3fc15b13be5e0b004124c953bc1ac6c0070399a486115ca5cf5128898a3413d930774468d51f40668892700e18bdf3e6335dd888a9e80e4c0ee7e2bb6a8682c56e72b423409992500bc003265f048d276b4f9748d992020a2c5e8c04aba95c7bc365dee09b3a27bc440bae5d544e2aeddc6c6dc288dd4833752026be454dc692651fe4c94a5c8b80ed10933d61381ce794633fcc162cd9de07fa47acc9ee50fe3b0404a3d1424d67d36c83fbe930e29721dab7e811a5a07066b7a45cc6d3f001b8fe07ae41ba0c09ad3fc7668ea5cf92719e2a25f7430319b1c8c8724ed511c3abd8ac81a88548694a00e12874b2ece8c4f0ae2e4664bb0708a825b5b3e0d3adefbac565156fc7e4530b71c65a19e1c7c90623f61ba04d918cf812d59038799338ba1e7345bd5cd137860e9e5a2654d91f428083607888661a911ff0647a18f6938581a86694c190ed8301c603ff1fa7768cabf390ecc0353c2707bed219b988121070ee6a4baf10746dd982d5ced47762c1f5faf23c746c484a79edc38d99c4d057c34a5c455713794334af027e6535a58357b56d6166e4ecbfee0e8d571759cbe2b981d4ae5db79a9fcde043382206abd6cfe85ae8ceffbc28091e93b1e1003f00ec1b6ad6cf50a42977db7b9fb8992f32eb1d43a986c8e7e875f88fe6472de9ae8d2ca87609647bb3a95f779abdde91e7db84a2fd020667954e3bda21c37e1c25a47aba8a045a5996c205b19693b08b67b013a38695e6ccaef31c0b16124e072b788549fec3da0265f05b5d68ed273bc877e6b0326659a9b62765d408a20be000c6f8c712c80c171e5c4d35102f961da5da184583c08f44b0f8558d528cc65e64d89d49161ed53f28e59807cab94ca6e8f08be8ba3e1014d593354d8499e26924d0d23f62ec3a18c51c6bf36820174974d5dc2992be673e7991963cd4a34c6539f7e2a9ae403b4792685d120fb4dad5ff0d2c7732e92866a07fa5610b3ec00d74beaef090bbf413d96a112960efbd5af900babc6801d6b063ca4ca4bc4556bcbc4f7735284c5b33070b67c2bd338d62ed20ee0d859a324aef85cb0aec0e7f53cc366ab1df287d24a04a9fc7184c501f346eaefb170ceba14e2903c05fa07df83415c15761947e270247fa2f14173cdf4355ab2c12283794ec43cddfc9958666b5702c4b0d802121a4ed698b8233c29aa4de5b4a92e57725d070c4454f95151da95ab8d13558d92e79f3aaba617024d076fc7ee8e638a77958abe239c82ce9592a684c016d1b17d01a04b0ea8c3ff3abf53c66b16b2c75b0b8abbd0cb59666d4f3ae2ba770159e323b0c40087ae7cc1183b89ea5bb18b92ec8dbf2a97639b68aeddc02a4226678dbe2920ac58262d36fb584673fa0659e27703f7ed3e838c45a72192801ae12424b90dd5deae583f156365413f2e990d9c514de08acf20fe937a87314ab30b03838991e8f2b7168e3fab04b6a02f642662844df2225baa5a5fcf28b37832c8e24e7383bb5c3dc1270e2c8156a2de57f687fdd864ff982115e6e505d9267ec3b6924642a6fc409fdc1f5aa09352680b5adb9e2efaf69f31ac17998a88febc8071646f39ae2ed1ec17a443e66074de17767c9116b81163852c45e899b348a4a85993f69b2c4289fe21e271af05b2f5f3163f39d8d75f738506640c8bada95db2ea69a0cf0da360dcae6f224c9ead5fefed7900afa2d88d1381660f566e881491db93b6a805071bb995d4af69922ddbc75f98d3479ec9abb76a646e65f71eff99a750db27ed9a1c5e670110ad2979322044130724c6913d0ecb188f5df6dfa5efffc6d60e5f93c822a4978ed28eaf598572162c9a7b1b74b41ea56364aa63350c2d7c1b67c60700ad64f44d04d02f9ac9d40a681f5a19c310fbbf5a7645ebf14487673d4fe916b59deb1668aea9544fc3bcf46212cb52c325c56f7400510fdee094ca18c901698a7b205d5d94885a39a1c39613396d47205955b8638500d6fb023c92af0aa56e2479e27e0d939630b80c8dfa6e2686411107f802c6993a7477e31b4a35eafad5eb68c20e383b1fcdddc2b536407ef80b7f6ed072daf724388fc8b4f7e0545705c5c0065f76a53292fef8b9e66dffb403cd2e674fa2b35a22e42f3a1280db94344d48cb1fb2884589495508375d9a642984d97b4bdebce630a38fb776d8de2e6256f9dc0cded14d78387b80f3a108eea65d135d0ddd4c91583ba2e714a97575eedd34dfaed6cb3252737956d21ffbdce65bbc9c90a72ea18e025bdac3089475eca5314b005f8ce6636b27a7833859a46b7faca89703bf6f747d5ff3e5d8159233119ade91e7e13e0f4763eb1425ccc243be596fe669132cbeef41649d591d1e22b4e84649cd4ef09b572b40748ff22ca7e2ddebccc8ec7d0877e06dbe7075119780fcf60e1af28644ba8597e75e12aba47b090c09e68ee64800f013f115826892d272b607a7a1a67b1e5de9a4385306bbbcb538f5d1232133c23d540416225eb9f7b47c7054136c690a17452e88d765556409c952785063fd53122dc2eded677abc5536b56e5c28d7ec2ac3bf3e5867aead027a6ce82275178dccbd2df2e2521854c670ba6df148da31c7fd2ce40a6ff8ea7a086eb306f6fd352e5c034dc4cdc2a47d7e1d2ce4791adf109b564d0a40e1690a2861ece05599dcf9ef3dcec2ba6387281477c354074ee0cc2ba929522a37f6a299d3ef339c42140f516f3722a4c554097009f63fd25b750c7418dfd635ff83ff6e5c64dbe12050071a6849bc6488faf80ab3070266ef2262392adc7831424d68657ab6cb6513ab9377542a32fb1794080f87bf554213543cc844d9c2003960053dacc3ba162bb29f19d97c70b96be7e30642e89db6cd07294d85dc82984123c9342bd325231dc0711e92fbb3fa77cb3df007d3ddbed9d6a9009c04b2af7cc740dee02a333048bd358978a2d47da75db25f7a3f17a57a8f088d9900dba827d14792d83463706e11ab8263fe9c4a47cd6f5237444887b666ade30fc6c192f5fc984844a6ed3f3544c2e25d9d12c68191c45899e2e33a8282e1e17c745ebbccafcdbc92f63b75c495e00f5fcd291ada1b5ff7bccb70768be1c77df987d5d8c5e1d68d35f0c5c10d2d319628d3c988c1625412452f399dfaf9f8884876f268fc092700d47ad4e2ffc91a1357a8025c1d1bf0152e321f8462a44fd5d0170584b251ac253b2136cc62018a2f51945e6a69719888ee56d44fbb56f84b3ba332444a2548a34d04732166e63c4ba710ba3fe7cb137f81a28eab679e32ac4af013adf53c4abcc881f642145c0ee18bcdce5419d31191421bebc164332e563bf141b568a9f8157d7e099c94a19f982a90ea614a30b1054fa7eae6920a3da13aaa352651b316415599e570bb022e2ed19a528f447a2b59d6982a2e469746cbd2f6038303993750b83d1b9b567d0afd8ab358fa60a9e8ea18889d2bfd0748e3a572fc7741522651d406d0cd481f4d11709362f088195141a32497d67b5de3244817a9d3e57430028cc6a55db6535491f8b00f146a62045312b19632bd6afd701abb427de1c583a96c2921f4b5f4d52f41761f2e7beacb431abe0d43f362670aafad2056be718d79ddb7e90bb27e10a65dd9ef9de53486f72849417208ca343eb7787f42eaef30478003825a8cadb379a7f7f23c1babdad6175535c7058d9c28b3d46c46344b693bde2b6c642cf032200f1b2de0d329fbd2d0b64cdbf7a475773c3aba780c017b56560bf554443bbccb2365abb08a647d23f7b64002920a02e67d4f5ac3e3a47c2195a8e9442f5905b2c51a811574697fe1ba931708a59d90cb034af0259431780d6533febad20b7816dc9592cd9c279d052d162fc763834d2cff23bb5f14d42534bb3648e3ae1c0c7b14eb07ba71f232fdd9882936f9d6452a59dcdbb10437b9b4e6cacfa1cac7d1de6325c738db0e4317238a79bbed63814c6cdf4cddf434974d7dbc0fe513653a1b9bdf1cba8a525ae1351ec96505227b7ac6df11fe32ec62a726c07de68a14654e664d64ed85fe22328ed9d2f08f079c8eddd3920aeda75a4d14caeac1d5236db76517cff0d86242cb9252459a693db5d6edb0885b7f8e6dd6c4785636975105120535de42350431392aced7818ca37799192d145232373db97525c2434aef07558c4c18890a947403dc998a1d3419650bd9b40788930492ed681bf48717ba22d1984365f1d1353e4f5b90d555c961b302616ed4d20e17aa347293df2291b5ba13fe38d1a85a5978e454dee3f04ef9da3a0591bf41db496dbd5693de16ab9a789416fc97a9e152765749dfb008ed2a850e30b24bd644fb471128d1e3117531d9c61a03ebe920ad9b47412109884a45b509bb5e367636451ed0e9313b1db70c399c62e538ed4210682f5587e1a3b5ca5bd7be671c9f779896b2bc60e8421f9b20ac3367e5c08a8968f485754e946d24f19e97a04eeac12dd60985b94af328483b5cdf8789a216ccc4e141f3a2e58736de5d6a2064331e527c6a674aced538c6c6887c951d9b8c5539cccd9ca14c6eb04f88854517daf17b554fbdc1db25b963c2cdd918ba9b3d5b4c7afe3333dd2751aa174611397186acb57e1c3d2e10194df1d7ecfdef76ae1daf16447fa6984448ef3cbb0ba96cdf2136857b00432a270dc73a411b32656810361b849b751b32188dd9a79545f60d782f4fe77d9dc0c9173da8380dad940ebda57c7e886e55b60f1f6427ce5a326470bebec89feecd1ffd1fee371c5573fdb0c3fa71fb088f161bcc7878a67ca012abbc65847b5a942a26f4d4f541895cc0a152c23c89d6e5a169c80aca16118628ca1def5169982ec7d12af9f0f519a73334d3740100e37318c9d254ea2aec1590de4d7b9905186f7336dac9ea614de81bf86284cd515c7e9cf91c1f0642737b4c813bcc00bdec17cc56d8e0e40fa5a0056c81571b106f54a514bd0d43c7d8988501d173a768cf4af322d56958a1261e9bc944e2bfafb5a8085649a4b180ac4c5dec76ea022988ecb2f71663703b60c5c8a5922c3575b085350281bde1afee9a2b99ffce6ae957366458cb8ded2f024261a08c61850844bab489a4ab48bb5f817fb30e0bc5a8d1adb129da90dcb26188717ee788f97d6c6e5903440b73e1266fd0f3d2e7303a82ecc043f3d48016990b374d87d3d9f2146233d33fdce11c783b1d7c503da42a615a0d1024532cda5e4e46852fc84f85928566082845183e14e557ea6fb233b09f4945765a5dd167661d33002ac94c5e903e13a22b062a056a671c57f74046c39873f98f7a6d3e025354304c7ffb8ea017348dc4cf1eace17c87677e19b24d14c840f3f3293bfb5227b97824179d78cb9ba4deecb643ebf5c2e4a21b756fe12646c16cd72299adc662e5a5b1cdf40db351c1fb66336dc2f52bc74c6bd819fb6fbbf9dc7389d4d23d2a3336a9576329329a070a60106b22d1b4f3ecbb84cd33b6d32f1898ffb1915e2af32d9bea643874dabbed1253714f1e360d606a4feb4fd012978f3c633c0607c3075768880cb1b0f5f5ee6eea3aea564fb9ca30af0d00977f0232e48f618a5c7e50cae95449ab94b10200bad45745d713373dff0ef965999e6aacc901dd4ff4b692d4934d4b5135bd183cfba0860257c6e86507f4d4dfa9f3fd5d8d5e077aa522347488b680e435c6fbffda78c3c408f97775ee1afba87c8e4f43e53b242528cbdb212eca6baa31c8de7aa3213b0adeff5b96cf1e4cbe10b67060ffcac7780e8803a9673bffe90d3ae36985f57de5b402b2f7ac36e17875f5f4177c85c9bb45903d89149966be18bb3198491aa882ce6cc9aa431b18d07f3b6be1dbd48cf3e6b8536beb64e26234bd5000204ff7e59191d79b85f67c1924aba32dadf741a7d467581da5f45e97eeca8c3d9e30c30faec1c1536d19bc069627facd8a626391c36fb4ca06a82e43ea6428b7e9b254fb6e5fbca14f19bb48e4516274f0d2b5be873df3ecc3d82e6e62ca866e2b4843015bc438a67da7921ecf75ca1052d3daa8ae2a5dd1edfd597fcf516030027d948f0c2d0968465ebdb03f7ad5b79e870ab6b6178b231c5033ab69ea0842b8875f9a2f44c1f3ced80ea1f3020464b6b36ad6616aaf4dd5572f8ec498cee7054bac5c469bd753ed4fcd75a18076089462e3258a7303fb3253331d0046501783bed323ff14c44f16791e67379f72521cf9b443446eb145793d5fb343123e3ae69afb4f827a6f908aa2c589292a132d21136c29ca970e5bc08864ca0400256b12ca1f5e59115db4b318340fb8d53089c37649300587a6c716e9187f7542945957ac04d2a97832d02407871d086821b76627ccea73d99132e78e0ba9d7c77a4adff471c6b2b13b92750ff1b59ef2c39c7f74c833967697a980f24bfce9de8a93ac74d2a963cbdb794645c83b11ce78eb9037e616b7e95a33e37818e99143481c1e0d3c18c3ce164f4d9cef339d1ef5903c22c5a4f0d69879cd415b0e50c89fdd852109d39a893bb0d3d526749092c683fda3b90edc59d48d662f555035c60d74a28fc65923dc35754ed0a2e5070a33558d7210c77aded8116c9a386e4d83ef4c2b010c109274fd1eff33e28002c2ed9ee54bf7fbf5e6be49071f668a901158917cd8511f37fc47ff7f6b2f53b4bacc4787c11453ab4381985f371c843ef5710e98e747049391b50003ffc0397321fb4049d3910e90c14c193d84bf4638fd9d904c60a51fb0e344f6256d44f4a9aeb5bd40d9f4b3473cb3c379c6e2ea620bac4f12abdf905e786637153454807893ff6c39f4dd3cbc726b942904046c64e8c94bc47838853044a1d8c897b8718314e21a46e36af23ae01347a01dca4d4a8f88964218b3a03e9a3afbc90601930f5d708f97d8351baf99f72595b179a39fe3804904975a5be5477c20b861d89cc4e4be2decb7f0e869614d6aabb32e4ef2770f8453855c907fbd505bc11da4d0e731916a66bde6730e3dce1880808aab0a3e765e89cc4003c94f39685f528a36dac605df7eb2950d970fba573947517f2a7a5959c4d14ee0ef8834145ad211b55389237202ea6ec2d5e9c87a3c1f18f176f382eb3160a5d490930c8de169c6f0a7f70d12f9823a3e20ff18f494d6d3afec23cf7589cd5d1c6efcf2e7619e778e9a681403508134fafcab6be2dc8bcfc4edd253603e5575b094dc653e745a28e2c8ce9b24a473307cabbba050dda77f29d7fabb299238cf3a4baa76fc46526ea805ea97ebdf1421394f385f689812152c6b190d7a8ac9189923855ccbd32ec46c4d5ac97ca7db93491ab6b7dce2ccc9c9fb482fd6299e7ef9e1011c3576f04a0d3e3c2892cccea1165abcb9a07cb98688cd49a8f3a6c6cff1e47dd412a61bfa1bf7f05d87914ea828e75336f7485c2f47e0c2794fd0c9e26e869630a1707df2e6342ece1840ea57a6c62e27eaf074623e5ad9f3c06bc1fe0b8793d0d9345ff1917147064965bec3f2133ea4140021a3653740be017d5be403db7dfac44cd5dbe5216b9653d42f49677ce7fea6d2eefc01deae99ce6ca74e46bad23385634415784d32e0c626ec21702e5cbc5125aa5fe3803fb5711c845227e29fd58599ab255a7f78f1cc0c0901059dbe3fd4afcd1d801606c13f62fc8fbf22c9eeacd921cbd268b515ffb251f1f57de8de7a4e4e35b268c091688a43011b517c1d5a30705df96f2123735b84fe85a92b60150f9c74ff189afaf6bc15d0f4485f1c7b8c4f9350129451c7c8e3139b075a7a4e3aedb257698c6f195c6693362ef5c89f970b3e2ffc1ac381090f233689a89ead4860418bc6ec79e002a4075ed74fec292943ccb7b104861bcdaa831dc9b1fefea47adf61ba3da85e72cf85e11bc2bc42c1e8a7aa8c7e6af76a6727807864e084b2390e24e19da9d223cf6800667eb14035457b3155d346a61a1276c2b4973b78eb630f7d8a9d26ea7a052c932ad2e68478a2a9a8975847dcb947f5460921cde601de187613aecdf0264715be31df2f3b6a5101a42c08c03bc6eaf117271ffef930f12f27aabd20f4e135b22f4f8a9ebdf6681d962d149a94e506d774c31983a5b34a406e37775bcbf10745b23ad693263fc2258536ac3b3aba82eb8d70cae6f49b66ff87807f4cbe102f0bb0a2b76d93f634d2b31d9a7831744051d6d34ce2db2f45836ffd1afd0f74df759bad69968a2ea99e50fe0b51e17bf1893457edbdd8920201c4f0f9a244722fb0c7be167a83ccc7d72d5508ae227f999eba4690672cd2e561128112a1940bc0d3438b12a56edcfc18bf5ac4952a07e7ed65bc52fa8cd4f57412e13bb760bc9080d232b141b6bfd6617b9bec4f6da3d45e089ad3c133e720fe79d5bf2115659294a790ea1fbfe915c3cba3fcba0755c8003279ca880de528db778f631eab1dc4539b000d29131ad26c2df3d691afedfa5c733b251736fd8f9ae85f651bbad7618fd626b11ee50e207214c4278fe363826bdc1b0e85bd3f545e837d8c79b9599b29232b3a41d8f1f3ba8a4f830d963bd2b0ccbcd848e25ba2d9da36ed5a2bc8524ec2a6ba4ca9e0c12abd0d1037943c80189658ef5b1c365c1d1d10389ad343ab7b8cfb906c5efab4f9ef2a2800ebdb57ae1329042e51119c1f5b9017a9e73511a55879d7253fc439d59fda3dc967cc6941fd663761bf56f1724078d0a3bfe62aa24674926c241c3fc7cf66bfa9b97b76224a9b14b56a29f571e36b42edc714d2a4004a5ad2adf98cea615b6d435d019513a9b9cda6f89b67e476bc9f24447cd20b007f5e0256415c9aa5360079b3bdf9527f18bbbc66cbdf1656d68aeb884def35c2f28190ae61fc68bd117b505f5185b6ad627eb9e0985c7b42c46b55ba0e035d11ebd69306a34d3381e85f4614f7463f18cc9ee6e6b3cd06670daf5c4c9e8f12d9ef0f4637e588e98036b739207c1cd4c07c657709a623e990139f4dd5120e86de3335f057ca139cf711ee1b91f5a887eff95e4b3663bc4798725c6f00d5a54b584b353aa778a6745308c634909cf42ea1eaa30711c181fc2296699e88b134c8bbe0e8a6b5977625fe4abdbb638dc09bd13e5d6a4ceba3b3b28ae67cf03ee09a3971779f6e1f0f1e62190951d901d14512bf029b1839ab34d394c90f71bf98f0318438a5aa2d13e6409a0ffc8d44abb246556e37ae4ea47888ec2703f19811afcfdc9f6a262cfac64a61ab7f424ffdad1eaebbbd25ce9180a194bf570a91dccc0ce32c3c68bc0e9af7c1fae9609031add0c595d62f54ed6ea4c1c83c6c732081bdf49fc7ca103317c0a23708a69fa4a3fa656a037b153dae99fa699fcd5d756563611038747446447a5e6e98b8470c5433fec13b52c0de52a347511a8bf0a50b6e370bc16da480be0279e157985c65ab5800973184dcf75198869675aed8d030b07adfd507c2f45c78a62068d0cf27020653d32ec16e1c544502de069ec6be8667ea5c4045f4d1bdcf4666fe77575a5ca70a1d5667ba22b16dab8460a6d797ebec62867e323915ad53727142649a48c1b7786e03ff61d9f242e85375bbb30b6fd1a26da2073a69c1c23823d609b61d4cd17d41bd39c72a4cd05a2369f9d1bcccf3496490e7f6f58e2d21e8a09ce29bc43b3f051730ee43b15ae0b181a429f38b0e7ececb36e75c0c69574ff204784d9b84ecfac0657f51dd520eb1424e64af9f5af49f7d6a3cf959f250aa906fa7499b9fd0ebef9160a6ce7a22c36cfcb95fd3b2d65178a1c4e44dd1021a5e049d9d3f711df1873113ecc0022e088e9d5427ace22c2f8f9d0e5ddf34cb56d44fb1fc918a9f35565a28940430445d5971cd61c60d83d16c4f3794d14bc6c66c982a0af5b574e73d83917aee044fa0af046cc7e661db78f1dc318630feac179a87a81d846039fd96242f1bface1b6274fb53dce3ec80ee39fe3f4bda194afa84549fdf8bec9841d4fda6bdf144c01eb1189696a0eaad77b710db068497be60c908f225d2a9c267155ca7588112b3a1ad619a21aec0e2a478811aa0c11c076fd69f91ab54ff80eb09b6b7af5d1891be9acd5b00a20d7c8d4a1fab2861cd9474944084c5c1dfd4b23d4264cea491ecb46576c00ab6ab6707ba323fff04e7ae270b34ad44410c2c60e28aebbc27af9114a2b13a999768b0b82eda7a07a812fc00e685fbb700127f3edaa6defaa6fd1381330578058a5c882be9f3da5500b98b77a6c1c7d56acca1573791efd88e6e7bd1c46d3f2e97fa27565d25e7a6a00ca9afd79e0ac215ba2a2d375cf4966885a1e4eb0ee3efc98f53286eab8f09c6736db70bc02cd4d031097142a928e33eeb5c661f92cdadb83e636e4b677a317374a17c1568a433bda49cf13496f99099c3a1d6677f3782e34d836f0f96d86a98b1febb54caf1630c627ff053b7029aef41a7ff6c99d2226adb5ded52e64339d23543fa861f546c0d82ae2a212728138e93193e4463f7a5a86309de001166da96ca4d180015d6011d9b920d5fe2ba261d0be946d759aac34732a01c5122c4b8d58d44c8d515c66ede737d082412b3d2eb9d7fdb740ef028ab4651428d1f14378a10d5b0f49d94cb255f95c8b9b1a1f22073017c7f1c50b9da7f391a7dddc84f22cc38bdcfd021990440d2bc3ba27cba23c1a393eba6519989875ba21fc41136cc5255c3258f0acab7c98df1d6950f3508bf881fe0757138d73493b2906f4324c607a2d5ca84b9b675eeb88f3d7a47aff5da67cd50a9cbaf583f22ca2c33f6794c5b1932254c9868425b0368e8ad24a743fb45f7cc1cb12d72217c7222f20aceb18864430c145556f29b0dffc5f14953d56db4862b3c756010bf3ac77e321b5b8fdd3c0f7130f3daae20990dde149e902f512e88d8baf26d587a6322f77f704742d05b841ba281b9a30c59c89a807897d2aa7441697c8237ac8606c846734aff7dd61b62b5d9baf1df4fd9c4c6a1090ba5f673618258f5101baea9b21ff5aa979f16d19542ab6061a90293980e6aba7174c0e03cf5750dbf186348f776c01d36a179c5f48f6aa2ef8b28f208aa9e7e7e257d7e0960c067b56f276c1a27a07f08b261c5c1dbd74c64c4bac18a9407b2124273892dd8d5f01b75d6fd2845b4350f8bc4e6b46ad3840be06a73f3cccebc0a414a4d88b45a84fe5c5084a187ade02110a2f387c5cece76a18bbc3bf384d1f1374806383b535b264f54a4db75937c6d8d9528d57f191a60908fdabf5bd6f089265002ccfb0621af660a466f7b951cb936b0cea4ea7ab361c1c56c64bebf3bde2596ef62aa3125e85c1d5d53f3c11f4b54852ba9b3c6ae1748f50eda313695d09a72408a3340f7ec032f27aa03886dce14d3efd0b137f9ff6195a0bab235636972062edfc58ca48b20f7473402e5aa53a343667126658251ea22c449335c45760c4ee93adfe110d268a46078da43f738f6a314f144ad42c13295623c835ae67d1e7a5787c7031a5e405696a35869e8bdf19d833ce2d32ecda729613705dd92715ebfa42686c78a1b3a3f306a34a13403a345cdcf12c2d5a2bad005768a24720eeda98b5ae704144d8d4944c87e5a42d79b3bd155a6e583f48418270253cc807e68a722fbcac6047de0b3a899d43ae64b17eb48570e230cafe53d57a45ac25352ffc70649c0d5c9136ce4fc2e76c80a38d3e9bc169f37d365d7e06bddde152e000c2617cc408f3e43d0c9ce07d0517b6d672cd3a4d33b73f060c1a957f76446d13a2c7cfc7ef288e8bdcbb7e3a0d29e0570c186f0773e106993378390e8f70b35cb1649beaa9d816d17a9c04519a9acdb7ef1565cc5a2dd1b81eca8cfe7f11000ff0fb26f41be89d0b257ad6c7bb0d34324f3dab0f27e270543da2ba0e4a58f5e90d313391d8b9a65a5bba6670db9484b67d0125df03e7e41c3d65a59d57e1407c6d1c4fe226d020a553c353710349b76a5c6a4dd9247d0173cb938af0bb15819f0a3716bdeeb0fb8801a50f8d4b3716df974a94a5525bdd7f407bb44774acebfc5d6cb1fc1fdfed0c9caf615577fcb0c9131d62aa07ed2b70bb7c8816d4336f46467f8f44bec1cdd9a0d11335ef0a004d1d008c9c0ee75cd519a30e0a384ef5b9fbea7782a41d752d671b3e3a62714cdeea4a0837ae8489da4d7298067264054f1afc21240944ae4996c33ee064525eebe9d4b6926ffdaab410e751edb015c7adbc76ca0c924659a845d7a1ed4a7e7dbb6a4c08d03b0975eb46a317da06cc8050e8dc186ca3fe4b9997b717676e38f95c17c051cdf542290c4e6506a02995b7e7cad4868961194c86ceeac6b7f06dff0cbb6567dfed088b5d5d2a8bf6e4c460dc94ec52c605d7386a6293e278f57a492e033b1c1531b80f9eb820e1623295d94befbba0fc0b2a3ff7dfe344aabbb1a54a16880f2de268a823241cbc4e9e4706afcb7614aec27ffbd446d86ff1f3db9045e807cb0bb8d8cefedaa9d3c5fa0590cab34a3c1993af306ab34a90cfc45a49c587c73d2d2fc86f773c3330841c0cd8f4789b1f9a6d37f00ba22a4e15d295de2c48d4ce50967e1944186cce25b1fe82c58ad47a016ed0984af54713b753e39bc499f823faf1eb128f0c020d565afa4784def6ed38fc694328e58f7db4858252c2effa16cfa79828e23714eec84e3c9528b1320cd6f920fd22206813688d9a3988effa7d4cee002155b16a045f54122eefe1948aebd01ee559f8f9f11c61e639c40f5062f000c6480493f746d33fa3b53ac6adf477dee0513b2933a18dfa01f86ae6bfbfe4491a06399834d4f02a2c955165c8610a52f7967f2ae1090a3ed59e91ba86084a7ae5454b5c1f48eeed3dcd647eaa168f0de226fc618441aa3512b89b4919f5bbdd50d987fd6ec2e1c68ccb5d5b69ec6e0eda8464acecbb32fe7c75e2794bef41810636ecedcf6aa29e1ff6080b88bb66beb26b4175ab2eb17c332dee7a733048ee52175b1d5b5577eb9667e714988447741e87f83417c5aae909df801e4ea85427c99ea716d33084c13865163c0da95a23e74dd07ed66611ec62081579bc6a01eb1c00e99efcd39b72af9482d1c1ad5b4204a50db781d30dbd5c7c839ad45e1f8d68a776d5d6259c895f533d8467360b0b28b445be0393ecc0222e69d82521885a845c728d5c78eb72f78d38a14fdf7875edbdf70c4e67b75213e4eda37c9e68821cba0c847072f9849eefa2e4ae0f12f804ae7066fb23d1d22f5234eb78c40f428f6e5c78db8d34aa0a9cb84ad73debaa6f53fb73e26dc1a3e83661c010336e3832ee525c32540f01f9a891f2b714d9a8b6886800b5c1b0022ad1db1c785b9850880c8ebafd8fe8eeb549a9f54f5aebd56da7b0deaac93cb46b3d932cb1c53322ff3215f82850a3826515f2de1883d817cb5e58e2512680c22a054e873ca7bfaf4b64e489839161d43795cbf15d1ef1f0e9fd21b4f60c77eaed4a73f66c3c390620e19ed6c73c4dabb0b4537e9b2502af0ad74312e67cd9d6c54dbb9e6a680e114301760d86ab4cbe883c87987dc2c417d83fc7ea8f9c290464f1c17f4a1be77d430af9727353ab71827f971dd90457759fd468f116350885e122cc066ea07e0026399b0762d4a13c312fce9191e862a0b0565c8149fcdebc6a26ca05b5cdacce91909450be7408e64a61999228271b109174c7e799ff2e1a24c68f50330bc0d2b79b89274b3c84f3dafb4019b7766ac6f8566177891ab4510dff559ca4f8334f154341bf965f5e9925f37beda3fa1b5d92816df580926561de2218fe541ad8ed1ac6851f3de73d56c00abdc1fa24406eb659cc35e1a905e7f6ab97ce0b728af981d803ba95107dbe489688dc9decaa446c57fa823485dde948f519067e8de98cc1293c78fbf4831fac9851a67fdf0a4d489a031f885219edd37fad85785670ea9db936277d9456d6a54a6ffacbebf734e4197c2c130e5fc073f70bab0fc59713665e8194c5c2605521839551fd887e44dcce9eb51bd4f8c68cb70cd8f0dd399892b9b13cf965a4e9c54168882fcf24325c5a370273e5509f0ac7e0ad0bf249c415100eb84b805662b4f3f9bd12fbe0eb0ed5cb352f57d75a873d42b9b4942ac5e5d892b75af4820046db74e3b867ba5bfbcd66906463ef0cab661b265e0dc8a2c1493e3fdb3b3574d6e3c54e8253ab54a116119f6be71a05f42222a499db405f02c3b4c8cf2fccbae9d7fbc61947a9035fe884582d963bbed62125c751ea20ce725cb779c5d8e10c99d81a293abe0f9ba35be57583ab59432d697ea26be5e896dba839dc10ed245f1fe474760d832dc30dea997f0535f457369b96181b399c89b4e79f73372598262e4a232636bddd8bf0606797a68915e6f3f407d8278c8a036031113c2ab6f952e5bbd6d0413b4ff35e99e147740f0c869adc500395239684946a0ca305ddd9f9f8f91db7964241231e26bb6e9d5bb1c8095b3d35b536afb4fcd4488c52e27789fc66348d5433353b84217487f6e5cf63d61699ed9fa7bc1b7d462d4d9125dfec38065736e1a9e413940aadeb033ae90294c768c43509f11a253b16499955945836b900bbedf8c929218438f62b7ff7ce28ed059f94a35ddde029008c6315c50279f043034c13cebcecf9f3861435eeb8dd74fbea5e402de7c968b2bbe3c506720ddf41bd78e207dbe352147e27749fb3fcaf7aa8998404bbd5285b56f9f02a870a65042a727de4d1af3fa3e0558a3c133150f0db1186450cae185b64f71207f741ed8caa176d286bd6953fe85b5d79a365a2d242823e6776ae1b66fc6079a4479d0b04b4e1e93e19b40712b6aa68889a9c8e707cd0af852de0ba06e22da855817258de2537676325ab16b78c3edfa40f998d49c19caaf4365f9ea4e96b184118d9b86fe2810920d4b242b5d9058ce4c42df3cf9885b76de3905235f19ed39152306b3327c524d978669ac82bbda9b792e36934c45cac7e69ca21ba31eeb8f440e219f3d93ac2e2923d661762832d9b9128047ca3ee82c4e89904083d71eff82d635edb4ae33a0099c4998d6fbd2e19ddb620d248908023cc21e64bea8963832649c8c2b70e7a00b0c19fef84a846d9d559003a26ef4151d4a17b57d0b400b1fceaa9d691967d977799d572c64970496b8f653c4783b0d029a177a190ae89f7578bea713e9a6d58baa584e267efb78859c5274b0b00bf46dc4935511c1f03396a8bca41943e9709872547ace52b7dce8a951bedda2202e13f45d17ab486a3863d1f7141b88026e39864a11dee26afdba4f59434e7534025b4c0ce354f7817a79efbb84b227aab376d29d022210256892b85701033838374f9db9e3670fbd646b37475bb52902ec8d313995e50af9c277cd1413510c315b04e44a4c012f10bb0be23e34aacedaf1dd89fa0c74f50e8367cd5fb86061be4cb29552c0ab958362b21f7202d2a3b82c5b1204444f0c1358d9e03a1913de0ac5c7a8ee283f9d630cde69cf9e5e11a047a568a4997dd6d5ffa5d6561b37af3fae17f1312cf69939bef641927f139e7b8df475527ce1040e2e76b0ea6db483870bac069222b3ab562339a8ba71567d7d27dbdff4e5ef42845a6f878a3cc444e6a439ffaf2789e6b16c1eb4f1b8892e24a309259314d6b821a169ccc716b1acd2313051096cf183753639f6fabe98aa11382e0873db4bf6e73af86e7756edf5947887a5e5e45bc13ad021b889e219dcf5ac723fcf313767e51a2ff971e168c1d0a9b310f40eb0a1bf30e308a8857c52c83f5f3d821aa6decd5a8cf000c713674fe9f79cfa1e6dc5b0a1e1d587446fc38110115942729f93787598c2d72021ce9234abfdf470ce337f6fe1e2c1c25fa1dcdbeea2ee757c975dc3c34cd35a6a539c656918590ba805ff20a3eadd64727348a7071fd59d746e1435563b387d2b6258b19f8e18817cde8cc9dba055c69e1106892b584351ff94fd4cc189529f9bf603c36d87347eb6b339d51f6063cadc2501817240fe0957ec683f3c198815931dcf48</script>  <div class="hbe hbe-content">    <div class="hbe hbe-input hbe-input-xray">      <input class="hbe hbe-input-field hbe-input-field-xray" type="password" id="hbePass">      <label class="hbe hbe-input-label hbe-input-label-xray" for="hbePass">        <span class="hbe hbe-input-label-content hbe-input-label-content-xray">请输入密码</span>      </label>      <svg class="hbe hbe-graphic hbe-graphic-xray" width="300%" height="100%" viewBox="0 0 1200 60" preserveAspectRatio="none">        <path d="M0,56.5c0,0,298.666,0,399.333,0C448.336,56.5,513.994,46,597,46c77.327,0,135,10.5,200.999,10.5c95.996,0,402.001,0,402.001,0"></path>        <path d="M0,2.5c0,0,298.666,0,399.333,0C448.336,2.5,513.994,13,597,13c77.327,0,135-10.5,200.999-10.5c95.996,0,402.001,0,402.001,0"></path>      </svg>    </div>  </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
    
    
    <summary type="html">* CSI (Channel State Information): 
   信道状态信息，是Wi-Fi物理层提供的一种细粒度数据。它描述了Wi-Fi信号在从发射端到接收端的传输过程中，受到多径效应、衰落、噪声等因素影响后的信道特征。通俗地说，CSI记录了Wi-Fi信号每个子载波的幅度（Amplitude）和相位（Phase）信息。
 * 幅度去噪： 对每个子载波的幅度时间序列进行低通滤波（如Butterworth滤波器）或移动平均，消除高频噪声。
 * 异常值剔除</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>机器学习——深度学习</title>
    <link href="https://polar-bear.eu.org/2025/07/03/ji-qi-xue-xi-shen-du-xue-xi/"/>
    <id>https://polar-bear.eu.org/2025/07/03/ji-qi-xue-xi-shen-du-xue-xi/</id>
    <published>2025-07-03T05:51:52.154Z</published>
    <updated>2025-07-04T09:07:30.665Z</updated>
    
    <content type="html"><![CDATA[<h2 id="机器学习">机器学习</h2><p>机器学习是一个专门研究和开发能够学习的机器的领域，目标是获得通用人工智能。</p><p>机器学习是人工智能的核心领域，目标是让计算机通过数据学习规律并做出预测或决策。其核心逻辑是：从数据中提取特征，通过算法训练模型，实现对未知数据的推断。</p><ul><li>分类：包括监督学习（如回归、分类算法）、无监督学习（如聚类、降维）、半监督学习和强化学习等。</li><li>关键特征：依赖人工设计的特征工程，例如在图像识别中，需要手动提取边缘、颜色等特征。</li></ul><blockquote><p>本篇是对之前文章的扩展，补充与深化，本人深感过去文章水平有限，仅是为完成工程任务调参了解的，极为片面，浅薄的记录，本文试图作为学习笔记系统性记录✍️本人的学习过程。(ﾉ∇︎〃 )</p><p>添加了很多<s>骚话</s>个人理解(´つヮ⊂︎)</p></blockquote><blockquote><p>前面大多为车轱辘话(╯‵□′)╯︵┻━┻，只需要大致了解概念。可直接跳至算法原理。(ฅ&gt;ω&lt;*ฅ)</p></blockquote><h2 id="序言">序言</h2><p><s>一些很漂亮很浪漫很有人类探索精神的屁话</s>╮(╯▽╰)╭</p><p>千百年来，人类试图了解智能的机制，并将它复制到思维机器上。</p><p>人类从不满足于让机械或电子设备帮助做一些简单的任务，例如，使<br>用燧石打火，使用滑轮吊起沉重的岩石，使用计算器做算术。</p><p>相反，我们希望能够自动化执行更具有挑战性、相对复杂的任务，如<br>对相似的照片进行分组、从健康细胞中识别出病变细胞，甚至是来一盘优雅的国际象棋博弈。这些任务似乎需要人类的智能才能完成，或至少需要人类思维中的某种更深层次、更神秘的能力来完成，而在诸如计算器这样简单的机器中是找不到这种能力的。<br>具有类似人类智能的机器是一个如此诱人且强大的想法，我们的文化<br>对它充满了幻想和恐惧，如斯坦利·库布里克导演的《2001: A Space<br>Odyssey》中的HAL 9000（拥有巨大的能力却最终给人类带来了威胁）、动作片中疯狂的“终结者（Terminator）”机器人以及电视剧《Knight Rider》中具有冷静个性的话匣子KITT汽车。</p><p>1997年，国际象棋卫冕世界冠军、国际象棋特级大师加里·卡斯帕罗夫<br>被IBM“深蓝”计算机击败，我们在庆祝这一历史性成就的同时，也担心机<br>器智能的潜力。</p><h3 id="神经网络">神经网络</h3><p><a href="https://polar-bear.eu.org/2025/04/26/ji-qi-xue-xi-shen-jing-wang-luo/">机器学习－－神经网络</a></p><blockquote><p>之前在学习Nanodet模型时，对于神经网络非常浅显的记录</p></blockquote><p>计算机可以以相当快的速度在短时间内执行数亿次数学运算，能够高效的数量海量数据，但是在很长一段时间内，计算机却无法做到人类能够轻易完成的任务，仅通过视觉以极快的速度识别身边的物体，无意识间控制四肢协调平衡运动，等等。</p><p>而我们却能够仅仅为大脑提供大概20w的功耗轻易做到复杂的计算机无法完成的任务。不禁让很多人试图再次利用仿生学在计算机上实习以上功能。</p><p><s>依旧骚话</s>✧(◍˃̶ᗜ˂̶◍)✩</p><h4 id="最早的神经网络模型–感知机">最早的神经网络模型–感知机</h4><p>那就回到1957年，找到美国心理学家弗兰克·罗森布拉特（Frank Rosenblatt），一个神经生物学和行为学副教授，提出一种单层神经网络模型，旨在模拟生物神经元工作原理，由输入层，隐藏层，和输出层组成。</p><p>其非常简单，输入问题，进行计算，得到结果，如果存在差异则更新内部权重，这即是训练过程。</p><p>你可能会想“这也没什么了不起的吧！”，<s>这确实没什么了不起</s>╮(╯▽╰)╭，你是这样想的，我也是。但这是由于当时技术的局限和理论的不完善，其确实是神经网络历史上最早提出的模型之一，也是现代深度学习的先驱，为后来的多层感知机和深度学习模型提供了理论支持，开创了人工神经网络的研究。</p><h4 id="神经网络-v2">神经网络</h4><p>虽然神经元有各种形式，但是所有的神经元都是将电信号从一端传输到另一端，沿着轴突，将电信号从树突传到树突。然后，这些信号从一个神经元传递到另一个神经元。这就是身体感知光、声、触压、热等信号的机制。来自专门的感觉神经元的信号沿着神经系统，传输到大脑，而大脑本身主要也是由神经元构成的。</p><p>我们需要多少个神经元才能执行相对复杂的有趣任务呢？</p><p>一般说来，能力非常强的人类大脑有大约1000亿个神经元！一只果蝇<br>拥有约10万个神经元，能够飞翔、觅食、躲避危险、寻找食物以及执行许多相当复杂的任务。10万个神经元，这个数字恰好落在了现代计算机试图复制的范围内。一只线虫仅仅具有302个神经元，与今天的数字计算机资源相比，简直就是微乎其微！但是一只线虫能够完成一些相当有用的任务，而这任务对于尺寸大得多的传统计算机程序而言却难以完成。</p><h5 id="激活函数">激活函数</h5><p>观察表明，神经元不会立即反应，而是会抑制输入，直到输入增强，<br>强大到可以触发输出。你可以这样认为，在产生输出之前，输入必须到达一个阈值。就像水在杯中——直到水装满了杯子，才可能溢出。直观上，这是有道理的——神经元不希望传递微小的噪声信号，而只是传递有意识的明显信号。下图说明了这种思想，只有输入超过了阈值（threshold），足够接通电路，才会产生输出信号。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_04/image_83060f9cc4f294b96510ee7e0dc85da6.png" alt=""></p><p>我们可以改进阶跃函数。下图所示的S形函数称为S函数（sigmoid function）。这个函数，比起冷冰冰、硬邦邦的阶跃函数要相对平滑，这使 得这个函数更自然、更接近现实。</p><p>$$<br>f(x) = \frac{1}{1 + e^{-x}}<br>$$</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_04/image_77a269ab10c97e5e03b50f44ac2bcdaf.png" alt=""></p><p>随着输入 <code>x</code> 的增加，sigmoid 函数的输出会接近 <code>1</code>，但永远不会达到 <code>1</code>。同样，当输入值减小时，S 型函数值 函数的输出接近，但永远不会达到 <code>0</code>。</p><blockquote><p><em>sigmoid</em> 一词通常更广泛地用于指代任何 S 形函数。从技术层面来看，对特定函数$f(x) = \frac{1}{1 + e^{-x}}$来说，更准确的术语是<em>逻辑函数</em>。</p></blockquote><p>sigmoid function是机器学习中重要的激活函数</p><ul><li>Sigmoid函数的输出范围是0到1。由于输出值限定在0到1，因此它对每个神经元的输出进行了归一化。</li><li>用于将预测概率作为输出的模型。由于概率的取值范围是0到1，因此Sigmoid函数非常合适</li><li>梯度平滑，避免跳跃的输出值</li><li>函数是可微的。这意味着可以找到任意两个点的Sigmoid曲线的斜率</li><li>结果明确，即非常接近1或0。</li><li>函数输出不是以0为中心的，这会降低权重更新的效率</li><li>Sigmoid函数执行指数运算，计算机运行得较慢。</li></ul><p>sigmoid激活函数在神经网络中起到的作用：</p><blockquote><p>引入非线性特性，神经网络基本单元是线性组合（加权求和），部分情况需要映射到非线性解决复杂情况$f(x) = \frac{1}{1 + e^{-x}}$</p><p>sigmoid通常用于二分类最后一层，输出结果在0-1之间，将结果解释为“某一类的概率”</p><p>反向传播便利性 ，因为sigmoid函数可导，复合求导可得$\sigma’(x) = \frac{1}{1+e^{-x}} \cdot \frac{e<sup>{-x}}{1+e</sup>{-x}} = \sigma(x)(1-\sigma(x))$便于反向传播中梯度计算</p></blockquote><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_8d0788e8b70ca0dc3d327da12de64c2b.png" alt="sigmoid函数及其导数"></p><p>其他激活函数</p><p>双曲正切激活函数</p><p>$$<br>F(x)=tanh(x)<br>$$</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_15ebed5b8b66fe209a796b9f3812dcd1.png" alt=""></p><blockquote><p>请注意，S 型函数的范围为 0 到 1，tanh 函数的范围为 -1 到 1</p></blockquote><p><strong>修正线性单元</strong>激活函数（简称 <strong>ReLU</strong>）</p><p>$$<br>F(x)=max(0,x)<br>$$</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_7831be009afad4fe283f3ca6b59b6823.png" alt=""></p><p>ReLU 作为激活函数的效果通常优于 S 型函数或 tanh 等平滑函数，因为它在神经网络训练期间不易受到梯度消失问题的影响。与这些函数相比，ReLU 的计算也更容易。</p><h5 id="矩阵">矩阵</h5><p>下面是一个简单的全连接层</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_04/image_9940b3560723f490c7c501a1fdf3f4db.png" alt=""></p><p>对于第二层，二层一同时接受一层一和一层二的输出，对于此处简单的计算，我们可以得到$X=(input1<em>w_{1,1})+(input2</em>w_{2,1})$,但是实际上的全连接层需要计算的连接个数众多，使用这种计算方法即不直观，而且串行运算在计算机中运行时消耗许多内存交换以及等待时间，显然，我们需要矩阵运算。</p><p>对于第二层神经元接受到的信号强度可以使用$X=W•I$计算，W是权重矩阵，I是输入矩阵，X是输入到第二层的结果矩阵。</p><p><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>X</mi><mo>=</mo><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">[</mo><mtable columnspacing="1em" rowspacing="4pt"><mtr><mtd><msub><mi>w</mi><mrow><mn>1</mn><mo>,</mo><mn>1</mn></mrow></msub></mtd><mtd><msub><mi>w</mi><mrow><mn>2</mn><mo>,</mo><mn>1</mn></mrow></msub></mtd></mtr><mtr><mtd><msub><mi>w</mi><mrow><mn>1</mn><mo>,</mo><mn>2</mn></mrow></msub></mtd><mtd><msub><mi>w</mi><mrow><mn>2</mn><mo>,</mo><mn>2</mn></mrow></msub></mtd></mtr></mtable><mo data-mjx-texclass="CLOSE">]</mo></mrow><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">[</mo><mtable columnspacing="1em" rowspacing="4pt"><mtr><mtd><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>1</mn></mtd></mtr><mtr><mtd><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>2</mn></mtd></mtr></mtable><mo data-mjx-texclass="CLOSE">]</mo></mrow><mo>=</mo><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">[</mo><mtable columnspacing="1em" rowspacing="4pt"><mtr><mtd><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>1</mn><mo>∗</mo><msub><mi>w</mi><mrow><mn>1</mn><mo>,</mo><mn>1</mn></mrow></msub><mo>+</mo><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>2</mn><mo>∗</mo><msub><mi>w</mi><mrow><mn>2</mn><mo>,</mo><mn>1</mn></mrow></msub><mo stretchy="false">)</mo></mtd></mtr><mtr><mtd><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>1</mn><mo>∗</mo><msub><mi>w</mi><mrow><mn>1</mn><mo>,</mo><mn>2</mn></mrow></msub><mo>+</mo><mi>i</mi><mi>n</mi><mi>p</mi><mi>u</mi><mi>t</mi><mn>2</mn><mo>∗</mo><msub><mi>w</mi><mrow><mn>2</mn><mo>,</mo><mn>2</mn></mrow></msub><mo stretchy="false">)</mo></mtd></mtr></mtable><mo data-mjx-texclass="CLOSE">]</mo></mrow></math></p><p>使用矩阵可以清晰描述，并且能够直接计算一层权重。</p><h5 id="隐藏层">隐藏层</h5><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_04/image_f47720cbed3322838fea0b2631bcd57c.png" alt=""></p><p>隐藏层，位于神经网络中间层，即既不作为输入也不作为输出，在中间起连接，传递作用的。</p><p>$W_{input_hidden}$是输入层和隐藏层之间的权重,$W_{hidden_output}$是隐藏层和输出层之间的权重</p><p>$$<br>X_{hidden}=W_{input_hidden}•Input<br>$$</p><p>隐藏层的输出可以再使用激活函数。</p><p>$$<br>Output_{hidden} = sigmoid(X_{hidden})<br>$$</p><p>计算输出层权重</p><p>$$<br>X_{output}=W_{hidden_output}•Output_{hidden}<br>$$</p><p>使用激活函数</p><p>$$<br>Output_{output}=sigmoid(X_{output})<br>$$</p><p>神经单元线性关系</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_c7a26918679ff78c5441c9d18d72390b.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_aa861ddd5da4aa99f775217f620253ad.png" alt=""></p><p>神经单元使用激活函数非线性关系</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_4d37337ca60fed8f53a3dd8e00c9b1b3.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_05/image_53f24caeab48abdfc30685bff11b0fc0.png" alt=""></p><p>神经网络（Neural Network，NN）是机器学习中的一种算法框架，灵感源于生物神经元，通过多层节点（神经元）连接传递信息，实现复杂映射。</p><ul><li>结构：由输入层、隐藏层、输出层组成，层间神经元通过权重连接，通过反向传播算法优化权重。</li><li>典型模型：早期的感知机、多层感知机（MLP），但受限于计算能力和数据量，应用范围较窄。</li></ul><h3 id="深度学习">深度学习</h3><p>深度学习（Deep Learning）本质上是多层神经网络的深化，通过增加网络层数（如几十层到上千层）和复杂结构，实现对数据的自动特征提取和表示学习。</p><p>深度学习是神经网络的延伸与升级，计算能力的提升解决了传统神经网络训练算力问题，使得深度学习具有更为复杂的结构，能够实现更为复杂的功能。</p><ul><li>自动特征工程：无需人工设计特征，例如CNN可自动提取图像的边缘、纹理等高层特征，RNN可处理序列数据的时序关系。</li></ul><p>卷积神经网络（CNN）、循环神经网络（RNN）、Transformer、生成对抗网络（GAN）等，广泛应用于图像识别、自然语言处理、语音识别等领域。</p><h2 id="什么是机器学习">什么是机器学习</h2><blockquote><p>使计算机不需要显式编程就能拥有学习能力的研究</p></blockquote><p>机器通过观察某项任务存在的模式，并且试图以某种直接或间接方式模仿。</p><p>而直接或间接的区别即分为监督学习和非监督学习</p><p>监督学习</p><ul><li>数据特点：输入数据（特征）配有明确的标签（Label），即“有标准答案”。</li><li>示例：图像分类任务中，每张图片标注“猫”“狗”等类别；房价预测中，房屋特征（面积、位置）对应具体价格。</li><li>如线性回归，决策树，SVM，CNN</li></ul><p>非监督学习</p><ul><li>数据特点：输入数据无标签，仅包含特征，需算法自行发现数据内在结构。</li><li>示例：用户行为数据（浏览记录、购买偏好）未标注类别，需通过聚类算法将相似用户分组。</li><li>如k-means，PCA，AE</li></ul><h4 id="监督学习">监督学习</h4><ul><li>本质：通过“输入特征+标签”的标注数据，学习从特征到标签的映射关系（函数），再用训练好的模型对新数据预测。</li><li>类比理解：类似学生通过“例题（标注数据）”学习解题规则，再用规则解答新题目。</li></ul><p>1.数据要求</p><ul><li>必须包含特征（Features） 和标签（Labels），如：</li><li>图像分类：像素值是特征，“猫/狗”是标签；</li><li>房价预测：房屋面积、位置是特征，价格是标签。</li></ul><p>2.学习目标</p><ul><li>最小化预测值与真实标签的误差，例如：</li><li>用线性回归预测房价时，让模型输出的价格与实际价格尽可能接近。</li></ul><p>3. 训练流程：</p><ul><li>划分训练集、验证集和测试集 → 模型拟合训练数据 → 通过验证集调参 → 用测试集评估泛化能力。</li></ul><h4 id="无监督学习">无监督学习</h4><ul><li>本质：仅通过输入特征（无标签），让模型自主发现数据的内在规律（如相似性、聚类结构、分布模式）。</li><li>类比理解：类似人类在没有老师指导的情况下，通过观察事物特征（如颜色、形状）自主将其分组（如将水果按大小、甜度分类）。</li></ul><p>主要是聚类和降维</p><p>聚类（Clustering）：数据分组</p><ul><li>目标：将相似的数据点归为同一簇（Cluster），不同簇间差异明显。</li><li>示例：</li><li>电商平台根据用户购买行为（浏览记录、消费金额）将用户分群，针对性推送商品；</li><li>生物学中按基因表达数据对物种分类。</li></ul><p>降维（Dimensionality Reduction）：特征压缩</p><ul><li>目标：将高维数据（如上万维特征）映射到低维空间，保留关键信息，减少计算复杂度。</li></ul><h4 id="参数学习和非参数学习">参数学习和非参数学习</h4><p>机器学习可以分为有无监督，也可分为有无参数</p><p>参数学习，即数据服从某种固定分布，通过训练数据学习一组固定数量的参数，用固定参数直接描述数据模型。</p><p>非参数学习，即不预设参数数量，依赖数据本身，模型复杂度会随之动态变化。</p><p>参数学习：典型算法与原理</p><ol><li>线性回归（Linear Regression）</li></ol><ul><li>核心：假设输出与输入是线性关系，用参数  \theta  表示权重，通过最小化均方误差（MSE）求解  \theta 。</li><li>公式： $y = \theta_0 + \theta_1x_1 + \dots + \theta_nx_n $，参数数量为特征维度+1（固定）。</li></ul><ol start="2"><li>逻辑回归（Logistic Regression）</li></ol><ul><li>核心：在线性回归基础上用Sigmoid函数将输出映射到[0,1]区间，用于二分类，参数含义与线性回归类似。</li><li>应用：垃圾邮件分类、疾病预测（是否患病）。</li></ul><ol start="3"><li>朴素贝叶斯（Naive Bayes）</li></ol><ul><li>核心：假设特征条件独立，学习先验概率  P(Y)  和条件概率  P(X|Y) （如高斯朴素贝叶斯假设  P(X|Y)  服从高斯分布）。</li><li>参数：存储各类别概率和特征分布参数（如均值、方差），数量固定。</li></ul><p>非参数学习：典型算法与原理</p><ol><li>K近邻（K-Nearest Neighbors, KNN）</li></ol><ul><li>核心：不学习参数，直接存储所有训练样本。预测时找新样本的K个最近邻，根据邻居类别投票（分类）或取均值（回归）。</li><li>特点：</li><li>无固定参数，K是超参数（需手动调优），模型复杂度随样本量增加而提高；</li><li>适合处理图像像素级分类（如MNIST手写数字识别）。</li></ul><ol start="2"><li>决策树（Decision Tree）</li></ol><ul><li>核心：通过递归划分特征空间（如按“年龄&gt;30岁”“收入&gt;5000元”等条件分裂节点），树的深度和节点数由数据决定（非固定参数）。</li><li>变种：随机森林（集成多棵决策树，非参数特性更强）。</li></ul><ol start="3"><li>核密度估计（Kernel Density Estimation, KDE）</li></ol><ul><li>核心：不假设数据分布，用核函数（如高斯核）平滑每个数据点的概率密度，整体密度由所有点叠加而成。</li><li>应用：估计数据的概率分布（如金融市场收益率的分布预测）。</li></ul><ol start="4"><li>支持向量机（SVM，非参数视角）</li></ol><ul><li>核心：当使用非线性核函数（如RBF核）时，SVM通过将数据映射到高维空间求解分隔超平面，模型复杂度与支持向量数量相关（数据量越大，支持向量可能越多）。</li></ul>]]></content>
    
    
    <summary type="html">机器学习
机器学习是一个专门研究和开发能够学习的机器的领域，目标是获得通用人工智能。

机器学习是人工智能的核心领域，目标是让计算机通过数据学习规律并做出预测或决策。其核心逻辑是：从数据中提取特征，通过算法训练模型，实现对未知数据的推断。

 * 分类：包括监督学习（如回归、分类算法）、无监督学习（如聚类、降维）、半监督学习和强化学习等。
 * 关键特征：依赖人工设计的特征工程，例如在图像识别中，需要手动提取边缘、颜色等特征。

本篇是对之前文章的扩展，补充</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>机器学习——神经网络</title>
    <link href="https://polar-bear.eu.org/2025/04/26/ji-qi-xue-xi-shen-jing-wang-luo/"/>
    <id>https://polar-bear.eu.org/2025/04/26/ji-qi-xue-xi-shen-jing-wang-luo/</id>
    <published>2025-04-26T18:35:00.559Z</published>
    <updated>2026-01-30T03:41:28.832Z</updated>
    
    <content type="html"><![CDATA[<h2 id="机器学习——神经网络">机器学习——神经网络</h2><p>概念合集</p><p><a href="https://zhuanlan.zhihu.com/p/100938949">机器学习（1）——绪论 - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/101000750">机器学习（2）——线性回归（Linear Regression） - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/101111312">机器学习（3）——Logistic回归（Logistic Regression） - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/101168359">机器学习（4）——模型评价与正则化 - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/102183217">机器学习（5）——神经网络（Neural Network，NN） - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/102502396">机器学习（6）——激活函数 - 知乎</a></p><p>通俗易懂（合集）：<a href="https://www.bilibili.com/video/BV1uGA3eLEeu">从函数到神经网络</a></p><p>进阶，概念（漫士沉思录）<a href="https://www.bilibili.com/video/BV1atCRYsE7x">90分钟！清华博士带你一口气搞懂人工智能和神经网络</a></p><p>（3Blue1Brown）<a href="https://www.bilibili.com/video/BV1bx411M7Zx">【官方双语】深度学习之神经网络的结构 Part 1 ver 2.0</a></p><h3 id="机器学习的基本流程（从函数到神经网络）">机器学习的基本流程（从函数到神经网络）</h3><p>机器学习是要找一个函数，对于给定的输入能给出正确的输出。例如聊天机器人就是输入当前的对话场景，输出机器的应答；语音识别就是输入待辨识的音频，输出对应的文字。</p><h4 id="函数（function）">函数（function）</h4><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_6320124980ba288f75765f64515aa6ad.png" alt=""></p><blockquote><p>Functions Describe the World                       ----不是我说的</p></blockquote><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_19deaf8662f6ea67b848975e24590440.png" alt=""></p><p>这个Functions完美的符合了所有点，解释了整个World，这即是早期人工智能符号主义，使用准确的函数准确描述所有结果。</p><p>但是现实世界中许多问题无法使用准确的函数描述，只能简化问题，核心思想就是“<strong>猜</strong>”和“<strong>差不多得了</strong>”。这即是现代联结主义，希望通过对大脑生理结构复杂性模拟来实现智能。</p><p>我们首先提供给机器一个特定的函数 f0 （建模），让机器评价它的好坏， 并对它不断进行改进（其过程即是不断的<strong>猜</strong>），期望最终得到一个最佳的函数 f∗ .</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_5858d229bdbb51fe6fae6eb218f416ab.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_9c49ef77ba90ea5a2d74a41dec666e84.png" alt=""></p><p>在这个简单的示例中，使用一次函数(模型：Y= wX + b)尽可能接近所有点，但是始终无法通过所有点，那就使用<strong>差不多得了</strong>，认为现在得到w,b就是最优解。</p><h4 id="激活函数（Activation-Function）">激活函数（Activation Function）</h4><p>但是，大多数实际数据并非线性关系，为了简单的将原来的线性函数（Y= wX + b）转化为非线性，可以在原本的函数外层套上一个非线性运算，叫<strong>激活函数</strong></p><blockquote><p>F(x) = wX + b        ==&gt;      F(x) = g(wX + b)</p></blockquote><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-10-12-41-012_tv.danmaku.bil_e8d388e0a9a184416290d598bdf5b758.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_6cf3011680c97f8a99e53db33c599c2b.png" alt=""></p><p>现在，通过添加激活函数g(x)=e<sup>x</sup>，能够较好的处理非线性数据关系，实际的激活函数比举例的要复杂一点点。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-10-14-54-611_tv.danmaku.bil_536524b200c7ec3c2c537fe1aec6b21d.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-10-16-05-862_tv.danmaku.bil_6aae467cd5c8e133f675f6ecc76115a2.jpg" alt=""></p><p>概念：将原本的复杂F(x)画成图的形状，类似神经元的连接（不要理解为真正生物神经突触连接）叫神经网络，神经元连接过程即为一个函数计算过程。</p><p>概念及其简单，不要因为名词陌生而觉得过于高端，理解过后既是及其简单的定义。</p><p>输入层：即函数输入。</p><p>隐藏层：因为套用多层激活函数，位于中间隐藏起来的层。</p><p>输出层：即完成函数计算输出结果。</p><p>前向传播：即按照神经网络依次正向计算得到结果的过程。</p><h4 id="评估-损失函数（lossfunction）">评估----损失函数（lossfunction）</h4><blockquote><p>建模、评价和改进，就是机器学习最基本的三个步骤。    ----不是我说的</p></blockquote><p>建模已经完成，能够完成猜的过程，但是，怎样才能评判猜得好不好呢，那就得指定一个标准来评判谁猜得更好，其依据即为<strong>损失函数</strong></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-11-52-21-841_tv.danmaku.bil_2f8010c9a4bd432572595f5134533c8f.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-19-26-272_tv.danmaku.bil_6c858077eca2ac0d235d3ecfecae74ce.jpg" alt=""></p><p>损失函数表示的是真实值与预测值的误差，在不断猜的过程中就是调整w,b的值使损失函数最小的优化问题，简单的函数可以求导为0求极值点来找到，而有w,b两个变量即是求各自的偏导。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-22-57-118_tv.danmaku.bil_a7287e669dff16fd79f491018d7dfe50.jpg" alt=""></p><p>以上通过线性函数来拟合x,y之间的关系即为<strong>线性回归</strong></p><h4 id="神经网络的损失函数">神经网络的损失函数</h4><p>线性回归的损失函数一般可以通过求导或求偏导的方式获取其极值点，但是，神经网络通常由<strong>线性函数</strong>和<strong>非线性激活函数</strong>多种复杂组合而成，其<strong>损失函数</strong>也应当是<strong>复杂的非线性函数</strong>，但是解决的办法却没有那么复杂，只需要<strong>一点点猜</strong>即可，通过不断的调整w,b再计算损失函数，观察损失函数的变化，是增加还是减小，能得到当前调整的参数对结果的影响，尽可能将损失函数结果变小。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-33-52-738_tv.danmaku.bil_8b8d23a4faf5f6b4d521911dc98574b9.jpg" alt=""></p><p>w变化的大小使得损失函数变化的大小即为<strong>损失函数对w的偏导</strong>，每次只需要让参数向偏导的反方向变化</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_515022a92386840b0bab1c6fe506dcea.png" alt=""></p><p>如图，函数最低点位于（0，0，2）其变量为x,y，在y=0平面上，不断尝试向<strong>损失函数关于x的偏导</strong>的反方向调整，即可到达最低点。</p><h4 id="学习率">学习率</h4><p>每次反反向调整可以添加一个系数进行控制，以控制损失函数沿偏导反向下降速率，而控制变化快慢的系数即为学习率。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-41-50-775_tv.danmaku.bil_14d00c131acac9122d4f5fac332a70e3.jpg" alt=""></p><p>在模型训练的不同时候对学习率控制尤为重要，常见的有学习率预热（warmup）和学习率衰减（Learning Rate Decay），在此基础上还有许多对学习率控制的优化器，如Adam与AdamW等，优化器对于模型位于不同位置和情况调整学习率以解决对应问题。</p><blockquote><p>可以直观的理解成，如果当前所处的区域比较平坦（梯度的二阶项很小）则我们可以用较大的学习率来更新，快速走出鞍点，如果当前所处的区域比较陡峭（梯度的二阶项很大），则为了防止梯度爆炸等不稳定的情况发生，我们需要用较小的学习率谨慎地更新。</p></blockquote><p><a href="https://zhuanlan.zhihu.com/p/643452086">Adam和AdamW - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/653605711">从梯度下降到AdamW一文读懂机器学习优化算法 - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/1108285598">每天3分钟，彻底弄懂神经网络的优化器（十一）AdamW - 知乎</a></p><p>常用学习率调整策略：<a href="https://zhuanlan.zhihu.com/p/524650878">Pytorch实现11种常用学习率调整策略(自定义学习率衰减) - 知乎</a></p><p><a href="https://zhuanlan.zhihu.com/p/670437303">机器学习-学习率：从理论到实战，探索学习率的调整策略 - 知乎</a></p><p>示例分析：<a href="https://polar-bear.eu.org/2025/04/21/nanodet-xun-lian-ce-shi/#%E5%AD%A6%E4%B9%A0%E7%8E%87">NanoDet训练 | polar-bear～Blog</a></p><h4 id="梯度下降">梯度下降</h4><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-44-57-872_tv.danmaku.bil_deb0592ae1abe103ce7030392db4bc6c.jpg" alt=""></p><p>这些偏导数构成的向量就叫梯度。</p><p>不断变化w,d参数，使损失函数逐渐变小的过程就叫梯度下降。</p><p>最常见的三种梯度下降算法是：</p><ul><li>批量梯度下降（Batch Gradient Descent）</li><li>随机梯度下降（Stochastic Gradient Descent, SGD）</li><li>小批量梯度下降（Mini-batch Gradient Descent）</li></ul><p>在批量梯度下降中，学习率应用于整个数据集，用于计算损失函数的平均梯度。而在随机梯度下降和小批量梯度下降中，学习率应用于单个或一小批样本，用于更新模型参数。</p><p>随机梯度下降和小批量梯度下降由于其高度随机的性质，常常需要一个逐渐衰减的学习率，以帮助模型收敛。</p><p><a href="https://zhuanlan.zhihu.com/p/580645925">梯度下降详解（主观理解+推导证明+例题） - 知乎</a></p><h4 id="反向传播">反向传播</h4><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-13-51-09-956_tv.danmaku.bil_d204afe8a92e6b1c67ba7eeeafc5d9f4.jpg" alt=""></p><p>神经网络中求参数对损失函数偏导可以使用链式法则，即<strong>损失函数</strong>对w1的偏导为“w1变化一个单位使得a变化多少，a变化一个单位使得^y变化多少，^y变化一个单位使得L变化多少，将三者偏导乘在一起，即得到偏导。</p><p>然后从右向左依次求导，然后更新每一层参数，例如计算完^y对w2的偏导（a隐藏层的参数w2，b2），在计算损失函数对w1的偏导时也会用到，即可不用重复计算，而是让值从右向左传播，叫<strong>反向传播</strong>。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-14-07-53-415_tv.danmaku.bil_6a4dbba270c6504012a03a93bd5d4a69.jpg" alt=""></p><p>通过从输入x到输出y的前向传播，然后反向传播计算损失函数对每个参数的梯度，如果每个参数向着梯度反方向变化，构成神经网络一次训练。</p><h4 id="过拟合">过拟合</h4><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-14-14-42-297_tv.danmaku.bil_09c704fd292d164187ec6988f176f18e.jpg" alt=""></p><p>在训练数据上表现良好，对新数据预测<strong>泛化能力</strong>差的现象叫<strong>过拟合</strong></p><p>模型学会了过于复杂的方法，以至于将噪声和随机波动一并考虑。</p><ul><li>使用更多的数据量（数据增强：旋转，翻转，裁剪，噪声）</li><li>提前终止训练</li><li>修改损失函数添加惩罚项抑制参数过分增长（正则化：这种方法）</li><li>Dropout：训练时丢弃部分参数防止对某些参数过度依赖</li></ul><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-15-50-06-203_tv.danmaku.bil_730ae4d902f8250c2cf3101d0d6f94d6.jpg" alt=""></p><p>在损失函数中添加惩罚项，来抑制模型过分复杂，L1和L2，即惩罚项分别为<strong>参数绝对值和</strong>和<strong>参数平方和</strong>，L2在参数大时抑制效果更强。</p><p>控制惩罚力度的参数叫<strong>正则化系数</strong>，控制参数的参数叫<strong>超参数</strong>。</p><p>其他问题</p><ul><li>梯度消失</li><li>梯度爆炸</li><li>收敛速度</li><li>计算开销</li></ul><p>解决</p><ul><li>梯度裁剪</li><li>残差网络Resnet</li><li>Densenet</li><li>权重初始化</li><li>归一法</li><li>动量法</li><li>RMSProp</li><li>Adam</li><li>mini-batch</li></ul><h4 id="矩阵">矩阵</h4><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-16-04-31-475_tv.danmaku.bil_76387cd9893b0bdc70ad924b036a9d78.jpg" alt=""><br><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-16-05-42-019_tv.danmaku.bil_f3e0a89500dc8c7939298e52740947c4.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-16-06-58-550_tv.danmaku.bil_da8a8e3f361506954b8e68cd5fe88061.jpg" alt=""></p><h4 id="卷积">卷积</h4><p>若要使用神经网络识别图片，按照像素平铺展开，例如，一个输入为 224x224x3 的图像，如果连接到一个有 1000 个神经元的全连接层，那么参数数量将非常庞大。则这个全连接层参数将超过百万级别，而且像素之间无法保留空间关系，会导致模型不能很好理解图像的局部模式。</p><p>卷积层通过卷积核在图像上滑动，并共享卷积核的权重。这意味着无论图像尺寸多大，卷积核的参数数量都是固定的。例如，一个 5x5 的卷积核，只有 25 个参数。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-16-15-23-024_tv.danmaku.bil_a11f83fbdedf57add5059a38741e8077.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-19-25-49-562_tv.danmaku.bil_07d49578c215c471f227d832a8ca8705.jpg" alt=""></p><p>在传统的图像处理中，卷积操作使用一个<strong>预先定义好的、固定的</strong>矩阵（称为卷积核、滤波器或掩码）在图像上滑动。这个矩阵中的数值决定了卷积操作的行为。</p><ul><li><strong>模糊:</strong> 使用平均滤波器或高斯滤波器。</li><li><strong>锐化:</strong> 使用拉普拉斯算子或Sobel算子。</li><li><strong>边缘检测:</strong> 使用Sobel算子、Prewitt算子或Canny算子。</li><li><strong>浮雕:</strong> 使用特定的矩阵来模拟光照效果。</li></ul><p>卷积操作实际上是计算卷积核与图像局部区域的加权和。通过改变卷积核中的权重，可以突出或抑制图像中的某些特征，从而达到图像处理的目的。</p><h4 id="卷积神经网络（Convolutional-Neural-Network，CNN）"><strong>卷积神经网络</strong>（Convolutional Neural Network，CNN）</h4><h5 id="卷积层（Convolution-Layer）">卷积层（Convolution Layer）</h5><p>在卷积神经网络中，与传统的图像处理不同，CNN（卷积神经网络）中的卷积核不是预先定义的，而是通过机器学习（通常是反向传播算法）从大量数据中学习得到的。CNN 通过训练，不断调整卷积核中的数值，使其能够更好地识别和提取图像中的特征，从而提高图像识别、分类或其他任务的准确性。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-19-37-59-365_tv.danmaku.bil_caee4b18b0a561e4b820d8e9b7820448.jpg" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-19-39-04-988_tv.danmaku.bil_1387b089c09065c4b17c1740ac3bd615.jpg" alt=""></p><p>卷积层可以替换神经网络中一层全连接层，起到减少权重参数，有效提取局部特征的作用</p><h5 id="池化层（Pooling-Layer）">池化层（Pooling Layer）</h5><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-19-42-41-744_tv.danmaku.bil_00fa34188685b54e7047dcb2769cd3f7.jpg" alt=""></p><p>与卷积层配合使用的一般还有池化层（Pooling Layer），池化层起到的作用是在保留重要特征的同时，降低特征图的空间维度，从而减少计算量和参数数量。</p><h4 id="循环神经网络（Rerrent-Neural-Network-RNN）">循环神经网络（Rerrent Neural Network, RNN）</h4><h5 id="词嵌入（word-embedding）">词嵌入（word embedding）</h5><p><a href="http://ronxin.github.io/wevi/">wevi单词嵌入可视化检查器</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_d8b2193a9d2a915cf3ed59c69498a813.png" alt=""></p><p>词嵌入（Word Embedding）是一种将自然语言中的词语映射到低维向量空间的技术。简单来说，就是把每个词都变成一个向量，这个向量能够捕捉到词语的语义信息，使得语义相似的词在向量空间中距离更近。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-19-59-17-939_tv.danmaku.bil_9783a1715b183f66c708d6bfa930d014.jpg" alt=""></p><p>通过计算两个词向量的点积或者余弦相似度，可以表示向量之间的相关性。</p><p>词向量嵌入矩阵潜空间降维投影到坐标系，可视化不同词语之间的距离</p><p><a href="http://projector.tensorflow.org/">Embedding projector - visualization of high-dimensional data</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_35db055d2ec2fe6884e34f1378fa2ada.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_951f9438ce4773f8bc90e0046496502b.png" alt=""></p><p>为了将上一词的词义与后文产生联系，可以将第一词的隐藏状态和第二词一起参数运算，依次传递，就可使得后文具有前词的信息。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-20-14-40-447_tv.danmaku.bil_e93a9493268321d13a9dd2a01ae1557d.jpg" alt=""></p><p>既是RNN循环神经网络，是一种专门用于处理序列数据的神经网络。与传统的前馈神经网络不同，RNN 具有循环连接，使得它可以将之前的状态信息传递到当前状态，从而能够处理具有时序关系的序列数据。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-20-18-30-375_tv.danmaku.bil_3e2f84b02a21554f3b6b7a0813789071.jpg" alt=""></p><p>详细流程如下：</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/Screenshot_2025-04-27-20-51-55-162_tv.danmaku.bil_4186e3737b05b1feb5df102f6a82ed02.jpg" alt=""></p><p>和经典神经网络相比，仅仅是多了一个前一时刻的隐藏状态。</p><h4 id="Transformer">Transformer</h4><p>Transformer 是一种基于自注意力机制（Self-Attention Mechanism）的神经网络架构，最初由 Google 在 2017 年的论文 “Attention is All You Need” 中提出。它彻底改变了自然语言处理（NLP）领域，并在机器翻译、文本生成、问答系统等任务中取得了显著的成果。</p>]]></content>
    
    
    <summary type="html">机器学习——神经网络
概念合集

机器学习（1）——绪论 - 知乎 [https://zhuanlan.zhihu.com/p/100938949]

机器学习（2）——线性回归（Linear Regression） - 知乎 [https://zhuanlan.zhihu.com/p/101000750]

机器学习（3）——Logistic回归（Logis [https://zhuanlan.zhihu.com/p/101111312]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>NanoDet训练及部署</title>
    <link href="https://polar-bear.eu.org/2025/04/21/nanodet-xun-lian-ce-shi/"/>
    <id>https://polar-bear.eu.org/2025/04/21/nanodet-xun-lian-ce-shi/</id>
    <published>2025-04-21T02:34:54.364Z</published>
    <updated>2026-02-28T04:42:57.197Z</updated>
    
    <content type="html"><![CDATA[<h2 id="NanoDet训练">NanoDet训练</h2><p>github：<a href="https://github.com/RangiLyu/nanodet">RangiLyu/nanodet: NanoDet-Plus⚡Super fast and lightweight anchor-free object detection model. 🔥Only 980 KB(int8) / 1.8MB (fp16) and run 97FPS on cellphone🔥</a></p><p>CPU：<a href="https://github.com/guo-pu/NanoDet-PyTorch-CPU">guo-pu/NanoDet-PyTorch-CPU: 此代码用于目标检测，模型小，检测速度快速，适合没GPU显卡的嵌入式设备运行，比如“树莓派”、ARM开发板、嵌入式开发板。</a></p><p><a href="https://github.com/hpc203/nanodet-plus-opencv">hpc203/nanodet-plus-opencv: 分别使用OpenCV、ONNXRuntime部署NanoDet-Plus，包含C++和Python两个版本的程序</a></p><p><a href="https://blog.csdn.net/qq_40280673/article/details/126097822">目标检测——使用nanodet训练自己制作的数据集并测试模型，通俗易懂（详细图文教程）_nanodet训练自己的模型-CSDN博客</a></p><p><a href="https://blog.csdn.net/matken/article/details/116212274">第一模块：深度学习轻量级模型nanodet-CSDN博客</a></p><p><a href="https://blog.csdn.net/qq_20144897/article/details/132071736">轻量级目标检测模型NanoDet-Plus微调、部署（保姆级教学）-CSDN博客</a></p><p>数据集：</p><p><a href="https://blog.csdn.net/qq_40280673/article/details/125158582?spm=1001.2014.3001.5501">使用Labelimg制作VOC格式数据集或yolo格式数据集（详细图文教程）_yolov5训练集-CSDN博客</a></p><h3 id="conda">conda</h3><p>安装<a href="https://blog.csdn.net/qq_44000789/article/details/142214660">最新版最详细Anaconda新手安装+配置+环境创建教程_anaconda配置-CSDN博客</a></p><p>添加环境变量</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">..\anaconda3</span><br><span class="line">..\anaconda3\Scripts</span><br><span class="line">..\anaconda3\Library\bin</span><br><span class="line">..\anaconda3\Library\mingw-w64\bin</span><br></pre></td></tr></table></figure><p>查看安装情况</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda --version</span><br></pre></td></tr></table></figure><p>创建/删除 环境<br>命令创建python版本为X.X、名字为 env_name 的虚拟环境。env_name文件可以在Anaconda安装目录 envs文件下找到。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda create -n env_name python=3.8</span><br></pre></td></tr></table></figure><p>在conda环境下，输入以下命令查看当前存在的环境：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda env list</span><br></pre></td></tr></table></figure><p>删除环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">conda remove -n env_name --all</span><br><span class="line">conda env remove -n env_name</span><br></pre></td></tr></table></figure><p>重命名环境（将 --clone 后面的环境重命名成 -n 后面的名字）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda create -n torch --clone py3  # 将 py3 重命名为 torch</span><br></pre></td></tr></table></figure><p>创建完成环境之后，系统会提示如何 进入和退出环境，如下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">conda activate env_name  # 进入环境</span><br><span class="line">conda deactivate# 退出环境</span><br></pre></td></tr></table></figure><h3 id="pytorch">pytorch</h3><p>查看CUDA版本<code>nvidia-smi</code>  <code>nvcc -V</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_0e05798a1db1a1845db45c9b9cf289ac.png" alt=""></p><p><a href="https://pytorch.org/get-started/previous-versions/">Previous PyTorch Versions | PyTorch</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_2e2c39973a8d9595cdef7da1ad960c9d.png" alt=""></p><p>NanoDet项目需要使用不高于2.00版本的Pytorch,而Pytorch低版本安装需要降低CUDA版本，需要重新安装CUDA 11.7</p><p>CUDA旧版存档：<a href="https://developer.nvidia.com/cuda-toolkit-archive">CUDA Toolkit Archive | NVIDIA Developer</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_23/image_8ce31c74ae67ded441bad2d05b0b6071.png" alt=""></p><p>在下载安装过程中，将<code>https://developer.download.nvidia.com</code>改为<code>https://developer.download.nvidia.cn</code>可以解决下载速度过慢的问题。</p><p>最后安装<code>sudo apt-get -y install cuda</code>的过程中，也可以在<code>/etc/apt/sources.list.d</code>修改</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nano archive_uri-https_developer_download_nvidia_com_compute_cuda_repos_ubuntu2204_x86_64_-jammy.list</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_23/image_b74e1d6156a10e29edd2af47ba8a6bfd.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_23/image_674c33632bbea8efc1ca2fe6a515260b.png" alt=""></p><p><a href="https://zhuanlan.zhihu.com/p/689645505">成功解决：AssertionError: Torch not compiled with CUDA enabled - 知乎</a></p><p>创建conda环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda create -n env_name python=3.8</span><br></pre></td></tr></table></figure><p>查看环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda env list</span><br></pre></td></tr></table></figure><p>进入环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda activate PyTorch</span><br></pre></td></tr></table></figure><p>安装pytorch</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.7 -c pytorch -c nvidia</span><br></pre></td></tr></table></figure><p>测试torch环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import torch</span><br><span class="line">print(torch.cuda.is_available())</span><br><span class="line">print(torch.cuda.device_count())</span><br><span class="line">print(torch.cuda.get_device_name(0))</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_7fcddf1e8cf1fb014c7aad22a982b215.png" alt=""></p><h3 id="NanoDet">NanoDet</h3><p>此处使用<a href="https://blog.csdn.net/qq_40280673/article/details/126097822">目标检测——使用nanodet训练自己制作的数据集并测试模型，通俗易懂（详细图文教程）_nanodet训练自己的模型-CSDN博客</a></p><p>整合文件链接：<a href="https://pan.baidu.com/s/1H_qB7OZKJodtbEImKN_TeQ">https://pan.baidu.com/s/1H_qB7OZKJodtbEImKN_TeQ</a> 提取码：dcj7</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_f986db621ae6ad52f12110db503a852a.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_21/image_0c30330781f307aec3ea2ae42aa58e1c.png" alt=""></p><p>NanoDet项目较早需要使用不高于2.00版本的Pytorch，高版本Pytorch去除了部分NanoDet所用方法</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.7 -c pytorch -c nvidia</span><br></pre></td></tr></table></figure><p>注意pytorch与torchvision版本对应</p><p><a href="https://github.com/pytorch/vision#installation">pytorch/vision：特定于计算机视觉的数据集、转换和模型</a></p><p>截至现在25/04/22，由于requirements.txt中未对依赖库做版本限制，会导致安装最新稳定版本，导致NanoDet缺少方法，建议以下库指定版本安装</p><p>pytorch-lightning  = 1.1.8</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_a73a48a85f27082f666bfe038500321f.png" alt="现使用版本"></p><p>（图中版本还是过高，在后期train中无法正常允许，需使用1.1.8版本）</p><p>修改requirements.txt</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Cython</span><br><span class="line">matplotlib</span><br><span class="line">numpy</span><br><span class="line">omegaconf&gt;=2.0.1</span><br><span class="line">onnx</span><br><span class="line">onnx-simplifier</span><br><span class="line">opencv-python</span><br><span class="line">pyaml</span><br><span class="line">pycocotools</span><br><span class="line">pytorch-lightning==1.1.8</span><br><span class="line">tabulate</span><br><span class="line">tensorboard</span><br><span class="line">termcolor</span><br><span class="line">tqdm</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>安装</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install -r requirements.txt</span><br></pre></td></tr></table></figure><p>在项目根目录安装nanodet</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python setup.py develop</span><br></pre></td></tr></table></figure><p>下载模型，测试NanoDet</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python demo/demo.py video --config ./config/nanodet-plus-m-1.5x_320.yml --model ./model/nanodet-plus-m-1.5x_320.pth --path ./Video/dai.avi </span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_045cb710e810fb1da721bf3432cf9520.png" alt=""></p><p>到此环境完成配置</p><h3 id="自训练模型">自训练模型</h3><h4 id="数据集准备">数据集准备</h4><p>数据标注工具</p><p>labelme：</p><p><a href="https://github.com/wkentaro/labelme/releases?page=1">Releases · wkentaro/labelme</a></p><p><a href="https://zhuanlan.zhihu.com/p/371756150">深度学习图像标签标注软件labelme超详细教程 - 知乎</a></p><p>labelimg：</p><p><a href="https://blog.csdn.net/qq_40280673/article/details/125158582?spm=1001.2014.3001.5501">使用Labelimg制作VOC格式数据集或yolo格式数据集（详细图文教程）_yolov5训练集-CSDN博客</a></p><p><a href="https://zhuanlan.zhihu.com/p/550021453">【教程】标注工具Labelimg的安装与使用 - 知乎</a></p><p><a href="https://blog.csdn.net/StopAndGoyyy/article/details/139906637">深度学习工具|LabelImg（标注工具）的安装与使用教程_labelimg软件-CSDN博客</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_c31b4e35dad48e06b66c68ede121fb5b.png" alt=""></p><p>先用labelimg或者labelme标注出数据集，数据量过少可以用数据增强生成增加数据量，按照脚本可得到数据增强后的images和xml，分别为图片和目标位置信息。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_01119ce0a795e2066bf8d343c5c425dc.png" alt=""></p><p>xml文件记录了图片名称和标注目标名称及在图片中的位置。</p><p>可以使用下面代码转化labelme到labelimg的xml格式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># jsonTOxml.py</span></span><br><span class="line"><span class="comment"># 用于将labelme标注的json文件转换为labelimg的VOC格式的xml文件</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> xml.etree.ElementTree <span class="keyword">as</span> ET</span><br><span class="line"><span class="keyword">from</span> xml.dom <span class="keyword">import</span> minidom</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">json_to_xml</span>(<span class="params">json_path, xml_dir</span>):</span><br><span class="line">    <span class="comment"># 读取json文件</span></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(json_path, <span class="string">&#x27;r&#x27;</span>, encoding=<span class="string">&#x27;utf-8&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        data = json.load(f)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 创建XML结构</span></span><br><span class="line">    annotation = ET.Element(<span class="string">&#x27;annotation&#x27;</span>)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加文件夹信息</span></span><br><span class="line">    folder = ET.SubElement(annotation, <span class="string">&#x27;folder&#x27;</span>)</span><br><span class="line">    folder.text = <span class="string">&#x27;images&#x27;</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加文件名</span></span><br><span class="line">    filename = ET.SubElement(annotation, <span class="string">&#x27;filename&#x27;</span>)</span><br><span class="line">    filename.text = data[<span class="string">&#x27;imagePath&#x27;</span>]</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加路径</span></span><br><span class="line">    path = ET.SubElement(annotation, <span class="string">&#x27;path&#x27;</span>)</span><br><span class="line">    path.text = os.path.abspath(os.path.join(xml_dir, data[<span class="string">&#x27;imagePath&#x27;</span>]))</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加来源信息</span></span><br><span class="line">    source = ET.SubElement(annotation, <span class="string">&#x27;source&#x27;</span>)</span><br><span class="line">    database = ET.SubElement(source, <span class="string">&#x27;database&#x27;</span>)</span><br><span class="line">    database.text = <span class="string">&#x27;Unknown&#x27;</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加图片尺寸</span></span><br><span class="line">    size = ET.SubElement(annotation, <span class="string">&#x27;size&#x27;</span>)</span><br><span class="line">    width = ET.SubElement(size, <span class="string">&#x27;width&#x27;</span>)</span><br><span class="line">    width.text = <span class="built_in">str</span>(data[<span class="string">&#x27;imageWidth&#x27;</span>])</span><br><span class="line">    height = ET.SubElement(size, <span class="string">&#x27;height&#x27;</span>)</span><br><span class="line">    height.text = <span class="built_in">str</span>(data[<span class="string">&#x27;imageHeight&#x27;</span>])</span><br><span class="line">    depth = ET.SubElement(size, <span class="string">&#x27;depth&#x27;</span>)</span><br><span class="line">    depth.text = <span class="string">&#x27;3&#x27;</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 添加分割信息</span></span><br><span class="line">    segmented = ET.SubElement(annotation, <span class="string">&#x27;segmented&#x27;</span>)</span><br><span class="line">    segmented.text = <span class="string">&#x27;0&#x27;</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 处理每个标注形状</span></span><br><span class="line">    <span class="keyword">for</span> shape <span class="keyword">in</span> data[<span class="string">&#x27;shapes&#x27;</span>]:</span><br><span class="line">        obj = ET.SubElement(annotation, <span class="string">&#x27;object&#x27;</span>)</span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 添加对象名称</span></span><br><span class="line">        name = ET.SubElement(obj, <span class="string">&#x27;name&#x27;</span>)</span><br><span class="line">        name.text = shape[<span class="string">&#x27;label&#x27;</span>]</span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 添加姿态信息</span></span><br><span class="line">        pose = ET.SubElement(obj, <span class="string">&#x27;pose&#x27;</span>)</span><br><span class="line">        pose.text = <span class="string">&#x27;Unspecified&#x27;</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 添加截断信息</span></span><br><span class="line">        truncated = ET.SubElement(obj, <span class="string">&#x27;truncated&#x27;</span>)</span><br><span class="line">        truncated.text = <span class="string">&#x27;0&#x27;</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 添加难度信息</span></span><br><span class="line">        difficult = ET.SubElement(obj, <span class="string">&#x27;difficult&#x27;</span>)</span><br><span class="line">        difficult.text = <span class="string">&#x27;0&#x27;</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 添加边界框</span></span><br><span class="line">        bndbox = ET.SubElement(obj, <span class="string">&#x27;bndbox&#x27;</span>)</span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 计算边界框坐标</span></span><br><span class="line">        points = shape[<span class="string">&#x27;points&#x27;</span>]</span><br><span class="line">        xmin = ET.SubElement(bndbox, <span class="string">&#x27;xmin&#x27;</span>)</span><br><span class="line">        xmin.text = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="built_in">min</span>(p[<span class="number">0</span>] <span class="keyword">for</span> p <span class="keyword">in</span> points)))</span><br><span class="line">        ymin = ET.SubElement(bndbox, <span class="string">&#x27;ymin&#x27;</span>)</span><br><span class="line">        ymin.text = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="built_in">min</span>(p[<span class="number">1</span>] <span class="keyword">for</span> p <span class="keyword">in</span> points)))</span><br><span class="line">        xmax = ET.SubElement(bndbox, <span class="string">&#x27;xmax&#x27;</span>)</span><br><span class="line">        xmax.text = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="built_in">max</span>(p[<span class="number">0</span>] <span class="keyword">for</span> p <span class="keyword">in</span> points)))</span><br><span class="line">        ymax = ET.SubElement(bndbox, <span class="string">&#x27;ymax&#x27;</span>)</span><br><span class="line">        ymax.text = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="built_in">max</span>(p[<span class="number">1</span>] <span class="keyword">for</span> p <span class="keyword">in</span> points)))</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 创建ElementTree对象</span></span><br><span class="line">    tree = ET.ElementTree(annotation)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 写入XML文件（不包含XML声明）</span></span><br><span class="line">    xml_filename = os.path.splitext(data[<span class="string">&#x27;imagePath&#x27;</span>])[<span class="number">0</span>] + <span class="string">&#x27;.xml&#x27;</span></span><br><span class="line">    xml_path = os.path.join(xml_dir, xml_filename)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 设置缩进并写入文件</span></span><br><span class="line">    ET.indent(tree, space=<span class="string">&quot;  &quot;</span>)</span><br><span class="line">    tree.write(xml_path, encoding=<span class="string">&#x27;utf-8&#x27;</span>, xml_declaration=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">convert_all_json</span>(<span class="params">json_dir, xml_dir</span>):</span><br><span class="line">    <span class="comment"># 确保输出目录存在</span></span><br><span class="line">    os.makedirs(xml_dir, exist_ok=<span class="literal">True</span>)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 遍历json目录下所有.json文件</span></span><br><span class="line">    <span class="keyword">for</span> filename <span class="keyword">in</span> os.listdir(json_dir):</span><br><span class="line">        <span class="keyword">if</span> filename.endswith(<span class="string">&#x27;.json&#x27;</span>):</span><br><span class="line">            json_path = os.path.join(json_dir, filename)</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                json_to_xml(json_path, xml_dir)</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">f&#x27;Converted <span class="subst">&#123;filename&#125;</span> successfully&#x27;</span>)</span><br><span class="line">            <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">f&#x27;Failed to convert <span class="subst">&#123;filename&#125;</span>: <span class="subst">&#123;<span class="built_in">str</span>(e)&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    <span class="comment"># 设置输入输出目录</span></span><br><span class="line">    input_dir = <span class="string">&#x27;json&#x27;</span></span><br><span class="line">    output_dir = <span class="string">&#x27;xml&#x27;</span></span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 执行转换</span></span><br><span class="line">    convert_all_json(input_dir, output_dir)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>以下是具体流程。</p><p>数据增强，旋转，翻转，裁剪，噪声，提高模型泛化能力，防止过拟合，添加训练数据量</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># zengqiang.py</span></span><br><span class="line"><span class="comment"># 数据增强</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> xml.etree.ElementTree <span class="keyword">as</span> ET</span><br><span class="line"><span class="keyword">import</span> pickle</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">from</span> os <span class="keyword">import</span> getcwd</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">import</span> shutil</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> imgaug <span class="keyword">as</span> ia</span><br><span class="line"><span class="keyword">from</span> imgaug <span class="keyword">import</span> augmenters <span class="keyword">as</span> iaa</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ia.seed(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">read_xml_annotation</span>(<span class="params">root, image_id</span>):</span><br><span class="line">    in_file = <span class="built_in">open</span>(os.path.join(root, image_id))</span><br><span class="line">    tree = ET.parse(in_file)</span><br><span class="line">    root = tree.getroot()</span><br><span class="line">    bndboxlist = []</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> <span class="built_in">object</span> <span class="keyword">in</span> root.findall(<span class="string">&#x27;object&#x27;</span>):  <span class="comment"># 找到root节点下的所有country节点</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">object</span> <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:  <span class="comment"># 添加这个检查</span></span><br><span class="line">            bndbox = <span class="built_in">object</span>.find(<span class="string">&#x27;bndbox&#x27;</span>)  <span class="comment"># 子节点下节点rank的值</span></span><br><span class="line"></span><br><span class="line">            xmin = <span class="built_in">int</span>(bndbox.find(<span class="string">&#x27;xmin&#x27;</span>).text)</span><br><span class="line">            xmax = <span class="built_in">int</span>(bndbox.find(<span class="string">&#x27;xmax&#x27;</span>).text)</span><br><span class="line">            ymin = <span class="built_in">int</span>(bndbox.find(<span class="string">&#x27;ymin&#x27;</span>).text)</span><br><span class="line">            ymax = <span class="built_in">int</span>(bndbox.find(<span class="string">&#x27;ymax&#x27;</span>).text)</span><br><span class="line">            <span class="comment"># print(xmin,ymin,xmax,ymax)</span></span><br><span class="line">            bndboxlist.append([xmin, ymin, xmax, ymax])</span><br><span class="line">            <span class="comment"># print(bndboxlist)</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> bndboxlist:</span><br><span class="line">        <span class="keyword">return</span> []</span><br><span class="line"></span><br><span class="line">    bndbox = root.find(<span class="string">&#x27;object&#x27;</span>).find(<span class="string">&#x27;bndbox&#x27;</span>)</span><br><span class="line">    <span class="keyword">return</span> bndboxlist</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># (506.0000, 330.0000, 528.0000, 348.0000) -&gt; (520.4747, 381.5080, 540.5596, 398.6603)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">change_xml_annotation</span>(<span class="params">root, image_id, new_target</span>):</span><br><span class="line">    new_xmin = new_target[<span class="number">0</span>]</span><br><span class="line">    new_ymin = new_target[<span class="number">1</span>]</span><br><span class="line">    new_xmax = new_target[<span class="number">2</span>]</span><br><span class="line">    new_ymax = new_target[<span class="number">3</span>]</span><br><span class="line"></span><br><span class="line">    in_file = <span class="built_in">open</span>(os.path.join(root, <span class="built_in">str</span>(image_id) + <span class="string">&#x27;.xml&#x27;</span>))  <span class="comment"># 这里root分别由两个意思</span></span><br><span class="line">    tree = ET.parse(in_file)</span><br><span class="line">    xmlroot = tree.getroot()</span><br><span class="line">    <span class="built_in">object</span> = xmlroot.find(<span class="string">&#x27;object&#x27;</span>)</span><br><span class="line">    bndbox = <span class="built_in">object</span>.find(<span class="string">&#x27;bndbox&#x27;</span>)</span><br><span class="line">    xmin = bndbox.find(<span class="string">&#x27;xmin&#x27;</span>)</span><br><span class="line">    xmin.text = <span class="built_in">str</span>(new_xmin)</span><br><span class="line">    ymin = bndbox.find(<span class="string">&#x27;ymin&#x27;</span>)</span><br><span class="line">    ymin.text = <span class="built_in">str</span>(new_ymin)</span><br><span class="line">    xmax = bndbox.find(<span class="string">&#x27;xmax&#x27;</span>)</span><br><span class="line">    xmax.text = <span class="built_in">str</span>(new_xmax)</span><br><span class="line">    ymax = bndbox.find(<span class="string">&#x27;ymax&#x27;</span>)</span><br><span class="line">    ymax.text = <span class="built_in">str</span>(new_ymax)</span><br><span class="line">    tree.write(os.path.join(root, <span class="built_in">str</span>(<span class="string">&quot;%06d&quot;</span> % (<span class="built_in">str</span>(<span class="built_in">id</span>) + <span class="string">&#x27;.xml&#x27;</span>))))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">change_xml_list_annotation</span>(<span class="params">root, image_id, new_target, saveroot, <span class="built_in">id</span>,img_name</span>):</span><br><span class="line">    in_file = <span class="built_in">open</span>(os.path.join(root, <span class="built_in">str</span>(image_id) + <span class="string">&#x27;.xml&#x27;</span>))  <span class="comment"># 这里root分别由两个意思</span></span><br><span class="line">    tree = ET.parse(in_file)</span><br><span class="line">    elem = tree.find(<span class="string">&#x27;filename&#x27;</span>)</span><br><span class="line">    elem.text = (img_name + <span class="built_in">str</span>(<span class="string">&quot;_%06d&quot;</span> % <span class="built_in">int</span>(<span class="built_in">id</span>)) + <span class="string">&#x27;.jpg&#x27;</span>)</span><br><span class="line">    xmlroot = tree.getroot()</span><br><span class="line">    index = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> <span class="built_in">object</span> <span class="keyword">in</span> xmlroot.findall(<span class="string">&#x27;object&#x27;</span>):  <span class="comment"># 找到root节点下的所有country节点</span></span><br><span class="line">        bndbox = <span class="built_in">object</span>.find(<span class="string">&#x27;bndbox&#x27;</span>)  <span class="comment"># 子节点下节点rank的值</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># xmin = int(bndbox.find(&#x27;xmin&#x27;).text)</span></span><br><span class="line">        <span class="comment"># xmax = int(bndbox.find(&#x27;xmax&#x27;).text)</span></span><br><span class="line">        <span class="comment"># ymin = int(bndbox.find(&#x27;ymin&#x27;).text)</span></span><br><span class="line">        <span class="comment"># ymax = int(bndbox.find(&#x27;ymax&#x27;).text)</span></span><br><span class="line"></span><br><span class="line">        new_xmin = new_target[index][<span class="number">0</span>]</span><br><span class="line">        new_ymin = new_target[index][<span class="number">1</span>]</span><br><span class="line">        new_xmax = new_target[index][<span class="number">2</span>]</span><br><span class="line">        new_ymax = new_target[index][<span class="number">3</span>]</span><br><span class="line"></span><br><span class="line">        xmin = bndbox.find(<span class="string">&#x27;xmin&#x27;</span>)</span><br><span class="line">        xmin.text = <span class="built_in">str</span>(new_xmin)</span><br><span class="line">        ymin = bndbox.find(<span class="string">&#x27;ymin&#x27;</span>)</span><br><span class="line">        ymin.text = <span class="built_in">str</span>(new_ymin)</span><br><span class="line">        xmax = bndbox.find(<span class="string">&#x27;xmax&#x27;</span>)</span><br><span class="line">        xmax.text = <span class="built_in">str</span>(new_xmax)</span><br><span class="line">        ymax = bndbox.find(<span class="string">&#x27;ymax&#x27;</span>)</span><br><span class="line">        ymax.text = <span class="built_in">str</span>(new_ymax)</span><br><span class="line"></span><br><span class="line">        index = index + <span class="number">1</span></span><br><span class="line"></span><br><span class="line">    tree.write(os.path.join(saveroot, img_name + <span class="built_in">str</span>(<span class="string">&quot;_%06d&quot;</span> % <span class="built_in">int</span>(<span class="built_in">id</span>)) + <span class="string">&#x27;.xml&#x27;</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">mkdir</span>(<span class="params">path</span>):</span><br><span class="line">    <span class="comment"># 去除首位空格</span></span><br><span class="line">    path = path.strip()</span><br><span class="line">    <span class="comment"># 去除尾部 \ 符号</span></span><br><span class="line">    path = path.rstrip(<span class="string">&quot;\\&quot;</span>)</span><br><span class="line">    <span class="comment"># 判断路径是否存在</span></span><br><span class="line">    <span class="comment"># 存在     True</span></span><br><span class="line">    <span class="comment"># 不存在   False</span></span><br><span class="line">    isExists = os.path.exists(path)</span><br><span class="line">    <span class="comment"># 判断结果</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> isExists:</span><br><span class="line">        <span class="comment"># 如果不存在则创建目录</span></span><br><span class="line">        <span class="comment"># 创建目录操作函数</span></span><br><span class="line">        os.makedirs(path)</span><br><span class="line">        <span class="built_in">print</span>(path + <span class="string">&#x27; 创建成功&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="comment"># 如果目录存在则不创建，并提示目录已存在</span></span><br><span class="line">        <span class="built_in">print</span>(path + <span class="string">&#x27; 目录已存在&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line"></span><br><span class="line">    IMG_DIR = <span class="string">&quot;./images&quot;</span>             <span class="comment">### 原始数据集图像的路径</span></span><br><span class="line">    XML_DIR = <span class="string">&quot;./Annotations&quot;</span>              <span class="comment">### 原始xml文件的路径</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># =============================================================================</span></span><br><span class="line"><span class="comment">#     AUG_XML_DIR = &quot;./Annotations&quot;  # 存储增强后的XML文件夹路径</span></span><br><span class="line"><span class="comment"># =============================================================================</span></span><br><span class="line">    AUG_XML_DIR = <span class="string">&quot;./val Enhance/xml&quot;</span>              <span class="comment">### 数据增强后的xml文件的保存路径</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        shutil.rmtree(AUG_XML_DIR)</span><br><span class="line">    <span class="keyword">except</span> FileNotFoundError <span class="keyword">as</span> e:</span><br><span class="line">        a = <span class="number">1</span></span><br><span class="line">    mkdir(AUG_XML_DIR)</span><br><span class="line"></span><br><span class="line"><span class="comment"># =============================================================================</span></span><br><span class="line"><span class="comment">#     AUG_IMG_DIR = &quot;./JPEGImages&quot;  # 存储增强后的影像文件夹路径</span></span><br><span class="line"><span class="comment"># =============================================================================</span></span><br><span class="line">    AUG_IMG_DIR = <span class="string">&quot;./val Enhance/images&quot;</span>  <span class="comment">### 数据增强后图片的保存路径</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        shutil.rmtree(AUG_IMG_DIR)</span><br><span class="line">    <span class="keyword">except</span> FileNotFoundError <span class="keyword">as</span> e:</span><br><span class="line">        a = <span class="number">1</span></span><br><span class="line">    mkdir(AUG_IMG_DIR)</span><br><span class="line"></span><br><span class="line">    AUGLOOP = <span class="number">5</span>  <span class="comment"># 每张影像增强的数量</span></span><br><span class="line"></span><br><span class="line">    boxes_img_aug_list = []</span><br><span class="line">    new_bndbox = []</span><br><span class="line">    new_bndbox_list = []</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line">    <span class="comment"># 影像增强序列配置</span></span><br><span class="line">    seq = iaa.Sequential([</span><br><span class="line">        <span class="comment"># 几何变换增强</span></span><br><span class="line">        iaa.Flipud(<span class="number">0.5</span>),  <span class="comment"># 垂直翻转，50%概率</span></span><br><span class="line">        iaa.Fliplr(<span class="number">0.5</span>),  <span class="comment"># 水平镜像翻转，50%概率</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 颜色空间变换增强</span></span><br><span class="line">        iaa.Multiply((<span class="number">1.2</span>, <span class="number">1.5</span>)),  <span class="comment"># 亮度调整，1.2-1.5倍随机</span></span><br><span class="line">        iaa.AddToHueAndSaturation((-<span class="number">20</span>, <span class="number">20</span>)),  <span class="comment"># 色相和饱和度调整，±20随机值</span></span><br><span class="line">        iaa.LinearContrast((<span class="number">0.8</span>, <span class="number">1.2</span>)),  <span class="comment"># 对比度调整，0.8-1.2倍随机</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 噪声和模糊增强</span></span><br><span class="line">        iaa.GaussianBlur(sigma=(<span class="number">0</span>, <span class="number">3.0</span>)),  <span class="comment"># 高斯模糊，sigma值0-3随机</span></span><br><span class="line">        iaa.AdditiveGaussianNoise(scale=(<span class="number">0</span>, <span class="number">0.05</span>*<span class="number">255</span>)),  <span class="comment"># 高斯噪声，强度0-5%随机</span></span><br><span class="line">  </span><br><span class="line">        <span class="comment"># 仿射变换增强</span></span><br><span class="line">        iaa.Affine(</span><br><span class="line">            translate_px=&#123;<span class="string">&quot;x&quot;</span>: <span class="number">15</span>, <span class="string">&quot;y&quot;</span>: <span class="number">15</span>&#125;,  <span class="comment"># 平移变换，x/y方向各15像素</span></span><br><span class="line">            scale=(<span class="number">0.8</span>, <span class="number">0.95</span>),  <span class="comment"># 缩放变换，0.8-0.95倍随机</span></span><br><span class="line">            rotate=(-<span class="number">30</span>, <span class="number">30</span>)  <span class="comment"># 旋转变换，-30到30度随机</span></span><br><span class="line">        )</span><br><span class="line">    ])</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> root, sub_folders, files <span class="keyword">in</span> os.walk(XML_DIR):</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> name <span class="keyword">in</span> files:</span><br><span class="line">            <span class="built_in">print</span>(name)</span><br><span class="line">            bndbox = read_xml_annotation(XML_DIR, name)</span><br><span class="line">            shutil.copy(os.path.join(XML_DIR, name), AUG_XML_DIR)</span><br><span class="line">            shutil.copy(os.path.join(IMG_DIR, name[:-<span class="number">4</span>] + <span class="string">&#x27;.jpg&#x27;</span>), AUG_IMG_DIR)</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(AUGLOOP):</span><br><span class="line">                seq_det = seq.to_deterministic()  <span class="comment"># 保持坐标和图像同步改变，而不是随机</span></span><br><span class="line">                <span class="comment"># 读取图片</span></span><br><span class="line">                img = Image.<span class="built_in">open</span>(os.path.join(IMG_DIR, name[:-<span class="number">4</span>] + <span class="string">&#x27;.jpg&#x27;</span>))</span><br><span class="line">                <span class="comment"># sp = img.size</span></span><br><span class="line">                img = np.asarray(img)</span><br><span class="line">                <span class="comment"># bndbox 坐标增强</span></span><br><span class="line">                <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(bndbox)):</span><br><span class="line">                    bbs = ia.BoundingBoxesOnImage([</span><br><span class="line">                        ia.BoundingBox(x1=bndbox[i][<span class="number">0</span>], y1=bndbox[i][<span class="number">1</span>], x2=bndbox[i][<span class="number">2</span>], y2=bndbox[i][<span class="number">3</span>]),</span><br><span class="line">                    ], shape=img.shape)</span><br><span class="line"></span><br><span class="line">                    bbs_aug = seq_det.augment_bounding_boxes([bbs])[<span class="number">0</span>]</span><br><span class="line">                    boxes_img_aug_list.append(bbs_aug)</span><br><span class="line"></span><br><span class="line">                    <span class="comment"># new_bndbox_list:[[x1,y1,x2,y2],...[],[]]</span></span><br><span class="line">                    n_x1 = <span class="built_in">int</span>(<span class="built_in">max</span>(<span class="number">1</span>, <span class="built_in">min</span>(img.shape[<span class="number">1</span>], bbs_aug.bounding_boxes[<span class="number">0</span>].x1)))</span><br><span class="line">                    n_y1 = <span class="built_in">int</span>(<span class="built_in">max</span>(<span class="number">1</span>, <span class="built_in">min</span>(img.shape[<span class="number">0</span>], bbs_aug.bounding_boxes[<span class="number">0</span>].y1)))</span><br><span class="line">                    n_x2 = <span class="built_in">int</span>(<span class="built_in">max</span>(<span class="number">1</span>, <span class="built_in">min</span>(img.shape[<span class="number">1</span>], bbs_aug.bounding_boxes[<span class="number">0</span>].x2)))</span><br><span class="line">                    n_y2 = <span class="built_in">int</span>(<span class="built_in">max</span>(<span class="number">1</span>, <span class="built_in">min</span>(img.shape[<span class="number">0</span>], bbs_aug.bounding_boxes[<span class="number">0</span>].y2)))</span><br><span class="line">                    <span class="keyword">if</span> n_x1 == <span class="number">1</span> <span class="keyword">and</span> n_x1 == n_x2:</span><br><span class="line">                        n_x2 += <span class="number">1</span></span><br><span class="line">                    <span class="keyword">if</span> n_y1 == <span class="number">1</span> <span class="keyword">and</span> n_y2 == n_y1:</span><br><span class="line">                        n_y2 += <span class="number">1</span></span><br><span class="line">                    <span class="keyword">if</span> n_x1 &gt;= n_x2 <span class="keyword">or</span> n_y1 &gt;= n_y2:</span><br><span class="line">                        <span class="built_in">print</span>(<span class="string">&#x27;error&#x27;</span>, name)</span><br><span class="line">                    new_bndbox_list.append([n_x1, n_y1, n_x2, n_y2])</span><br><span class="line">                <span class="comment"># 存储变化后的图片</span></span><br><span class="line">                image_aug = seq_det.augment_images([img])[<span class="number">0</span>]</span><br><span class="line">                path = os.path.join(AUG_IMG_DIR,</span><br><span class="line">                                    name[:-<span class="number">4</span>] + <span class="built_in">str</span>( <span class="string">&quot;_%06d&quot;</span> % (epoch + <span class="number">1</span>)) + <span class="string">&#x27;.jpg&#x27;</span>)</span><br><span class="line">                image_auged = bbs.draw_on_image(image_aug, thickness=<span class="number">0</span>)</span><br><span class="line">                Image.fromarray(image_auged).save(path)</span><br><span class="line"></span><br><span class="line">                <span class="comment"># 存储变化后的XML</span></span><br><span class="line">                change_xml_list_annotation(XML_DIR, name[:-<span class="number">4</span>], new_bndbox_list, AUG_XML_DIR,</span><br><span class="line">                                           epoch + <span class="number">1</span>,name[:-<span class="number">4</span>])</span><br><span class="line">                <span class="built_in">print</span>( name[:-<span class="number">4</span>] + <span class="built_in">str</span>( <span class="string">&quot;_%06d&quot;</span> % (epoch + <span class="number">1</span>)) + <span class="string">&#x27;.jpg&#x27;</span>)</span><br><span class="line">                new_bndbox_list = []</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>标注得到的VOC格式数据集转为coco数据集</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># xmlTojson.py</span></span><br><span class="line"><span class="comment"># 用这个将xml转化为json格式可以正常的训练</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> xml.etree.ElementTree <span class="keyword">as</span> ET</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"></span><br><span class="line">coco = <span class="built_in">dict</span>()</span><br><span class="line">coco[<span class="string">&#x27;images&#x27;</span>] = []</span><br><span class="line">coco[<span class="string">&#x27;type&#x27;</span>] = <span class="string">&#x27;instances&#x27;</span></span><br><span class="line">coco[<span class="string">&#x27;annotations&#x27;</span>] = []</span><br><span class="line">coco[<span class="string">&#x27;categories&#x27;</span>] = []</span><br><span class="line"></span><br><span class="line">category_set = <span class="built_in">dict</span>()</span><br><span class="line">image_set = <span class="built_in">set</span>()</span><br><span class="line"></span><br><span class="line">category_item_id = <span class="number">0</span></span><br><span class="line"><span class="comment"># image_id = &#x27;ball-&#x27;</span></span><br><span class="line">image_id = <span class="number">0</span></span><br><span class="line">id_num = <span class="number">0</span></span><br><span class="line">annotation_id = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">addCatItem</span>(<span class="params">name</span>):</span><br><span class="line">    <span class="keyword">global</span> category_item_id</span><br><span class="line">    category_item = <span class="built_in">dict</span>()</span><br><span class="line">    category_item[<span class="string">&#x27;supercategory&#x27;</span>] = <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    category_item_id += <span class="number">1</span></span><br><span class="line">    category_item[<span class="string">&#x27;id&#x27;</span>] = category_item_id</span><br><span class="line">    category_item[<span class="string">&#x27;name&#x27;</span>] = name</span><br><span class="line">    coco[<span class="string">&#x27;categories&#x27;</span>].append(category_item)</span><br><span class="line">    category_set[name] = category_item_id</span><br><span class="line">    <span class="keyword">return</span> category_item_id</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">addImgItem</span>(<span class="params">file_name, size</span>):</span><br><span class="line">    <span class="keyword">global</span> image_id, id_num</span><br><span class="line">    <span class="keyword">if</span> file_name <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">raise</span> Exception(<span class="string">&#x27;Could not find filename tag in xml file.&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> size[<span class="string">&#x27;width&#x27;</span>] <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">raise</span> Exception(<span class="string">&#x27;Could not find width tag in xml file.&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> size[<span class="string">&#x27;height&#x27;</span>] <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">raise</span> Exception(<span class="string">&#x27;Could not find height tag in xml file.&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    image_item = <span class="built_in">dict</span>()</span><br><span class="line">    <span class="comment"># temp = str(id_num)</span></span><br><span class="line">    temp = <span class="built_in">int</span>(id_num)</span><br><span class="line">    <span class="comment"># image_item[&#x27;id&#x27;] = image_id + temp</span></span><br><span class="line">    image_item[<span class="string">&#x27;id&#x27;</span>] = temp</span><br><span class="line">    id_num += <span class="number">1</span></span><br><span class="line">    image_item[<span class="string">&#x27;file_name&#x27;</span>] = file_name</span><br><span class="line">    image_item[<span class="string">&#x27;width&#x27;</span>] = size[<span class="string">&#x27;width&#x27;</span>]</span><br><span class="line">    image_item[<span class="string">&#x27;height&#x27;</span>] = size[<span class="string">&#x27;height&#x27;</span>]</span><br><span class="line">    coco[<span class="string">&#x27;images&#x27;</span>].append(image_item)</span><br><span class="line">    image_set.add(file_name)</span><br><span class="line">    <span class="keyword">return</span> image_item[<span class="string">&#x27;id&#x27;</span>]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">addAnnoItem</span>(<span class="params">object_name, image_id, category_id, bbox</span>):</span><br><span class="line">    <span class="keyword">global</span> annotation_id</span><br><span class="line">    annotation_item = <span class="built_in">dict</span>()</span><br><span class="line">    annotation_item[<span class="string">&#x27;segmentation&#x27;</span>] = []</span><br><span class="line">    seg = []</span><br><span class="line">    <span class="comment"># bbox[] is x,y,w,h</span></span><br><span class="line">    <span class="comment"># left_top</span></span><br><span class="line">    seg.append(bbox[<span class="number">0</span>])</span><br><span class="line">    seg.append(bbox[<span class="number">1</span>])</span><br><span class="line">    <span class="comment"># left_bottom</span></span><br><span class="line">    seg.append(bbox[<span class="number">0</span>])</span><br><span class="line">    seg.append(bbox[<span class="number">1</span>] + bbox[<span class="number">3</span>])</span><br><span class="line">    <span class="comment"># right_bottom</span></span><br><span class="line">    seg.append(bbox[<span class="number">0</span>] + bbox[<span class="number">2</span>])</span><br><span class="line">    seg.append(bbox[<span class="number">1</span>] + bbox[<span class="number">3</span>])</span><br><span class="line">    <span class="comment"># right_top</span></span><br><span class="line">    seg.append(bbox[<span class="number">0</span>] + bbox[<span class="number">2</span>])</span><br><span class="line">    seg.append(bbox[<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line">    annotation_item[<span class="string">&#x27;segmentation&#x27;</span>].append(seg)</span><br><span class="line"></span><br><span class="line">    annotation_item[<span class="string">&#x27;area&#x27;</span>] = bbox[<span class="number">2</span>] * bbox[<span class="number">3</span>]</span><br><span class="line">    annotation_item[<span class="string">&#x27;iscrowd&#x27;</span>] = <span class="number">0</span></span><br><span class="line">    annotation_item[<span class="string">&#x27;ignore&#x27;</span>] = <span class="number">0</span></span><br><span class="line">    annotation_item[<span class="string">&#x27;image_id&#x27;</span>] = image_id</span><br><span class="line">    annotation_item[<span class="string">&#x27;bbox&#x27;</span>] = bbox</span><br><span class="line">    annotation_item[<span class="string">&#x27;category_id&#x27;</span>] = category_id</span><br><span class="line">    annotation_id += <span class="number">1</span></span><br><span class="line">    annotation_item[<span class="string">&#x27;id&#x27;</span>] = annotation_id</span><br><span class="line">    coco[<span class="string">&#x27;annotations&#x27;</span>].append(annotation_item)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">parseXmlFiles</span>(<span class="params">xml_path</span>):</span><br><span class="line">    <span class="keyword">for</span> f <span class="keyword">in</span> os.listdir(xml_path):</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> f.endswith(<span class="string">&#x27;.xml&#x27;</span>):</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line">        bndbox = <span class="built_in">dict</span>()</span><br><span class="line">        size = <span class="built_in">dict</span>()</span><br><span class="line">        current_image_id = <span class="literal">None</span></span><br><span class="line">        current_category_id = <span class="literal">None</span></span><br><span class="line">        file_name = <span class="literal">None</span></span><br><span class="line">        size[<span class="string">&#x27;width&#x27;</span>] = <span class="literal">None</span></span><br><span class="line">        size[<span class="string">&#x27;height&#x27;</span>] = <span class="literal">None</span></span><br><span class="line">        size[<span class="string">&#x27;depth&#x27;</span>] = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">        xml_file = os.path.join(xml_path, f)</span><br><span class="line">        <span class="built_in">print</span>(xml_file)</span><br><span class="line"></span><br><span class="line">        tree = ET.parse(xml_file)</span><br><span class="line">        root = tree.getroot()</span><br><span class="line">        <span class="keyword">if</span> root.tag != <span class="string">&#x27;annotation&#x27;</span>:</span><br><span class="line">            <span class="keyword">raise</span> Exception(<span class="string">&#x27;pascal voc xml root element should be annotation, rather than &#123;&#125;&#x27;</span>.<span class="built_in">format</span>(root.tag))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># elem is &lt;folder&gt;, &lt;filename&gt;, &lt;size&gt;, &lt;object&gt;</span></span><br><span class="line">        <span class="keyword">for</span> elem <span class="keyword">in</span> root:</span><br><span class="line">            current_parent = elem.tag</span><br><span class="line">            current_sub = <span class="literal">None</span></span><br><span class="line">            object_name = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> elem.tag == <span class="string">&#x27;folder&#x27;</span>:</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> elem.tag == <span class="string">&#x27;filename&#x27;</span>:</span><br><span class="line">                file_name = elem.text</span><br><span class="line">                <span class="keyword">if</span> file_name <span class="keyword">in</span> category_set:</span><br><span class="line">                    <span class="keyword">raise</span> Exception(<span class="string">&#x27;file_name duplicated&#x27;</span>)</span><br><span class="line"></span><br><span class="line">            <span class="comment"># add img item only after parse &lt;size&gt; tag</span></span><br><span class="line">            <span class="keyword">elif</span> current_image_id <span class="keyword">is</span> <span class="literal">None</span> <span class="keyword">and</span> file_name <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span> <span class="keyword">and</span> size[<span class="string">&#x27;width&#x27;</span>] <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                <span class="keyword">if</span> file_name <span class="keyword">not</span> <span class="keyword">in</span> image_set:</span><br><span class="line">                    current_image_id = addImgItem(file_name, size)</span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">&#x27;add image with &#123;&#125; and &#123;&#125;&#x27;</span>.<span class="built_in">format</span>(file_name, size))</span><br><span class="line">                <span class="keyword">else</span>:</span><br><span class="line">                    <span class="keyword">raise</span> Exception(<span class="string">&#x27;duplicated image: &#123;&#125;&#x27;</span>.<span class="built_in">format</span>(file_name))</span><br><span class="line">                    <span class="comment"># subelem is &lt;width&gt;, &lt;height&gt;, &lt;depth&gt;, &lt;name&gt;, &lt;bndbox&gt;</span></span><br><span class="line">            <span class="keyword">for</span> subelem <span class="keyword">in</span> elem:</span><br><span class="line">                bndbox[<span class="string">&#x27;xmin&#x27;</span>] = <span class="literal">None</span></span><br><span class="line">                bndbox[<span class="string">&#x27;xmax&#x27;</span>] = <span class="literal">None</span></span><br><span class="line">                bndbox[<span class="string">&#x27;ymin&#x27;</span>] = <span class="literal">None</span></span><br><span class="line">                bndbox[<span class="string">&#x27;ymax&#x27;</span>] = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">                current_sub = subelem.tag</span><br><span class="line">                <span class="keyword">if</span> current_parent == <span class="string">&#x27;object&#x27;</span> <span class="keyword">and</span> subelem.tag == <span class="string">&#x27;name&#x27;</span>:</span><br><span class="line">                    object_name = subelem.text</span><br><span class="line">                    <span class="keyword">if</span> object_name <span class="keyword">not</span> <span class="keyword">in</span> category_set:</span><br><span class="line">                        current_category_id = addCatItem(object_name)</span><br><span class="line">                    <span class="keyword">else</span>:</span><br><span class="line">                        current_category_id = category_set[object_name]</span><br><span class="line"></span><br><span class="line">                <span class="keyword">elif</span> current_parent == <span class="string">&#x27;size&#x27;</span>:</span><br><span class="line">                    <span class="keyword">if</span> size[subelem.tag] <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                        <span class="keyword">raise</span> Exception(<span class="string">&#x27;xml structure broken at size tag.&#x27;</span>)</span><br><span class="line">                    size[subelem.tag] = <span class="built_in">int</span>(subelem.text)</span><br><span class="line"></span><br><span class="line">                <span class="comment"># option is &lt;xmin&gt;, &lt;ymin&gt;, &lt;xmax&gt;, &lt;ymax&gt;, when subelem is &lt;bndbox&gt;</span></span><br><span class="line">                <span class="keyword">for</span> option <span class="keyword">in</span> subelem:</span><br><span class="line">                    <span class="keyword">if</span> current_sub == <span class="string">&#x27;bndbox&#x27;</span>:</span><br><span class="line">                        <span class="keyword">if</span> bndbox[option.tag] <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                            <span class="keyword">raise</span> Exception(<span class="string">&#x27;xml structure corrupted at bndbox tag.&#x27;</span>)</span><br><span class="line">                    bndbox[option.tag] = <span class="built_in">int</span>(option.text)</span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">f&quot;读取到 <span class="subst">&#123;option.tag&#125;</span>: <span class="subst">&#123;bndbox[option.tag]&#125;</span>&quot;</span>)</span><br><span class="line">  </span><br><span class="line">                <span class="keyword">if</span> current_sub == <span class="string">&#x27;bndbox&#x27;</span>:</span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">f&quot;xmin: <span class="subst">&#123;bndbox[<span class="string">&#x27;xmin&#x27;</span>]&#125;</span>, ymin: <span class="subst">&#123;bndbox[<span class="string">&#x27;ymin&#x27;</span>]&#125;</span>, xmax: <span class="subst">&#123;bndbox[<span class="string">&#x27;xmax&#x27;</span>]&#125;</span>, ymax: <span class="subst">&#123;bndbox[<span class="string">&#x27;ymax&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">                <span class="comment"># only after parse the &lt;object&gt; tag</span></span><br><span class="line">                <span class="keyword">if</span> bndbox[<span class="string">&#x27;xmin&#x27;</span>] <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                    <span class="keyword">if</span> object_name <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">                        <span class="keyword">raise</span> Exception(<span class="string">&#x27;xml structure broken at bndbox tag&#x27;</span>)</span><br><span class="line">                    <span class="keyword">if</span> current_image_id <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">                        <span class="keyword">raise</span> Exception(<span class="string">&#x27;xml structure broken at bndbox tag&#x27;</span>)</span><br><span class="line">                    <span class="keyword">if</span> current_category_id <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">                        <span class="keyword">raise</span> Exception(<span class="string">&#x27;xml structure broken at bndbox tag&#x27;</span>)</span><br><span class="line">                    bbox = []</span><br><span class="line">                    <span class="comment"># x</span></span><br><span class="line">                    bbox.append(bndbox[<span class="string">&#x27;xmin&#x27;</span>])</span><br><span class="line">                    <span class="comment"># y</span></span><br><span class="line">                    bbox.append(bndbox[<span class="string">&#x27;ymin&#x27;</span>])</span><br><span class="line">                    <span class="comment"># w</span></span><br><span class="line">                    width = bndbox[<span class="string">&#x27;xmax&#x27;</span>] - bndbox[<span class="string">&#x27;xmin&#x27;</span>]</span><br><span class="line">                    bbox.append(width)</span><br><span class="line">                    <span class="comment"># h</span></span><br><span class="line">                    height = bndbox[<span class="string">&#x27;ymax&#x27;</span>] - bndbox[<span class="string">&#x27;ymin&#x27;</span>]</span><br><span class="line">                    bbox.append(height)</span><br><span class="line">  </span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">f&quot;width: <span class="subst">&#123;width&#125;</span>, height: <span class="subst">&#123;height&#125;</span>&quot;</span>)</span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">f&quot;文件名: <span class="subst">&#123;file_name&#125;</span>, 对象名称: <span class="subst">&#123;object_name&#125;</span>, 计算得到的 bbox: <span class="subst">&#123;bbox&#125;</span>&quot;</span>)</span><br><span class="line">                    <span class="built_in">print</span>(<span class="string">&#x27;add annotation with &#123;&#125;,&#123;&#125;,&#123;&#125;,&#123;&#125;&#x27;</span>.<span class="built_in">format</span>(object_name, current_image_id, current_category_id,</span><br><span class="line">                                                                   bbox))</span><br><span class="line">                    addAnnoItem(object_name, current_image_id, current_category_id, bbox)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line"></span><br><span class="line">    xml_path = <span class="string">&quot;./val Enhance/xml&quot;</span>  <span class="comment">## 原始的xml文件路径</span></span><br><span class="line">    json_file = <span class="string">&#x27;./nanodet_train_zengqian.json&#x27;</span>  <span class="comment">## 转后保存.json文件的路径</span></span><br><span class="line">    <span class="comment">#</span></span><br><span class="line">    <span class="comment"># xml_path = &quot;./Annotations&quot;  ## 原始的xml文件路径</span></span><br><span class="line">    <span class="comment"># json_file = &#x27;./nanodet_train.json&#x27;  ## 转后保存.json文件的路径</span></span><br><span class="line"></span><br><span class="line">    parseXmlFiles(xml_path)</span><br><span class="line">    json.dump(coco, <span class="built_in">open</span>(json_file, <span class="string">&#x27;w&#x27;</span>))</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>将.xml标签文件转化为一个.json文件，用于coco数据集训练。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_b048ad7703c2d3e7dfdd2197123cc9ca.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_124846923aa4cec3a30c9302048bbfa8.png" alt=""></p><p>查看标注框是否正确，watch.py将展示json中有bbox属性的图片并标注出bbox，以便可视化检查数据标注质量。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># watch.py</span></span><br><span class="line"><span class="comment"># 查看标注框是否正确</span></span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> cv2</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载 JSON 文件</span></span><br><span class="line"><span class="comment"># nanodet_train.json</span></span><br><span class="line"><span class="comment"># nanodet_train_zengqian.json</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&#x27;nanodet_train_zengqian.json&#x27;</span>, <span class="string">&#x27;r&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    data = json.load(f)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取图像目录</span></span><br><span class="line">img_dir = <span class="string">&#x27;./val Enhance/images&#x27;</span></span><br><span class="line"><span class="comment"># img_dir = &#x27;./images&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取屏幕大小</span></span><br><span class="line">screen_width = <span class="number">640</span></span><br><span class="line">screen_height = <span class="number">640</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 遍历图像列表</span></span><br><span class="line"><span class="keyword">for</span> image <span class="keyword">in</span> data[<span class="string">&#x27;images&#x27;</span>]:</span><br><span class="line">    <span class="comment"># 获取图像文件名</span></span><br><span class="line">    img_file_name = image[<span class="string">&#x27;file_name&#x27;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 打开图像文件</span></span><br><span class="line">    img_path = os.path.join(img_dir, img_file_name)</span><br><span class="line">    img = cv2.imread(img_path)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 缩放图像至屏幕大小</span></span><br><span class="line">    scale = <span class="built_in">min</span>(screen_width / img.shape[<span class="number">1</span>], screen_height / img.shape[<span class="number">0</span>])</span><br><span class="line">    new_size = (<span class="built_in">int</span>(img.shape[<span class="number">1</span>] * scale), <span class="built_in">int</span>(img.shape[<span class="number">0</span>] * scale))</span><br><span class="line">    img = cv2.resize(img, new_size)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取 annotations 信息</span></span><br><span class="line">    annotations = [anno <span class="keyword">for</span> anno <span class="keyword">in</span> data[<span class="string">&#x27;annotations&#x27;</span>] <span class="keyword">if</span> anno[<span class="string">&#x27;image_id&#x27;</span>] == image[<span class="string">&#x27;id&#x27;</span>]]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 绘制方框</span></span><br><span class="line">    <span class="keyword">for</span> anno <span class="keyword">in</span> annotations:</span><br><span class="line">        bbox = anno[<span class="string">&#x27;bbox&#x27;</span>]</span><br><span class="line">        x1, y1, w, h = bbox</span><br><span class="line">        cv2.rectangle(img, (x1, y1), (x1 + w, y1 + h), (<span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>), <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 显示图像</span></span><br><span class="line">    cv2.imshow(img_file_name, img)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 等待按键</span></span><br><span class="line">    cv2.waitKey(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 关闭图像窗口</span></span><br><span class="line">    cv2.destroyAllWindows()</span><br></pre></td></tr></table></figure><p>查看数据标注是否正确，以及数据增强后标注是否一同缩放旋转正确对应。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_ee377cea19d1127978ade531d9210a6b.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_d43e3fcbb6be935819b61df4a51fe077.png" alt=""></p><p>分割训练集和测试集，按比例拆分。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># split_coco.py</span></span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">split_coco_data</span>(<span class="params">coco_file, train_ratio=<span class="number">0.8</span>, output_train_file=<span class="string">&quot;train.json&quot;</span>, output_test_file=<span class="string">&quot;test.json&quot;</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    将 COCO 标注文件按照指定的比例分割成训练集和测试集。</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    参数:</span></span><br><span class="line"><span class="string">        coco_file (str): COCO 标注 JSON 文件的路径。</span></span><br><span class="line"><span class="string">        train_ratio (float): 训练集中图像所占的比例 (默认值: 0.8)。</span></span><br><span class="line"><span class="string">        output_train_file (str): 保存训练集 COCO JSON 文件的路径 (默认值: &quot;train.json&quot;)。</span></span><br><span class="line"><span class="string">        output_test_file (str): 保存测试集 COCO JSON 文件的路径 (默认值: &quot;test.json&quot;)。</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(coco_file, <span class="string">&#x27;r&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        coco_data = json.load(f)</span><br><span class="line"></span><br><span class="line">    images = coco_data[<span class="string">&#x27;images&#x27;</span>]  <span class="comment"># 获取所有图像信息</span></span><br><span class="line">    annotations = coco_data[<span class="string">&#x27;annotations&#x27;</span>]  <span class="comment"># 获取所有标注信息</span></span><br><span class="line">    categories = coco_data[<span class="string">&#x27;categories&#x27;</span>] <span class="keyword">if</span> <span class="string">&#x27;categories&#x27;</span> <span class="keyword">in</span> coco_data <span class="keyword">else</span> [] <span class="comment"># 获取类别信息，如果不存在则设为空列表</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 随机打乱图像列表，确保分割的随机性</span></span><br><span class="line">    random.shuffle(images)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 计算训练集的大小</span></span><br><span class="line">    train_size = <span class="built_in">int</span>(<span class="built_in">len</span>(images) * train_ratio)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 分割图像列表为训练集和测试集</span></span><br><span class="line">    train_images = images[:train_size]</span><br><span class="line">    test_images = images[train_size:]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 获取训练集和测试集图像的 ID 列表</span></span><br><span class="line">    train_image_ids = [img[<span class="string">&#x27;id&#x27;</span>] <span class="keyword">for</span> img <span class="keyword">in</span> train_images]</span><br><span class="line">    test_image_ids = [img[<span class="string">&#x27;id&#x27;</span>] <span class="keyword">for</span> img <span class="keyword">in</span> test_images]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 根据图像 ID 过滤标注信息，得到训练集和测试集的标注</span></span><br><span class="line">    train_annotations = [ann <span class="keyword">for</span> ann <span class="keyword">in</span> annotations <span class="keyword">if</span> ann[<span class="string">&#x27;image_id&#x27;</span>] <span class="keyword">in</span> train_image_ids]</span><br><span class="line">    test_annotations = [ann <span class="keyword">for</span> ann <span class="keyword">in</span> annotations <span class="keyword">if</span> ann[<span class="string">&#x27;image_id&#x27;</span>] <span class="keyword">in</span> test_image_ids]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 创建训练集 COCO 数据集</span></span><br><span class="line">    train_coco_data = &#123;</span><br><span class="line">        <span class="string">&#x27;images&#x27;</span>: train_images,</span><br><span class="line">        <span class="string">&#x27;annotations&#x27;</span>: train_annotations,</span><br><span class="line">        <span class="string">&#x27;categories&#x27;</span>: categories  <span class="comment"># 包含类别信息</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 创建测试集 COCO 数据集</span></span><br><span class="line">    test_coco_data = &#123;</span><br><span class="line">        <span class="string">&#x27;images&#x27;</span>: test_images,</span><br><span class="line">        <span class="string">&#x27;annotations&#x27;</span>: test_annotations,</span><br><span class="line">        <span class="string">&#x27;categories&#x27;</span>: categories  <span class="comment"># 包含类别信息</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 将训练集 COCO 数据集保存到 JSON 文件</span></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(output_train_file, <span class="string">&#x27;w&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        json.dump(train_coco_data, f)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 将测试集 COCO 数据集保存到 JSON 文件</span></span><br><span class="line">    <span class="keyword">with</span> <span class="built_in">open</span>(output_test_file, <span class="string">&#x27;w&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">        json.dump(test_coco_data, f)</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;COCO 数据集分割完成:&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  - 训练集: <span class="subst">&#123;<span class="built_in">len</span>(train_images)&#125;</span> 张图像, <span class="subst">&#123;<span class="built_in">len</span>(train_annotations)&#125;</span> 个标注 (保存到 <span class="subst">&#123;output_train_file&#125;</span>)&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;  - 测试集: <span class="subst">&#123;<span class="built_in">len</span>(test_images)&#125;</span> 张图像, <span class="subst">&#123;<span class="built_in">len</span>(test_annotations)&#125;</span> 个标注 (保存到 <span class="subst">&#123;output_test_file&#125;</span>)&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="comment"># 将 &#x27;coco_annotations.json&#x27; 替换为你的 COCO 标注文件的实际路径</span></span><br><span class="line">    coco_annotation_file = <span class="string">&quot;nanodet_train.json&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 你可以根据需要调整 train_ratio (例如，0.7 表示 70% 用于训练，30% 用于测试)</span></span><br><span class="line">    split_coco_data(coco_annotation_file, train_ratio=<span class="number">0.8</span>, output_train_file=<span class="string">&quot;train.json&quot;</span>, output_test_file=<span class="string">&quot;test.json&quot;</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>得到2：8的测试训练集</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_3f83fac79fce014064d920e862edef77.png" alt=""></p><p>修改配置文件</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_f31bfc2df8d8a1e1f5010f9ae48904e6.png" alt="原图作者目标检测——使用nanodet训练自己制作的数据集并测试模型，通俗易懂（详细图文教程）nanodet训练自己的模型-CSDN博客"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_a0ec75738755bdf3b5686a572738d141.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_42341b6952ba0dc378d1537ecce23f9e.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_876ac3450d2d1324103d46314c27f217.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_e3880b89db68d5e0a4fbd6638e7ab3c1.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_96cf0249da0dfe8a0df6eac0a5d150f0.png" alt=""></p><h4 id="模型训练">模型训练</h4><p>使用配置文件进行训练</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python tools/train.py ./config/legacy_v0.x_configs/nanodet-m.yml</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_fd1fb6d2d41943dd62af1a38d71fac12.png" alt=""></p><p>待训练完成后模型保存为pth，默认会按照<code>mAP</code>评分保持最佳模型。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_22/image_9b5947506fad781acda79faf9c926240.png" alt=""></p><p>可以用刚刚训练的模型测试一下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python demo/demo.py video --config ./config/nanodet-m.yml --model ./workspace/nanodet_m/model_best/nanodet_model_best.pth --path ./Video/rc.mp4</span><br></pre></td></tr></table></figure><h4 id="恢复中断训练">恢复中断训练</h4><p>如果训练意外中断，可以使用PyTorch Lightning 提供的 checkpoint 功能，只需要更改配置文件,将schedule.resume设置为True即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">schedule:</span><br><span class="line">  resume: True  # 或者 False，取决于你是否要恢复训练</span><br><span class="line">  # 其他 schedule 配置</span><br></pre></td></tr></table></figure><p>重新启动训练<code>python tools/train.py config\nanodet-plus-m-1.5x_416.yml</code></p><p>PyTorch Lightning 会自动检测 <code>model_last.ckpt</code> 文件，并从上次保存的 checkpoint 恢复训练。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_27/image_611d80cbe9d40f3aee9af44120ba8dad.png" alt=""></p><h4 id="TensorBoard">TensorBoard</h4><p><strong>可视化日志</strong><br>TensorBoard 日志保存在您在配置文件中设置的位置。<code>save_dir</code><br>要可视化 tensorboard 日志，请运行：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd &lt;YOUR_SAVE_DIR&gt;</span><br><span class="line">tensorboard --logdir ./</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_28/b4b3da70890ef603956e37b84b6f530_b4ee8bf99f4f26281f7daf65224277e2.png" alt=""></p><p>观察模型是否收敛：因为仅仅观察损失函数很难判断是否需要停止训练，可观测其性能指标增长趋势逐步调整训练轮次，因为经过数据增强数据集多达5000+，所以此处训练轮次可以适当减少。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_fd974217b81aaff2a7233aa8a6f4d92e.png" alt=""></p><p>主要观察mAP指标继续训练是否还有增长趋势，若还存在上升趋势可追加训练轮次，直到性能指标趋于平稳，则可认为模型以及拟合。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_549d752ebe851cea7cc58dd6b8762c2c.png" alt=""></p><p>训练350轮</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_07/image_f392c5d85293f096ae68f117d337acf0.png" alt=""></p><h4 id="模型导出">模型导出</h4><p>pth转onnx</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python tools/export_onnx.py --cfg_path ./config/nanodet-plus-m-1.5x_416.yml --model_path workspace/nanodet-plus-m-1.5x_416/model_best/nanodet_model_best.pth </span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/07_07/image_33a4f85982336acc62d6bae409081eb8.png" alt=""></p><p>onnx转IR</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 示例：将 ONNX 模型转换为 OpenVINO IR</span><br><span class="line">ovc your_model.onnx --output_model openvino_ir</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_a8d620810f85bd2c1b717a70463e804a.png" alt=""></p><h4 id="学习率">学习率</h4><p>理论：<a href="https://polar-bear.eu.org/2025/04/26/ji-qi-xue-xi-shen-jing-wang-luo/#%E5%AD%A6%E4%B9%A0%E7%8E%87">机器学习——神经网络 | polar-bear～Blog</a></p><p>不同学习率：</p><ul><li><strong>过大的学习率</strong>：可能导致模型在最优解附近震荡，或者在极端情况下导致模型发散。</li><li><strong>过小的学习率</strong>：虽然能够保证模型最终收敛，但是会大大降低模型训练的速度。有时，它甚至可能导致模型陷入局部最优解。</li></ul><p>观察学习率曲线，此处使用<code>学习率预热</code>（warmup）<code>和学习率衰减</code>（Learning Rate Decay）</p><p>warm-up 是指在训练的初期，逐渐增加学习率的过程，以帮助模型更好地收敛到最优解，逐渐增加学习率，而不是直接使用高学习率再衰减的原因是防止在模型初始时高学习率快速降低损失函数至局部最优导致模型后期学习率衰减无法跳出局部最优寻找全局最优（长难句，个人理解）</p><p><code>ratio: 0.0001  # 预热的起始学习率与 lr 的比率</code>在训练的开始会使用低学习率以实现在训练初期更好地适应数据，提高训练的稳定性和性能。</p><p>Learning Rate Decay则使模型在后期<code>精细调节</code>,<code>防止震荡</code>,<code>避免过拟合</code></p><p>使用一个简单的线性回归案例，持续高学习率确实可以快速收敛，加快模型收敛速度，突破局部最优寻找全局最优，但是到了模型训练后期，应该缓慢降低学习率，否则高学习率会导致模型陷入局部震荡无法正常收敛，如下图。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_997f08afed042fbce1d0371d9e0741b2.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_7baf2a48afc3a7df4fee6b8b018e701b.png" alt=""></p><p>（在高学习率下线性回归模型损失值会大幅波动。 这表示学习速率过高，模型训练永远不会收敛。）</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_fc9d8958b385df7f324942831007ad23.png" alt=""></p><p>余弦退火衰减 CosineAnnealingLR:</p><p>当越来越接近Loss值的全局最小值时，学习率应该变得更小来使得模型尽可能接近这一点，而余弦退火（Cosine annealing）可以通过余弦函数来降低学习率。余弦函数中随着x的增加余弦值首先缓慢下降，然后加速下降，再次缓慢下降。这种下降模式能和学习率配合，以一种十分有效的计算方式来产生很好的效果。</p><p>神经网络在刚开始训练时，并非如同理想的情况一样，只需要确定一个方向即可。模型参数在初始化时，是非常不稳定的，因此在刚开始时需要选用小的学习率。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_13/image_d44662a47557f69a71c9c396b9b9b014.png" alt=""></p><p>(图片来自文2)</p><p><a href="https://blog.csdn.net/weixin_35848967/article/details/108493217">学习率衰减之余弦退火(CosineAnnealing）-CSDN博客</a></p><p><a href="https://blog.csdn.net/weixin_42392454/article/details/127766771">狗都会用的余弦退火（CosineAnnealingLR）学习率调节算法讲解-CSDN博客</a></p><p><a href="https://zhuanlan.zhihu.com/p/261134624">pytorch的余弦退火学习率 - 知乎</a></p><h2 id="Openvino部署">Openvino部署</h2><h3 id="Openvino安装">Openvino安装</h3><p>OpenVINOTM安装分为完整版安装与不完整版(Runtime)安装。</p><p>完整版安装会安装所有部件，包括模型优化器和推理部署套件运行工具(Runtime)，目前该方式支持PIP安装方式，因此建议采用PIP安装在虚拟环境中，防止安装出错照成电脑环境出现问题。该安装方式至此Python、C++同时使用，由于安装路径较长，对C++使用不太方便，因此该安装方式最好使用Python编程。</p><p>非完整版安装主要安装编译环境(Runtime)，安装比较简单，且一般会安装到根目录下，方便使用，因此如果不使用模型优化且情况下，或者使用C++编译环境的话，建议选用此方式。</p><p>openvino推荐使用存档直接安装或者conda安装</p><p>ubuntu：Ubuntu 24.04.2 LTS</p><p>openvino：2025.1</p><h3 id="直接安装">直接安装</h3><p><a href="https://docs.openvino.ai/2025/get-started/install-openvino.html?PACKAGE=OPENVINO_BASE&amp;VERSION=v_2025_1_0&amp;OP_SYSTEM=LINUX&amp;DISTRIBUTION=ARCHIVE">https://docs.openvino.ai/2025/get-started/install-openvino.html?PACKAGE=OPENVINO_BASE&amp;VERSION=v_2025_1_0&amp;OP_SYSTEM=LINUX&amp;DISTRIBUTION=ARCHIVE</a></p><p>前往官网下载对应版本</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_1e104b83793d85d1113fb3c0250d7b87.png" alt=""></p><p>在/opt下创建文件夹</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo mkdir /opt/intel</span><br></pre></td></tr></table></figure><p>解压后移动到/opt/intel</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">tar -xf openvino_2025.0.0.tgz</span><br><span class="line">sudo mv openvino_toolkit_ubuntu22_2025 /opt/intel/openvino_2025.0.0</span><br></pre></td></tr></table></figure><p>可以创建软链接，方便路径。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd /opt/intel</span><br><span class="line">sudo ln -s openvino_2025.1.0 openvino_2025</span><br></pre></td></tr></table></figure><p>安装openvino环境依赖</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd /opt/intel/openvino_2025.1.0</span><br><span class="line">sudo -E ./install_dependencies/install_openvino_dependencies.sh</span><br></pre></td></tr></table></figure><p>配置环境变量</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim ~/.bashrc</span><br></pre></td></tr></table></figure><p>将脚本路径添加进去，这样每次启动终端都会加载openvino</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">source /opt/intel/openvino_2025/setupvars.sh</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_9e114ca70c22f68e1502ba247beddf33.png" alt=""></p><h3 id="conda-v2">conda</h3><p><a href="https://www.anaconda.com/download/success">https://www.anaconda.com/download/success</a></p><p>下载conda安装脚本</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_0a5757c253e705ba3443eeea942110f9.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_eabff0f73ea17fa23bb257ed5c2e78c4.png" alt=""></p><p>一路yes即可</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_a90713cbd3cd574ccc99d77e14ab7909.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_8eee5eacc8186c972619bb8f53ee1772.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_12374777e2ddd287953263653fd3fecd.png" alt=""></p><p>完成安装，刷新一下终端</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source ~/.bashrc</span><br></pre></td></tr></table></figure><p>输入</p><p>conda</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_d52e8f059ef1e60ce28099f5a95eda20.png" alt=""></p><p>安装完成后最好升级一下conda</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda update -n base -c defaults conda</span><br></pre></td></tr></table></figure><p>创建虚拟环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda create --name py310 python=3.10</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_99a32e7b486a6ea81785320fd1d041b8.png" alt=""></p><p>进入虚拟环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda activate py310</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_604db87a2add371ceea9c0c6fb7e3ee5.png" alt=""></p><p>将以下命令行添加到 ~/.bashrc ，只需要在终端输入 py310 就直接进入了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alias py310=&#x27;source activate py310&#x27;</span><br></pre></td></tr></table></figure><p>使用conda安装openvino</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">conda update --all</span><br><span class="line">conda install -c conda-forge openvino=2025.1.0</span><br></pre></td></tr></table></figure><p>openvino安装位置位于</p><p>/home/rick/anaconda3/envs/py310/include</p><p>/home/rick/anaconda3/envs/py310/lib</p><h3 id="测试openvino安装状态">测试openvino安装状态</h3><p>新建main.cpp</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;openvino/openvino.hpp&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 初始化OpenVINO核心</span></span><br><span class="line">        ov::Core core;</span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 打印OpenVINO版本信息</span></span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;OpenVINO version: &quot;</span> &lt;&lt; ov::<span class="built_in">get_openvino_version</span>() &lt;&lt; std::endl;</span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 获取可用设备列表</span></span><br><span class="line">        std::vector&lt;std::string&gt; available_devices = core.<span class="built_in">get_available_devices</span>();</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Available devices: &quot;</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">const</span> <span class="keyword">auto</span>&amp; device : available_devices) &#123;</span><br><span class="line">            std::cout &lt;&lt; device &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        std::cout &lt;&lt; std::endl;</span><br><span class="line">  </span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125; <span class="built_in">catch</span> (<span class="type">const</span> std::exception&amp; ex) &#123;</span><br><span class="line">        std::cerr &lt;&lt; <span class="string">&quot;Exception: &quot;</span> &lt;&lt; ex.<span class="built_in">what</span>() &lt;&lt; std::endl;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>新建CMakeLists.txt</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">cmake_minimum_required(VERSION 3.5)</span><br><span class="line">project(openvino_test)</span><br><span class="line"></span><br><span class="line">set(CMAKE_CXX_STANDARD 17)</span><br><span class="line">set(CMAKE_CXX_STANDARD_REQUIRED ON)</span><br><span class="line"></span><br><span class="line"># 设置OpenVINO路径</span><br><span class="line">set(OpenVINO_DIR &quot;/opt/intel/openvino_2025/runtime/include&quot;)</span><br><span class="line"></span><br><span class="line"># 查找OpenVINO包</span><br><span class="line">find_package(OpenVINO REQUIRED)</span><br><span class="line"></span><br><span class="line"># 添加可执行文件</span><br><span class="line">add_executable(openvino_test main.cpp)</span><br><span class="line"></span><br><span class="line"># 链接OpenVINO库</span><br><span class="line">target_link_libraries(openvino_test PRIVATE openvino::runtime)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>执行：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p build &amp;&amp; cd build &amp;&amp; cmake .. &amp;&amp; make</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_68470ac041338aaf80bb0aeac2f40aac.png" alt=""></p><p><code>ctrl</code>+<code>shift</code>+<code>p</code>或<code>F1</code>打开快捷指令输入</p><blockquote><p>edit configurations (UI)</p></blockquote><p>找到include路径，将openvino路径填入，防止code找不到库，导致include报红。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_7eef4f4ebda58de14b358f0fdc109c64.png" alt=""></p><p>选择调试配置，使用Cmake</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/05_26/image_d6874c9fefd085d1c9c3b1eefb52bd90.png" alt=""></p><p>点击cmake插件底部的运行即可使用cmakelist完成编译运行。</p><h3 id="安装opencv">安装opencv</h3><p>直接安装在系统目录</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install libopencv-dev</span><br></pre></td></tr></table></figure><p>在cmakelist.txt可以使用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 查找依赖包</span><br><span class="line">find_package(OpenCV REQUIRED)</span><br></pre></td></tr></table></figure><p>自动搜索到。</p><h3 id="安装海康MVS">安装海康MVS</h3><p>到下载页面下载：<a href="https://www.hikrobotics.com/cn/machinevision/service/download/?module=0">https://www.hikrobotics.com/cn/machinevision/service/download/?module=0</a></p><p>下载 机器视觉工业相机客户端MVS V3.0.1 (Linux)</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_04/image_2ee0aabe66d16ff2545dd79368114319.png" alt=""></p><p>下载的压缩包中含有不同架构的安装包</p><p>安装</p><p>sudo dpkg -i MVS-3.0.1_x86_64_20241128.deb</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_04/image_a2776772ed79e258e2338981e1ff8714.png" alt=""></p><p>安装在/opt/MVS 目录下</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_07/image_d744d43f7cbc8acc94e7e0ea62ea2600.png" alt=""></p><p>运行<code>/opt/MVS/bin/MVS.sh</code>测试是否安装成功。</p><h3 id="摄像头频闪">摄像头频闪</h3><p>若遇到频闪，则调整曝光时间避开场地光源频率</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_19/image_39014a085edb85a765b1a4e36ef81d4f.png" alt=""></p><h3 id="boost安装">boost安装</h3><p>前往官网下载：<a href="https://www.boost.org/releases/1.74.0/">https://www.boost.org/releases/1.74.0/</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_30/image_542305a436d558842c0bfed15dd386c1.png" alt=""></p><p>下载后解压到任意路径</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="built_in">mv</span> ./boost_1_74_0 /opt/boost_1_74_0</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_30/image_7bfc3f7e9023c22ad7e9f6da640bce12.png" alt=""></p><p>执行安装脚本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./bootstrap.sh </span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_30/image_23200a47690e11c0ef82e91a32e90fa1.png" alt=""></p><p>运行构建命令：./b2</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_30/image_ef25561c023294ef0e45f6dc7c4654f1.png" alt=""></p><p>安装库文件：sudo ./b2 install</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/06_30/image_62ea0df3154cdfc0cd3549eea59bb06d.png" alt=""></p>]]></content>
    
    
    <summary type="html">NANODET训练
github：RangiLyu/nanodet: NanoDet-Plus⚡Super fast and lightweight anchor-free
object detection model. 🔥Only 980 KB(int8) / 1.8MB (fp16) and run 97FPS on
cellphone🔥 [https://github.com/RangiLyu/nanodet]

CPU</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>在Docker中安装Postgresql</title>
    <link href="https://polar-bear.eu.org/2025/04/10/zai-docker-zhong-an-zhuang-postgresql/"/>
    <id>https://polar-bear.eu.org/2025/04/10/zai-docker-zhong-an-zhuang-postgresql/</id>
    <published>2025-04-10T00:40:58.210Z</published>
    <updated>2025-04-10T00:45:35.254Z</updated>
    
    <content type="html"><![CDATA[<h2 id="在Docker中安装Postgresql">在Docker中安装Postgresql</h2><p>有个服务挂在supabase上长期未用，然后发现已经过期，只保留备份文件，遂本地部署。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_a30ab79168c2d44c4969ce650410b819.png" alt=""></p><h3 id="拉取镜像">拉取镜像</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull postgres</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_9be89cf7b2f9b74454ce05d4bb6ea579.png" alt=""></p><h3 id="创建本地卷">创建本地卷</h3><p>数据卷可以在<strong>容器之间共享和重用</strong>， 默认会一直存在，即使容器被删除（docker volume inspect pgdata可查看数据卷的本地位置，验证持久数据目录）你也不想数据库和容器一起消失吧</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker volume create pgdata</span><br><span class="line"></span><br><span class="line">docker volume inspect pgdata</span><br></pre></td></tr></table></figure><p>可以看到输出本地卷信息</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">root@rick:/home/rick<span class="comment"># docker volume inspect pgdata</span></span><br><span class="line">[</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="string">&quot;CreatedAt&quot;</span>: <span class="string">&quot;2025-04-10T08:46:11Z&quot;</span>,</span><br><span class="line">        <span class="string">&quot;Driver&quot;</span>: <span class="string">&quot;local&quot;</span>,</span><br><span class="line">        <span class="string">&quot;Labels&quot;</span>: null,</span><br><span class="line">        <span class="string">&quot;Mountpoint&quot;</span>: <span class="string">&quot;/var/snap/docker/common/var-lib-docker/volumes/pgdata/_data&quot;</span>,</span><br><span class="line">        <span class="string">&quot;Name&quot;</span>: <span class="string">&quot;pgdata&quot;</span>,</span><br><span class="line">        <span class="string">&quot;Options&quot;</span>: null,</span><br><span class="line">        <span class="string">&quot;Scope&quot;</span>: <span class="string">&quot;local&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">]</span><br><span class="line">root@rick:/home/rick<span class="comment">#</span></span><br></pre></td></tr></table></figure><h3 id="启动容器，使用持久数据存储启动-PostgreSQL-容器">启动容器，使用持久数据存储启动 PostgreSQL 容器</h3><p>启动时，需要将刚上个步骤创建的卷<code>pgdata</code>挂载到容器的<code>/var/snap/docker/common/var-lib-docker/volumes/pgdata/_data</code>目录。</p><ul><li><strong>run</strong> ：创建并运行一个容器；</li><li><strong>–name</strong> ：指定容器名称。（容器名称 自己设置）</li><li><strong>-e POSTGRES_PASSWORD</strong>=password，设置环境变量，指定数据库的登录口令为password（password 自己设置）</li><li><strong>-p</strong> ：指定宿主机和 Docker 容器端口映射，冒号前为宿主机端口号，另一个是容器端口号。（Docker的容器默认情况下只能由本地主机访问，即A主机上的容器不能被B主机访问，所以要做端口映射）（端口号 自己设置）</li><li><strong>-d postgres</strong>：指定使用postgres作为镜像</li></ul><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name postgres -e POSTGRES_PASSWORD=123456 -p 5040:5040 -v pgdata:/var/snap/docker/common/var-lib-docker/volumes/pgdata/_data -d postgres</span><br></pre></td></tr></table></figure><h3 id="连接数据库">连接数据库</h3><p><strong>从容器连接</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it postgres /bin/bash</span><br></pre></td></tr></table></figure><p>切换用户</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">su postgres</span><br></pre></td></tr></table></figure><p>连接</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_586ae9978db1ce6491f3609f4fe0148f.png" alt=""></p><p><strong>从主机连接</strong></p><p>首先安装客户端<code>sudo apt install postgresql-client</code></p><p>显示容器ip地址<code>docker inspect -f '&#123;&#123;range .NetworkSettings.Networks&#125;&#125;&#123;&#123;.IPAddress&#125;&#125;&#123;&#123;end&#125;&#125;' 容器ID</code></p><p>连接容器：<code>psql -U postgres -h 172.17.0.3</code></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_e3b34b8ab7594b5d0ba42d64b71aa4bc.png" alt=""></p><p>恢复备份文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -U postgres -h 172.17.0.3 -f db_cluster-28-10-2024@15-17-45.backup</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_221fe96590152a17d020a323191bc83d.png" alt=""><br><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_470c09e2a178eb688829362d6db9a28e.png" alt=""></p>]]></content>
    
    
    <summary type="html">在DOCKER中安装POSTGRESQL
有个服务挂在supabase上长期未用，然后发现已经过期，只保留备份文件，遂本地部署。

[https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/04_10/image_a30ab79168c2d44c4969ce650410b819.png]

拉取镜像</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>永久免费LinuxONE云服务器</title>
    <link href="https://polar-bear.eu.org/2025/02/22/yong-jiu-mian-fei-linuxone-yun-fu-wu-qi/"/>
    <id>https://polar-bear.eu.org/2025/02/22/yong-jiu-mian-fei-linuxone-yun-fu-wu-qi/</id>
    <published>2025-02-22T22:11:01.284Z</published>
    <updated>2025-02-22T22:32:48.153Z</updated>
    
    <content type="html"><![CDATA[<h2 id="永久免费LinuxONE云服务器">永久免费LinuxONE云服务器</h2><p>无需信用卡，120天免费续费，注册的时候不要挂梯子，不能安装宝塔不能挂梯，2核4G,</p><p>延迟高，但是带宽高</p><p>LinuxONE官网：<a href="https://linuxone.cloud.marist.edu/#/login">https://linuxone.cloud.marist.edu/#/login</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_2ce79c75695f9806c3955d967a4b904d.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_2ce79c75695f9806c3955d967a4b904d.png"></p><p>前往官网注册，建议使用QQ邮箱，选择国家：美国，最后申请原因：I want to learn Linux</p><p>稍后会发送邮件到邮箱，前往授权后即可登陆。</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_a77f66029e9b21fe2575d8f3e23f07d3.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_a77f66029e9b21fe2575d8f3e23f07d3.png"></p><p>进入主页，随后创建服务器</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_c5c9eadfc0b1be1eb2cbc00e2521a182.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_c5c9eadfc0b1be1eb2cbc00e2521a182.png">名称随意，选择系统，建议Ubuntu</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_4310ea7311c704aadc0c08f5f5ec69eb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_4310ea7311c704aadc0c08f5f5ec69eb.png">选择设备配置，只有一个可选，创建SSH密钥，用于建立SSH连接，随后创建即可。</p><p>等待数分钟，直到服务器状态变为active</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_3bfcdc025fcf3cc36477638603196a41.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_3bfcdc025fcf3cc36477638603196a41.png">使用ssh连接用户名为Linux User对应，默认应该是linux1，ip即为所给ip，端口默认22</p><h2 id="连接">连接</h2><p>使用SSH软件连接</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_e943909d77e58497e044976b982db1b4.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/02_23/image_e943909d77e58497e044976b982db1b4.png"></p><p>使用刚才创建的私钥连接即可</p><p>或者ssh linux1@*. * . * . * -i /win/sshkey</p><h2 id="切换root用户">切换root用户</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo passwd root</span><br><span class="line"></span><br><span class="line">su </span><br></pre></td></tr></table></figure><h2 id="安装1panel">安装1panel</h2><p>该服务器因为不能安装宝塔，故可使用1panel</p><p><strong>curl -sSL https</strong>:<strong><a href="//resource.fit2cloud.com/1panel/package/quick">//resource.fit2cloud.com/1panel/package/quick</a>_start.sh -o quick_start.sh &amp;&amp; sudo bash quick_start.sh</strong></p><h2 id="开放端口">开放端口</h2><p>所有端口</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">iptables -P INPUT ACCEPT</span><br><span class="line">iptables -P FORWARD ACCEPT</span><br><span class="line">iptables -P OUTPUT ACCEPT</span><br><span class="line">iptables -F</span><br></pre></td></tr></table></figure><p>开放后建议安装启用ufw防火墙</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo ufw allow 22/tcp</span><br><span class="line">sudo ufw <span class="built_in">enable</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">永久免费LINUXONE云服务器
无需信用卡，120天免费续费，注册的时候不要挂梯子，不能安装宝塔不能挂梯，2核4G,

延迟高，但是带宽高

LinuxONE官网：https://linuxone.cloud.marist.edu/#/login</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Cloudflare Worker自建Docker代理加速</title>
    <link href="https://polar-bear.eu.org/2025/01/22/cloudflare-worker-zi-jian-docker-dai-li-jia-su/"/>
    <id>https://polar-bear.eu.org/2025/01/22/cloudflare-worker-zi-jian-docker-dai-li-jia-su/</id>
    <published>2025-01-22T04:48:31.815Z</published>
    <updated>2025-08-12T01:20:11.096Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Cloudflare-Worker自建Docker代理加速">Cloudflare Worker自建Docker代理加速</h2><p>2025/08/12 更新</p><p>过去使用的Docker代理已经失效，会出现Missing x-amz-content-sha256错误，现在使用<a href="https://github.com/cmliu/CF-Workers-docker.io">cmliu/CF-Workers-docker.io: 这个项目是一个基于 Cloudflare Workers 的 Docker 镜像代理工具。它能够中转对 Docker 官方镜像仓库的请求，解决一些访问限制和加速访问的问题。</a></p><hr><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_12/image_59c53977b9db9a9caa4f66e8280965a1.png" alt=""></p><p><a href="https://github.com/cmliu/CF-Workers-docker.io">cmliu/CF-Workers-docker.io: 这个项目是一个基于 Cloudflare Workers 的 Docker 镜像代理工具。它能够中转对 Docker 官方镜像仓库的请求，解决一些访问限制和加速访问的问题。</a></p><blockquote><p>[!WARNING]<br>根据 <a href="https://www.cloudflare.com/zh-cn/terms/">Cloudflare 协议</a> 中，2.2.1 第 (j) use the Services to provide a virtual private network or other similar proxy services.</p><p>使用本服务可能存在被 Cloudflare 封号的潜在风险，请自行斟酌使用风险。</p><p>如果你选择了“根据主机名选择对应的上游地址”方式部署，你可能会:</p><p>被 Netcraft 扫描到，收到警告邮件</p><p>被 Netcraft 同步到 Google Safe Browsing 标记为钓鱼网站</p><p>被 Netcraft 投诉到 Cloudflare 标记为钓鱼网站, 无法正常 pull 镜像</p><p>收到律师函</p></blockquote><p>打开Cloudflare的Worker复制 <a href="https://github.com/cmliu/CF-Workers-docker.io/blob/main/_worker.js">_worker.js</a> 代码，<code>保存并部署</code>即可</p><p>填写到worker的js文件里面，在标记的地方更改自己的域名，然后部署</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_581fbebf9e73986e7b204ba577df8f16.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_581fbebf9e73986e7b204ba577df8f16.png"></p><p>并且在worker的设置里面添加自定义的域名</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_08d1880045eea3f28a4e1a0a0d0f5efb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_08d1880045eea3f28a4e1a0a0d0f5efb.png"></p><p>直接访问域名可以直接搜索Docker仓库</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_12/image_0e5d10cf5a4339af616bc134fb844608.png" alt=""></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/08_12/image_6eb34ae8bb909489ddd372121256502e.png" alt=""></p><p>使用代理，官方镜像路径前面加域名</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull xxxxx.com/mysql/mysql-server</span><br><span class="line">docker pull 自定义域名/+docker包名</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">CLOUDFLARE WORKER自建DOCKER代理加速
2025/08/12 更新

过去使用的Docker代理已经失效，会出现Missing x-amz-content-sha256错误，现在使用
cmliu/CF-Workers-docker.io: 这个项目是一个基于 Cloudflare Workers 的 Docker 镜像代理工具。它能够中转对
Docker 官方镜 [https://github.com/cmliu/CF-Workers-docker.io]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Gemini中转API</title>
    <link href="https://polar-bear.eu.org/2025/01/21/gemini-zhong-zhuan-api/"/>
    <id>https://polar-bear.eu.org/2025/01/21/gemini-zhong-zhuan-api/</id>
    <published>2025-01-21T19:36:25.936Z</published>
    <updated>2025-01-21T19:37:08.640Z</updated>
    
    <content type="html"><![CDATA[<p>Gemini 转OpenAI API格式</p><p><a href="https://github.com/PublicAffairs/openai-gemini">GitHub - PublicAffairs/openai-gemini：Gemini ➜ OpenAI API 代理。无服务器！</a></p><p>选择部署到 Cloudflare</p><p>填写帐户 ID和API 令牌</p><p>创建令牌</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_5bf52aa16d537ce3adee50f2790fc01d.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_5bf52aa16d537ce3adee50f2790fc01d.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_838ff6b4bc0693271bdad844b12cd73a.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_838ff6b4bc0693271bdad844b12cd73a.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_c9772594d9fde2f711d667b7815ca61b.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_c9772594d9fde2f711d667b7815ca61b.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_e79bd60f237d0a11fe07aec6cfd42aeb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_e79bd60f237d0a11fe07aec6cfd42aeb.png"></p><p>填写帐户 ID和API 令牌</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_0e3245451a5d133b41a3c04f3b19e5d7.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_0e3245451a5d133b41a3c04f3b19e5d7.png"></p><p>fork到自己的储存库并开启Github action功能</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_e6597f005cfa381b83274109599931a5.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_e6597f005cfa381b83274109599931a5.png"></p><p>完成</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_9e1894c0f73a7d5980e5852e999cb36f.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_9e1894c0f73a7d5980e5852e999cb36f.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_ce63eae69a071ff271886200b733aeb9.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_ce63eae69a071ff271886200b733aeb9.png"></p><p>完成后进入到cloudflare 的Worker页面</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_20572f92e813c99565556a29e5dff5e6.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_20572f92e813c99565556a29e5dff5e6.png"></p><p>找到刚刚创建的gemini</p><p>在设置中为其添加一个域名</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_22a58c37e0f588d0f69113636e0d3bd3.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_22a58c37e0f588d0f69113636e0d3bd3.png"></p><p>##Gemini API申请</p><p>现在中转服务已经部署，接下来是Gemini API申请: <a href="https://aistudio.google.com/">https://aistudio.google.com/</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_c7683203cc67aa5b0cda54417e4befcb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_c7683203cc67aa5b0cda54417e4befcb.png"></p><p>列出可用模型</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_21c448744a9da42af16bf6441d75060a.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_22/image_21c448744a9da42af16bf6441d75060a.png"></p>]]></content>
    
    
    <summary type="html">Gemini 转OpenAI API格式

GitHub - PublicAffairs/openai-gemini：Gemini ➜ OpenAI API 代理。无服务器！
[https://github.com/PublicAffairs/openai-gemini]

选择部署到 Cloudflare

填写帐户 ID和API 令牌

创建令牌</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>PVE安装Home Assistant</title>
    <link href="https://polar-bear.eu.org/2025/01/07/pve-an-zhuang-home-assistant/"/>
    <id>https://polar-bear.eu.org/2025/01/07/pve-an-zhuang-home-assistant/</id>
    <published>2025-01-07T23:34:05.254Z</published>
    <updated>2025-01-07T23:40:44.104Z</updated>
    
    <content type="html"><![CDATA[<h2 id="PVE安装Home-Assistant">PVE安装Home Assistant</h2><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_75d390aebb9b1249909c3ef63b0fe04c.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_75d390aebb9b1249909c3ef63b0fe04c.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_2c515e1a0530a7fa7674bf2820a719c0.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_2c515e1a0530a7fa7674bf2820a719c0.png"></p><p>接下来默认即可</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_54b8d1a75ee12d62a3edcc3a25bc8a02.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_54b8d1a75ee12d62a3edcc3a25bc8a02.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_d0dd9e16773cc0931662ec69c2666ad1.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_d0dd9e16773cc0931662ec69c2666ad1.png"></p><p>类型选host</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_314931e3007e0e0b9fb2795e3d071c47.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_314931e3007e0e0b9fb2795e3d071c47.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_8dc4a644a24370b10707d1d5402e6300.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_8dc4a644a24370b10707d1d5402e6300.png"></p><p>半虚拟化、E1000、直通，感觉半虚拟化和直通差不多</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_186b2ab757f6573d837057ee6dc0adce.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_186b2ab757f6573d837057ee6dc0adce.png"></p><p>分离并删除硬盘</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_c8aeb7687f675424c783381599f94e26.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_c8aeb7687f675424c783381599f94e26.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_d4f1f17df7cf7a9741c95bbaa6352f78.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_d4f1f17df7cf7a9741c95bbaa6352f78.png"></p><p>调整BIOS为UEFI模式，这个是HassOS要求的</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_88f3740c446748c903601ebae9bc580f.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_88f3740c446748c903601ebae9bc580f.png"></p><p>下载HA虚拟机文件<a href="https://www.home-assistant.io/installation/alternative">替代方案 - Home Assistant</a></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_b376524d2b7bca1fc0f3a5d0c85afb45.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_b376524d2b7bca1fc0f3a5d0c85afb45.png"></p><p>下载解压得到qcow2文件传到PVE里面</p><p>连接到PVE shell，将文件传到/tmp文件夹下</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_ea518e28b17a99dd1721cfa536fbc405.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_ea518e28b17a99dd1721cfa536fbc405.png"></p><p>接下来进入tmp目录,向104（HA）虚拟机导入磁盘</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /tmp</span><br><span class="line">qm importdisk 104 haos_ova-14.1.qcow2 local-lvm</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_ed7e0f70eed5e5bdda2a11b4da077419.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_ed7e0f70eed5e5bdda2a11b4da077419.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_041ae76d87838d9b2c205fc27735e425.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_041ae76d87838d9b2c205fc27735e425.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_bf6788c3c1ece3c02b694696c523c7f2.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_bf6788c3c1ece3c02b694696c523c7f2.png"></p><p>出现一个未使用的磁盘，双击它添加</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_5282fe4eec755c59cb3dbd48ee5a83d9.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_5282fe4eec755c59cb3dbd48ee5a83d9.png"></p><p>在选择-引导顺序里面将硬盘设为第一位</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_e535d0ae42a21b0d684ee21150f9b29e.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_e535d0ae42a21b0d684ee21150f9b29e.png"></p><p>现在可以启动虚拟机了</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_86c8d5b2e8da983b026f4f0bc6b64296.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_86c8d5b2e8da983b026f4f0bc6b64296.png"></p><p>等待系统最后安装完成，打开网页端，浏览器里面输入这个网址并打开：<a href="http://homeassistant.local:8123">http://homeassistant.local:8123</a></p>]]></content>
    
    
    <summary type="html">PVE安装HOME ASSISTANT
https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_75d390aebb9b1249909c3ef63b0fe04c.png [https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_08/image_75d390aebb9b1249909c3ef63b0fe04c.png]</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Docker安装HomeAssistant</title>
    <link href="https://polar-bear.eu.org/2025/01/06/docker-an-zhuang-homeassistant/"/>
    <id>https://polar-bear.eu.org/2025/01/06/docker-an-zhuang-homeassistant/</id>
    <published>2025-01-06T07:10:34.535Z</published>
    <updated>2025-01-07T23:24:49.326Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Docker安装HomeAssistant">Docker安装HomeAssistant</h2><blockquote><p>Docker安装不支持附件组件</p></blockquote><p>直接从docker官方直接拉取镜像，可能会遇到网络问题</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">homeassistant/home-assistant</span><br></pre></td></tr></table></figure><p>可以从镜像地址下载</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ghcr.io/home-assistant/home-assistant:stable</span><br></pre></td></tr></table></figure><p>Docker安装可兼容多平台，但是此方法安装HA<strong>无权访问附加组件</strong></p><p>如图，在飞牛OS上安装</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_06/image_3b73082d3e6976149db3b8d0b0e77e20.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_06/image_3b73082d3e6976149db3b8d0b0e77e20.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">docker run -d \</span><br><span class="line">  --name homeassistant \</span><br><span class="line">  --privileged \</span><br><span class="line">  --restart=unless-stopped \</span><br><span class="line">  -e TZ=Asia/Shanghai \</span><br><span class="line">  -v /data/homeassistant:/config \</span><br><span class="line">  --network=host \</span><br><span class="line">  homeassistant/home-assistant</span><br></pre></td></tr></table></figure><p><code>-v /data/homeassistant:/config</code>这一项需要根据自己实际情况修改，即把自己物理机某文件夹挂载到容器内，我是建了个文件夹<code>/data/homeassistant</code>来存放HA的文件</p><p>端口8123映射到本地8123</p><p>创建一个homeasststant的文件夹，将创建的homeasststant 文件路径，载到容器的 /config 路径</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_590cac76150ce6bc8eb19445d3863fb7.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_590cac76150ce6bc8eb19445d3863fb7.png"></p><p>添加环境变量 TZ，将时区设置为 Asia/Shanghai</p><p>网络设置成host</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_546059ff67f8a60f94b8dae55bad6937.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_546059ff67f8a60f94b8dae55bad6937.png"></p><p>访问<strong><a href="http://ip:8123">http://ip:8123</a></strong>即可</p><p>在 homeasststant 目录下创建一个名为 custom_components 的文件夹</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_077119a4dd4a8de0bc048bd7b4b489c3.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_077119a4dd4a8de0bc048bd7b4b489c3.png"></p><p>下载HACS 文件上传并解压到该目录中</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">## 下载地址</span><br><span class="line">https://github.com/hacs/integration/releases/tag/2.0.1</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_a5f34dea07bc3c26653c8b9d9b1c8376.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_a5f34dea07bc3c26653c8b9d9b1c8376.png"></p><p>重启 Home Assistant.</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_81faaee2c3944615f90e1c2b877155b6.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_81faaee2c3944615f90e1c2b877155b6.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_6c7c7f7aff0960a6196e6b6145b27ecb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_6c7c7f7aff0960a6196e6b6145b27ecb.png"></p><p>点击 设置-设备与服务</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_40431f886ece627b9e08b68c4fd35255.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_40431f886ece627b9e08b68c4fd35255.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_533bfae96458c9327796bfb0fc7483f3.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_533bfae96458c9327796bfb0fc7483f3.png"></p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_00b1811e3c914d095888a37a0aeabfed.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_00b1811e3c914d095888a37a0aeabfed.png"></p><p>全选，提交</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_048d849d90cd2f4178f342d9f1549082.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_048d849d90cd2f4178f342d9f1549082.png"></p><p>如果点提交之后弹出如下对话框，请直接重启nas设备即可正常往下设置</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_adb47d5ce5b219de9653b08697365f92.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_adb47d5ce5b219de9653b08697365f92.png"></p><p>加载一会，弹窗对话框，点击第一个链接去验证github账号</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_becdfac8f6cdb8e0e38a00feb038fe2e.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_becdfac8f6cdb8e0e38a00feb038fe2e.png"></p><p>同意授权即可</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_f451721c8ddddadeb45275cc82e2cff7.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2025/01_07/image_f451721c8ddddadeb45275cc82e2cff7.png"></p>]]></content>
    
    
    <summary type="html">DOCKER安装HOMEASSISTANT
Docker安装不支持附件组件

直接从docker官方直接拉取镜像，可能会遇到网络问题

1


hom</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Git 使用教程</title>
    <link href="https://polar-bear.eu.org/2024/11/21/git-shi-yong-jiao-cheng/"/>
    <id>https://polar-bear.eu.org/2024/11/21/git-shi-yong-jiao-cheng/</id>
    <published>2024-11-21T03:06:52.058Z</published>
    <updated>2024-11-21T03:35:24.105Z</updated>
    
    <content type="html"><![CDATA[<h2 id="常规操作">常规操作</h2><p>开始前我们需要先设置提交的用户信息，包括用户名和邮箱：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git config --global user.name <span class="string">&#x27;name&#x27;</span></span><br><span class="line">$ git config --global user.email <span class="built_in">test</span>@test.com</span><br></pre></td></tr></table></figure><h3 id="创建版本库">创建版本库</h3><p>首先，打开终端或命令行界面，进入要创建版本库的目录下。</p><p>接着，使用以下命令初始化一个空的 Git 仓库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure><p>然后，将需要管理的文件添加到暂存区：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add</span><br></pre></td></tr></table></figure><p>你也可以使用以下命令一次性将所有变更添加到暂存区：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br></pre></td></tr></table></figure><p>接下来，提交暂存区中的变更到本地仓库，并添加一个描述信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&#x27;第一次版本提交&#x27;</span></span><br></pre></td></tr></table></figure><p>现在，你已经成功地创建了一个版本库。你可以使用其他 Git 命令来管理它，例如：</p><blockquote><p>git status：查看当前工作区和暂存区的状态。<br>git log：查看提交记录。<br>git branch：管理分支。<br>git remote：管理远程仓库。</p></blockquote><h2 id="远程仓库">远程仓库</h2><h3 id="如何添加远程仓库">如何添加远程仓库</h3><p>要将本地代码库连接到远程仓库，可以使用以下git命令：</p><p>首先，将本地代码库初始化为Git仓库（如果尚未完成）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure><p>添加远程仓库的URL，其中<remote-name>是自定义名称，<remote-url>是远程仓库的URL：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add &lt;remote-name&gt; &lt;remote-url&gt;</span><br></pre></td></tr></table></figure><p>可以使用以下命令确认远程仓库是否已成功添加：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote -v</span><br></pre></td></tr></table></figure><p>此后，您就可以使用 <code>git push</code>命令将代码推送到远程仓库，或使用 <code>git pull</code>命令从远程仓库拉取代码。</p><h3 id="从远程库克隆">从远程库克隆</h3><p>要从远程仓库克隆代码到本地，可以使用以下git命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> &lt;remote-url&gt;</span><br></pre></td></tr></table></figure><p>其中<remote-url>是远程仓库的URL。执行此命令后，Git将在当前目录下创建一个新目录，其中包含克隆的代码库副本。如果想指定不同的目录名，可以将目录名作为可选参数添加到命令中：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> &lt;remote-url&gt; &lt;directory-name&gt;</span><br></pre></td></tr></table></figure><h2 id="创建与合并分支">创建与合并分支</h2><p>创建一个新的分支可以使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch &lt;branch_name&gt;</span><br></pre></td></tr></table></figure><p>这将在当前所在的提交上创建一个名为 &lt;branch_name&gt; 的新分支。</p><p>要切换到新创建的分支，可以使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout &lt;branch_name&gt;</span><br></pre></td></tr></table></figure><p>创建并立即切换到该分支，可以使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b &lt;branch_name&gt;</span><br></pre></td></tr></table></figure><p>合并分支可以使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git merge &lt;branch_name&gt;</span><br></pre></td></tr></table></figure><p>这将将 &lt;branch_name&gt; 分支中的更改合并到当前分支。</p><h2 id="推送分支">推送分支</h2><p>在 Git 中，推送分支指将本地的分支提交到远程仓库中，使得其他团队成员可以访问和获取该分支的代码。以下是在 Git 中推送分支的一些常用命令：</p><p>推送当前分支到远程仓库，并与远程分支关联：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push -u origin &lt;branch-name&gt;</span><br></pre></td></tr></table></figure><p>推送当前分支到远程仓库，并与远程分支合并：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin &lt;branch-name&gt;</span><br></pre></td></tr></table></figure><p>强制推送当前分支到远程仓库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push -f origin &lt;branch-name&gt;</span><br></pre></td></tr></table></figure><p>删除远程分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin :&lt;branch-name&gt;</span><br></pre></td></tr></table></figure><p>或</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push --delete origin &lt;branch-name&gt;</span><br></pre></td></tr></table></figure><p>在推送分支时，通常会遇到冲突等问题。如果发生冲突，需要先解决冲突，然后再进行推送。</p><h2 id="处理冲突">处理冲突</h2><p>当两个分支上的代码修改了同一部分，并且尝试将这两个分支合并时，就会发生代码冲突。Git提供了以下步骤来解决冲突：</p><p>运行 <code>git status</code> 命令查看哪些文件包含冲突。<br>编辑有冲突的文件，手动解决文件中的冲突。<br>对编辑后的文件进行 <code>git add</code>，标记为已解决冲突的文件。<br>使用 <code>git commit</code> 提交更改，Git 会自动生成一个合并提交，其中包含各自分支中的更改。<br>注意：在解决冲突前，最好先备份当前的代码状态，以免不小心破坏代码库。另外，在处理冲突之前，可以通过运行 <code>git diff</code> 命令来查看冲突的源代码，以便更好地理解要解决的问题。</p><h3 id="分支管理策略">分支管理策略</h3><p>在 Git 中，常见的分支管理策略包括以下几个方面：</p><ul><li>主分支：主分支通常是最稳定的分支，用于发布生产版本。在 Git 中，主分支通常是 master 分支或者 main 分支。</li><li>开发分支：开发分支通常从主分支派生而来，在其上进行新功能或修复错误的开发。在 Git 中，通常使用 develop 分支作为开发分支。</li><li>特性分支：特性分支是为了开发单独的功能而创建的分支。这些分支通常从开发分支派生而来，并在实现目标后被合并回开发分支。在 Git 中，通常使用 feature/ 分支命名约定来表示特性分支。</li><li>发布分支：发布分支是用于准备发布版本的分支，通常从主分支派生而来。这些分支应该包含与发布相关的所有更改，并且应该经过全面测试和审核后再合并回主分支。在 Git 中，通常使用 release/ 分支命名约定来表示发布分支。</li><li>热修复分支：热修复分支通常用于快速修复紧急问题，例如安全漏洞或崩溃。这些分支通常从主分支派生而来，并且只包含必要的更改。在 Git 中，通常使用 hotfix/ 分支命名约定来表示热修复分支。</li></ul><h2 id="具体操作">具体操作</h2><h3 id="克隆仓库">克隆仓库</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> git@github.com:TOE-RC/robotmaster-c.git</span><br><span class="line">git <span class="built_in">clone</span> &lt;remote-url&gt;</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_5f052876d9b219f42b9a86fb47c60eac.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_5f052876d9b219f42b9a86fb47c60eac.png"></p><h3 id="提交仓库">提交仓库</h3><p>在本地更改并且保存后，使用这条命令一次性将所有变更添加到暂存区</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br></pre></td></tr></table></figure><p>提交暂存区中的变更到本地仓库，并添加一个描述信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&#x27;第一次版本提交&#x27;</span></span><br></pre></td></tr></table></figure><p>提交到远程仓库</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push</span><br></pre></td></tr></table></figure><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_71bdf1e5c87f0be8a689fcfc43f8b11c.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_71bdf1e5c87f0be8a689fcfc43f8b11c.png"></p><h3 id="处理冲突-v2">处理冲突</h3><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_7250aa9512338a42987cd48ae6584453.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_7250aa9512338a42987cd48ae6584453.png"></p><p>在你提交之前假设有其他人提交了新的版本，这时候提交就会出现冲突错误</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_cc8aa3ad57e9d7df94390d124267cfdb.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_cc8aa3ad57e9d7df94390d124267cfdb.png"></p><p>建议使用VSCode自带的插件</p><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_13388c15ab1f627389c004600f703318.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_13388c15ab1f627389c004600f703318.png"></p><h3 id="覆盖仓库">覆盖仓库</h3><p><img src="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_2e3cee40df1501f13914050a36fe0e26.png" alt="https://cdn.ziyourufeng.eu.org/51hhh/img_bed/main/img/2024/11_21/image_2e3cee40df1501f13914050a36fe0e26.png"></p><p>本地初始化Git文件夹 <code>git init</code>，绑定远程仓库 <code>git remote add robotmaster-c git@github.com:TOE-RC/robotmaster-c.git</code>，检测仓库是否成功添加 <code>git remote -v</code>。</p><p>这里 <code>git pull</code>出现了错误，提示如果你想要拉取并合并特定的分支，你需要指定远程仓库和分支名 <code>git pull remote branch</code>，或者为当前分支设置跟踪信息，之后，你就可以简单地使用 <code>git pull</code> 来拉取最新的代码，而不需要每次都指定远程仓库和分支。</p><p>首先先建立本地分支进行第一次提交</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br><span class="line">git commit -m <span class="string">&quot;Initial commit&quot;</span></span><br></pre></td></tr></table></figure><p>获取远程仓库的所有分支信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git fetch</span><br></pre></td></tr></table></figure><p>设置跟踪远程 <code>main</code> 分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git branch --set-upstream-to=robotmaster-c/main master</span><br><span class="line">git branch --set-upstream-to=仓库名/仓库分支 本地分支</span><br></pre></td></tr></table></figure><p>此时即可 <code>git pull --allow-unrelated-histories</code></p>]]></content>
    
    
    <summary type="html">常规操作
开始前我们需要先设置提交的用户信息，包括用户名和邮箱：

1
2


$ git config --global user.name &#39;na</summary>
    
    
    
    
  </entry>
  
</feed>
