├── .gitignore ├── 01.base ├── 01.env.md ├── 02.base.md ├── 03.linear.md ├── 04.higher.md ├── 05.odds.md ├── README.md └── images │ ├── 1725105003545.png │ ├── 1725105639726.png │ ├── 1725110469061.jpg │ ├── 1725148068180(1).png │ ├── 1725148940379.png │ ├── 1725148968981(1).png │ ├── 1725149018283.png │ ├── 1725150688028.png │ ├── 389b1a036ebf0d36c4c2233c49c3556.jpg │ ├── e951f1d6da6d09477880fc13f655b23.jpg │ ├── image-20240831193113478.png │ ├── image-20240831193501897.png │ ├── image-20240831193543224.png │ ├── image-20240831194432476.png │ ├── image-20240831195641685.png │ ├── image-20240831195802036.png │ ├── image-20240831220117612.png │ ├── image-20240901072421293.png │ ├── image-20240901072824863.png │ ├── image-20240901080538372.png │ ├── image-20240901093307337.png │ ├── image-20240901111744905.png │ ├── image-20240901112046630.png │ ├── image-20240901113934658.png │ ├── image-20240901114708887.png │ ├── image-20240901120654336.png │ ├── image-20240901122532080.png │ ├── image-20240901122822715.png │ ├── image-20240901122852869.png │ ├── image-20240907191647155.png │ ├── image-20240907192106915.png │ ├── image-20240910115046782.png │ ├── image-20240910121926988.png │ ├── image-20241103100209574.png │ ├── image-20241103100345461.png │ ├── image-20241103121849440.png │ ├── image-20241103124606702.png │ ├── image-20241103125947540.png │ ├── image-20241103203955447.png │ ├── image-20241103204339232.png │ ├── image-20241106225939512.png │ ├── image-20241108071154361.png │ ├── image-20241108071828663.png │ ├── image-20241108205118094.png │ ├── image-20241108205142069.png │ ├── image-20241108211302187.png │ ├── image-20241108212312023.png │ ├── image-20241108212445350.png │ ├── image-20241108220711380.png │ ├── image-20241108221035111.png │ ├── image-20241108221229577.png │ ├── image-20241108222744862.png │ ├── image-20241108223336564.png │ ├── image-20241109024627974.png │ ├── image-20241109031032328.png │ ├── image-20241109031356478.png │ ├── image-20241109150817967.png │ ├── image-20241109154450656.png │ ├── image-20241110092405151.png │ ├── image-20241110092447001.png │ ├── image-20241110092718306.png │ ├── image-20241110095216295.png │ ├── image-20241110095607086.png │ ├── image-20241110095620201.png │ ├── image-20241110101708796.png │ ├── image-20241110102423654.png │ ├── image-20241110103428544.png │ ├── image-20241110103552859.png │ ├── image-20241110105635460.png │ ├── image-20241110105928305.png │ ├── image-20241110110700577.png │ ├── image-20241110135308642.png │ ├── image-20241110140743986.png │ ├── image-20241110142551689.png │ ├── image-20241110143455304.png │ ├── image-20241110145138140.png │ ├── image-20241110145256864.png │ ├── image-20241110151831018.png │ ├── image-20241110154210542.png │ ├── image-20241110161833098.png │ ├── image-20241110164906093.png │ ├── image-20241110165653935.png │ ├── image-20241110170325278.png │ ├── image-20241111214830663.png │ ├── image-20241111214859696.png │ ├── image-20241112112037795.png │ ├── image-20241113003705839.png │ ├── image-20241113004516264.png │ ├── image-20241113005446796.png │ ├── image-20241113213533007.png │ ├── image-20241113215104872.png │ ├── image-20241113215631143.png │ ├── image-20241113215851509.png │ ├── image-20241114203340853.png │ ├── image-20241114204528433.png │ ├── image-20241114212937793.png │ ├── image-20241114220105658.png │ ├── image-20241114222647137.png │ ├── image-20241114222945545.png │ ├── image-20241114223315609.png │ ├── image-20241114223740021.png │ ├── image-20241115204555682.png │ ├── image-20241115205039736.png │ ├── image-20241117092736536.png │ ├── image-20241117093320424.png │ ├── image-20241117094156647.png │ └── image-20241117094843430.png ├── 02.start ├── 01.neural_network.md ├── 02.start_torch.md ├── 03.xl.md ├── 04.models.md ├── README.md └── images │ ├── 0.jpg │ ├── 1.jpg │ ├── 6.jpg │ ├── bobby.jpg │ ├── boddy_preprocessed.jpg │ ├── boddy_preprocessed_1.jpg │ ├── boddy_preprocessed_2.jpg │ ├── image-20241130095650256.png │ ├── image-20241130141303272.png │ ├── image-20241201075420519.png │ ├── image-20241201080533249.png │ ├── image-20241202120839339.png │ ├── image-20241204201648009.png │ ├── image-20241204203025017.png │ ├── image-20241204204305065.png │ ├── image-20241214093654062.png │ ├── image-20241214094330314.png │ ├── image-20241214094828150.png │ ├── image-20241214095337053.png │ ├── image-20241218003140880.png │ ├── image-20250204215615584.png │ ├── image-20250205084740229.png │ ├── image-20250205090040316.png │ ├── image-20250205141415174.png │ ├── image-20250205144041513.png │ └── tmpq43su1.tmp.png ├── 03.image ├── README.md ├── Untitled 1.md ├── dcgan_faces_tutorial.md ├── frcnn.md ├── images │ ├── 1739107119297.png │ ├── 1739449592381.png │ ├── 1739665463017.png │ ├── airplane.jpg │ ├── cat.jpg │ ├── copy-button.svg+xml │ ├── dcgan_generator.png │ ├── dog.jpg │ ├── fake_images.jpg │ ├── image-20250210183009016.png │ ├── image-20250210205818778.png │ ├── image-20250210214910109.png │ ├── image-20250213202802853.png │ ├── image-20250213203259114.png │ ├── image-20250213210939996.png │ ├── image-20250215205033982.png │ └── image-20250216092937641.png └── vgg.md ├── 04.nlp └── README.md ├── Dockerfile ├── LICENSE ├── README.md ├── SUMMARY.md ├── book.json ├── images ├── 1725105003545.png ├── 1725105639726.png ├── 1725110469061.jpg ├── 1725148068180(1).png ├── 1725148940379.png ├── 1725148968981(1).png ├── 1725149018283.png ├── 1725150688028.png ├── image-20240831193113478.png ├── image-20240831193501897.png ├── image-20240831193543224.png ├── image-20240831194432476.png ├── image-20240831195641685.png ├── image-20240831195802036.png ├── image-20240831220117612.png ├── image-20240901072421293.png ├── image-20240901072824863.png ├── image-20240901080538372.png ├── image-20240901093307337.png ├── image-20240901111744905.png ├── image-20240901112046630.png ├── image-20240901113934658.png ├── image-20240901114708887.png ├── image-20240901120654336.png ├── image-20240901122532080.png ├── image-20240901122822715.png ├── image-20240901122852869.png ├── image-20240907191647155.png ├── image-20240907192106915.png └── logo.png ├── init_gitbook.bat ├── other ├── 01.1.md └── README.md ├── package-lock.json ├── package.json └── undefined.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | 400 | _book/* -------------------------------------------------------------------------------- /01.base/01.env.md: -------------------------------------------------------------------------------- 1 | # 1.1 环境配置 2 | 3 | 4 | 5 | 学习模型开发时,搭建环境可能会碰到很多曲折,这里提供一些通用的环境搭建安装方法,以便读者能够快速搭建出一套 AI 模型开发调试环境。 6 | 7 |
8 | 9 | ### 安装显卡驱动和开发库 10 | 11 | 本文只讲述 NVIDIA 显卡驱动的安装方法。 12 | 13 | NVIDIA 显卡有多个系列,常用的有 Tensor 和 GeForce RTX 系列,两类显卡的驱动安装方式不一样,下面的章节会单独介绍如何安装驱动。 14 | 15 |
16 | 17 | 第一步,检测电脑是否正确识别显卡或已安装驱动。 18 | 19 | 打开设备管理器,点击 `显示适配器` ,查看设备列表是否存在显卡。 20 | 21 |
22 | 23 | ![image-20240831193543224](images/image-20240831193543224.png) 24 | 25 | 26 | 27 | 28 | 29 | ![image-20240831193501897](images/image-20240831193501897.png) 30 | 31 |
32 | 33 | 34 | 35 | 如果电脑已经识别出显卡,可以通过 NVIDIA GeForce Experience 或者在其它驱动管理工具更新到最新版本的驱动程序。 36 | 37 |
38 | 39 | ![1725110469061](images/1725110469061.jpg) 40 | 41 |
42 | 43 | 或者直接到官方驱动页面搜索显卡型号要安装的驱动程序,Nvida 官方驱动搜索下载页面:https://www.nvidia.cn/drivers/lookup/ 44 | 45 |
46 | 47 | ![image-20240831194432476](images/image-20240831194432476.png) 48 | 49 |
50 | 51 | #### 对于 Tensor 系列显卡 52 | 53 | 例如在 Azure 等云平台创建 GPU 服务器后,如果显卡是 Tensor ,刚开机时可能识别不出显卡,需要先安装驱动之后才能显示显卡设备。 54 | 55 |
56 | 57 | Windows 可参考该链接安装:https://learn.microsoft.com/zh-CN/azure/virtual-machines/windows/n-series-driver-setup 58 | 59 | Linux 可参考该链接安装:https://learn.microsoft.com/zh-CN/azure/virtual-machines/linux/n-series-driver-setup 60 | 61 |
62 | 63 | 对于 Windows ,安装方法比较简单,只需要按照文档下载 GRID 程序安装包即可。 64 | 65 | ![image-20240831193113478](images/image-20240831193113478.png) 66 | 67 |
68 | 69 | #### 对于 N 卡 70 | 71 | 对于 GeForce RTX 4060TI 、GeForce RTX 4070 等显卡,可以直接到官方下载驱动安装器: 72 | 73 | https://www.nvidia.cn/geforce/drivers/ 74 | 75 |
76 | 77 | 一般来说,家用主机的出厂时都会安装好的驱动的。 78 | 79 |
80 | 81 | ### 安装 CUDA 和 cuDNN 82 | 83 | ![image-20240831195641685](images/image-20240831195641685.png) 84 | 85 |
86 | 87 | CUDA 是 NVIDIA 专为图形处理单元 (GPU) 上的通用计算开发的并行计算平台和编程模型。借助 CUDA,开发者能够利用 GPU 的强大性能显著加速计算应用。 88 | 89 | 简单来说 CUDA 就是支持 CPU 分发和 GPU 并行计算的编程模型,为了使用 CUDA ,需要安装开发工具包。 90 | 91 | > CUDA 介绍: 92 | > 93 | > https://developer.nvidia.cn/cuda-zone 94 | > 95 | > https://developer.nvidia.com/zh-cn/blog/cuda-intro-cn/ 96 | 97 |
98 | 99 | CUDA 安装包下载地址:https://developer.nvidia.com/cuda-downloads 100 | 101 | 下打开安装包,根据提示操作安装即可,简洁安装会安装 C 盘,高级安装可以自定义安装位置,建议使用简洁安装,以免出现额外情况。 102 | 103 | ![1725105003545](images/1725105003545.png) 104 | 105 |
106 | 107 | 安装完成后,环境变量会多出两条记录: 108 | 109 | ![image-20240831195802036](images/image-20240831195802036.png) 110 | 111 |
112 | 113 | cuDNN 是基于 GPU 的深度学习加速库,下载文件后是一个压缩包。 114 | 115 | 下载地址:https://developer.nvidia.com/cudnn-downloads 116 | 117 | ![1725105639726](images/1725105639726.png) 118 | 119 |
120 | 121 | 打开 `C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\`,找到版本目录,或者通过环境变量 `CUDA_PATH` 找到安装目录,将 cuDNN 压缩包的内容复制合并到 CUDA 目录。 122 | 123 | ![image-20240831220117612](images/image-20240831220117612.png) 124 | 125 |
126 | 127 | 最后将 bin、lib、`lib\x64`、include、libnvvp 五个目录添加到环境变量 Path 中。 128 | 129 | > 也不知道具体到底需要多少环境变量,加就是了。 130 | 131 |
132 | 133 | ### 安装 Miniconda 134 | 135 | Miniconda 是一个 Python 包管理器,能够在系统中创建多个环境隔离的 Python 环境。 136 | 137 | 下载地址:https://docs.anaconda.com/miniconda/ 138 | 139 |
140 | 141 | 下载完成后,搜索 miniconda3 快捷菜单,以管理员身份运行,点击可以打开控制台,菜单列表会有 cmd 和 powershell 两个快捷链接,建议使用 powershell 入口。 142 | 143 | > 后续执行 conda 命令,都要使用管理员身份运行。 144 | 145 | ![image-20240901072421293](images/image-20240901072421293.png) 146 | 147 |
148 | 149 | 配置国内源加速下载: 150 | 151 | ```bash 152 | conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ 153 | ``` 154 | 155 |
156 | 157 | 执行 `conda env list` 目录查看默认环境安装目录。 158 | 159 | ![image-20240901072824863](images/image-20240901072824863.png) 160 | 161 |
162 | 163 | 如果电脑已经安装过 Python 并且添加了环境变量,则不要将 `G:\ProgramData\miniconda3` 添加到环境变量中,因为这样会导致环境缭乱。 164 | 165 | 如果电脑还没有安装过 Python ,则可以直接将 `G:\ProgramData\miniconda3` 、`G:\ProgramData\miniconda3\Scripts` 添加到环境变量中。 166 | 167 |
168 | 169 | 笔者电脑卸载了手动安装的 Python,只使用 miniconda3 提供的环境。 170 | 171 |
172 | 173 | 如果 Python、pip 使用的是自行安装的,直接执行命令安装依赖包的时候,跟 miniconda3 环境是隔离的。如果需要在 miniconda3 环境安装依赖包,需要打开 miniconda3 控制台执行 pip 命令,这样安装的包才会出现在 miniconda3 环境中。 174 | 175 | 一个环境中安装依赖包后,不同的项目可以共用已下载的依赖包,不需要每个项目单独下载一次。 176 | 177 |
178 | 179 | ### 安装 PyTorch 和 Transformers 180 | 181 | Flax、PyTorch 或 TensorFlow 都是深度学习框架,而 Transformers 底层可以使用 Flax、PyTorch 或 TensorFlow 深度学习框架,实现模型加载、训练等功能。 182 | 183 |
184 | 185 | PyTorch 安装参考文档:https://pytorch.org/get-started/locally/ 186 | 187 |
188 | 189 | 可以安装 GPU 版本(CUDA)或 CPU 版本,然后复制下方提示的安装命令。 190 | 191 | ![1725148068180(1)](images/1725148068180(1).png) 192 | 193 |
194 | 195 | ```bash 196 | conda install pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia 197 | ``` 198 | 199 |
200 | 201 | 然后还需要执行命令安装 Transformers 和一些依赖库。 202 | 203 | ```bash 204 | pip install protobuf 'transformers>=4.30.2' cpm_kernels 'torch>=2.0' gradio mdtex2html sentencepiece accelerate 205 | ``` 206 | 207 |
208 | 209 | ### 使用 Modelscope 下载加载模型 210 | 211 | ModelScope 是阿里云主导的一个国内 AI 模型社区,提供了各类模型和数据集以及开发工具库,由于 huggingface 上手难度稍大以及国外网络原因,这里使用 Modelscope 下载和加载模型。 212 | 213 |
214 | 215 | 安装 modelscope: 216 | 217 | ```bash 218 | pip install modelscope 219 | ``` 220 | 221 |
222 | 223 | ### PyCharm 项目配置 224 | 225 | PyCharm 是最常用的 Python 编程工具,因此这里讲解如何在 PyCharm 中配置 miniconda3 环境。 226 | 227 |
228 | 229 | 打开 PyCharm ,在设置中添加 miniconda3 的环境,步骤如图所示。 230 | 231 |
232 | 233 | ![1725148940379](images/1725148940379.png) 234 | 235 | ![1725148968981(1)](images/1725148968981(1).png) 236 | 237 |
238 | 239 | 然后创建一个项目,在项目中选择基于 conda 的环境。 240 | 241 |
242 | 243 | ![1725149018283](images/1725149018283.png) 244 | 245 |
246 | 247 | ### 模型加载和对话 248 | 249 | 在项目目录下创建 main.py 文件。 250 | 251 |
252 | 253 | ![image-20240901080538372](images/image-20240901080538372.png) 254 | 255 |
256 | 257 | 将以下代码贴到 main.py,然后运行代码,会自动下载模型、加载模型和对话。 258 | 259 |
260 | 261 | ```python 262 | from modelscope import AutoTokenizer, AutoModel, snapshot_download 263 | 264 | # 下载模型 265 | # ZhipuAI/chatglm3-6b 模型仓库 266 | # D:/modelscope 模型文件缓存存放目录 267 | model_dir = snapshot_download("ZhipuAI/chatglm3-6b",cache_dir="D:/modelscope", revision="v1.0.0") 268 | 269 | # 加载模型 270 | # float 是 32,half 是16 位浮点数,内存可以减少一半 271 | tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True) 272 | model = AutoModel.from_pretrained(model_dir, trust_remote_code=True).half().cuda() 273 | model = model.eval() 274 | 275 | # 开始对话 276 | response, history = model.chat(tokenizer, "你好", history=[]) 277 | print(response) 278 | response, history = model.chat(tokenizer, "晚上睡不着应该怎么办", history=history) 279 | print(response) 280 | 281 | ``` 282 | 283 |
284 | 285 | ![1725150688028](images/1725150688028.png) 286 | 287 |
288 | 289 | `"ZhipuAI/chatglm3-6b"` 指的是 `ZhipuAI` 仓库的 `chatglm3-6b` 模型,可以通过 ModelScope 查看社区已上传的各类模型: 290 | 291 | https://www.modelscope.cn/models 292 | 293 |
294 | 295 | `revision="v1.0.0"` 下载版本号跟仓库分支名称一致,可以填写不同分支名称下载不同的版本。 296 | 297 | ![image-20240901093307337](images/image-20240901093307337.png) 298 | 299 |
300 | 301 | ### CPU 和 GPU 302 | 303 | 如果出现以下报错,可能安装的是 CPU 而不是 GPU 版本的 PyTorch。 304 | 305 | ``` 306 | raise AssertionError("Torch not compiled with CUDA enabled") 307 | AssertionError: Torch not compiled with CUDA enabled 308 | ``` 309 | 310 | ![image-20240901111744905](images/image-20240901111744905.png) 311 | 312 |
313 | 314 | 执行代码: 315 | 316 | ```python 317 | import torch 318 | print(torch.__version__) 319 | ``` 320 | 321 | ![image-20240901113934658](images/image-20240901113934658.png) 322 | 323 |
324 | 325 | 按经验,如果使用了 pip 安装相关库,而不是使用 conda 命令安装的,需要执行以下命令卸载 pytorch: 326 | 327 | ```bash 328 | pip uninstall torch torchvision torchaudio 329 | ``` 330 | 331 | ```bash 332 | conda uninstall pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia 333 | ``` 334 | 335 |
336 | 337 | 然后执行命令重新安装 pytorch: 338 | 339 | ```bash 340 | conda install pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia 341 | ``` 342 | 343 |
344 | 345 | 重新执行命令后即可正常: 346 | 347 | ![image-20240901120654336](images/image-20240901120654336.png) 348 | 349 |
350 | 351 | ### transformers 版本错误 352 | 353 | 由于安装各类库的时候都是安装最新版本安装的,可能有部分库不兼容,执行到以下代码行时,抛出错误。 354 | 355 | ```python 356 | response, history = model.chat(tokenizer, "你好", history=[]) 357 | ``` 358 | 359 |
360 | 361 | 首先出现以下警告,然后出现报错: 362 | 363 | ```bash 364 | 1Torch was not compiled with flash attention. (Triggered internally at C:\cb\pytorch_1000000000000\work\aten\src\ATen\native\transformers\cuda\sdp_utils.cpp:555.) 365 | context_layer = torch.nn.functional.scaled_dot_product_attention(query_layer, key_layer, value_layer, 366 | ``` 367 | 368 |
369 | 370 | 需要将 transformers 版本较级。 371 | 372 | ```bash 373 | pip install transformers==4.41.2 374 | ``` 375 | 376 |
377 | 378 | 经历各种曲折,最后终于成功了: 379 | 380 | ![image-20240901122852869](images/image-20240901122852869.png) 381 | 382 |
383 | 384 | ### Csharp 环境 385 | 386 | 首先引入 TorchSharp 包,这个是 API 核心包,官方仓库地址:https://github.com/dotnet/TorchSharp。 387 | 388 | TorchSharp 并不是通过 ironpython 的方式调用 Python 接口,因为 Pytorch 是建立在大量 C++ 代码上的,Python 只是其中一种前端接口方式,官方还推出了一个使用纯 C++ 11 的接口方式,TorchSharp 是使用 C# 对 C++ 的封装,因此性能上也非常可靠,使用上也比较简单,**不需要依赖 Python 环境**。 389 | 390 | 如果你对 C++ 版本接口有兴趣,请参考:https://pytorch.org/tutorials/advanced/cpp_frontend.html 391 | 392 |
393 | 394 | 由于 TorchSharp 包只是对 C++ 接口的封装,还需要对应环境的 Torch 驱动才能使用,以下三个按需引入即可。 395 | 396 | 如果只使用 CPU 不需要 GPU,则使用 TorchSharp-cpu 包,跨平台可用,如果使用 GPU 包,则需要注意安装对应系统的包。 397 | 398 |
399 | 400 | - [TorchSharp-cpu](https://www.nuget.org/packages/TorchSharp-cpu) (CPU, Linux/Windows/OSX) 401 | - [TorchSharp-cuda-windows](https://www.nuget.org/packages/TorchSharp-cuda-windows) (CPU/CUDA 12.1, Windows) 402 | - [TorchSharp-cuda-linux](https://www.nuget.org/packages/TorchSharp-cuda-linux) (CPU/CUDA 12.1, Linux) 403 | 404 | 405 | 406 | ![image-20240907191647155](images/image-20240907191647155.png) 407 | 408 |
409 | 410 | 点击确定安装时,由于需要下载大量的文件,因此安装时间比较长,需要耐心等待。 411 | 412 |
413 | 414 | ![image-20240907192106915](images/image-20240907192106915.png) 415 | 416 |
417 | 418 | 此外,推荐安装 Maomi.Torch 包,里面包含了一些常用的扩展方法。 419 | -------------------------------------------------------------------------------- /01.base/02.base.md: -------------------------------------------------------------------------------- 1 | # 1.2 Pytorch 基础 2 | 3 | 本文内容介绍 Pytorcn 的基础 API,主要是数组的创建方式和运算方式,由于相关内容跟 Numpy 比较相似,并且 Numpy 类型可以转 torch.Tensor,因此对 Numpy 感兴趣的读者可以参考笔者的其它文章: 4 | 5 | * Python 之 Numpy 框架入门 6 | 7 | > https://www.whuanle.cn/archives/21461 8 | > 9 | > https://www.cnblogs.com/whuanle/p/17855578.html 10 | 11 |
12 | 13 | 提示:学习本文时,如果对线性代数有足够的了解,则学习效果更佳,没有线性代数基础也没关系,后面会学习到。本文会同时使用 Python 和 C# 编写示例,方便各位读者对照差异,在后续的章节学习中,基本只会使用 C# 编写示例。 14 | 15 |
16 | 17 | ### 基础使用 18 | 19 | 由于神经网络中的数值很多以向量或数组等形式存在,不像日常编程中的数值类型那么简单,因此打印数值信息是我们学习了解或调试程序的一种手段,下面我们来观察程序是怎么打印 Pytorch 中复杂数据类型的。 20 | 21 |
22 | 23 | #### 打印 24 | 25 | 下面使用 Pytorch 创建一个从 0..9 的数组,接着打印数组。 26 | 27 | Python: 28 | 29 | ```python 30 | import torch 31 | x = torch.arange(10) 32 | print(x) 33 | ``` 34 | 35 | ```bash 36 | tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 37 | ``` 38 | 39 |
40 | 41 | C# 版本不使用 `Console.WriteLine()`,而是使用官方提供的库。 42 | 43 | ```csharp 44 | using TorchSharp; 45 | 46 | var x = torch.arange(10); 47 | x.print(style:TensorStringStyle.Default); 48 | x.print(style:TensorStringStyle.Numpy); 49 | x.print(style:TensorStringStyle.Metadata); 50 | x.print(style:TensorStringStyle.Julia); 51 | x.print(style:TensorStringStyle.CSharp); 52 | ``` 53 | 54 | ```bash 55 | [10], type = Int64, device = cpu 0 1 2 3 4 5 6 7 8 9 56 | [0, 1, 2, ... 7, 8, 9] 57 | [10], type = Int64, device = cpu 58 | [10], type = Int64, device = cpu 0 1 2 3 4 5 6 7 8 9 59 | [10], type = Int64, device = cpu, value = long [] {0L, 1L, 2L, ... 7L, 8L, 9L} 60 | ``` 61 | 62 |
63 | 64 | Python 打印的结果比较容易理解,C# 默认打印的方式比较难看,所以一般来说,可视化都使用 `TensorStringStyle.Numpy` 枚举。 65 | 66 | C# 打印数值时,参数有个 `string? fltFormat = "g5"`,表示精确度的意思,即打印的小数位数。 67 | 68 | 在 Maomi.Torch 包中提供了一些扩展方法,读者可以使用 `x.print_numpy()` 扩展直接打印对应风格的信息。 69 | 70 |
71 | 72 | 对于后面的章节来说,默认都引入 Python 的 torch 包名称、C# 的 TorchSharp 命名空间,后续代码示例可能会省略引入代码,读者自行引入。 73 | 74 |
75 | 76 | #### 基本数据类型 77 | 78 | Pytorch 的数据类型跟我们编程语言中的基本类型不太一样,读者要注意区别。 79 | 80 | 具体详细的官方文档参考链接: 81 | 82 | [https://pytorch.org/docs/stable/tensor_attributes.html](https://pytorch.org/docs/stable/tensor_attributes.html) 83 | 84 | [https://pytorch.ac.cn/docs/stable/tensor_attributes.html](https://pytorch.ac.cn/docs/stable/tensor_attributes.html) 85 | 86 |
87 | 88 | Pytorch 创建的数据类型以 `torch.Tensor` 表示,`torch.Tensor` 是用来处理机器学习模型中的各种数据的基础结构,包括标量、向量、矩阵以及更高维度的张量。**如果笔者没理解错的话,在 Pytorch 中创建的 Tensor 对象就叫张量。开发者可以通过各种形式的数据在 Pytorch 创建 Tensor**。 89 | 90 | > Pytorch 创建的数据类型,都使用 Tensor 对象表示。 91 | > 92 | > 对于这句话的理解,建议看完本文再回头看看。 93 | 94 |
95 | 96 | PyTorch 有十二种不同的数据类型,列表如下: 97 | 98 | | 数据类型 | dtype | 99 | | ------------------- | ------------------------------------- | 100 | | 32 位浮点数 | `torch.float32` 或 `torch.float` | 101 | | 64 位浮点数 | `torch.float64` 或 `torch.double` | 102 | | 64 位复数 | `torch.complex64` 或 `torch.cfloat` | 103 | | 128 位复数 | `torch.complex128` 或 `torch.cdouble` | 104 | | 16 位浮点数 | `torch.float16` 或 `torch.half` | 105 | | 16 位浮点数 | `torch.bfloat16` | 106 | | 8 位整数(无符号) | `torch.uint8` | 107 | | 8 位整数(有符号) | `torch.int8` | 108 | | 16 位整数(有符号) | `torch.int16` 或 `torch.short` | 109 | | 32 位整数(有符号) | `torch.int32` 或 `torch.int` | 110 | | 64 位整数(有符号) | `torch.int64` 或 `torch.long` | 111 | | 布尔值 | `torch.bool` | 112 | 113 |
114 | 115 | 下面示范在创建一个数值全为 1 的数组时,设置数组的类型。 116 | 117 | Python: 118 | 119 | ```python 120 | float_tensor = torch.ones(1, dtype=torch.float) 121 | double_tensor = torch.ones(1, dtype=torch.double) 122 | complex_float_tensor = torch.ones(1, dtype=torch.complex64) 123 | complex_double_tensor = torch.ones(1, dtype=torch.complex128) 124 | int_tensor = torch.ones(1, dtype=torch.int) 125 | long_tensor = torch.ones(1, dtype=torch.long) 126 | uint_tensor = torch.ones(1, dtype=torch.uint8) 127 | ``` 128 | 129 |
130 | 131 | C#: 132 | 133 | ```csharp 134 | var float_tensor = torch.ones(1, dtype: torch.float32); 135 | var double_tensor = torch.ones(1, dtype: torch.float64); 136 | var complex_float_tensor = torch.ones(1, dtype: torch.complex64); 137 | var complex_double_tensor = torch.ones(1, dtype: torch.complex128); 138 | var int_tensor = torch.ones(1, dtype: torch.int32); ; 139 | var long_tensor = torch.ones(1, dtype: torch.int64); 140 | var uint_tensor = torch.ones(1, dtype: torch.uint8); 141 | ``` 142 | 143 |
144 | 145 | 在 C# 中, torch.ScalarType 枚举表示 Pytorch 的数据类型,所以可以有以下两种方式指定数据类型。 146 | 147 | 例如: 148 | 149 | ```csharp 150 | var arr = torch.zeros(3,3,3, torch.ScalarType.Float32); 151 | arr.print_numpy(); 152 | ``` 153 | 154 | 或: 155 | 156 | ```csharp 157 | var arr = torch.zeros(3,3,3, torch.float32); 158 | arr.print_numpy(); 159 | ``` 160 | 161 |
162 | 163 | #### CPU 或 GPU 运算 164 | 165 | 我们知道,AI 模型可以在 CPU 下运行,也可以在 GPU 下运行,Pytorch 的数据也可以这样做,在创建数据类型时就设置绑定的设备,在运算使用会使用对应的设备进行运算。 166 | 167 | > 一般使用 `cpu` 表示 CPU,使用 `cuda` 或 `cuda:{显卡序号}` 表示 GPU。 168 | 169 |
170 | 171 | 下面编写代码判断 Pytorch 正在使用 GPU 还是 CPU 运行。 172 | 173 |
174 | 175 | Python: 176 | 177 | ```python 178 | print(torch.get_default_device()) 179 | ``` 180 | 181 |
182 | 183 | C#: 184 | 185 | ```csharp 186 | Console.WriteLine(torch.get_default_device()) 187 | ``` 188 | 189 |
190 | 191 | 如果当前设备支持 GPU,则使用 GPU 启动 Pytorch,否则使用 CPU 启动 Pytorch。可以通过 `torch.device('cuda')`、`torch.device('cuda:0')` 指定使用 GPU 、指定使用哪个 GPU。 192 | 193 |
194 | 195 | Python: 196 | 197 | ```python 198 | if torch.cuda.is_available(): 199 | print("当前设备支持 GPU") 200 | device = torch.device('cuda') 201 | # 使用 GPU 启动 202 | torch.set_default_device(device) 203 | current_device = torch.cuda.current_device() 204 | print(f"绑定的 GPU 为:{current_device}") 205 | else: 206 | # 不支持 GPU,使用 CPU 启动 207 | device = torch.device('cpu') 208 | torch.set_default_device(device) 209 | 210 | default_device = torch.get_default_device() 211 | print(f"当前正在使用 {default_device}") 212 | ``` 213 | 214 |
215 | 216 | C#: 217 | 218 | ```csharp 219 | if (torch.cuda.is_available()) 220 | { 221 | Console.WriteLine("当前设备支持 GPU"); 222 | var device = torch.device("cuda",index:0); 223 | // 使用 GPU 启动 224 | torch.set_default_device(device); 225 | } 226 | else 227 | { 228 | var device = torch.device("cpu"); 229 | // 使用 CPU 启动 230 | torch.set_default_device(device); 231 | Console.WriteLine("当前正在使用 CPU"); 232 | } 233 | 234 | var default_device = torch.get_default_device(); 235 | Console.WriteLine($"当前正在使用 {default_device}"); 236 | ``` 237 | 238 | > C# 没有 `torch.cuda.current_device()` 这个方法,建议默认设置使用哪块 GPU,即设置 index 参数。 239 | 240 |
241 | 242 | 另外可以通过使用 `torch.cuda.device_count()` 获取设备有多少个显卡,这里不再赘述。 243 | 244 |
245 | 246 | Pytorch 还支持针对单独的数据类型设置使用 CPU 还是 GPU,还可以让两者混合运算,这里不再赘述。 247 | 248 |
249 | 250 | #### Tensor 类型 251 | 252 | 在 Pytorch 中,可以将标量、数组等类型转换为 Tensor 类型,Tensor 表示的数据结构就叫张量。 253 | 254 | ``` 255 | x = torch.tensor(3.0); 256 | ``` 257 | 258 |
259 | 260 | #### 基本数组 261 | 262 | Pytorch 使用 `asarray()` 函数将 obj 值转换为数组,其定义如下: 263 | 264 | ```python 265 | torch.asarray(obj, *, dtype=None, device=None, copy=None, requires_grad=False) → Tensor 266 | ``` 267 | 268 | > 官方 API 文档:[torch.asarray — PyTorch 2.5 documentation](https://pytorch.org/docs/stable/generated/torch.asarray.html#torch-asarray) 269 | 270 |
271 | 272 | `obj` 可以是以下之一: 273 | 274 | * a tensor(张量) 275 | * a NumPy array or a NumPy scalar(NumPy 数组或 NumPy 标量) 276 | * a DLPack capsule 277 | * an object that implements Python’s buffer protocol 278 | * a scalar(标量) 279 | * a sequence of scalars(标量序列) 280 | 281 | > 笔者不会的或者本文用不到的,就不翻译了。 282 | 283 |
284 | 285 | 比如说,传入一个平常的数组类型,转换成 Pytorch 中的数组类型。 286 | 287 |
288 | 289 | Python: 290 | 291 | ```python 292 | arr = torch.asarray([1,2,3,4,5,6], dtype=torch.float) 293 | print(arr) 294 | ``` 295 | 296 |
297 | 298 | C#: 299 | 300 | ```csharp 301 | var arr = torch.from_array(new float[] { 1, 2, 3, 4, 5 }); 302 | arr.print(style: TensorStringStyle.Numpy); 303 | ``` 304 | 305 |
306 | 307 | 请注意,两种语言的版本差异有些大。 308 | 309 | 前面提到过,可以给单独的数据类型设置使用 CPU 还是 GPU。 310 | 311 | ```python 312 | device = torch.device("cuda",index=0) 313 | arr = torch.asarray(obj=[1,2,3,4,5,6], dtype=torch.float, device=device) 314 | print(arr) 315 | ``` 316 | 317 |
318 | 319 | 将数据类型转换为使用 CPU 设备: 320 | 321 | ```python 322 | device = torch.device("cuda",index=0) 323 | arr = torch.asarray(obj=[1,2,3,4,5,6], dtype=torch.float, device=device) 324 | arr = arr.cpu() 325 | print(arr) 326 | ``` 327 | 328 |
329 | 330 | 但是将数据在 GPU、CPU 之间转换,会消耗一定的性能。 331 | 332 |
333 | 334 | ### 生成数组 335 | 336 | #### torch.zeros 337 | 338 | 用于创建一个元素全为 0 的数组,可以指定数组大小,其定义如下: 339 | 340 | ```python 341 | torch.zeros(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor 342 | ``` 343 | 344 |
345 | 346 | Python: 347 | 348 | ```python 349 | arr = torch.zeros(10, dtype=torch.float) 350 | print(arr) 351 | ``` 352 | 353 |
354 | 355 | C#: 356 | 357 | ```python 358 | var arr = torch.zeros(10); 359 | arr.print(style: TensorStringStyle.Numpy); 360 | ``` 361 | 362 |
363 | 364 | 另外,可以指定生成的数组维度,例如下面指定生成 `2*3` 的多维数组。 365 | 366 | ```csharp 367 | var arr = torch.zeros(2,3, torch.float32); 368 | arr.print(style: TensorStringStyle.Numpy); 369 | ``` 370 | 371 | > 代码为 C# 语言。 372 | 373 |
374 | 375 | 打印: 376 | 377 | ```bash 378 | [[0, 0, 0] [0, 0, 0]] 379 | ``` 380 | 381 |
382 | 383 | 我们还可以生成多种维度的数组,例如下面生成一个 `3*3*3` 的数组: 384 | 385 | ```csharp 386 | var arr = torch.zeros(3,3,3, torch.float32); 387 | arr.print(style: TensorStringStyle.Numpy); 388 | ``` 389 | 390 |
391 | 392 | 为了方便理解,下面将打印结果做了格式化处理。 393 | 394 | ```bash 395 | [ 396 | [[0, 0, 0] [0, 0, 0] [0, 0, 0]] 397 | [[0, 0, 0] [0, 0, 0] [0, 0, 0]] 398 | [[0, 0, 0] [0, 0, 0] [0, 0, 0]] 399 | ] 400 | ``` 401 | 402 |
403 | 404 | #### torch.ones 405 | 406 | 创建一个全由 1 填充的数组,使用方法跟 torch.zeros 完全一致,因此这里不再赘述。 407 | 408 |
409 | 410 | #### torch.empty 411 | 412 | 创建一个未初始化的数组,使用方法跟 torch.zeros 完全一致,因此这里不再赘述。 413 | 414 | 由于其没有初始化内存,因此内存区域会残留数据,元素的值不确定。 415 | 416 |
417 | 418 | #### 复制函数 419 | 420 | 此外,上面三个函数还有对应的原型复制函数: 421 | 422 | ```python 423 | torch.ones_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor 424 | ``` 425 | 426 | ```python 427 | torch.zeros_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor 428 | ``` 429 | 430 | ```python 431 | torch.empty_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor 432 | ``` 433 | 434 |
435 | 436 | 它们的作用是根据数组类型,拷贝一个相同的结构,然后填充对应值。 437 | 438 | 如下示例,复制数组相同的结构,但是填充的值为 1。 439 | 440 | ```csharp 441 | var arr = torch.ones_like(torch.zeros(3, 3, 3)); 442 | arr.print(style: TensorStringStyle.Numpy); 443 | ``` 444 | 445 | > 该代码语言为 C#。 446 | 447 |
448 | 449 | ```bash 450 | [ 451 | [[1, 1, 1] [1, 1, 1] [1, 1, 1]] 452 | [[1, 1, 1] [1, 1, 1] [1, 1, 1]] 453 | [[1, 1, 1] [1, 1, 1] [1, 1, 1]] 454 | ] 455 | ``` 456 | 457 |
458 | 459 | #### torch.rand 460 | 461 | torch.rand 会生成一个张量,数组会填充来自 `[0,1)` 区间上的均匀分布的随机数。 462 | 463 | 函数定义如下: 464 | 465 | ```python 466 | torch.rand(*size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor 467 | ``` 468 | 469 |
470 | 471 | 例如生成 `2*3` 大小的,范围在 `[0,1)` 区间的随机数,使用 C# 编写代码: 472 | ```csharp 473 | var arr = torch.rand(2,3); 474 | arr.print(style: TensorStringStyle.Numpy); 475 | ``` 476 | 477 | ``` 478 | [[0.60446, 0.058962, 0.65601] [0.58197, 0.76914, 0.16542]] 479 | ``` 480 | 481 |
482 | 483 | 由于 C# 绘制图形的库不像 Python matplotlib 简单易用,因此读者可以引用 Maomi.Torch.ScottPlot、Maomi.ScottPlot.Winforms 两个包,可以快速转换 Pytorch 类型和生成绘制窗口 。下面示范使用编写代码绘制均匀分布的随机数,方便使用 Python matplotlib 和 Maomi.ScottPlot.Winforms 框架显示图形。 484 | 485 | Python: 486 | 487 | ```python 488 | import torch 489 | import matplotlib.pyplot as plt 490 | 491 | arr = torch.rand(100, dtype=torch.float) 492 | 493 | print(arr) 494 | 495 | x = arr.numpy() 496 | y = x 497 | plt.scatter(x,y) 498 | plt.show() 499 | ``` 500 | 501 | image-20241111214830663 502 | 503 |
504 | 505 | C#: 506 | 507 | ```csharp 508 | using Maomi.Torch; 509 | using Maomi.Plot; 510 | using TorchSharp; 511 | 512 | var x = torch.rand(100); 513 | 514 | x.print(style: TensorStringStyle.Numpy); 515 | 516 | ScottPlot.Plot myPlot = new(); 517 | myPlot.Add.Scatter(x, x); 518 | var form = myPlot.Show(400, 300); 519 | ``` 520 | 521 | image-20241111214859696 522 | 523 |
524 | 525 | 由图可知,生成的随机数是均匀散布在 `[0,1)` 区间内。 526 | 527 |
528 | 529 | #### torch.randn 530 | 531 | 生成具有给定形状的标准正态分布(平均值为0,方差为1)的随机样本。随机样本取值范围是[0,1)。 532 | 533 | 定义如下: 534 | 535 | ``` 536 | torch.randn(*size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor 537 | ``` 538 | 539 | > 官方文档:https://pytorch.ac.cn/docs/stable/generated/torch.randn.html#torch.rand 540 | 541 |
542 | 543 | 由于 C# 不好绘图,这里使用 Python 编写示例: 544 | 545 | ```python 546 | import torch 547 | import matplotlib.pyplot as plt 548 | 549 | arr = torch.randn(100, dtype=torch.float) 550 | 551 | print(arr) 552 | 553 | x = arr.numpy() 554 | y = x 555 | plt.hist(x, bins=30, alpha=0.5, color='b', edgecolor='black') 556 | 557 | plt.show() 558 | ``` 559 | 560 | > x 坐标轴是数值,y 坐标轴是出现次数。 561 | 562 | ![image-20241103125947540](images/image-20241103125947540.png) 563 | 564 |
565 | 566 | #### torch.randint 567 | 568 | 在某个区间内生成随机数。 569 | 570 | 定义如下: 571 | 572 | ```python 573 | torch.randint(low=0, high, size, \*, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor 574 | ``` 575 | 576 |
577 | 578 | 比如在 0-100 范围内生成 10 个元素,安装 `5*2` 结构组成,使用 C# 代码编写。 579 | 580 | ```csharp 581 | var arr = torch.randint(low: 0, high: 100, size: new int[] { 5, 2 }); 582 | arr.print(style: TensorStringStyle.Numpy); 583 | ``` 584 | 585 | ```bash 586 | [[17, 46] [89, 52] [10, 89] [80, 91] [52, 91]] 587 | ``` 588 | 589 |
590 | 591 | 如果要生成某个区间的浮点数,则可以使用 `torch.rand` ,但是因为 `torch.rand` 生成范围是 `[0,1)`,因此需要自行乘以倍数。例如要生成 `[0,100)` 的随机数。 592 | 593 | ```csharp 594 | var arr = torch.rand(size: 100, dtype: torch.ScalarType.Float32) * 100; 595 | arr.print(style: TensorStringStyle.Numpy); 596 | ``` 597 | 598 |
599 | 600 | #### torch.arange 601 | 602 | 指定区间以及步长,均匀提取元素生成数组。 603 | 604 | 定义如下: 605 | 606 | ```python 607 | torch.arange(start=0, end, step=1, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor 608 | ``` 609 | 610 |
611 | 612 | 比如说,需要生成 `[0,1,2,3,4,5,6,7,8,9]` 这样的数组,可以使用: 613 | 614 | ```csharp 615 | var arr = torch.arange(start: 0, stop: 10, step: 1); 616 | arr.print(style: TensorStringStyle.Numpy); 617 | ``` 618 | 619 |
620 | 621 | 如果将步长改成 0.5。 622 | 623 | ```csharp 624 | var arr = torch.arange(start: 0, stop: 10, step: 0.5); 625 | ``` 626 | 627 | ``` 628 | [0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000, 629 | 4.5000, 5.0000, 5.5000, 6.0000, 6.5000, 7.0000, 7.5000, 8.0000, 8.5000, 630 | 9.0000, 9.5000] 631 | ``` 632 | 633 |
634 | 635 | ### 数组操作和计算 636 | 637 |
638 | 639 | #### **轴** 640 | 641 | 在 Pytorch 中,往往使用 dim(dimension) 参数表示轴,轴就是张量的层数。 642 | 643 | 有以下数组: 644 | 645 | ```csharp 646 | [[ 1, 2, 3 ], { 4, 5, 6 ]] 647 | ``` 648 | 649 | 如果把 `a = [1,2,3]`,`b = [4,5,6]`,则: 650 | 651 | ``` 652 | [a,b] 653 | ``` 654 | 655 |
656 | 657 | 那么当我们要获取 `a` 时,`dim(a) = 0`,`dim(b) = 1`。 658 | 659 | ```csharp 660 | var arr = torch.from_array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } }); 661 | 662 | arr.print(style: TensorStringStyle.Numpy); 663 | 664 | // 打印维度 665 | arr.shape.print(); 666 | 667 | var a = arr[0]; 668 | a.print(); 669 | var b = arr[1]; 670 | b.print(); 671 | ``` 672 | 673 | ```bash 674 | [[1, 2, 3] [4, 5, 6]] 675 | [2, 3] 676 | [3], type = Int32, device = cpu 1 2 3 677 | [3], type = Int32, device = cpu 4 5 6 678 | ``` 679 | 680 |
681 | 682 | 这里我们分两步理解,由于该数组是 `2*3` 数组,可以使用 `.shape.print()` 打印出来。 683 | 684 | 由于第一层有两个元素,因此可以使用 `Tensor[i]` 获取第一层的第 i 个元素,其中 `i<2`。 685 | 686 | 同理,由于 a、b 的下一层都有 3 个元素,因此第二层 `n<3`。 687 | 688 |
689 | 690 | 例如要将数组的 `3`、`6` 两个元素取出来。 691 | 692 | 用 C# 可以这样写,但是打印的时候不能选 TensorStringStyle.Numpy ,否则打印不出来。 693 | 694 | ```csharp 695 | var arr = torch.from_array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } }); 696 | 697 | var a = arr[0, 2]; 698 | a.print(style: TensorStringStyle.CSharp); 699 | var b = arr[1, 2]; 700 | b.print(style: TensorStringStyle.CSharp); 701 | ``` 702 | 703 |
704 | 705 | 同理,如果数组有三层,可以这样获取 `3`、`6` 两个元素 706 | 707 | ```csharp 708 | var arr = torch.from_array(new[, ,] { { { 1, 2, 3 } }, { { 4, 5, 6 } } }); 709 | 710 | var a = arr[0, 0, 2]; 711 | a.print(style: TensorStringStyle.CSharp); 712 | var b = arr[1, 0, 2]; 713 | b.print(style: TensorStringStyle.CSharp); 714 | ``` 715 | 716 |
717 | 718 | 如果要取出一部分元素,TorchCsharp 可以使用 `a[i..j]` 的语法截取,示例如下。 719 | 720 | ```csharp 721 | var arr = torch.from_array(new int[] { 1, 2, 3 }); 722 | arr = arr[0..2]; 723 | arr.print(style: TensorStringStyle.Numpy); 724 | ``` 725 | 726 | ```bash 727 | [1, 2] 728 | ``` 729 | 730 |
731 | 732 | #### 数组排序 733 | 734 | Pytorch 中有一些排序函数: 735 | 736 | **sort** :沿给定维度按值升序对 `input` 张量的元素进行排序。 737 | 738 | **argsort**:它是沿指定轴的间接排序,本文不讲解。 739 | 740 | **msort**:按值对 `input` 张量沿其第一维以升序排序。`torch.msort(t)` 等效于 `torch.sort(t, dim=0)`。 741 | 742 |
743 | 744 | `sort` 可以降序或升序,参数说明如下: 745 | 746 | ``` 747 | torch.sort(input, dim=-1, descending=False, stable=False, *, out=None) 748 | ``` 749 | 750 | - **input** (张量) – 输入张量。 751 | - **dim** (int,可选) – 要排序的维度 752 | - **descending** (bool,可选) – 控制排序顺序(升序或降序) 753 | - **stable** (boo,可选) – 使排序例程稳定,从而保证等效元素的顺序得以保留。 754 | 755 |
756 | 757 | 示例: 758 | 759 | ```csharp 760 | var arr = torch.arange(start: 0, stop: 10, step: 1); 761 | 762 | // 或者使用 torch.sort(arr, descending: true) 763 | (torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort(descending: true); 764 | 765 | a1.Values.print(style: TensorStringStyle.Numpy); 766 | ``` 767 | 768 | ```bash 769 | [9, 8, 7, ... 2, 1, 0] 770 | ``` 771 | 772 |
773 | 774 | Values 是排序后的结果,Indices 是排序的规则。 775 | 776 |
777 | 778 | 如果数组结构比较复杂,默认不设置参数时,只有最内层数组进行排序。如下代码所示,有两层数组。 779 | 780 | ```csharp 781 | var arr = torch.from_array(new[,] { { 4, 6, 5 }, { 8, 9, 7 }, { 3, 2, 1 } }); 782 | 783 | (torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort(); 784 | 785 | a1.Values.print(style: TensorStringStyle.Numpy); 786 | a1.Indices.print(style: TensorStringStyle.Numpy); 787 | ``` 788 | 789 | ``` 790 | [[4, 5, 6] [7, 8, 9] [1, 2, 3]] 791 | [[0, 2, 1] [2, 0, 1] [2, 1, 0]] 792 | ``` 793 | 794 | Indices 会记录当前元素在以前的排序位置。 795 | 796 |
797 | 798 | 当设置 `arr.sort(dim: 0);` 时,按照第一层排序。 799 | 800 | ``` 801 | [[3, 2, 1] [4, 6, 5] [8, 9, 7]] 802 | [[2, 2, 2] [0, 0, 0] [1, 1, 1]] 803 | ``` 804 | 805 |
806 | 807 | 当设置 `arr.sort(dim: 1);` 时,只有里面一层排序。 808 | 809 | ``` 810 | [[4, 5, 6] [7, 8, 9] [1, 2, 3]] 811 | [[0, 2, 1] [2, 0, 1] [2, 1, 0]] 812 | ``` 813 | 814 |
815 | 816 | 当一个张量的维度比较大时,我们可以这样逐层排序。 817 | 818 | ```csharp 819 | var arr = torch.from_array(new[, ,] { { { 4, 6, 5 }, { 8, 9, 7 }, { 3, 2, 1 } } }); 820 | 821 | var dimCount = arr.shape.Length; 822 | for (int i = dimCount - 1; i >= 0; i--) 823 | { 824 | (torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort(dim: i); 825 | arr = a1.Values; 826 | arr.print(style: TensorStringStyle.Numpy); 827 | } 828 | ``` 829 | 830 | ``` 831 | [[[1, 2, 3] [4, 5, 6] [7, 8, 9]]] 832 | ``` 833 | 834 |
835 | 836 | C# 多维数组没有 Python 那么方便,会要求每一层的元素个数必须一致。 837 | 838 | 例如下面的数组声明是对的: 839 | 840 | ```csharp 841 | var array = new int[, , ] 842 | { 843 | { 844 | { 10, 12, 11},{ 14, 15, 11 } 845 | }, 846 | { 847 | { 4, 6, 5 }, { 8, 9, 7 } 848 | } 849 | }; 850 | ``` 851 | 852 |
853 | 854 | 如果层数元素个数不一致会报错: 855 | 856 | ![image-20241103203955447](images/image-20241103203955447.png) 857 | 858 |
859 | 860 | 另外要注意,C# 有多维数组和交错数组,下面是交错数组的声明方式,TorchSharp 并不支持。多维数组是数组,交错数组是数组的数组,或数组的数组的数组,要注意区分。 861 | 862 | ```csharp 863 | var array = new int[][][] 864 | { 865 | new int[][] 866 | { 867 | new int[] { 1, 2, 3 }, 868 | new int[] { 4, 5, 6 }, 869 | new int[] { 7, 8, 9 } 870 | }, 871 | new int[][] 872 | { 873 | new int[] { 10, 12, 11 }, 874 | new int[] { 14, 15, 13 } 875 | } 876 | }; 877 | ``` 878 | 879 | ![image-20241103204339232](images/image-20241103204339232.png) 880 | 881 |
882 | 883 | #### 数组运算符 884 | 885 | 在 PyTorch 中,张量支持许多运算符,下面列举部分加以说明: 886 | 887 |
888 | 889 | **算术运算符** 890 | 891 | - `+`:加法,如 `a + b` 892 | - `-`:减法,如 `a - b` 893 | - `*`:元素级乘法,如 `a * b` 894 | - `/`:元素级除法,如 `a / b` 895 | - `//`:元素级整除,如 `a // b` ,TorchCsharp 不支持。 896 | - `%`:取模运算,如 `a % b` 897 | - `**`:幂运算,如 `a ** b`,TorchCsharp 不支持,使用 `.pow(x)` 代替。 898 | 899 |
900 | 901 | **逻辑运算符** 902 | 903 | - `==`:元素级相等比较,如 `a == b` 904 | - `!=`:元素级不等于比较,如 `a != b` 905 | - `>`:元素级大于比较,如 `a > b` 906 | - `<`:元素级小于比较,如 `a < b` 907 | - `>=`:元素级大于等于比较,如 `a >= b` 908 | - `<=`:元素级小于等于比较,如 `a <= b` 909 | 910 |
911 | 912 | **位运算符** 913 | 914 | - `&`:按位与运算,如 `a & b` 915 | - `|`:按位或运算,如 `a | b` 916 | - `^`:按位异或运算,如 `a ^ b` 917 | - `~`:按位取反运算,如 `~a` 918 | - `<<`:按位左移,如 `a << b` 919 | - `>>`:按位右移,如 `a >> b` 920 | 921 |
922 | 923 | **索引和切片** 924 | 925 | - `[i]`:索引运算符,如 `a[i]` 926 | - `[i:j]`:切片运算符,如 `a[i:j]` ,TorchCsharp 使用 `a[i..j]` 语法。 927 | - `[i, j]`:多维索引运算符,如 `a[i, j]` 928 | 929 |
930 | 931 | 例如张量每个元素的值 `*10`。 932 | 933 | ```csharp 934 | var arr = torch.from_array(new int[] { 1, 2, 3 }); 935 | arr = arr * 10; 936 | arr.print(style: TensorStringStyle.Numpy); 937 | ``` 938 | 939 | ``` 940 | [10, 20, 30] 941 | ``` 942 | 943 |
944 | 945 | 此外,还有 Pytorch 还很多函数,后面的章节中会逐渐学习。 946 | 947 |
948 | -------------------------------------------------------------------------------- /01.base/03.linear.md: -------------------------------------------------------------------------------- 1 | # 线性代数 2 | 3 | ## 基础知识 4 | 5 | ### 标量、向量、矩阵 6 | 7 | 笔者只能给出大体的概念,至于数学上的具体定义,这里就不展开了。 8 | 9 | 标量(scalar):只有大小没有方向的数值,例如体重、身高。 10 | 11 | 向量(vector):既有大小也有方向的数值,可以用行或列来表示。 12 | 13 | 矩阵(matrix):由多行多列的向量组成。 14 | 15 | 张量(Tensor):在 Pytorch 中,torch.Tensor 类型数据结构就是张量,结构跟数组或矩阵相似。 16 | 17 |
18 | 19 | - Tensor:是 PyTorch 中的基本数据类型,可以理解为多维数组。 Tensor 可以用来表示数据集、模型参数和模型输出等。 20 | - Scalar:是一个特殊类型的 Tensor,只有一维。 Scalar 用来表示标量值,如学习率、损失值等。 21 | - Vector:是一个特殊类型的 Tensor,有一维或两维。 Vector 用来表示向量值,如梯度、特征值等。 22 | - Matrix:是一个特殊类型的 Tensor,有两维。 Matrix 用来表示矩阵值,如权重矩阵、输出矩阵等。 23 | 24 |
25 | 26 | 比如说 1.0、2 这些都是标量,在各种编程语言中都以基础数据类型提供了支持,例如 C# 的基元类型。 27 | 28 |
29 | 30 | 下面将标量转换为 torch.Tensor 类型。 31 | 32 | ```csharp 33 | var x = torch.tensor(1.0); 34 | var y = torch.tensor(2); 35 | 36 | x.print_csharp(); 37 | y.print_csharp(); 38 | ``` 39 | 40 | ```bash 41 | [], type = Float64, device = cpu, value = 1 42 | [], type = Int32, device = cpu, value = 2 43 | ``` 44 | 45 |
46 | 47 | 将数组转换为 torch.Tensor 类型: 48 | 49 | ```csharp 50 | var data = new int[ , ]{ {1, 2}, { 3, 4}}; 51 | var x_data = torch.tensor(data); 52 | 53 | x_data.print_csharp(); 54 | ``` 55 | 56 |
57 | 58 | 由于上一章已经讲解了很多数组的创建方式,因此这里不再赘述。 59 | 60 |
61 | 62 | ### Pytorch 的一些数学函数 63 | 64 | Pytorch 通过 torch.Tensor 表示各种数据类型,torch.Tensor 提供超过 100 多种的张量操作,例如算术运算、线性代数、矩阵操作、采样等。 65 | 66 | 由于篇幅有限,这里就不单独给出,读者请自行参考以下资料: 67 | 68 | https://pytorch.org/docs/stable/torch.html 69 | 70 | https://pytorch.ac.cn/docs/stable/torch.html 71 | 72 |
73 | 74 | ## 线性代数 75 | 76 |
77 | 78 | ### 向量 79 | 80 | #### 向量的概念 81 | 82 | 在研究力学、物理学等工程应用领域中会碰到两类的量,一类完全由**数值的大小**决定,例如温度、时间、面积、体积、密度、质量等,称为**数量**或**标量**,另一类的量,**只知道数值的大小还不能完全确定所描述量**,例如加速度、速度等,这些量除了大小还有方向,称为向量。 83 | 84 |
85 | 86 | 在平面坐标轴上有两点 $A(x_{1},y_{1})$ 、 $B(x_{2},y_{2})$ ,以 A 为起点 、B 为终点的线段被称为被称为有向线段,其既有大小也有方向,使用 $\overrightarrow{AB} $ 表示,使用坐标表示为 $(x_{2}-x_{1},y_{2}-y_{1})$ ,如果不强调方向,也可以使用 $\alpha $ 等符号进行简记。 87 | 88 | ![image-20241108071154361](images/image-20241108071154361.png) 89 | 90 |
91 | 92 | A、B 之间的距离称为向量的模,使用 | $\overrightarrow{AB} $ | 或 | $\overrightarrow{BA} $ | 或 | $\alpha $ | 表示。 93 | 94 | 平面中的向量,其距离公式是: 95 | 96 | $$ 97 | | \overrightarrow{AB} | = \sqrt{(x_{2}-x_{1})^{2} + (y_{2}-y_{1})^2} 98 | $$ 99 | 100 |
101 | 其实原理也很简单,根据勾股定理,AB 的平方等于两个直角边长平方之和,所以: 102 | 103 | $$ 104 | | \overrightarrow{AB} | ^2 = (x_{2}-x_{1})^{2} + (y_{2}-y_{1})^2 105 | $$ 106 | 107 |
108 | 109 | ![image-20241108212312023](images/image-20241108212312023.png) 110 | 111 |
112 | 113 | 去平方就是: 114 | 115 | $$ 116 | | \overrightarrow{AB} | = \sqrt{(x_{2}-x_{1})^{2} + (y_{2}-y_{1})^2} 117 | $$ 118 | 119 |
120 | 121 | 如下图所示,其两点间的距离: 122 | 123 | $$ 124 | | \overrightarrow{AB} | = \sqrt{(4-1)^{2} + (4-1)^2} = \sqrt{18} = 3\sqrt{2} = 4.242640687119285 125 | $$ 126 | 127 |
128 | 129 | ![image-20241108071828663](images/image-20241108071828663.png) 130 | 131 |
132 | 133 | 使用 C# 计算向量的模,结果如下 134 | 135 | ```csharp 136 | var A = torch.from_array(new[] { 1.0, 1.0 }); 137 | var B = torch.from_array(new[] { 4.0, 4.0 }); 138 | var a = B - A; 139 | 140 | var norm = torch.norm(a); 141 | norm.print_csharp(); 142 | ``` 143 | 144 | ``` 145 | [], type = Float64, device = cpu, value = 4.2426 146 | ``` 147 | 148 | > 注意,计算向量的模只能使用浮点型数据,不能使用 int、long 这些整型。 149 | 150 |
151 | 152 | 同理,对于三维空间中的两点 $A(x_{1},y_{1},z_{1})$ 、 $B(x_{2},y_{2},z_{2})$ ,距离公式是: 153 | 154 | $$ 155 | | \overrightarrow{AB} | = \sqrt{(x_{2}-x_{1})^{2} + (y_{2}-y_{1})^2 + (z_{2}-z_{1})^2} 156 | $$ 157 | 158 |
159 | 160 | #### 向量的加减乘除法 161 | 162 | 向量的加法很简单,坐标相加即可。 163 | 164 | 如图所示,平面中有三点 A(1,1)、B(3,5)、C(6,4)。 165 | 166 | ![image-20241108205142069](images/image-20241108205142069.png) 167 | 168 |
169 | 170 | 得到三个向量分别为: $\overrightarrow{AB} (2,4) $ 、 $\overrightarrow{BC} (3,-1) $ 、 $\overrightarrow{AC} (5,3) $ 171 | 172 |
173 | 174 | 根据数学上向量的加法可知, $\overrightarrow{AB} $ + $\overrightarrow{BC} $ = $\overrightarrow{AC} $ 175 | 176 | ```csharp 177 | var B = torch.from_array(new[] { 2.0, 4.0 }); 178 | var A = torch.from_array(new[] { 3.0, -1.0 }); 179 | var a = A + B; 180 | 181 | a.print_csharp(); 182 | ``` 183 | 184 | ``` 185 | [2], type = Float64, device = cpu, value = double [] {5, 3} 186 | ``` 187 | 188 |
189 | 190 | 同理,在 Pytorch 中,向量减法也是两个 torch.Tensor 类型相减即可。 191 | 192 | 推广到三维空间,计算方法也是一样的。 193 | 194 | ```csharp 195 | var B = torch.from_array(new[] { 2.0, 3.0, 4.0 }); 196 | var A = torch.from_array(new[] { 3.0, 4.0, 5.0 }); 197 | var a = B - A; 198 | 199 | a.print_csharp(); 200 | ``` 201 | 202 | ``` 203 | [3], type = Float64, device = cpu, value = double [] {-1, -1, -1} 204 | ``` 205 | 206 |
207 | 208 | 另外,向量乘以或除以一个标量,直接运算即可,如 $ \overrightarrow{AB} (2,4) $,则 $ 3 * \overrightarrow{AB} (2,4) $ = (6,12)。 209 | 210 |
211 | 212 | #### 向量的投影 213 | 214 | 如图所示, $\overrightarrow{AB} (2,4) $ 是平面上的向量,如果我们要计算向量在 x、y 上的投影是很简单的,例如在 x 轴上的投影是 2,因为 A 点的 x 坐标是 1,B 点的 x 坐标是 3,所以 3 - 1 = 2 为 $\overrightarrow{AB} (2,4) $ 在 x 轴上的投影,5 - 1 = 4 是在 y 轴上的投影。 215 | 216 | ![image-20241108211302187](images/image-20241108211302187.png) 217 | 218 |
219 | 220 | 在数学上使用 $Projx(u)$ 表示向量 u 在 x 上的投影,同理 $Projy(u)$ 是 u 在 y 上的投影。 221 | 222 | 如果使用三角函数,我们可以这样计算向量在各个轴上的投影。 223 | 224 | $$ 225 | Projx(u) = |\overrightarrow{AB}| \cos \alpha = |\overrightarrow{AC}| 226 | $$ 227 | 228 | $$ 229 | Projy(u) = |\overrightarrow{AB}| \sin \alpha = |\overrightarrow{BC}| 230 | $$ 231 | 232 |
233 | 234 | AC、BC 长度是 4,根据勾股定理得出 AB 长度是 $4\sqrt{2} $,由于 $cos \frac{\pi }{2} = \frac{\sqrt{2}} {2}$ ,所以 $Projx(u) = 4$。 235 | 236 | ![image-20241108212445350](images/image-20241108212445350.png) 237 | 238 |
239 | 240 | 那么在平面中,我们已知向量的坐标,求向量与 x 、y 轴的夹角,可以这样求。 241 | 242 | $$ 243 | \cos \alpha = \frac{x}{|v|} 244 | $$ 245 | 246 | $$ 247 | \sin \alpha = \frac{y}{|v|} 248 | $$ 249 | 250 |
251 | 252 | 例如上图中 $\overrightarrow{AB} (4,4) $,x 和 y 都是 4,其中 $|v| = 4\sqrt{2}$ ,所以 $\cos \alpha = \frac{4}{4\sqrt{2}} = \frac{\sqrt{2}}{2}$ 253 | 254 |
255 | 256 | 从 x、y 轴推广到平面中任意两个向量 $\alpha$ 、 $\beta$ ,求其夹角 $\varphi$ 的公式为: 257 | 258 | $$ 259 | \cos \varphi = \frac{\alpha \cdot \beta}{|\alpha|\cdot|\beta|} 260 | $$ 261 | 262 |
263 | 264 | 继续按下图所示,计算 $\overrightarrow{AB}$ 、 $\overrightarrow{AC}$ 之间的夹角,很明显,我们按经验直接可以得出夹角 $\varphi$ 是 45° 。 265 | 266 | ![image-20241108221035111](images/image-20241108221035111.png) 267 | 268 |
269 | 270 | 但是如果我们要通过投影方式计算出来,则根据 $ \frac{\alpha \cdot \beta}{|\alpha|\cdot|\beta|} $ ,使用 C# 计算如下。 271 | 272 | ```csharp 273 | var AB = torch.from_array(new[] { 4.0, 4.0 }); 274 | var AC = torch.from_array(new[] { 4.0, 0.0 }); 275 | 276 | // 点积 277 | var dot = torch.dot(AB, AC); 278 | 279 | // 求每个向量的模 280 | var ab = torch.norm(AB); 281 | var ac = torch.norm(AC); 282 | 283 | // 求出 cosφ 的值 284 | var cos = dot / (ab * ac); 285 | cos.print_csharp(); 286 | 287 | // 使用 torch.acos 计算夹角 (以弧度为单位) 288 | var theta = torch.acos(cos); 289 | 290 | // 将弧度转换为角度 291 | var theta_degrees = torch.rad2deg(theta); 292 | theta_degrees.print_csharp(); 293 | ``` 294 | 295 | ``` 296 | [], type = Float64, device = cpu, value = 0.70711 297 | [], type = Float64, device = cpu, value = 45 298 | ``` 299 | 300 | ![image-20241108221229577](images/image-20241108221229577.png) 301 | 302 |
303 | 304 | ### 柯西-施瓦茨不等式 305 | 306 | $a$ 、 $b$ 是两个向量,根据前面学到的投影和夹角知识,我们可以将以下公式进行转换。 307 | 308 | $$ 309 | \cos \varphi = \frac{\alpha \cdot \beta}{|\alpha|\cdot|\beta|} 310 | $$ 311 | 312 | $$ 313 | \alpha \cdot \beta = |\alpha|\cdot|\beta| \cos \varphi 314 | $$ 315 | 316 | 由于 $-1 \le \cos \varphi \le 1$,所以: 317 | 318 | $$ 319 | - |\alpha|\cdot|\beta| \le \alpha \cdot \beta \le |\alpha|\cdot|\beta| 320 | $$ 321 | 322 |
323 | 324 | 这个就是 柯西-施瓦茨不等式。 325 | 326 |
327 | 328 | 也就是说,当两个向量的夹角最小时,两个向量的方向相同(角度为 0),此时两个向量的乘积达到最大值,角度越大,乘积越小。在深度学习中,可以将两个向量的方向表示为相似程度,例如向量数据库检索文档时,可以算法计算出向量,然后根据相似程度查找最优的文档信息。 329 | 330 | ![image-20241112112037795](./images/image-20241112112037795.png) 331 | 332 |
333 | 334 | #### 向量的点积 335 | 336 | **点积即向量的数量积,点积、数量积、内积,都是同一个东西。** 337 | 338 | 两个向量的数量积是标量,即一个数值,而向量积是不同的东西,这里只说明数量积。 339 | 340 | 数量积称为两个向量的数乘,而向量积才是两个向量的乘法。 341 | 342 | 向量的数乘公式如下: 343 | 344 | $$ 345 | a\cdot b=\displaystyle\sum_{i=1}^{n} a_{i} b_{i}=a_{1} b_{1}+a_{2} b_{2}+...+a_{n} b_{n} 346 | $$ 347 | 348 |
349 | 350 | 加上前面学习投影时列出的公式,如果可以知道向量的模和夹角,我们也可以这样求向量的点积: 351 | 352 | $$ 353 | \alpha \cdot \beta = |\alpha|\cdot|\beta| \cos \varphi 354 | $$ 355 | 356 |
357 | 358 | 例如 $\overrightarrow{AB} (2,4) $ 、 $\overrightarrow{BC} (3,-1) $ 两个向量,如下图所示。 359 | 360 | ![image-20241108205142069](images/image-20241108205142069.png) 361 | 362 | 计算其点积如下: 363 | 364 | ```csharp 365 | var B = torch.from_array(new[] { 2.0, 4.0 }); 366 | var A = torch.from_array(new[] { 3.0, -1.0 }); 367 | 368 | var dot = torch.dot(A, B); 369 | 370 | dot.print_csharp(); 371 | ``` 372 | 373 | ``` 374 | [], type = Float64, device = cpu, value = 2 375 | ``` 376 | 377 |
378 | 379 | 读者可以试试根据点积结果计算出 $\angle ABC$ 的角度。 380 | 381 |
382 | 383 | #### 向量积 384 | 385 | 在画坐标轴时,我们默认轴上每个点间距都是 1,此时 x、y、z 上的单位向量都是 1,如果一个向量的模是 1,那么这个向量就是单位向量,所以单位向量可以有无数个。 386 | 387 | ![image-20241113004516264](./images/image-20241113004516264.png) 388 | 389 |
390 | 391 | 在数学中,我们往往会有很多未知数,此时我们使用 $i$ 、 $j$ 、 $k$ 分别表示与 x、y、z 轴上正向一致的三个单位向量,**在数学和物理中,单位向量通常用于表示方向而不关心其大小**。不理解这句话也没关系,忽略。 392 | 393 |
394 | 395 | 在不关心向量大小的情况下,我们使用单位向量可以这样表示两个向量: 396 | 397 | $$ 398 | a = x_{1}i+y_{1}j+z_{1}k = (x_{1}, y_{1}, z_{1}) 399 | $$ 400 | 401 | $$ 402 | b = x_{2}i+y_{2}j+z_{2}k = (x_{2}, y_{2}, z_{2}) 403 | $$ 404 | 405 |
406 | 407 | 在三维空间中, $i$ 、 $j$ 、 $k$ 分别表示三个轴方向的单位向量。 408 | 409 | - $i$ 表示沿 x 轴方向的单位向量。 410 | - $j$ 表示沿 y 轴方向的单位向量。 411 | - $k$ 表示沿 z 轴方向的单位向量。 412 | 413 | 这种方式表示 a 在 x 轴上有 $x_{1}$ 个单位,在 y 轴上有 $y_{1}$ 个单位,在 z 轴上有 $z_{1}$ 个单位。 414 | 415 | 一般来说,提供这种向量表示法,我们并不关心向量的大小,我们只关心其方向,如下图所示。 416 | 417 | ![image-20241108223336564](images/image-20241108223336564.png) 418 | 419 | 现在我们来求解一个问题,在空间中找到跟 $\overrightarrow{AB} $ 、 $\overrightarrow{BC} $ 同时垂直的向量,例如下图的 $\overrightarrow{AD} $ ,很明显,这样的向量不止一个,有无数个,所以我们这个时候要了解什么是法向量和单位向量。 420 | 421 | ![image-20241113005446796](./images/image-20241113005446796.png) 422 | 423 | 法向量是一个与平面垂直的向量(这里不涉及曲面、曲线这些),要找出法向量也很简单,有两种方法,一种是坐标表示: 424 | 425 | $$ 426 | a \times b = 427 | \begin{vmatrix} 428 | &i &j &k \\ 429 | &x_{1} &y_{1} &z_{1} \\ 430 | &x_{2} &y_{2} &z_{2} 431 | \end{vmatrix} = (y_{1}z_{2}-z_{1}y_{2})i - (x_{1}z_{2}-z_{1}x_{2})j + (x_{1}y_{2}-y_{1}x_{2})k 432 | $$ 433 | 434 |
435 | 这样记起来有些困难,我们可以这样看,容易记得。 436 | 437 | $$ 438 | a \times b = 439 | \begin{vmatrix} 440 | &i &j &k \\ 441 | &x_{1} &y_{1} &z_{1} \\ 442 | &x_{2} &y_{2} &z_{2} 443 | \end{vmatrix} = (y_{1}z_{2}-z_{1}y_{2})i + (z_{1}x_{2}-x_{1}z_{2})j + (x_{1}y_{2}-y_{1}x_{2})k 444 | $$ 445 | 446 |
那么法向量 $n$ 的 $x = (y_{1}{z2} -z_{1}y_{2})$ ,y、z 轴同理,就不给出了,x、y、z 分别就是 i、j、k 前面的一块符号公式,所以法向量为: 447 | 448 | $$ 449 | n(y_{1}z_{2}-z_{1}y_{2},z_{1}x_{2}-x_{1}z_{2},x_{1}y_{2}-y_{1}x_{2}) 450 | $$ 451 | 452 |
453 | 454 | 任何一条下式满足的向量,都跟 $a$ 、 $b$ 组成的平面垂直。 455 | 456 | $$ 457 | c = (y_{1}z_{2}-z_{1}y_{2})i + (z_{1}x_{2}-x_{1}z_{2})j + (x_{1}y_{2}-y_{1}x_{2})k 458 | $$ 459 | 460 |
例题如下。 461 | 462 | 求与 $a = 3i - 2j + 4k$ , $b = i + j - 2k$ 都垂直的法向量 。 463 | 464 | 首先提取 $a$ 在每个坐标轴上的分量 $(3,-2,4)$,b 的分量为 $(1,1,-2)$。 465 | 466 | 则: 467 | 468 | $$ 469 | a \times b = 470 | \begin{vmatrix} 471 | &i &j &k \\ 472 | &3 &-2 &4 \\ 473 | &1 &1 &-2 474 | \end{vmatrix} = (4-4)i + (4-(-6))j + (3-(-2))k = 10j + 5k 475 | $$ 476 | 477 | 所以法向量 $n(0,10,5)$。 478 | 479 | 这就是通过向量积求得与两个向量都垂直的法向量的方法。 480 | 481 |
482 | 483 | 你甚至可以使用 C# 手撸这个算法出来: 484 |
485 | 486 | ```csharp 487 | var A = torch.tensor(new double[] { 3.0, -2, 4 }); 488 | 489 | var B = torch.tensor(new double[] { 1.0, 1.0, -2.0 }); 490 | var cross = Cross(A, B); 491 | cross.print(); 492 | 493 | static Tensor Cross(Tensor A, Tensor B) 494 | { 495 | if (A.size(0) != 3 || B.size(0) != 3) 496 | { 497 | throw new ArgumentException("Both input tensors must be 3-dimensional."); 498 | } 499 | 500 | var a1 = A[0]; 501 | var a2 = A[1]; 502 | var a3 = A[2]; 503 | var b1 = B[0]; 504 | var b2 = B[1]; 505 | var b3 = B[2]; 506 | 507 | var i = a2 * b3 - a3 * b2; 508 | var j = a3 * b1 - a1 * b3; 509 | var k = a1 * b2 - a2 * b1; 510 | 511 | return torch.tensor(new double[] { i.ToDouble(), -j.ToDouble(), k.ToDouble() }); 512 | } 513 | ``` 514 | 515 | ``` 516 | [3], type = Float64, device = cpu 0 -10 5 517 | ``` 518 | 519 |
520 | 521 | 由于当前笔者所用的 C# 版本的 cross 函数不对劲,不能直接使用,所以我们也可以利用内核函数直接扩展一个接口出来。 522 | 523 | ```csharp 524 | public static class MyTorch 525 | { 526 | [DllImport("LibTorchSharp")] 527 | public static extern IntPtr THSLinalg_cross(IntPtr input, IntPtr other, long dim); 528 | 529 | public static Tensor cross(Tensor input, Tensor other, long dim = -1) 530 | { 531 | var res = THSLinalg_cross(input.Handle, other.Handle, dim); 532 | if (res == IntPtr.Zero) { torch.CheckForErrors(); } 533 | return torch.Tensor.UnsafeCreateTensor(res); 534 | } 535 | } 536 | ``` 537 | 538 |
539 | 540 | ```csharp 541 | var A = torch.tensor(new double[] { 3.0, -2, 4 }); 542 | 543 | var B = torch.tensor(new double[] { 1.0, 1.0, -2.0 }); 544 | 545 | var cross = MyTorch.cross(A, B); 546 | cross.print_csharp(); 547 | 548 | ``` 549 | 550 | ``` 551 | 552 | [3], type = Float64, device = cpu, value = double [] {0, 10, 5} 553 | 554 | ```` 555 | 556 |
557 | 558 | 当前笔者所用版本 other 参数是 Scalar 而不是 Tensor,这里应该是个 bug,最新 main 分支已经修复,但是还没有发布。 559 | 560 | ![image-20241109024627974](images/image-20241109024627974.png) 561 | 562 |
563 | 564 | 另外,还有一种通过夹角求得法向量的方法,如果知道两个向量的夹角,也可以求向量积,公式如下: 565 | 566 | $$ 567 | a \times b = |a| \cdot |b| \sin\alpha 568 | $$ 569 | 570 |
571 | 572 | 一般来说,对于空间求解问题,我们往往是可以计算向量积的,然后通过向量积得出 $|a| \cdot |b| \sin\alpha$ 的结果,而不是通过 $|a| \cdot |b| \sin\alpha$ 求出 $a \times b$ 。 573 | 574 | 关于此条公式,这里暂时不深入。 575 | 576 |
577 | 578 | #### 直线和平面表示法 579 | 580 | 在本小节节中,我们将学习空间中的直线和平面的一些知识。 581 | 582 | 在空间中的平面,可以使用一般式方程表达: 583 | 584 | $$ 585 | v = Ax + By + Cz + D 586 | $$ 587 | 588 |
其中 A、B、C 是法向量的坐标,即 $n = \{A,B,C\}$。 589 | 590 |
591 | 592 | 首先,空间中的直线有三种表示方法,分别是对称式方程、参数式方程、截距式方程。 593 | 594 |
595 | 596 | **直线的对称式方程** 597 | 598 | 给定空间中的一点 $P_{0}(x_{0},y_{0},z_{0})$ 有一条直线 L 穿过 $p_{0}$ 点,以及和非零向量 $v=\{l,m,n\}$ 平行。 599 | 600 | ![image-20241109150817967](images/image-20241109150817967.png) 601 | 602 |
603 | 604 | 直线上任意一点和 $p_{0}$ 的向量都和 $v$ 平行, $\overrightarrow{P_{0}P} =\{x - x_{0},y - y_{0}, z - z_{0}\}$ ,所以其因为其对应的坐标成比例,所以其截距式方程为: 605 | 606 | $$ 607 | \frac{x-x_{0}}{l} = \frac{y-y_{0}}{m} =\frac{z-z_{0}}{n} 608 | $$ 609 |
610 | 611 | **直线的参数式方程** 612 | 613 | 因为: 614 | 615 | $$ 616 | \frac{x-x_{0}}{l} = \frac{y-y_{0}}{m} =\frac{z-z_{0}}{n} = t 617 | $$ 618 | 619 |
620 | 所以: 621 | 622 | $$ 623 | \begin{cases}x = x_{0} + lt 624 | \\y = y_{0} + mt 625 | \\z = z_{0} + nt 626 | 627 | \end{cases} 628 | $$ 629 | 630 |
631 | 这便是直线的参数式方程。 632 |
633 | 634 | **直线的一般式方程** 635 | 636 | 空间中的直线可以看作是两个平面之间的交线,所以直线由两个平面的一般式方程给出: 637 | 638 | $$ 639 | \begin{cases} 640 | v_{1} = A_{1}x + B_{1}y + C_{1}z + D_{1} \\ 641 | v_{2} = A_{2}x + B_{2}y + C_{2}z + D_{2} 642 | \end{cases} 643 | $$ 644 | 645 |
646 | 这些公式在计算以下场景问题时很有帮助,不过本文不再赘述。 647 | 648 |
649 | 650 | ① 空间中任意一点到平面的距离。 651 | 652 | ② 直线和平面之间的夹角。 653 | 654 | ③ 平面之间的夹角。 655 | 656 |
657 | 658 | ### 矩阵 659 | 660 | 矩阵在在线性代数中具有很重要的地位,深度学习大量使用了矩阵的知识,所以读者需要好好掌握。 661 | 662 | 如下图所示,A 是一个矩阵,具有多行多列, $a_{11}$ 、 $a_{12}$ 、...、 $a_{1n}$ 是一个行, $a_{11}$ 、 $a_{21}$ 、...、 $a_{m1}$ 是一个列。 663 | 664 | ![image-20240910115046782](./images/image-20240910115046782.png) 665 | 666 |
在 C# 中,矩阵属于二维数组,即 $m*n$ ,例如要创建一个 $3*3$ 的矩阵,可以这样表示: 667 | 668 | ```csharp 669 | var A = torch.tensor(new double[,] 670 | { 671 | { 3.0, -2.0, 4.0 }, 672 | { 3.0, -2.0, 4.0 }, 673 | { 3.0, -2.0, 4.0 } 674 | }); 675 | 676 | A.print_csharp(); 677 | ```` 678 | 679 |
680 | 681 | 使用 `.T` 将矩阵的行和列倒过来: 682 | 683 | ```csharp 684 | var A = torch.tensor(new double[,] 685 | { 686 | { 3.0, -2.0, 4.0 } 687 | }); 688 | 689 | A.T.print_csharp(); 690 | ``` 691 | 692 |
生成的是: 693 | 694 | ``` 695 | { 696 | {3.0}, 697 | {-2.0}, 698 | {4.0} 699 | } 700 | ``` 701 | 702 | 如图所示: 703 | 704 | ![image-20241109154450656](images/image-20241109154450656.png) 705 | 706 |
707 | 708 | #### 矩阵的加减 709 | 710 | 矩阵的加减法很简单,就是相同位置的数组加减。 711 |
712 | 713 | ```csharp 714 | var A = torch.tensor(new double[,] 715 | { 716 | { 1.0, 2.0, 4.0 }, 717 | { 1.0, 2.0, 4.0 }, 718 | { 1.0, 2.0, 4.0 } 719 | }); 720 | 721 | var B = torch.tensor(new double[,] 722 | { 723 | { 1.0, 1.0, 2.0 }, 724 | { 1.0, 1.0, 2.0 }, 725 | { 1.0, 1.0, 2.0 } 726 | }); 727 | 728 | (A+B).print_csharp(); 729 | ``` 730 | 731 |
732 | 结果是: 733 |
734 | ``` 735 | { 736 | {2, 3, 6}, 737 | {2, 3, 6}, 738 | {2, 3, 6} 739 | } 740 | ``` 741 | 742 |
743 | 744 | 如果直接将两个矩阵使用 Pytorch 相乘,则是每个位置的数值相乘,这种乘法称为 Hadamard 乘积: 745 | 746 | ```csharp 747 | var A = torch.tensor(new double[,] 748 | { 749 | { 1.0, 2.0 } 750 | }); 751 | 752 | var B = torch.tensor(new double[,] 753 | { 754 | { 3.0, 4.0 } 755 | }); 756 | 757 | // 或者 torch.mul(A, B) 758 | (A * B).print_csharp(); 759 | ``` 760 | 761 | ``` 762 | [2x1], type = Float64, device = cpu, value = double [,] { {3}, {8}} 763 | ``` 764 | 765 |
766 | 767 | #### 矩阵乘法 768 | 769 | 我们知道,向量内积可以写成 $x_{2}x_{1}+y_{2}y_{1}+z_{2}z_{1}$,如果使用矩阵,可以写成: 770 | 771 | $$ 772 | \begin{bmatrix} 773 | &x_{1} &y_{1} &z_{1} \\ 774 | \end{bmatrix} \cdot 775 | \begin{bmatrix} 776 | &x_{2} \\ 777 | &y_{2} \\ 778 | &z_{2} 779 | \end{bmatrix} = x_{2}x_{1}+y_{2}y_{1}+z_{2}z_{1} 780 | $$ 781 | 782 |
783 | 换成实际案例,则是: 784 | 785 | $$ 786 | \begin{bmatrix} 787 | &1 &2 &3\\ 788 | \end{bmatrix} \cdot 789 | \begin{bmatrix} 790 | &4 \\ 791 | &5 \\ 792 | &6 793 | \end{bmatrix} = 1*4 + 2*5 + 3*6 = 32 794 | $$ 795 | 796 |
797 | 使用 C# 计算结果: 798 | 799 | ```csharp 800 | var a = torch.tensor(new int[] { 1, 2, 3 }); 801 | var b = torch.tensor(new int[,] { { 4 }, { 5 }, { 6 } }); 802 | 803 | var c = torch.matmul(a,b); 804 | c.print_csharp(); 805 | ``` 806 | 807 | ``` 808 | [1], type = Int32, device = cpu, value = int [] {32} 809 | ``` 810 | 811 |
812 | 813 | 上面的矩阵乘法方式使用 **A ⊗ B** 表示,对于两个多行多列的矩阵乘法,则比较复杂,下面单独使用一个小节讲解。 814 | 815 |
816 | 817 | **A ⊗ B** 818 | 819 | 矩阵的乘法比较麻烦,在前面,我们看到一个只有行的矩阵和一个只有列的矩阵相乘,结果只有一个值,但是对于多行多列的两个矩阵相乘,矩阵每个位置等于 A 矩阵行和 B 矩阵列相乘之和。 820 | 821 |
822 | 823 | 比如下面是一个简单的 `2*2` 矩阵。 824 | 825 | $$ 826 | \begin{bmatrix} 827 | &a_{11} &a_{12} \\ 828 | &a_{21} &a_{22} 829 | \end{bmatrix} \cdot 830 | \begin{bmatrix} 831 | &b_{11} &b_{12} \\ 832 | &b_{21} &b_{22} 833 | \end{bmatrix} 834 | = 835 | \begin{bmatrix} 836 | &c_{11} &c_{12} \\ 837 | &c_{21} &c_{22} 838 | \end{bmatrix} 839 | $$ 840 | 841 |
842 | 843 | 因为 $c_{11}$ 是第一行第一列,所以 $c_{11}$ 是 A 矩阵的第一行乘以 B 第一列的内积。 844 | 845 | $$ 846 | c_{11} = 847 | \begin{bmatrix} 848 | &a_{11} &a_{12} 849 | \end{bmatrix} \cdot 850 | \begin{bmatrix} 851 | &b_{11} \\ 852 | &b_{21} 853 | \end{bmatrix} 854 | = a_{11}*b_{11}+a_{12}*b_{21} 855 | $$ 856 | 857 |
858 | 859 | 因为 $c_{12}$ 是第一行第二列,所以 $c_{12}$ 是 A 矩阵的第一行乘以 B 第二列的内积。 860 | 861 | $$ 862 | c_{12} = 863 | \begin{bmatrix} 864 | &a_{11} &a_{12} 865 | \end{bmatrix} \cdot 866 | \begin{bmatrix} 867 | &b_{12} \\ 868 | &b_{22} 869 | \end{bmatrix} 870 | = a_{11}*b_{12}+a_{12}*b_{22} 871 | $$ 872 | 873 |
874 | 875 | 因为 $c_{21}$ 是第二行第一列,所以 $c_{21}$ 是 A 矩阵的第二行乘以 B 第一列的内积。 876 | 877 | $$ 878 | c_{21} = 879 | \begin{bmatrix} 880 | &a_{21} &a_{22} 881 | \end{bmatrix} \cdot 882 | \begin{bmatrix} 883 | &b_{22} \\ 884 | &b_{21} 885 | \end{bmatrix} 886 | = a_{21}*b_{11}+a_{22}*b_{21} 887 | $$ 888 | 889 |
890 | 891 | 因为 $c_{22}$ 是第二行第二列,所以 $c_{22}$ 是 A 矩阵的第二行乘以 B 第二列的内积。 892 | 893 | $$ 894 | c_{22} = 895 | \begin{bmatrix} 896 | &a_{21} &a_{22} 897 | \end{bmatrix} \cdot 898 | \begin{bmatrix} 899 | &b_{12} \\ 900 | &b_{22} 901 | \end{bmatrix} 902 | = a_{21}*b_{12}+a_{22}*b_{22} 903 | $$ 904 | 905 |
906 | 例题如下: 907 | 908 | $$ 909 | \begin{bmatrix} 910 | &1 &2 \\ 911 | &3 &4 912 | \end{bmatrix} \cdot 913 | \begin{bmatrix} 914 | &5 &6 \\ 915 | &7 &8 916 | \end{bmatrix} 917 | 918 | = 919 | 920 | \begin{bmatrix} 921 | &(1*5 + 2*7) &(1*6 + 2*8) \\ 922 | &(3*5 + 4*7) &(3*6 + 4*8) 923 | \end{bmatrix} 924 | = 925 | \begin{bmatrix} 926 | &19 &22 \\ 927 | &43 &50 928 | \end{bmatrix} 929 | $$ 930 | 931 |
932 | 使用 C# 计算多行多列的矩阵: 933 | 934 | ```csharp 935 | var A = torch.tensor(new double[,] 936 | { 937 | { 1.0, 2.0 }, 938 | { 3.0, 4.0 } 939 | }); 940 | 941 | var B = torch.tensor(new double[,] 942 | { 943 | { 5.0 , 6.0 }, 944 | { 7.0 , 8.0 } 945 | }); 946 | 947 | torch.matmul(A, B).print_csharp(); 948 | ``` 949 | 950 | ``` 951 | { {19, 22}, {43, 50}} 952 | ``` 953 | -------------------------------------------------------------------------------- /01.base/05.odds.md: -------------------------------------------------------------------------------- 1 | # 概率论 2 | 3 | ### 推荐书籍 4 | 5 | 大家都知道学习 Pytorch 或 AI 需要一定的数学基础,当然也不需要太高,只需要掌握一些基础知识和求解方法,常见需要的数学基础有线性代数、微积分、概率论等,由于高等数学课程里面同时包含了线性代数和微积分的知识,因此读者只需要学习高等数学、概率论两门课程即可。数学不用看得太深,这样太花时间了,能理解意思就行。 6 | 7 | 8 | 9 | 首先推荐以下两本书,无论是否已经忘记了初高中数学知识,对于数学基础薄弱的读者来说,都可以看。 10 | 11 | * 《普林斯顿微积分读本》 12 | 13 | * 《普林斯顿概率论读本》 14 | 15 | 16 | 17 | 国内的书主要是一些教材,学习难度会大一些,不过完整看完可以提升数学水平,例如同济大学出版的《高等数学》上下册、《概率论与数理统计》,不过国内的这些教材主要为了刷题解题、考研考试,可能不太适合读者,而且学习起来的时间也太长了。 18 | 19 | 20 | 21 | 接着是推荐《深度学习中的数学》,作者是涌井良幸和涌井贞美,对于入门的读者来说上手难度也大一些,不那么容易看得进去,读者可以在看完本文之后再去阅读这本经典书,相信会更加容易读懂。 22 | 23 | 24 | 25 | 另外,千万不要用微信读书这些工具看数学书,排版乱七八糟的,数学公式是各种抠图,数学符号也是用图片拼凑的,再比如公式里面中文英文符号都不分。 26 | 27 | 建议直接买实体书,容易深度思考,数学要多答题解题才行。就算买来吃灰,放在书架也可以装逼呀。买吧。 28 | 29 | 30 | 31 | 本文虽然不要求读者数学基础,但是还是需要知道一些数学符号的,例如求和∑ 、集合交并∩∪等,这些在本文中不会再赘述,读者不理解的时候需要自行搜索资料。 32 | 33 | 34 | 35 | 由于笔者对概率论不熟,因此暂时不写这一章。 -------------------------------------------------------------------------------- /01.base/README.md: -------------------------------------------------------------------------------- 1 | ### AI 推荐书籍 2 | 3 | 《深度学习的数学》 4 | 5 | 《程序员的数学基础》 6 | 7 | 《动手学深度学习》 8 | 9 | 《破解深度学习》 10 | 11 |
12 | 13 | ### 数学推荐书籍 14 | 15 | 大家都知道学习 Pytorch 或 AI 需要一定的数学基础,当然也不需要太高,只需要掌握一些基础知识和求解方法,常见需要的数学基础有线性代数、微积分、概率论等,由于高等数学课程里面同时包含了线性代数和微积分的知识,因此读者只需要学习高等数学、概率论两门课程即可。数学不用看得太深,这样太花时间了,能理解意思就行。 16 | 17 |
18 | 19 | 首先推荐以下两本书,无论是否已经忘记了初高中数学知识,对于数学基础薄弱的读者来说,都可以看。 20 | 21 | * 《普林斯顿微积分读本》 22 | 23 | * 《普林斯顿概率论读本》 24 | 25 |
26 | 27 | 国内的书主要是一些教材,学习难度会大一些,不过完整看完可以提升数学水平,例如同济大学出版的《高等数学》上下册、《概率论与数理统计》,不过国内的这些教材主要为了刷题解题、考研考试,可能不太适合读者,而且学习起来的时间也太长了。 28 | 29 |
30 | 31 | 接着是推荐《深度学习中的数学》,作者是涌井良幸和涌井贞美,对于入门的读者来说上手难度也大一些,不那么容易看得进去,读者可以在看完本文之后再去阅读这本经典书,相信会更加容易读懂。 32 | 33 |
34 | 35 | 另外,千万不要用微信读书这些工具看数学书,排版乱七八糟的,数学公式是各种抠图,数学符号也是用图片拼凑的,再比如公式里面中文英文符号都不分。 36 | 37 | 建议直接买实体书,容易深度思考,数学要多答题解题才行。就算买来吃灰,放在书架也可以装逼呀。买吧。 38 | 39 |
40 | 41 | 本文虽然不要求读者数学基础,但是还是需要知道一些数学符号的,例如求和∑ 、集合交并∩∪等,这些在本文中不会再赘述,读者不理解的时候需要自行搜索资料。 42 | 43 |
-------------------------------------------------------------------------------- /01.base/images/1725105003545.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725105003545.png -------------------------------------------------------------------------------- /01.base/images/1725105639726.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725105639726.png -------------------------------------------------------------------------------- /01.base/images/1725110469061.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725110469061.jpg -------------------------------------------------------------------------------- /01.base/images/1725148068180(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725148068180(1).png -------------------------------------------------------------------------------- /01.base/images/1725148940379.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725148940379.png -------------------------------------------------------------------------------- /01.base/images/1725148968981(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725148968981(1).png -------------------------------------------------------------------------------- /01.base/images/1725149018283.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725149018283.png -------------------------------------------------------------------------------- /01.base/images/1725150688028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/1725150688028.png -------------------------------------------------------------------------------- /01.base/images/389b1a036ebf0d36c4c2233c49c3556.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/389b1a036ebf0d36c4c2233c49c3556.jpg -------------------------------------------------------------------------------- /01.base/images/e951f1d6da6d09477880fc13f655b23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/e951f1d6da6d09477880fc13f655b23.jpg -------------------------------------------------------------------------------- /01.base/images/image-20240831193113478.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831193113478.png -------------------------------------------------------------------------------- /01.base/images/image-20240831193501897.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831193501897.png -------------------------------------------------------------------------------- /01.base/images/image-20240831193543224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831193543224.png -------------------------------------------------------------------------------- /01.base/images/image-20240831194432476.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831194432476.png -------------------------------------------------------------------------------- /01.base/images/image-20240831195641685.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831195641685.png -------------------------------------------------------------------------------- /01.base/images/image-20240831195802036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831195802036.png -------------------------------------------------------------------------------- /01.base/images/image-20240831220117612.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240831220117612.png -------------------------------------------------------------------------------- /01.base/images/image-20240901072421293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901072421293.png -------------------------------------------------------------------------------- /01.base/images/image-20240901072824863.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901072824863.png -------------------------------------------------------------------------------- /01.base/images/image-20240901080538372.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901080538372.png -------------------------------------------------------------------------------- /01.base/images/image-20240901093307337.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901093307337.png -------------------------------------------------------------------------------- /01.base/images/image-20240901111744905.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901111744905.png -------------------------------------------------------------------------------- /01.base/images/image-20240901112046630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901112046630.png -------------------------------------------------------------------------------- /01.base/images/image-20240901113934658.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901113934658.png -------------------------------------------------------------------------------- /01.base/images/image-20240901114708887.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901114708887.png -------------------------------------------------------------------------------- /01.base/images/image-20240901120654336.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901120654336.png -------------------------------------------------------------------------------- /01.base/images/image-20240901122532080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901122532080.png -------------------------------------------------------------------------------- /01.base/images/image-20240901122822715.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901122822715.png -------------------------------------------------------------------------------- /01.base/images/image-20240901122852869.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240901122852869.png -------------------------------------------------------------------------------- /01.base/images/image-20240907191647155.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240907191647155.png -------------------------------------------------------------------------------- /01.base/images/image-20240907192106915.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240907192106915.png -------------------------------------------------------------------------------- /01.base/images/image-20240910115046782.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240910115046782.png -------------------------------------------------------------------------------- /01.base/images/image-20240910121926988.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20240910121926988.png -------------------------------------------------------------------------------- /01.base/images/image-20241103100209574.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103100209574.png -------------------------------------------------------------------------------- /01.base/images/image-20241103100345461.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103100345461.png -------------------------------------------------------------------------------- /01.base/images/image-20241103121849440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103121849440.png -------------------------------------------------------------------------------- /01.base/images/image-20241103124606702.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103124606702.png -------------------------------------------------------------------------------- /01.base/images/image-20241103125947540.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103125947540.png -------------------------------------------------------------------------------- /01.base/images/image-20241103203955447.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103203955447.png -------------------------------------------------------------------------------- /01.base/images/image-20241103204339232.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241103204339232.png -------------------------------------------------------------------------------- /01.base/images/image-20241106225939512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241106225939512.png -------------------------------------------------------------------------------- /01.base/images/image-20241108071154361.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108071154361.png -------------------------------------------------------------------------------- /01.base/images/image-20241108071828663.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108071828663.png -------------------------------------------------------------------------------- /01.base/images/image-20241108205118094.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108205118094.png -------------------------------------------------------------------------------- /01.base/images/image-20241108205142069.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108205142069.png -------------------------------------------------------------------------------- /01.base/images/image-20241108211302187.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108211302187.png -------------------------------------------------------------------------------- /01.base/images/image-20241108212312023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108212312023.png -------------------------------------------------------------------------------- /01.base/images/image-20241108212445350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108212445350.png -------------------------------------------------------------------------------- /01.base/images/image-20241108220711380.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108220711380.png -------------------------------------------------------------------------------- /01.base/images/image-20241108221035111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108221035111.png -------------------------------------------------------------------------------- /01.base/images/image-20241108221229577.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108221229577.png -------------------------------------------------------------------------------- /01.base/images/image-20241108222744862.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108222744862.png -------------------------------------------------------------------------------- /01.base/images/image-20241108223336564.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241108223336564.png -------------------------------------------------------------------------------- /01.base/images/image-20241109024627974.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241109024627974.png -------------------------------------------------------------------------------- /01.base/images/image-20241109031032328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241109031032328.png -------------------------------------------------------------------------------- /01.base/images/image-20241109031356478.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241109031356478.png -------------------------------------------------------------------------------- /01.base/images/image-20241109150817967.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241109150817967.png -------------------------------------------------------------------------------- /01.base/images/image-20241109154450656.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241109154450656.png -------------------------------------------------------------------------------- /01.base/images/image-20241110092405151.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110092405151.png -------------------------------------------------------------------------------- /01.base/images/image-20241110092447001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110092447001.png -------------------------------------------------------------------------------- /01.base/images/image-20241110092718306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110092718306.png -------------------------------------------------------------------------------- /01.base/images/image-20241110095216295.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110095216295.png -------------------------------------------------------------------------------- /01.base/images/image-20241110095607086.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110095607086.png -------------------------------------------------------------------------------- /01.base/images/image-20241110095620201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110095620201.png -------------------------------------------------------------------------------- /01.base/images/image-20241110101708796.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110101708796.png -------------------------------------------------------------------------------- /01.base/images/image-20241110102423654.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110102423654.png -------------------------------------------------------------------------------- /01.base/images/image-20241110103428544.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110103428544.png -------------------------------------------------------------------------------- /01.base/images/image-20241110103552859.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110103552859.png -------------------------------------------------------------------------------- /01.base/images/image-20241110105635460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110105635460.png -------------------------------------------------------------------------------- /01.base/images/image-20241110105928305.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110105928305.png -------------------------------------------------------------------------------- /01.base/images/image-20241110110700577.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110110700577.png -------------------------------------------------------------------------------- /01.base/images/image-20241110135308642.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110135308642.png -------------------------------------------------------------------------------- /01.base/images/image-20241110140743986.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110140743986.png -------------------------------------------------------------------------------- /01.base/images/image-20241110142551689.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110142551689.png -------------------------------------------------------------------------------- /01.base/images/image-20241110143455304.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110143455304.png -------------------------------------------------------------------------------- /01.base/images/image-20241110145138140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110145138140.png -------------------------------------------------------------------------------- /01.base/images/image-20241110145256864.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110145256864.png -------------------------------------------------------------------------------- /01.base/images/image-20241110151831018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110151831018.png -------------------------------------------------------------------------------- /01.base/images/image-20241110154210542.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110154210542.png -------------------------------------------------------------------------------- /01.base/images/image-20241110161833098.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110161833098.png -------------------------------------------------------------------------------- /01.base/images/image-20241110164906093.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110164906093.png -------------------------------------------------------------------------------- /01.base/images/image-20241110165653935.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110165653935.png -------------------------------------------------------------------------------- /01.base/images/image-20241110170325278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241110170325278.png -------------------------------------------------------------------------------- /01.base/images/image-20241111214830663.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241111214830663.png -------------------------------------------------------------------------------- /01.base/images/image-20241111214859696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241111214859696.png -------------------------------------------------------------------------------- /01.base/images/image-20241112112037795.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241112112037795.png -------------------------------------------------------------------------------- /01.base/images/image-20241113003705839.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113003705839.png -------------------------------------------------------------------------------- /01.base/images/image-20241113004516264.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113004516264.png -------------------------------------------------------------------------------- /01.base/images/image-20241113005446796.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113005446796.png -------------------------------------------------------------------------------- /01.base/images/image-20241113213533007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113213533007.png -------------------------------------------------------------------------------- /01.base/images/image-20241113215104872.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113215104872.png -------------------------------------------------------------------------------- /01.base/images/image-20241113215631143.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113215631143.png -------------------------------------------------------------------------------- /01.base/images/image-20241113215851509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241113215851509.png -------------------------------------------------------------------------------- /01.base/images/image-20241114203340853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114203340853.png -------------------------------------------------------------------------------- /01.base/images/image-20241114204528433.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114204528433.png -------------------------------------------------------------------------------- /01.base/images/image-20241114212937793.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114212937793.png -------------------------------------------------------------------------------- /01.base/images/image-20241114220105658.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114220105658.png -------------------------------------------------------------------------------- /01.base/images/image-20241114222647137.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114222647137.png -------------------------------------------------------------------------------- /01.base/images/image-20241114222945545.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114222945545.png -------------------------------------------------------------------------------- /01.base/images/image-20241114223315609.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114223315609.png -------------------------------------------------------------------------------- /01.base/images/image-20241114223740021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241114223740021.png -------------------------------------------------------------------------------- /01.base/images/image-20241115204555682.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241115204555682.png -------------------------------------------------------------------------------- /01.base/images/image-20241115205039736.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241115205039736.png -------------------------------------------------------------------------------- /01.base/images/image-20241117092736536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241117092736536.png -------------------------------------------------------------------------------- /01.base/images/image-20241117093320424.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241117093320424.png -------------------------------------------------------------------------------- /01.base/images/image-20241117094156647.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241117094156647.png -------------------------------------------------------------------------------- /01.base/images/image-20241117094843430.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/01.base/images/image-20241117094843430.png -------------------------------------------------------------------------------- /02.start/01.neural_network.md: -------------------------------------------------------------------------------- 1 | # 神经网络基础知识 2 | 3 | 在本章中,我们将来学习各种基础知识,连接神经网络的一些知识点,将数学和神经网络模型串联起来,为后面学习神经网络编程和模型训练打好基础。 4 | 5 | 由于神经网络涉及到很多数学知识和算法,而本书定位为入门级别的教程,加之笔者也是初学者,整个系列教程也是笔者边学边写的,因此这里不深入讲解复杂的细节,只是讲解一些知识到点,知道用来干嘛的就行。 6 | 7 | 本章的内容是笔者的笔记整理,知识不一定正确,想了解神经网络基础知识,建议读者参阅以下书籍: 8 | 9 | * 《深度学习的数学》,作者:涌泉良幸; 10 | * 非常推荐《深入浅出神经网络与深度学习》,作者: 迈克尔·尼尔森; 11 | * 《动手学PyTorch建模与应用》,作者:王国平; 12 | * 《PyTorch深度学习实战》,作者:[美] 伊莱•史蒂文斯; 13 | * 《机器学习》,作者:周志华; 14 | 15 | 16 | 17 | 另外,笔者还推荐以下文章: 18 | 19 | 激活函数(Activation Function) -- 从线性转向非线性 https://zhuanlan.zhihu.com/p/656985797 20 | 21 | 为什么需要激活横竖?激活函数 https://blog.csdn.net/weixin_45751409/article/details/109851828 22 | 23 | 评估大模型显存 https://mp.weixin.qq.com/s/W_LiyC584qXLbwoxSBmnEg 24 | 25 | 模型格式和识别文件信息 https://juejin.cn/post/7408858126042726435 26 | 27 | 28 | 29 | 对于深度学习的路线,可以参考《动手深度学习-PyTorch(第二版)》李沐 30 | 31 | 在线版本:https://zh.d2l.ai/chapter_preface/index.html 32 | 33 | https://zh-v2.d2l.ai/d2l-zh-pytorch.pdf 34 | 35 | ![image-20241201075420519](images/image-20241201075420519.png) 36 | 37 | > 图来自:《动手深度学习-PyTorch(第二版)》 38 | 39 | 40 | 41 | ### 线性网络和多层感知机 42 | 43 | 神经网络是以神经元为基础的,这个跟生物上的神经元有所区别。下图是生物学上的神经元细胞图。 44 | 45 | ![image-20241130095650256](images/image-20241130095650256.png) 46 | 47 | > 图来自 《深度学习的数学》。 48 | 49 |
50 | 51 | 神经元由细胞体、轴突、树突组成,神经元有多个轴突,单细胞体收到刺激后,会通过轴突把信号传递给其它神经元。神经元通过树突接收从其它神经元传递过来的信号。 52 | 53 | 把神经元通过轴突向其它神经元传递信号的动作称为点火,传递的信号只有 1 和 0,并且同时向所有轴突程度信号,也就是所有被轴突连接到的神经元都会收到通知。 54 | 55 | 那么,神经元什么时候会点火呢。 56 | 57 | 神经元是有阈值的,神经元有多个树突,从不同的神经元接收信号,只有当这些信号达到阈值时,才能刺激神经元。 58 | 59 | ![image-20241201080533249](images/image-20241201080533249.png) 60 | 61 | 比如说,神经元 A 的信号阈值是 $a$ 有三个树突,分别连接了 $x_{1}$ 、 $x_{2}$ 、 $x_{3}$ 三个神经元,每个连接都有权重,那么: 62 | 63 | 64 | $$ 65 | \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} < \theta , y = 0\\ 66 | \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} \ge \theta , y = 1\\ 67 | $$ 68 | 69 | 70 | 71 |
72 | 73 | 看这个公式,如果把权重和神经元分开,相当于两个向量的内积。 74 | 75 | 76 | 77 | ![image-20241130141303272](images/image-20241130141303272.png) 78 | 79 |
这种情况下,输出值只有 0,1,我们把这种模型称为线性模型,关于神经元的模型和公式有多个变种,这里就不细聊了。 80 | 81 | 如果使用矩阵乘法表示,也可以写成: 82 | $$ 83 | [\omega{_{1}},\omega{_{2}},...,\omega{_{n}}] * [x_{1},x_{2},...,x_{n}] = \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + ... + \omega{_{n}}{x_{n}} 84 | $$ 85 | 86 | $$ 87 | y = \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + ... + \omega{_{n}}{x_{n}} - \theta 88 | $$ 89 | 90 | 91 | ### 神经网络 92 | 93 | 对应一个神经网络来说,会由多个层组成:输入层、隐藏层、输出层。 94 | 95 | 比如说,如果我们要设置一个模型识别图片进行分类,一个简化的例子是以图片大小为 `28*28`,用二维数组表示的话,即784个像素值。不过一般我们把这28*28的二维数组转换为一层线性数据,即784个神经元。也就是说,输入层的大小就是 784。 96 | 97 | 在实际应用中,我们常常会对图片做预处理,比如缩放图片的大小至固定值,转换为黑白图片,再转换为线性数据方便神经网络处理。 98 | 99 | 100 | 101 | ### 多层感知机(MLP) 102 | 103 | 多层感知机由多个感知机组成,每个感知机层由多个神经元构成。多层感知机包括输入层、一个或多个隐藏层以及输出层。通过一层一层的输入、计算和输出,神经网络能够提取和组合数据中的特征,并进行预测。 104 | 105 | 106 | 107 | ### 激活函数 108 | 109 | 有一类函数叫单位阶跃函数,如果我们将前面的神经元输入输出函数修改为: 110 | 111 | 112 | $$ 113 | \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} - \theta < 0, y = 0\\ 114 | \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} - \theta \ge 0 , y = 1\\ 115 | $$ 116 | 117 | 118 | 119 | 我们设 $z = \omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} - \theta$ , 上面的关系为 $u$ ,则: 120 | $$ 121 | y = u(z) = \left\{ 122 | \begin{aligned} 123 | 0 \quad (z < 0) \\ 124 | 1 \quad (z \ge 0) 125 | \end{aligned} 126 | \right. 127 | $$ 128 | 129 | 130 | 131 | 尽管单位阶跃函数很直观,但在深度学习中,通常使用其它的激活函数来引入非线性。 132 | 133 | 134 | 135 | 当然,在深度学习中,输出并不是只有 0 和 1,如果我们把 $u$ 替换为其它函数,那么: 136 | $$ 137 | y = a(z) = a(\omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} - \theta) 138 | $$ 139 | 在数学上一般使用 $b$ 来表示 $-\theta$, $b$ 称为偏置。 140 | 141 | 所以: 142 | $$ 143 | y = a(z) = a(\omega{_{1}}{x_{1}} + \omega{_{2}}{x_{2}} + \omega{_{3}}{x_{3}} + b) 144 | $$ 145 | 146 | 147 | 148 | 这里的函数 $a$ 被称为激活函数。 149 | 150 | 151 | 152 | 常见的激活函数包括: 153 | 154 | **Sigmoid 激活函数** :输出值在 0 到 1 之间,常用于二分类问题。但在高值或低值区域会有梯度消失的问题。 155 | 156 | **Tanh(双曲正切)激活函数** :输出值在 -1到 1 之间,相对于 Sigmoid 函数,tanh 函数收敛时的 0 均值特性更好,但同样存在梯度消失问题。 157 | 158 | **ReLU(Rectified Linear Unit)激活函数** :输出值为输入和 0 的较大值,计算简单且有效,能够减轻梯度消失问题 159 | 160 | **Leaky ReLU 激活函数** :是 ReLU 的变种,对于输入为负的小范围值允许小的梯度通过,从而减少“神经元死亡”风险。 161 | 162 | **ELU(Exponential Linear Unit)激活函数** :改善了 ReLU 的负输入问题,输出范围包括负值。 163 | 164 | **Softmax 激活函数** :一般用于多分类问题的输出层,将输入向量转化为概率分布,使得输出值之和为 1。 165 | 166 | **Swish 激活函数** :被 Google 研究提出,兼有 ReLU 的非负特性和 Sigmoid 的平滑特性,被认为在一些情况下效果优于 ReLU 。 167 | 168 | 169 | 170 | ### 神经网络的训练步骤 171 | 172 | 173 | 174 | ### 网络的定义 175 | 176 | 177 | 178 | 多层神经网络是怎么逐步传递的 179 | 180 | ![image-20241214094330314](images/image-20241214094330314.png) 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 单位阶跃函数。 189 | 190 | ![image-20241214093654062](images/image-20241214093654062.png) 191 | 192 | 193 | 194 | ![image-20241214094828150](images/image-20241214094828150.png) 195 | 196 | 197 | 198 | 199 | 200 | ![image-20241214095337053](images/image-20241214095337053.png) 201 | 202 | 203 | 204 | ### 神经网络分层 205 | 206 | #### 输入层 207 | 208 | #### 隐藏层 209 | 210 | 神经网络的权重的偏置。 211 | 212 | #### 输出层 213 | 214 | 215 | 216 | 感知机和多层网络 217 | 218 | #### 最优化 219 | 220 | 代价函数 221 | 222 | 优化器 223 | 224 | 225 | 226 | ### 向前传播、向后传播 227 | 228 | 前向传播(forward)和反向传播(backward) 229 | 230 | 参考 https://zhuanlan.zhihu.com/p/447113449 231 | 232 | 233 | 234 | ### 神经网络分类 235 | 236 | 卷积神经网络、循环神经网络、前馈神经网络。 237 | 238 | 239 | 240 | ### 卷积神经网络经典模型架构简介 241 | 242 | GoogleNet 等模型 243 | -------------------------------------------------------------------------------- /02.start/02.start_torch.md: -------------------------------------------------------------------------------- 1 | # 开始使用 Torch 2 | 3 | 本章内容主要基于 Pytorch 官方入门教程编写,使用 C# 代码代替 Python,主要内容包括处理数据、创建模型、优化模型参数、保存模型、加载模型,读者通过本章内容开始了解 TorchSharp 框架的使用方法。 4 | 5 |
6 | 7 | 官方教程: 8 | 9 | https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html 10 | 11 | 12 | 13 | ### 准备 14 | 15 | 创建一个控制台项目,示例代码参考 `example2.2`,通过 nuget 引入以下类库: 16 | 17 | ``` 18 | TorchSharp 19 | TorchSharp-cuda-windows 20 | TorchVision 21 | Maomi.Torch 22 | ``` 23 | 24 | 25 | 26 | 首先添加以下代码,查找最适合当前设备的工作方式,主要是选择 GPU 开发框架,例如 CUDA、MPS,CPU,有 GPU 就用 GPU,没有 GPU 降级为 CPU。 27 | 28 | ```csharp 29 | using Maomi.Torch; 30 | 31 | Device defaultDevice = MM.GetOpTimalDevice(); 32 | torch.set_default_device(defaultDevice); 33 | 34 | Console.WriteLine("当前正在使用 {defaultDevice}"); 35 | ``` 36 | 37 | 38 | 39 | ### 下载数据集 40 | 41 | 训练模型最重要的一步是准备数据,但是准备数据集是一个非常繁杂和耗时间的事情,对于初学者来说也不现实,所以 Pytorch 官方在框架集成了一些常见的数据集,开发者可以直接通过 API 使用这些提前处理好的数据集和标签。 42 | 43 | Pytorch 使用 `torch.utils.data.Dataset` 表示数据集抽象接口,存储了数据集的样本和对应标签;`torch.utils.data.DataLoader` 表示加载数据集的抽象接口,主要是提供了迭代器。这两套接口是非常重要的,对于开发者自定义的数据集,需要实现这两套接口,自定义加载数据集方式。 44 | 45 |
46 | 47 | Pytorch 有三大领域的类库,分别是 TorchText、TorchVision、TorchAudio,这三个库都自带了一些常用开源数据集,但是 .NET 里社区仓库只提供了 TorchVision,生态严重落后于 Pytorch。TorchVision 是一个工具集,可以从 Fashion-MNIST 等下载数据集以及进行一些数据类型转换等功能。 48 | 49 |
50 | 51 | 在本章中,使用的数据集叫 FashionMNIST,Pytorch 还提供了很多数据集,感兴趣的读者参考:https://pytorch.org/vision/stable/datasets.html 52 | 53 |
54 | 55 | 现在开始讲解如何通过 TorchSharp 框架加载 FashionMNIST 数据集,首先添加引用: 56 | 57 | ```csharp 58 | using TorchSharp; 59 | using static TorchSharp.torch; 60 | using datasets = TorchSharp.torchvision.datasets; 61 | using transforms = TorchSharp.torchvision.transforms; 62 | ``` 63 | 64 | 65 | 66 | 然后通过接口加载训练数据集和测试数据集: 67 | 68 | ```csharp 69 | // 指定训练数据集 70 | var training_data = datasets.FashionMNIST( 71 | root: "data", // 数据集在那个目录下 72 | train: true, // 加载该数据集,用于训练 73 | download: true, // 如果数据集不存在,是否下载 74 | target_transform: transforms.ConvertImageDtype(ScalarType.Float32) // 指定特征和标签转换,将标签转换为Float32 75 | ); 76 | 77 | // 指定测试数据集 78 | var test_data = datasets.FashionMNIST( 79 | root: "data", // 数据集在那个目录下 80 | train: false, // 加载该数据集,用于训练 81 | download: true, // 如果数据集不存在,是否下载 82 | target_transform: transforms.ConvertImageDtype(ScalarType.Float32) // 指定特征和标签转换,将标签转换为Float32 83 | ); 84 | ``` 85 | 86 |
87 | 88 | 部分参数解释如下: 89 | 90 | - `root` 是存放训练/测试数据的路径。 91 | - `train` 指定训练或测试数据集。 92 | - `download=True` 如果 `root` 中没有数据,则从互联网下载数据。 93 | - `transform` 和 `target_transform` 指定特征和标签转换。 94 | 95 |
96 | 97 | 注意,与 Python 版本有所差异, Pytorch 官方给出了 `ToTensor()` 函数用于将图像转换为 torch.Tensor 张量类型,但是由于 C# 版本并没有这个函数,因此只能手动指定一个转换器。 98 | 99 |
100 | 101 | 启动项目,会自动下载数据集,接着在程序运行目录下会自动创建一个 data 目录,里面是数据集文件,包括用于训练的数据和测试的数据集。 102 | 103 | ![image-20241202120839339](images/image-20241202120839339.png) 104 | 105 |
106 | 107 | 文件内容如下所示,子目录 test_data 里面的是测试数据集,用于检查模型训练情况和优化。 108 | 109 | ``` 110 | │ t10k-images-idx3-ubyte.gz 111 | │ t10k-labels-idx1-ubyte.gz 112 | │ train-images-idx3-ubyte.gz 113 | │ train-labels-idx1-ubyte.gz 114 | │ 115 | └───test_data 116 | t10k-images-idx3-ubyte 117 | t10k-labels-idx1-ubyte 118 | train-images-idx3-ubyte 119 | train-labels-idx1-ubyte 120 | ``` 121 | 122 | 123 | 124 | ### 显示图片 125 | 126 | 数据集是 Dataset 类型,继承了 `Dataset>` 类型,Dataset 本质是列表,我们把 Dataset 列表的 item 称为数据,每个 item 都是一个字典类型,**每个字典由 data、label 两个 key 组成**。 127 | 128 | 在上一节,已经编写好如何加载数据集,将训练数据和测试数据分开加载,为了了解 Dataset ,读者可以通过以下代码将数据集的结构打印到控制台。 129 | 130 | 131 | 132 | ```csharp 133 | for (int i = 0; i < training_data.Count; i++) 134 | { 135 | var dic = training_data.GetTensor(i); 136 | var img = dic["data"]; 137 | var label = dic["label"]; 138 | label.print(); 139 | } 140 | ``` 141 | 142 |
143 | 144 | 通过观察控制台,可以知道,每个数据元素都是一个字典,**每个字典由 data、label 两个 key 组成**,`dic["data"]` 是一个图片,而 label 就是表示该图片的文本值是什么。 145 | 146 |
147 | 148 | Maomi.Torch 框架提供了将张量转换为图片并显示的方法,例如下面在窗口显示数据集前面的三张图片: 149 | 150 | ```csharp 151 | for (int i = 0; i < training_data.Count; i++) 152 | { 153 | var dic = training_data.GetTensor(i); 154 | var img = dic["data"]; 155 | var label = dic["label"]; 156 | 157 | if (i > 2) 158 | { 159 | break; 160 | } 161 | 162 | img.ShowImage(); 163 | } 164 | ``` 165 | 166 | > 使用 Maomi.ScottPlot.Winforms 库,还可以通过 `img.ShowImageToForm()` 接口通过窗口的形式显示图片。 167 | 168 |
169 | 170 | 你也可以直接转存为图片: 171 | 172 | ``` 173 | img.SavePng("data/{i}.png"); 174 | ``` 175 | 176 | ![image-20250204215615584](images/image-20250204215615584.png) 177 | 178 | ### 加载数据集 179 | 180 | 由于 FashionMNIST 数据集有 6 万张图片,一次性加载所有图片比较消耗内存,并且一次性训练对 GPU 的要求也很高,因此我们需要分批处理数据集。 181 | 182 |
183 | 184 | `torch.utils.data` 中有数据加载器,可以帮助我们分批加载图片集到内存中,开发时使用迭代器直接读取,不需要关注分批情况。 185 | 186 | 如下面所示,分批加载数据集,批处理大小是 64 张图片。 187 | 188 | ```csharp 189 | // 分批加载图像,打乱顺序 190 | var train_loader = torch.utils.data.DataLoader(training_data, batchSize: 64, shuffle: true, device: defaultDevice); 191 | 192 | // 分批加载图像,不打乱顺序 193 | var test_loader = torch.utils.data.DataLoader(test_data, batchSize: 64, shuffle: false, device: defaultDevice); 194 | ``` 195 | 196 |
197 | 198 | 注意,分批是在 DataLoader 内部发生的,我们可以理解为缓冲区大小,对于开发者来说,并不需要关注分批情况。 199 | 200 | 201 | 202 | ### 定义网络 203 | 204 | 接下来定义一个神经网络,神经网络有多个层,通过神经网络来训练数据,通过数据的训练可以的出参数、权重等信息,这些信息会被保存到模型中,加载模型时,必须要有对应的网络结构,比如神经网络的层数要相同、每层的结构一致。 205 | 206 | 该网络通过接受 `28*28` 大小的图片,经过处理后输出 10 个分类值,每个分类结果都带有其可能的概率,概率最高的就是识别结果。 207 | 208 |
209 | 210 | 将以下代码存储到 NeuralNetwork.cs 中。 211 | 212 | ```csharp 213 | using TorchSharp.Modules; 214 | using static TorchSharp.torch; 215 | using nn = TorchSharp.torch.nn; 216 | 217 | public class NeuralNetwork : nn.Module 218 | { 219 | // 传递给基类的参数是模型的名称 220 | public NeuralNetwork() : base(nameof(NeuralNetwork)) 221 | { 222 | flatten = nn.Flatten(); 223 | linear_relu_stack = nn.Sequential( 224 | nn.Linear(28 * 28, 512), 225 | nn.ReLU(), 226 | nn.Linear(512, 512), 227 | nn.ReLU(), 228 | nn.Linear(512, 10)); 229 | 230 | // C# 版本需要调用这个函数,将模型的组件注册到模型中 231 | RegisterComponents(); 232 | } 233 | 234 | Flatten flatten; 235 | Sequential linear_relu_stack; 236 | 237 | public override Tensor forward(Tensor input) 238 | { 239 | // 将输入一层层处理并传递给下一层 240 | var x = flatten.call(input); 241 | var logits = linear_relu_stack.call(x); 242 | return logits; 243 | } 244 | } 245 | ``` 246 | 247 | > 注意,网络中只能定义字段,不要定义属性;不要使用 `_` 开头定义字段; 248 | 249 | 250 | 251 | 然后继续在 Program 里继续编写代码,初始化神经网络,并使用 GPU 来加载网络。 252 | 253 | ```csharp 254 | var model = new NeuralNetwork(); 255 | model.to(defaultDevice); 256 | ``` 257 | 258 | 259 | 260 | ### 优化模型参数 261 | 262 | 为了训练模型,需要定义一个损失函数和一个优化器,损失函数的主要作用是衡量模型的预测结果与真实标签之间的差异,即误差或损失,有了损失函数后,通过优化器可以指导模型参数的调整,使预测结果能够逐步靠近真实值,从而提高模型的性能。Pytorch 自带很多损失函数,这里使用计算交叉熵损失的损失函数。 263 | 264 | ```csharp 265 | // 定义损失函数、优化器和学习率 266 | var loss_fn = nn.CrossEntropyLoss(); 267 | var optimizer = torch.optim.SGD(model.parameters(), learningRate : 1e-3); 268 | ``` 269 | 270 |
271 | 272 | 同时,优化器也很重要,是用于调整模型参数以最小化损失函数的模块。 273 | 274 | 因为损失函数比较多,但是优化器就那么几个,所以这里简单列一下 Pytorch 中自带的一些优化器。 275 | 276 | * **SGD(随机梯度下降)**:通过按照损失函数的梯度进行线性步长更新权重; 277 | * **Adam(自适应矩估计)** :基于一阶和二阶矩估计的优化算法,它能自适应地调整学习率,对大多数问题效果较好; 278 | * **RMSprop**:适用于处理非平稳目标,能够自动进行学习率的调整; 279 | * **AdamW(带权重衰减的 Adam)** :在 Adam 的基础上添加了权重衰减(weight decay),防止过拟合。 280 | 281 | 282 | 283 | ### 训练模型 284 | 285 | 接下来讲解训练模型的步骤,如下代码所示。 286 | 287 | 下面是详细步骤: 288 | 289 | * 每读取一张图片,就使用神经网络进行**识别**(`.call()` 函数),`pred` 为**识别结果**; 290 | * 通过损失函数判断网络的识别结果和标签值的误差; 291 | * 通过损失函数反向传播,计算网络的梯度等; 292 | * 通过 SGD 优化器,按照损失函数的梯度进行线性步长更新权重,`optimizer.step()` 会调整模型的权重,根据计算出来的梯度来更新模型的参数,使模型逐步接近优化目标。 293 | * 因为数据是分批处理的,因此计算当前批次的梯度后,需要使用 `optimizer.zero_grad()` 重置当前所有梯度。 294 | * 计算训练成果,即打印当前训练进度和损失值。 295 | 296 | ```csharp 297 | static void Train(DataLoader dataloader, NeuralNetwork model, CrossEntropyLoss loss_fn, SGD optimizer) 298 | { 299 | var size = dataloader.dataset.Count; 300 | model.train(); 301 | 302 | int batch = 0; 303 | foreach (var item in dataloader) 304 | { 305 | var x = item["data"]; 306 | var y = item["label"]; 307 | 308 | // 第一步 309 | // 训练当前图片 310 | var pred = model.call(x); 311 | 312 | // 通过损失函数得出与真实结果的误差 313 | var loss = loss_fn.call(pred, y); 314 | 315 | // 第二步,反向传播 316 | loss.backward(); 317 | 318 | // 计算梯度并优化参数 319 | optimizer.step(); 320 | 321 | // 清空优化器当前的梯度 322 | optimizer.zero_grad(); 323 | 324 | // 每 100 次打印损失值和当前训练的图片数量 325 | if (batch % 100 == 0) 326 | { 327 | loss = loss.item(); 328 | 329 | // Pytorch 框架会在 x.shape[0] 存储当前批的位置 330 | var current = (batch + 1) * x.shape[0]; 331 | 332 | Console.WriteLine("loss: {loss.item(),7} [{current,5}/{size,5}]"); 333 | } 334 | 335 | batch++; 336 | } 337 | } 338 | ``` 339 | 340 | > torch.Tensor 类型的 `.shape` 属性比较特殊,是一个数组类型,主要用于存储当前类型的结构,要结合上下文才能判断,例如在当前训练中,`x.shape` 值是 `[64,1,28,28]`,`shape[1]` 是图像的通道,1 是灰色,3 是彩色(RGB三通道);`shape[2]`、`shape[3]` 分别是图像的长度和高度。 341 | 342 |
343 | 344 | 通过上面步骤可以看出,“训练” 是一个字面意思,跟人类的学习不一样,这里是先使用模型识别一个图片,然后计算误差,更新模型参数和权重,然后进入下一次调整。 345 | 346 |
347 | 348 | 训练模型的同时,我们还需要评估模型的准确率等信息,评估时需要使用测试图片来验证训练结果。 349 | 350 |
351 | 352 | ```csharp 353 | static void Test(DataLoader dataloader, NeuralNetwork model, CrossEntropyLoss loss_fn) 354 | { 355 | var size = (int)dataloader.dataset.Count; 356 | var num_batches = (int)dataloader.Count; 357 | 358 | // 将模型设置为评估模式 359 | model.eval(); 360 | 361 | var test_loss = 0F; 362 | var correct = 0F; 363 | 364 | using (var n = torch.no_grad()) 365 | { 366 | foreach (var item in dataloader) 367 | { 368 | var x = item["data"]; 369 | var y = item["label"]; 370 | 371 | // 使用已训练的参数预测测试数据 372 | var pred = model.call(x); 373 | 374 | // 计算损失值 375 | test_loss += loss_fn.call(pred, y).item(); 376 | correct += (pred.argmax(1) == y).type(ScalarType.Float32).sum().item(); 377 | } 378 | } 379 | 380 | test_loss /= num_batches; 381 | correct /= size; 382 | Console.WriteLine("Test Error: \n Accuracy: {(100 * correct):F1}%, Avg loss: {test_loss:F8} \n"); 383 | } 384 | ``` 385 | 386 |
387 | 388 | 389 | 390 | 下图是后面训练打印的日志,可以看出准确率是逐步上升的。 391 | 392 | ![image-20250205090040316](images/image-20250205090040316.png) 393 | 394 |
395 | 396 | 397 | 398 | 在 Program 中添加训练代码,我们使用训练数据集进行五轮训练,每轮训练都输出识别结果。 399 | 400 | ```csharp 401 | // 训练的轮数 402 | var epochs = 5; 403 | 404 | foreach (var epoch in Enumerable.Range(0, epochs)) 405 | { 406 | Console.WriteLine("Epoch {epoch + 1}\n-------------------------------"); 407 | Train(train_loader, model, loss_fn, optimizer); 408 | Test(train_loader, model, loss_fn); 409 | } 410 | 411 | Console.WriteLine("Done!"); 412 | ``` 413 | 414 | 415 | 416 | ### 保存和加载模型 417 | 418 | 经过训练后的模型,可以直接保存和加载,代码很简单,如下所示: 419 | 420 | ```csharp 421 | model.save("model.dat"); 422 | Console.WriteLine("Saved PyTorch Model State to model.dat"); 423 | 424 | model.load("model.dat"); 425 | ``` 426 | 427 | 428 | 429 | ### 使用模型识别图片 430 | 431 | 要使用模型识别图片,只需要使用 `var pred = model.call(x);` 即可,但是因为模型并不能直接输出识别结果,而是根据网络结构输出到每个神经元中,每个神经元都表示当前概率。在前面定义的网络中,`nn.Linear(512, 10))` 会输出 10 个分类结果,每个分类结果都带有概率,那么我们将概率最高的一个结果拿出来,就相当于图片的识别结果了。 432 | 433 | 代码如下所示,步骤讲解如下: 434 | 435 | * 因为模型和网络并不使用字符串表示每个分类结果,所以需要手动配置分类表。 436 | * 然后从测试数据集中选取第一个图片和标签,识别图片并获得序号。 437 | * 从分类字符串中通过序号获得分类名称。 438 | 439 | ```csharp 440 | var classes = new string[] { 441 | "T-shirt/top", 442 | "Trouser", 443 | "Pullover", 444 | "Dress", 445 | "Coat", 446 | "Sandal", 447 | "Shirt", 448 | "Sneaker", 449 | "Bag", 450 | "Ankle boot", 451 | }; 452 | 453 | // 设置为评估模式 454 | model.eval(); 455 | 456 | // 加载测试数据中的第一个图片以及其标签 457 | var x = test_data.GetTensor(0)["data"]; 458 | var y = test_data.GetTensor(0)["label"]; 459 | 460 | using (torch.no_grad()) 461 | { 462 | x = x.to(defaultDevice); 463 | var pred = model.call(x); 464 | var predicted = classes[pred[0].argmax(0).ToInt32()]; 465 | var actual = classes[y.ToInt32()]; 466 | Console.WriteLine("Predicted: \"{predicted}\", Actual: \"{actual}\""); 467 | } 468 | ``` 469 | 470 | 471 | 472 | 当然,使用 Maomi.Torch 的接口,可以很方便读取图片使用模型识别: 473 | 474 | ```csharp 475 | var img = MM.LoadImage("0.png"); 476 | using (torch.no_grad()) 477 | { 478 | img = img.to(defaultDevice); 479 | var pred = model.call(img); 480 | 481 | // 转换为归一化的概率 482 | var array = torch.nn.functional.softmax(pred, dim: 0); 483 | var max = array.ToFloat32Array().Max(); 484 | var predicted = classes[pred[0].argmax(0).ToInt32()]; 485 | 486 | Console.WriteLine("识别结果 {predicted},概率 {max * 100}%"); 487 | } 488 | ``` 489 | 490 | -------------------------------------------------------------------------------- /02.start/03.xl.md: -------------------------------------------------------------------------------- 1 | # 使用 Torch 训练模型 2 | 3 | 本章主要参考《破解深度学习》的第四章,在本章将会实现一个数字分类器,主要包括数据加载和处理、模型训练和保存、预训练模型加载,但是内容跟 [开始使用 Torch](02.start_torch.md) 一章差不多,只是数据集和网络定义不一样,通过本章的案例帮助读者进一步了解 TorchSharp 以及掌握模型训练的步骤和基础。 4 | 5 | > 本章代码请参考 example2.3。 6 | 7 |
8 | 9 | 搭建神经网络的一般步骤: 10 | 11 | ![image-20241204201648009](images/image-20241204201648009.png) 12 | 13 |
14 | 15 | 在上一篇中我们通过示例已经学习到相关的过程,所以本章会在之前的基础上继续讲解一些细节和步骤。 16 | 17 |
18 | 19 | 在上一章中,我们学习了如何下载和加载数据集,如果将数据集里面的图片导出,我们可以发现里面都是单个数字。 20 | 21 | 你可以使用 Maomi.Torch 包中的扩展方法将数据集转存到本地目录中。 22 | 23 | ```csharp 24 | for (int i = 0; i < training_data.Count; i++) 25 | { 26 | var dic = training_data.GetTensor(i); 27 | var img = dic["data"]; 28 | var label = dic["label"]; 29 | 30 | img.SaveJpeg("imgs/{i}.jpg"); 31 | } 32 | ``` 33 | 34 |
35 | 36 | 如图所示: 37 | 38 | ![image-20241204203025017](images/image-20241204203025017.png) 39 | 40 |
41 | 42 | 每个图片的大小是 `28*28=784`,所以神经网络的输入层的大小是 784。 43 | 44 | ![image-20241204204305065](images/image-20241204204305065.png) 45 | 46 |
47 | 48 | 我们直接知道,由于数据集的图片都是 `0-9` 的数字,都是灰度图像(没有彩色),因此模型训练结果的输出应该是 10 个,也就是神经网络的输出层神经元个数是 10。 49 | 50 |
51 | 52 | 神经网络的输入层是要固定大小是,表示神经元的个数输入是固定的,不是随时可以扩充的,也就是一个神经网络不能输入任意大小的图像,这些图像都要经过一定的算法出来,生成与神经网络输入层对应大小的图像。 53 | 54 | 55 | 56 | ### 定义神经网络 57 | 58 | 第一步,定义我们的网络模型,这是一个全连接网络,由激活函数和三个线性层组成。 59 | 60 | 该网络模型没有指定输入层和输出层的大小,这样该模型可以适配不同的图像分类任务,开发者在训练和加载模式时,指定输入层和输出层大小即可。 61 | 62 | 代码如下所示: 63 | 64 | ```csharp 65 | using TorchSharp; 66 | using static TorchSharp.torch; 67 | 68 | using nn = TorchSharp.torch.nn; 69 | 70 | public class MLP : nn.Module, IDisposable 71 | { 72 | private readonly int _inputSize; 73 | private readonly int _hiddenSize; 74 | private readonly int _numClasses; 75 | 76 | private TorchSharp.Modules.Linear fc1; 77 | private TorchSharp.Modules.ReLU relu; 78 | private TorchSharp.Modules.Linear fc2; 79 | private TorchSharp.Modules.Linear fc3; 80 | 81 | /// 82 | /// 输入层大小,图片的宽*高. 83 | /// 隐藏层大小. 84 | /// 输出层大小,例如有多少个分类. 85 | /// 86 | public MLP(int inputSize, int hiddenSize, int outputSize) : base(nameof(MLP)) 87 | { 88 | _inputSize = inputSize; 89 | _hiddenSize = hiddenSize; 90 | _numClasses = outputSize; 91 | 92 | // 定义激活函数和线性层 93 | relu = nn.ReLU(); 94 | fc1 = nn.Linear(inputSize, hiddenSize); 95 | fc2 = nn.Linear(hiddenSize, hiddenSize); 96 | fc3 = nn.Linear(hiddenSize, outputSize); 97 | 98 | RegisterComponents(); 99 | } 100 | 101 | public override torch.Tensor forward(torch.Tensor input) 102 | { 103 | // 一层一层传递 104 | // 第一层读取输入,然后传递给激活函数, 105 | // 第二层读取第一层的输出,然后传递给激活函数, 106 | // 第三层读取第二层的输出,然后生成输出结果 107 | var @out = fc1.call(input); 108 | @out = relu.call(@out); 109 | @out = fc2.call(@out); 110 | @out = relu.call(@out); 111 | @out = fc3.call(@out); 112 | return @out; 113 | } 114 | 115 | protected override void Dispose(bool disposing) 116 | { 117 | base.Dispose(disposing); 118 | fc1.Dispose(); 119 | relu.Dispose(); 120 | fc2.Dispose(); 121 | fc3.Dispose(); 122 | } 123 | } 124 | ``` 125 | 126 |
127 | 128 | 首先 fc1 作为第一层网络,输入的图像需要转换为一维结构,主要用于接收数据、数据预处理。由于绘图太麻烦了,这里用文字简单说明一下,例如图像是 `28*28`,也就是每行有 28 个像素,一共 28 行,那么使用一个 784 大小的数组可以将图像的每一行首尾连在一起,放到一个一维数组中。 129 | 130 | 由于图像都是灰度图像,一个黑白像素值在 0-255 之间(byte 类型),如果使用 `[0.0,1.0]` 之间表示黑白(float32 类型),那么输入像素表示为灰度,值为 0.0 表示白色,值为 1.0 表示黑色,中间数值表示灰度。 131 | 132 | > 大多数情况下,或者说在本教程中,图像的像素都是使用 float32 类型表示,即 torch.Tensor 存储的图像信息都是 float32 类型表示一个像素。 133 | 134 | ![image-20250205141415174](images/image-20250205141415174.png) 135 | 136 | > 图来自《深入浅出神经网络与深度学习》。 137 | 138 |
139 | 140 | fc2 是隐藏层,在本章示范的网络模型中,隐藏层只有一层,大小是 15 个神经元,承担者特征提取、非线性变换等职责,隐藏层的神经元数量是不定的,主要是根据经验来设置,然后根据训练的模型性能来调整。 141 | 142 |
143 | 144 | fc3 是输出层,根据提取的特征将输出推送到 10 个神经元中,每个神经元表示一个数值,每个神经元都会接收到消息,但是因为不同数字的特征和权重值不一样,所以每个神经元的值都不一样,接收到的值就是表示当前数字的可能性概率。 145 | 146 |
147 | 148 | 149 | 150 | ### 加载数据集 151 | 152 | 加载数据集的代码示例如下,由于上一章已经讲解过,因此这里就不再赘述。 153 | 154 | ```csharp 155 | // 1. 加载数据集 156 | 157 | // 从 MNIST 数据集下载数据或者加载已经下载的数据 158 | using var train_data = datasets.MNIST("./mnist/data", train: true, download: true, target_transform: transforms.ConvertImageDtype(ScalarType.Float32)); 159 | using var test_data = datasets.MNIST("./mnist/data", train: false, download: true, target_transform: transforms.ConvertImageDtype(ScalarType.Float32)); 160 | 161 | Console.WriteLine("Train data size: " + train_data.Count); 162 | Console.WriteLine("Test data size: " + test_data.Count); 163 | 164 | var batch_size = 100; 165 | // 分批加载图像,打乱顺序 166 | var train_loader = torch.utils.data.DataLoader(train_data, batchSize: batch_size, shuffle: true, defaultDevice); 167 | 168 | // 分批加载图像,不打乱顺序 169 | var test_loader = torch.utils.data.DataLoader(test_data, batchSize: batch_size, shuffle: false, defaultDevice); 170 | ``` 171 | 172 | 173 | 174 | ### 创建网络模型 175 | 176 | 由于 MNIST 数据集的图像都是 `28*28` 的,因此我们创建网络模型实例时,定义输入层为 784 大小。 177 | 178 | ```csharp 179 | // 输入层大小,按图片的宽高计算 180 | var input_size = 28 * 28; 181 | 182 | // 隐藏层大小,大小不固定,可以自己调整 183 | var hidden_size = 15; 184 | 185 | // 手动配置分类结果个数 186 | var num_classes = 10; 187 | 188 | var model = new MLP(input_size, hidden_size, num_classes); 189 | model.to(defaultDevice); 190 | ``` 191 | 192 | 193 | 194 | ### 定义损失函数 195 | 196 | 创建损失函数和优化器,这个学习率的大小也是依据经验和性能进行设置,没有什么规律,学习率的作用可以参考梯度下降算法中的知识。 197 | 198 | ```csharp 199 | // 创建损失函数 200 | var criterion = nn.CrossEntropyLoss(); 201 | 202 | // 学习率 203 | var learning_rate = 0.001; 204 | 205 | // 优化器 206 | var optimizer = optim.Adam(model.parameters(), lr: learning_rate); 207 | ``` 208 | 209 | 210 | 211 | ### 训练 212 | 213 | 开始训练模型,对数据集进行 10 轮训练,每轮训练都输出训练结果,这里不使用一张张图片测试准确率,而是一次性识别所有图片(一万张),然后计算平均准确率。 214 | 215 | ```csharp 216 | foreach (var epoch in Enumerable.Range(0, num_epochs)) 217 | { 218 | model.train(); 219 | int i = 0; 220 | foreach (var item in train_loader) 221 | { 222 | var images = item["data"]; 223 | var lables = item["label"]; 224 | 225 | images = images.reshape(-1, 28 * 28); 226 | var outputs = model.call(images); 227 | 228 | var loss = criterion.call(outputs, lables); 229 | 230 | optimizer.zero_grad(); 231 | 232 | loss.backward(); 233 | 234 | optimizer.step(); 235 | 236 | i++; 237 | if ((i + 1) % 300 == 0) 238 | { 239 | Console.WriteLine("Epoch [{(epoch + 1)}/{num_epochs}], Step [{(i + 1)}/{train_data.Count / batch_size}], Loss: {loss.ToSingle():F4}"); 240 | } 241 | } 242 | 243 | model.eval(); 244 | using (torch.no_grad()) 245 | { 246 | long correct = 0; 247 | long total = 0; 248 | 249 | foreach (var item in test_loader) 250 | { 251 | var images = item["data"]; 252 | var labels = item["label"]; 253 | 254 | images = images.reshape(-1, 28 * 28); 255 | var outputs = model.call(images); 256 | 257 | var (_, predicted) = torch.max(outputs, 1); 258 | total += labels.size(0); 259 | correct += (predicted == labels).sum().item(); 260 | } 261 | Console.WriteLine("Accuracy of the network on the 10000 test images: {100 * correct / total} %"); 262 | } 263 | } 264 | ``` 265 | 266 |
267 | 268 | 保存训练后的模型: 269 | 270 | ```csharp 271 | model.save("mnist_mlp_model.dat"); 272 | ``` 273 | 274 |
275 | 276 | 训练信息: 277 | 278 | ![image-20250205144041513](images/image-20250205144041513.png) 279 | 280 | 281 | 282 | ### 识别手写图像 283 | 284 | 如下示例图像所示,是一个手写数字。 285 | 286 | ![0](images/0.jpg) 287 | 288 |
重新加载模型: 289 | 290 | ```csharp 291 | 292 | model.save("mnist_mlp_model.dat"); 293 | model.load("mnist_mlp_model.dat"); 294 | 295 | 296 | // 把模型转为评估模式 297 | model.eval(); 298 | ``` 299 | 300 |
301 | 302 | 使用 Maomi.Torch 导入图片并转为 Tensor,然后将 `28*28` 转换为以为的 `784`。 303 | 304 | > 由于加载图像的时候默认是彩色的,所以需要将其转换为灰度图像,即 `channels=1`。 305 | 306 | ```csharp 307 | // 加载图片为张量 308 | var image = MM.LoadImage("5.jpg", channels: 1); 309 | image = image.to(defaultDevice); 310 | image = image.reshape(-1, 28 * 28); 311 | ``` 312 | 313 |
314 | 315 | 识别图像并输出结果: 316 | 317 | ```csharp 318 | using (torch.no_grad()) 319 | { 320 | var oputput = model.call(image); 321 | var prediction = oputput.argmax(dim: 1, keepdim: true); 322 | Console.WriteLine("Predicted Digit: " + prediction.item().ToString()); 323 | } 324 | ``` 325 | 326 |
327 | 328 | 当然,对应彩色的图像,也可以这样通过灰度转换处理,再进行层归一化,即可获得对应结构的 torch.Tensor。 329 | 330 | ```csharp 331 | image = image.reshape(-1, 28 * 28); 332 | 333 | var transform = transforms.ConvertImageDtype(ScalarType.Float32); 334 | var img = transform.call(image).unsqueeze(0); 335 | ``` 336 | 337 |
338 | 339 | 再如下图所示,随便搞了个数字,图像是 `212*212`,图像格式是 jpg。 340 | 341 | > 注意,由于数据集的图片都是 jpg 格式,因此要识别的图像,也需要使用 jpg 格式。 342 | 343 | 344 | 345 | ![6](images/6.jpg) 346 | 347 |
348 | 349 | 如下代码所示,首先使用 Maomi.Torch 加载图片,然后调整图像大小为 `28*28`,以区配网络模型的输入层大小。 350 | 351 | ```csharp 352 | // 加载图片为张量 353 | image = MM.LoadImage("6.jpg", channels: 1); 354 | image = image.to(defaultDevice); 355 | 356 | // 将图像转换为 28*28 大小 357 | image = transforms.Resize(28, 28).call(image); 358 | image = image.reshape(-1, 28 * 28); 359 | 360 | using (torch.no_grad()) 361 | { 362 | var oputput = model.call(image); 363 | var prediction = oputput.argmax(dim: 1, keepdim: true); 364 | Console.WriteLine("Predicted Digit: " + prediction.item().ToString()); 365 | } 366 | ``` 367 | 368 | -------------------------------------------------------------------------------- /02.start/04.models.md: -------------------------------------------------------------------------------- 1 | # 使用预训练模型 2 | 3 | 本章主要参考 《深度学习实战》(伊莱史蒂文斯) 中的示例,使用 resnet101 网络模型加载预训练的模型,识别图片中的动物。 4 | 5 | > ResNet-101 是残差网络,用于图像分类与预测。 6 | 7 |
8 | 9 | Pytorch 默认已经内置了很多网络,这些网络可以在 `TorchSharp.torchvision.models` 里面找到,当实例化网络时会自动下载模型,都是 TorchSharp 不包含模型下载功能,因为 TorchSharp 跟 Pytorch 的模型格式不兼容,因此笔者怎么对部分模型做了转换,可参考仓库 https://huggingface.co/whuanle/torchcsharp 10 | 11 | Maomi.Torch 默认提供的模型如下: 12 | 13 | ``` 14 | alexnet 15 | googlenet 16 | inception_v3 17 | mobilenet_v2 18 | mobilenet_v3_large 19 | mobilenet_v3_small 20 | resnet18 21 | resnet34 22 | resnet50 23 | wide_resnet50_2 24 | resnext50_32x4d 25 | resnet101 26 | resnext101_32x8d 27 | resnext101_64x4d 28 | wide_resnet101_2 29 | resnet152 30 | vgg11 31 | vgg11_bn 32 | vgg13 33 | vgg13_bn 34 | vgg16 35 | vgg16_bn 36 | vgg19 37 | vgg19_bn 38 | ``` 39 | 40 |
41 | 42 | 相同模型后面的数字表示网络层数,例如 resnet50 表示具有 50 层的网络。 43 | 44 |
45 | 46 | 创建一个控制台项目,示例代码参考 `example2.4`,通过 nuget 引入以下类库: 47 | 48 | ``` 49 | TorchSharp 50 | TorchSharp-cuda-windows 51 | TorchVision 52 | Maomi.Torch 53 | ``` 54 | 55 |
56 | 57 | 引入以下依赖: 58 | 59 | ``` 60 | ing Maomi.Torch; 61 | using TorchSharp; 62 | using TorchSharp.Modules; 63 | using static TorchSharp.torchvision; 64 | using model = TorchSharp.torchvision.models; 65 | ``` 66 | 67 | 68 | 69 | ### 使用预训练模型 70 | 71 | 如下代码所示,使用 TorchSharp.torchvision.models 创建一个 resnet101 网络模型实例,然后通过 Maomi.Torch 提供的扩展方法,从 huggingface 中下载模型文件,并自动加载到内存中,resnet101 大约有四千多万个参数。 72 | 73 | ```csharp 74 | var defaultDeface = MM.GetOpTimalDevice(); 75 | torch.set_default_device(defaultDeface); 76 | 77 | var resnet101 = model.resnet101(device: defaultDeface); 78 | resnet101 = resnet101.LoadResnet101(); 79 | resnet101.to(defaultDeface); 80 | resnet101.eval(); 81 | ``` 82 | 83 |
84 | 85 | 如果使用的是国内网络,访问 huggingface 受阻,可以使用 ModelScope 下载模型文件。 86 | 87 | ```csharp 88 | var resnet101 = model.resnet101(device: defaultDeface); 89 | 90 | MM.ReposityBase = MM.ModelScope; 91 | 92 | resnet101 = resnet101.LoadResnet101(); 93 | resnet101.to(defaultDeface); 94 | resnet101.eval(); 95 | ``` 96 | 97 | 98 | 99 | 默认模型会被下载到 `{User}/.cache/torchcsharp` 下,通过修改 `CSTORCH_HOME` 环境变量可以切换模型下载目录。 100 | 101 | 如果你想了解模型的参数数量,可以使用以下代码计算总参数数量: 102 | 103 | ```csharp 104 | var parameterCount = 0L; 105 | foreach (var item in resnet101.parameters()) 106 | { 107 | parameterCount += item.numel(); 108 | } 109 | Console.WriteLine(parameterCount); 110 | ``` 111 | 112 | 可以看到 `parameterCount=44549160`,该网络模型有四千四百多万个参数。 113 | 114 |
115 | 116 | ### 处理图像 117 | 118 | 由于 resnet101 网络模型的架构特点,我们不能直接使用模型识别图片,而是将图片整理成与输入层区配的结构,因此需要使用以下函数转换图片,并最终进行层归一化。 119 | 120 | ```csharp 121 | var preprocess = transforms.Compose( 122 | transforms.Resize(256), 123 | transforms.CenterCrop(224), 124 | transforms.ConvertImageDtype(torch.ScalarType.Float32), 125 | transforms.Normalize(means: new double[] { 0.485, 0.456, 0.406 }, stdevs: new double[] { 0.229, 0.224, 0.225 }) 126 | ); 127 | 128 | // 加载图形并缩放裁剪 129 | var img = MM.LoadImage("bobby.jpg"); 130 | img.to(defaultDeface); 131 | 132 | // 使用转换函数处理图形 133 | img = preprocess.call(img); 134 | 135 | img = img.reshape(3, img.shape[2], img.shape[3]); 136 | var batch_t = torch.unsqueeze(img, 0); 137 | ``` 138 | 139 |
140 | 141 | 通过 `transforms.Compose` 整合多个转换函数,生成一个对图像的预处理函数,对输入的图像张量进行重塑、裁剪和归一化处理,首先将图像缩放到 `256*256` 大小,然后围绕中心将 图像裁剪为224×224个像素,并将其转换为一个张量类型,最后对其 RGB 分量(红色、绿色和蓝色)进行归一化处理,使其具有定义的均值和标准差。 142 | 143 |
144 | 145 | 为什么经过 `preprocess` 转换图像后,还需要使用 `img.reshape(3, img.shape[2], img.shape[3])` 再处理一次图像,这是因为 TorchSharp 框架没有 Pytorch 那么简便,Pytorch 里面是弱类型和带有自动类型转换,C# 版本则麻烦一些,需要手动处理。 146 | 147 |
148 | 149 | 使用 Maomi.Torch 扩展方法,可以很容易将转换过程中的 torch.Tensor 类型以图像的显示显示出来: 150 | 151 | ```csharp 152 | img.ShowImage(); 153 | ``` 154 | 155 |
156 | 157 | 经过变换和层归一化的图像如下: 158 | 159 | ![tmpq43su1.tmp](images/tmpq43su1.tmp.png) 160 | 161 | ### 使用预训练模型识别图像 162 | 163 | 最后使用预训练模型识别经过处理后的图像,根据输出结果排序概率最大的五种情况,然后使用标签文件区配识别结果,最终以文字的显示输出信息。 164 | 165 |
166 | 167 | ```csharp 168 | var @out = resnet101.call(batch_t); 169 | @out.print(); 170 | 171 | List labels = new(); 172 | using (StreamReader sr = new StreamReader("imagenet_classes.txt")) 173 | { 174 | string? line; 175 | while ((line = sr.ReadLine()) != null) 176 | { 177 | labels.Add(line.Trim()); 178 | } 179 | } 180 | 181 | // 计算输出结果的分数。默认是 0.0-1.0,所以 *100 得出百分比 182 | var percentage = torch.nn.functional.softmax(@out, dim: 1)[0] * 100; 183 | 184 | // 对识别结果和分数进行排序 185 | var (_, indices) = torch.sort(@out, descending: true); 186 | 187 | // 输出概率前五的物品名称 188 | for (int i = 0; i < 5; i++) 189 | { 190 | Console.WriteLine("result:" + labels[(int)indices[0][i]] + ",chance:" + percentage[(int)indices[0][i]].item().ToString() + "%"); 191 | } 192 | ``` 193 | 194 |
输出: 195 | 196 | ``` 197 | result:golden retriever,chance:92.15422% 198 | result:Labrador retriever,chance:7.12242% 199 | result:redbone,chance:0.16837709% 200 | result:tennis ball,chance:0.16251208% 201 | result:cocker spaniel, English cocker spaniel, cocker,chance:0.15211052% 202 | ``` 203 | 204 | -------------------------------------------------------------------------------- /02.start/README.md: -------------------------------------------------------------------------------- 1 | # 入门神经网络和 Torch 2 | 3 | 在第二部分中,将会介绍神经网络基础知识、开始进行模型训练、模型保存加载等,读者通过第二部分的学习,对深度学习框架的使用有初步的了解,掌握网络的定义和模型的训练、加载等步骤的细节。 4 | 5 | 主要包括: 6 | 7 | 1,神经网络基础知识、线性模型、全连接层,内容比较简单,不深入讨论, 8 | 9 | 2,了解 Pytorch 怎么搭建神经网络,基础流程,内容要非常简单,不深入讨论。 10 | 11 | 3,使用一个示例简单入门,下还有参数优化的影响、,不深入讨论,各种卷积神经网络上的优化。 12 | 13 | 4,启动社区上已经有的模型, 14 | 15 | 5,了解神经网络的基础骨架 16 | -------------------------------------------------------------------------------- /02.start/images/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/0.jpg -------------------------------------------------------------------------------- /02.start/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/1.jpg -------------------------------------------------------------------------------- /02.start/images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/6.jpg -------------------------------------------------------------------------------- /02.start/images/bobby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/bobby.jpg -------------------------------------------------------------------------------- /02.start/images/boddy_preprocessed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/boddy_preprocessed.jpg -------------------------------------------------------------------------------- /02.start/images/boddy_preprocessed_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/boddy_preprocessed_1.jpg -------------------------------------------------------------------------------- /02.start/images/boddy_preprocessed_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/boddy_preprocessed_2.jpg -------------------------------------------------------------------------------- /02.start/images/image-20241130095650256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241130095650256.png -------------------------------------------------------------------------------- /02.start/images/image-20241130141303272.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241130141303272.png -------------------------------------------------------------------------------- /02.start/images/image-20241201075420519.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241201075420519.png -------------------------------------------------------------------------------- /02.start/images/image-20241201080533249.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241201080533249.png -------------------------------------------------------------------------------- /02.start/images/image-20241202120839339.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241202120839339.png -------------------------------------------------------------------------------- /02.start/images/image-20241204201648009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241204201648009.png -------------------------------------------------------------------------------- /02.start/images/image-20241204203025017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241204203025017.png -------------------------------------------------------------------------------- /02.start/images/image-20241204204305065.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241204204305065.png -------------------------------------------------------------------------------- /02.start/images/image-20241214093654062.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241214093654062.png -------------------------------------------------------------------------------- /02.start/images/image-20241214094330314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241214094330314.png -------------------------------------------------------------------------------- /02.start/images/image-20241214094828150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241214094828150.png -------------------------------------------------------------------------------- /02.start/images/image-20241214095337053.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241214095337053.png -------------------------------------------------------------------------------- /02.start/images/image-20241218003140880.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20241218003140880.png -------------------------------------------------------------------------------- /02.start/images/image-20250204215615584.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20250204215615584.png -------------------------------------------------------------------------------- /02.start/images/image-20250205084740229.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20250205084740229.png -------------------------------------------------------------------------------- /02.start/images/image-20250205090040316.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20250205090040316.png -------------------------------------------------------------------------------- /02.start/images/image-20250205141415174.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20250205141415174.png -------------------------------------------------------------------------------- /02.start/images/image-20250205144041513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/image-20250205144041513.png -------------------------------------------------------------------------------- /02.start/images/tmpq43su1.tmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/02.start/images/tmpq43su1.tmp.png -------------------------------------------------------------------------------- /03.image/README.md: -------------------------------------------------------------------------------- 1 | # 3,计算机视觉识别和图像处理技术 2 | 3 | 4 | 5 | 主要内容: 6 | 7 | 图像的各种原理、图像的转换技术 8 | 9 | 卷积神经网络,为什么要使用卷积神经网络 10 | 11 | 各类案例,图像分类、目标检测、图像分割等 -------------------------------------------------------------------------------- /03.image/Untitled 1.md: -------------------------------------------------------------------------------- 1 | [FiftyOne Installation — FiftyOne 1.3.0 documentation](https://docs.voxel51.com/getting_started/install.html) 2 | 3 | 4 | 5 | 详细安装教程 6 | 7 | [fiftyone · PyPI](https://pypi.org/project/fiftyone/) 8 | 9 | 10 | 11 | 12 | 13 | ``` 14 | pip install fiftyone 15 | ``` 16 | 17 | 18 | 19 | 安装 ffmpeg,需要使用超级管理员打开 powershell 或 cmd,执行命令安装: 20 | 21 | ``` 22 | choco install ffmpeg 23 | ``` 24 | 25 | 26 | 27 | 找一个空目录创建 main.py 和 fiftyone.bat 两个文件,内容分别为: 28 | 29 | ```python 30 | import fiftyone as fo 31 | 32 | session = fo.launch_app() 33 | session.wait() 34 | ``` 35 | 36 | 37 | 38 | ``` 39 | @echo off 40 | python main.py 41 | pause 42 | ``` 43 | 44 | 45 | 46 | 由于此时没有导入数据集,Fiftyone 界面是空白状态。 47 | 48 | ![image-20250216092937641](images/image-20250216092937641.png) -------------------------------------------------------------------------------- /03.image/dcgan_faces_tutorial.md: -------------------------------------------------------------------------------- 1 | # 通过**生成**对抗网络(GAN)训练和生成头像 2 | 3 | [TOC] 4 | 5 | ### 说明 6 | 7 | 本文根据 Pytorch 官方文档的示例移植而来,部分文字内容和图片来自 Pytorch 文档,文章后面不再单独列出引用说明。 8 | 9 | 官方文档地址: 10 | 11 | https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html 12 | 13 | > 社区中文翻译版本:https://pytorch.ac.cn/tutorials/beginner/dcgan_faces_tutorial.html 14 | 15 |
16 | 17 | Pytorch 示例项目仓库: 18 | 19 | https://github.com/pytorch/examples 20 | 21 | 对应 Python 版本示例:https://github.com/pytorch/tutorials/blob/main/beginner_source/dcgan_faces_tutorial.py 22 | 23 |
24 | 25 | 本文项目参考 dcgan 项目:https://github.com/whuanle/Maomi.Torch/tree/main/examples/dcgan 26 | 27 | 28 | 29 | ### 简介 30 | 31 | 本教程将通过一个示例介绍生成对抗网络(DCGAN),在教程中,我们将训练一个生成对抗网络 (GAN) 模型来生成新的名人头像。这里的大部分代码来自 [pytorch/examples](https://github.com/pytorch/examples) 中的 DCGAN 实现,然后笔者通过 C# 移植了代码实现,本文档将对该实现进行详尽的解释,并阐明该模型的工作原理和原因,阅读本文不需要 GAN 的基础知识,原理部分比较难理解,不用将精力放在这上面,主要是根据代码思路走一遍即可。 32 | 33 |
34 | 35 | 生成式对抗网络,简单来说就像笔者喜欢摄影,但是摄影水平跟专业摄影师有差距,然后不断苦练技术,每拍一张照片就让朋友判断是笔者拍的还是专业摄影师拍的,如果朋友一眼就发现是我拍的,说明水平还不行。然后一直练,一直拍,直到朋友区分不出照片是笔者拍的,还是专业摄影师拍的,这就是生成式对抗网络。 36 | 37 | 设计生成式对抗网络,需要设计生成网络和判断网络,生成网络读取训练图片并训练转换生成输出结果,然后由判断器识别,检查生成的图片和训练图片的差异,如果判断器可以区分出生成的图片和训练图片的差异,说明还需要继续训练,直到判断器区分不出来。 38 | 39 | 40 | 41 | ### 什么是 GAN 42 | 43 | GANs 是一种教深度学习模型捕捉训练数据分布的框架,这样我们可以从相同的分布生成新的数据。GANs 由 Ian Goodfellow 于 2014 年发明,并首次在论文 [Generative Adversarial Nets](https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf) 中描述。它们由两个不同的模型组成,一个是*生成器*,另一个是*判别器*。生成器的任务是生成看起来像训练图像的“假”图像。判别器的任务是查看图像,并输出它是否是真实训练图像或来自生成器的假图像。在训练期间,生成器不断尝试通过生成越来越好的假图像来欺骗判别器,而判别器则努力成为一名更好的侦探,正确分类真实图像和假图像。这场博弈的平衡点是生成器生成完美的假图像,看起来似乎直接来自训练数据,而判别器总是以 50% 的置信度猜测生成器的输出是真实的还是假的。 44 | 45 | 现在,让我们定义一些将在整个教程中使用的符号,从判别器开始。设 $x$ 为表示图像的数据。$D(x)$ 是判别器网络,输出 $x$ 来自训练数据而不是生成器的(标量)概率。这里,由于我们处理的是图像,$D(x)$ 的输入是 CHW 尺寸为 3x64x64 的图像。直观上,当 $x$ 来自训练数据时,$D(x)$ 应该是高的,而当 $x$ 来自生成器时,$D(x)$ 应该是低的。$D(x)$ 也可以视为传统的二分类器。 46 | 47 | 对于生成器的符号,设 $z$ 为从标准正态分布中采样的潜在空间向量。$G(z)$ 表示将潜在向量 $z$ 映射到数据空间的生成器函数。$G$ 的目标是估计训练数据来自的分布 ($p_{data}$),以便从该估计分布中生成假样本 ($p_g$)。 48 | 49 | 因此,$D(G(z))$ 是生成器输出 $G$ 为真实图像的概率(标量)。如 [Goodfellow 的论文](https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf) 中所描述,$D$ 和 $G$ 进行一个极小极大博弈,其中 $D$ 尽量最大化它正确分类真实和假的概率 ($logD(x)$),而 $G$ 尽量最小化 $D$ 预测其输出为假的概率 ($log(1-D(G(z)))$)。在这篇论文中,GAN 损失函数为 50 | 51 | $$\underset{G}{\text{min}} \underset{D}{\text{max}}V(D,G) = \mathbb{E}_{x\sim p_{data}(x)}\big[logD(x)\big] + \mathbb{E}_{z\sim p_{z}(z)}\big[log(1-D(G(z))\big]$$ 52 | 53 | 理论上,这个极小极大博弈的解是 $p_g = p_{data}$,而判别器随机猜测输入是真实的还是假的。然而,GANs 的收敛理论仍在积极研究中,实际上模型并不总是能够训练到这一点。 54 | 55 | 56 | 57 | ### 什么是 DCGAN 58 | 59 | DCGAN 是上述 GAN 的直接扩展,不同之处在于它在判别器和生成器中明确使用了卷积层和反卷积层。Radford 等人在论文[《利用深度卷积生成对抗网络进行无监督表示学习》](https://arxiv.org/pdf/1511.06434.pdf)中首次描述了这种方法。判别器由步幅卷积层、[批量归一化](https://pytorch.org/docs/stable/nn.html#torch.nn.BatchNorm2d)层以及[LeakyReLU](https://pytorch.org/docs/stable/nn.html#torch.nn.LeakyReLU)激活函数组成。输入是一个 3x64x64 的输入图像,输出是一个标量概率,表示输入是否来自真实的数据分布。生成器由[反卷积](https://pytorch.org/docs/stable/nn.html#torch.nn.ConvTranspose2d)层、批量归一化层和[ReLU](https://pytorch.org/docs/stable/nn.html#relu)激活函数组成。输入是从标准正态分布中抽取的潜在向量 $z$,输出是一个 3x64x64 的 RGB 图像。步幅的反卷积层允许将潜在向量转换为具有与图像相同形状的体积。在论文中,作者还提供了一些如何设置优化器、如何计算损失函数以及如何初始化模型权重的建议,这些将在后续章节中解释。 60 | 61 |
62 | 63 | 然后引入依赖并配置训练参数: 64 | 65 | ```csharp 66 | using dcgan; 67 | using Maomi.Torch; 68 | using System.Diagnostics; 69 | using TorchSharp; 70 | using TorchSharp.Modules; 71 | using static TorchSharp.torch; 72 | 73 | // 使用 GPU 启动 74 | Device defaultDevice = MM.GetOpTimalDevice(); 75 | torch.set_default_device(defaultDevice); 76 | 77 | // Set random seed for reproducibility 78 | var manualSeed = 999; 79 | 80 | // manualSeed = random.randint(1, 10000) # use if you want new results 81 | Console.WriteLine("Random Seed:" + manualSeed); 82 | random.manual_seed(manualSeed); 83 | torch.manual_seed(manualSeed); 84 | 85 | Options options = new Options() 86 | { 87 | Dataroot = "E:\\datasets\\celeba", 88 | // 设置这个可以并发加载数据集,加快训练速度 89 | Workers = 10, 90 | BatchSize = 128, 91 | }; 92 | ``` 93 | 94 | > 稍后讲解如何下载图片数据集。 95 | 96 |
97 | 98 | 用于训练的人像图片数据集大概是 22万张,不可能一次性全部加载,所以需要设置 BatchSize 参数分批导入、分批训练,如果读者的 GPU 性能比较高,则可以设置大一些。 99 | 100 | 101 | 102 | ### 参数说明 103 | 104 | 前面提到了 Options 模型类定义训练模型的参数,下面给出每个参数的详细说明。 105 | 106 | > 注意字段名称略有差异,并且移植版本并不是所有参数都用上。 107 | 108 | - `dataroot` - 数据集文件夹根目录的路径。我们将在下一节中详细讨论数据集。 109 | - `workers` - 用于使用 `DataLoader` 加载数据的工作线程数。 110 | - `batch_size` - 训练中使用的批大小。DCGAN 论文使用 128 的批大小。 111 | - `image_size` - 用于训练的图像的空间大小。此实现默认为 64x64。如果需要其他大小,则必须更改 D 和 G 的结构。有关更多详细信息,请参阅 [此处](https://github.com/pytorch/examples/issues/70)。 112 | - `nc` - 输入图像中的颜色通道数。对于彩色图像,此值为 3。 113 | - `nz` - 潜在向量的长度。 114 | - `ngf` - 与通过生成器传递的特征图的深度有关。 115 | - `ndf` - 设置通过判别器传播的特征图的深度。 116 | - `num_epochs` - 要运行的训练 epoch 数。训练时间越长可能会带来更好的结果,但也会花费更长的时间。 117 | - `lr` - 训练的学习率。如 DCGAN 论文中所述,此数字应为 0.0002。 118 | - `beta1` - Adam 优化器的 beta1 超参数。如论文中所述,此数字应为 0.5。 119 | - `ngpu` - 可用的 GPU 数量。如果此值为 0,则代码将在 CPU 模式下运行。如果此数字大于 0,则它将在那几个 GPU 上运行。 120 | 121 |
122 | 123 | 首先定义一个全局参数模型类,并设置默认值: 124 | 125 | ```csharp 126 | public class Options 127 | { 128 | /// 129 | /// Root directory for dataset 130 | /// 131 | public string Dataroot { get; set; } = "data/celeba"; 132 | 133 | /// 134 | /// Number of workers for dataloader 135 | /// 136 | public int Workers { get; set; } = 2; 137 | 138 | /// 139 | /// Batch size during training 140 | /// 141 | public int BatchSize { get; set; } = 128; 142 | 143 | /// 144 | /// Spatial size of training images. All images will be resized to this size using a transformer. 145 | /// 146 | public int ImageSize { get; set; } = 64; 147 | 148 | /// 149 | /// Number of channels in the training images. For color images this is 3 150 | /// 151 | public int Nc { get; set; } = 3; 152 | 153 | /// 154 | /// Size of z latent vector (i.e. size of generator input) 155 | /// 156 | public int Nz { get; set; } = 100; 157 | 158 | /// 159 | /// Size of feature maps in generator 160 | /// 161 | public int Ngf { get; set; } = 64; 162 | 163 | /// 164 | /// Size of feature maps in discriminator 165 | /// 166 | public int Ndf { get; set; } = 64; 167 | 168 | /// 169 | /// Number of training epochs 170 | /// 171 | public int NumEpochs { get; set; } = 5; 172 | 173 | /// 174 | /// Learning rate for optimizers 175 | /// 176 | public double Lr { get; set; } = 0.0002; 177 | 178 | /// 179 | /// Beta1 hyperparameter for Adam optimizers 180 | /// 181 | public double Beta1 { get; set; } = 0.5; 182 | 183 | /// 184 | /// Number of GPUs available. Use 0 for CPU mode. 185 | /// 186 | public int Ngpu { get; set; } = 1; 187 | } 188 | ``` 189 | 190 | 191 | 192 | ### 数据集处理 193 | 194 | 本教程中,我们将使用 [Celeb-A Faces 数据集](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html) 来训练模型,可以从链接网站或在 [Google Drive](https://drive.google.com/drive/folders/0B7EVK8r0v71pTUZsaXdaSnZBZzg) 下载。 195 | 196 | 数据集官方地址:https://mmlab.ie.cuhk.edu.hk/projects/CelebA.html 197 | 198 | 可以通过 Google 网盘或百度网盘下载: 199 | 200 | https://drive.google.com/drive/folders/0B7EVK8r0v71pWEZsZE9oNnFzTm8?resourcekey=0-5BR16BdXnb8hVj6CNHKzLg&usp=sharing 201 | 202 | https://pan.baidu.com/s/1CRxxhoQ97A5qbsKO7iaAJg 203 | 204 | > 提取码:`rp0s` 205 | 206 |
207 | 208 | 注意,本文只需要用到图片,不需要用到标签,不用下载所有文件,只需要下载 `CelebA/Img/img_align_celeba.zip` 即可。下载后解压到一个空目录中,其目录结构示例: 209 | 210 | ```sh 211 | /path/to/celeba 212 | -> img_align_celeba 213 | -> 188242.jpg 214 | -> 173822.jpg 215 | -> 284702.jpg 216 | -> 537394.jpg 217 | ... 218 | ``` 219 | 220 |
221 | 222 | 然后在 `Options.Dataroot` 参数填写 `/path/to/celeba` 即可,导入数据集时会自动搜索该目录下的子目录,将子目录作为图像的分类名称,然后向子目录加载所有图像文件。 223 | 224 |
225 | 226 | 这是一个重要步骤,因为我们将使用 `ImageFolder` 数据集类,该类要求数据集根文件夹中有子目录。现在,我们可以创建数据集,创建数据加载器,设置运行设备,并最终可视化一些训练数据。 227 | 228 |
229 | 230 | ```csharp 231 | // 创建一个 samples 目录用于输出训练过程中产生的输出效果 232 | if(Directory.Exists("samples")) 233 | { 234 | Directory.Delete("samples", true); 235 | } 236 | 237 | Directory.CreateDirectory("samples"); 238 | 239 | // 加载图像并对图像做转换处理 240 | var dataset = MM.Datasets.ImageFolder(options.Dataroot, torchvision.transforms.Compose( 241 | torchvision.transforms.Resize(options.ImageSize), 242 | torchvision.transforms.CenterCrop(options.ImageSize), 243 | torchvision.transforms.ConvertImageDtype(ScalarType.Float32), 244 | torchvision.transforms.Normalize(new double[] { 0.5, 0.5, 0.5 }, new double[] { 0.5, 0.5, 0.5 })) 245 | ); 246 | 247 | // 分批加载图像 248 | var dataloader = torch.utils.data.DataLoader(dataset, batchSize: options.BatchSize, shuffle: true, num_worker: options.Workers, device: defaultDevice); 249 | 250 | var netG = new dcgan.Generator(options).to(defaultDevice); 251 | ``` 252 | 253 |
254 | 255 | 在设置好输入参数并准备好数据集后,我们现在可以进入实现部分。我们将从权重初始化策略开始,然后详细讨论生成器、判别器、损失函数和训练循环。 256 | 257 |
258 | 259 | ### 权重初始化 260 | 261 | 根据 DCGAN 论文,作者指出所有模型权重应从均值为 0,标准差为 0.02 的正态分布中随机初始化。`weights_init` 函数以已初始化的模型为输入,重新初始化所有卷积层、转置卷积层和批量归一化层以满足此标准。此函数在模型初始化后立即应用于模型。 262 | 263 |
264 | 265 | ```csharp 266 | static void weights_init(nn.Module m) 267 | { 268 | var classname = m.GetType().Name; 269 | if (classname.Contains("Conv")) 270 | { 271 | if (m is Conv2d conv2d) 272 | { 273 | nn.init.normal_(conv2d.weight, 0.0, 0.02); 274 | } 275 | } 276 | else if (classname.Contains("BatchNorm")) 277 | { 278 | if (m is BatchNorm2d batchNorm2d) 279 | { 280 | nn.init.normal_(batchNorm2d.weight, 1.0, 0.02); 281 | nn.init.zeros_(batchNorm2d.bias); 282 | } 283 | } 284 | } 285 | 286 | ``` 287 | 288 |
289 | 290 | 网络模型会有多层结构,模型训练时到不同的层时会自动调用 weights_init 函数初始化,作用对象不是模型本身,而是网络模型的层。 291 | 292 | ![1739107119297](images/1739107119297.png) 293 | 294 | 295 | 296 | ### 生成器 297 | 298 | 生成器 $G$ 旨在将潜在空间向量 ( $z$ ) 映射到数据空间。由于我们的数据是图像,将 $z$ 转换为数据空间意味着最终要创建一个与训练图像具有相同大小的 RGB 图像 (即 3x64x64)。在实践中,这是通过一系列步幅为二维的卷积转置层来实现的,每一层都配有一个 2d 批量规范化层和一个 relu 激活函数。生成器的输出通过一个 tanh 函数返回到输入数据范围 $[-1,1]$ 。值得注意的是在 conv-transpose 层之后存在批量规范化函数,因为这是 DCGAN 论文的重要贡献之一。这些层有助于训练期间梯度的流动。下图显示了 DCGAN 论文中的生成器。 299 | 300 | ![dcgan_generator](images/dcgan_generator.png) 301 | 302 |
请注意,我们在输入部分设置的输入(`nz`,`ngf`,和 `nc`)如何影响代码中生成器的架构。`nz` 是 z 输入向量的长度,`ngf` 与在生成器中传播的特征图的大小有关,而 `nc` 是输出图像中的通道数(对于 RGB 图像设置为 3)。下面是生成器的代码。 303 | 304 |
305 | 306 | 定义图像生成的网络模型: 307 | 308 | ```csharp 309 | public class Generator : nn.Module, IDisposable 310 | { 311 | private readonly Options _options; 312 | 313 | public Generator(Options options) : base(nameof(Generator)) 314 | { 315 | _options = options; 316 | main = nn.Sequential( 317 | // input is Z, going into a convolution 318 | nn.ConvTranspose2d(options.Nz, options.Ngf * 8, 4, 1, 0, bias: false), 319 | nn.BatchNorm2d(options.Ngf * 8), 320 | nn.ReLU(true), 321 | // state size. (ngf*8) x 4 x 4 322 | nn.ConvTranspose2d(options.Ngf * 8, options.Ngf * 4, 4, 2, 1, bias: false), 323 | nn.BatchNorm2d(options.Ngf * 4), 324 | nn.ReLU(true), 325 | // state size. (ngf*4) x 8 x 8 326 | nn.ConvTranspose2d(options.Ngf * 4, options.Ngf * 2, 4, 2, 1, bias: false), 327 | nn.BatchNorm2d(options.Ngf * 2), 328 | nn.ReLU(true), 329 | // state size. (ngf*2) x 16 x 16 330 | nn.ConvTranspose2d(options.Ngf * 2, options.Ngf, 4, 2, 1, bias: false), 331 | nn.BatchNorm2d(options.Ngf), 332 | nn.ReLU(true), 333 | // state size. (ngf) x 32 x 32 334 | nn.ConvTranspose2d(options.Ngf, options.Nc, 4, 2, 1, bias: false), 335 | nn.Tanh() 336 | // state size. (nc) x 64 x 64 337 | ); 338 | 339 | RegisterComponents(); 340 | } 341 | 342 | public override Tensor forward(Tensor input) 343 | { 344 | return main.call(input); 345 | } 346 | 347 | Sequential main; 348 | } 349 | ``` 350 | 351 |
352 | 353 | 初始化模型: 354 | 355 | ```csharp 356 | var netG = new dcgan.Generator(options).to(defaultDevice); 357 | netG.apply(weights_init); 358 | Console.WriteLine(netG); 359 | ``` 360 | 361 | 362 | 363 | ### 判别器 364 | 365 | 如前所述,判别器 $D$ 是一个二分类网络,它以图像为输入并输出一个标量概率,即输入图像是真实的(而非伪造的)的概率。这里,$D$ 接受一个 3x64x64 的输入图像,通过一系列的 Conv2d、BatchNorm2d 和 LeakyReLU 层进行处理,并通过 Sigmoid 激活函数输出最终的概率。根据问题的需要,可以扩展这一架构以包含更多层数,但使用跨步卷积、BatchNorm 和 LeakyReLUs 是有意义的。DCGAN 论文提到,使用跨步卷积而非池化来进行下采样是一个好习惯,因为它使网络能够学习其自己的池化函数。此外,批量规范化和 leaky relu 函数促进了健康的梯度流动,这对 $G$ 和 $D$ 的学习过程至关重要。 366 | 367 |
368 | 369 | 定义判别器网络模型: 370 | 371 | ```csharp 372 | public class Discriminator : nn.Module, IDisposable 373 | { 374 | private readonly Options _options; 375 | 376 | public Discriminator(Options options) : base(nameof(Discriminator)) 377 | { 378 | _options = options; 379 | 380 | main = nn.Sequential( 381 | // input is (nc) x 64 x 64 382 | nn.Conv2d(options.Nc, options.Ndf, 4, 2, 1, bias: false), 383 | nn.LeakyReLU(0.2, inplace: true), 384 | // state size. (ndf) x 32 x 32 385 | nn.Conv2d(options.Ndf, options.Ndf * 2, 4, 2, 1, bias: false), 386 | nn.BatchNorm2d(options.Ndf * 2), 387 | nn.LeakyReLU(0.2, inplace: true), 388 | // state size. (ndf*2) x 16 x 16 389 | nn.Conv2d(options.Ndf * 2, options.Ndf * 4, 4, 2, 1, bias: false), 390 | nn.BatchNorm2d(options.Ndf * 4), 391 | nn.LeakyReLU(0.2, inplace: true), 392 | // state size. (ndf*4) x 8 x 8 393 | nn.Conv2d(options.Ndf * 4, options.Ndf * 8, 4, 2, 1, bias: false), 394 | nn.BatchNorm2d(options.Ndf * 8), 395 | nn.LeakyReLU(0.2, inplace: true), 396 | // state size. (ndf*8) x 4 x 4 397 | nn.Conv2d(options.Ndf * 8, 1, 4, 1, 0, bias: false), 398 | nn.Sigmoid() 399 | ); 400 | 401 | RegisterComponents(); 402 | } 403 | 404 | public override Tensor forward(Tensor input) 405 | { 406 | var output = main.call(input); 407 | 408 | return output.view(-1, 1).squeeze(1); 409 | } 410 | 411 | Sequential main; 412 | } 413 | ``` 414 | 415 |
416 | 417 | 初始化模型: 418 | 419 | ```csharp 420 | var netD = new dcgan.Discriminator(options).to(defaultDevice); 421 | netD.apply(weights_init); 422 | Console.WriteLine(netD); 423 | ``` 424 | 425 | 426 | 427 | ### 损失函数和优化器 428 | 429 | 设置好 $D$ 和 $G$ 后,我们可以通过损失函数和优化器指定它们的学习方式。我们将使用二元交叉熵损失函数([BCELoss](https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html#torch.nn.BCELoss)),它在 PyTorch 中定义如下: 430 | 431 | $$ 432 | \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - \left[ y_n \cdot \log x_n + (1 - y_n) \cdot \log (1 - x_n) \right] 433 | $$ 434 | 435 | 436 |
437 | 438 | 请注意,这个函数提供了目标函数中两个对数分量,即 $log(D(x))$ 和 $log(1-D(G(z)))$ 的计算。我们可以通过 $y$ 输入来指定使用 BCE 方程的哪一部分。这将在即将到来的训练循环中完成,但是了解我们可以通过改变 $y$(即 GT 标签)选择希望计算的分量非常重要。 439 | 440 | 接下来,我们将真实标签定义为 1,假的标签定义为 0。这些标签将在计算 $D$ 和 $G$ 的损失时使用,这也是原始 GAN 论文中使用的约定。最后,我们设置两个独立的优化器,一个用于 $D$,另一个用于 $G$。根据 DCGAN 论文的规定,两者都是 Adam 优化器,学习率为 0.0002,Beta1 = 0.5。为了追踪生成器的学习进展,我们将生成一个从高斯分布中抽取的固定批次的潜在向量(即 fixed_noise)。在训练循环中,我们将定期将这个 fixed_noise 输入 $G$,并且在迭代过程中,我们将看到图像从噪声中形成。 441 | 442 |
443 | 444 | ```csharp 445 | var criterion = nn.BCELoss(); 446 | var fixed_noise = torch.randn(new long[] { options.BatchSize, options.Nz, 1, 1 }, device: defaultDevice); 447 | var real_label = 1.0; 448 | var fake_label = 0.0; 449 | var optimizerD = torch.optim.Adam(netD.parameters(), lr: options.Lr, beta1: options.Beta1, beta2: 0.999); 450 | var optimizerG = torch.optim.Adam(netG.parameters(), lr: options.Lr, beta1: options.Beta1, beta2: 0.999); 451 | ``` 452 | 453 | 454 | 455 | 456 | 457 | ### 训练 458 | 459 | 最后,在我们定义了GAN框架的所有部分之后,我们可以开始训练它了。请注意,训练GANs在某种程度上是一门艺术,因为不正确的超参数设置会导致模式崩溃,并且很难解释出了什么问题。在这里,我们将紧密遵循 [Goodfellow的论文](https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf) 中的算法1,同时遵循一些在[ganhacks](https://github.com/soumith/ganhacks)中显示的最佳实践。具体来说,我们将“为真实和虚假的图像构建不同的小批量”,并调整G的目标函数以最大化 $log(D(G(z)))$ 。训练分为两个主要部分:第一部分更新判别器,第二部分更新生成器。 460 | 461 | **第1部分 - 训练判别器** 462 | 463 | 回顾一下,训练判别器的目标是最大化正确分类给定输入为真实或虚假的概率。根据Goodfellow的说法,我们希望“通过上升随机梯度来更新判别器”。实际上,我们希望最大化 $log(D(x)) + log(1-D(G(z)))$ 。根据 [ganhacks](https://github.com/soumith/ganhacks) 的独立小批量建议,我们将分两步计算这一点。首先,我们将从训练集中构建一个真实样本的小批量,前向传递通过 $D$,计算损失 ( $log(D(x))$ ) ,然后反向传递计算梯度。其次,我们将使用当前的生成器构建一个虚假样本的小批量,将此批次前向传递通过 $D$,计算损失 ( $log(1-D(G(z)))$ ),并通过反向传递*累积*梯度。现在,随着从全真和全假批次累积的梯度,我们调用判别器优化器的一步。 464 | 465 | **第2部分 - 训练生成器** 466 | 467 | 如原论文所述,我们希望通过最小化 $log(1-D(G(z)))$ 来训练生成器,以便生成更好的虚假样本。如前所述,Goodfellow 显示这在学习过程中尤其是早期不会提供足够的梯度。作为解决方案,我们希望最大化 $log(D(G(z)))$ 。在代码中,我们通过以下方法实现这一点:使用判别器对第1部分生成器的输出进行分类,使用真实标签作为GT计算G的损失,在反向传递中计算G的梯度,最后用优化器一步更新G的参数。使用真实标签作为损失函数的GT标签可能看起来违反直觉,但这允许我们使用 `BCELoss` 的 $log(x)$ 部分(而不是 $log(1-x)$ 部分),这正是我们所需要的。 468 | 469 | 最后,我们将进行一些统计报告,并且在每个epoch结束时,我们将通过生成器推送我们的固定噪声批次,以便直观地跟踪G的训练进度。报告的训练统计数据包括: 470 | 471 | - **Loss\_D** - 判别器损失,计算为全真和全假批次损失的总和 ( $log(D(x)) + log(1 - D(G(z)))$ )。 472 | - **Loss\_G** - 生成器损失,计算为 $log(D(G(z)))$ 473 | - **D(x)** - 判别器对全真批次的平均输出(跨批次)。这应该从接近 1 开始,然后在G变好时理论上收敛到 0.5。想想这是为什么。 474 | - **D(G(z))** - 判别器对全假批次的平均输出。第一个数字是 D 更新之前的,第二个数字是 D 更新之后的。这些数字应该从接近0开始,并在 G 变好时收敛到 0.5。想想这是为什么。 475 | 476 | **注意:** 这一步可能需要一段时间,具体取决于你运行了多少个epochs以及是否从数据集中删除了一些数据。 477 | 478 |
479 | 480 | ```csharp 481 | var img_list = new List(); 482 | var G_losses = new List(); 483 | var D_losses = new List(); 484 | 485 | Console.WriteLine("Starting Training Loop..."); 486 | 487 | Stopwatch stopwatch = new(); 488 | stopwatch.Start(); 489 | int i = 0; 490 | // For each epoch 491 | for (int epoch = 0; epoch < options.NumEpochs; epoch++) 492 | { 493 | foreach (var item in dataloader) 494 | { 495 | var data = item[0]; 496 | 497 | netD.zero_grad(); 498 | // Format batch 499 | var real_cpu = data.to(defaultDevice); 500 | var b_size = real_cpu.size(0); 501 | var label = torch.full(new long[] { b_size }, real_label, dtype: ScalarType.Float32, device: defaultDevice); 502 | // Forward pass real batch through D 503 | var output = netD.forward(real_cpu); 504 | // Calculate loss on all-real batch 505 | var errD_real = criterion.call(output, label); 506 | // Calculate gradients for D in backward pass 507 | errD_real.backward(); 508 | var D_x = output.mean().item(); 509 | 510 | // Train with all-fake batch 511 | // Generate batch of latent vectors 512 | var noise = torch.randn(new long[] { b_size, options.Nz, 1, 1 }, device: defaultDevice); 513 | // Generate fake image batch with G 514 | var fake = netG.call(noise); 515 | label.fill_(fake_label); 516 | // Classify all fake batch with D 517 | output = netD.call(fake.detach()); 518 | // Calculate D's loss on the all-fake batch 519 | var errD_fake = criterion.call(output, label); 520 | // Calculate the gradients for this batch, accumulated (summed) with previous gradients 521 | errD_fake.backward(); 522 | var D_G_z1 = output.mean().item(); 523 | // Compute error of D as sum over the fake and the real batches 524 | var errD = errD_real + errD_fake; 525 | // Update D 526 | optimizerD.step(); 527 | 528 | //////////////////////////// 529 | // (2) Update G network: maximize log(D(G(z))) 530 | //////////////////////////// 531 | netG.zero_grad(); 532 | label.fill_(real_label); // fake labels are real for generator cost 533 | // Since we just updated D, perform another forward pass of all-fake batch through D 534 | output = netD.call(fake); 535 | // Calculate G's loss based on this output 536 | var errG = criterion.call(output, label); 537 | // Calculate gradients for G 538 | errG.backward(); 539 | var D_G_z2 = output.mean().item(); 540 | // Update G 541 | optimizerG.step(); 542 | 543 | // ex: [0/25][4/3166] Loss_D: 0.5676 Loss_G: 7.5972 D(x): 0.9131 D(G(z)): 0.3024 / 0.0007 544 | Console.WriteLine($"[{epoch}/{options.NumEpochs}][{i%dataloader.Count}/{dataloader.Count}] Loss_D: {errD.item():F4} Loss_G: {errG.item():F4} D(x): {D_x:F4} D(G(z)): {D_G_z1:F4} / {D_G_z2:F4}"); 545 | 546 | // 每处理 100 批,输出一次图片效果 547 | if (i % 100 == 0) 548 | { 549 | real_cpu.SaveJpeg("samples/real_samples.jpg"); 550 | fake = netG.call(fixed_noise); 551 | fake.detach().SaveJpeg("samples/fake_samples_epoch_{epoch:D3}.jpg"); 552 | } 553 | 554 | i++; 555 | } 556 | 557 | 558 | netG.save("samples/netg_{epoch}.dat"); 559 | netD.save("samples/netd_{epoch}.dat"); 560 | } 561 | ``` 562 | 563 |
564 | 565 | 最后打印训练结果和输出: 566 | 567 | ```csharp 568 | Console.WriteLine("Training finished."); 569 | stopwatch.Stop(); 570 | Console.WriteLine("Training Time: {stopwatch.Elapsed}"); 571 | 572 | netG.save("samples/netg.dat"); 573 | netD.save("samples/netd.dat"); 574 | ``` 575 | 576 |
577 | 578 | 按照官方示例推荐进行 25 轮训练,由于笔者使用使用 4060TI 8G 机器训练,训练 25 轮大概时间: 579 | 580 | ``` 581 | Training finished. 582 | Training Time: 00:49:45.6976041 583 | ``` 584 | 585 |
586 | 587 | 每轮训练结果的图像: 588 | 589 | ![image-20250210183009016](images/image-20250210183009016.png) 590 | 591 |
第一轮训练生成: 592 | 593 | ![image-20250210205818778](images/image-20250210205818778.png) 594 | 595 |
596 | 597 | 第 25 轮生成的: 598 | 599 | ![image-20250210214910109](images/image-20250210214910109.png) 600 | 601 |
602 | 603 | 虽然还是有些抽象,但生成结果比之前好一些了。 604 | 605 | 606 | 607 | 在 dcgan_out 项目中开业看到,使用 5 轮训练结果输出的模型,生成图像: 608 | 609 | ```csharp 610 | Device defaultDevice = MM.GetOpTimalDevice(); 611 | torch.set_default_device(defaultDevice); 612 | 613 | // Set random seed for reproducibility 614 | var manualSeed = 999; 615 | 616 | // manualSeed = random.randint(1, 10000) # use if you want new results 617 | Console.WriteLine("Random Seed:" + manualSeed); 618 | random.manual_seed(manualSeed); 619 | torch.manual_seed(manualSeed); 620 | 621 | 622 | Options options = new Options() 623 | { 624 | Dataroot = "E:\\datasets\\celeba", 625 | Workers = 10, 626 | BatchSize = 128, 627 | }; 628 | 629 | var netG = new dcgan.Generator(options); 630 | netG.to(defaultDevice); 631 | netG.load("netg.dat"); 632 | 633 | // 生成随机噪声 634 | var fixed_noise = torch.randn(64, options.Nz, 1, 1, device: defaultDevice); 635 | 636 | // 生成图像 637 | var fake_images = netG.call(fixed_noise); 638 | 639 | fake_images.SaveJpeg("fake_images.jpg"); 640 | ``` 641 | 642 |
虽然还是有些抽象,但确实还行。 643 | 644 | ![fake_images](images/fake_images.jpg) -------------------------------------------------------------------------------- /03.image/frcnn.md: -------------------------------------------------------------------------------- 1 | COCO数据集是一个大型的、丰富的物体检测,分割和字幕数据集。这个数据集以scene understanding为目标,主要从复杂的日常场景中截取,图像中的目标通过精确的segmentation进行位置的标定。图像包括91类目标,328,000影像和2,500,000个label。目前为止有语义分割的最大数据集,提供的类别有80 类,有超过33 万张图片,其中20 万张有标注,整个数据集中个体的数目超过150 万个。 2 | 3 | [COCO - Common Objects in Context](https://cocodataset.org/#download) 4 | 5 | 6 | 7 | training validation testing images 8 | 9 | ![1739665463017](images/1739665463017.png) 10 | 11 | 12 | 13 | 由于国内网络下载实在太慢,因此我们通过 OpenDataLab 开源数据集仓库平台下载, 14 | 15 | [数据集-OpenDataLab](https://opendatalab.com/OpenDataLab/COCO_2017) 16 | 17 | 18 | 19 | 执行命令下载: 20 | 21 | ``` 22 | openxlab dataset get --dataset-repo OpenDataLab/COCO_2017 23 | ``` 24 | 25 | 26 | 27 | 由于整个仓库接近 50G,下载和解压需要很长时间,所以需要耐心等待,在等待过程中,先把代码写一下。 28 | 29 | -------------------------------------------------------------------------------- /03.image/images/1739107119297.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/1739107119297.png -------------------------------------------------------------------------------- /03.image/images/1739449592381.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/1739449592381.png -------------------------------------------------------------------------------- /03.image/images/1739665463017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/1739665463017.png -------------------------------------------------------------------------------- /03.image/images/airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/airplane.jpg -------------------------------------------------------------------------------- /03.image/images/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/cat.jpg -------------------------------------------------------------------------------- /03.image/images/copy-button.svg+xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /03.image/images/dcgan_generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/dcgan_generator.png -------------------------------------------------------------------------------- /03.image/images/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/dog.jpg -------------------------------------------------------------------------------- /03.image/images/fake_images.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/fake_images.jpg -------------------------------------------------------------------------------- /03.image/images/image-20250210183009016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250210183009016.png -------------------------------------------------------------------------------- /03.image/images/image-20250210205818778.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250210205818778.png -------------------------------------------------------------------------------- /03.image/images/image-20250210214910109.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250210214910109.png -------------------------------------------------------------------------------- /03.image/images/image-20250213202802853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250213202802853.png -------------------------------------------------------------------------------- /03.image/images/image-20250213203259114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250213203259114.png -------------------------------------------------------------------------------- /03.image/images/image-20250213210939996.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250213210939996.png -------------------------------------------------------------------------------- /03.image/images/image-20250215205033982.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250215205033982.png -------------------------------------------------------------------------------- /03.image/images/image-20250216092937641.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/03.image/images/image-20250216092937641.png -------------------------------------------------------------------------------- /03.image/vgg.md: -------------------------------------------------------------------------------- 1 | # 图像分类 | VGG大规模图像识别的超深度卷积网络 2 | 3 | 本文主要讲解用于大规模图像识别的超深度卷积网络 VGG,通过 VGG 实现自有数据集进行图像分类训练模型和识别,VGG 有 vgg11、vgg11_bn、vgg13、vgg13_bn、vgg16、vgg16_bn、vgg19、vgg19_bn 等变种,VGG 架构的实现可参考论文:[https://arxiv.org/abs/1409.1556](https://arxiv.org/abs/1409.1556) 4 | 5 | > 论文中文版地址: 6 | > 7 | > [https://noahsnail.com/2017/08/17/2017-08-17-VGG论文翻译——中文版/](https://noahsnail.com/2017/08/17/2017-08-17-VGG论文翻译——中文版/) 8 | 9 | 10 | 11 | ### 数据集 12 | 13 | 本文主要使用经典图像分类数据集 CIFAR-10 进行训练,CIFAR-10 数据集中有 10 个分类,每个类别均有 60000 张图像,50000 张训练图像和 10000 张测试图像,每个图像都经过了预处理,生成 32x32 彩色图像。 14 | 15 | CIFAR-10 的 10 个分类分别是: 16 | 17 | ``` 18 | airplane 19 | automobile 20 | bird 21 | cat 22 | deer 23 | dog 24 | frog 25 | horse 26 | ship 27 | truck 28 | ``` 29 | 30 | 31 | 32 | 下面给出几种数据集的本地化导入方式。 33 | 34 | 35 | 36 | #### 直接下载 37 | 38 | 由于 CIFAR-10 是经典数据集,因此 TorchSharp 默认支持下载该数据集,但是由于网络问题,国内下载数据库需要开飞机,数据集自动下载和导入: 39 | 40 | ```csharp 41 | // 加载训练和验证数据 42 | 43 | var train_dataset = datasets.CIFAR10(root: "E:/datasets/CIFAR-10", train: true, download: true, target_transform: transform); 44 | var val_dataset = datasets.CIFAR10(root: "E:/datasets/CIFAR-10", train: false, download: true, target_transform: transform); 45 | ``` 46 | 47 | 48 | 49 | ### opendatalab 数据集社区 50 | 51 | opendatalab 是一个开源数据集社区仓库,里面有大量免费下载的数据集,借此机会给读者讲解一下如何从 opendatalab 下载数据集,这对读者学习非常有帮助。 52 | 53 | CIFAR-10 数据集仓库地址: 54 | 55 | [https://opendatalab.com/OpenDataLab/CIFAR-10/cli/main](https://opendatalab.com/OpenDataLab/CIFAR-10/cli/main) 56 | 57 | 58 | 59 | 打开 https://opendatalab.com 注册账号,然后在个人信息中心添加密钥。 60 | 61 | ![1739449592381](images/1739449592381.png) 62 | 63 | 64 | 65 | 然后下载 openxlab 提供的 cli 工具: 66 | 67 | ```bash 68 | pip install openxlab #安装 69 | ``` 70 | 71 | 72 | 73 | 安装 openxlab 后,会要求添加路径到环境变量,环境变量地址是 Scripts 地址,示例: 74 | 75 | ``` 76 | C:\Users\%USER%\AppData\Roaming\Python\Python312\Scripts 77 | ``` 78 | 79 | 80 | 81 | 接着进行登录,输入命令后按照提示输入 key 和 secret: 82 | 83 | 84 | ```bash 85 | openxlab login # 进行登录,输入对应的AK/SK,可在个人中心查看AK/SK 86 | ``` 87 | 88 | 89 | 90 | 然后打开空目录下载数据集,数据集仓库会被下载到 `OpenDataLab___CIFAR-10` 目录中: 91 | 92 | ```bash 93 | openxlab dataset info --dataset-repo OpenDataLab/CIFAR-10 # 数据集信息及文件列表查看 94 | 95 | openxlab dataset get --dataset-repo OpenDataLab/CIFAR-10 #数据集下载 96 | ``` 97 | 98 | 99 | 100 | ![image-20250213203259114](images/image-20250213203259114.png) 101 | 102 | 103 | 104 | 数据集信息及文件列表查看 105 | 106 | ``` 107 | openxlab dataset info --dataset-repo OpenDataLab/CIFAR-10 108 | ``` 109 | 110 | 111 | 112 | ![image-20250213202802853](images/image-20250213202802853.png) 113 | 114 | 115 | 116 | 下载的文件比较多,但是我们只需要用到 `cifar-10-binary.tar.gz`,直接解压 `cifar-10-binary.tar.gz` 到目录中(也可以不解压)。 117 | 118 | ![image-20250213210939996](images/image-20250213210939996.png) 119 | 120 | 121 | 122 | 然后导入数据: 123 | 124 | ```csharp 125 | // 加载训练和验证数据 126 | 127 | var train_dataset = datasets.CIFAR10(root: "E:/datasets/OpenDataLab___CIFAR-10", train: true, download: false, target_transform: transform); 128 | var val_dataset = datasets.CIFAR10(root: "E:/datasets/OpenDataLab___CIFAR-10", train: false, download: false, target_transform: transform); 129 | ``` 130 | 131 | 132 | 133 | ### 自定义数据集 134 | 135 | Maomi.Torch 提供了自定义数据集导入方式,降低了开发者制作数据集的难度。自定义数据集也要区分训练数据集和测试数据集,训练数据集用于特征识别和训练,而测试数据集用于验证模型训练的准确率和损失值。 136 | 137 | 测试数据集和训练数据集可以放到不同的目录中,具体名称没有要求,然后每个分类单独一个目录,目录名称就是分类名称,按照目录名称的排序从 0 生成标签值。 138 | 139 | ``` 140 | ├─test 141 | │ ├─airplane 142 | │ ├─automobile 143 | │ ├─bird 144 | │ ├─cat 145 | │ ├─deer 146 | │ ├─dog 147 | │ ├─frog 148 | │ ├─horse 149 | │ ├─ship 150 | │ └─truck 151 | └─train 152 | │ ├─airplane 153 | │ ├─automobile 154 | │ ├─bird 155 | │ ├─cat 156 | │ ├─deer 157 | │ ├─dog 158 | │ ├─frog 159 | │ ├─horse 160 | │ ├─ship 161 | │ └─truck 162 | ``` 163 | 164 | ![image-20250215205033982](images/image-20250215205033982.png) 165 | 166 | 167 | 168 | 169 | 170 | 读者可以参考 `exportdataset`项目,将 CIFAR-10 数据集生成导出到目录中。 171 | 172 | 173 | 174 | 通过自定义目录导入数据集的代码为: 175 | 176 | ```csharp 177 | var train_dataset = MM.Datasets.ImageFolder(root: "E:/datasets/t1/train", target_transform: transform); 178 | var val_dataset = MM.Datasets.ImageFolder(root: "E:/datasets/t1/test", target_transform: transform); 179 | ``` 180 | 181 | 182 | 183 | ### 模型训练 184 | 185 | 定义图像预处理转换代码,代码如下所示: 186 | 187 | ```csharp 188 | Device defaultDevice = MM.GetOpTimalDevice(); 189 | torch.set_default_device(defaultDevice); 190 | 191 | Console.WriteLine("当前正在使用 {defaultDevice}"); 192 | 193 | // 数据预处理 194 | var transform = transforms.Compose([ 195 | transforms.Resize(32, 32), 196 | transforms.ConvertImageDtype( ScalarType.Float32), 197 | MM.transforms.ReshapeTransform(new long[]{ 1,3,32,32}), 198 | transforms.Normalize(means: new double[] { 0.485, 0.456, 0.406 }, stdevs: new double[] { 0.229, 0.224, 0.225 }), 199 | MM.transforms.ReshapeTransform(new long[]{ 3,32,32}) 200 | ]); 201 | ``` 202 | 203 | 204 | 205 | 因为 TorchSharp 对图像维度处理的兼容性不好,没有 Pytorch 的自动处理,因此导入的图片维度和批处理维度、transforms 处理的维度兼容性不好,容易报错,因此这里需要使用 Maomi.Torch 的转换函数,以便在导入图片和进行图像批处理的时候,保障 shape 符合要求。 206 | 207 | 208 | 209 | 分批加载数据集: 210 | 211 | ```csharp 212 | // 加载训练和验证数据 213 | 214 | var train_dataset = datasets.CIFAR10(root: "E:/datasets/CIFAR-10", train: true, download: true, target_transform: transform); 215 | var val_dataset = datasets.CIFAR10(root: "E:/datasets/CIFAR-10", train: false, download: true, target_transform: transform); 216 | 217 | var train_loader = new DataLoader(train_dataset, batchSize: 1024, shuffle: true, device: defaultDevice, num_worker: 10); 218 | var val_loader = new DataLoader(val_dataset, batchSize: 1024, shuffle: false, device: defaultDevice, num_worker: 10); 219 | ``` 220 | 221 | 222 | 223 | 初始化 vgg16 网络: 224 | 225 | ```csharp 226 | var model = torchvision.models.vgg16(num_classes: 10); 227 | model.to(device: defaultDevice); 228 | ``` 229 | 230 | 231 | 232 | 设置损失函数和优化器: 233 | 234 | ```csharp 235 | var criterion = nn.CrossEntropyLoss(); 236 | var optimizer = optim.SGD(model.parameters(), learningRate: 0.001, momentum: 0.9); 237 | ``` 238 | 239 | 240 | 241 | 训练模型并保存: 242 | 243 | ```csharp 244 | int num_epochs = 150; 245 | 246 | for (int epoch = 0; epoch < num_epochs; epoch++) 247 | { 248 | model.train(); 249 | double running_loss = 0.0; 250 | int i = 0; 251 | foreach (var item in train_loader) 252 | { 253 | var (inputs, labels) = (item["data"], item["label"]); 254 | var inputs_device = inputs.to(defaultDevice); 255 | var labels_device = labels.to(defaultDevice); 256 | 257 | optimizer.zero_grad(); 258 | var outputs = model.call(inputs_device); 259 | var loss = criterion.call(outputs, labels_device); 260 | loss.backward(); 261 | optimizer.step(); 262 | 263 | running_loss += loss.item() * inputs.size(0); 264 | Console.WriteLine($"[{epoch}/{num_epochs}][{i % train_loader.Count}/{train_loader.Count}]"); 265 | i++; 266 | } 267 | double epoch_loss = running_loss / train_dataset.Count; 268 | Console.WriteLine($"Train Loss: {epoch_loss:F4}"); 269 | 270 | model.eval(); 271 | long correct = 0; 272 | int total = 0; 273 | using (torch.no_grad()) 274 | { 275 | foreach (var item in val_loader) 276 | { 277 | var (inputs, labels) = (item["data"], item["label"]); 278 | 279 | var inputs_device = inputs.to(defaultDevice); 280 | var labels_device = labels.to(defaultDevice); 281 | var outputs = model.call(inputs_device); 282 | var predicted = outputs.argmax(1); 283 | total += (int)labels.size(0); 284 | correct += (predicted == labels_device).sum().item(); 285 | } 286 | } 287 | 288 | double val_accuracy = 100.0 * correct / total; 289 | Console.WriteLine($"Validation Accuracy: {val_accuracy:F2}%"); 290 | } 291 | 292 | model.save("model.dat"); 293 | ``` 294 | 295 | 296 | 297 | 启动项目后可以直接执行训练,训练一百多轮后,准确率在 70% 左右,损失值在 `0.0010` 左右,继续训练已经提高不了准确率了。 298 | 299 | 导出的模型坏事比较大的: 300 | 301 | ``` 302 | 513M model.dat 303 | ``` 304 | 305 | 306 | 307 | 下面来编写图像识别测试,在示例项目 `vggdemo` 中自带了三张图片,读者可以直接导入使用。 308 | 309 | ```csharp 310 | 311 | model.load("model.dat"); 312 | model.to(device: defaultDevice); 313 | model.eval(); 314 | 315 | 316 | var classes = new string[] { 317 | "airplane", 318 | "automobile", 319 | "bird", 320 | "cat", 321 | "deer", 322 | "dog", 323 | "frog", 324 | "horse", 325 | "ship", 326 | "truck" 327 | }; 328 | 329 | List imgs = new(); 330 | imgs.Add(transform.call(MM.LoadImage("airplane.jpg").to(defaultDevice)).view(1, 3, 32, 32)); 331 | imgs.Add(transform.call(MM.LoadImage("cat.jpg").to(defaultDevice)).view(1, 3, 32, 32)); 332 | imgs.Add(transform.call(MM.LoadImage("dog.jpg").to(defaultDevice)).view(1, 3, 32, 32)); 333 | 334 | using (torch.no_grad()) 335 | { 336 | 337 | foreach (var data in imgs) 338 | { 339 | var outputs = model.call(data); 340 | 341 | var index = outputs[0].argmax(0).ToInt32(); 342 | 343 | // 转换为归一化的概率 344 | // outputs.shape = [1,10],所以取 [dim:1] 345 | var array = torch.nn.functional.softmax(outputs, dim: 1); 346 | var max = array[0].ToFloat32Array(); 347 | var predicted1 = classes[index]; 348 | Console.WriteLine($"识别结果 {predicted1},准确率:{max[index] * 100}%"); 349 | } 350 | } 351 | ``` 352 | 353 | 354 | 355 | 识别结果: 356 | 357 | ``` 358 | 当前正在使用 cuda:0 359 | 识别结果 airplane,准确率:99.99983% 360 | 识别结果 cat,准确率:99.83113% 361 | 识别结果 dog,准确率:100% 362 | ``` 363 | 364 | 365 | 366 | 用到的三张图片均从网络上搜索而来: 367 | 368 | ![airplane](images/airplane.jpg) 369 | 370 | ![cat](images/cat.jpg) 371 | 372 | ![dog](images/dog.jpg) 373 | -------------------------------------------------------------------------------- /04.nlp/README.md: -------------------------------------------------------------------------------- 1 | # 4,自然语言处理 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM nginx:latest 3 | COPY _book /usr/share/nginx/html -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 文档说明 2 | 3 | 教程名称:使用 C# 入门深度学习 4 | 5 | 作者:痴者工良 6 | 7 | 教程地址: 8 | 9 | [https://torch.whuanle.cn](https://torch.whuanle.cn) 10 | 11 |
12 | 13 | 电子书仓库:https://github.com/whuanle/cs_pytorch 14 | 15 | Maomi.Torch 项目仓库:https://github.com/whuanle/Maomi.Torch 16 | 17 |
18 | 19 | ## 导读 20 | 21 | 本教程通过使用 C# ,学习数学基础、Pytorch 框架、深度学习等,目前还在编写中。 22 | 23 | - 教程中每个小节都有代码示例 24 | - 深入原理,讲解深层知识 25 | - 由易到难,从入门到掌握 26 | - 循序渐进,一步步学习,一步步拓展知识面 27 | - 内容完整、齐全,可以系统式学习 28 | - 大量代码示例和场景实践 29 | 30 | 31 | 32 | ### 目录 33 | 34 | * [文档导读](README.md) 35 | * [第一部分:基础](./01.base/README.md) 36 | * [搭建深度学习环境](./01.base/01.env.md) 37 | * [Pytorch 基础](./01.base/02.base.md) 38 | * [线性代数基础](./01.base/03.linear.md) 39 | * [微积分和梯度下降](./01.base/04.higher.md) 40 | * [概率论基础](./01.base/05.odds.md) 41 | * [第二部分:入门案例](./02.start/README.md) 42 | * [神经网络基础知识](./02.start/01.neural_network.md) 43 | * [使用神经网络训练模型-案例一](./02.start/02.start_torch.md) 44 | * [使用神经网络训练模型-案例二](./02.start/03.xl.md) 45 | * [使用预训练模型](./02.start/04.models.md) 46 | * [第三部分:计算机视觉](03.image/README.md) 47 | * [通过生成对抗网络(GAN)训练和生成头像](03.image/dcgan_faces_tutorial.md) 48 | * [图像分类 | VGG大规模图像识别的超深度卷积网络](03.image/vgg.md) 49 | * [未整理]() 50 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # 使用 C# 入门深度学习 2 | 3 | * [文档导读](README.md) 4 | * [第一部分:基础](./01.base/README.md) 5 | * [搭建深度学习环境](./01.base/01.env.md) 6 | * [Pytorch 基础](./01.base/02.base.md) 7 | * [线性代数基础](./01.base/03.linear.md) 8 | * [微积分和梯度下降](./01.base/04.higher.md) 9 | * [概率论基础](./01.base/05.odds.md) 10 | * [第二部分:入门案例](./02.start/README.md) 11 | * [神经网络基础知识](./02.start/01.neural_network.md) 12 | * [使用神经网络训练模型-案例一](./02.start/02.start_torch.md) 13 | * [使用神经网络训练模型-案例二](./02.start/03.xl.md) 14 | * [使用预训练模型](./02.start/04.models.md) 15 | * [第三部分:计算机视觉](03.image/README.md) 16 | * [通过生成对抗网络(GAN)训练和生成头像](03.image/dcgan_faces_tutorial.md) 17 | * [图像分类 | VGG大规模图像识别的超深度卷积网络](03.image/vgg.md) 18 | * [未整理]() 19 | 20 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "tbfed-pagefooter", 4 | "mermaid-gb3", 5 | "insert-logo", 6 | "chapter-fold", 7 | "advanced-emoji", 8 | "github", 9 | "splitter", 10 | "alerts", 11 | "popup", 12 | "prism", 13 | "hide-element", 14 | "head-append", 15 | "newtabs", 16 | "katex-maomi", 17 | "anchor-navigation-ex", 18 | "-highlight", 19 | "-livereload" 20 | ], 21 | "title": "C# Pytorch - 痴者工良", 22 | "author": "痴者工良", 23 | "description": "这是一本关于 C# 深度学习 的书,作者 痴者工良", 24 | "language": "zh-hans", 25 | "links": { 26 | "sidebar": { 27 | "痴者工良的博客": "https://www.whuanle.cn" 28 | } 29 | }, 30 | "pluginsConfig": { 31 | "tbfed-pagefooter": { 32 | "copyright": "Copyright © 痴者工良 2024", 33 | "modify_label": "文档最后更新时间:", 34 | "modify_format": "YYYY-MM-DD HH:mm:ss" 35 | }, 36 | "insert-logo": { 37 | "url": "/images/logo.png", 38 | "style": "background: none; max-height: 50px; min-height: 50px" 39 | }, 40 | "github": { 41 | "url": "https://github.com/whuanle/cs_pytorch" 42 | }, 43 | "prism": { 44 | "lang": { 45 | "flow": "typescript", 46 | "shell": "bash" 47 | }, 48 | "ignore": [ 49 | "mermaid", 50 | "eval-js" 51 | ], 52 | "css": [ 53 | "prismjs/themes/prism.css" 54 | ], 55 | "js": [ 56 | "prismjs/prism.js", 57 | "prismjs/components.js", 58 | "prismjs/components/prism-csharp.min.js", 59 | "prismjs/components/prism-python.min.js", 60 | "prismjs/components/prism-go.min.js", 61 | "prismjs/components/prism-yaml.min.js", 62 | "prismjs/components/prism-bash.min.js", 63 | "prismjs/components/prism-shell-session.min.js" 64 | ] 65 | }, 66 | "hide-element": { 67 | "elements": [ 68 | ".gitbook-link" 69 | ] 70 | }, 71 | "head-append": { 72 | "code": [ 73 | "", 74 | "var _hmt = _hmt || [];", 75 | "(function() {", 76 | "})();", 77 | "" 78 | ] 79 | }, 80 | "anchor-navigation-ex": { 81 | "tocLevel1Icon": "fa fa-hand-o-right", 82 | "tocLevel2Icon": "fa fa-hand-o-right", 83 | "tocLevel3Icon": "fa fa-hand-o-right", 84 | "multipleH1": false, 85 | "multipleH2": false, 86 | "multipleH3": false, 87 | "multipleH4": false, 88 | "showLevelIcon": true, 89 | "showLevel": true 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /images/1725105003545.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725105003545.png -------------------------------------------------------------------------------- /images/1725105639726.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725105639726.png -------------------------------------------------------------------------------- /images/1725110469061.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725110469061.jpg -------------------------------------------------------------------------------- /images/1725148068180(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725148068180(1).png -------------------------------------------------------------------------------- /images/1725148940379.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725148940379.png -------------------------------------------------------------------------------- /images/1725148968981(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725148968981(1).png -------------------------------------------------------------------------------- /images/1725149018283.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725149018283.png -------------------------------------------------------------------------------- /images/1725150688028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/1725150688028.png -------------------------------------------------------------------------------- /images/image-20240831193113478.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831193113478.png -------------------------------------------------------------------------------- /images/image-20240831193501897.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831193501897.png -------------------------------------------------------------------------------- /images/image-20240831193543224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831193543224.png -------------------------------------------------------------------------------- /images/image-20240831194432476.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831194432476.png -------------------------------------------------------------------------------- /images/image-20240831195641685.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831195641685.png -------------------------------------------------------------------------------- /images/image-20240831195802036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831195802036.png -------------------------------------------------------------------------------- /images/image-20240831220117612.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240831220117612.png -------------------------------------------------------------------------------- /images/image-20240901072421293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901072421293.png -------------------------------------------------------------------------------- /images/image-20240901072824863.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901072824863.png -------------------------------------------------------------------------------- /images/image-20240901080538372.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901080538372.png -------------------------------------------------------------------------------- /images/image-20240901093307337.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901093307337.png -------------------------------------------------------------------------------- /images/image-20240901111744905.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901111744905.png -------------------------------------------------------------------------------- /images/image-20240901112046630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901112046630.png -------------------------------------------------------------------------------- /images/image-20240901113934658.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901113934658.png -------------------------------------------------------------------------------- /images/image-20240901114708887.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901114708887.png -------------------------------------------------------------------------------- /images/image-20240901120654336.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901120654336.png -------------------------------------------------------------------------------- /images/image-20240901122532080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901122532080.png -------------------------------------------------------------------------------- /images/image-20240901122822715.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901122822715.png -------------------------------------------------------------------------------- /images/image-20240901122852869.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240901122852869.png -------------------------------------------------------------------------------- /images/image-20240907191647155.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240907191647155.png -------------------------------------------------------------------------------- /images/image-20240907192106915.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/image-20240907192106915.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whuanle/cs_pytorch/c124dd4ed6e2583ab4871b49546ed7465b2f83d2/images/logo.png -------------------------------------------------------------------------------- /init_gitbook.bat: -------------------------------------------------------------------------------- 1 | rm package-lock.json ; 2 | npm i ; 3 | gitbook install ; 4 | -------------------------------------------------------------------------------- /other/01.1.md: -------------------------------------------------------------------------------- 1 | MLN 类: 2 | 3 | 4 | 5 | 6 | 7 | ``` 8 | using System.Runtime.InteropServices; 9 | using TorchSharp; 10 | using static TorchSharp.torch; 11 | 12 | using TorchSharp.Modules; 13 | using TorchSharp.Data; 14 | 15 | 16 | using nn = TorchSharp.torch.nn; 17 | using optim = TorchSharp.torch.optim; 18 | using datasets = TorchSharp.torchvision.datasets; 19 | using transforms = TorchSharp.torchvision.transforms; 20 | using System.Drawing; 21 | 22 | public class MLP : nn.Module, IDisposable 23 | { 24 | private readonly int _inputSize; 25 | private readonly int _hiddenSize; 26 | private readonly int _numClasses; 27 | 28 | private TorchSharp.Modules.Linear fc1; 29 | private TorchSharp.Modules.ReLU relu; 30 | private TorchSharp.Modules.Linear fc2; 31 | private TorchSharp.Modules.Linear fc3; 32 | 33 | public MLP(int inputSize, int hiddenSize, int numClasses, Device device) : base(nameof(MLP)) 34 | { 35 | _inputSize = inputSize; 36 | _hiddenSize = hiddenSize; 37 | _numClasses = numClasses; 38 | 39 | fc1 = nn.Linear(inputSize, hiddenSize, device: device); 40 | relu = nn.ReLU(); 41 | fc2 = nn.Linear(hiddenSize, hiddenSize, device: device); 42 | fc3 = nn.Linear(hiddenSize, numClasses, device: device); 43 | 44 | RegisterComponents(); 45 | 46 | } 47 | 48 | public override torch.Tensor forward(torch.Tensor input) 49 | { 50 | var @out = fc1.call(input); 51 | @out = relu.call(@out); 52 | @out = fc2.call(@out); 53 | @out = relu.call(@out); 54 | @out = fc3.call(@out); 55 | return @out; 56 | } 57 | 58 | protected override void Dispose(bool disposing) 59 | { 60 | base.Dispose(disposing); 61 | fc1.Dispose(); 62 | relu.Dispose(); 63 | fc2.Dispose(); 64 | fc3.Dispose(); 65 | } 66 | } 67 | ``` 68 | 69 | 70 | 71 | ``` 72 | using System.Runtime.InteropServices; 73 | using TorchSharp; 74 | using static TorchSharp.torch; 75 | 76 | using TorchSharp.Modules; 77 | using TorchSharp.Data; 78 | 79 | 80 | using nn = TorchSharp.torch.nn; 81 | using optim = TorchSharp.torch.optim; 82 | using datasets = TorchSharp.torchvision.datasets; 83 | using transforms = TorchSharp.torchvision.transforms; 84 | using System.Drawing; 85 | 86 | public class MLP : nn.Module, IDisposable 87 | { 88 | private readonly int _inputSize; 89 | private readonly int _hiddenSize; 90 | private readonly int _numClasses; 91 | 92 | private readonly TorchSharp.Modules.Linear _fc1; 93 | private readonly TorchSharp.Modules.ReLU _relu; 94 | private readonly TorchSharp.Modules.Linear _fc2; 95 | private readonly TorchSharp.Modules.Linear _fc3; 96 | 97 | public MLP(int inputSize, int hiddenSize, int numClasses) : base("MLP") 98 | { 99 | _inputSize = inputSize; 100 | _hiddenSize = hiddenSize; 101 | _numClasses = numClasses; 102 | 103 | _fc1 = nn.Linear(inputSize, hiddenSize); 104 | _relu = nn.ReLU(); 105 | _fc2 = nn.Linear(hiddenSize, hiddenSize); 106 | _fc3 = nn.Linear(hiddenSize, numClasses); 107 | } 108 | 109 | public torch.Tensor forward(torch.Tensor x) 110 | { 111 | var @out = _fc1.forward(x); 112 | @out = _relu.forward(@out); 113 | @out = _fc2.forward(@out); 114 | @out = _relu.forward(@out); 115 | @out = _fc3.forward(@out); 116 | return @out; 117 | } 118 | 119 | protected override void Dispose(bool disposing) 120 | { 121 | base.Dispose(disposing); 122 | _fc1.Dispose(); 123 | _relu.Dispose(); 124 | _fc2.Dispose(); 125 | _fc3.Dispose(); 126 | } 127 | } 128 | 129 | 130 | public static class ImageTransforms 131 | { 132 | public static torch.Tensor ToTensor(Bitmap image) 133 | { 134 | int width = image.Width; 135 | int height = image.Height; 136 | 137 | // 创建一个用于存储图像数据的张量 138 | var tensor = torch.zeros(new long[] { 3, height, width }); 139 | 140 | // 设置像素值 141 | for (int y = 0; y < height; y++) 142 | { 143 | for (int x = 0; x < width; x++) 144 | { 145 | Color pixel = image.GetPixel(x, y); 146 | tensor[0, y, x] = (float)pixel.R / 255.0f; 147 | tensor[1, y, x] = (float)pixel.G / 255.0f; 148 | tensor[2, y, x] = (float)pixel.B / 255.0f; 149 | } 150 | } 151 | 152 | return tensor; 153 | } 154 | } 155 | 156 | ``` 157 | 158 | 159 | 160 | 161 | 162 | Program 类 163 | 164 | ``` 165 | using System.Runtime.InteropServices; 166 | using TorchSharp; 167 | using static TorchSharp.torch; 168 | 169 | using TorchSharp.Modules; 170 | using TorchSharp.Data; 171 | 172 | 173 | using nn = TorchSharp.torch.nn; 174 | using optim = TorchSharp.torch.optim; 175 | using datasets = TorchSharp.torchvision.datasets; 176 | using transforms = TorchSharp.torchvision.transforms; 177 | using static TorchSharp.torch.optim; 178 | using static TorchSharp.torch.optim.lr_scheduler; 179 | 180 | //// 使用 GPU 启动 181 | var device = torch.device("cpu"); 182 | torch.set_default_device(device); 183 | 184 | // 1. 加载数据集 185 | 186 | // 从 MNIST 数据集下载数据或者加载已经下载的数据 187 | using var train_data = datasets.MNIST("./mnist/data", train: true, download: true, target_transform: transforms.ConvertImageDtype(ScalarType.Float32)); 188 | using var test_data = datasets.MNIST("./mnist/data", train: false, download: true, target_transform: transforms.ConvertImageDtype(ScalarType.Float32)); 189 | 190 | Console.WriteLine("Train data size: " + train_data.Count); 191 | Console.WriteLine("Test data size: " + test_data.Count); 192 | 193 | var batch_size = 100; 194 | // 分批加载图像,打乱顺序 195 | var train_loader = torch.utils.data.DataLoader(train_data, batchSize: batch_size, shuffle: true, device); 196 | // 分批加载图像,不打乱顺序 197 | var test_loader = torch.utils.data.DataLoader(test_data, batchSize: batch_size, shuffle: false, device); 198 | 199 | // 输入的图像的维度 200 | var input_size = 28 * 28; 201 | // 隐藏层大小 202 | var hidden_size = 512; 203 | // 手动配置分类结果个数 204 | var num_classes = 10; 205 | 206 | var model = new MLP(input_size, hidden_size, num_classes, device); 207 | 208 | // 创建损失函数 209 | var criterion = nn.CrossEntropyLoss(); 210 | 211 | // 学习率 212 | var learning_rate = 0.001; 213 | // 优化器 214 | var optimizer = optim.Adam(model.parameters(), lr: learning_rate); 215 | 216 | // 训练的轮数 217 | var num_epochs = 10; 218 | 219 | foreach (var epoch in Enumerable.Range(0, num_epochs)) 220 | { 221 | int i = 0; 222 | foreach (var item in train_loader) 223 | { 224 | var images = item["data"]; 225 | var lables = item["label"]; 226 | 227 | images = images.reshape(-1, 28 * 28); 228 | var outputs = model.call(images); 229 | 230 | var loss = criterion.call(outputs, lables); 231 | 232 | optimizer.zero_grad(); 233 | 234 | loss.backward(); 235 | 236 | optimizer.step(); 237 | 238 | i++; 239 | if ((i + 1) % 300 == 0) 240 | { 241 | Console.WriteLine($"Epoch [{(epoch + 1)}/{num_epochs}], Step [{(i + 1)}/{train_data.Count / batch_size}], Loss: {loss.ToSingle():F4}"); 242 | } 243 | } 244 | } 245 | 246 | 247 | using (torch.no_grad()) 248 | { 249 | long correct = 0; 250 | long total = 0; 251 | 252 | foreach (var item in test_loader) 253 | { 254 | var images = item["data"]; 255 | var labels = item["label"]; 256 | 257 | images = images.reshape(-1, 28 * 28); 258 | var outputs = model.call(images); 259 | 260 | var (_, predicted) = torch.max(outputs, 1); 261 | total += labels.size(0); 262 | correct += (predicted == labels).sum().item(); 263 | } 264 | Console.WriteLine($"Accuracy of the network on the 10000 test images: {100 * correct / total} %"); 265 | } 266 | 267 | 268 | model.save("mnist_mlp_model.pkl"); 269 | 270 | Console.ReadLine(); 271 | 272 | ``` 273 | 274 | -------------------------------------------------------------------------------- /other/README.md: -------------------------------------------------------------------------------- 1 | 这里是一些未整理的内容. 2 | 3 | 4 | 5 | 6 | 7 | 加载图片转换为黑白通道 8 | 9 | ``` 10 | 11 | // 加载图片为张量 12 | torch.Tensor image = TensorImageExtensions.LoadImage("0.jpg"); 13 | // 定义变换:将图像变为灰度并转换为张量 14 | var transform = transforms.Compose(new torchvision.ITransform[] { 15 | transforms.Grayscale(outputChannels:1), 16 | transforms.ConvertImageDtype(ScalarType.Float32) 17 | }); 18 | 19 | var img = transform.call(image).unsqueeze(0); 20 | img.SaveJpeg("./aaa.jpg"); 21 | image = image.reshape(-1, 28 * 28); 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cs_pytorch", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "gitbook-plugin-katex-maomi": "^0.16.115", 9 | "gitbook-plugin-katex-mhchem": "^0.16.9", 10 | "graceful-fs": "^4.2.11" 11 | } 12 | }, 13 | "node_modules/commander": { 14 | "version": "8.3.0", 15 | "license": "MIT", 16 | "engines": { 17 | "node": ">= 12" 18 | } 19 | }, 20 | "node_modules/gitbook-plugin-katex-maomi": { 21 | "version": "0.16.115", 22 | "resolved": "https://registry.npmjs.org/gitbook-plugin-katex-maomi/-/gitbook-plugin-katex-maomi-0.16.115.tgz", 23 | "integrity": "sha512-qyHxtekWAquKBtLosAbZTsBFP9tKDECAklWpUedh47WVVC0r0UZC2wlFzrnWZTl09aWfO4P7Cvy1dHg2wh9fZg==", 24 | "license": "Apache-2.0", 25 | "dependencies": { 26 | "katex": "0.16.11" 27 | }, 28 | "engines": { 29 | "gitbook": ">=3.0.0" 30 | } 31 | }, 32 | "node_modules/gitbook-plugin-katex-maomi/node_modules/katex": { 33 | "version": "0.16.11", 34 | "funding": [ 35 | "https://opencollective.com/katex", 36 | "https://github.com/sponsors/katex" 37 | ], 38 | "license": "MIT", 39 | "dependencies": { 40 | "commander": "^8.3.0" 41 | }, 42 | "bin": { 43 | "katex": "cli.js" 44 | } 45 | }, 46 | "node_modules/gitbook-plugin-katex-mhchem": { 47 | "version": "0.16.9", 48 | "license": "Apache-2.0", 49 | "dependencies": { 50 | "katex": "0.16.9" 51 | }, 52 | "engines": { 53 | "gitbook": ">=3.0.0" 54 | } 55 | }, 56 | "node_modules/graceful-fs": { 57 | "version": "4.2.11", 58 | "license": "ISC" 59 | }, 60 | "node_modules/katex": { 61 | "version": "0.16.9", 62 | "funding": [ 63 | "https://opencollective.com/katex", 64 | "https://github.com/sponsors/katex" 65 | ], 66 | "license": "MIT", 67 | "dependencies": { 68 | "commander": "^8.3.0" 69 | }, 70 | "bin": { 71 | "katex": "cli.js" 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "gitbook-plugin-katex-maomi": "^0.16.115", 4 | "gitbook-plugin-katex-mhchem": "^0.16.9", 5 | "graceful-fs": "^4.2.11" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /undefined.md: -------------------------------------------------------------------------------- 1 | # 文档说明 2 | 3 | 教程名称:使用 C# 入门深度学习 4 | 5 | 作者:痴者工良 6 | 7 | 教程地址: 8 | 9 | [https://torch.whuanle.cn](https://torch.whuanle.cn) 10 | 11 |
12 | 13 | 电子书仓库:https://github.com/whuanle/cs_pytorch 14 | 15 | Maomi.Torch 项目仓库:https://github.com/whuanle/Maomi.Torch 16 | 17 |
18 | 19 | ## 导读 20 | 21 | 本教程通过使用 C# ,学习数学基础、Pytorch 框架、深度学习等,目前还在编写中。 22 | 23 | - 教程中每个小节都有代码示例 24 | - 深入原理,讲解深层知识 25 | - 由易到难,从入门到掌握 26 | - 循序渐进,一步步学习,一步步拓展知识面 27 | - 内容完整、齐全,可以系统式学习 28 | - 大量代码示例和场景实践 29 | 30 | 31 | 32 | ### 目录 33 | 34 | * [文档导读](README.md) 35 | * [第一部分:基础](./01.base/README.md) 36 | * [搭建深度学习环境](./01.base/01.env.md) 37 | * [Pytorch 基础](./01.base/02.base.md) 38 | * [线性代数基础](./01.base/03.linear.md) 39 | * [微积分和梯度下降](./01.base/04.higher.md) 40 | * [概率论基础](./01.base/05.odds.md) 41 | * [第二部分:入门案例](./02.start/README.md) 42 | * [神经网络基础知识](./02.start/01.neural_network.md) 43 | * [使用神经网络训练模型-案例一](./02.start/02.start_torch.md) 44 | * [使用神经网络训练模型-案例二](./02.start/03.xl.md) 45 | * [使用预训练模型](./02.start/04.models.md) 46 | * [第三部分:计算机视觉](03.image/README.md) 47 | * [通过生成对抗网络(GAN)训练和生成头像](03.image/dcgan_faces_tutorial.md) 48 | * [图像分类 | VGG大规模图像识别的超深度卷积网络](03.image/vgg.md) 49 | * [未整理]() 50 | --------------------------------------------------------------------------------