Skip to content

Commit

Permalink
Minor fixes 2 (#7)
Browse files Browse the repository at this point in the history
* new version

* foced direct agents to save

* implemented lr scheduler for transformer
  • Loading branch information
majoma7 authored Aug 31, 2024
1 parent 34d2445 commit 7380981
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 1,140 deletions.
6 changes: 6 additions & 0 deletions ddopnew/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,12 @@
'ddopnew/meta_experiment_functions.py'),
'ddopnew.meta_experiment_functions.transfer_lag_window_to_env': ( '30_experiment_functions/meta_experiment_functions.html#transfer_lag_window_to_env',
'ddopnew/meta_experiment_functions.py')},
'ddopnew.ml_utils': { 'ddopnew.ml_utils.LRSchedulerPerStep': ( '00_utils/ml_utils.html#lrschedulerperstep',
'ddopnew/ml_utils.py'),
'ddopnew.ml_utils.LRSchedulerPerStep.__init__': ( '00_utils/ml_utils.html#lrschedulerperstep.__init__',
'ddopnew/ml_utils.py'),
'ddopnew.ml_utils.LRSchedulerPerStep.step': ( '00_utils/ml_utils.html#lrschedulerperstep.step',
'ddopnew/ml_utils.py')},
'ddopnew.obsprocessors': { 'ddopnew.obsprocessors.AddParamsToFeatures': ( '00_utils/obsprocessors.html#addparamstofeatures',
'ddopnew/obsprocessors.py'),
'ddopnew.obsprocessors.AddParamsToFeatures.__call__': ( '00_utils/obsprocessors.html#addparamstofeatures.__call__',
Expand Down
49 changes: 31 additions & 18 deletions ddopnew/agents/newsvendor/erm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import logging

from abc import ABC, abstractmethod
from typing import Union, Optional, List, Tuple, Literal
from typing import Union, Optional, List, Tuple, Literal, Callable, Dict
import numpy as np
import os
from tqdm import tqdm
Expand All @@ -21,6 +21,7 @@
from ...torch_utils.loss_functions import TorchQuantileLoss, TorchPinballLoss
from ...obsprocessors import FlattenTimeDimNumpy
from ...dataloaders.base import BaseDataLoader
from ...ml_utils import LRSchedulerPerStep

import torch

Expand All @@ -45,7 +46,7 @@ def __init__(self,
dataset_params: Optional[dict] = None, # parameters needed to convert the dataloader to a torch dataset
dataloader_params: Optional[dict] = None, # default: {"batch_size": 32, "shuffle": True}
optimizer_params: Optional[dict] = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params: Dict | None = None, # default: None. If dict, then first key is "scheduler" and the rest are the parameters
obsprocessors: Optional[List] = None, # default: []
device: str = "cpu", # "cuda" or "cpu"
agent_name: str | None = None,
Expand All @@ -66,7 +67,7 @@ def __init__(self,
self.loss_function_params=None # default
self.set_loss_function()
self.set_optimizer(optimizer_params)
self.set_learning_rate_scheduler(learning_rate_scheduler)
self.set_learning_rate_scheduler(learning_rate_scheduler_params)
self.test_batch_size = test_batch_size

super().__init__(environment_info = environment_info, obsprocessors = obsprocessors, agent_name = agent_name, receive_batch_dim = receive_batch_dim)
Expand Down Expand Up @@ -154,10 +155,19 @@ def set_optimizer(self, optimizer_params: dict): # dict with keys: optimizer, lr
else:
raise ValueError(f"Optimizer {optimizer} not supported")

def set_learning_rate_scheduler(self, learning_rate_scheduler: None = None): #
def set_learning_rate_scheduler(self, learning_rate_scheduler_params): #
""" Set learning rate scheudler (can be None) """
if learning_rate_scheduler is not None:
raise NotImplementedError("Learning rate scheduler not implemented yet")

if learning_rate_scheduler_params is not None:

params = learning_rate_scheduler_params.copy()
scheduler_type = params["scheduler"]
del params["scheduler"]
if scheduler_type == "LRSchedulerPerStep":
self.learning_rate_scheduler = LRSchedulerPerStep(self.optimizer, **params)
else:
raise ValueError(f"Learning rate scheduler {scheduler_type} not supported")

else:
self.learning_rate_scheduler = None

Expand Down Expand Up @@ -196,6 +206,9 @@ def fit_epoch(self):

loss.backward()
self.optimizer.step()

if self.learning_rate_scheduler is not None:
self.learning_rate_scheduler.step()

total_loss += loss.item()

Expand Down Expand Up @@ -325,7 +338,7 @@ def __init__(self,
input_shape: Tuple,
output_shape: Tuple,
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params = None, # TODO: add base class for learning rate scheduler for typing
dataset_params: dict | None = None, # parameters needed to convert the dataloader to a torch dataset
dataloader_params: dict | None = None, # default: {"batch_size": 32, "shuffle": True}
obsprocessors: list | None = None, # default: []
Expand All @@ -352,7 +365,7 @@ def __init__(self,
input_shape=input_shape,
output_shape=output_shape,
optimizer_params=optimizer_params,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,
dataset_params=dataset_params,
dataloader_params=dataloader_params,
obsprocessors=obsprocessors,
Expand Down Expand Up @@ -399,7 +412,7 @@ def __init__(self,
input_shape: Tuple,
output_shape: Tuple,
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params = None, # TODO: add base class for learning rate scheduler for typing
model_params: dict | None = None, # default: {"relu_output": False}
dataset_params: dict | None = None, # parameters needed to convert the dataloader to a torch dataset
dataloader_params: dict | None = None, # default: {"batch_size": 32, "shuffle": True}
Expand All @@ -426,7 +439,7 @@ def __init__(self,
input_shape=input_shape,
output_shape=output_shape,
optimizer_params=optimizer_params,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,
dataloader_params=dataloader_params,
dataset_params=dataset_params,
obsprocessors=obsprocessors,
Expand Down Expand Up @@ -464,7 +477,7 @@ def __init__(self,
co: np.ndarray | Parameter,
input_shape: Tuple,
output_shape: Tuple,
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params: Dict | None = None,

# parameters in yaml file
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
Expand Down Expand Up @@ -498,7 +511,7 @@ def __init__(self,
input_shape=input_shape,
output_shape=output_shape,
optimizer_params=optimizer_params,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,
dataloader_params=dataloader_params,
dataset_params=dataset_params,
obsprocessors=obsprocessors,
Expand Down Expand Up @@ -559,7 +572,7 @@ def __init__(self,
input_shape: Tuple,
output_shape: Tuple,
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params = None, # TODO: add base class for learning rate scheduler for typing
model_params: dict | None = None, # default: {"relu_output": False}
dataset_params: dict | None = None, # parameters needed to convert the dataloader to a torch dataset
dataloader_params: dict | None = None, # default: {"batch_size": 32, "shuffle": True}
Expand All @@ -581,7 +594,7 @@ def __init__(self,
input_shape=input_shape,
output_shape=output_shape,
optimizer_params=optimizer_params,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,
model_params=model_params,
dataloader_params=dataloader_params,
obsprocessors=obsprocessors,
Expand Down Expand Up @@ -666,7 +679,7 @@ def __init__(self,
co: np.ndarray | Parameter,
input_shape: Tuple,
output_shape: Tuple,
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params: Dict | None = None,

# parameters in yaml file
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
Expand Down Expand Up @@ -708,7 +721,7 @@ def __init__(self,
input_shape=input_shape,
output_shape=output_shape,
optimizer_params=optimizer_params,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,
dataset_params=dataset_params,
dataloader_params=dataloader_params,
obsprocessors=obsprocessors,
Expand Down Expand Up @@ -750,7 +763,7 @@ def __init__(self,
co: np.ndarray | Parameter,
input_shape: Tuple,
output_shape: Tuple,
learning_rate_scheduler = None, # TODO: add base class for learning rate scheduler for typing
learning_rate_scheduler_params: Dict | None = None,

# parameters in yaml file
optimizer_params: dict | None = None, # default: {"optimizer": "Adam", "lr": 0.01, "weight_decay": 0.0}
Expand All @@ -775,7 +788,7 @@ def __init__(self,
co=co,
input_shape=input_shape,
output_shape=output_shape,
learning_rate_scheduler=learning_rate_scheduler,
learning_rate_scheduler_params=learning_rate_scheduler_params,

optimizer_params=optimizer_params,
model_params=model_params,
Expand Down
39 changes: 39 additions & 0 deletions ddopnew/ml_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_utils/40_ml_utils.ipynb.

# %% auto 0
__all__ = ['LRSchedulerPerStep']

# %% ../nbs/00_utils/40_ml_utils.ipynb 3
from typing import List, Tuple, Literal
import torch

# %% ../nbs/00_utils/40_ml_utils.ipynb 4
class LRSchedulerPerStep():
"""
Learning rate scheduler from Attention is all you need paper (https://arxiv.org/abs/1706.03762)
One ajustment: Added base LR as tunable parameter rather than setting it automated based on model dimension
"""

def __init__(self,
optimizer: torch.optim.Optimizer, # Optimizer to adjust learning rate for
base_learning_rate: float = 0.0001,
warmup: int =4000):

# Ensure optimizer is a PyTorch optimizer
if not isinstance(optimizer, torch.optim.Optimizer):
raise ValueError('Optimizer must be a PyTorch optimizer')

self.optimizer = optimizer
self.basic = base_learning_rate
self.warm = warmup**-1.5
self.scaling_factor = 1/warmup**-0.5 # ensures that the peak realtive to the base lr is always 1

self.step_num = 0
self.step()

def step(self):
self.step_num += 1
lr = self.basic * self.scaling_factor * min(self.step_num**-0.5, self.step_num*self.warm)

for param_group in self.optimizer.param_groups:
param_group['lr'] = lr
116 changes: 116 additions & 0 deletions nbs/00_utils/40_ml_utils.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ML utils\n",
"\n",
"> Some helper functions for machine learning tasks."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| default_exp ml_utils"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| hide\n",
"from nbdev.showdoc import *"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"\n",
"from typing import List, Tuple, Literal\n",
"import torch"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"\n",
"class LRSchedulerPerStep():\n",
" \"\"\"\n",
" Learning rate scheduler from Attention is all you need paper (https://arxiv.org/abs/1706.03762)\n",
" One ajustment: Added base LR as tunable parameter rather than setting it automated based on model dimension\n",
" \"\"\"\n",
" \n",
" def __init__(self,\n",
" optimizer: torch.optim.Optimizer, # Optimizer to adjust learning rate for\n",
" base_learning_rate: float = 0.0001,\n",
" warmup: int =4000):\n",
"\n",
" # Ensure optimizer is a PyTorch optimizer\n",
" if not isinstance(optimizer, torch.optim.Optimizer):\n",
" raise ValueError('Optimizer must be a PyTorch optimizer')\n",
" \n",
" self.optimizer = optimizer\n",
" self.basic = base_learning_rate\n",
" self.warm = warmup**-1.5\n",
" self.scaling_factor = 1/warmup**-0.5 # ensures that the peak realtive to the base lr is always 1\n",
"\n",
" self.step_num = 0 \n",
" self.step()\n",
" \n",
" def step(self):\n",
" self.step_num += 1\n",
" lr = self.basic * self.scaling_factor * min(self.step_num**-0.5, self.step_num*self.warm)\n",
" \n",
" for param_group in self.optimizer.param_groups:\n",
" param_group['lr'] = lr"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| hide\n",
"import nbdev; nbdev.nbdev_export()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "python3",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading

0 comments on commit 7380981

Please sign in to comment.