-
Notifications
You must be signed in to change notification settings - Fork 257
/
Copy pathcpp_frontend.html
1853 lines (1647 loc) · 190 KB
/
cpp_frontend.html
1
2
3
4
5
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PyTorch C++ 프론트엔드 사용하기 — PyTorch Tutorials 1.10.2+cu102 documentation</title>
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<!-- <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> -->
<link rel="stylesheet" href="../_static/copybutton.css" type="text/css" />
<link rel="stylesheet" href="../_static/gallery.css" type="text/css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.0-beta/dist/katex.min.css" type="text/css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css" type="text/css" />
<link rel="stylesheet" href="../_static/katex-math.css" type="text/css" />
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="TorchScript의 동적 병렬 처리(Dynamic Parallelism)" href="torch-script-parallelism.html" />
<link rel="prev" title="Forward-mode Automatic Differentiation (Beta)" href="../intermediate/forward_ad_usage.html" />
<script src="../_static/js/modernizr.min.js"></script>
<!-- Preload the theme fonts -->
<link rel="preload" href="../_static/fonts/FreightSans/freight-sans-book.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../_static/fonts/FreightSans/freight-sans-medium.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../_static/fonts/IBMPlexMono/IBMPlexMono-Medium.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../_static/fonts/FreightSans/freight-sans-bold.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../_static/fonts/FreightSans/freight-sans-medium-italic.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../_static/fonts/IBMPlexMono/IBMPlexMono-SemiBold.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<!-- Preload the katex fonts -->
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Math-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Main-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Main-Bold.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size1-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size4-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size2-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size3-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Caligraphic-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css" integrity="sha384-vSIIfh2YWi9wW0r9iZe7RJPrKwp6bG+s9QZMoITbCckVJqGCCRhc+ccxNcdpHuYu" crossorigin="anonymous">
</head>
<div class="container-fluid header-holder tutorials-header" id="header-holder">
<div class="container">
<div class="header-container">
<a class="header-logo" href="https://pytorch.kr/" aria-label="PyTorch"></a>
<div class="main-menu">
<ul>
<li>
<a href="https://pytorch.kr/get-started">시작하기</a>
</li>
<li class="active">
<a href="https://tutorials.pytorch.kr">튜토리얼</a>
</li>
<li>
<a href="https://pytorch.kr/hub">허브</a>
</li>
<li>
<a href="https://discuss.pytorch.kr">커뮤니티</a>
</li>
</ul>
</div>
<a class="main-menu-open-button" href="#" data-behavior="open-mobile-menu"></a>
</div>
</div>
</div>
<body class="pytorch-body">
<div class="table-of-contents-link-wrapper">
<span>Table of Contents</span>
<a href="#" class="toggle-table-of-contents" data-behavior="toggle-table-of-contents"></a>
</div>
<nav data-toggle="wy-nav-shift" class="pytorch-left-menu" id="pytorch-left-menu">
<div class="pytorch-side-scroll">
<div class="pytorch-menu pytorch-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<div class="pytorch-left-menu-search">
<div class="version">
1.10.2+cu102
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search Tutorials" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<p class="caption"><span class="caption-text">파이토치(PyTorch) 레시피</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../recipes/recipes_index.html">모든 레시피 보기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../prototype/prototype_index.html">모든 프로토타입 레시피 보기</a></li>
</ul>
<p class="caption"><span class="caption-text">파이토치(PyTorch) 시작하기</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/intro.html">파이토치(PyTorch) 기본 익히기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/quickstart_tutorial.html">빠른 시작(Quickstart)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/tensorqs_tutorial.html">텐서(Tensor)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/data_tutorial.html">Dataset과 DataLoader</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/transforms_tutorial.html">변형(Transform)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/buildmodel_tutorial.html">신경망 모델 구성하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/autogradqs_tutorial.html"><code class="docutils literal notranslate"><span class="pre">torch.autograd</span></code>를 사용한 자동 미분</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/optimization_tutorial.html">모델 매개변수 최적화하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/basics/saveloadrun_tutorial.html">모델 저장하고 불러오기</a></li>
</ul>
<p class="caption"><span class="caption-text">Introduction to PyTorch on YouTube</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt.html">Introduction to PyTorch - YouTube Series</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/introyt1_tutorial.html">Introduction to PyTorch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/tensors_deeper_tutorial.html">Introduction to PyTorch Tensors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/autogradyt_tutorial.html">The Fundamentals of Autograd</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/modelsyt_tutorial.html">Building Models with PyTorch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/tensorboardyt_tutorial.html">PyTorch TensorBoard Support</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/trainingyt.html">Training with PyTorch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/introyt/captumyt.html">Model Understanding with Captum</a></li>
</ul>
<p class="caption"><span class="caption-text">파이토치(PyTorch) 배우기</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/deep_learning_60min_blitz.html">PyTorch로 딥러닝하기: 60분만에 끝장내기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/pytorch_with_examples.html">예제로 배우는 파이토치(PyTorch)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/nn_tutorial.html"><cite>torch.nn</cite> 이 <em>실제로</em> 무엇인가요?</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/tensorboard_tutorial.html">TensorBoard로 모델, 데이터, 학습 시각화하기</a></li>
</ul>
<p class="caption"><span class="caption-text">이미지/비디오</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/torchvision_tutorial.html">TorchVision 객체 검출 미세조정(Finetuning) 튜토리얼</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/transfer_learning_tutorial.html">컴퓨터 비전(Vision)을 위한 전이학습(Transfer Learning)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/fgsm_tutorial.html">적대적 예제 생성(Adversarial Example Generation)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/dcgan_faces_tutorial.html">DCGAN 튜토리얼</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/vt_tutorial.html">배포를 위한 비전 트랜스포머(Vision Transformer) 모델 최적화하기</a></li>
</ul>
<p class="caption"><span class="caption-text">오디오</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_io_tutorial.html">Audio I/O</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_resampling_tutorial.html">Audio Resampling</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_data_augmentation_tutorial.html">Audio Data Augmentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_feature_extractions_tutorial.html">Audio Feature Extractions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_feature_augmentation_tutorial.html">Audio Feature Augmentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/audio_datasets_tutorial.html">Audio Datasets</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/speech_recognition_pipeline_tutorial.html">Speech Recognition with Wav2Vec2</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/speech_command_classification_with_torchaudio_tutorial.html">Speech Command Classification with torchaudio</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/text_to_speech_with_torchaudio.html">Text-to-speech with torchaudio</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/forced_alignment_with_torchaudio_tutorial.html">Forced Alignment with Wav2Vec2</a></li>
</ul>
<p class="caption"><span class="caption-text">텍스트</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/transformer_tutorial.html">nn.Transformer 와 TorchText 로 시퀀스-투-시퀀스(Sequence-to-Sequence) 모델링하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/char_rnn_classification_tutorial.html">기초부터 시작하는 NLP: 문자-단위 RNN으로 이름 분류하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/char_rnn_generation_tutorial.html">기초부터 시작하는 NLP: 문자-단위 RNN으로 이름 생성하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/seq2seq_translation_tutorial.html">기초부터 시작하는 NLP: Sequence to Sequence 네트워크와 Attention을 이용한 번역</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/text_sentiment_ngrams_tutorial.html">torchtext 라이브러리로 텍스트 분류하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/translation_transformer.html">nn.Transformer와 torchtext로 언어 번역하기</a></li>
</ul>
<p class="caption"><span class="caption-text">강화학습</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/reinforcement_q_learning.html">강화 학습 (DQN) 튜토리얼</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/mario_rl_tutorial.html">Train a Mario-playing RL Agent</a></li>
</ul>
<p class="caption"><span class="caption-text">PyTorch 모델을 프로덕션 환경에 배포하기</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/flask_rest_api_tutorial.html">Flask를 사용하여 Python에서 PyTorch를 REST API로 배포하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/Intro_to_TorchScript_tutorial.html">TorchScript 소개</a></li>
<li class="toctree-l1"><a class="reference internal" href="cpp_export.html">C++에서 TorchScript 모델 로딩하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="super_resolution_with_onnxruntime.html">(선택) PyTorch 모델을 ONNX으로 변환하고 ONNX 런타임에서 실행하기</a></li>
</ul>
<p class="caption"><span class="caption-text">Code Transforms with FX</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/fx_conv_bn_fuser.html">(베타) FX에서 합성곱/배치 정규화(Convolution/Batch Norm) 결합기(Fuser) 만들기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/fx_profiling_tutorial.html">(beta) Building a Simple CPU Performance Profiler with FX</a></li>
</ul>
<p class="caption"><span class="caption-text">프론트엔드 API</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../intermediate/memory_format_tutorial.html">(베타) PyTorch를 사용한 Channels Last 메모리 형식</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/forward_ad_usage.html">Forward-mode Automatic Differentiation (Beta)</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">PyTorch C++ 프론트엔드 사용하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="torch-script-parallelism.html">TorchScript의 동적 병렬 처리(Dynamic Parallelism)</a></li>
<li class="toctree-l1"><a class="reference internal" href="cpp_autograd.html">C++ 프론트엔드의 자동 미분 (autograd)</a></li>
</ul>
<p class="caption"><span class="caption-text">PyTorch 확장하기</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/custom_function_double_backward_tutorial.html">Double Backward with Custom Functions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/custom_function_conv_bn_tutorial.html">Fusing Convolution and Batch Norm using Custom Function</a></li>
<li class="toctree-l1"><a class="reference internal" href="cpp_extension.html">Custom C++ and CUDA Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="torch_script_custom_ops.html">Extending TorchScript with Custom C++ Operators</a></li>
<li class="toctree-l1"><a class="reference internal" href="torch_script_custom_classes.html">커스텀 C++ 클래스로 TorchScript 확장하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="dispatcher.html">Registering a Dispatched Operator in C++</a></li>
<li class="toctree-l1"><a class="reference internal" href="extend_dispatcher.html">Extending dispatcher for a new backend in C++</a></li>
</ul>
<p class="caption"><span class="caption-text">모델 최적화</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/profiler.html">PyTorch 모듈 프로파일링 하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/tensorboard_profiler_tutorial.html">PyTorch Profiler With TensorBoard</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/hyperparameter_tuning_tutorial.html">Hyperparameter tuning with Ray Tune</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/vt_tutorial.html">배포를 위한 비전 트랜스포머(Vision Transformer) 모델 최적화하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/parametrizations.html">Parametrizations Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/pruning_tutorial.html">가지치기 기법(Pruning) 튜토리얼</a></li>
<li class="toctree-l1"><a class="reference internal" href="dynamic_quantization_tutorial.html">(베타) LSTM 기반 단어 단위 언어 모델의 동적 양자화</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/dynamic_quantization_bert_tutorial.html">(베타) BERT 모델 동적 양자화하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/quantized_transfer_learning_tutorial.html">(베타) 컴퓨터 비전 튜토리얼을 위한 양자화된 전이학습(Quantized Transfer Learning)</a></li>
<li class="toctree-l1"><a class="reference internal" href="static_quantization_tutorial.html">(beta) Static Quantization with Eager Mode in PyTorch</a></li>
</ul>
<p class="caption"><span class="caption-text">병렬 및 분산 학습</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/dist_overview.html">PyTorch Distributed Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/model_parallel_tutorial.html">단일 머신을 사용한 모델 병렬화 모범 사례</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/ddp_tutorial.html">분산 데이터 병렬 처리 시작하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/dist_tuto.html">PyTorch로 분산 어플리케이션 개발하기</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/rpc_tutorial.html">Getting Started with Distributed RPC Framework</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/rpc_param_server_tutorial.html">Implementing a Parameter Server Using Distributed RPC Framework</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/dist_pipeline_parallel_tutorial.html">Distributed Pipeline Parallelism Using RPC</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/rpc_async_execution.html">Implementing Batch RPC Processing Using Asynchronous Executions</a></li>
<li class="toctree-l1"><a class="reference internal" href="rpc_ddp_tutorial.html">분산 데이터 병렬(DDP)과 분산 RPC 프레임워크 결합</a></li>
<li class="toctree-l1"><a class="reference internal" href="../intermediate/pipeline_tutorial.html">파이프라인 병렬화로 트랜스포머 모델 학습시키기</a></li>
<li class="toctree-l1"><a class="reference internal" href="ddp_pipeline.html">분산 데이터 병렬 처리와 병렬 처리 파이프라인을 사용한 트랜스포머 모델 학습</a></li>
<li class="toctree-l1"><a class="reference internal" href="generic_join.html">Distributed Training with Uneven Inputs Using the Join Context Manager</a></li>
</ul>
<p class="caption"><span class="caption-text">Mobile</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../beginner/deeplabv3_on_ios.html">iOS에서의 이미지 분할 DeepLapV3</a></li>
<li class="toctree-l1"><a class="reference internal" href="../beginner/deeplabv3_on_android.html">안드로이드에서의 이미지 분할 DeepLapV3</a></li>
</ul>
</div>
</div>
</nav>
<div class="pytorch-container">
<div class="pytorch-page-level-bar" id="pytorch-page-level-bar">
<div class="pytorch-breadcrumbs-wrapper">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="pytorch-breadcrumbs">
<li>
<a href="../index.html">
Tutorials
</a> >
</li>
<li>PyTorch C++ 프론트엔드 사용하기</li>
<li class="pytorch-breadcrumbs-aside">
<a href="../_sources/advanced/cpp_frontend.rst.txt" rel="nofollow"><img src="../_static/images/view-page-source-icon.svg"></a>
</li>
</ul>
</div>
</div>
<div class="pytorch-shortcuts-wrapper" id="pytorch-shortcuts-wrapper">
Shortcuts
</div>
</div>
<section data-toggle="wy-nav-shift" id="pytorch-content-wrap" class="pytorch-content-wrap">
<div class="pytorch-content-left">
<div class="pytorch-call-to-action-links">
<div id="tutorial-type">advanced/cpp_frontend</div>
<div id="google-colab-link">
<img class="call-to-action-img" src="../_static/images/pytorch-colab.svg"/>
<div class="call-to-action-desktop-view">Run in Google Colab</div>
<div class="call-to-action-mobile-view">Colab</div>
</div>
<div id="download-notebook-link">
<img class="call-to-action-notebook-img" src="../_static/images/pytorch-download.svg"/>
<div class="call-to-action-desktop-view">Download Notebook</div>
<div class="call-to-action-mobile-view">Notebook</div>
</div>
<div id="github-view-link">
<img class="call-to-action-img" src="../_static/images/pytorch-github.svg"/>
<div class="call-to-action-desktop-view">View on GitHub</div>
<div class="call-to-action-mobile-view">GitHub</div>
</div>
</div>
<div class="rst-content">
<div role="main" class="main-content" itemscope="itemscope" itemtype="http://schema.org/Article">
<article itemprop="articleBody" id="pytorch-article" class="pytorch-article">
<div class="section" id="pytorch-c">
<h1>PyTorch C++ 프론트엔드 사용하기<a class="headerlink" href="#pytorch-c" title="Permalink to this headline">¶</a></h1>
<p><strong>번역</strong>: <a class="reference external" href="https://github.com/eric-yoo">유용환</a></p>
<p>PyTorch C++ 프론트엔드는 PyTorch 머신러닝 프레임워크의 순수 C++
인터페이스입니다. PyTorch의 주된 인터페이스는 물론 파이썬이지만
이 곳의 API는 텐서(tensor)나 자동 미분과 같은 기초적인 자료구조
및 기능을 제공하는 C++ 코드베이스 위에 구현되었습니다. C++
프론트엔드는 이러한 기초적인 C++ 코드베이스를 비롯해 머신러닝 학습과 추론을
위해 필요한 도구들을 상속하는 순수 C++11 API를 제공합니다. 여기에는
신경망 모델링을 위해 필요한 공용 컴포넌트들의 빌트인 모음, 그것을
상속하기 위한 커스텀 모듈, 확률적 경사 하강법과 같은 유명한 최적화 알고리즘
라이브러리, 병렬 데이터 로더 및 데이터셋을 정의하고 불러오기 위한
API, 직렬화 루틴 등이 포합됩니다.</p>
<p>이 튜토리얼은 C++ 프론트엔드로 모델을 학습하는 엔드 투 엔드
예제를 안내합니다. 구체적으로, 우리는 생성 모델 중 하나인
<a class="reference external" href="https://arxiv.org/abs/1511.06434">DCGAN</a> 을 학습시켜
MNIST 숫자 이미지들을 생성할 것입니다. 개념적으로 쉬운 예시이지만,
여러분이 PyTorch C++ 프론트엔드에 대한 대략적인 개요를 파악하고 더
복잡한 모델을 학습시키고 싶은 욕구를 불러일으키기에 충분할 것입니다.
먼저 C++ 프론트엔드 사용에 대한 동기부여가 될 만한 이야기로 시작하고,
곧바로 모델을 정의하고 학습해보도록 하겠습니다.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">C++ 프론트엔드에 대한 짧고 재미있는 발표를 보려면 <a class="reference external" href="https://www.youtube.com/watch?v=auRPXMMHJzc">CppCon 2018 라이트닝 토크</a> 를 시청하세요.</p>
</div>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last"><a class="reference external" href="https://pytorch.org/cppdocs/frontend.html">이 노트</a> 는 C++
프론트엔드의 컴포넌트와 디자인 철학의 전반적인 개요를 제공합니다.</p>
</div>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">PyTorch C++ 생태계에 대한 문서는 <a class="reference external" href="https://pytorch.org">https://pytorch.org</a>/cppdocs에서
확인할 수 있습니다. API 레벨의 문서뿐만 아니라 개괄적인 설명도
찾을 수 있을 것입니다.</p>
</div>
<div class="section" id="id3">
<h2>동기부여<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h2>
<p>GAN과 MNIST 숫자로의 설레는 여정을 시작하기에 앞서, 먼저
파이썬 대신 C++ 프론트엔드를 사용하는 이유에 대해
설명하겠습니다. 우리(PyTorch 팀)는 파이썬을 사용할 수 없거나
사용하기에 적합하지 않은 환경에서 연구를 가능하게 하기 위해
C++ 프론트엔드를 만들었습니다. 예를 들면 다음과 같습니다.</p>
<ul class="simple">
<li><strong>저지연 시스템</strong>: 초당 프레임 수가 높고 지연 시간이 짧은
순수 C++ 게임 엔진에서 강화 학습 연구를 수행할 수 있습니다.
그러한 환경에서는 파이썬 라이브러리보다 순수 C++ 라이브러리를
사용하는 것이 훨씬 더 적합합니다. 파이썬은 느린 인터프리터
때문에 다루기가 쉽지 않습니다.</li>
<li><strong>고도의 멀티쓰레딩 환경</strong>: 글로벌 인터프리터 락(GIL)으로 인해
파이썬은 동시에 둘 이상의 시스템 쓰레드를 실행할 수 없습니다.
대안으로 멀티프로세싱을 사용하면 확장성이 떨어지며 심각한 한계가
있습니다. C++는 이러한 제약 조건이 없으며 쓰레드를 쉽게 만들고
사용할 수 있습니다. <a class="reference external" href="https://eng.uber.com/deep-neuroevolution/">Deep Neuroevolution</a> 에
사용된 것과 같이 고도의 병렬화가 필요한 모델도 이를 활용할 수
있습니다.</li>
<li><strong>기존의 C++ 코드베이스</strong>: 백엔드 서버의 웹 페이지 서비스부터
사진 편집 소프트웨어의 3D 그래픽 렌더링에 이르기까지 어떠한
작업이라도 수행하는 기존 C++ 애플리케이션 소유자로서, 머신러닝
방법론을 시스템에 통합하고 싶을 수 있습니다. C++ 프론트엔드는
PyTorch (파이썬) 경험 본연의 높은 유연성과 직관성을 유지하면서,
파이썬과 C++를 앞뒤로 바인딩하는 번거로움 없이 C++를 사용할 수
있게 해줍니다.</li>
</ul>
<p>C++ 프론트엔드의 목적은 파이썬 프론트엔드와 경쟁하는 것이 아닌
보완하는 것입니다. 연구자와 엔지니어 모두가 PyTorch의 단순성,
유연성 및 직관적인 API를 매우 좋아합니다. 우리의 목표는 여러분이
위의 예시를 비롯한 모든 가능한 환경에서 이 핵심 디자인 원칙을
이용할 수 있도록 하는 것입니다. 이러한 시나리오 중 하나가 여러분의
사례에 해당하거나, 단순히 관심이 있거나 궁금하다면 아래 내용을 통해
C++ 프론트엔드에 대해 자세히 살펴보세요.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<blockquote>
<div>C++ 프론트엔드는 파이썬 프론트엔드와 최대한 유사한 API를</div></blockquote>
<p class="last">제공하고자 합니다. 만일 파이썬 프론트엔드에 익숙한 사람이 “C++
프론트엔드로 X를 어떻게 해야 하는가?” 의문을 갖는다면, 많은 경우에
파이썬에서와 같은 방식으로 코드를 작성해 파이썬에서와 동일한 함수와
메서드를 사용할 수 있을 것입니다. (다만, 온점을 더블 콜론으로 바꾸는
것에 유의하세요.)</p>
</div>
</div>
<div class="section" id="id4">
<h2>기본 애플리케이션 작성하기<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h2>
<p>먼저 최소한의 C++ 애플리케이션을 작성해 우리의 설정과
빌드 환경이 동일한지 확인하겠습니다. 먼저, C++
프론트엔드를 사용하는 데 필요한 모든 관련 헤더, 라이브러리 및
CMake 빌드 파일을 패키징하는 <em>LibTorch</em> 배포판의 사본이
필요합니다. 리눅스, 맥OS, 윈도우용 LibTorch 배포판은
<a class="reference external" href="https://pytorch.org/get-started/locally/">PyTorch website</a> 에서
다운로드할 수 있습니다. 이 튜토리얼의 나머지 부분은 기본 우분투 리눅스
환경을 가정하지만 맥OS나 윈도우를 사용하셔도 괜찮습니다.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last"><a class="reference external" href="https://pytorch.org/cppdocs/installing.html">PyTorch C++ 배포판 설치</a>
의 설명에 다음의 과정이 더 자세히 안내되어
있습니다.</p>
</div>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">윈도우에서는 디버그 및 릴리스 빌드가 ABI와 호환되지 않습니다. 프로젝트를
디버그 모드로 빌드하려면 LibTorch의 디버그 버전을 사용해보세요.
아래의 <code class="docutils literal notranslate"><span class="pre">cmake</span> <span class="pre">--build</span> <span class="pre">.</span></code> 에 올바른 설정을 지정하는 것도 잊지
마세요.</p>
</div>
<p>가장 먼저 할 것은 PyTorch 웹사이트에서 검색된 링크를 통해 LibTorch
배포판을 로컬에 다운로드하는 것입니다. 일반적 Ubuntu Linux 환경의 경우
다음 명령어를 실행합니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># CUDA 9.0 등에 대한 지원이 필요한 경우 아래 URL에서 "cpu"를 "cu90"로 바꾸세요.</span>
wget https://download.pytorch.org/libtorch/nightly/cpu/libtorch-shared-with-deps-latest.zip
unzip libtorch-shared-with-deps-latest.zip
</pre></div>
</div>
<p>다음으로 <code class="docutils literal notranslate"><span class="pre">torch/torch.h</span></code> 를 호출하는 <code class="docutils literal notranslate"><span class="pre">dcgan.cpp</span></code> 라는 이름의 C++
파일 하나를 작성합시다. 우선은 아래와 같이 3x3 항등 행렬을 출력하기만 하면
됩니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><torch/torch.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="o">::</span><span class="n">eye</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">tensor</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>이 작은 애플리케이션과 이후 완성할 학습용 스크립트를 빌드하기 위해 우리는 아래의 <code class="docutils literal notranslate"><span class="pre">CMakeLists.txt</span></code> 를
사용할 것입니다:</p>
<div class="highlight-cmake notranslate"><div class="highlight"><pre><span></span><span class="nb">cmake_minimum_required</span><span class="p">(</span><span class="s">VERSION</span> <span class="s">3.0</span> <span class="s">FATAL_ERROR</span><span class="p">)</span>
<span class="nb">project</span><span class="p">(</span><span class="s">dcgan</span><span class="p">)</span>
<span class="nb">find_package</span><span class="p">(</span><span class="s">Torch</span> <span class="s">REQUIRED</span><span class="p">)</span>
<span class="nb">add_executable</span><span class="p">(</span><span class="s">dcgan</span> <span class="s">dcgan.cpp</span><span class="p">)</span>
<span class="nb">target_link_libraries</span><span class="p">(</span><span class="s">dcgan</span> <span class="s2">"${TORCH_LIBRARIES}"</span><span class="p">)</span>
<span class="nb">set_property</span><span class="p">(</span><span class="s">TARGET</span> <span class="s">dcgan</span> <span class="s">PROPERTY</span> <span class="s">CXX_STANDARD</span> <span class="s">14</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">CMake는 LibTorch에 권장되는 빌드 시스템이지만 필수 요구
사항은 아닙니다. Visual Studio 프로젝트 파일, QMake, 일반
Make 파일 등 다른 빌드 환경을 사용해도 됩니다. 하지만
이에 대한 즉각적인 지원은 제공하지 않습니다.</p>
</div>
<p>위 CMake 파일 4번째 줄의 <code class="docutils literal notranslate"><span class="pre">find_package(Torch</span> <span class="pre">REQUIRED)</span></code> 는
CMake가 LibTorch 라이브러리 빌드 설정을 찾도록 안내합니다.
CMake가 해당 파일의 <em>위치</em> 를 찾을 수 있도록 하려면 <code class="docutils literal notranslate"><span class="pre">cmake</span></code> 호출 시
<code class="docutils literal notranslate"><span class="pre">CMAKE_PREFIX_PATH</span></code> 를 설정해야 합니다. 이에 앞서 <code class="docutils literal notranslate"><span class="pre">dcgan</span></code> 애플리케이션에
대해 디렉터리 구조를 다음과 같이 통일하도록 하겠습니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>dcgan/
CMakeLists.txt
dcgan.cpp
</pre></div>
</div>
<p>또한 앞으로 압축 해제된 LibTorch 배포판의 경로를 <code class="docutils literal notranslate"><span class="pre">/path/to/libtorch</span></code>
로 부르도록 하겠습니다. 이는 <strong>반드시 절대 경로여야</strong> 합니다. 특히
<code class="docutils literal notranslate"><span class="pre">CMAKE_PREFIX_PATH</span></code> 를 <code class="docutils literal notranslate"><span class="pre">../../libtorch</span></code> 와 같이 설정하면 예상치 못한
오류가 발생할 수 있습니다. 그보다는 <code class="docutils literal notranslate"><span class="pre">$PWD/../../libtorch</span></code> 와 같이 해당
절대 경로를 입력하세요. 이제 애플리케이션을 빌드할 준비가 되었습니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>root@fa350df05ecf:/home# mkdir build
root@fa350df05ecf:/home# <span class="nb">cd</span> build
root@fa350df05ecf:/home/build# cmake -DCMAKE_PREFIX_PATH<span class="o">=</span>/path/to/libtorch ..
-- The C compiler identification is GNU <span class="m">5</span>.4.0
-- The CXX compiler identification is GNU <span class="m">5</span>.4.0
-- Check <span class="k">for</span> working C compiler: /usr/bin/cc
-- Check <span class="k">for</span> working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - <span class="k">done</span>
-- Detecting C compile features
-- Detecting C compile features - <span class="k">done</span>
-- Check <span class="k">for</span> working CXX compiler: /usr/bin/c++
-- Check <span class="k">for</span> working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - <span class="k">done</span>
-- Detecting CXX compile features
-- Detecting CXX compile features - <span class="k">done</span>
-- Looking <span class="k">for</span> pthread.h
-- Looking <span class="k">for</span> pthread.h - found
-- Looking <span class="k">for</span> pthread_create
-- Looking <span class="k">for</span> pthread_create - not found
-- Looking <span class="k">for</span> pthread_create <span class="k">in</span> pthreads
-- Looking <span class="k">for</span> pthread_create <span class="k">in</span> pthreads - not found
-- Looking <span class="k">for</span> pthread_create <span class="k">in</span> pthread
-- Looking <span class="k">for</span> pthread_create <span class="k">in</span> pthread - found
-- Found Threads: TRUE
-- Found torch: /path/to/libtorch/lib/libtorch.so
-- Configuring <span class="k">done</span>
-- Generating <span class="k">done</span>
-- Build files have been written to: /home/build
root@fa350df05ecf:/home/build# cmake --build . --config Release
Scanning dependencies of target dcgan
<span class="o">[</span> <span class="m">50</span>%<span class="o">]</span> Building CXX object CMakeFiles/dcgan.dir/dcgan.cpp.o
<span class="o">[</span><span class="m">100</span>%<span class="o">]</span> Linking CXX executable dcgan
<span class="o">[</span><span class="m">100</span>%<span class="o">]</span> Built target dcgan
</pre></div>
</div>
<p>위에서 우리는 먼저 <code class="docutils literal notranslate"><span class="pre">dcgan</span></code> 디렉토리 안에 <code class="docutils literal notranslate"><span class="pre">build</span></code> 폴더를 만들고
이 폴더에 들어가서 필요한 빌드(Make) 파일을 생성하는 <code class="docutils literal notranslate"><span class="pre">cmake</span></code> 명령어를
실행한 후 <code class="docutils literal notranslate"><span class="pre">cmake</span> <span class="pre">--build</span> <span class="pre">.</span> <span class="pre">--config</span> <span class="pre">Release</span></code> 를 실행하여 프로젝트를
성공적으로 컴파일했습니다. 이제 우리의 작은 바이너리를 실행하고 기본
프로젝트 설정에 대한 이 섹션을 완료할 준비가 됐습니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>root@fa350df05ecf:/home/build# ./dcgan
<span class="m">1</span> <span class="m">0</span> <span class="m">0</span>
<span class="m">0</span> <span class="m">1</span> <span class="m">0</span>
<span class="m">0</span> <span class="m">0</span> <span class="m">1</span>
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">3</span>,3<span class="o">}</span> <span class="o">]</span>
</pre></div>
</div>
<p>제가 보기엔 항등 행렬인 것 같군요!</p>
</div>
<div class="section" id="id6">
<h2>신경망 모델 정의하기<a class="headerlink" href="#id6" title="Permalink to this headline">¶</a></h2>
<p>이제 기본적인 환경을 설정했으니, 이번 튜토리얼에서 훨씬
더 흥미로운 부분을 살펴봅시다. 먼저 C++ 프론트엔드에서 모듈을
정의하고 상호 작용하는 방법에 대해 논의하겠습니다. 기본적인
소규모 예제 모듈부터 시작하여 C++ 프론트엔드가 제공하는 다양한
내장 모듈 라이브러리를 사용하여 완성도 있는 GAN을 구현하겠습니다.</p>
<div class="section" id="api">
<h3>모듈 API 기초<a class="headerlink" href="#api" title="Permalink to this headline">¶</a></h3>
<p>파이썬 인터페이스와 마찬가지로, C++ 프론트엔드에 기반을 둔 신경망도
<em>모듈</em> 이라 불리는 재사용 가능한 빌딩 블록으로 구성되어 있습니다. 파이썬에
다른 모든 모듈이 파생되는 <code class="docutils literal notranslate"><span class="pre">torch.nn.Module</span></code> 라는 기본 모듈 클래스가
있듯이 C++에는 <code class="docutils literal notranslate"><span class="pre">torch::nn::Module</span></code> 클래스가 있습니다.
일반적으로 모듈에는 캡슐화된 알고리즘을 구현하는 <code class="docutils literal notranslate"><span class="pre">forward()</span></code>
메서드를 비롯해 매개변수, 버퍼 및 하위 모듈 세 가지 하위 객체가
포함됩니다.</p>
<p>매개변수와 버퍼는 텐서의 형태로 상태를 저장합니다. 매개변수는 그래디언트를
기록하지만 버퍼는 기록하지 않습니다. 매개변수는 일반적으로 신경망의 학습
가능한 가중치입니다. 버퍼의 예로는 배치 정규화를 위한 평균 및 분산이
있습니다. 특정 논리 및 상태 블록을 재사용하기 위해, PyTorch API는
모듈들이 중첩되는 것을 허용합니다. 중첩된 모듈은 <em>하위 모듈</em> 이라고
합니다.</p>
<p>매개변수, 버퍼 및 하위 모듈은 명시적으로 등록(register)을 해야 합니다.
등록이 되면 <code class="docutils literal notranslate"><span class="pre">parameters()</span></code> 나 <code class="docutils literal notranslate"><span class="pre">buffers()</span></code> 같은 메서드를 사용하여 (중첩을
포함한) 전체 모듈 계층 구조에서 모든 매개변수 묶음을 검색할 수 있습니다.
마찬가지로, <code class="docutils literal notranslate"><span class="pre">to(...)</span></code> 와 같은 메서드는 모듈 계층 구조 전체에 대한 메서드입니다.
예를 들어, <code class="docutils literal notranslate"><span class="pre">to(torch::kCUDA)</span></code> 는 모든 매개변수와 버퍼를 CPU에서 CUDA 메모리로
이동시킵니다.</p>
<div class="section" id="id7">
<h4>모듈 정의 및 매개변수 등록<a class="headerlink" href="#id7" title="Permalink to this headline">¶</a></h4>
<p>이 내용을 코드로 구현하기 위해, 파이썬 인터페이스로 작성된 간단한 모듈 하나를
생각해 봅시다.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">torch</span>
<span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Net</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">W</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="n">M</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
<span class="k">return</span> <span class="n">torch</span><span class="o">.</span><span class="n">addmm</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">,</span> <span class="nb">input</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">W</span><span class="p">)</span>
</pre></div>
</div>
<p>이를 C++로 작성하면 다음과 같습니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><torch/torch.h></span><span class="cp"></span>
<span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">Net</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">M</span><span class="p">)</span> <span class="p">{</span>
<span class="n">W</span> <span class="o">=</span> <span class="n">register_parameter</span><span class="p">(</span><span class="s">"W"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">randn</span><span class="p">({</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">}));</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">register_parameter</span><span class="p">(</span><span class="s">"b"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">randn</span><span class="p">(</span><span class="n">M</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">forward</span><span class="p">(</span><span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">input</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">torch</span><span class="o">::</span><span class="n">addmm</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">input</span><span class="p">,</span> <span class="n">W</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">W</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>파이썬에서와 마찬가지로 모듈 기본 클래스에서 파생한 <code class="docutils literal notranslate"><span class="pre">Net</span></code> 이라는 클래스를
정의합니다. (쉬운 설명을 위해 <code class="docutils literal notranslate"><span class="pre">class</span></code> 대신 <code class="docutils literal notranslate"><span class="pre">struct</span></code> 을 사용했습니다.)
파이썬에서 torch.randn을 사용하는 것처럼 생성자에서는 <code class="docutils literal notranslate"><span class="pre">torch::randn</span></code> 을
사용해 텐서를 만듭니다. 한 가지 흥미로운 차이점은 매개변수를 등록하는
방법입니다. 파이썬에서는 텐서를 <code class="docutils literal notranslate"><span class="pre">torch.nn</span></code> 으로 감싸는 것과 달리,
C++에서는 <code class="docutils literal notranslate"><span class="pre">register_parameter</span></code> 메서드를 통해 텐서를 전달해야
합니다. 이러한 차이의 원인은 파이썬 API의 경우, 어떤 속성(attirbute)이
<code class="docutils literal notranslate"><span class="pre">torch.nn.Parameter</span></code> 타입인지 감지해 그러한 텐서를 자동으로 등록할 수 있기
때문에 나타납니다. C++에서는 리플렉션(reflection)이 매우 제한적이므로 보다
전통적인 (그리하여 덜 마법적인) 방식이 제공됩니다.</p>
</div>
<div class="section" id="id8">
<h4>서브모듈 등록 및 모듈 계층 구조 탐색<a class="headerlink" href="#id8" title="Permalink to this headline">¶</a></h4>
<p>매개변수 등록과 마찬가지 방법으로 서브모듈을 등록할 수 있습니다.
파이썬에서 서브모듈은 어떤 모듈의 속성으로 지정될 때 자동으로
감지되고 등록됩니다.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Net</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="c1"># Registered as a submodule behind the scenes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">linear</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">another_bias</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="n">M</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">linear</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">another_bias</span>
</pre></div>
</div>
<p>예를 들어, <code class="docutils literal notranslate"><span class="pre">parameters()</span></code> 메서드를 사용하면 모듈 계층의 모든 매개변수에
재귀적으로 액세스할 수 있습니다.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">net</span> <span class="o">=</span> <span class="n">Net</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">parameters</span><span class="p">()))</span>
<span class="go">[Parameter containing:</span>
<span class="go">tensor([0.0808, 0.8613, 0.2017, 0.5206, 0.5353], requires_grad=True), Parameter containing:</span>
<span class="go">tensor([[-0.3740, -0.0976, -0.4786, -0.4928],</span>
<span class="go"> [-0.1434, 0.4713, 0.1735, -0.3293],</span>
<span class="go"> [-0.3467, -0.3858, 0.1980, 0.1986],</span>
<span class="go"> [-0.1975, 0.4278, -0.1831, -0.2709],</span>
<span class="go"> [ 0.3730, 0.4307, 0.3236, -0.0629]], requires_grad=True), Parameter containing:</span>
<span class="go">tensor([ 0.2038, 0.4638, -0.2023, 0.1230, -0.0516], requires_grad=True)]</span>
</pre></div>
</div>
<p>C++에서 <code class="docutils literal notranslate"><span class="pre">torch::nn::Linear</span></code> 등의 모듈을 서브모듈로 등록하려면 이름에서
유추할 수 있듯이 <code class="docutils literal notranslate"><span class="pre">register_module()</span></code> 메서드를 사용합니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">Net</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">M</span><span class="p">)</span>
<span class="o">:</span> <span class="n">linear</span><span class="p">(</span><span class="n">register_module</span><span class="p">(</span><span class="s">"linear"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">)))</span> <span class="p">{</span>
<span class="n">another_bias</span> <span class="o">=</span> <span class="n">register_parameter</span><span class="p">(</span><span class="s">"b"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">randn</span><span class="p">(</span><span class="n">M</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">forward</span><span class="p">(</span><span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">input</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">linear</span><span class="p">(</span><span class="n">input</span><span class="p">)</span> <span class="o">+</span> <span class="n">another_bias</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span> <span class="n">linear</span><span class="p">;</span>
<span class="n">torch</span><span class="o">::</span><span class="n">Tensor</span> <span class="n">another_bias</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">torch::nn</span></code> 에 대한 <a class="reference external" href="https://pytorch.org/cppdocs/api/namespace_torch__nn.html">이 문서</a>
에서 <code class="docutils literal notranslate"><span class="pre">torch::nn::Linear</span></code>, <code class="docutils literal notranslate"><span class="pre">torch::nn::Dropout</span></code>, <code class="docutils literal notranslate"><span class="pre">torch::nn::Conv2d</span></code>
등 사용 가능한 전체 빌트인 모듈 목록을 확인할 수
있습니다.</p>
</div>
<p>위 코드에서 한 가지 미묘한 사실은 서브모듈은 생성자의 이니셜라이저
목록에 작성되고 매개변수는 생성자의 바디(body)에 작성되었다는
것입니다. 여기에는 충분한 이유가 있으며 아래 C++ 프론트엔드의
<em>오너십 모델</em> 섹션에서 더 다룰 예정입니다. 그렇지만 최종 결론은
파이썬에서처럼 모듈 트리의 매개변수에 재귀적으로 액세스할 수
있다는 것입니다. <code class="docutils literal notranslate"><span class="pre">parameters()</span></code> 를 호출하면 순회가 가능한
<code class="docutils literal notranslate"><span class="pre">std::vector<torch::Tensor></span></code> 가 반환됩니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Net</span> <span class="n">net</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&</span> <span class="nl">p</span> <span class="p">:</span> <span class="n">net</span><span class="p">.</span><span class="n">parameters</span><span class="p">())</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">p</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>이를 실행한 결과는 다음과 같습니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>root@fa350df05ecf:/home/build# ./dcgan
<span class="m">0</span>.0345
<span class="m">1</span>.4456
-0.6313
-0.3585
-0.4008
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span><span class="o">}</span> <span class="o">]</span>
-0.1647 <span class="m">0</span>.2891 <span class="m">0</span>.0527 -0.0354
<span class="m">0</span>.3084 <span class="m">0</span>.2025 <span class="m">0</span>.0343 <span class="m">0</span>.1824
-0.4630 -0.2862 <span class="m">0</span>.2500 -0.0420
<span class="m">0</span>.3679 -0.1482 -0.0460 <span class="m">0</span>.1967
<span class="m">0</span>.2132 -0.1992 <span class="m">0</span>.4257 <span class="m">0</span>.0739
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span>,4<span class="o">}</span> <span class="o">]</span>
<span class="m">0</span>.01 *
<span class="m">3</span>.6861
-10.1166
-45.0333
<span class="m">7</span>.9983
-20.0705
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span><span class="o">}</span> <span class="o">]</span>
</pre></div>
</div>
<p>파이썬에서와 같이 세 개의 매개변수가 출력됐습니다. 이 매개변수들의 이름을
확인할 수 있도록 C++ API는 <code class="docutils literal notranslate"><span class="pre">named_parameters()</span></code> 메서드를 제공하며, 이는
파이썬에서와 같이 <code class="docutils literal notranslate"><span class="pre">Orderdict</span></code> 를 반환합니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="n">Net</span> <span class="nf">net</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&</span> <span class="nl">pair</span> <span class="p">:</span> <span class="n">net</span><span class="p">.</span><span class="n">named_parameters</span><span class="p">())</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">pair</span><span class="p">.</span><span class="n">key</span><span class="p">()</span> <span class="o"><<</span> <span class="s">": "</span> <span class="o"><<</span> <span class="n">pair</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>마찬가지로 코드를 실행하면 결과는 아래와 같습니다.</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>root@fa350df05ecf:/home/build# make <span class="o">&&</span> ./dcgan <span class="m">11</span>:13:48
Scanning dependencies of target dcgan
<span class="o">[</span> <span class="m">50</span>%<span class="o">]</span> Building CXX object CMakeFiles/dcgan.dir/dcgan.cpp.o
<span class="o">[</span><span class="m">100</span>%<span class="o">]</span> Linking CXX executable dcgan
<span class="o">[</span><span class="m">100</span>%<span class="o">]</span> Built target dcgan
b: -0.1863
-0.8611
-0.1228
<span class="m">1</span>.3269
<span class="m">0</span>.9858
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span><span class="o">}</span> <span class="o">]</span>
linear.weight: <span class="m">0</span>.0339 <span class="m">0</span>.2484 <span class="m">0</span>.2035 -0.2103
-0.0715 -0.2975 -0.4350 -0.1878
-0.3616 <span class="m">0</span>.1050 -0.4982 <span class="m">0</span>.0335
-0.1605 <span class="m">0</span>.4963 <span class="m">0</span>.4099 -0.2883
<span class="m">0</span>.1818 -0.3447 -0.1501 -0.0215
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span>,4<span class="o">}</span> <span class="o">]</span>
linear.bias: -0.0250
<span class="m">0</span>.0408
<span class="m">0</span>.3756
-0.2149
-0.3636
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">5</span><span class="o">}</span> <span class="o">]</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">torch::nn::Module</span></code> 에 대한 <a class="reference external" href="https://pytorch.org/cppdocs/api/classtorch_1_1nn_1_1_module.html#exhale-class-classtorch-1-1nn-1-1-module">문서</a> 는
모듈 계층 구조에 대한 메서드 목록 전체가 포함되어
있습니다.</p>
</div>
</div>
<div class="section" id="forward">
<h4>순전파(forward) 모드로 네트워크 실행<a class="headerlink" href="#forward" title="Permalink to this headline">¶</a></h4>
<p>네트워크를 C++로 실행하기 위해서는, 우리가 정의한 <code class="docutils literal notranslate"><span class="pre">forward()</span></code> 메서드를
호출하기만 하면 됩니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Net</span> <span class="n">net</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">net</span><span class="p">.</span><span class="n">forward</span><span class="p">(</span><span class="n">torch</span><span class="o">::</span><span class="n">ones</span><span class="p">({</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">}))</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>출력은 대략 아래와 같을 것입니다</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>root@fa350df05ecf:/home/build# ./dcgan
<span class="m">0</span>.8559 <span class="m">1</span>.1572 <span class="m">2</span>.1069 -0.1247 <span class="m">0</span>.8060
<span class="m">0</span>.8559 <span class="m">1</span>.1572 <span class="m">2</span>.1069 -0.1247 <span class="m">0</span>.8060
<span class="o">[</span> Variable<span class="o">[</span>CPUFloatType<span class="o">]{</span><span class="m">2</span>,5<span class="o">}</span> <span class="o">]</span>
</pre></div>
</div>
</div>
<div class="section" id="ownership">
<h4>모듈 오너십 (Ownership)<a class="headerlink" href="#ownership" title="Permalink to this headline">¶</a></h4>
<p>이제 우리는 C++에서 모듈을 정의하고, 매개변수를 등록하고, 하위 모듈을
등록하고, <code class="docutils literal notranslate"><span class="pre">parameters()</span></code> 등의 메서드를 통해 모듈 계층을 탐색하고,
모듈의 <code class="docutils literal notranslate"><span class="pre">forward()</span></code> 메서드를 실행하는 방법을 배웠습니다. C++ API에는
다른 메서드, 클래스, 그리고 주제가 많지만 전체 목록은 <a class="reference external" href="https://pytorch.org/cppdocs/api/namespace_torch__nn.html">문서</a> 를
참조하시기 바랍니다. 잠시 후에 DCGAN 모델과 엔드 투 엔드 학습
파이프라인을 구현하면서도 몇 가지 개념을 더 다룰 예정입니다. 그에 앞서
C++ 프론트엔드에서 <code class="docutils literal notranslate"><span class="pre">torch::nn::Module</span></code> 의 하위 클래스들에 대해 제공하는
<em>오너십 모델</em> 에 대해 간단히 설명하겠습니다.</p>
<p>이 논의에서 오너십 모델이란 모듈을 저장하고 전달하는 방식
(누가 혹은 무엇이 특정 모듈 인스턴스를 소유하는지)을 지칭합니다.
파이썬에서 객체는 항상 힙에 동적으로 할당되며 레퍼런스 시맨틱을
가지는데, 이는 다루고 이해하기가 매우 쉽습니다. 실제로 파이썬에서는
객체가 어디에 존재하고 어떻게 레퍼런스되는지 신경 쓰지 않고 하려는
일에만 집중할 수 있습니다.</p>
<p>저급 언어인 C++는 이 부분에서 더 많은 옵션을 제공합니다. 이는
C++ 프론트엔드의 복잡성을 증가시키며 그 설계와 인체공학적 요소에도
큰 영향을 줍니다. 특히, C++ 프론트엔드 모듈에서는 밸류 시맨틱
<em>또는</em> 레퍼런스 시맨틱을 사용할 수 있습니다. 전자가 지금까지의
사례에서 살펴본 가장 단순한 경우로, 모듈 객체가 스택에 할당되고
함수에 전달될 때 레퍼런스 혹은 포인터로 복사 및 이동(<code class="docutils literal notranslate"><span class="pre">std:move</span></code>)
시키거나 가져올 수 있습니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span> <span class="p">};</span>
<span class="kt">void</span> <span class="nf">a</span><span class="p">(</span><span class="n">Net</span> <span class="n">net</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="kt">void</span> <span class="nf">b</span><span class="p">(</span><span class="n">Net</span><span class="o">&</span> <span class="n">net</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="kt">void</span> <span class="nf">c</span><span class="p">(</span><span class="n">Net</span><span class="o">*</span> <span class="n">net</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Net</span> <span class="n">net</span><span class="p">;</span>
<span class="n">a</span><span class="p">(</span><span class="n">net</span><span class="p">);</span>
<span class="n">a</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">net</span><span class="p">));</span>
<span class="n">b</span><span class="p">(</span><span class="n">net</span><span class="p">);</span>
<span class="n">c</span><span class="p">(</span><span class="o">&</span><span class="n">net</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>후자(레퍼런스 시맨틱)의 경우, <code class="docutils literal notranslate"><span class="pre">std::shared_ptr</span></code> 를 사용할 수 있습니다.
모든 곳에서 <code class="docutils literal notranslate"><span class="pre">shared_ptr</span></code> 를 사용한다는 가정 하에, 레퍼런스 시맨틱의
장점은 파이썬에서와 같이 모듈이 함수에 전달되고 인자가 선언되는 방식에
대해 생각할 부담을 덜어준다는 것입니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{};</span>
<span class="kt">void</span> <span class="nf">a</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o"><</span><span class="n">Net</span><span class="o">></span> <span class="n">net</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">auto</span> <span class="n">net</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_shared</span><span class="o"><</span><span class="n">Net</span><span class="o">></span><span class="p">();</span>
<span class="n">a</span><span class="p">(</span><span class="n">net</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>경험적으로, 동적 언어를 사용하던 연구자들은 비록 밸류 시맨틱이
더 C++에 “네이티브”함에도 불구하고 레퍼런스 시맨틱을 훨씬
선호합니다. 또한 <code class="docutils literal notranslate"><span class="pre">torch::nn::Module</span></code> 의 설계는
사용자 친화적인 파이썬 API를 유사하게 따르기 위해 shared 오너십에
의존합니다. 앞서 예시로 들었던 <code class="docutils literal notranslate"><span class="pre">Net</span></code> 의 정의를 축약해서 다시
살펴봅시다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">Net</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">M</span><span class="p">)</span>
<span class="o">:</span> <span class="n">linear</span><span class="p">(</span><span class="n">register_module</span><span class="p">(</span><span class="s">"linear"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">)))</span>
<span class="p">{</span> <span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span> <span class="n">linear</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>하위 모듈인 <code class="docutils literal notranslate"><span class="pre">linear</span></code> 를 사용하기 위해 이를 클래스에 직접 저장하고자
합니다. 그러나 동시에 모듈의 기초 클래스가 이 하위 모듈에 대해 알고 접근할
수 있기를 원합니다. 이를 위해서는 해당 하위 모듈에 대한 참조를 저장해야 합니다.
이 순간 이미 우리는 shared 오너십을 필요로 합니다. <code class="docutils literal notranslate"><span class="pre">torch::nn::Module</span></code>
클래스와 구상 클래스인 <code class="docutils literal notranslate"><span class="pre">Net</span></code> 모두에서 하위 모듈에 대한 레퍼런스가
필요합니다. 따라서 기초 클래스는 모듈을 <code class="docutils literal notranslate"><span class="pre">shared_ptr</span></code> 로 저장하며 이에
따라 구상 클래스 또한 마찬가지일 것입니다.</p>
<p>하지만 잠깐! 위의 코드에는 <code class="docutils literal notranslate"><span class="pre">shared_ptr</span></code> 에 대한 언급이 없습니다! 왜 그런
것일까요? 왜냐하면 <code class="docutils literal notranslate"><span class="pre">std::shared_ptr<MyModule></span></code> 는 타이핑하기에 너무 길기 때문입니다.
연구원들의 생산성을 유지하기 위해, 우리는 레퍼런스 시맨틱을 유지하면서 밸류
시맨틱만의 장점인 <code class="docutils literal notranslate"><span class="pre">shared_ptr</span></code> 에 대한 언급을 숨기기 위한 정교한 계획을
세웠습니다. 그 작동 방식을 이해하기 위해 코어 라이브러리에 있는 <code class="docutils literal notranslate"><span class="pre">torch::nn::Linear</span></code>
모듈의 단순화된 정의를 살펴보겠습니다. (전체 정의는
<a class="reference external" href="https://github.com/pytorch/pytorch/blob/master/torch/csrc/api/include/torch/nn/modules/linear.h">여기</a> 에서
확인할 수 있습니다.)</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">LinearImpl</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">LinearImpl</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">in</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">out</span><span class="p">);</span>
<span class="n">Tensor</span> <span class="nf">forward</span><span class="p">(</span><span class="k">const</span> <span class="n">Tensor</span><span class="o">&</span> <span class="n">input</span><span class="p">);</span>
<span class="n">Tensor</span> <span class="n">weight</span><span class="p">,</span> <span class="n">bias</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">TORCH_MODULE</span><span class="p">(</span><span class="n">Linear</span><span class="p">);</span>
</pre></div>
</div>
<p>요약하자면 이 모듈은 <code class="docutils literal notranslate"><span class="pre">Linear</span></code> 가 아닌 <code class="docutils literal notranslate"><span class="pre">LinearImpl</span></code> 이라고 불립니다. 그리고
<code class="docutils literal notranslate"><span class="pre">TORCH_MODULE</span></code> 라는 매크로가 실제 <code class="docutils literal notranslate"><span class="pre">Linear</span></code> 클래스를 정의합니다. 이렇게 “생성된”
클래스는 <code class="docutils literal notranslate"><span class="pre">std::shared_ptr<LinearImpl></span></code> 를 감싸는 래퍼(wrapper)입니다.
단순한 typedef가 아닌 래퍼이므로 생성자도 여전히 예상하는 대로 작동합니다.
즉, <code class="docutils literal notranslate"><span class="pre">std::make_shared<LinearImpl>(3,</span> <span class="pre">4)</span></code> 가 아닌 <code class="docutils literal notranslate"><span class="pre">torch::nn::Linear(3,</span> <span class="pre">4)</span></code>
라고 쓸 수 있습니다. 이렇게 매크로에 의해 생성된 클래스는 <em>holder</em> 모듈이라고
부릅니다. (shared) 포인터와 마찬가지로 화살표 연산자(즉,
<code class="docutils literal notranslate"><span class="pre">model->forward(...)</span></code>)를 사용해 기저 객체에 액세스합니다.
결론적으로 파이썬 API와 매우 유사한 오너십 모델을 얻었습니다.
기본적으로 레퍼런스 시맨틱을 따르지만, <code class="docutils literal notranslate"><span class="pre">std:shared_ptr</span></code> 나
<code class="docutils literal notranslate"><span class="pre">std::make_shared</span></code> 등을 타이핑할 필요가 없습니다. 우리의 <code class="docutils literal notranslate"><span class="pre">Net</span></code> 예시에서
모듈 holder API를 사용하면 아래와 같습니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">NetImpl</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{};</span>
<span class="n">TORCH_MODULE</span><span class="p">(</span><span class="n">Net</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">a</span><span class="p">(</span><span class="n">Net</span> <span class="n">net</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Net</span> <span class="n">net</span><span class="p">;</span>
<span class="n">a</span><span class="p">(</span><span class="n">net</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>여기서 언급할 만한 미묘한 문제가 하나 있습니다. 기본 생성자에 의해 만들어진
<code class="docutils literal notranslate"><span class="pre">std::shared_ptr</span></code> 는 “비어” 있습니다. 즉, null 포인터입니다. 기본 생성자로
만들어진 <code class="docutils literal notranslate"><span class="pre">Linear</span></code> 이나 <code class="docutils literal notranslate"><span class="pre">Net</span></code> 은 무엇이어야 할까요? 음, 이건 어려운 결정입니다.
빈 (null) <code class="docutils literal notranslate"><span class="pre">std::shared_ptr<LinearImpl></span></code> 로 정할 수 있습니다. 하지만
<code class="docutils literal notranslate"><span class="pre">Linear(3,</span> <span class="pre">4)</span></code> 가 <code class="docutils literal notranslate"><span class="pre">std::make_shared<LinearImpl>(3,</span> <span class="pre">4)</span></code> 와 같다는 것을 기억합시다.
즉, <code class="docutils literal notranslate"><span class="pre">Linear</span> <span class="pre">linear;</span></code> 이 null 포인터여야 한다고 결정한다면
생성자에서 인자를 전혀 받지 않거나 모든 인자에 대해 기본값을 사용하는
모듈을 생성할 방법이 없어집니다. 이러한 이유로 현재
API에서 기본 생성자에 의해 만들어진 모듈 holder(<code class="docutils literal notranslate"><span class="pre">Linear()</span></code> 등)는
기저 모듈(<code class="docutils literal notranslate"><span class="pre">LinearImpl()</span></code>)의 기본 생성자를 호출합니다. 만약
기저 모듈에 기본 생성자가 없으면 컴파일러 오류가 발생합니다.
반대로 빈 holder를 생성하려면 holder 생성자에 <code class="docutils literal notranslate"><span class="pre">nullptr</span></code> 를
전달하면 됩니다.</p>
<p>실제로는 앞에서와 같이 하위 모듈을 사용해 모듈을 <em>이니셜라이저 (initializer) 목록</em> 에
등록 및 생성하거나,</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">Net</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">M</span><span class="p">)</span>
<span class="o">:</span> <span class="n">linear</span><span class="p">(</span><span class="n">register_module</span><span class="p">(</span><span class="s">"linear"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">)))</span>
<span class="p">{</span> <span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span> <span class="n">linear</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>파이썬 사용자들에게 더 친숙한 방법으로, 먼저 null 포인터로 홀더를 생성한 이후
생성자에서 값을 지정할 수 있습니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">Net</span> <span class="o">:</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>
<span class="n">Net</span><span class="p">(</span><span class="kt">int64_t</span> <span class="n">N</span><span class="p">,</span> <span class="kt">int64_t</span> <span class="n">M</span><span class="p">)</span> <span class="p">{</span>
<span class="n">linear</span> <span class="o">=</span> <span class="n">register_module</span><span class="p">(</span><span class="s">"linear"</span><span class="p">,</span> <span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">M</span><span class="p">));</span>
<span class="p">}</span>
<span class="n">torch</span><span class="o">::</span><span class="n">nn</span><span class="o">::</span><span class="n">Linear</span> <span class="n">linear</span><span class="p">{</span><span class="k">nullptr</span><span class="p">};</span> <span class="c1">// construct an empty holder</span>
<span class="p">};</span>
</pre></div>
</div>
<p>결론적으로 어떤 오너십 모델, 어떤 시맨틱을 사용하면 좋을까요? C++
프론트엔드 API는 모듈 holder가 제공하는 오너십 모델을 가장 잘 지원합니다.
이 메커니즘의 유일한 단점은 모듈 선언 아래에 boilerplate 한 줄이
추가된다는 것입니다. 즉, 가장 단순한 모델은 C++ 모듈의 기초를 배울 떄
나오는 밸류 시맨틱 모델입니다. 작고 간단한 스크립트의 경우,
이것만으로 충분할 수 있습니다. 그러나 언젠가는 기술적 이유로 인해
이 기능이 항상 지원되지는 않는다는 사실을 알게 될 것입니다. 예를 들어 직렬화
API(<code class="docutils literal notranslate"><span class="pre">torch::save</span></code> 및 <code class="docutils literal notranslate"><span class="pre">torch::load</span></code>)는 모듈 holder(혹은 일반
<code class="docutils literal notranslate"><span class="pre">shared_ptr</span></code>)만을 지원합니다. 따라서 C++ 프론트엔드로 모듈을
정의할 떄에는 모듈 holder API 방식이 권장되며, 앞으로 본 튜토리얼에서
이 API를 사용하겠습니다.</p>
</div>
</div>
<div class="section" id="id13">
<h3>DCGAN 모듈 정의하기<a class="headerlink" href="#id13" title="Permalink to this headline">¶</a></h3>
<p>이제 이 글에서 해결하려는 머신러닝 태스크를 위한 모듈을 정의하는데
필요한 배경과 도입부 설명이 끝났습니다. 다시 상기하자면, 우리의 태스크는
<a class="reference external" href="http://yann.lecun.com/exdb/mnist/">MNIST 데이터셋</a> 의 숫자 이미지를
생성하는 것입니다. 우리는 이 태스크를 풀기 위해
<a class="reference external" href="https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf">적대적 생성 신경망(GAN)</a> 을
사용하고자 합니다. 그 중에서도 우리는 <a class="reference external" href="https://arxiv.org/abs/1511.06434">DCGAN 아키텍처</a> 를 사용할 것입니다.
DCGAN은 가장 초기에 발표됐던 제일 간단한 GAN이지만 이 태스크를 위해서는
충분합니다.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">이 튜토리얼에 나온 소스 코드 전체는 <a class="reference external" href="https://github.com/pytorch/examples/tree/master/cpp/dcgan">이 저장소</a> 에서 확인할 수 있습니다.</p>
</div>
<div class="section" id="id16">
<h4>GAN이 뭐였죠?<a class="headerlink" href="#id16" title="Permalink to this headline">¶</a></h4>
<p>GAN은 <em>생성기(generator)</em> 와 <em>판별기(discriminator)</em> 라는
두 가지 신경망 모델로 구성됩니다. 생성기는 노이즈 분포에서 샘플을 입력받고,
각 노이즈 샘플을 목표 분포(이 경우 MNIST 데이터셋)와 유사한 이미지로
변환하는 것이 목표입니다. 판별기는 MNIST 데이터셋의 <em>진짜</em>
이미지를 입력받거나 생성기로부터 <em>가짜</em> 이미지를 입력받습니다.
그리고 어떤 이미지가 얼마나 진짜같은지 (<code class="docutils literal notranslate"><span class="pre">1</span></code> 에 가까운 출력)
혹은 가짜같은 지 (<code class="docutils literal notranslate"><span class="pre">0</span></code> 에 가까운 출력) 판별합니다. 생성기가
만든 이미지가 얼마나 진짜같은 지 판별기가 피드백하고 이 피드백은 생성기
학습에 사용됩니다. 판별기가 진짜에 대한 안목이 얼마나 좋은 지에
대한 피드백은 판별기를 최적화하기 위해 사용됩니다. 이론적으로,
생성기와 판별기 사이의 섬세한 균형은 이 둘을 동시에 개선시킵니다.
이를 통해 생성기는 목표 분포와 구별할 수 없는 이미지를 생성하고,
(그때쯤이면) 잘 학습되어 있을 판별기의 안목을 속여 진짜와 가짜
이미지 모두에 대해 <code class="docutils literal notranslate"><span class="pre">0.5</span></code> 의 확률을 출력할 것입니다. 최종
결과물은 노이즈를 입력받아 실제 숫자의 이미지를 출력으로 생성하는
기계입니다.</p>
</div>
<div class="section" id="generator">
<h4>생성기 (Generator) 모듈<a class="headerlink" href="#generator" title="Permalink to this headline">¶</a></h4>
<p>먼저 일련의 전치된 (transposed) 2D 합성곱, 배치 정규화 및
ReLU 활성화 유닛으로 구성된 생성기 모듈을 정의하겠습니다.
모듈의 <code class="docutils literal notranslate"><span class="pre">forward()</span></code> 메서드를 직접 정의하여 모듈 간 입력을
(함수형으로) 명시적으로 전달합니다.</p>
<div class="highlight-cpp notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="nc">DCGANGeneratorImpl</span> <span class="o">:</span> <span class="n">nn</span><span class="o">::</span><span class="n">Module</span> <span class="p">{</span>