Tensorflow & Pytorch 비교 RNN
in Deep Learning on basic
RNN 기본 모델 코드를 Tensorflow와 Pytorch에서 비교한 게시물 입니다.
tensorflow와 pytorch를 동시에 사용하기 위해서,
Main Base : Tensorflow 실습 코드 출처
비교용 Base : Pytorch 실습 코드 출처
or pytorch 2.2.0+cpu version에서 오류 수정 한 버전으로 비교.
전체 파일 내용은 tensorflow_pytorch_comaprison 확인 가능.
해당 블로그에는 비교 내용 작성.
1. RNN 기초
in tensorflow
먼저 tensorflow에서의 RNN 코드이다.
TensorFlow에서는 tf.keras.Sequential
을 이용해 간결하게 RNN 구조를 정의할 수 있다.
임베딩 가중치를 one-hot 형태로 고정하고,
이후 SimpleRNN
, Dropout
, Dense
층을 쌓아 모델을 구성한다.
num_classes = 2
hidden_dims = [10, 10]
input_dim = len(char2idx)
output_dim = len(char2idx)
one_hot = np.eye(len(char2idx)) #N×N 크기의 단위 행렬(identity matrix)을 생성
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(input_dim = input_dim, output_dim = output_dim,
trainable=False, mask_zero=True, input_length=max_sequence,
embeddings_initializer=tf.keras.initializers.Constant(one_hot)))
#trainable은 임베딩 가중치를 훈련 가능하게 할지 여부를 결정, False로 설정 -> 훈련 중에 업데이트되지 않음.
model.add(tf.keras.layers.SimpleRNN(units=hidden_dims[0], return_sequences=True))
model.add(tf.keras.layers.TimeDistributed(tf.keras.layers.Dropout(rate=0.2))) #dropout을 시간 단계별로 적용
model.add(tf.keras.layers.SimpleRNN(units=hidden_dims[1]))
model.add(tf.keras.layers.Dropout(rate=0.2))
model.add(tf.keras.layers.Dense(units=num_classes))
만약 tensorflow에서 순환신겸망을 양방향으로 구축하고 싶다면 아래와 같이
Bidirectional 층을 추가해주어야 합니다.
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(input_dim = input_dim, output_dim = output_dim, mask_zero = True,
trainable=False, input_length = max_sequence,
embeddings_initializer = tf.keras.initializers.Constant(one_hot)))
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.SimpleRNN(units=hidden_dim, return_sequences=True))) #양방향 순환 신경망
model.add(tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(units=num_classes)))
in pytorch
그 다음은 pytorch에서의 모델 구축이다.
PyTorch에서는 nn.Module을 상속받아 클래스로 모델을 구현한다.
입력은 (batch, sequence_length, input_size) 형태를 가진다.
순환신겸망을 양방향으로 구축하고 싶다면
bidirectional=True 옵션을 지정하면 된다.
class RNN(torch.nn.Module):
def __init__(self, num_classes, input_size, hidden_size, num_layers):
super(RNN, self).__init__()
self.num_classes = num_classes
self.num_layers = num_layers
self.input_size = input_size
self.hidden_size = hidden_size
self.sequence_length = sequence_length
self.rnn = torch.nn.RNN(input_size = 5,
hidden_size = 5,
batch_first = True) #bidirectional=True
def forward(self, x):
h_0 = torch.zeros(
self.num_layers, x.size(0), self.hidden_size)
x.view(x.size(0), self.sequence_length, self.input_size) # Reshape input (batch, sequence, input)
out, _ = self.rnn(x, h_0)
return out.view(-1, num_classes)
1-2. 모델 학습 코드
그리고 학습을 원한다면, epoch 수 만큼 반복해가면서 gradient를 감소시키는 방향으로
모델을 학습시키면 된다.
in tensorflow
TensorFlow는 tf.GradientTape()로 자동 미분을 처리하고,
apply_gradients()를 통해 파라미터를 갱신합니다.
tr_loss_hist = []
for epoch in range(epochs):
avg_tr_loss = 0
tr_step = 0
for x_mb, y_mb in tr_dataset:
with tf.GradientTape() as tape:
tr_loss = loss_fn(model, x=x_mb, y=y_mb, training=True)
grads = tape.gradient(target=tr_loss, sources=model.variables)
opt.apply_gradients(grads_and_vars=zip(grads, model.variables))
avg_tr_loss += tr_loss
tr_step += 1
else:
avg_tr_loss /= tr_step
tr_loss_hist.append(avg_tr_loss)
in pytorch
PyTorch는 직접 .backward()로 기울기를 계산하고,
.step()으로 파라미터를 업데이트합니다.
rnn = RNN(num_classes, input_size, hidden_size, num_layers)
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(rnn.parameters(), lr=0.1)
for epoch in range(20):
outputs = rnn(inputs)
optimizer.zero_grad()
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
_, idx = outputs.max(1)
idx = idx.data.numpy()
result_str = [idx2char[c] for c in idx.squeeze()]
# .squeeze( : 텐서 크기 줄이기 -> 차원크기 1인 차원 제거
# ex) (1, 2, 3)과 같은 크기의 텐서를 (2, 3)으로 변경.