Initial Commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
__pycache__
|
||||||
|
.devcontainer
|
||||||
5
Dockerfile
Normal file
5
Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
FROM pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime
|
||||||
|
|
||||||
|
COPY requirements.txt /tmp/requirements.txt
|
||||||
|
|
||||||
|
RUN pip install -r /tmp/requirements.txt
|
||||||
BIN
Reports/November/MP2324_verslag1_Mylle_Victor.pdf
Normal file
BIN
Reports/November/MP2324_verslag1_Mylle_Victor.pdf
Normal file
Binary file not shown.
BIN
Reports/November/ea-en.pdf
Normal file
BIN
Reports/November/ea-en.pdf
Normal file
Binary file not shown.
BIN
Reports/November/ea-nl.pdf
Normal file
BIN
Reports/November/ea-nl.pdf
Normal file
Binary file not shown.
BIN
Reports/November/eb-en.pdf
Normal file
BIN
Reports/November/eb-en.pdf
Normal file
Binary file not shown.
185
Reports/November/ugent-doc.cls
Normal file
185
Reports/November/ugent-doc.cls
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%
|
||||||
|
% Ghent University document class
|
||||||
|
% Created by DF Benoit, December 15, 2022
|
||||||
|
%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
\NeedsTeXFormat{LaTeX2e}
|
||||||
|
\ProvidesClass{ugent-doc}
|
||||||
|
|
||||||
|
% Required packages
|
||||||
|
\RequirePackage{kvoptions}
|
||||||
|
\RequirePackage{geometry}
|
||||||
|
\RequirePackage{calc}
|
||||||
|
\RequirePackage{graphicx}
|
||||||
|
\RequirePackage{xcolor}
|
||||||
|
|
||||||
|
% ugent-doc specific options (kvoptions)
|
||||||
|
\SetupKeyvalOptions{family=ugd,prefix=ugd@} %UGentArticle
|
||||||
|
|
||||||
|
% Declare the class specific options
|
||||||
|
\DeclareStringOption[eb]{faculty}[eb]
|
||||||
|
\DeclareStringOption[en]{language}[en]
|
||||||
|
\DeclareStringOption[article]{doctype}[article]
|
||||||
|
\DeclareBoolOption[true]{sftitles} % Default: true
|
||||||
|
\ProcessKeyvalOptions*
|
||||||
|
|
||||||
|
% Pass options not specified above to the parent class
|
||||||
|
% \@unusedoptionlist is a macro in kvoptions
|
||||||
|
\LoadClass[\@unusedoptionlist]{\ugd@doctype}
|
||||||
|
|
||||||
|
% All sections, subsections and subsubsections in sans serif
|
||||||
|
\ifugd@sftitles
|
||||||
|
\RequirePackage[sf]{titlesec}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Define UGent colors
|
||||||
|
%= = = = = = = = = = =
|
||||||
|
% Base colors
|
||||||
|
% UGent blue
|
||||||
|
\definecolor{ugentblue}{RGB}{30,100,200}
|
||||||
|
% UGent yellow
|
||||||
|
\definecolor{ugentyellow}{RGB}{255,210,0}
|
||||||
|
% UGent white
|
||||||
|
\definecolor{ugentwhite}{RGB}{255,255,255}
|
||||||
|
% UGent black
|
||||||
|
\definecolor{ugentblack}{RGB}{0,0,0}
|
||||||
|
|
||||||
|
% Faculty specific colors
|
||||||
|
% Faculty of Literature & Philosophy
|
||||||
|
\definecolor{ugent-lw}{RGB}{241,164,43}
|
||||||
|
% Faculty of Law
|
||||||
|
\definecolor{ugent-re}{RGB}{220,78,40}
|
||||||
|
% Faculty of Science
|
||||||
|
\definecolor{ugent-we}{RGB}{45,140,168}
|
||||||
|
% Faculty of Medicine and Health Sciences
|
||||||
|
\definecolor{ugent-ge}{RGB}{232,94,113}
|
||||||
|
% Faculty of Engineering and Architecture
|
||||||
|
\definecolor{ugent-ea}{RGB}{139,190,232}
|
||||||
|
% Faculty of Economics and Business Administration
|
||||||
|
\definecolor{ugent-eb}{RGB}{174,176,80}
|
||||||
|
% Faculty of Veterinary Medicine
|
||||||
|
\definecolor{ugent-di}{RGB}{130,84,145}
|
||||||
|
% Faculty of Psychology and Educational Sciences
|
||||||
|
\definecolor{ugent-pp}{RGB}{251,126,58}
|
||||||
|
% Faculty of Bioscience Engineering
|
||||||
|
\definecolor{ugent-bw}{RGB}{39,171,173}
|
||||||
|
% Faculty of Pharmaceutical Sciences
|
||||||
|
\definecolor{ugent-fw}{RGB}{190,81,144}
|
||||||
|
% Faculty of Political and Social Sciences
|
||||||
|
\definecolor{ugent-ps}{RGB}{113,168,96}
|
||||||
|
|
||||||
|
% Define new commands
|
||||||
|
\def\thetitle#1{\def\@thetitle{#1}}
|
||||||
|
\def\thesubtitle#1{\def\@thesubtitle{#1}}
|
||||||
|
\def\infoboxa#1{\def\@infoboxa{#1}}
|
||||||
|
\def\infoboxb#1{\def\@infoboxb{#1}}
|
||||||
|
\def\infoboxc#1{\def\@infoboxc{#1}}
|
||||||
|
\def\infoboxd#1{\def\@infoboxd{#1}}
|
||||||
|
|
||||||
|
% Initialize new commands as 'empty'
|
||||||
|
\def\@thetitle{}
|
||||||
|
\def\@thesubtitle{}
|
||||||
|
\def\@infoboxa{}
|
||||||
|
\def\@infoboxb{}
|
||||||
|
\def\@infoboxc{}
|
||||||
|
\def\@infoboxd{}
|
||||||
|
|
||||||
|
% Define lengths based on UGent document grid
|
||||||
|
% See: https://styleguide.ugent.be/basic-principles/grid-and-layout.html
|
||||||
|
\newlength{\longedge}
|
||||||
|
\setlength{\longedge}{\maxof{\paperheight}{\paperwidth}}
|
||||||
|
\newlength{\gridunit}
|
||||||
|
\setlength{\gridunit}{\longedge/28} %Divide long edge by 7 and next by 4
|
||||||
|
\newlength{\subpaperheight}
|
||||||
|
\setlength{\subpaperheight}{\paperheight-7\gridunit} %Type area: 3 units for faculty logo, 4 units for UGent logo
|
||||||
|
\newlength{\subpaperwidth}
|
||||||
|
\setlength{\subpaperwidth}{\paperwidth-\gridunit} %Left margin of 1 gridunit
|
||||||
|
|
||||||
|
% Define strut based on \gridunit
|
||||||
|
\newcommand{\mystrut}[1][-.5]{\rule[#1\gridunit]{0pt}{0pt}}
|
||||||
|
|
||||||
|
% Set default page layout
|
||||||
|
% Can be overwritten in preamble of document
|
||||||
|
\renewcommand{\baselinestretch}{1.15} % line spacing
|
||||||
|
\geometry{bottom=2.5cm,top=2.5cm,left=3cm,right=2cm} % margins
|
||||||
|
|
||||||
|
% Redefine the titlepage in accordance with UGent styleguide
|
||||||
|
\renewcommand\maketitle{\begin{titlepage}%
|
||||||
|
\thispagestyle{empty} % by default, the pagestyle of title page is plain
|
||||||
|
\newgeometry{top=0cm, bottom=0cm, left=0cm, right=0cm} % set special margins
|
||||||
|
\setlength{\parindent}{0cm} % necessary to put minipages/boxes at extreme left of page
|
||||||
|
\setlength{\parsep}{0cm} % necessary to stack minipages/boxes without space
|
||||||
|
\setlength{\fboxsep}{0cm} % no border around minipages/boxes
|
||||||
|
\setlength{\parskip}{0cm}
|
||||||
|
\setlength{\lineskip}{0cm}
|
||||||
|
|
||||||
|
\ifugd@sftitles
|
||||||
|
\sffamily % Titlepage in sans serif font
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\includegraphics[height=3\gridunit]{\ugd@faculty-\ugd@language.pdf}%
|
||||||
|
|
||||||
|
\makebox[\gridunit]{}% Left margin of 1 gridunit
|
||||||
|
\colorbox{ugent-\ugd@faculty!30}{%
|
||||||
|
%\colorbox{ugentwhite}{%
|
||||||
|
\begin{minipage}[c][\subpaperheight][t]{\subpaperwidth}%
|
||||||
|
\vskip 5\gridunit % top margin within minipage
|
||||||
|
\hskip \gridunit % left margin of 1 within the colorbox
|
||||||
|
%\fbox{%
|
||||||
|
\begin{minipage}{\subpaperwidth-2\gridunit} % tile minipage, right margin of 1
|
||||||
|
\raggedright\bfseries\huge
|
||||||
|
\textcolor{ugentblue}{\mystrut\@thetitle}\newline
|
||||||
|
\Large\textcolor{ugentblue}{\@thesubtitle}
|
||||||
|
\mystrut[1]
|
||||||
|
\end{minipage}%}
|
||||||
|
|
||||||
|
\vskip\fill % Push down to bottom of minipage
|
||||||
|
|
||||||
|
\ifx\@infoboxa\empty\else % ony put box if not empty
|
||||||
|
\hskip\gridunit % left margin of infobox
|
||||||
|
%\fbox{%
|
||||||
|
\begin{minipage}[b]{\subpaperwidth-3\gridunit} % right margin of 1
|
||||||
|
\@infoboxa
|
||||||
|
\end{minipage}%}
|
||||||
|
|
||||||
|
\baselineskip0pt\mystrut
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\ifx\@infoboxb\empty\else % ony put box if not empty
|
||||||
|
\hskip\gridunit % left margin of infobox
|
||||||
|
%\fbox{%
|
||||||
|
\begin{minipage}[b]{\subpaperwidth-3\gridunit} % right margin of 1
|
||||||
|
\@infoboxb
|
||||||
|
\end{minipage}%}
|
||||||
|
|
||||||
|
\baselineskip0pt\mystrut
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\ifx\@infoboxc\empty\else % ony put box if not empty
|
||||||
|
\hskip\gridunit % left margin of infobox
|
||||||
|
%\fbox{%
|
||||||
|
\begin{minipage}[b]{\subpaperwidth-3\gridunit} % right margin of 1
|
||||||
|
\@infoboxc
|
||||||
|
\end{minipage}%}
|
||||||
|
|
||||||
|
\baselineskip0pt\mystrut
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\ifx\@infoboxd\empty\else % ony put box if not empty
|
||||||
|
\hskip\gridunit % left margin of infobox
|
||||||
|
%\fbox{%
|
||||||
|
\begin{minipage}[b]{\subpaperwidth-3\gridunit} % right margin of 1
|
||||||
|
\@infoboxd
|
||||||
|
\end{minipage}%}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\baselineskip0pt\mystrut[-1]
|
||||||
|
\end{minipage}
|
||||||
|
}%
|
||||||
|
|
||||||
|
\includegraphics[height=4\gridunit]{ugent-\ugd@language.pdf}%
|
||||||
|
\end{titlepage}
|
||||||
|
\restoregeometry
|
||||||
|
}
|
||||||
BIN
Reports/November/ugent-en.pdf
Normal file
BIN
Reports/November/ugent-en.pdf
Normal file
Binary file not shown.
31
Reports/November/verslag.aux
Normal file
31
Reports/November/verslag.aux
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
\relax
|
||||||
|
\providecommand\babel@aux[2]{}
|
||||||
|
\@nameuse{bbl@beforestart}
|
||||||
|
\abx@aux@refcontext{nyt/global//global/global}
|
||||||
|
\providecommand\hyper@newdestlabel[2]{}
|
||||||
|
\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
|
||||||
|
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
|
||||||
|
\global\let\oldnewlabel\newlabel
|
||||||
|
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
|
||||||
|
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
|
||||||
|
\AtEndDocument{\ifx\hyper@anchor\@undefined
|
||||||
|
\let\newlabel\oldnewlabel
|
||||||
|
\fi}
|
||||||
|
\fi}
|
||||||
|
\global\let\hyper@last\relax
|
||||||
|
\gdef\HyperFirstAtBeginDocument#1{#1}
|
||||||
|
\providecommand\HyField@AuxAddToFields[1]{}
|
||||||
|
\providecommand\HyField@AuxAddToCoFields[2]{}
|
||||||
|
\babel@aux{english}{}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {1}Intermediate Results}{1}{section.1}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Previous day as forecast}{1}{subsection.1.1}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {1.2}All Zeros}{1}{subsection.1.2}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {1.3}Linear Model}{1}{subsection.1.3}\protected@file@percent }
|
||||||
|
\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Results of the linear model with different ranges of training data}}{2}{table.1}\protected@file@percent }
|
||||||
|
\newlabel{tab:linear_model}{{1}{2}{Results of the linear model with different ranges of training data}{table.1}{}}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\numberline {2}Schedule next months}{3}{section.2}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Other input features}{3}{subsection.2.1}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}More complex models}{3}{subsection.2.2}\protected@file@percent }
|
||||||
|
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Reinforcement learning}{3}{subsection.2.3}\protected@file@percent }
|
||||||
|
\abx@aux@read@bbl@mdfivesum{nobblfile}
|
||||||
|
\gdef \@abspage@last{4}
|
||||||
2872
Reports/November/verslag.bcf
Normal file
2872
Reports/November/verslag.bcf
Normal file
File diff suppressed because it is too large
Load Diff
1036
Reports/November/verslag.log
Normal file
1036
Reports/November/verslag.log
Normal file
File diff suppressed because it is too large
Load Diff
8
Reports/November/verslag.out
Normal file
8
Reports/November/verslag.out
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
\BOOKMARK [1][-]{section.1}{\376\377\000I\000n\000t\000e\000r\000m\000e\000d\000i\000a\000t\000e\000\040\000R\000e\000s\000u\000l\000t\000s}{}% 1
|
||||||
|
\BOOKMARK [2][-]{subsection.1.1}{\376\377\000P\000r\000e\000v\000i\000o\000u\000s\000\040\000d\000a\000y\000\040\000a\000s\000\040\000f\000o\000r\000e\000c\000a\000s\000t}{section.1}% 2
|
||||||
|
\BOOKMARK [2][-]{subsection.1.2}{\376\377\000A\000l\000l\000\040\000Z\000e\000r\000o\000s}{section.1}% 3
|
||||||
|
\BOOKMARK [2][-]{subsection.1.3}{\376\377\000L\000i\000n\000e\000a\000r\000\040\000M\000o\000d\000e\000l}{section.1}% 4
|
||||||
|
\BOOKMARK [1][-]{section.2}{\376\377\000S\000c\000h\000e\000d\000u\000l\000e\000\040\000n\000e\000x\000t\000\040\000m\000o\000n\000t\000h\000s}{}% 5
|
||||||
|
\BOOKMARK [2][-]{subsection.2.1}{\376\377\000O\000t\000h\000e\000r\000\040\000i\000n\000p\000u\000t\000\040\000f\000e\000a\000t\000u\000r\000e\000s}{section.2}% 6
|
||||||
|
\BOOKMARK [2][-]{subsection.2.2}{\376\377\000M\000o\000r\000e\000\040\000c\000o\000m\000p\000l\000e\000x\000\040\000m\000o\000d\000e\000l\000s}{section.2}% 7
|
||||||
|
\BOOKMARK [2][-]{subsection.2.3}{\376\377\000R\000e\000i\000n\000f\000o\000r\000c\000e\000m\000e\000n\000t\000\040\000l\000e\000a\000r\000n\000i\000n\000g}{section.2}% 8
|
||||||
BIN
Reports/November/verslag.pdf
Normal file
BIN
Reports/November/verslag.pdf
Normal file
Binary file not shown.
89
Reports/November/verslag.run.xml
Normal file
89
Reports/November/verslag.run.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" standalone="yes"?>
|
||||||
|
<!-- logreq request file -->
|
||||||
|
<!-- logreq version 1.0 / dtd version 1.0 -->
|
||||||
|
<!-- Do not edit this file! -->
|
||||||
|
<!DOCTYPE requests [
|
||||||
|
<!ELEMENT requests (internal | external)*>
|
||||||
|
<!ELEMENT internal (generic, (provides | requires)*)>
|
||||||
|
<!ELEMENT external (generic, cmdline?, input?, output?, (provides | requires)*)>
|
||||||
|
<!ELEMENT cmdline (binary, (option | infile | outfile)*)>
|
||||||
|
<!ELEMENT input (file)+>
|
||||||
|
<!ELEMENT output (file)+>
|
||||||
|
<!ELEMENT provides (file)+>
|
||||||
|
<!ELEMENT requires (file)+>
|
||||||
|
<!ELEMENT generic (#PCDATA)>
|
||||||
|
<!ELEMENT binary (#PCDATA)>
|
||||||
|
<!ELEMENT option (#PCDATA)>
|
||||||
|
<!ELEMENT infile (#PCDATA)>
|
||||||
|
<!ELEMENT outfile (#PCDATA)>
|
||||||
|
<!ELEMENT file (#PCDATA)>
|
||||||
|
<!ATTLIST requests
|
||||||
|
version CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
<!ATTLIST internal
|
||||||
|
package CDATA #REQUIRED
|
||||||
|
priority (9) #REQUIRED
|
||||||
|
active (0 | 1) #REQUIRED
|
||||||
|
>
|
||||||
|
<!ATTLIST external
|
||||||
|
package CDATA #REQUIRED
|
||||||
|
priority (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) #REQUIRED
|
||||||
|
active (0 | 1) #REQUIRED
|
||||||
|
>
|
||||||
|
<!ATTLIST provides
|
||||||
|
type (static | dynamic | editable) #REQUIRED
|
||||||
|
>
|
||||||
|
<!ATTLIST requires
|
||||||
|
type (static | dynamic | editable) #REQUIRED
|
||||||
|
>
|
||||||
|
<!ATTLIST file
|
||||||
|
type CDATA #IMPLIED
|
||||||
|
>
|
||||||
|
]>
|
||||||
|
<requests version="1.0">
|
||||||
|
<internal package="biblatex" priority="9" active="0">
|
||||||
|
<generic>latex</generic>
|
||||||
|
<provides type="dynamic">
|
||||||
|
<file>verslag.bcf</file>
|
||||||
|
</provides>
|
||||||
|
<requires type="dynamic">
|
||||||
|
<file>verslag.bbl</file>
|
||||||
|
</requires>
|
||||||
|
<requires type="static">
|
||||||
|
<file>blx-dm.def</file>
|
||||||
|
<file>apa.dbx</file>
|
||||||
|
<file>blx-compat.def</file>
|
||||||
|
<file>biblatex.def</file>
|
||||||
|
<file>standard.bbx</file>
|
||||||
|
<file>apa.bbx</file>
|
||||||
|
<file>apa.cbx</file>
|
||||||
|
<file>biblatex.cfg</file>
|
||||||
|
<file>english.lbx</file>
|
||||||
|
<file>american.lbx</file>
|
||||||
|
<file>american-apa.lbx</file>
|
||||||
|
<file>english-apa.lbx</file>
|
||||||
|
</requires>
|
||||||
|
</internal>
|
||||||
|
<external package="biblatex" priority="5" active="0">
|
||||||
|
<generic>biber</generic>
|
||||||
|
<cmdline>
|
||||||
|
<binary>biber</binary>
|
||||||
|
<infile>verslag</infile>
|
||||||
|
</cmdline>
|
||||||
|
<input>
|
||||||
|
<file>verslag.bcf</file>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<file>verslag.bbl</file>
|
||||||
|
</output>
|
||||||
|
<provides type="dynamic">
|
||||||
|
<file>verslag.bbl</file>
|
||||||
|
</provides>
|
||||||
|
<requires type="dynamic">
|
||||||
|
<file>verslag.bcf</file>
|
||||||
|
</requires>
|
||||||
|
<requires type="editable">
|
||||||
|
<file>./references.bib</file>
|
||||||
|
</requires>
|
||||||
|
</external>
|
||||||
|
</requests>
|
||||||
BIN
Reports/November/verslag.synctex.gz
Normal file
BIN
Reports/November/verslag.synctex.gz
Normal file
Binary file not shown.
192
Reports/November/verslag.tex
Normal file
192
Reports/November/verslag.tex
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
\documentclass[12pt,a4paper,faculty=ea,language=en,doctype=article]{ugent-doc}
|
||||||
|
|
||||||
|
% Optional: margins and spacing
|
||||||
|
%-------------------------------
|
||||||
|
% Uncomment and adjust to change the default values set by the template
|
||||||
|
% Note: the defaults are suggested values by Ghent University
|
||||||
|
%\geometry{bottom=2.5cm,top=2.5cm,left=3cm,right=2cm}
|
||||||
|
%\renewcommand{\baselinestretch}{1.15} % line spacing
|
||||||
|
|
||||||
|
% Font
|
||||||
|
%------
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc} % allows non-ascii input characters
|
||||||
|
% Comment or remove the two lines below to use the default Computer Modern font
|
||||||
|
\usepackage{libertine}
|
||||||
|
\usepackage{libertinust1math}
|
||||||
|
% NOTE: because the UGent font Panno is proprietary, it is not possible to use it
|
||||||
|
% in Overleaf. But UGent does not suggest to use Panno for documents (or maybe only for
|
||||||
|
% the titlepage). For the body, the UGent suggestion is to use a good serif font (for
|
||||||
|
% LaTeX this could be libertine or Computer Modern).
|
||||||
|
|
||||||
|
% Proper word splitting
|
||||||
|
%-----------------------
|
||||||
|
\usepackage[english]{babel}
|
||||||
|
|
||||||
|
% Mathematics
|
||||||
|
%-------------
|
||||||
|
\usepackage{amsmath}
|
||||||
|
|
||||||
|
% Figures
|
||||||
|
%---------
|
||||||
|
\usepackage{graphicx} % optional: the package is already loaded by the template
|
||||||
|
\graphicspath{{./figures/}}
|
||||||
|
|
||||||
|
% Bibliography settings
|
||||||
|
%-----------------------
|
||||||
|
\usepackage[backend=biber, style=apa, sorting=nyt, hyperref=true]{biblatex}
|
||||||
|
\addbibresource{./references.bib}
|
||||||
|
\usepackage{csquotes} % Suggested when using babel+biblatex
|
||||||
|
|
||||||
|
% Hyperreferences
|
||||||
|
%-----------------
|
||||||
|
\usepackage[colorlinks=true, allcolors=ugentblue]{hyperref}
|
||||||
|
|
||||||
|
% Whitespace between paragraphs and no indentation
|
||||||
|
%--------------------------------------------------
|
||||||
|
\usepackage[parfill]{parskip}
|
||||||
|
|
||||||
|
% Input for title page
|
||||||
|
%----------------------
|
||||||
|
|
||||||
|
% The title
|
||||||
|
\thetitle{Forecasting and generative modeling of the Belgian electricity market}
|
||||||
|
\thesubtitle{November Intermediate Report}
|
||||||
|
|
||||||
|
%% Note: a stricter UGent style could be achieved with, e.g.:
|
||||||
|
\usepackage{ulem} % for colored underline
|
||||||
|
\renewcommand{\ULthickness}{2pt} % adjust thickness of underline
|
||||||
|
\thetitle{Forecasting and generative modeling of the Belgian electricity market}
|
||||||
|
% Note: do not forget to reset the \ULthickness to 1pt after invoking \maketitle
|
||||||
|
% (otherwise all underlines in the rest of your document will be too thick):
|
||||||
|
%\renewcommand{\ULthickness}{1pt}
|
||||||
|
|
||||||
|
% The first (top) infobox at bottom of titlepage
|
||||||
|
\infoboxa{\bfseries\large Master Thesis}
|
||||||
|
|
||||||
|
% The second infobox at bottom of titlepage
|
||||||
|
\infoboxb{Name:
|
||||||
|
\begin{tabular}[t]{l}
|
||||||
|
Victor Mylle
|
||||||
|
\end{tabular}
|
||||||
|
}
|
||||||
|
|
||||||
|
% The third infobox at bottom of titlepage
|
||||||
|
\infoboxc{
|
||||||
|
Promotors:
|
||||||
|
\begin{tabular}[t]{l}
|
||||||
|
prof. dr. ir. Chris Develder \\
|
||||||
|
prof. Bert Claessens
|
||||||
|
\end{tabular}
|
||||||
|
\\\\
|
||||||
|
Supervisor:
|
||||||
|
\begin{tabular}[t]{l}
|
||||||
|
Jonas Van Gompel
|
||||||
|
\end{tabular}
|
||||||
|
}
|
||||||
|
|
||||||
|
% The last (bottom) infobox at bottom of titlepage
|
||||||
|
\infoboxd{Academic year: 2023--2024} % note dash, not hyphen
|
||||||
|
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
% =====================================================================
|
||||||
|
% Cover
|
||||||
|
% =====================================================================
|
||||||
|
|
||||||
|
% ------------ TITLE PAGE ---------
|
||||||
|
\maketitle
|
||||||
|
\renewcommand{\ULthickness}{1pt}
|
||||||
|
|
||||||
|
% =====================================================================
|
||||||
|
% Front matter
|
||||||
|
% =====================================================================
|
||||||
|
|
||||||
|
% ------------ TABLE OF CONTENTS ---------
|
||||||
|
% {\hypersetup{hidelinks}\tableofcontents} % hide link color in toc
|
||||||
|
% \newpage
|
||||||
|
% \begin{titlepage}
|
||||||
|
|
||||||
|
% \centering % Centers everything on the page
|
||||||
|
|
||||||
|
% % Logo or Image (Optional)
|
||||||
|
% % \includegraphics[width=0.5\textwidth]{path_to_logo.jpg}
|
||||||
|
|
||||||
|
% \vspace*{2cm} % Add vertical space
|
||||||
|
|
||||||
|
% {\large Title: Forecasting and generative modeling of the Belgian electricity market\par}
|
||||||
|
|
||||||
|
% \vspace{2cm}
|
||||||
|
% {\Large Victor Mylle\par}
|
||||||
|
|
||||||
|
% \vspace{1cm}
|
||||||
|
% {\large Period of Internship: 3 July 2023 - 31 August 2023\par}
|
||||||
|
|
||||||
|
% \vspace{1cm}
|
||||||
|
% {\large Mentor: dr. ir. Femke De Backere\par}
|
||||||
|
% {\large TechWolf supervisor: ir. Jens-Joris Decorte}
|
||||||
|
|
||||||
|
% \end{titlepage}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\section{Intermediate Results}
|
||||||
|
The electricity market is a complicated system with many different factors. During this thesis, we will try to model the day-ahead system imbalance. Using this imbalance, a model can be trained using reinforcement learning to trade on the electricity market to generate profit. The first step is to model the imbalance. The imbalance is the difference between the amount of electricity that is bought and sold on the day-ahead market and the amount of electricity that is actually consumed. Elia (Transmission System Operator) is responsible for keeping the grid stable and takes the steps necessary to do so. They provide electricity when there is a shortage and take electricity when there is a surplus. The amount of energy that is provided or consumed is called the Net Regulation Volume. Based on the Net Regulation Volume and the bid ladder, the electricity price can be calculated. \\\\
|
||||||
|
Elia publishes a lot of data on their website. This data can then be used as training data. First, simple baselines can be implemented to forecast the NRV of the next day.
|
||||||
|
\\\\
|
||||||
|
The data available ranges from 01-01-2015 until the current date. The data is available in minute or quarter intervals. For our use case, the quarter interval will do. The data is split into training data and test data. The data from 2023 is used as the test set.
|
||||||
|
|
||||||
|
\subsection{Previous day as forecast}
|
||||||
|
One baseline can be to use the previous day NRV values as the forecast for the next day. This gives the following results on the test set: \\\\
|
||||||
|
MAE: 145.97317296006946 \\
|
||||||
|
MSE: 39632.622958020256
|
||||||
|
\subsection{All Zeros}
|
||||||
|
Using all zeros as forecast gives the following results on the test set: \\\\
|
||||||
|
MAE: 106.1727146629051 \\
|
||||||
|
MSE: 21977.654647179577 \\
|
||||||
|
\\
|
||||||
|
The first small conclusion that can be made is that just using all zeros as the forecast gives better results than using the previous day NRV values.
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Linear Model}
|
||||||
|
A simple linear model can also be trained on the data. This doesn't generatively model the NRV but forecasts the next value based on the given NRV values. This model can then be used autoregressively to forecast the NRV of the next day.
|
||||||
|
% Table with results with different ranges of training data
|
||||||
|
\begin{table}[h]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{|l|l|l|}
|
||||||
|
\hline
|
||||||
|
Training data range & MAE & MSE \\ \hline
|
||||||
|
2015-2022 & 78.04712677001953& 10891.9501953125 \\ \hline
|
||||||
|
2016-2022 & 77.98072814941406 & 10872.8173828125 \\ \hline
|
||||||
|
2017-2022 & 77.94755554199219 & 10859.1943359375 \\ \hline
|
||||||
|
2018-2022 & 77.90494537353516 & 10840.017578125 \\ \hline
|
||||||
|
2019-2022 & 77.88092041015625 & 10830.2880859375 \\ \hline
|
||||||
|
2020-2022 & 77.84571075439453 & 10823.6826171875 \\ \hline
|
||||||
|
2021-2022 & 77.86540985107422 & 10831.35546875 \\ \hline
|
||||||
|
2022-2022 & 77.95752716064453 & 10871.7685546875 \\ \hline
|
||||||
|
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Results of the linear model with different ranges of training data}
|
||||||
|
\label{tab:linear_model}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
The experiments performed use a linear model. The input size is 96 (the quarter-hour values of the NRV) and the output is one value that represents the predicted next NRV value. The experiments use Adam as an optimizer with a learning rate of 0.0003. All input values were rescaled using the MinMaxScaler.
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Schedule next months}
|
||||||
|
An overview of the planning for the next months is given below. The planning is subject to change depending on the results of the experiments.
|
||||||
|
|
||||||
|
\subsection{Other input features}
|
||||||
|
For the moment, only the NRV is used as input. More inputs can be used to model the NRV. For example, Elia provides a load forecast for every quarter hour. This can also be used as input for the model. Weather and other dependencies should be further explored.
|
||||||
|
|
||||||
|
\subsection{More complex models}
|
||||||
|
For now, the models were kept simple. More complex models can however be used to generatively model the NRV. For example, diffusion models can be explored.
|
||||||
|
|
||||||
|
\subsection{Reinforcement learning}
|
||||||
|
Once a model is trained to generatively model the NRV, a reinforcement learning model can be trained to make better decisions on the electricity market. This step however, requires a good generative model of the NRV.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
||||||
87
Result-Reports/November.md
Normal file
87
Result-Reports/November.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Result Report November
|
||||||
|
## 1. TODOs
|
||||||
|
|
||||||
|
- [x] Compare autoregressive vs non-autoregressive
|
||||||
|
- [ ] Add more input parameters (load forecast)
|
||||||
|
- [x] Quantile Regression sampling fix
|
||||||
|
- [x] Quantile Regression exploration
|
||||||
|
|
||||||
|
## 2. Autoregressive vs Non-Autoregressive
|
||||||
|
|
||||||
|
Training data: 2015 - 2022 \
|
||||||
|
Batch_size: 1024 \
|
||||||
|
Learning_rate: 0.0003 \
|
||||||
|
Early_stopping: 10
|
||||||
|
|
||||||
|
### 2.1 Linear Model
|
||||||
|
Comparison: [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/compare-experiments;ids=3b512226b24c46199b584d7abc23bf96,097b3832eb5e4c5a8fa2e04887975c29/scalars/values?scalars=values)
|
||||||
|
<!-- table with 3 columns and rows: experiment, Train-MAE, Train-MSE, Test-MAE, Test-MSE -->
|
||||||
|
| | Autoregressive | Non-Autoregressive |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Experiment (ClearML) | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/3b512226b24c46199b584d7abc23bf96/execution?columns=selected&columns=type&columns=name&columns=tags&columns=status&columns=project.name&columns=users&columns=started&columns=last_update&columns=last_iteration&columns=parent.name&order=-last_update&filter=) | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/097b3832eb5e4c5a8fa2e04887975c29/execution?columns=selected&columns=type&columns=name&columns=tags&columns=status&columns=project.name&columns=users&columns=started&columns=last_update&columns=last_iteration&columns=parent.name&order=-last_update&filter=) |
|
||||||
|
| Train-MAE | 68.0202865600586 | 94.83179473876953 |
|
||||||
|
| Train-MSE | 7861.2197265625 | 15977.8759765625 |
|
||||||
|
| Test-MAE | 78.05316925048828 | 104.11575317382812 |
|
||||||
|
| Test-MSE | 10882.755859375 | 21145.583984375 |
|
||||||
|
|
||||||
|
### 2.2 Non Linear Model
|
||||||
|
|
||||||
|
Hidden layers: 1 \
|
||||||
|
Hidden units: 512
|
||||||
|
|
||||||
|
Comparison: [Link](hhttps://clearml.victormylle.be/projects/135c055e64e54486a54055f33ca9a5af/compare-experiments;ids=57f4a09c6ce54296b6e034f2e0236420,b5f6862f900948c18a834a1a970c8710/scalars/values?scalars=values)
|
||||||
|
|
||||||
|
| | Autoregressive | Non-Autoregressive |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Experiment (ClearML) | [Link](https://clearml.victormylle.be/projects/135c055e64e54486a54055f33ca9a5af/experiments/57f4a09c6ce54296b6e034f2e0236420/output/execution) | [Link](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/b5f6862f900948c18a834a1a970c8710/output/execution) |
|
||||||
|
| Train-MAE | 66.78179931640625 | 94.52633666992188 |
|
||||||
|
| Train-MSE | 7507.53955078125 | 15835.671875 |
|
||||||
|
| Test-MAE | 77.63729095458984 | 104.07229614257812 |
|
||||||
|
| Test-MSE | 10789.544921875 | 21090.9765625 |
|
||||||
|
|
||||||
|
Also tried with [3 hidden layers for Non-Autoregressive model](https://clearml.victormylle.be/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/583d0bc1dfb7494d81cf356f6d003dbb/output/execution), test results didn't improve.
|
||||||
|
|
||||||
|
# 3. Quantile Regression
|
||||||
|
|
||||||
|
## 3.1 Sampling Fix
|
||||||
|
The model outputs values for the quantiles it is trained on. For example, the quantiles [0.025, 0.05, 0.1, 0.15, 0.85, 0.9, 0.95, 0.975] can be used. The values outputted by the model are like: [-0.23013, -0.19831, -0.15217, -0.13654, 0.011687, 0.015129, 0.043187, 0.047704]. Plotting these as CDF:
|
||||||
|
|
||||||
|
\
|
||||||
|
*Plotted output values with cubic interpolation*
|
||||||
|
|
||||||
|
Samling from a uniform distribution, we can convert it to our distribution by using the inverse CDF. In python we can interpolate immediately by switching the x and y axis. This gives us the following code:
|
||||||
|
```
|
||||||
|
interp1d(quantiles, output_values, kind='quadratic', bounds_error=False, fill_value="extrapolate")
|
||||||
|
```
|
||||||
|
The mean of x amount of samples can be calculated.
|
||||||
|
|
||||||
|
## 3.2 Exploration
|
||||||
|
### 3.2.1 Linear Model
|
||||||
|
Learning Rate: 0.0003 \
|
||||||
|
Batch Size: 1024 \
|
||||||
|
Early Stopping: 10 \
|
||||||
|
Trining Data: 2015 - 2022
|
||||||
|
|
||||||
|
| Quantiles | Train-MAE | Train-MSE | Test-MAE | Test-MSE |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 0.025, 0.1, 0.2, 0.3, 0.5, 0.6, 0.8, 0.85, 0.9, 0.975 | 68.07254628777868 | 7872.668472187121 | 78.11135584669907 | 10903.793883789216 |
|
||||||
|
| 0.025, 0.1, 0.15, 0.2, 0.5, 0.8, 0.85, 0.9, 0.975 | 68.0732244289865 | 7873.212834241974 | 78.1143230666738 | 10907.350919114313 |
|
||||||
|
| 0.025, 0.05, 0.1, 0.15, 0.85, 0.9, 0.95, 0.975 | 68.2798014428824 | 7936.7644114273935 | 78.50109206637464 | 11005.706457116454 |
|
||||||
|
| 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 | 68.06139224378171 | 7871.467571921973 | 78.10843456751378 | 10904.55519059502 |
|
||||||
|
| 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9 | 68.0350635204691 | 7868.661882749334 | 78.1139478264609 | 10905.562798801011 |
|
||||||
|
| 0.1, 0.2, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.9 | 68.03191172170285 | 7868.483061240721 | 78.13204232055722 | 10908.837301340453 |
|
||||||
|
|
||||||
|
These are all very close
|
||||||
|
|
||||||
|
### 3.2.2 Non Linear Model
|
||||||
|
Learning Rate: 0.0003 \
|
||||||
|
Batch Size: 1024 \
|
||||||
|
Early Stopping: 10 \
|
||||||
|
Trining Data: 2015 - 2022 \
|
||||||
|
Hidden Layers: 3 \
|
||||||
|
Hidden Units: 1024
|
||||||
|
|
||||||
|
| Quantiles | Train-MAE | Train-MSE | Test-MAE | Test-MSE |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 0.1, 0.2, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.8, 0.9 | 65.6542529596313 | 7392.5142575554955 | 77.55779692831604 | 10769.161724849037 |
|
||||||
|
| 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 | 65.68495924348356 | 7326.2239225611975 | 77.62433888969542 | 10789.003223366473 |
|
||||||
BIN
Result-Reports/images/quantile_regression_sampling.png
Normal file
BIN
Result-Reports/images/quantile_regression_sampling.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
308188
data/history-quarter-hour-data.csv
Normal file
308188
data/history-quarter-hour-data.csv
Normal file
File diff suppressed because it is too large
Load Diff
10
requirements.txt
Normal file
10
requirements.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pandas
|
||||||
|
matplotlib
|
||||||
|
plotly
|
||||||
|
nbformat
|
||||||
|
skforecast
|
||||||
|
seaborn
|
||||||
|
statsmodels
|
||||||
|
lightgbm
|
||||||
|
prettytable
|
||||||
|
clearml
|
||||||
2
src/data/__init__.py
Normal file
2
src/data/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from .dataset import NrvDataset
|
||||||
|
from .preprocessing import DataProcessor
|
||||||
15
src/data/dataset.py
Normal file
15
src/data/dataset.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import torch
|
||||||
|
from torch.utils.data import Dataset, DataLoader
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
class NrvDataset(Dataset):
|
||||||
|
def __init__(self, dataframe, sequence_length=96, predict_sequence_length=96):
|
||||||
|
self.data = torch.tensor(dataframe['nrv'].to_numpy(), dtype=torch.float32)
|
||||||
|
self.sequence_length = sequence_length
|
||||||
|
self.predict_sequence_length = predict_sequence_length
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.data) - self.sequence_length - self.predict_sequence_length
|
||||||
|
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
return self.data[idx:idx+self.sequence_length], self.data[idx+self.sequence_length:idx+self.sequence_length+self.predict_sequence_length]
|
||||||
116
src/data/preprocessing.py
Normal file
116
src/data/preprocessing.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
from sklearn.preprocessing import MinMaxScaler
|
||||||
|
import torch
|
||||||
|
from data.dataset import NrvDataset
|
||||||
|
from datetime import datetime
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
history_data_path = "../../data/history-quarter-hour-data.csv"
|
||||||
|
|
||||||
|
class DataProcessor:
|
||||||
|
def __init__(self):
|
||||||
|
self.batch_size = 2048
|
||||||
|
|
||||||
|
self.train_range = (-np.inf, datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC))
|
||||||
|
self.test_range = (datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), np.inf)
|
||||||
|
|
||||||
|
self.update_range_str()
|
||||||
|
|
||||||
|
self.features = ['nrv']
|
||||||
|
|
||||||
|
self.nrv_df = self.get_nrv_history()
|
||||||
|
self.nrv_scaler = MinMaxScaler(feature_range=(-1, 1))
|
||||||
|
|
||||||
|
|
||||||
|
def set_train_range(self, train_range: tuple):
|
||||||
|
self.train_range = train_range
|
||||||
|
self.update_range_str()
|
||||||
|
|
||||||
|
def set_test_range(self, test_range: tuple):
|
||||||
|
self.test_range = test_range
|
||||||
|
self.update_range_str()
|
||||||
|
|
||||||
|
def update_range_str(self):
|
||||||
|
self.train_range_start = str(self.train_range[0]) if self.train_range[0] != -np.inf else "-inf"
|
||||||
|
self.train_range_end = str(self.train_range[1]) if self.train_range[1] != np.inf else "inf"
|
||||||
|
self.test_range_start = str(self.test_range[0]) if self.test_range[0] != -np.inf else "-inf"
|
||||||
|
self.test_range_end = str(self.test_range[1]) if self.test_range[1] != np.inf else "inf"
|
||||||
|
|
||||||
|
def get_nrv_history(self):
|
||||||
|
df = pd.read_csv(history_data_path, delimiter=';')
|
||||||
|
df = df[['datetime', 'netregulationvolume']]
|
||||||
|
df = df.rename(columns={'netregulationvolume': 'nrv'})
|
||||||
|
df['datetime'] = pd.to_datetime(df['datetime'])
|
||||||
|
counts = df['datetime'].dt.date.value_counts().sort_index()
|
||||||
|
df = df[df['datetime'].dt.date.isin(counts[counts == 96].index)]
|
||||||
|
|
||||||
|
df.sort_values(by="datetime", inplace=True)
|
||||||
|
return df
|
||||||
|
|
||||||
|
def set_batch_size(self, batch_size: int):
|
||||||
|
self.batch_size = batch_size
|
||||||
|
|
||||||
|
def get_dataloader(self, dataset, shuffle: bool = True):
|
||||||
|
return torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, shuffle=shuffle, num_workers=4)
|
||||||
|
|
||||||
|
def get_train_dataloader(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||||
|
train_df = self.nrv_df.copy()
|
||||||
|
|
||||||
|
if self.train_range[0] != -np.inf:
|
||||||
|
train_df = train_df[(train_df['datetime'] >= self.train_range[0])]
|
||||||
|
|
||||||
|
if self.train_range[1] != np.inf:
|
||||||
|
train_df = train_df[(train_df['datetime'] <= self.train_range[1])]
|
||||||
|
|
||||||
|
if transform:
|
||||||
|
train_df['nrv'] = self.nrv_scaler.fit_transform(train_df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||||
|
|
||||||
|
train_dataset = NrvDataset(train_df, predict_sequence_length=predict_sequence_length)
|
||||||
|
return self.get_dataloader(train_dataset)
|
||||||
|
|
||||||
|
def get_test_dataloader(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||||
|
|
||||||
|
test_df = self.nrv_df.copy()
|
||||||
|
|
||||||
|
if self.test_range[0] != -np.inf:
|
||||||
|
test_df = test_df[(test_df['datetime'] >= self.test_range[0])]
|
||||||
|
|
||||||
|
if self.test_range[1] != np.inf:
|
||||||
|
test_df = test_df[(test_df['datetime'] <= self.test_range[1])]
|
||||||
|
|
||||||
|
if transform:
|
||||||
|
test_df['nrv'] = self.nrv_scaler.transform(test_df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||||
|
test_dataset = NrvDataset(test_df, predict_sequence_length=predict_sequence_length)
|
||||||
|
return self.get_dataloader(test_dataset, shuffle=False)
|
||||||
|
|
||||||
|
|
||||||
|
def get_dataloaders(self, transform: bool = True, predict_sequence_length: int = 96):
|
||||||
|
return self.get_train_dataloader(transform=transform, predict_sequence_length=predict_sequence_length), self.get_test_dataloader(transform=transform, predict_sequence_length=predict_sequence_length)
|
||||||
|
|
||||||
|
def get_random_day(self, train: bool = True, transform: bool = True):
|
||||||
|
df = self.nrv_df.copy()
|
||||||
|
|
||||||
|
range = self.train_range if train else self.test_range
|
||||||
|
|
||||||
|
if range[0] != -np.inf:
|
||||||
|
df = df[(df['datetime'] >= range[0])]
|
||||||
|
|
||||||
|
if range[1] != np.inf:
|
||||||
|
df = df[(df['datetime'] <= range[1])]
|
||||||
|
|
||||||
|
if transform:
|
||||||
|
df['nrv'] = self.nrv_scaler.transform(df['nrv'].values.reshape(-1, 1)).reshape(-1)
|
||||||
|
|
||||||
|
data_tensor = torch.tensor(df[self.features].values, dtype=torch.float32)
|
||||||
|
|
||||||
|
random_start_idx = np.random.randint(0, len(df) - 191)
|
||||||
|
|
||||||
|
current_day_features = data_tensor[random_start_idx:random_start_idx+96]
|
||||||
|
next_day_features = data_tensor[random_start_idx+96:random_start_idx+192]
|
||||||
|
|
||||||
|
return (current_day_features, next_day_features)
|
||||||
|
|
||||||
|
def inverse_transform(self, tensor: torch.Tensor):
|
||||||
|
return self.nrv_scaler.inverse_transform(tensor.cpu().numpy()).reshape(-1)
|
||||||
1
src/losses/__init__.py
Normal file
1
src/losses/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .pinball_loss import PinballLoss
|
||||||
33
src/losses/pinball_loss.py
Normal file
33
src/losses/pinball_loss.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import torch
|
||||||
|
from torch import nn
|
||||||
|
|
||||||
|
class PinballLoss(nn.Module):
|
||||||
|
"""
|
||||||
|
Calculates the quantile loss function.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
self.pred : torch.tensor
|
||||||
|
Predictions.
|
||||||
|
self.target : torch.tensor
|
||||||
|
Target to predict.
|
||||||
|
self.quantiles : torch.tensor
|
||||||
|
"""
|
||||||
|
def __init__(self, quantiles):
|
||||||
|
super(PinballLoss, self).__init__()
|
||||||
|
self.quantiles_tensor = quantiles
|
||||||
|
self.quantiles = quantiles.tolist()
|
||||||
|
|
||||||
|
def forward(self, pred, target):
|
||||||
|
"""
|
||||||
|
Computes the loss for the given prediction.
|
||||||
|
"""
|
||||||
|
|
||||||
|
error = target - pred
|
||||||
|
upper = self.quantiles_tensor * error
|
||||||
|
lower = (self.quantiles_tensor - 1) * error
|
||||||
|
|
||||||
|
losses = torch.max(lower, upper)
|
||||||
|
loss = torch.mean(torch.sum(losses, dim=1))
|
||||||
|
return loss
|
||||||
|
|
||||||
3
src/models/__init__.py
Normal file
3
src/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .linear_regression import LinearRegression
|
||||||
|
from .complex_model import TimeSeriesModel
|
||||||
|
from .non_linear_regression import NonLinearRegression
|
||||||
29
src/models/complex_model.py
Normal file
29
src/models/complex_model.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
|
||||||
|
class TimeSeriesModel(nn.Module):
|
||||||
|
def __init__(self, input_size, output_size, num_layers=5, hidden_size=128, dropout_rate=0.3):
|
||||||
|
super(TimeSeriesModel, self).__init__()
|
||||||
|
|
||||||
|
self.output_size = output_size
|
||||||
|
|
||||||
|
layers = []
|
||||||
|
for i in range(num_layers):
|
||||||
|
if i == 0:
|
||||||
|
layers.append(nn.Linear(input_size, hidden_size))
|
||||||
|
else:
|
||||||
|
layers.append(nn.Linear(hidden_size, hidden_size))
|
||||||
|
layers.append(nn.BatchNorm1d(hidden_size))
|
||||||
|
layers.append(nn.Dropout(dropout_rate))
|
||||||
|
layers.append(nn.ReLU())
|
||||||
|
|
||||||
|
self.layers = nn.ModuleList(layers)
|
||||||
|
self.output = nn.Linear(hidden_size, output_size)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
x = torch.squeeze(x, -1)
|
||||||
|
|
||||||
|
for layer in self.layers:
|
||||||
|
x = layer(x)
|
||||||
|
x = self.output(x)
|
||||||
|
return x
|
||||||
14
src/models/linear_regression.py
Normal file
14
src/models/linear_regression.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import torch
|
||||||
|
|
||||||
|
class LinearRegression(torch.nn.Module):
|
||||||
|
def __init__(self, inputSize, output_size):
|
||||||
|
super(LinearRegression, self).__init__()
|
||||||
|
self.inputSize = inputSize
|
||||||
|
self.output_size = output_size
|
||||||
|
self.linear = torch.nn.Linear(inputSize, output_size)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
x = torch.squeeze(x, -1)
|
||||||
|
|
||||||
|
out = self.linear(x)
|
||||||
|
return out
|
||||||
31
src/models/non_linear_regression.py
Normal file
31
src/models/non_linear_regression.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import torch
|
||||||
|
|
||||||
|
class NonLinearRegression(torch.nn.Module):
|
||||||
|
def __init__(self, inputSize, output_size, hiddenSize=128, numLayers=2):
|
||||||
|
super(NonLinearRegression, self).__init__()
|
||||||
|
self.inputSize = inputSize
|
||||||
|
self.output_size = output_size
|
||||||
|
|
||||||
|
self.hiddenSize = hiddenSize
|
||||||
|
self.numLayers = numLayers
|
||||||
|
|
||||||
|
# add linear layers with relu
|
||||||
|
self.layers = torch.nn.ModuleList()
|
||||||
|
self.layers.append(torch.nn.Linear(inputSize, hiddenSize))
|
||||||
|
for _ in range(numLayers - 2):
|
||||||
|
self.layers.append(torch.nn.Linear(hiddenSize, hiddenSize))
|
||||||
|
self.layers.append(torch.nn.Linear(hiddenSize, output_size))
|
||||||
|
|
||||||
|
self.relu = torch.nn.ReLU()
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
x = torch.squeeze(x, -1)
|
||||||
|
|
||||||
|
for layer in self.layers[:-1]:
|
||||||
|
x = self.relu(layer(x))
|
||||||
|
|
||||||
|
out = self.layers[-1](x)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
src/notebooks/checkpoint.pt
Normal file
BIN
src/notebooks/checkpoint.pt
Normal file
Binary file not shown.
43019
src/notebooks/data-exploration.ipynb
Normal file
43019
src/notebooks/data-exploration.ipynb
Normal file
File diff suppressed because one or more lines are too long
124
src/notebooks/loss_test.ipynb
Normal file
124
src/notebooks/loss_test.ipynb
Normal file
File diff suppressed because one or more lines are too long
2092
src/notebooks/pytorch-linear.ipynb
Normal file
2092
src/notebooks/pytorch-linear.ipynb
Normal file
File diff suppressed because one or more lines are too long
230
src/notebooks/training.ipynb
Normal file
230
src/notebooks/training.ipynb
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import sys\n",
|
||||||
|
"sys.path.append('..')\n",
|
||||||
|
"from data import DataProcessor\n",
|
||||||
|
"from trainers.quantile_trainer import QuantileTrainer\n",
|
||||||
|
"from trainers.autoregressive_trainer import AutoRegressiveTrainer\n",
|
||||||
|
"from trainers.trainer import Trainer\n",
|
||||||
|
"from utils.clearml import ClearMLHelper\n",
|
||||||
|
"from models import *\n",
|
||||||
|
"from losses import *\n",
|
||||||
|
"import torch\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"from torch.nn import MSELoss, L1Loss\n",
|
||||||
|
"from datetime import datetime\n",
|
||||||
|
"import pytz\n",
|
||||||
|
"import torch.nn as nn\n",
|
||||||
|
"\n",
|
||||||
|
"# auto reload\n",
|
||||||
|
"%load_ext autoreload\n",
|
||||||
|
"%autoreload 2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Non-AutoRegressive"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"InsecureRequestWarning: Certificate verification is disabled! Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"ClearML Task: created new task id=909da25a8d214f75ab3858506ae615e8\n",
|
||||||
|
"2023-11-07 16:29:35,665 - clearml.Task - INFO - Storing jupyter notebook directly as code\n",
|
||||||
|
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/909da25a8d214f75ab3858506ae615e8/output/log\n",
|
||||||
|
"2023-11-07 16:30:08,121 - clearml.model - WARNING - 500 model found when searching for `file:///workspaces/Thesis/src/notebooks/checkpoint.pt`\n",
|
||||||
|
"2023-11-07 16:30:08,123 - clearml.model - WARNING - Selected model `Quantile Regression - Linear` (id=bc0cb0d7fc614e2e8b0edf5b85348646)\n",
|
||||||
|
"2023-11-07 16:30:08,130 - clearml.frameworks - INFO - Found existing registered model id=bc0cb0d7fc614e2e8b0edf5b85348646 [/workspaces/Thesis/src/notebooks/checkpoint.pt] reusing it.\n",
|
||||||
|
"2023-11-07 16:30:08,677 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Non-AutoRegressive%20-%20Non%20Linear%20%283%20hidden%20layers%20-%201024%20units%29.909da25a8d214f75ab3858506ae615e8/models/checkpoint.pt\n",
|
||||||
|
"2023-11-07 16:30:10,302 - clearml.Task - INFO - Completed model upload to http://192.168.1.182:8081/Thesis/NrvForecast/Non-AutoRegressive%20-%20Non%20Linear%20%283%20hidden%20layers%20-%201024%20units%29.909da25a8d214f75ab3858506ae615e8/models/checkpoint.pt\n",
|
||||||
|
"Early stopping triggered\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"#### Hyperparameters ####\n",
|
||||||
|
"inputDim = 96\n",
|
||||||
|
"learningRate = 0.0003\n",
|
||||||
|
"epochs = 50\n",
|
||||||
|
"\n",
|
||||||
|
"# model = LinearRegression(inputDim, 96)\n",
|
||||||
|
"model = NonLinearRegression(inputDim, 96, hiddenSize=1024, numLayers=5)\n",
|
||||||
|
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||||
|
"\n",
|
||||||
|
"#### Data Processor ####\n",
|
||||||
|
"data_processor = DataProcessor()\n",
|
||||||
|
"data_processor.set_batch_size(1024)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"data_processor.set_train_range((datetime(year=2015, month=1, day=1, tzinfo=pytz.UTC), datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC)))\n",
|
||||||
|
"data_processor.set_test_range((datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), np.inf))\n",
|
||||||
|
"\n",
|
||||||
|
"#### ClearML ####\n",
|
||||||
|
"clearml_helper = ClearMLHelper(project_name=\"Thesis/NrvForecast\")\n",
|
||||||
|
"\n",
|
||||||
|
"#### Trainer ####\n",
|
||||||
|
"trainer = Trainer(model, optimizer, nn.MSELoss(), data_processor, \"cuda\", debug=False, clearml_helper=clearml_helper)\n",
|
||||||
|
"trainer.add_metrics_to_track([MSELoss(), L1Loss()])\n",
|
||||||
|
"trainer.plot_every(10)\n",
|
||||||
|
"trainer.early_stopping(patience=10)\n",
|
||||||
|
"trainer.train(epochs=epochs)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# AutoRegressive Simple Linear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"ClearML Task: created new task id=6467cef37fdc408d95b89f0dca0e26dd\n",
|
||||||
|
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/6467cef37fdc408d95b89f0dca0e26dd/output/log\n",
|
||||||
|
"Early stopping triggered\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"#### Hyperparameters ####\n",
|
||||||
|
"inputDim = 96\n",
|
||||||
|
"learningRate = 0.0003\n",
|
||||||
|
"epochs = 50\n",
|
||||||
|
"\n",
|
||||||
|
"# model = LinearRegression(inputDim, 1)\n",
|
||||||
|
"model = NonLinearRegression(inputDim, 1, hiddenSize=1024, numLayers=5)\n",
|
||||||
|
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||||
|
"\n",
|
||||||
|
"#### Data Processor ####\n",
|
||||||
|
"data_processor = DataProcessor()\n",
|
||||||
|
"data_processor.set_batch_size(1024)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"data_processor.set_train_range((datetime(year=2015, month=1, day=1, tzinfo=pytz.UTC), datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC)))\n",
|
||||||
|
"data_processor.set_test_range((datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), np.inf))\n",
|
||||||
|
"\n",
|
||||||
|
"#### ClearML ####\n",
|
||||||
|
"clearml_helper = ClearMLHelper(project_name=\"Thesis/NrvForecast\")\n",
|
||||||
|
"\n",
|
||||||
|
"#### Trainer ####\n",
|
||||||
|
"trainer = AutoRegressiveTrainer(model, optimizer, nn.MSELoss(), data_processor, \"cuda\", debug=False, clearml_helper=clearml_helper)\n",
|
||||||
|
"trainer.add_metrics_to_track([MSELoss(), L1Loss()])\n",
|
||||||
|
"trainer.plot_every(10)\n",
|
||||||
|
"trainer.early_stopping(patience=10)\n",
|
||||||
|
"trainer.train(epochs=epochs)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Quantile Regression"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"/workspaces/Thesis/src/notebooks/../trainers/quantile_trainer.py:16: UserWarning:\n",
|
||||||
|
"\n",
|
||||||
|
"To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"ClearML Task: created new task id=07a2dc72793446d8a8101eafce0d80db\n",
|
||||||
|
"ClearML results page: http://192.168.1.182:8080/projects/2e46d4af6f1e4c399cf9f5aa30bc8795/experiments/07a2dc72793446d8a8101eafce0d80db/output/log\n",
|
||||||
|
"Early stopping triggered\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"#### Hyperparameters ####\n",
|
||||||
|
"inputDim = 96\n",
|
||||||
|
"learningRate = 0.0003\n",
|
||||||
|
"epochs = 50\n",
|
||||||
|
"\n",
|
||||||
|
"quantiles = torch.tensor([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]).to(\"cuda\")\n",
|
||||||
|
"\n",
|
||||||
|
"# model = LinearRegression(inputDim, len(quantiles))\n",
|
||||||
|
"model = NonLinearRegression(inputDim, len(quantiles), hiddenSize=1024, numLayers=5)\n",
|
||||||
|
"model.output_size = 1\n",
|
||||||
|
"optimizer = torch.optim.Adam(model.parameters(), lr=learningRate)\n",
|
||||||
|
"\n",
|
||||||
|
"#### Data Processor ####\n",
|
||||||
|
"data_processor = DataProcessor()\n",
|
||||||
|
"data_processor.set_batch_size(1024)\n",
|
||||||
|
"\n",
|
||||||
|
"data_processor.set_train_range((-np.inf, datetime(year=2022, month=11, day=30, tzinfo=pytz.UTC)))\n",
|
||||||
|
"data_processor.set_test_range((datetime(year=2023, month=1, day=1, tzinfo=pytz.UTC), np.inf))\n",
|
||||||
|
"\n",
|
||||||
|
"#### ClearML ####\n",
|
||||||
|
"clearml_helper = ClearMLHelper(project_name=\"Thesis/NrvForecast\")\n",
|
||||||
|
"\n",
|
||||||
|
"#### Trainer ####\n",
|
||||||
|
"trainer = QuantileTrainer(model, optimizer, data_processor, quantiles, \"cuda\", debug=True, clearml_helper=clearml_helper)\n",
|
||||||
|
"trainer.add_metrics_to_track([PinballLoss(quantiles), MSELoss(), L1Loss()])\n",
|
||||||
|
"trainer.early_stopping(patience=10)\n",
|
||||||
|
"trainer.plot_every(10)\n",
|
||||||
|
"trainer.train(epochs=epochs)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "base",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.10.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
||||||
59
src/trainers/autoregressive_trainer.py
Normal file
59
src/trainers/autoregressive_trainer.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from clearml import OutputModel
|
||||||
|
import torch
|
||||||
|
from data.preprocessing import DataProcessor
|
||||||
|
from utils.clearml import ClearMLHelper
|
||||||
|
from utils.autoregressive import predict_auto_regressive
|
||||||
|
import plotly.graph_objects as go
|
||||||
|
import numpy as np
|
||||||
|
import plotly.subplots as sp
|
||||||
|
from plotly.subplots import make_subplots
|
||||||
|
from trainers.trainer import Trainer
|
||||||
|
|
||||||
|
class AutoRegressiveTrainer(Trainer):
|
||||||
|
def debug_plots(self, task, train: bool, samples, epoch):
|
||||||
|
X, y = samples
|
||||||
|
X = X.to(self.device)
|
||||||
|
|
||||||
|
num_samples = len(X)
|
||||||
|
rows = num_samples # One row per sample since we only want one column
|
||||||
|
cols = 1
|
||||||
|
|
||||||
|
fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Sample {i+1}' for i in range(num_samples)])
|
||||||
|
|
||||||
|
for i, (current_day, next_day) in enumerate(zip(X, y)):
|
||||||
|
predictions = self.predict_auto_regressive(current_day)
|
||||||
|
sub_fig = self.get_plot(current_day, next_day, predictions, show_legend=(i == 0))
|
||||||
|
|
||||||
|
row = i + 1
|
||||||
|
col = 1
|
||||||
|
|
||||||
|
for trace in sub_fig.data:
|
||||||
|
fig.add_trace(trace, row=row, col=col)
|
||||||
|
|
||||||
|
loss = self.criterion(predictions.to(self.device), next_day.to(self.device)).item()
|
||||||
|
|
||||||
|
fig['layout']['annotations'][i].update(text=f"{loss.__class__.__name__}: {loss:.6f}")
|
||||||
|
|
||||||
|
# y axis same for all plots
|
||||||
|
fig.update_yaxes(range=[-1, 1], col=1)
|
||||||
|
|
||||||
|
|
||||||
|
fig.update_layout(height=300 * rows)
|
||||||
|
task.get_logger().report_plotly(
|
||||||
|
title=f"{'Training' if train else 'Test'} Samples",
|
||||||
|
series="full_day",
|
||||||
|
iteration=epoch,
|
||||||
|
figure=fig
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def predict_auto_regressive(self, initial_sequence: torch.Tensor, sequence_length: int = 96):
|
||||||
|
initial_sequence = initial_sequence.to(self.device)
|
||||||
|
|
||||||
|
return predict_auto_regressive(self.model, initial_sequence, sequence_length)
|
||||||
|
|
||||||
|
def random_day_prediction(self):
|
||||||
|
current_day_features, next_day_features = self.data_processor.get_random_test_day()
|
||||||
|
|
||||||
|
predictions = self.predict_auto_regressive(current_day_features)
|
||||||
|
return current_day_features, next_day_features, predictions
|
||||||
102
src/trainers/quantile_trainer.py
Normal file
102
src/trainers/quantile_trainer.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import torch
|
||||||
|
from utils.autoregressive import predict_auto_regressive_quantile
|
||||||
|
from scipy.interpolate import interp1d
|
||||||
|
from trainers.trainer import Trainer
|
||||||
|
from trainers.autoregressive_trainer import AutoRegressiveTrainer
|
||||||
|
from data.preprocessing import DataProcessor
|
||||||
|
from utils.clearml import ClearMLHelper
|
||||||
|
from losses import PinballLoss
|
||||||
|
from plotly.subplots import make_subplots
|
||||||
|
import plotly.graph_objects as go
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
class QuantileTrainer(AutoRegressiveTrainer):
|
||||||
|
def __init__(self, model: torch.nn.Module, optimizer: torch.optim.Optimizer, data_processor: DataProcessor, quantiles: list, device: torch.device, clearml_helper: ClearMLHelper = None, debug: bool = True):
|
||||||
|
quantiles_tensor = torch.tensor(quantiles)
|
||||||
|
quantiles_tensor = quantiles_tensor.to(device)
|
||||||
|
self.quantiles = quantiles
|
||||||
|
|
||||||
|
criterion = PinballLoss(quantiles=quantiles_tensor)
|
||||||
|
super().__init__(model=model, optimizer=optimizer, criterion=criterion, data_processor=data_processor, device=device, clearml_helper=clearml_helper, debug=debug)
|
||||||
|
|
||||||
|
def predict_auto_regressive(self, initial_sequence: torch.Tensor, sequence_length: int = 96):
|
||||||
|
initial_sequence = initial_sequence.to(self.device)
|
||||||
|
|
||||||
|
return predict_auto_regressive_quantile(self.model, self.sample_from_dist, initial_sequence, self.quantiles, sequence_length)
|
||||||
|
|
||||||
|
def log_final_metrics(self, task, dataloader, train: bool = True):
|
||||||
|
metrics = { metric.__class__.__name__: 0.0 for metric in self.metrics_to_track }
|
||||||
|
transformed_metrics = { metric.__class__.__name__: 0.0 for metric in self.metrics_to_track }
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
for inputs, targets in dataloader:
|
||||||
|
inputs, targets = inputs.to(self.device), targets
|
||||||
|
outputs = self.model(inputs)
|
||||||
|
|
||||||
|
samples = []
|
||||||
|
for output in outputs:
|
||||||
|
samples.append(self.sample_from_dist(self.quantiles.cpu().numpy(), output.cpu().numpy()))
|
||||||
|
|
||||||
|
samples = torch.tensor(samples).to(self.device).reshape(-1, 1)
|
||||||
|
|
||||||
|
inversed_samples = torch.tensor(self.data_processor.inverse_transform(samples))
|
||||||
|
inversed_targets = torch.tensor(self.data_processor.inverse_transform(targets.reshape(-1, 1)))
|
||||||
|
|
||||||
|
for metric in self.metrics_to_track:
|
||||||
|
if metric.__class__ != PinballLoss:
|
||||||
|
transformed_metrics[metric.__class__.__name__] += metric(samples, targets.view(-1, 1).to(self.device))
|
||||||
|
metrics[metric.__class__.__name__] += metric(inversed_samples, inversed_targets)
|
||||||
|
else:
|
||||||
|
transformed_metrics[metric.__class__.__name__] += metric(outputs, targets.view(-1, 1).to(self.device))
|
||||||
|
|
||||||
|
for metric in self.metrics_to_track:
|
||||||
|
metrics[metric.__class__.__name__] /= len(dataloader)
|
||||||
|
transformed_metrics[metric.__class__.__name__] /= len(dataloader)
|
||||||
|
|
||||||
|
for metric_name, metric_value in metrics.items():
|
||||||
|
if PinballLoss.__name__ in metric_name:
|
||||||
|
continue
|
||||||
|
name = f'train_{metric_name}' if train else f'test_{metric_name}'
|
||||||
|
task.get_logger().report_single_value(name=name, value=metric_value)
|
||||||
|
|
||||||
|
for metric_name, metric_value in transformed_metrics.items():
|
||||||
|
name = f'train_transformed_{metric_name}' if train else f'test_transformed_{metric_name}'
|
||||||
|
task.get_logger().report_single_value(name=name, value=metric_value)
|
||||||
|
|
||||||
|
def get_plot(self, current_day, next_day, predictions, show_legend: bool = True):
|
||||||
|
fig = go.Figure()
|
||||||
|
|
||||||
|
# Convert to numpy for plotting
|
||||||
|
current_day_np = current_day.view(-1).cpu().numpy()
|
||||||
|
next_day_np = next_day.view(-1).cpu().numpy()
|
||||||
|
predictions_np = predictions.cpu().numpy()
|
||||||
|
|
||||||
|
# Add traces for current and next day
|
||||||
|
fig.add_trace(go.Scatter(x=np.arange(96), y=current_day_np, name="Current Day"))
|
||||||
|
fig.add_trace(go.Scatter(x=96 + np.arange(96), y=next_day_np, name="Next Day"))
|
||||||
|
|
||||||
|
for i, q in enumerate(self.quantiles):
|
||||||
|
fig.add_trace(go.Scatter(x=96 + np.arange(96), y=predictions_np[:, i],
|
||||||
|
name=f"Prediction (Q={q})", line=dict(dash='dash')))
|
||||||
|
|
||||||
|
# Update the layout
|
||||||
|
fig.update_layout(title="Predictions and Quantiles of the Linear Model", showlegend=show_legend)
|
||||||
|
|
||||||
|
return fig
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sample_from_dist(quantiles, output_values):
|
||||||
|
# Interpolate the inverse CDF
|
||||||
|
inverse_cdf = interp1d(quantiles, output_values, kind='quadratic', bounds_error=False, fill_value="extrapolate")
|
||||||
|
|
||||||
|
# generate one random uniform number
|
||||||
|
uniform_random_numbers = np.random.uniform(0, 1, 1000)
|
||||||
|
|
||||||
|
# Apply the inverse CDF to the uniform random numbers
|
||||||
|
samples = inverse_cdf(uniform_random_numbers)
|
||||||
|
|
||||||
|
# Return the mean of the samples
|
||||||
|
return np.mean(samples)
|
||||||
|
|
||||||
|
|
||||||
301
src/trainers/trainer.py
Normal file
301
src/trainers/trainer.py
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
from clearml import OutputModel
|
||||||
|
import torch
|
||||||
|
from data.preprocessing import DataProcessor
|
||||||
|
from utils.clearml import ClearMLHelper
|
||||||
|
import plotly.graph_objects as go
|
||||||
|
import numpy as np
|
||||||
|
import plotly.subplots as sp
|
||||||
|
from plotly.subplots import make_subplots
|
||||||
|
|
||||||
|
class Trainer:
|
||||||
|
def __init__(self, model: torch.nn.Module, optimizer: torch.optim.Optimizer, criterion: torch.nn.Module, data_processor: DataProcessor, device: torch.device, clearml_helper: ClearMLHelper = None, debug: bool = True):
|
||||||
|
self.model = model
|
||||||
|
self.optimizer = optimizer
|
||||||
|
self.criterion = criterion
|
||||||
|
self.device = device
|
||||||
|
self.clearml_helper = clearml_helper
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
self.metrics_to_track = []
|
||||||
|
|
||||||
|
self.data_processor = data_processor
|
||||||
|
|
||||||
|
self.patience = None
|
||||||
|
self.delta = None
|
||||||
|
self.plot_every_n_epochs = 1
|
||||||
|
|
||||||
|
self.model.to(self.device)
|
||||||
|
|
||||||
|
def plot_every(self, n: int):
|
||||||
|
self.plot_every_n_epochs = n
|
||||||
|
|
||||||
|
def early_stopping(self, patience: int = 5, delta: float = 0.0):
|
||||||
|
self.patience = patience
|
||||||
|
self.delta = delta
|
||||||
|
|
||||||
|
def add_metrics_to_track(self, loss: torch.nn.Module | list[torch.nn.Module]):
|
||||||
|
if isinstance(loss, list):
|
||||||
|
self.metrics_to_track.extend(loss)
|
||||||
|
else:
|
||||||
|
self.metrics_to_track.append(loss)
|
||||||
|
|
||||||
|
def init_clearml_task(self):
|
||||||
|
if not self.clearml_helper:
|
||||||
|
return None
|
||||||
|
|
||||||
|
task_name = input("Enter a task name: ")
|
||||||
|
if task_name == "":
|
||||||
|
task_name = "Untitled Task"
|
||||||
|
task = self.clearml_helper.get_task(task_name=task_name)
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
task.add_tags('Debug')
|
||||||
|
|
||||||
|
change_description = input("Enter a change description: ")
|
||||||
|
if change_description:
|
||||||
|
task.set_comment(change_description)
|
||||||
|
|
||||||
|
task.add_tags(self.model.__class__.__name__)
|
||||||
|
task.add_tags(self.criterion.__class__.__name__)
|
||||||
|
task.add_tags(self.optimizer.__class__.__name__)
|
||||||
|
task.add_tags(self.__class__.__name__)
|
||||||
|
|
||||||
|
self.optimizer.name = self.optimizer.__class__.__name__
|
||||||
|
self.criterion.name = self.criterion.__class__.__name__
|
||||||
|
|
||||||
|
task.connect(self.optimizer, name="optimizer")
|
||||||
|
task.connect(self.criterion, name="criterion")
|
||||||
|
task.connect(self.data_processor, name="data_processor")
|
||||||
|
|
||||||
|
return task
|
||||||
|
|
||||||
|
def random_samples(self, train: bool = True, num_samples: int = 10):
|
||||||
|
random_X = []
|
||||||
|
random_Y = []
|
||||||
|
|
||||||
|
for _ in range(num_samples):
|
||||||
|
X, y = self.data_processor.get_random_day(train=train)
|
||||||
|
random_X.append(X)
|
||||||
|
random_Y.append(y)
|
||||||
|
|
||||||
|
random_X = torch.stack(random_X)
|
||||||
|
random_Y = torch.stack(random_Y)
|
||||||
|
return random_X, random_Y
|
||||||
|
|
||||||
|
def train(self, epochs: int):
|
||||||
|
train_loader, test_loader = self.data_processor.get_dataloaders(predict_sequence_length=self.model.output_size)
|
||||||
|
|
||||||
|
train_random_X, train_random_y = self.random_samples(train=True)
|
||||||
|
test_random_X, test_random_y = self.random_samples(train=False)
|
||||||
|
|
||||||
|
task = self.init_clearml_task()
|
||||||
|
|
||||||
|
self.best_score = None
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
for epoch in range(1, epochs + 1):
|
||||||
|
self.model.train()
|
||||||
|
running_loss = 0.0
|
||||||
|
|
||||||
|
for inputs, targets in train_loader:
|
||||||
|
inputs, targets = inputs.to(self.device), targets.to(self.device)
|
||||||
|
|
||||||
|
self.optimizer.zero_grad()
|
||||||
|
output = self.model(inputs)
|
||||||
|
|
||||||
|
loss = self.criterion(output, targets)
|
||||||
|
loss.backward()
|
||||||
|
self.optimizer.step()
|
||||||
|
|
||||||
|
running_loss += loss.item()
|
||||||
|
|
||||||
|
|
||||||
|
running_loss /= len(train_loader.dataset)
|
||||||
|
test_loss = self.test(test_loader)
|
||||||
|
|
||||||
|
if self.patience is not None:
|
||||||
|
if self.best_score is None or test_loss < self.best_score + self.delta:
|
||||||
|
self.save_checkpoint(test_loss, task, epoch)
|
||||||
|
counter = 0
|
||||||
|
else:
|
||||||
|
counter += 1
|
||||||
|
if counter >= self.patience:
|
||||||
|
print('Early stopping triggered')
|
||||||
|
break
|
||||||
|
|
||||||
|
if task:
|
||||||
|
task.get_logger().report_scalar(title=self.criterion.__class__.__name__, series="train", value=running_loss, iteration=epoch)
|
||||||
|
task.get_logger().report_scalar(title=self.criterion.__class__.__name__, series="test", value=test_loss, iteration=epoch)
|
||||||
|
|
||||||
|
|
||||||
|
if epoch % self.plot_every_n_epochs == 0:
|
||||||
|
self.debug_plots(task, True, (train_random_X, train_random_y), epoch)
|
||||||
|
self.debug_plots(task, False, (test_random_X, test_random_y), epoch)
|
||||||
|
|
||||||
|
if task:
|
||||||
|
self.finish_training(task=task)
|
||||||
|
task.close()
|
||||||
|
|
||||||
|
|
||||||
|
def log_final_metrics(self, task, dataloader, train: bool = True):
|
||||||
|
metrics = { metric.__class__.__name__: 0.0 for metric in self.metrics_to_track }
|
||||||
|
transformed_metrics = { metric.__class__.__name__: 0.0 for metric in self.metrics_to_track }
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
for inputs, targets in dataloader:
|
||||||
|
inputs, targets = inputs.to(self.device), targets
|
||||||
|
outputs = self.model(inputs)
|
||||||
|
|
||||||
|
inversed_outputs = torch.tensor(self.data_processor.inverse_transform(outputs))
|
||||||
|
inversed_inputs = torch.tensor(self.data_processor.inverse_transform(targets))
|
||||||
|
|
||||||
|
for metric in self.metrics_to_track:
|
||||||
|
transformed_metrics[metric.__class__.__name__] += metric(outputs, targets.to(self.device))
|
||||||
|
metrics[metric.__class__.__name__] += metric(inversed_outputs, inversed_inputs)
|
||||||
|
|
||||||
|
for metric in self.metrics_to_track:
|
||||||
|
metrics[metric.__class__.__name__] /= len(dataloader)
|
||||||
|
transformed_metrics[metric.__class__.__name__] /= len(dataloader)
|
||||||
|
|
||||||
|
for metric_name, metric_value in metrics.items():
|
||||||
|
if train:
|
||||||
|
metric_name = f'train_{metric_name}'
|
||||||
|
else:
|
||||||
|
metric_name = f'test_{metric_name}'
|
||||||
|
|
||||||
|
task.get_logger().report_single_value(name=metric_name, value=metric_value)
|
||||||
|
|
||||||
|
for metric_name, metric_value in transformed_metrics.items():
|
||||||
|
if train:
|
||||||
|
metric_name = f'train_transformed_{metric_name}'
|
||||||
|
else:
|
||||||
|
metric_name = f'test_transformed_{metric_name}'
|
||||||
|
|
||||||
|
task.get_logger().report_single_value(name=metric_name, value=metric_value)
|
||||||
|
|
||||||
|
def finish_training(self, task):
|
||||||
|
if self.best_score is not None:
|
||||||
|
self.model.load_state_dict(torch.load('checkpoint.pt'))
|
||||||
|
self.model.eval()
|
||||||
|
|
||||||
|
transformed_train_loader, transformed_test_loader = self.data_processor.get_dataloaders(predict_sequence_length=self.model.output_size)
|
||||||
|
|
||||||
|
self.log_final_metrics(task, transformed_train_loader, train=True)
|
||||||
|
self.log_final_metrics(task, transformed_test_loader, train=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test(self, test_loader: torch.utils.data.DataLoader):
|
||||||
|
self.model.eval()
|
||||||
|
test_loss = 0
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
for data, target in test_loader:
|
||||||
|
data, target = data.to(self.device), target.to(self.device)
|
||||||
|
output = self.model(data)
|
||||||
|
|
||||||
|
test_loss += self.criterion(output, target).item()
|
||||||
|
|
||||||
|
test_loss /= len(test_loader.dataset)
|
||||||
|
return test_loss
|
||||||
|
|
||||||
|
def save_checkpoint(self, val_loss, task, iteration: int):
|
||||||
|
torch.save(self.model.state_dict(), 'checkpoint.pt')
|
||||||
|
task.update_output_model(model_path='checkpoint.pt', iteration=iteration, auto_delete_file=False)
|
||||||
|
self.best_score = val_loss
|
||||||
|
|
||||||
|
def get_plot(self, current_day, next_day, predictions, show_legend: bool = True):
|
||||||
|
fig = go.Figure()
|
||||||
|
|
||||||
|
fig.add_trace(go.Scatter(x=np.arange(96), y=current_day.view(-1).cpu().numpy(), name="Current Day"))
|
||||||
|
fig.add_trace(go.Scatter(x=96 + np.arange(96), y=next_day.view(-1).cpu().numpy(), name="Next Day"))
|
||||||
|
|
||||||
|
fig.add_trace(go.Scatter(x=96 + np.arange(96), y=predictions.reshape(-1), name="Predictions"))
|
||||||
|
|
||||||
|
fig.update_layout(title="Predictions of the Linear Model")
|
||||||
|
return fig
|
||||||
|
|
||||||
|
|
||||||
|
def debug_plots(self, task, train: bool, samples, epoch):
|
||||||
|
X, y = samples
|
||||||
|
X = X.to(self.device)
|
||||||
|
|
||||||
|
num_samples = len(X)
|
||||||
|
rows = num_samples # One row per sample since we only want one column
|
||||||
|
cols = 1
|
||||||
|
|
||||||
|
fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Sample {i+1}' for i in range(num_samples)])
|
||||||
|
|
||||||
|
for i, (current_day, next_day) in enumerate(zip(X, y)):
|
||||||
|
self.model.eval()
|
||||||
|
with torch.no_grad():
|
||||||
|
predictions = self.model(current_day).cpu()
|
||||||
|
|
||||||
|
sub_fig = self.get_plot(current_day, next_day, predictions, show_legend=(i == 0))
|
||||||
|
|
||||||
|
row = i + 1
|
||||||
|
col = 1
|
||||||
|
|
||||||
|
for trace in sub_fig.data:
|
||||||
|
fig.add_trace(trace, row=row, col=col)
|
||||||
|
|
||||||
|
|
||||||
|
loss = self.criterion(predictions.to(self.device), next_day.squeeze(-1).to(self.device)).item()
|
||||||
|
|
||||||
|
fig['layout']['annotations'][i].update(text=f"{loss.__class__.__name__}: {loss:.6f}")
|
||||||
|
|
||||||
|
# y axis same for all plots
|
||||||
|
fig.update_yaxes(range=[-1, 1], col=1)
|
||||||
|
|
||||||
|
|
||||||
|
fig.update_layout(height=300 * rows)
|
||||||
|
task.get_logger().report_plotly(
|
||||||
|
title=f"{'Training' if train else 'Test'} Samples",
|
||||||
|
series="full_day",
|
||||||
|
iteration=epoch,
|
||||||
|
figure=fig
|
||||||
|
)
|
||||||
|
|
||||||
|
def debug_scatter_plot(self, task, train: bool, samples, epoch):
|
||||||
|
X, y = samples
|
||||||
|
X = X.to(self.device)
|
||||||
|
y = y.to(self.device)
|
||||||
|
y = y[:, 0]
|
||||||
|
|
||||||
|
self.model.eval()
|
||||||
|
predictions = self.model(X)
|
||||||
|
|
||||||
|
num_samples = len(X)
|
||||||
|
rows = -(-num_samples // 2) # Ceiling division to handle odd number of samples
|
||||||
|
cols = 2
|
||||||
|
|
||||||
|
fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Sample {i+1}' for i in range(num_samples)])
|
||||||
|
|
||||||
|
for i, (current_day, next_value, pred) in enumerate(zip(X, y, predictions)):
|
||||||
|
sub_fig = self.scatter_plot(current_day, pred, next_value)
|
||||||
|
row = (i // cols) + 1
|
||||||
|
col = (i % cols) + 1
|
||||||
|
for trace in sub_fig.data:
|
||||||
|
fig.add_trace(trace, row=row, col=col)
|
||||||
|
|
||||||
|
fig.update_layout(height=300 * rows)
|
||||||
|
task.get_logger().report_plotly(
|
||||||
|
title=f"{'Training' if train else 'Test'} Samples",
|
||||||
|
series="scatter",
|
||||||
|
iteration=epoch,
|
||||||
|
figure=fig
|
||||||
|
)
|
||||||
|
|
||||||
|
def scatter_plot(self, x, y, real_y):
|
||||||
|
fig = go.Figure()
|
||||||
|
|
||||||
|
# 96 values of x
|
||||||
|
fig.add_trace(go.Scatter(x=np.arange(96), y=x.view(-1).cpu().numpy(), name="Current Day"))
|
||||||
|
|
||||||
|
# add one value of y
|
||||||
|
fig.add_trace(go.Scatter(x=[96], y=[y.item()], name="Next Day"))
|
||||||
|
|
||||||
|
# add one value of real_y
|
||||||
|
fig.add_trace(go.Scatter(x=[96], y=[real_y.item()], name="Real Next Day"))
|
||||||
|
|
||||||
|
fig.update_layout(title="Predictions of the Linear Model")
|
||||||
|
return fig
|
||||||
0
src/utils/__init__.py
Normal file
0
src/utils/__init__.py
Normal file
60
src/utils/autoregressive.py
Normal file
60
src/utils/autoregressive.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import torch
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def predict_auto_regressive(model: torch.nn.Module, features: torch.Tensor, sequence_length: int = 96):
|
||||||
|
"""
|
||||||
|
Predicts the next value in a sequence using an autoregressive approach.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- model: The trained PyTorch model.
|
||||||
|
- features: Initial sequence of data with length equal to sequence_length.
|
||||||
|
- sequence_length: The length of the sequence.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- A tensor containing the predicted values.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model.eval()
|
||||||
|
predictions = []
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
for _ in range(sequence_length):
|
||||||
|
|
||||||
|
output = model(features.unsqueeze(0))
|
||||||
|
predictions.append(output.item())
|
||||||
|
|
||||||
|
features = torch.cat((features[1:], output), dim=0)
|
||||||
|
|
||||||
|
|
||||||
|
return torch.tensor(predictions).unsqueeze(-1)
|
||||||
|
|
||||||
|
def predict_auto_regressive_quantile(model: torch.nn.Module, sample_from_dist, features: torch.Tensor, quantiles: torch.Tensor, sequence_length: int = 96):
|
||||||
|
"""
|
||||||
|
Predicts the next value in a sequence using an autoregressive approach.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- model: The trained PyTorch model.
|
||||||
|
- features: Initial sequence of data with length equal to sequence_length.
|
||||||
|
- sequence_length: The length of the sequence.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- A tensor containing the predicted values.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model.eval()
|
||||||
|
predictions = []
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
for _ in range(sequence_length):
|
||||||
|
output = model(features.unsqueeze(0))
|
||||||
|
|
||||||
|
predictions.append(output.squeeze(0))
|
||||||
|
|
||||||
|
sample = sample_from_dist(quantiles.cpu().numpy(), output.squeeze(0).cpu().numpy())
|
||||||
|
|
||||||
|
features = torch.cat((features[1:], torch.tensor(sample,).to("cuda").unsqueeze(0).unsqueeze(0)), dim=0)
|
||||||
|
features = features.float()
|
||||||
|
|
||||||
|
return torch.stack(predictions)
|
||||||
|
|
||||||
8
src/utils/cdf_pdf.py
Normal file
8
src/utils/cdf_pdf.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
# Given lists of quantiles and their corresponding probabilities
|
||||||
|
quantiles = [-0.23013, -0.19831, -0.15217, -0.13654, -0.05726,
|
||||||
|
0.011687, 0.015129, 0.043187, 0.047704]
|
||||||
|
probs = [0.025, 0.05, 0.1, 0.15, 0.5, 0.85, 0.9, 0.95, 0.975]
|
||||||
|
|
||||||
10
src/utils/clearml.py
Normal file
10
src/utils/clearml.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from clearml import Task
|
||||||
|
|
||||||
|
class ClearMLHelper:
|
||||||
|
def __init__(self, project_name: str):
|
||||||
|
self.project_name = project_name
|
||||||
|
|
||||||
|
def get_task(self, task_name: str = "Model Training"):
|
||||||
|
task = Task.init(project_name=self.project_name, task_name=task_name, continue_last_task=False)
|
||||||
|
task.set_base_docker(f"pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime")
|
||||||
|
return task
|
||||||
Reference in New Issue
Block a user