I am trying to make a LRScheduler Object for cyclical learning rate with warm restarts. I have written the code and checked it does what it is supposed to but am having difficulty making it a _LRScheduler object. The errors I get when I do
model = Mnist_Logistic()
opt=optim.SGD(model.parameters(), lr=lr)
cylical=Cyc_lr(optimizer=opt , lr_max=0.5 , lr_min=0.01 , datasize=700 , bs=64 , epochs=1)
model,opt = get_model()
loss_func(model(xb), yb)
are :
AttributeError: 'Cyc_lr' object has no attribute 'max_lr'
even when self.max_lr is defined in init and taken as input, in this case
AttributeError: 'cyc_lr' object has no attribute 'optimizer'
Even though optimiser object has been passed
I have added a last_epoch=-1 argument as it wanted that. Can someone tell me how I can create this object? I don’t get what I am doing wrong.
I looked at the pytorch classes in the docs and followed the pattern.
Here is the Cyclical LR class( get_lr is abt hairy but what formal statements is this class missing?)
from torch.optim.lr_scheduler import _LRScheduler
class Cyc_lr(_LRScheduler):
def __init__(self,optimizer,lr_max,lr_min,datasize,bs,epochs,last_epoch=-1):
"""Args:
Cyclical Learning rate with warm restart
lr_max: maximum learning rate
lr_min: minimum learning rate
datasize: total number of datapoints in train dataset (excluding val/test)
bs: batchsize trained on
epochs: number of epochs to reset learning rate
"""
super(Cyc_lr, self).__init__(optimizer, last_epoch)
self.optimizer=optimizer
self.n = 0
self.last_epoch=-1
self.batches=int(datasize/bs) # how many batches in one epoch, one batch is one lr step
self.points=epochs*self.batches # how many lr steps for one max to min
self.min_lr = lr_min
self.max_lr = lr_max
if 'self.lr' not in locals(): self.lr=self.max_lr # create self.lr initially as max lr
self.miny=self.min_lr/self.max_lr # get the ratio and take arccos to know when to stop x in cos function
self.stopx=np.arccos(self.miny) # so that cos points are created only in between the required range
self.x=np.linspace(0,self.stopx+0.5,self.points)
self.y=0.5*np.cos(self.x)+0.5
self.maxn=len(self.y)-1 # length of cos list
def get_lr(self):
self.lr=self.max_lr*self.y[self.n] # multiply lr by decreasing cos ration
self.n+=1
if self.lr<self.min_lr: # incase somethings go wrong
self.n=0
self.lr=self.max_lr
self.points=2*self.points
self.x=np.linspace(0,self.stopx+0.5,self.points)
self.y=0.5*np.cos(self.x)+0.5
if self.n==self.maxn:
self.n=0
self.lr=self.max_lr
self.points=int(1.5*self.points) # increase points by 1.5x so reaching min takes longer
self.x=np.linspace(0,self.stopx+0.5,self.points)
self.y=0.5*np.cos(self.x)+0.5
self.maxn=len(self.y)-1
return self.lr