호기심 많은 분석가
[BoostCamp] Week3_Day14. 첫 U-Stage를 마무리하며 본문
개요
다음 주부터는 3주간 배운 지식을 바탕으로 이미지 분류 대회를 진행한다. 바로 투입되기에는 지식의 흡수도 완전하지 않고, 완성도도 높지 않지만 실전과 함께 배워야 하지 않겠는가, 우리 팀은 1등이 목표가 아닌 모두가 함께 성장하는 방향으로 진행하고자 한다. 마지막 날이라 그런지 정말 많은 이벤트들이 있었다.
✍🏻학습 정리
(08강) Multi-GPU 학습
🎯 PyTorch에서 Multi GPU를 사용하기 위해 딥러닝 모델을 병렬화 하는
Model Parallel의 개념과 데이터 로딩을 병렬화하는 Data Parallel의 개념을 학습
- 예전에는 어떻게 하면 구조를 단순화하여 GPU를 적게 쓸까 고민하고, 작은 데이터로 학습했다면 지금은 훌륭한 GPU를 많이 쓰고 데이터를 많이 활용해서 좋은 성능을 이끌어낸다.
오늘날의 딥러닝은 엄청난 데이터와의 싸움
1. 개념정리
- Single(1) vs. Multi(2 이상)
- GPU vs. Node(System)
- Node는 컴퓨터를 의미함
- Single Node Single GPU
- 1개의 Node와 1개의 GPU를 쓴다고 하면 1대의 컴퓨터 안에 1개의 GPU가 있음을 의미
- Single Node Multi GPU
- 1대의 컴퓨터에는 GPU가 4-8개까지 들어갈 수 있다
- Multi Node Multi GPU
- 궁극적인 목표지만 리소스도 많이 들고 되게 어렵다
2. Model parallel
- 다중 GPU에 학습을 분산하는 두 가지 방법
- 모델을 나누기 / 데이터를 나누기
- 모델을 나누는 것은 생각보다 예전부터 썼음 (AlexNet)
- 예를 들어 90개의 filter가 있다면 45개의 filter는 A파트로 할당하고, 남은 45개의 filter를 B파트로 할당해서 서로 독립적으로 연산할 수 있게 했다. 그러고 3번째 Conv layer에서 그 filter를 서로 뒤섞음으로써 각각의 GPU들이 병렬적인 처리를 하게 도와줌
- 모델의 병목, 파이프라인의 어려움 등으로 인해 모델 병렬화는 고난이도 과제
- 모델 병렬화에서 문제가 되는 부분은 아래 사진의 윗부분을 의미한다. 윗부분처럼 하면 병렬화하는 의미가 없다. 병렬화한다는 것은 각각이 각각의 시간에 맞게 처리를 하는 것인데 비어 있으면 그렇지 않고, 또한 파이프라인까지 만들어져 있지 않기 때문에 효과가 없다.
- 좋은 병렬화는 각 GPU가 처리될 때가 겹쳐야 한다. 그렇게 파이프라인을 구성해주는 게 굉장히 중요하다
- 0, 1, 2, 3은 batch를 의미하는데 GPU0에서 0배치가 끝나면 GPU1으로 보내주는 코드를 짜야한다.
class ModelParallelResNet50(ResNet):
def __init__(self, *args, **kwargs):
super(ModelParallelResNet50, self).__init__(
Bottleneck, [3, 4, 6, 3], num_classes=num_classes, *args, **kwargs)
# 첫번째 모델을 cuda 0에 할당
self.seq1 = nn.Sequential(
self.conv1, self.bn1, self.relu, self.maxpool, self.layer1, self.layer2
).to('cuda:0')
# 두번째 모델을 cuda 1에 할당
self.seq2 = nn.Sequential(
self.layer3, self.layer4, self.avgpool,
).to('cuda:1')
# fully-connected
self.fc.to('cuda:1')
# 두 모델을 연결하기
def forward(self, x) :
# cuda:0에서 seq1을 다 하고 나서 cuda:1으로 보내줌(copy), 병렬화
x = self.seq2(self.seq1(x).to('cuda:1'))
return self.fc(x.view(x.size(0), -1))
- 하지만 윗 사진과 코드처럼 하게 되면 병렬화가 잘 안되고 병목(데이터 처리의 지연) 현상이 생기니까 파이프라인을 잘 만들어줘서 끊임없이 GPU를 활용할 수 있게 해줘야 함
3. Data parallel
- 데이터를 나눠 GPU에 할당 후 결과의 평균을 취하는 방법
- minibatch 수식과 유사한데 한 번에 여러 GPU에서 수행
- 데이터는 100만 장이 있다면 50만 장은 batch1, 나머지 50만 장은 batch2로 학습해서 각각의 GPU에서 나오는 loss값을 gradient(미분)해줘서 그 미분 값의 평균을 가지고 전체 미분 값을 구해줌
3-1. 모델 수행방법
- 데이터가 오면 GPU가 여러 GPU에 데이터를 쪼개서 나눠줌
- 모델들을 각각의 GPU에 복사(Replicate)를 시켜줌
- 각각의 모델들이 연산을 수행함(Forward)
- 그 연산한 결과 값을 한 곳에 모아줌
- 그럼 각각의 loss 값을 한 번에 보여준다.
- global interpreter lock (GIL)의 이유도 있음
- 그리고 모은 GPU에서 각각의 loss를 구해주게 됨 → Gradient도 각각 구해줌
- 그 Gradient를 다시 여러 GPU에 뿌려준다
- 각각의 모델들이 Backward 과정을 거침
- 새로운 weight 값의 파라미터들이 나옴
- 그걸 모아서 그들의 평균을 내서 gradient를 update 해줌
- 하나의 GPU가 책임을 많이 진다. 그래서 GPU가 폭발하곤 하는 것
- PyTorch에서는 아래 두 가지 방식을 제공
- DataParallel, DistributedDataParallel
- DataParallel - 단순히 데이터를 분배한 후 평균을 취함, 위에서 본 것
- GPU 사용 불균형 문제 발생, 그래서 한 GPU가 너무 무리하지 않게 Batch 사이즈를 조절해줘야 한다, GIL 문제도 있다
- DistributedDataParallel - 각 CPU마다 process 생성하여 개별 GPU에 할당
- 기본적으로 DataParallel로 하나 개별적으로 연산의 평균을 냄
- 위의 과정에서 모으는 과정이 없고 각각이 모든 연산을 진행하고 마지막에 평균냄
- 이것을 PyTorch 개발자들이 권장한다 → 속도의 이득이나 multi-process를 사용할 수 있어 여러 컴퓨터에서 계산하여 취합할 수 있는 구조이기 때문
# 아래 한 줄만 입력해주면 Data Parallel이 시행된다.
parallel_model = torch.nn.DataParallel(model) # Encapsulate the model
predictions = parallel_model(inputs) # Forward pass on multi-GPUs
loss = loss_function(predictions, labels) # Compute loss function
loss.mean().backward() # Average GPU-losses + backward pass
optimizer.step() # Optimizer step
predictions = parallel_model(inputs) # Forward pass with new parameters
- DistributedDataParallel은 조금 더 코드가 귀찮음 → Sampler를 사용해줘야 한다
train_sampler = torch.utils.data.distributed.DistributedSampler(train_data)
shuffle = False
pin_memory = True # DRAM(Memory)에 Data를 바로 올릴 수 있도록 절차를 간소화
# -> 그게 GPU로 가서 연산이 됨, 그걸 빠르게 해준다
trainloader = torch.utils.data.DataLoader(train_data, batch_size=20, pin_memory=pin_memory,
num_workers=3, shuffle=shuffle, sampler=train_sampler)
# num_workers는 GPU의 4배를 보통 해준다고 함
- Python의 멀티프로세싱 코드
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__' :
with Pool(5) as p :
print(p.map(f, [1, 2, 3])
# f라는 함수에 1, 2, 3이라는 값을 mapping시키는 것을 5개의 멀티프로세스로 구해줌
- 위 코드와 과정이 비슷하다
def main() :
n_gpus =torch.cuda.device_count() # GPU 사용 가능 개수
# main_worker라는 함수, GPU(프로세스) 개수, 들어갈 파라미터
torch.multiprocessing.spawn(main_worker, nprocs=n_gpus, args=(n_gpus, ))
def main_worker(gpu, n_gpus):
image_size = 224
batch_size = 512
num_worker = 8
epochs = ...
# 데이터를 잘라주는 기준을 GPU만큼으로 잘라준다
batch_size = int(batch_size / n_gpus)
num_worker = int(num_worker / n_gpus)
# 멀티프로세싱 통신 규약 정의 - 멀티프로세스를 위해, 데이터를 주고 받기 위해
torch.distributed.init_process_group(
backend='nccl', init_method='tcp://127.0.0.1:2568', world_size=n_gpus rank=gpu)
model = MODEL
torch.cuda_set_device(gpu)
model = model.cuda(gpu)
# Distributed dataparallel 정의
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[gpu])
(09강) Hyperparameter Tuning
🎯 PyTorch 기반으로 여러 config들을 통해 학습할 때에 사용되는 parameter들을 실험자가
손 쉽게 지역 최적해를 구할 수 있도록 도와주는 Ray Tune 프레임워크로 최적화
- 성능을 높이기 위한 방법
- 모델 변화
- 가장 좋은 방법이지만, 대부분 좋은 방법들은 정해져 있음
- 데이터 변화 - 데이터를 추가하거나, 기존 데이터 오류 찾거나
- 꽤 좋은 방법, 데이터는 다다익선
- 하이퍼파라미터 튜닝
- 생각보다 성능의 표현이 크지 않지만, 끝날 때까지 끝난 게 아니다는 생각으로 시도
- 모델 변화
1. Hyperparameter Tuning
- 모델 스스로 학습하지 않는 값은 사람이 지정
- learning rate - (NAS, AutoML), 모델의 크기, optimizer 등
- 하이퍼 파라미터에 의해서 값의 크게 좌우될 때도 있음 - 요즘은 잘 그렇지 않다고 함
- 예전엔 Recipe를 기반으로 값을 넣어줄 때만 제대로 값이 나오곤 했는데, 요즘은 많은 데이터로 이것을 극복
- 마지막 0.01을 쥐어짜야 할 때 도전해볼 만하다.
- 예전만큼의 중요성은 떨어졌다
- 가장 기본적인 방법 - gird search vs. random layout
- Gird Search : 일정한 여러 기준 사이를 돌아가면서 학습하고 그중 최고를 찾는 방법
- Random Layout : 일정하지 않게 랜덤으로 뽑아서 가장 좋은 값을 찾는 방법
→ Random Layout으로 학습이 잘 되는 구간을 찾아서 거기에서 Grid Search를 행해주면 좋다, 하지만 지금은 거의 안 쓰이고 최근에는 베이지만 기반 기법들이 주도(BOHB)
2. Ray
- Hyperparameter Tuning의 대표적인 도구
- multi-node multi processing 지원 모듈 - 여러 대 컴퓨터를 연결해서 지원
- ML/DL의 병렬 처리를 위해 개발된 모듈
- Python의 일반적인 병렬 처리도 Ray를 사용하기 때문에 기본적으로 알아두면 좋다.
- SPARK 플랫폼 개발한 연구실에서 만든 모듈
- 기본적으로 현재의 분산 병렬 ML/DL 모듈의 표준
- Hyperparameter Search를 위한 다양한 모듈 제공
2-1. Ray 사용 코드
- Config에 Search space 지정 → 굉장히 중요
- 함수들은 Ray 표준문서 참고
# !pip install ray
# ray 내부적으로 tensorboardX라는 모듈을 사용하기 때문에 같이 설치
# !pip install tensorboardX
from functools import partial
from ray import tune
from ray.tune import CLIReporter
from ray.tune.schedulers import ASHAScheduler
config = {
"l1": tune.sample_from(lambda _: 2 ** np.random.randint(2, 9)),
"l2": tune.sample_from(lambda _: 2 ** np.random.randint(2, 9)),
"lr": tune.loguniform(1e-4, 1e-1), # GridSearch
"batch_size": tune.choice([2, 4, 8, 16]) # GridSearch
}
- 학습 스케쥴링 알고리즘 지정
- ASHA Scheduler는 중간중간 의미 없는 metric들은 잘라내는 알고리즘
- 아래 사진의 Rung1 → Rung2를 보면 몇 개의 metric이 날아감
scheduler = ASHAScheduler(
metric="loss",
mode="min",
max_t=max_num_epochs,
grace_period=1,
reduction_factor=2)
# 결과 출력 양식 지정
reporter = CLIReporter(
# parameter_columns=["l1", "l2", "lr", "batch_size"],
metric_columns=["loss", "accuracy", "training_iteration"])
- 병렬 처리 양식으로 학습 시행
result = tune.run(
# 데이터를 쪼개는 파트, train_cifar : 학습할 함수
partial(train_cifar, data_dir=data_dir),
# 사용할 cpu, gpu 개수
resources_per_trial={"cpu": 2, "gpu": gpus_per_trial},
config=config,
num_samples=num_samples,
scheduler=scheduler,
progress_reporter=reporter)
- 우리가 Ray를 사용하려는 모델은 학습하는 과정이 처음부터 끝까지 모두 한 함수에 들어가 있어야 함 → 그래야 Ray가 불러올 수 있다.
정리
- 하이퍼파라미터 튜닝은 시간 대비 효율이 좋은 방식은 아니다. 어떻게 하면 더 좋은 데이터를 넣어줄 수 있을까 고민하는 게 더 좋음.
- 그렇게 마지막으로 가서 조금 더 노력하는 것이 하이퍼파라미터 튜닝
- 요즘은 다른 방법들도 있지만 Ray의 작동 방식은 알아두는 것이 좋다.
(10강) PyTorch Troubleshooting
🎯 GPU에서의 Out Of Memory (OOM) 에러 상황들의 예시를 보고 해결하는 법
- 엄청 필요한 강의다. OOM이 발생할 때마다 답이 없다고 느꼈는데, 드디어 해결할 수 있겠다
1. OOM이 해결하기 어려운 이유들
- 왜 발생했는지 알기 어려움
- 어디서 발생했는지 알기 어려움
- Error backtracking이 이상한 데로 감
- 메모리의 이전 상황의 파악이 어려움
→ Batch size ↓ → GPU clean (런치 재시작) → Run
2-1. GPUtil 사용하기
- nvidia-smi처럼 GPU의 상태를 보여주는 모듈
- Colab은 환경에서 GPU 상태 보여주기 편함
- iter마다 메모리가 늘어나는지 확인!!
- 계속 쌓이면 잘못 코드를 짰을 가능성이 있음
!pip install GPUtil
import GPUtil
GPUtil.showUtilization()
2-2. torch.cuda.empty_cache() 써보기
- 사용되지 않은 GPU상 cache를 정리
- 가용 메모리를 확보
- del 과는 구분이 필요
- reset 대신 쓰기 좋은 함수
- 생각보다 꽤 일어나는 일이기 때문에 학습 전에는 한 번씩 실행해보는 것을 추천
import torch
from GPUtil import showUtilization as gpu_usage
print('Initial GPU Usage')
gpu_usage()
tensorList = []
for x in range(10):
# tensorList를 랜덤으로 cuda에 쌓이게 함, 40%의 메모리가 쌓임
tensorList.append(torch.randn(100000000, 10).cuda())
print('GPU Usage after allcoatiing a bunch of Tensors')
gpu_usage()
# memory free를 시켜줌, 하지만 이 메모리를 다시 쓰는 것은 garbage collector를
# 사용할 때, cache 쌓이는 것을 없애줄 때 사용할 수 있다
del tensorList
print('GPU Usage after deleting the Tensors')
gpu_usage()
print('GPU Usage after emptying the cache')
torch.cuda.empty_cache()
gpu_usage()
2-3. training loop에 tensor로 축적되는 변수는 확인할 것
- tensor로 처리된 변수는 GPU 상에 메모리로 올라감
- 해당 변수는 loop 안에 연산이 있을 때 GPU에 computational graph를 생성 (메모리 잠식)
- 아래의 코드를 보면 loss 값은 한 번 필요한데 tensor의 형태로 backward 된 것이 계속 기록되니까 메모리 잠식이 일어남
total_loss = 0
for i in range(10000) :
optimizer.zero_grad()
output = model(input)
# tensor
loss = criterion(output)
loss.backward()
optimizer.step()
total_loss += loss
→ 그래서 그런 1-d tensor의 경우에는 python 기본 객체로 변환하여 처리할 것
total_loss = 0
for x in range(10):
# assume loss is computed
iter_loss = torch.randn(3, 4).mean()
iter_loss.requires_grad = True
total_loss += iter_loss.item or float(iter_loss) # 사용
2-4. del 명령어를 적절히 사용하기
- 필요가 없어진 변수는 적절한 삭제가 필요함
- python의 메모리 배치 특성상 loop이 끝나도 메모리를 차지함
for x in range(10):
i = x
print(i) # for loop이 끝났음에도 불구하고 9가 찍힌다.
for i in range(5):
intermediate = f(input[i])
result += g(intermediate)
# 이 파트에서 적절한 del이 필요함
output = h(result)
return output
# 이렇게하면 intermediate가 굉장히 많은 메모리를 차지함
2-5. 가능 batch 사이즈 실험해보기
- 학습 시 OOM이 발생했다면 batch 사이즈를 1로 해서 실험해보기
oom = False
try :
run_model(batch_size) # 64, 128,...
except RuntimeError : # Out of Memory
oom = True
if oom :
for _ in range(batch_size):
run_model(1)
2-6. torch.no_grad() 사용하기
- Inference(성능 평가) 시점에서는 torch.no_grad() 구문을 사용
- backward가 일어나지 않기 때문에 메모리를 사용하지 않음
- backward pass으로 인해 쌓이는 메모리에서 자유로움
with torch.no_grad() :
for data, target in test_loader:
output = network(data)
test_loss += F.nll_loss(output, target, size_average=False).item()
pred = output.data.max(1, keepdim=True)[1]
correct += pred.eq(target.data.view_as(pred)).sum()
2-7. 예상치 못한 에러 메시지
- OOM 말고도 유사한 에러들이 발생
- CUDNN_STATUS_NOT_INIT이나 device_side_assert 등
- 해당 에러도 cuda와 관련하여 OOM의 일종으로 생각될 수 있으며, 적절한 코드 처리가 필요함
이유를 알 수 없는 GPU 에러 정리(device-side assert, CUDA error, CUDNN_STATUS_NOT_INITIALIZED 등등...)
2-8. 그 외...
- colab에서 너무 큰 사이즈는 실행하지 말 것 → linear, CNN, LSTM
- CNN에서 대부분의 에러는 크기가 안 맞아서 생기는 경우
- torchsummary 등으로 사이즈를 맞출 것
- tensor의 float precision을 16bit로 줄일 수도 있음 → 많이 쓰진 않는다.
마지막 3 강의에서는 정말 중요한 것들을 배웠다. 나도 이전의 여러 경험들에서 겪었던 문제고, 알고 싶었던 부분이었다. 이렇게 배우게 되어서 다행이고, 앞으로도 자주 들릴 포스팅일 것 같다.
👨🏻🏫멘토링
- 이번 주도 역시나 한 주를 어떻게 보냈고, 어땠는지 감상을 나눔
Q&A
1. gather & scatter
- gather
- 고차원의 tensor가 있을 때 효율적으로 값들을 가져오는 함수다.
- 결과가 dim 방향으로 나옴 → dim이 1이라면 출력도 세로로
- scatter
- gather의 반대로써 입력 텐서에 있는 값들을 일부 가져와서 새로운 텐서에 넣어주는 함수
- dim이 0이면 세로 방향으로 데이터를 집어넣어 줌
2. transformer계열의 모델이 LM을 학습해서 다양한 태스크에 finetuning 하여 사용 가능하고, CNN도 feature extractor로써 다양한 task에 사용되는데, bert이전의 모델들(LSTM) 같은 모델들도 finetuning이 잘 되나요..?
- 다른 모델들도 사전학습 모델이 있었고, 성능이 좋았지만, bert가 너무 압도적인 성능을 보여서 많이 잊혔다.
CV와 NLP에 대해서 이번 주도 토의를 조금 나누고, 다음 주부터는 학습 일정 보여드리고 목표를 받기로 하였음. 우리 멘토님은 항상 무언가를 더 해주고 싶어 하신다. 그런 마음에 늘 감사드리고, 나도 어떻게 하면 더 소통할 수 있을까 고민하고 친근하게 다가가려 노력한다. 심지어 공부도 잘하시는데 남은 2주간 더 가까워졌으면 좋겠다.
⁉ 랜덤 피어세션
- 곽** 30조 - 통계학과, 컴퓨터학과 : 뭔가 이루고자 들어왔다.
- NLP : 재밌어서..!
- 이** 30조 - 소프트웨어 졸업 예정, 거의 AI 처음이다. CV vs NLP 중 고민 중, 아마 CV로 갈 것 같다.
- NLP가 수요가 많을 것 같은데 흥미는 CV라서 고민 중이다.
- 정** 30조 - 경제학, 응용통계학, 최종 목표는 창업인데 개발 능력이 굉장히 중요해 보여서 전문적인 교육을 받기 위해 왔다. NLP 쪽을 갈 것 같다.
- NLP : 공급이 부족해 보인다. 챗봇 만들어보고 싶다.
- 심** 6조 - 소프트웨어 전공 졸업, CV에 관심이 많다.
- NLP가 취업에 좋아 보이지만, CV가 재밌어서 CV를 갈 것 같다.
- 홍** 6조 - 통계학과, EDA만 하다 보니까 한계에 부딪히더라, 직접 문제를 해결해 보자 해서 코세라 강의를 들었다.
- CV : 초보이기도 하고, 자료가 많은 분야라서 배우고 싶었다.
- 팀에서 ResNet 구현하는 스터디를 진행했다.
- 석사 박**님의 도움으로 구현함
- 과제 중간중간 안 풀리던 건 팀원들과 토의를 하며 해결했다.
- 나동빈 님 유튜브, 논문 리뷰-구현하는 법
- 논문을 처음부터 읽으려면 더 어려울 거니까 구현해보는 것도 추천한다.
- 30조는 알고리즘, 코딩 테스트 준비 중, 매주 금요일 낮 10-12시
여러 조의 이야기를 들을 수 있는 랜덤피어세션은 늘 흥미로운 시간이다. 다른 조들을 만나다 보면 역시 우물 안의 개구리였음을 깨닫곤 한다. 저렇게 다들 열심히 하는 데 나도 더 노력해야지..!
🙋🏻♂️피어세션
- 랜덤피어세션에 대해서 이야기 나눔
- 회고록 함께 작성하고 대회에 대해서 이야기 나눔
- 깃헙으로 협업!
- 1등보다 모두가 일정 수준 이상 갈 수 있는, 모든 업무를 할 수 있게 대회를 진행하자
- 코드 리뷰를 많이 하자
- 배우기 위한 과정이니까
다른 이벤트들 때문에 유독 짧았던 피어세션이었다. 수업 리뷰는 이루어지지 않았고, 오늘 있었던 일과 다음 주 대회에 대해 논의 나눴다.
👨🏻🏫오피스아워
- 가장 기대가 됐던 오피스아워이다. 너무 재밌었던 과제였으며, 감사드렸던 과제이기 때문이다.
1. Custom 모델 제작
- 박현병 멘토님
- 문제 출제 의도를 설명할 것
- 베타 함수는 다음 파이 토치에서 호환성 문제도 생길 수 있기 때문에 내가 쓰는 함수가 베타 함수인지 꼭 확인해보자
Gather
Index Tensor의 크기는 우리가 원하는 Output Tensor의 크기와 같다. Gather의 Index는 각 원소마다 하나씩 값을 지정해주어야 한다.
List에서 indexing을 하던 것처럼 한 번에 여러 요소를 선택할 수가 없다! 원하는 요소의 개수만큼 index를 만들어야 한다.
i, j는 여기서 0차원, 1차원, k가 2차원이다. index[i][j][k]의 값에 따라 어떤 요소를 선택할지가 결정된다.
참고 더 보기 : torchscript, torch.fx, libtorch
https://pytorch.org/docs/master/jit.html#torchscript
📭롤링페이퍼
- U stage가 종료되면서 수고한 나 자신에게 응원의 한 마디를 쓰고, 롤링페이퍼를 작성하는 시간을 가졌는데, 처음에는 '또 할 게 늘었구나'라고 생각했지만, 하다 보니 롤링페이퍼 작성하는 게 너무 재밌어서 학습 시간에도 영향을 끼쳤을 정도... 우리 팀원들 말고도 꽤 여러 분들이 작성해주셨는데 정말 감사할 따름이고 익명이라 누군지 다 모르고 지나가는 게 조금 아쉽다. 부스트 캠프에서는 가끔 이런 귀염 뽀짝 한 것도 진행해줘서 좋다. 랜덤피어세션도 그렇고 많은 캠퍼들을 만날 수 있는 기회가 더 주어졌으면 좋겠다.
'Coding > BoostCamp' 카테고리의 다른 글
[BoostCamp] Week4_Day16. 모델의 완성 (0) | 2021.08.27 |
---|---|
[BoostCamp] Week4_Day15. P-Stage의 시작 (0) | 2021.08.25 |
[BoostCamp] Week3_Day13. 따뜻한 피드백 (0) | 2021.08.21 |
[BoostCamp] Week3_Day12. 역대 최고의 교육자료, Custom Model (0) | 2021.08.21 |
[BoostCamp] Week3_Day11. PyTorch를 배워보자! (0) | 2021.08.17 |