├── .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 | 
24 |
25 |
26 |
27 |
28 |
29 | 
30 |
31 |
32 |
33 |
34 |
35 | 如果电脑已经识别出显卡,可以通过 NVIDIA GeForce Experience 或者在其它驱动管理工具更新到最新版本的驱动程序。
36 |
37 |
38 |
39 | 
40 |
41 |
42 |
43 | 或者直接到官方驱动页面搜索显卡型号要安装的驱动程序,Nvida 官方驱动搜索下载页面:https://www.nvidia.cn/drivers/lookup/
44 |
45 |
46 |
47 | 
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 | 
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 | 
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 | 
104 |
105 |
106 |
107 | 安装完成后,环境变量会多出两条记录:
108 |
109 | 
110 |
111 |
112 |
113 | cuDNN 是基于 GPU 的深度学习加速库,下载文件后是一个压缩包。
114 |
115 | 下载地址:https://developer.nvidia.com/cudnn-downloads
116 |
117 | 
118 |
119 |
120 |
121 | 打开 `C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\`,找到版本目录,或者通过环境变量 `CUDA_PATH` 找到安装目录,将 cuDNN 压缩包的内容复制合并到 CUDA 目录。
122 |
123 | 
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 | 
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 | 
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 | .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 | 
234 |
235 | .png)
236 |
237 |
238 |
239 | 然后创建一个项目,在项目中选择基于 conda 的环境。
240 |
241 |
242 |
243 | 
244 |
245 |
246 |
247 | ### 模型加载和对话
248 |
249 | 在项目目录下创建 main.py 文件。
250 |
251 |
252 |
253 | 
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 | 
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 | 
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 | 
311 |
312 |
313 |
314 | 执行代码:
315 |
316 | ```python
317 | import torch
318 | print(torch.__version__)
319 | ```
320 |
321 | 
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 | 
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 | 
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 | 
407 |
408 |
409 |
410 | 点击确定安装时,由于需要下载大量的文件,因此安装时间比较长,需要耐心等待。
411 |
412 |
413 |
414 | 
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 |
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 |
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
418 |
419 | 现在我们来求解一个问题,在空间中找到跟 $\overrightarrow{AB} $ 、 $\overrightarrow{BC} $ 同时垂直的向量,例如下图的 $\overrightarrow{AD} $ ,很明显,这样的向量不止一个,有无数个,所以我们这个时候要了解什么是法向量和单位向量。
420 |
421 | 
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 | 
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 | 
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 | 
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 | 
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 | 
36 |
37 | > 图来自:《动手深度学习-PyTorch(第二版)》
38 |
39 |
40 |
41 | ### 线性网络和多层感知机
42 |
43 | 神经网络是以神经元为基础的,这个跟生物上的神经元有所区别。下图是生物学上的神经元细胞图。
44 |
45 | 
46 |
47 | > 图来自 《深度学习的数学》。
48 |
49 |
50 |
51 | 神经元由细胞体、轴突、树突组成,神经元有多个轴突,单细胞体收到刺激后,会通过轴突把信号传递给其它神经元。神经元通过树突接收从其它神经元传递过来的信号。
52 |
53 | 把神经元通过轴突向其它神经元传递信号的动作称为点火,传递的信号只有 1 和 0,并且同时向所有轴突程度信号,也就是所有被轴突连接到的神经元都会收到通知。
54 |
55 | 那么,神经元什么时候会点火呢。
56 |
57 | 神经元是有阈值的,神经元有多个树突,从不同的神经元接收信号,只有当这些信号达到阈值时,才能刺激神经元。
58 |
59 | 
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 | 
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 | 
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | 单位阶跃函数。
189 |
190 | 
191 |
192 |
193 |
194 | 
195 |
196 |
197 |
198 |
199 |
200 | 
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 | 
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 | 
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 | 
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 | 
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 | 
39 |
40 |
41 |
42 | 每个图片的大小是 `28*28=784`,所以神经网络的输入层的大小是 784。
43 |
44 | 
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 | 
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 | 
279 |
280 |
281 |
282 | ### 识别手写图像
283 |
284 | 如下示例图像所示,是一个手写数字。
285 |
286 | 
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 | 
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 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
293 |
294 |
295 |
296 | ### 生成器
297 |
298 | 生成器 $G$ 旨在将潜在空间向量 ( $z$ ) 映射到数据空间。由于我们的数据是图像,将 $z$ 转换为数据空间意味着最终要创建一个与训练图像具有相同大小的 RGB 图像 (即 3x64x64)。在实践中,这是通过一系列步幅为二维的卷积转置层来实现的,每一层都配有一个 2d 批量规范化层和一个 relu 激活函数。生成器的输出通过一个 tanh 函数返回到输入数据范围 $[-1,1]$ 。值得注意的是在 conv-transpose 层之后存在批量规范化函数,因为这是 DCGAN 论文的重要贡献之一。这些层有助于训练期间梯度的流动。下图显示了 DCGAN 论文中的生成器。
299 |
300 | 
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 | 
590 |
591 |
第一轮训练生成:
592 |
593 | 
594 |
595 |
596 |
597 | 第 25 轮生成的:
598 |
599 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
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 |
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 | 
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 | 
101 |
102 |
103 |
104 | 数据集信息及文件列表查看
105 |
106 | ```
107 | openxlab dataset info --dataset-repo OpenDataLab/CIFAR-10
108 | ```
109 |
110 |
111 |
112 | 
113 |
114 |
115 |
116 | 下载的文件比较多,但是我们只需要用到 `cifar-10-binary.tar.gz`,直接解压 `cifar-10-binary.tar.gz` 到目录中(也可以不解压)。
117 |
118 | 
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 | 
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 | 
369 |
370 | 
371 |
372 | 
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 |
--------------------------------------------------------------------------------