Colab의 기본모드는 참 애매합니다.
안되는 건아니지만 된다고 하기에도 참 뭐하고.
일단 그래서 PRO를 질러 봤습니다.
마찬가지로 참 애매합니다.
런타임 구성을 GPU로 바꿨지만 역시 되는 것도 안되는 것도 아닌
- 참 본론으로 들어가기전에 한국에서는 Colab결재가 안됩니다.
다른 이유 때문은 아니고 우편번호를 입력하라고 나오는데 한국 우편번호는 밴입니다.
그래서 사람들은 애플 주소나 메타 또는 테슬라 주소를 검색해서 우편번호를 가져옵니다.
아마도 우리나라 가입자 70%는 애플 직원일겁니다. -
그래서 PRO+를 질러 봤습니다.
속은 시원합니다.
이제 뭔가 되는 느낌입니다.
하지만 여기서 느낀 점이 있어서 이 글을 쓰게 되었습니다.
(쥬피터)노트북 환경의 특징은 실행하고자 하는 소스 단위를 셀이라는 단위로 나누어 실행이 가능합니다.
즉 덩어리 소스가 아닌 소형의 소스로 만든 다음 나눠서 실행이 가능합니다.
Colab 유료버젼 사용시 주의 사항을 요약하고 전략을 알려 드립니다.
1. 소스를 세세히 나눠라.
# %%
%pip install kaleido
# %%
from psutil import virtual_memory
ram_gb = virtual_memory().total / 1e9
print('Your runtime has {:.1f} gigabytes of available RAM\n'.format(ram_gb))
if ram_gb < 20:
print('Not using a high-RAM runtime')
else:
print('You are using a high-RAM runtime!')
# %%
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.init as init
import torchvision
import torch.nn.functional as F
# https://pytorch.org/docs/stable/torchvision/datasets.html
# 파이토치에서는 torchvision.datasets에 MNIST 등의 다양한 데이터를 사용하기 용이하게 정리해놨습니다.
# 이를 사용하면 데이터를 따로 학습에 맞게 정리하거나 하지 않아도 바로 사용이 가능합니다.
import torchvision.datasets as dset
# https://pytorch.org/docs/stable/torchvision/transforms.html?highlight=transforms
# torchvision.transforms에는 이미지 데이터를 자르거나 확대 및 다양하게 변형시키는 함수들이 구현되어 있습니다.
import torchvision.transforms as transforms
# https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader
# DataLoader는 전처리가 끝난 데이터들을 지정한 배치 크기에 맞게 모아서 전달해주는 역할을 합니다.
from torch.utils.data import DataLoader
import pandas as pd
import numpy as np
import matplotlib.pyplot as pltx
import plotly.graph_objects as go
import plotly.subplots as ms
import plotly.express as px
import plotly as plt
import pandas as pd
import numpy as np
import time
from PIL import Image
import io
import os.path as path
import math
# %%
batch_size = 2000
learning_rate = 0.0005
num_epoch = 1000
data_size = 100
action_kind = 4
screen_height = 50
screen_width = 70
qsize = 512
# %%
# %%
class Account():
def __init__(self, df, origin) -> None:
self.BASIC_FEES = 0.0005
self.hold_score = 0
self.byu_score = 0
self.sell_score = 0
self.orgin_money = origin
self.money = origin
self.balance = origin
self.unit = 0
self.buy_index = 0
self.max_rate = 0
self.df = df
self.rate = 0
self.old_rate = 0
self.bak_unit = 0
self.bak_balance = 0
def reset(self):
self.balance = self.orgin_money
self.money = self.orgin_money
self.old_rate = 0
self.unit = 0
self.rate = 0
self.buy_index = 0
def select(self, action:int):
ret_action = 0
if self.unit > 0 :
ret_action = 0 if action == 1 else action
else:
ret_action = 0 if action == 2 else action
return ret_action
def exec_action(self, action, idx):
real_action = self.select(action)
if real_action == 1:
return self.unit_buy(idx), real_action
elif real_action == 2:
return self.unit_sell(idx), real_action
else:
return self.unit_hold(idx), real_action
def unit_buy(self, index):
self.back_up()
buy_balance = self.balance
self.buy_index = index
self.old_rate = self.rate
while True:
buy_unit = buy_balance / self.df.loc[index, 'close']
amount = (buy_unit * self.df.loc[index, 'close']) * self.BASIC_FEES + buy_unit * self.df.loc[index, 'close']
if self.balance < amount :
buy_balance -= self.balance * 0.0001
else:
self.balance -= amount
self.unit = buy_unit
self.rate = ((self.unit * self.df.loc[index, 'close'] + self.balance) - self.orgin_money) * 100 / self.orgin_money
# if index%50 == 0 : print("buy index[{}]hold unit[{:,.6f}] remind money[{:,.6f}] rate[{:,.8f}] expected[{:,.8f}]".format(index, self.unit, self.balance, self.rate, (self.unit * self.df.loc[index, 'close'] + self.balance)))
print("buy index[{}]hold unit[{:,.6f}] remind money[{:,.6f}] rate[{:,.8f}] expected[{:,.8f}]".format(index, self.unit, self.balance, self.rate, (self.unit * self.df.loc[index, 'close'] + self.balance)))
break
return self.rate
def unit_sell(self, index):
self.back_up()
self.old_rate = self.rate
sell_balance = self.unit * self.df.loc[index, 'close'] - (self.unit * self.df.loc[index, 'close']) * self.BASIC_FEES
self.balance += sell_balance
self.unit = 0
self.rate = ((self.unit * self.df.loc[index, 'close'] + self.balance) - self.orgin_money) * 100 / self.orgin_money
# if index%50 == 0 : print("sell index[{}]hold unit[{:,.6f}] remind money[{:,.6f}] rate[{:,.8f}] expected[{:,.8f}]".format(index, self.unit, self.balance, self.rate, (self.unit * self.df.loc[index, 'close'] + self.balance)))
print("sell index[{}]hold unit[{:,.6f}] remind money[{:,.6f}] rate[{:,.8f}] expected[{:,.8f}]".format(index, self.unit, self.balance, self.rate, (self.unit * self.df.loc[index, 'close'] + self.balance)))
self.money = self.balance
self.max_rate = 0
return self.rate
def unit_hold(self, index):
self.old_rate = self.rate
self.rate = ((self.unit * self.df.loc[index, 'close'] + self.balance) - self.orgin_money) * 100 / self.orgin_money
# print("index[{}]hold unit[{:,.6f}] remind money[{:,.6f}] rate[{:,.8f}] expected[{:,.8f}]".format(index, self.unit, self.balance, self.rate, (self.unit * self.df.loc[index, 'close'] + self.balance)))
return self.rate
def get_newaction(self, index):
if self.unit > 0:
hold_rate = ((self.unit * self.df.loc[index, "sma3"] + self.balance) - self.orgin_money) * 100 / self.orgin_money
sell_rate = ((self.unit * self.df.loc[index, "close"] + self.balance) - self.orgin_money) * 100 / self.orgin_money
return 0 if hold_rate > sell_rate else 2
else:
buy_balance = self.balance
self.buy_index = index
self.old_rate = self.rate
while True:
buy_unit = buy_balance / self.df.loc[index, 'close']
amount = (buy_unit * self.df.loc[index, 'close']) * self.BASIC_FEES + buy_unit * self.df.loc[index, 'close']
if self.balance < amount :
buy_balance -= self.balance * 0.0001
else:
self.balance -= amount
self.unit = buy_unit
buy_rate = ((self.unit * self.df.loc[index, 'close'] + self.balance) - self.orgin_money) * 100 / self.orgin_money
break
hold_rate = (self.balance - self.orgin_money) * 100 / self.orgin_money
return 0 if hold_rate > buy_rate else 1
def back_up(self):
self.bak_balance = self.balance
self.bak_unit = self.unit
def back_ward(self):
self.balance = self.bak_balance
self.unit = self.bak_unit
def is_bankrupt(self):
return (self.money < 10000)
# %%
def get_chart(df, idx, max_data:int=300, i_w:int=140, i_h:int=100):
ndf = df.head(idx - start_idx).tail(max_data)
ndf.reset_index(drop=True, inplace=True)
# print(ndf)
candle = go.Candlestick(x=ndf.index,open=ndf['open'],high=ndf['high'],low=ndf['low'],close=ndf['close'], increasing_line_color = 'red',decreasing_line_color = 'blue', showlegend=False)
upper = go.Scatter(x=ndf.index, y=ndf['upper'], line=dict(color='red', width=2), name='upper', showlegend=False)
ma20 = go.Scatter(x=ndf.index, y=ndf['ma20'], line=dict(color='black', width=2), name='ma20', showlegend=False)
lower = go.Scatter(x=ndf.index, y=ndf['lower'], line=dict(color='blue', width=2), name='lower', showlegend=False)
volume = go.Bar(x=ndf.index, y=ndf['volume'], marker_color='red', name='volume', showlegend=False)
MACD = go.Scatter(x=ndf.index, y=ndf['macd'], line=dict(color='blue', width=2), name='MACD', legendgroup='group2', legendgrouptitle_text='MACD')
MACD_Signal = go.Scatter(x=ndf.index, y=ndf['signal'], line=dict(dash='dashdot', color='green', width=2), name='MACD_Signal')
MACD_Oscil = go.Bar(x=ndf.index, y=ndf['flag'], marker_color='purple', name='MACD_Oscil')
fast_k = go.Scatter(x=ndf.index, y=ndf['fast_k'], line=dict(color='skyblue', width=2), name='fast_k', legendgroup='group3', legendgrouptitle_text='%K %D')
slow_d = go.Scatter(x=ndf.index, y=ndf['slow_d'], line=dict(dash='dashdot', color='black', width=2), name='slow_d')
PB = go.Scatter(x=ndf.index, y=ndf['PB']*100, line=dict(color='blue', width=2), name='PB', legendgroup='group4', legendgrouptitle_text='PB, MFI')
MFI10 = go.Scatter(x=ndf.index, y=ndf['MFI10'], line=dict(dash='dashdot', color='green', width=2), name='MFI10')
RSI = go.Scatter(x=ndf.index, y=ndf['rsi14'], line=dict(color='red', width=2), name='RSI', legendgroup='group5', legendgrouptitle_text='RSI')
# 스타일
fig = ms.make_subplots(rows=5, cols=2, specs=[[{'rowspan':4},{}],[None,{}],[None,{}],[None,{}],[{},{}]], shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01)
fig.add_trace(candle,row=1,col=1)
fig.add_trace(upper,row=1,col=1)
fig.add_trace(ma20,row=1,col=1)
fig.add_trace(lower,row=1,col=1)
fig.add_trace(volume,row=5,col=1)
fig.add_trace(candle,row=1,col=2)
fig.add_trace(upper,row=1,col=2)
fig.add_trace(ma20,row=1,col=2)
fig.add_trace(lower,row=1,col=2)
fig.add_trace(MACD,row=2,col=2)
fig.add_trace(MACD_Signal,row=2,col=2)
fig.add_trace(MACD_Oscil,row=2,col=2)
fig.add_trace(fast_k,row=3,col=2)
fig.add_trace(slow_d,row=3,col=2)
fig.add_trace(PB,row=4,col=2)
fig.add_trace(MFI10,row=4,col=2)
fig.add_trace(RSI,row=5,col=2)
# 추세추종
# trend_fol = 0
# trend_refol = 0
# for i in ndf.index:
# if ndf['PB'][i] > 0.8 and ndf['MFI10'][i] > 80:
# trend_fol = go.Scatter(x=[ndf.index[i]], y=[ndf['close'][i]], marker_color='orange', marker_size=20, marker_symbol='triangle-up', opacity=0.7, showlegend=False)
# fig.add_trace(trend_fol,row=1,col=1)
# elif ndf['PB'][i] < 0.2 and ndf['MFI10'][i] < 20:
# trend_fol = go.Scatter(x=[ndf.index[i]], y=[ndf['close'][i]], marker_color='darkblue', marker_size=20, marker_symbol='triangle-down', opacity=0.7, showlegend=False)
# fig.add_trace(trend_fol,row=1,col=1)
# 역추세추종
# for i in ndf.index:
# if ndf['PB'][i] < 0.05 and ndf['IIP21'][i] > 0:
# trend_refol = go.Scatter(x=[ndf.index[i]], y=[ndf['close'][i]], marker_color='purple', marker_size=20, marker_symbol='triangle-up', opacity=0.7, showlegend=False) #보라
# fig.add_trace(trend_refol,row=1,col=1)
# elif df['PB'][i] > 0.95 and ndf['IIP21'][i] < 0:
# trend_refol = go.Scatter(x=[ndf.index[i]], y=[ndf['close'][i]], marker_color='skyblue', marker_size=20, marker_symbol='triangle-down', opacity=0.7, showlegend=False) #하늘
# fig.add_trace(trend_refol,row=1,col=1)
# fig.add_trace(trend_fol,row=1,col=1)
# 추세추총전략을 통해 캔들차트에 표시합니다.
# fig.add_trace(trend_refol,row=1,col=1)
# 역추세 전략을 통해 캔들차트에 표시합니다.
# fig.update_layout(autosize=True, xaxis1_rangeslider_visible=False, xaxis2_rangeslider_visible=False, margin=dict(l=50,r=50,t=50,b=50), template='seaborn', title=f'({ticker})의 날짜: ETH [추세추종전략:오↑파↓] [역추세전략:보↑하↓]')
# fig.update_xaxes(tickformat='%y년%m월%d일', zeroline=True, zerolinewidth=1, zerolinecolor='black', showgrid=True, gridwidth=2, gridcolor='lightgray', showline=True,linewidth=2, linecolor='black', mirror=True)
# fig.update_yaxes(tickformat=',d', zeroline=True, zerolinewidth=1, zerolinecolor='black', showgrid=True, gridwidth=2, gridcolor='lightgray',showline=True,linewidth=2, linecolor='black', mirror=True)
# fig.update_traces(xhoverformat='%y년%m월%d일')
# size = len(img)
# img = plt.io.to_image(fig, format='png')
# canvas = FigureCanvasBase(fig)
# img = Image.frombytes(mode='RGB', size=(700, 500), data=fig.to_image().to, decoder_name='raw')
# img = Image.frombytes('RGBA', (700, 500), plt.io.to_image(fig, format='png'), 'raw')
# img = Image.fromarray('RGBA', (700, 500), np.array(plt.io.to_image(fig, format='png')), 'raw')
# img = Image.fromarray(np.array(plt.io.to_image(fig, format='png')), 'RGB')
# img = Image.fromarray(np.array(plt.io.to_image(fig, format='png')), 'L')
# img = Image.open(io.BytesIO(plt.io.to_image(fig, format='png', width=140, height=100)))
# img = Image.open(io.BytesIO(plt.io.to_image(fig, format='png', width=700, height=500)))
img = Image.open(io.BytesIO(plt.io.to_image(fig, format='png')))
# print(img)
img.convert("RGB")
# img.show()
# print(img)
img.thumbnail((i_h, i_w), Image.LANCZOS)
# print(img)
# img = Image.Image(img, 'RGB')
# img.show()
return img
# %%
# %%
class DQN(nn.Module):
def __init__(self, h, w, outputs, qsize):
super(DQN, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(4, h*w, kernel_size=5, stride=5),
nn.BatchNorm2d(h*w),
nn.ReLU()
)
self.conv2 = nn.Sequential(
nn.MaxPool2d(kernel_size=2,stride=2),
nn.Conv2d(h*w, 4 * qsize, kernel_size=(3,5), stride=5),
nn.BatchNorm2d(4 * qsize),
nn.ReLU()
)
self.conv3 = nn.Sequential(
nn.Conv2d(4 * qsize, qsize, kernel_size=1, stride=5),
nn.BatchNorm2d(qsize),
nn.ReLU()
)
self.head = nn.Sequential(
nn.Dropout(0.25),
# nn.Linear(qsize, qsize*2),
# nn.ReLU(),
# nn.Linear(qsize*2, qsize*2),
# nn.LeakyReLU(),
# nn.Linear(qsize*2, qsize*4),
# nn.LeakyReLU(),
# nn.Linear(qsize*4, qsize*8),
# nn.LeakyReLU(),
# nn.Dropout(0.25),
# nn.Linear(qsize*8, qsize*4),
# nn.LeakyReLU(),
# nn.Linear(qsize*4, qsize),
# nn.LeakyReLU(),
nn.Linear(qsize, outputs),
# nn.ReLU(),
# nn.Softmax(dim=1)
)
# Called with either one element to determine next action, or a batch
# during optimization. Returns tensor([[left0exp,right0exp]...]).
def forward(self, x):
x = self.conv1(x)
# print("x1------->", x.size())
# x = F.dropout2d(x)
x = self.conv2(x)
# print("x2------->", x.size())
# x = F.dropout2d(x)
x = self.conv3(x)
# print("x3------->", x.size())
x = x.view(x.size(0), -1)
# print("x6------->", x.size())
x = self.head(x)
# print("x7------->", x.size())
return x
# %%
from google.colab import drive
import os
drive.mount('/content/drive')
os.chdir("/content/drive/MyDrive/dqn3_test")
# %%
def select_action(df, idx):
action = ((df.loc[idx, "close"] - df.loc[idx, "closemin"]) * (action_kind-1) // (df.loc[idx, "closemax"] - df.loc[idx, "closemin"]))
action = 1 if action == 0 else ((action_kind - 2) if action == (action_kind - 1) else action)
action = 0 if df.loc[idx, "low"] <= df.loc[idx, "closemin"] else action
action = (action_kind-1) if df.loc[idx, "high"] >= df.loc[idx, "closemax"] else action
# action = action if action <=0 else 1
# action = action if action >= 2 else 1
action = int(action)
# print("idx{0:d} action[{1}] deg[{2}] close:{3} closemin:{4} closemax:{5}".format(idx, action, df.loc[idx, "sma20deg"], df.loc[idx, "close"], df.loc[idx, "closemin"], df.loc[idx, "closemax"]))
return action
# %%
df = pd.read_csv("data_all.dat")
start_idx = df.index[0]
print("start_idx[{}]".format(start_idx))
# %%
converter = torchvision.transforms.ToTensor()
# %%
# gpu가 사용 가능한 경우에는 device를 gpu로 설정하고 불가능하면 cpu로 설정합니다.
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# %%
# 모델을 지정한 장치로 올립니다.
model = DQN(screen_height, screen_width, action_kind, qsize=qsize).to(device)
if path.exists("train_dqn_{0:02d}_{1}_{2:04d}.pt".format(action_kind, device, qsize)):
model.load_state_dict(torch.load("train_dqn_{0:02d}_{1}_{2:04d}.pt".format(action_kind,device,qsize)))
model.eval()
loss_func = nn.CrossEntropyLoss()
# 최적화함수로는 Adam을 사용합니다.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
optimizer.zero_grad()
# scheduler
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer=optimizer, mode='min')
# %%
charts = []
charts = []
# files = os.listdir(".")
# for filename in files :
for i in range(39):
filename = "chart_all_{0:04d}.dmp".format(i)
if filename.endswith(".dmp"):
for j in range(10):
tmp = torch.load(filename)
for item in tmp:
charts.append(item)
print("charts:", len(charts))
#%%
stat = None
if stat == None:
stat = model.state_dict()
train_loader = DataLoader(charts,batch_size=batch_size, shuffle=True,num_workers=2,drop_last=True)
test_loader = DataLoader(charts,batch_size=batch_size, shuffle=False,num_workers=2,drop_last=True)
loss_arr =[]
model.load_state_dict(stat)
model.train()
loss_func.train()
lr_step = 0
for i in range(num_epoch):
oldloss = None
for j,[image,label] in enumerate(train_loader):
x = image.to(device).squeeze(1)
y = label
y = y.type(torch.LongTensor).to(device)
# print("j[{0}]".format(j), x , y)
output = model.forward(x)
# print("output:", output)
loss = loss_func(output,y)
if oldloss == None:
oldloss = loss.cpu().detach().numpy()
loss.backward()
# optimizer.zero_grad()
optimizer.step()
if j % 300 == 0:
print(loss.cpu().detach().numpy())
loss_arr.append(loss.cpu().detach().numpy())
stat = model.state_dict()
torch.save(stat,"train_dqn_{0:02d}_{1}_{2:04d}.pt".format(action_kind, device, qsize))
stat = model.state_dict()
torch.save(stat,"train_dqn_{0:02d}_{1}_{2:04d}.pt".format(action_kind, device, qsize))
lr_step = oldloss - loss.cpu().detach().numpy()
scheduler.step(lr_step)
pltx.plot(loss_arr)
pltx.show()
#%%
# 맞은 개수, 전체 개수를 저장할 변수를 지정합니다.
correct = 0
total = 0.000000000001
model.eval()
loss_func.eval()
# 인퍼런스 모드를 위해 no_grad 해줍니다.
with torch.no_grad():
# 테스트로더에서 이미지와 정답을 불러옵니다.
for image,label in test_loader:
# 두 데이터 모두 장치에 올립니다.
x = image.to(device).squeeze(1)
y = label.to(device)
# 모델에 데이터를 넣고 결과값을 얻습니다.
output = model.forward(x)
# https://pytorch.org/docs/stable/torch.html?highlight=max#torch.max
# torch.max를 이용해 최대 값 및 최대값 인덱스를 뽑아냅니다.
# 여기서는 최대값은 필요없기 때문에 인덱스만 사용합니다.
_,output_index = torch.max(output,1)
# 전체 개수는 라벨의 개수로 더해줍니다.
# 전체 개수를 알고 있음에도 이렇게 하는 이유는 batch_size, drop_last의 영향으로 몇몇 데이터가 잘릴수도 있기 때문입니다.
total += label.size(0)
# 모델의 결과의 최대값 인덱스와 라벨이 일치하는 개수를 correct에 더해줍니다.
correct += (output_index == y).sum().float()
# 테스트 데이터 전체에 대해 위의 작업을 시행한 후 정확도를 구해줍니다.
print("Accuracy of Test Data: {}%".format(100*correct/total))
#@title
model.eval()
account = Account(df, 50000000)
account.reset()
with torch.no_grad():
tot = 0.0000000000001
corr = 0.0
predict_arr = []
for idy in df.index:
x = get_chart(df, idy, data_size, i_w = screen_width, i_h = screen_height)
x = converter(x).unsqueeze(0).to(device).squeeze(1)
output = model.forward(x)
_,action = torch.max(output,1)
# print("action:", action)
action = action.cpu().numpy()[0]
# print("action:", action)
predict_arr[action] += 1
sel_act = select_action(df, idy)
tot += 1 if sel_act in [0, action_kind-1] or action in [0, action_kind-1] else 0
corr += 1 if (sel_act in [0, action_kind-1] or action in [0, action_kind-1]) and sel_act == action else 0
reward, real_action = account.exec_action(2 if action == (action_kind - 1) else (1 if action == 0 else 0) , idy)
if idy % 100 == 0:
print("progress {0:.2f}".format(idy * 100 / df.index.max()))
print("idy:%d action[%d:%d] price [%.4f] unit[%.4f] agent rate:%.05f remind money:%.02f accuracy:%.02f"
% (idy, sel_act, action, df.loc[idy, 'close'], account.unit, account.rate, account.balance + account.unit * df.loc[idy, 'close'], 100*corr/tot))
print("prediction count")
for act in predict_arr:
print("action{0:02d} ==> {1:d}".format(act, predict_arr[act]))
Colab을 사용하기 위해서는 구글 라이브러리 실행부가 있어야 합니다.
그런 부분을 될 수 있으면 위로 올립니다.
선언부(import)가 있는 부분 중 소스에 필수 적인것은 한곳에 모으고 구글 라이브러리에서만 사용하는 것은 구글 라이브러리가 있는 곳에 모읍니다.
2. GPU사용부와 비GPU부분을 확실히 나눈다.
GPU사용부는 확습과 테스트 두곳 뿐이다.
모델 선언부도 당연히 아니므로 그 부분도 분리 한다.
3. 일반 메모리를 사용하는 데이터 처리부분은 데이터 사이즈를 몇KB단위로 나누어 torch.save함수를 이용하여 파일로 저장한다.
마치 알집을 번호 붙여서 나누는 것 처럼.
그리고 사용할 때 한 배열에 불러서 사용한다.
학습용 데이터는 제각각에 생각보다 시간이 많이 들고 데이터 사이즈가 어느 이상 크지면 구글의 컴퓨팅 단위는 순식간에 0이 되어 버립니다.
PRO+를 구매해도 하루면 땡이죠.
그리고는 경고는 떠지만 추가 구입할 방법이 없습니다.
(완전히 0이 되면 비구독으로 구매가 가능합니다.)
즉 메모리 사용량이 넘치면 프로세스가 느려지면서 돈이 공중으로 금방 사라집니다.
한달 정도는 쓸거라는 생각은 한 순간에 희망사항이 됩니다.
그래서 아주 작은 단위로 데이터를 메모리로 로딩한 다음 torch.save 와 torch.load를 활용해서 파일로 저장하고
번호를 붙입니다.
메모리에 올리는 것도 반대로 합니다.
작은 파일을 만드는 작은 로컬 컴에서 해야합니다.
이 작업은 구글 Colab에서 하다가는 돈 7만원은 금방 날라 갑니다.
로컬 피씨에서 해서 구글 드라이브에 올리면 됩니다.
4. 학습을 제외한 나머지는 로컬에서 실행합니다.
그렇게 할려면 최대한 셀을 나누어야 합니다.
로컬에도 GPU환경이 있다면 모델 수정에만 Colab을 사용합니다.
이 비용도 상당합니다.
5. tip으로 어느 정도 loss가 줄면 학습 부분만 계속 해서 실행하면서 계속 loss를 내릴 수 있습니다.
전체 소스를 다시 로딩한다면 상당한 시간이 걸릴 수 있지만
중간에 중간 cell 단위로 프로그램을 실행할 수 있으므로 leanring rate를 줄이고 실행한
다음 학습률을 실행하면서 훨씬 빠르게 학습이 가능 합니다.
그리고 모델을 저장하는 부분도 cell을 분리 한다면
어느 정도 학습이 이루어 지고 모델을 저장하는 부분을 따로 실행하여 모델을 임시 저장한 다음
다시 학습을 하고 또 테스트를 진행한 다음 다시 학습을 할 수 도 있습니다.
결론 : Colab PRO와 PRO+는 생각보다 비쌉니다.
이유는 단위가 컴퓨팅 단위로 고용량 메모리나 프리미엄 GPU를 사용하려면 그 만큼의 비용이 추가로 듭니다.
그러므로 데이터와 비GPU영역의 작업을 최대한 효과적으로 해서 PRO버젼을 사용시 메모리로 데이타를 옮기는 작업을 최소화해야 합니다.
그렇지 않으면
"한시간 후에 구매용량이 부족하여 작업이 종료되며 종료시 런타임이 재작동하여 기존 작업을 잃을 수 있다"
라는 개쓰레기 같은 팝업과 결재가 불가능하여 돈을 추가로 내려고 해도 낼 수 없다는 신기한 경험을 하게 됩니다.
아니 내가 돈을 내겠다는데 안된다고 ?