Sunteți pe pagina 1din 349

Sisteme de Recunoaștere a Formelor

(Pattern Recognition, Machine Learning & Data Mining)


Curs 01 – Introducere și Concepte de Bază Python
prof. dr. ing. Robert Győrödi
Introducere
https://martechtoday.com/how-visual-recognition-is-set-to-change-advertising-223719
https://lotustech.io/applications-lotusx/case-study-1/

• Machine Learning a devenit o unealtă importantă pentru o


multitudine de discipline științifice
• Abordările bazate pe antrenare substituie rapid metodele
tradiționale manuale
• Bazat pe antrenare = arătăm exemple a ce este interesant și
sperăm că mașina învață să facă acel lucru în locul nostru
• Bazat pe model = am ajuns la un model al datelor și dorim să
învățăm parametri necunoscuți
• Câteva domenii de cercetare moderne:
– Recunoașterea imaginilor (ce este în această imagine și unde?)
– Recunoașterea vorbirii (ce spun?)
– Medicină (diagnoză pe baza datelor) Price et al., “Highly accurate two-gene classifier
for differentiating gastrointestinal stromal
tumors and leiomyosarcomas”, PNAS 2007.
De ce Python?
• Python devine din ce în ce mai mult o unealtă
esențială pentru data science
• Nu era așa tot timpul: acum 10 ani toată lumea
folosea Matlab
• Totuși, datorită problemelor de licențiere și
dezvoltării susținute a Python, Python a început
să crească în preferințele utilizatorilor
• Puterea Python constă în marea sa variabilitate și
existența unei comunități foarte mari
https://polygraph-cool.github.io/kaggle_survey/#how
• Există două versiuni: Python 2.x (2.7) și 3.x
(3.7/8/9)
Alternative la Python
• Matlab este #1 pentru algebră liniară • R a fost #1 pentru statistică și analiza
• Matlab este un produs întreținut în datelor
mod profesional • R este bun pentru nevoi specifice de
• Unele toolbox-uri Matlab sunt foarte analiza datelor și vizualizare
bune (Image Processing). Altele sunt • Mult cod scris în R de către
depășite (Neural Network) comunitatea de statisticieni
• Apar versiuni noi de două ori pe an. • Python se interfațează cu alte domenii
Cantitatea de noutate variază variind de la rețele neuronale profunde
• Matlab este costisitor pentru utilizatori (Tensorflow, pyTorch) și analiza
din afara învățământului imaginilor (OpenCV) până la un server
web (Django/Flask)
”Matlab este făcut pentru matematicieni, R pentru statisticieni iar
Python pentru programatori.”
Module esențiale
• numpy: nivelul de analiză matricială / numerică
• scipy: utilitare pentru calcule științifice (linalg, FFT, procesare
semnale/imagini ...)
• scikit-learn: machine learning
• scikit-image: procesare de imagini
• matplotlib: grafice și vizualizare
• opencv-python: vedere artificială (computer vision)
• pandas: analiză de date
• statsmodels: statistică
• Tensorflow, keras: învățare profundă (deep learning)
• PyCharm: editor (IDE)
• spyder: Scientific Python Development EnviRonment (alt editor)
Ce folosim pentru dezvoltare?
• Există mai multe opțiuni pentru dezvoltare:
– Folosind un editor de texte simplu
– Folosind un IDE:
• Spyder (vine cu Anaconda, dar se poate instala și separat)
• PyCharm (Community sau Edu este gratuit)
• IDLE (vine cu Python de la python.org)
• Visual Studio Code (+ plugin-uri pentru Python)
• Jupyter Lab / Notebook (asta vom folosim la curs)
• Altele ...
De unde instalăm Python? v1 Windows
• O opțiune ar fi să instalați Python de la:
– https://www.python.org/downloads/
– Preferabil versiunea x86-x64 (care s-ar putea să nu fie cea implicită, de ex. python-3.8.8-amd64.exe)
• Pentru Windows, la instalare alegeți următoarele:
– Pe prima pagină a programului de instalare:
• Instalați launcher pentru toți utilizatorii, Adăugare Python la PATH, Instalare personalizată
– Pe pagina Optional Features: selectați toate componentele opționale
– Pe pagina Advanced Options: selectați instalare pentru toți utilizatorii
– Pe pagina Setup was succesful, opțional puteți dezactiva limitarea lungimii căilor (recomandat)
• Din linia de comandă în mod administrator
– Actualizați pip la ultima versiune:
• python -m pip install --upgrade pip
– Instalați uneltele pentru spațiul virtual:
• pip install wheel
• pip install virtualenv virtualenvwrapper-win
• Preferabil ar fi să definim, într-o variabilă de mediu, o cale unde vom stoca spațiile virtuale de lucru, implicit acesta este:
– WORKON_HOME=%USERPROFILE%\Envs

MOMENTAN VERSIUNEA MAXIMĂ SUPORTATĂ pentru CURS este 3.8.x !!!


De unde instalăm Python? v1 Linux (Ubuntu)
• Pentru Linux (Ubuntu) Python este deja instalat, dar – sudo -H pip install -r spyder-req.txt
putem încerca o actualizare de sistem – cat <<EOF >>.bashrc
– sudo apt update export PATH=/usr/local/bin:\$PATH
– sudo apt upgrade export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
• După aceasta instalăm pachetele necesare: export
– sudo apt install -y python3 VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv
– sudo apt install -y python3-pip source /usr/local/bin/virtualenvwrapper.sh
– sudo -H python3 -m pip install --upgrade pip EOF
– sudo -H pip install virtualenv virtualenvwrapper
– sudo -H pip install --ignore-installed pyzmq

• Trebuie ieșit din terminalul curent pentru a se reinițializa


variabilele de mediu

MOMENTAN VERSIUNEA MAXIMĂ SUPORTATĂ pentru CURS este 3.8.x !!!


Cum configurăm Python pentru ML? v1
• Deschidem o linie de comandă (NU POWERSHELL !!!) / shell și intrăm într-un director unde dorim să scriem cod Python
• Creăm / activăm un spațiu virtual pentru dezvoltare (de ex. cu numele ”ml”):
– mkvirtualenv ml / workon ml • Instalăm librăriile:
• Creăm un fișier requirements.txt cu librăriile necesare: – pip install -r requirements.txt
– numpy • La terminarea lucrului, putem ieși din spațiul virtual dând comanda:
– scipy – deactivate
– pandas
– matplotlib
– scikit-learn
– scikit-image
– tensorflow
– keras
– opencv-contrib-python
– jupyter
– notebook
– jupyterlab
– voila
– statsmodels
– arrow
– faker
– xlwt
– openpyxl
De unde instalăm Python? v2
• O altă opțiune ar fi să folosim distribuția Anaconda.
– https://www.anaconda.com/distribution/
– Alegeți versiunea corespunzătoare sistemului vostru, preferabil x64
• Avantajul major este ușurința lucrului cu diversele unelte și module, folosind un mediu grafic
• Instalare
– Windows:
• Pe pagina Select Installation Type, alegeți pentru Install for: ”All users”
• Pe pagina Visual Studio Code Installation, dacă nu îl aveți deja instalat și dacă doriți să îl instalați, apăsați butonul ”Install
Microsoft VSCode”
• După instalare deschideți din meniul Start ”Anaconda prompt” cu drepturi de Administrator
• Dați comanda ”conda update -n base -c defaults conda”
• Deschideți din meniul Start ”Anaconda prompt”
– Linux (Ubuntu)
• Se lansează pachetul descărcat (ex. sh Anaconda3-2020.11-Linux-x86_64.sh) și răspundeți cu ”yes” la toate întrebările ...
• Script-ul de instalare va întreba dacă doriți să instalați Microsoft Visual Studio Code, puteți să dați ”yes”
• După instalare ieșiți din terminal și deschideți un nou terminal
• Dați comanda ”conda update -n base -c defaults conda”

MOMENTAN VERSIUNEA MAXIMĂ SUPORTATĂ pentru CURS este 3.8.x !!!


Cum configurăm Python pentru ML? v2
• Deschidem o linie de comandă / shell și intrăm într-un director unde dorim să scriem cod Python
• Creăm un spațiu virtual pentru dezvoltare (de ex. cu numele ”ml”):
– conda create -n ml
• Activăm spațiul virtual:
– conda activate ml
• Instalăm librăriile necesare:
– conda install python numpy scipy pandas matplotlib scikit-learn scikit-image tensorflow keras spyder jupyter jupyterlab
• Instalăm librăriile care nu sunt disponibile prin conda:
– pip install spyder-notebook spyder-terminal spyder-unittest spyder-reports ipywidgets pyqt5==5.9.2 opencv-contrib-python
• Putem testa spațiul virtual, de ex. din Spyder (în această configurare e simplu spyder și nu spyder3 !!!):
– spyder
• La terminarea lucrului, putem ieși din spațiul virtual dând comanda:
– conda deactivate
Limbajul Python
• Pentru a urmări și testa exemplele din curs, după ce ați
instalat și configurat Python conform slide-urilor precedente,
dați următoarea comandă din linia de comandă:
jupyter-lab
• Se va crea un server local web și se va deschide automat
pagina de start.
• De aici puteți crea un nou Notebook în care să încercați codul
Limbajul Python
• Python a fost proiectat ca și un limbaj ușor de citit import math as m
• Python folosește spații (indentare) pentru a delimita
if __name__ == '__main__':
blocurile de program print("Hello Python!")
– La început probabil că nu vă va plăcea, dar mai print("This is PI: ", m.pi)
târziu probabil vă veți schimba părerea în bine!
• Toate modulele care se folosesc sunt importate cu o
declarație import
• Membri unui modul sunt referiți folosind notația dot:
– np.cos([1, 2, 3])
• Este un limbaj interpretat. De asemenea este și interactiv
cu extensiile IPython
Bazele Python – linie comandă
• Codul Python poate fi executat fie dintr-un fișier
script (*.py) sau în mod interactiv (ca și în Matlab) (ml) ml@mlvm:~$ ipython
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
Type 'copyright', 'credits' or 'license' for more information

• Pentru modul interactiv se poate executa python


IPython 7.3.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: ?range

din linia de comandă Init signature: range(self, /, *args, **kwargs)


Docstring:
range(stop) -> range object

• Alternativ, ipython (dacă este instalat) pornește


range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start

python într-un mod mai prietenos: (inclusive) to stop (exclusive) by step. range(i, j) produces i,
i+1, i+2, ..., j-1. start defaults to 0, and stop is omitted!
range(4) produces 0, 1, 2, 3. These are exactly the valid indices

– Merg completările prin TAB


for a list of 4 elements. When step is given, it specifies the
increment (or decrement).
Type: type
Subclasses:

– Sunt disponibile multe funcții utilitare (ex. ls, In [2]: print(*range(1, 7, 2))
1 3 5

pwd, cd)
– Acces la funcții magice (ex. %run, %timeit, Comanda range creează o
%edit, %paste, %pastebin) listă de întregi. Se poate
compara cu sintaxa Matlab
1:2:6
Ajutor
• Pentru fiecare comandă, aveți acces la ajutor pentru a vă reîmprospăta
memoria:
python
>>> help("".strip)
Help on built-in function strip:

strip(chars=None, /) method of builtins.str instance


Return a copy of the string with leading and trailing whitespace remove.

If chars is given and not None, remove characters in chars instead.

• În ipython, prescurtarea ? este deasemenea disponibilă


• Mulți însă preferă să folosească Google pentru ajutor - ține de obișnuința
fiecăruia
Folosirea Modulelor
• Librăriile Python sunt numite module >>> sin(pi)
Traceback (most recent call last):
• Fiecare modul trebuie să fie importat înainte File "<input>", line 1, in <module>
sin(pi)
de folosire NameError: name 'sin' is not defined
>>> from numpy import sin, pi
• Există trei alternative populare: >>> sin(pi)
1.2246467991473532e-16
– Importul întregului modul:
>>> import numpy as np
import numpy >>> np.sin(np.pi)
1.2246467991473532e-16
– Importul unor anumite funcții din modul:
>>> from numpy import *
from numpy import array, sim, cos >>> sin(pi)
1.2246467991473532e-16
– Importul tuturor funcțiilor dintr-un modul:
from numpy import *
Folosirea Modulelor
• Câteva observații: >>> import scipy
– Toate metodele suportă prescurtări >>> matfile = scipy.io.loadmat("twoClassData.mat")
Traceback (most recent call last):
import numpy as np File "<input>", line 1, in <module>
matfile = scipy.io.loadmat("twoClassData.mat")
– Câteodată import <module> dă AttributeError: module 'scipy' has no attribute 'io'
eroare, dacă defapt modulul este o
colecție de module. De exemplu,
import scipy. În locul acestuia >>> import scipy.io as sio
>>> matfile = sio.loadmat("twoClassData.mat") # Works OK
importați un anumit modul, ca de ex.
import scipy.signal
– Importarea tuturor funcțiilor dintr-un >>> from scipy.io import loadmat
>>> matfile = loadmat("twoClassData.mat") # Works OK
modul nu este recomandat, deoarece
module diferite pot conține funcții cu
același nume
NumPy
• Practic toate calculele științifice în >>> # Lista Python accepta oice tip de data
Python sunt bazate pe modulele numpy >>> v = [1, 2, 3, "hello", None]

și scipy
• NumPy oferă un tablou numeric ca și
>>> # Am dori sa numim numpy mai scurt np
>>> import numpy as np
alternativă la lista Python >>>
>>> # Definim un tablou numpy (vector):
• Tipul listă este prea generic și acceptă >>> v = np.array([1, 2, 3, 4])
>>>
orice mix de tipuri de date >>> # Obs: instructiunea de mai sus face cast
>>> # a unei liste Python la un tablou numpy
• Deși practic pentru manipulări generice, >>>
>>> # Redimensionare la o matrice 2x2
devine ineficient în calcule >>> V = np.resize(v, (2, 2))

• În schimb, tabloul NumPy este mai >>>


>>> # Inversa:
limitat și mai focusat pe calcule numerice >>> np.linalg.inv(V)
array([[-2. , 1. ],
[ 1.5, -0.5]])
Mai multe despre vectori
• np.arrange creează un tablou de tip interval (ca și 1:0.5:10 în Matlab)
>>> np.arange(1, 10, 0.5) # Argumente: (start, end, step)
array([1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5, 6. , 6.5, 7. ,
7.5, 8. , 8.5, 9. , 9.5])
>>> # De observat ca punctul final nu este inclus (spre deosebire de Matlab, unde este inclus)

• Cele mai multe funcții pe vector/matrice sunt similare celor din Matlab:
>>> np.linspace(1, 10, 5) # Argumente: (start, end, num_items)
array([ 1. , 3.25, 5.5 , 7.75, 10. ])
>>>
>>> np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
>>>
>>> np.random.randn(2, 3)
array([[-0.06274209, -1.58088495, -0.32318544],
[-0.58858417, 0.79139608, -0.17651722]])
Matrici
• O matrice este definită similar, fie specificând valorile manual sau folosind
funcții speciale
>>> # O matrice este pur si simplu un tablou de tablouri
>>> # Poate parea complicat la inceput, dar este defapt
>>> # chiar elegant pentru tablouri N-dimensionale
>>>
>>> np.array([[1, 2], [3, 4]])
array([[1, 2],
[3, 4]])
>>>
>>> from scipy.linalg import toeplitz, hilbert # S-ar putea si "...import *"
>>> toeplitz([3, 1, -2])
array([[ 3, 1, -2],
[ 1, 3, 1],
[-2, 1, 3]])
>>>
>>> hilbert(3)
array([[1. , 0.5 , 0.33333333],
[0.5 , 0.33333333, 0.25 ],
[0.33333333, 0.25 , 0.2 ]])
Produsul matricelor

• Înmulțirea matricelor
este diferită față de >>> A = np.array([[1, 2], [3, 4]])
>>> B = np.array([[5, 6], [7, 8]])
>>>
Matlab. >>> A * B # Inmultire element cu element (Matlab: A .* B)
array([[ 5, 12],
[21, 32]])

• Folosiți operatorul '@' >>>


>>> A @ B # Inmultire matrici (Python 3.5.2+)
array([[19, 22],

sau funcția >>>


[43, 50]])

>>> np.dot(A, B) # Forma functionala; alternativ: np.matmul


np.matmul array([[19, 22],
[43, 50]])
Indexarea
• Indexarea vectorilor folosește notația :
• Un exemplu în care extragem elementele selectate din vectorul 1 ... 10:
>>> x = np.arange(1, 11)
>>> x[0:8:2] # Spre deosebire de Matlab, indexarea porneste de la 0
array([1, 3, 5, 7])
>>>
>>> # Nota: pentru indexare se folosesc paranteze drepte
>>> # Nota2: operatorul : are ordinea start:end:step;
>>> # si nu start:step:end ca si in Matlab

• Punctele de început și sfârșit pot fi omise:


>>> x[5:] # Toate elementele de la al 5-lea
array([ 6, 7, 8, 9, 10])
>>> x[:5] # Toate elementele pana la al 5-lea
array([1, 2, 3, 4, 5])
>>> x[::3] # Toate elementele cu pasul 3
array([ 1, 4, 7, 10])
Indexarea
• Indicii negativi sunt numărați de la sfârșit >>> # Presupunand x = np.arange(1, 11):
>>> x[-1] # Ultimul element 10
(-1 = ultimul, -2 = penultimul, etc.): >>> x[-3:] # Ultimii 3 elementi
array([ 8, 9, 10])
>>> x[::-1] # Elementele in ordine inversa
array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])

Indici pozitivi 0 1 2 3 4 5 6 7 8 9

↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
Tablou 1 2 3 4 5 6 7 8 9 10
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
Indici negativi -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
Indexarea
• Deasemenea tablourile N-dimensionale >>> M = np.reshape(np.arange(0, 36), (6, 6))
(matrici) pot fi indexați în mod similar. >>> M
array([[ 0, 1, 2, 3, 4, 5],
Această operațiune se numește slicing și [ 6, 7, 8, 9, 10, 11],
rezultatul este un slice al matricii. [12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
• În exemplul dat, extragem elementele de [24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]])
pe rândurile 2:4 = [2,3] și coloanele 1, 2, 4 >>> M[2:4, [1,2,4]]
(cele cu roșu) array([[13, 14, 16],
[19, 20, 22]])
• De notat că primul index este cel de rând,
NU ”coordonata x”
• Această ordine este numită ”stil Fortran”
sau ”column major”, alternativa fiind ”stil
C” sau ”row major”
Indexarea
• Pentru a specifica doar indici pentru >>> M = np.reshape(np.arange(0, 36), (6, 6))
colane sau rânduri, se folosește ”:” >>> M
array([[ 0, 1, 2, 3, 4, 5],
singur [ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],

• Exemplul extrage ultimele două [18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],

rânduri [30, 31, 32, 33, 34, 35]])


>>> M[4:, :]

• M[4: , : ] se citește ”întoarce toate


array([[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]])

rândurile după al 4-lea și toate


coloanele”
• În acest caz, forme alternative ar fi:
M[-2: , : ] și M[[4,5], : ]
Tablouri N-dimensionale
• Tablourile cu dimensionalitate mai >>> # Generam un tablou aleator de "imagini":

mare sunt întâlnite frecvent în >>> A = np.random.rand(1000, 96, 128, 3)


>>>

machine learning >>> # Ce dimensiune este?


>>> A.shape
(1000, 96, 128, 3)

• De exemplu, un set de 1000 de >>>


>>> # Accesam pixel-ul de la x = 3, y = 4, canalul 2 de culoare
>>> # al celei de a 2-a imagini
imagini color de dimensiunea w x >>> A[1, 4, 3, 2]
0.3810683742273504

h = 128 x 96 este reprezentat ca și >>>


>>> # Cerem toate canalele de culoare de la acea locatie:
>>> A[1, 4, 3, :]
un tablou de 1000 x 96 x 128 x 3 array([0.51206191, 0.63510204, 0.38106837])
>>>

• Aici, dimensiunile sunt: index-ul


>>> # Cerem o imagine completa 96x128:
>>> A[1, :, :, :]
array([[[0.55218855, 0.71814744, 0.0927863 ], ...,

imaginii, coordinata y, coordinata >>>


[0.73973444, 0.50256263, 0.59729578]]])

x, canalul de culoare >>> # Notatie echivalenta mai scurta:


>>> A[1, ...]
array([[[0.55218855, 0.71814744, 0.0927863 ], ...,
[0.73973444, 0.50256263, 0.59729578]]])
Funcții
• Funcțiile sunt definite folosind cuvântul >>> # Definim prima noastra functie
cheie def >>> def hello(target):
... print("Hello " + target + "!")
• Definițiile de funcții se pot face oriunde ...
>>> hello("world")
în cod Hello world!
>>>
• Funcțiile pot fi importate în alte fișiere >>> hello("Mars")
Hello Mars!
folosind import >>>
>>> # Putem deasemenea sa definim un argument implicit:
• Argumentele funcțiilor pot fi poziționale >>> def hello(target = "world"):
... print("Hello " + target + "!")
sau denumite (vezi exemplul) ...
>>> hello()
• Argumentele denumite îmbunătățesc Hello world!
>>>
lizibilitatea și sunt utile pentru setarea >>> hello("Mars")
Hello Mars!
ultimului argument dintr-o listă lungă >>>
>>> # Putem asigna si folosind numele:
>>> hello(target = "Mars")
Hello Mars!
Funcții

• Putem folosi funcții magice, gen %timeit


>>> # Definim o functie
>>> def fibonacci(N):
... a, b = 0, 1
... while a < N:
... yield a
... a, b = b, a + b
...
>>> list(fibonacci(100))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>>
>>> %timeit fibonacci(10**4)
308 ns ± 21.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Cicluri și diverse
• Ciclurile și alte construcții >>> for lang in ['Assembler', 'Python', "Matlab", 'C++']:
... if lang in ["Assembler", "C++"]:
uzuale de programare sunt ...
...
print ("I am ok with %s." % (lang))
else:
ușor de reamintit ... print ("I love %s." % (lang))

• for poate cicla peste orice I


I
am ok with Assembler.
love Python.
iterabil, cum ar fi o listă I
I
love Matlab.
am ok with C++.
sau un fișier >>> # Citeste toate liniile unui fisier pana la capat
• În Matlab, adăugarea de valori >>>
>>> fp = open("req.txt", "r")
la un vector într-un ciclu nu >>>
>>>
lines = []
while True:
este recomandat. Vectorii ...
...
try:
line = fp.readline()
Python sunt defapt liste, astfel ...
...
if not line: # Fisierul s-a terminat
break
adăugarea nu pune probleme ...
...
lines.append(line)
except:
... # Exceptie sau fisierul s-a terminat
... break
...
>>> fp.close()
Exemplu – citirea dintr-un fișier
• În multe cazuri va trebui să citim date dintr-un fișier de tip CSV
(Comma Separated Values) folosind Python
• Există mai multe alternative:
– Scris cod de la zero pentru citire
– Folosirea unui modul care conține funcții de citire din fișiere
CSV:
• numpy.loadtxt "ID","DAX","SMI","CAC","FTSE„
"1",1628.75,1678.1,1772.8,2443.6

• numpy.genfromtxt "2",1613.63,1688.5,1750.5,2460.2
"3",1606.51,1678.6,1718,2448.2
• csv.reader "4",1621.04,1684.1,1708.1,2470.4
"5",1618.16,1686.6,1723.1,2484.7
• pandas.read_csv "6",1610.61,1671.6,1714.3,2466.8
"7",1630.75,1682.9,1734.5,2487.9
"8",1640.17,1703.6,1757.4,2508.4
"9",1635.47,1697.5,1754,2510.5
"10",1645.89,1716.3,1754.3,2497.4
Exemplu – citirea de date
• https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/datasets/EuStockMarkets.csv

import numpy as np # Altfel, impartim linia in numere


values = line.split(";")
if __name__ == "__main__":
X = [] # Liniile din fisier vor fi memorate aici # Sarim peste primul element,
# adica peste ID
# Vom folosi instructiunea Python with values = values[1:]
# Astfel nu va trebui sa inchidem explicit fisierul
# Convertim fiecare valoare de la
with open("EuStockMarkets.csv", "r") as fp: # sir la float
values = [float(v) for v in values]
# Fisierul este iterabil, deci
# putem sa il citim direct (fara # Adaugam la X
# sa folosim readline) X.append(values)

for line in fp: # La final X este o lista de liste. Convertim la


# numpy.array
# Trecem peste prima linie: X = np.array(X)
if "DAX" in line:
continue print("Toate datele au fost citite.")
print("Dimensiunea rezultatelor este %s" % (str(X.shape)))
Vizualizarea datelor
• Modulul matplotlib este o librărie pentru import matplotlib.pyplot as plt
import numpy as np
grafice
• Numele funcțiilor sunt asemănătoare celor N = 100
n = np.arange(N) # Vector [0, 1, 2, ..., N-1]
Matlab x = np.cos(2 * np.pi * n * 0.03)
x_noisy = x + 0.2 * np.random.randn(N)
• De obicei veți da ”import matplotlib.pyplot”
fig = plt.figure(figsize = [10,5])
• Alternativ, ”from matplotlib.pylab import *”
face mediul foarte similar cu Matlab plt.plot(n, x, 'r-',
linewidth = 2,
label = 'Sinusoida curata')

plt.plot(n, x_noisy, 'bo-',


markerfacecolor = "green",
label = "Sinusoida zgomotoasa")

plt.grid(True)
plt.xlabel("Timpul in $\mu$S")
plt.ylabel("Amplitudinea")
plt.title("Un grafic exemplu")
plt.legend(loc = "upper left")

plt.savefig("sinusoid.png", bbox_inches = "tight")


plt.show()
Un exemplu

• Problema: ”Sortarea peștilor care vin pe un conveior


corespunzător speciei folosind senzori optici”
Un exemplu
• Analiza problemei
– Se instalează o cameră video și se captează câteva imagini
eșantion pentru a extrage caracteristici
• Lungime
• Strălucire
• Lățime
• Numărul și forma aripioarelor
• Poziția gurii, etc.
– Acesta este setul tuturor caracteristicilor sugerate pentru a
fi explorate pentru folosirea în clasificatorul nostru!
Un exemplu
• Preprocesarea
– Folosirea unei operații de segmentare
pentru a izola peștii unii de alții și de
fundal

• Informația despre un singur pește este


trimisă la un extractor de caracteristici a
cărui scop este de a reduce datele prin
măsurarea anumitor caracteristici

• Caracteristicile sunt trimise unui clasificator


Un exemplu
• Clasificarea
– Selectăm lungimea unui pește ca o caracteristică posibilă
pentru discriminare
Un exemplu

• Concluzie:
– Lungimea este o caracteristică slabă luată separat!

• Pasul următor:
– Selectăm strălucirea ca și o posibilă caracteristică.
Un exemplu

• Avem o separare mai bună!


Un exemplu
• Relația dintre granița de decizie bazată pe prag și cost
– Mutpm granița de decizie spre valori mai mici ale
strălucirii pentru a minimiza costul (a reduce
numărul de bibani care sunt clasificați drept
somon)

• Sarcina teoriei deciziei


Un exemplu

• Adoptăm strălucirea și adăugăm lățimea peștelui


Un exemplu

• Avem o îmbunătățire
Un exemplu
• Am putea adăuga și alte caracteristici care nu sunt
corelate cu cele pe care le avem deja.
– O precauție trebuie totuși luată ca să nu reducem
performanțele prin adăugarea unor ”caracteristici
zgomotoase”
• Ideal, cea mai bună graniță de decizie ar trebui să fie cea
care oferă o performanță optimă ca cea din următoarea
figură
Un exemplu

• O separare perfectă!

• Dar ce specie e ?
Un exemplu
• Cu toate acestea, satisfacția noastră e prematură
deoarece ținta principală în proiectarea unui
clasificator este acela de a clasifica în mod corect
intrări noi!

• Problemă de generalizare!
Un exemplu

• Un model mai general, care generează erori


acceptabile!
Modelul sistemului
• Percepția
– Folosirea unui traductor (cameră
sau microfon)
– Sistemul de recunoaștere depinde
de lărgimea de bandă, distorsiunea
datorată senzitivității rezoluției
traductorului
• Segmentarea și gruparea
– Tiparele ar trebui bine separate și
nu ar trebui să se suprapună
Modelul sistemului
• Extragerea de caracteristici
– Caracteristicile discriminante
– Caracteristici invariante față de translație,
rotație și scalare
• Clasificarea
– Folosirea unui vector de caracteristici
furnizat de un extractor de caracteristici
pentru a asigna obiectul unei categorii
• Post procesare
– Exploatarea informației contextului de
intrare alta decât cea de la tiparul însuși
pentru a îmbunătăți performanțele
Ciclul de proiectare

• Colectarea datelor
• Alegerea caracteristicilor
• Alegerea modelului
• Antrenarea
• Evaluarea
• Complexitatea computațională
Ciclul de proiectare

• Colectarea datelor
– Cum putem să știm dacă
am cules un set adecvat și
reprezentativ de exemple
pentru antrenarea și
testarea sistemului?
Ciclul de proiectare

• Alegerea caracteristicilor
– Depinde de caracteristicile
domeniului problemei
– Simplu de extras, invariant
la transformări irelevante,
insensibil la zgomot
Ciclul de proiectare

• Alegerea modelului
– Nesatisfăcuți cu
performanțele sistemului
nostru de clasificare ar
trebui să testăm și alte clase
de modele
Ciclul de proiectare

• Antrenarea
– Folosirea de date pentru a
determina clasificatorul
– Există multe proceduri
diferite pentru antrenarea
clasificatorilor și pentru
alegerea modelelor
Ciclul de proiectare

• Evaluarea
– Măsurarea ratei de eroare
(sau performanței) și
trecerea de la un set de
caracteristici la un alt set
Ciclul de proiectare
• Complexitatea computațională
– Care este punctul de echilibru
între ușurința computațională
și performanță?
– Cum se scalează un algoritm
ca o funcție de numărul de
caracteristici, tipare sau
categorii?
Învățarea și Adaptarea
• Învățarea supervizată
– Un specialist din domeniu asigură o etichetă de
categorie sau cost pentru fiecare tipar din setul de
antrenare
• Învățarea nesupervizată
– Sistemul formează clustere de ”grupări naturale”
din tiparele de intrare
Prelucrarea datelor
• Încărcarea datelor
• Curățarea și manipularea datelor
• Inspectarea datelor
• Prezentarea rezultatelor ca și:
– Valori
– Foi de lucru
– Grafice
– Altele
Ce vom face?
• Vom simula datele pentru o anumită campanie de publicitate
• Creăm date, simulând faptul că pot veni într-un format care
nu este perfect sau pregătit pentru prelucrare
• Le curățăm și le încărcăm în unealta principală pe care o vom
folosi, cum ar fi DataFrame din librăria pandas
• Manipulăm datele din DataFrame
• Salvăm datele din DataFrame într-un fișier în diverse formate
• Inspectăm datele și obținem niște rezultate din ele
Pregătire notebook

• Celula #1 va specifica importurile

#1
import json
import random
from datetime import date, timedelta
import faker
Pregătirea datelor
• Structura de date:
– O listă de obiecte utilizator
– Fiecare obiect utilizator va fi legat de un număr de obiecte de campanie
• Instanțiem clasa Faker pe care o să îl utilizăm la generarea de date
#2
fake = faker.Faker()
• Generăm 1000 de nume de utilizatori
#3
usernames = set()
usernames_no = 1000

# populate the set with 1000 unique usernames


while len(usernames) < usernames_no:
usernames.add(fake.user_name())
Pregătirea datelor

• Crearea listei de utilizatori #4


def get_random_name_and_gender():
skew = .6 # 60% of users will be female
male = random.random() > skew
if male:
return fake.name_male(), 'M'
else:
return fake.name_female(), 'F'

def get_users(usernames):
users = []
for username in usernames:
name, gender = get_random_name_and_gender()
user = {
'username': username,
'name': name,
'gender': gender,
'email': fake.email(),
'age': fake.random_int(min=18, max=90),
'address': fake.address(),
}
users.append(json.dumps(user))
return users

users = get_users(usernames)
users[:3]
Pregătirea datelor

• Generarea unei #5
# campaign name format:
# InternalType_StartDate_EndDate_TargetAge_TargetGender_Currency
def get_type():
# just some gibberish internal codes

denumiri de campanie types = ['AKX', 'BYU', 'GRZ', 'KTR']


return random.choice(types)

def get_start_end_dates():
duration = random.randint(1, 2 * 365)
offset = random.randint(-365, 365)
start = date.today() - timedelta(days=offset)
end = start + timedelta(days=duration)

def _format_date(date_):
return date_.strftime("%Y%m%d")
return _format_date(start), _format_date(end)

def get_age():
age = random.randint(20, 45)
age -= age % 5
diff = random.randint(5, 25)
diff -= diff % 5
return '{}-{}'.format(age, age + diff)

def get_gender():
return random.choice(('M', 'F', 'B'))

def get_currency():
return random.choice(('GBP', 'EUR', 'USD'))

def get_campaign_name():
separator = '_'
type_ = get_type()
start, end = get_start_end_dates()
age = get_age()
gender = get_gender()
currency = get_currency()
return separator.join((type_, start, end, age, gender, currency))
Pregătirea datelor

• Generarea unui obiect campanie


#6
# campaign data:
# name, budget, spent, clicks, impressions
def get_campaign_data():
name = get_campaign_name()
budget = random.randint(10**3, 10**6)
spent = random.randint(10**2, budget)
clicks = int(random.triangular(10**2, 10**5, 0.2 * 10**5))
impressions = int(random.gauss(0.5 * 10**6, 2))
return {
'cmp_name': name,
'cmp_bgt': budget,
'cmp_spent': spent,
'cmp_clicks': clicks,
'cmp_impr': impressions
}
Pregătirea datelor

• Asamblarea datelor
#7
def get_data(users):
data = []
for user in users:
campaigns = [get_campaign_data()
for _ in range(random.randint(2, 8))]
data.append({'user': user, 'campaigns': campaigns})
return data
Curățarea datelor
• Să aruncăm o privire
#8
rough_data = get_data(users)
rough_data[:2] # let's take a peek

• Acum să începem prelucrarea


#9
data = []
for datum in rough_data:
for campaign in datum['campaigns']:
campaign.update({'user': datum['user']})
data.append(campaign)
data[:2] # let's take another peek

• Salvăm datele
#10
with open('data.json', 'w') as stream:
stream.write(json.dumps(data))
Crearea DataFrame
• Inițializăm un nou Notebook
#1
import json
import calendar
import numpy as np
from pandas import DataFrame
import arrow
import pandas as pd

• Încărcăm datele
#2
with open('data.json') as stream:
data = json.loads(stream.read())

• Creăm un DataFrame
#3
df = DataFrame(data)
df.head()
Analiza datelor
• O vedere de ansamblu asupra datelor
#4
df.count()

• Mai multe detalii


#5
df.describe()

• Cele trei campanii cu cele mai mari și mai mici bugete


#6
df.sort_values(by=['cmp_bgt'], ascending=False).head(3)

#7
df.sort_values(by=['cmp_bgt'], ascending=False).tail(3)
Decodificarea numelui de campanie
• Vom folosi metoda apply a obiectului Series
#8
def unpack_campaign_name(name):
# very optimistic method, assumes data in campaign name
# is always in good state
type_, start, end, age, gender, currency = name.split('_')
start = arrow.get(start, 'YYYYMMDD').date()
end = arrow.get(end, 'YYYYMMDD').date()
return type_, start, end, age, gender, currency

campaign_data = df['cmp_name'].apply(unpack_campaign_name)
campaign_cols = ['Type', 'Start', 'End', 'Age', 'Gender', 'Currency']
campaign_df = DataFrame(
campaign_data.tolist(), columns=campaign_cols, index=df.index)
campaign_df.head(3)

• Combinăm cele două DataFrame-uri și aruncăm o privire


#9
df = df.join(campaign_df)

#10
df[['cmp_name'] + campaign_cols].head(3)
Despachetarea datelor utilizator
• Vom folosi aceeași strategie – unpack, join, peek
#11
def unpack_user_json(user):
# very optimistic as well, expects user objects
# to have all attributes
user = json.loads(user.strip())
return [
user['username'],
user['email'],
user['name'],
user['gender'],
user['age'],
user['address'],
]

user_data = df['user'].apply(unpack_user_json)
user_cols = ['username', 'email', 'name', 'gender', 'age', 'address']
user_df = DataFrame(user_data.tolist(), columns=user_cols, index=df.index)

#12
df = df.join(user_df)

#13
df[['user'] + user_cols].head(2)
Redenumim câteva coloane
• Am putea folosi denumiri mai potrivite pentru câteva coloane

#14
better_columns = [
'cmp_name', 'Budget', 'Spent’,
'Clicks', 'Impressions’, 'user',
'Type', 'Start', 'End',
'Target Age', 'Target Gender', 'Currency',
'Username', 'Email', 'Name',
'Gender', 'Age', 'Address',
]
df.columns = better_columns
Adăugăm coloane suplimentare - măsuri
• Pentru fiecare campanie avem:
– Numărul de click-uri
– Numărul de afișări
– Suma cheltuită
• Măsuri noi: #15
– CTR – Click Through Rate def calculate_extra_columns(df):
# Click Through Rate
– CPC – Cost Per Click df['CTR'] = df['Clicks'] / df['Impressions']
# Cost Per Click

– CPI – Cost Per Impression df['CPC'] = df['Spent'] / df['Clicks']


# Cost Per Impression
df['CPI'] = df['Spent'] / df['Impressions’]

calculate_extra_columns(df)
• Să aruncăm o privire
#16
df[['Spent', 'Clicks', 'Impressions',
'CTR', 'CPC', 'CPI']].head(3)
Verificăm acuratețea pentru câteva cazuri

• Ar trebui să verificăm manual acuratețea rezultatelor


pentru un număr de cazuri
#17
clicks = df['Clicks'][0]
impressions = df['Impressions'][0]
spent = df['Spent'][0]
CTR = df['CTR'][0]
CPC = df['CPC'][0]
CPI = df['CPI'][0]
print('CTR:', CTR, clicks / impressions)
print('CPC:', CPC, spent / clicks)
print('CPI:', CPI, spent / impressions)
Mai putem adăuga câteva coloane
• Durata unei campanii
• Ziua din săptămână pentru start-ul campaniei
#18
def get_day_of_the_week(day):
number_to_day = dict(enumerate(calendar.day_name, 1))
return number_to_day[day.isoweekday()]

def get_duration(row):
return (row['End'] - row['Start']).days

df['Day of Week'] = df['Start'].apply(get_day_of_the_week)


df['Duration'] = df.apply(get_duration, axis=1)

• Verificăm rezultatele
#19
df[['Start', 'End', 'Duration', 'Day of Week']].head(3)
Curățare
• Putem deasemenea șterge câteva coloane de care nu avem nevoie
– cmp_name
– user
• Putem deasemenea reordona coloanele dintr-un DataFrame pentru a fi
mai relevante
#20
final_columns = [
'Type', 'Start', 'End', 'Duration', 'Day of Week', 'Budget',
'Currency', 'Clicks', 'Impressions', 'Spent', 'CTR', 'CPC',
'CPI', 'Target Age', 'Target Gender', 'Username', 'Email',
'Name', 'Gender', 'Age'
]
df = df[final_columns]
Salvarea DataFrame într-un fișier
• În CSV
#21
df.to_csv('df.csv')

• În JSON
#22
df.to_json('df.json')

• În Excel
#23
df.to_excel('df.xlsx')

• Puteți tasta df.to_ și apăsa TAB pentru a genera un pop up de


auto-completare, pentru a vedea toate opțiunile posibile
Vizualizarea rezultatelor
• Configurăm pandas să afișeze graficele în celule
#24
%matplotlib inline

• Aplicăm un anumit stil


#25
import matplotlib.pyplot as plt
plt.style.use(['classic', 'ggplot'])
import pylab
pylab.rcParams.update({'font.family' : 'serif'})

• Să vedem detalii despre DataFrame


#26
df.describe()
Vizualizarea rezultatelor
• Să afișăm cele patru informații pe care le avem despre fiecare campanie:
`Budget`, `Spent`, `Clicks` și `Impressions`
#27
df[['Budget', 'Spent', 'Clicks', 'Impressions']].hist(
bins=16, figsize=(16, 6));

• Puteți explica graficele rezultate?


• Să afișăm pe grafic măsurile pe care e-am calculat
#28
df[['CTR', 'CPC', 'CPI']].hist(
bins=20, figsize=(16, 6));
Să analizăm doar un segment din date
• Putem aplica o mască pe DataFrame
#29
mask = (df.Spent > 0.75 * df.Budget)
df[mask][['Budget', 'Spent', 'Clicks', 'Impressions']].hist(
bins=15, figsize=(16, 6), color='g');

• Măsurile `Spent`, `Clicks` și `Impressions` grupate pe ziua săptămânii


#30
df_weekday = df.groupby(['Day of Week']).sum()
df_weekday[['Impressions', 'Spent', 'Clicks']].plot(
figsize=(16, 6), subplots=True);
O agregare simplă
• Dorim să agregăm pe `Target Gender` și `Target Age` și să afișăm
`Impressions` și `Spent`
– Pentru ambele, dorim să vedem media `mean` și devierea standard
`std`
#31
agg_config = {
'Impressions': ['mean', 'std'],
'Spent': ['mean', 'std'],
}
df.groupby(['Target Gender', 'Target Age']).agg(agg_config)
Tabelă pivot
• Putem arăta corelarea dintre `Target Age` și `Impressions`, `Clicks` și
`Spent`, subdivizate corespunzător `Target Gender`

#32
pivot = df.pivot_table(
values=['Impressions', 'Clicks', 'Spent'],
index=['Target Age'],
columns=['Target Gender'],
aggfunc=np.sum
)
pivot
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 02 – Teoria Estimării
prof. dr. ing. Robert Győrödi
Sisteme de Recunoaștere a Formelor

• Avem două categorii mari de sisteme:


– Bazate pe modele
– Bazate pe antrenare
Teoria clasică a estimării și detecției
• Înainte de a trece efectiv la a discuta despre recunoașterea formelor / machine
learning, vom discuta despre teoria clasică a estimării
• Teoria estimării are multe legături cu fundamentele machine learning modern
• Puncte pe care le vom discuta:
– Teoria estimării:
• Fundamente
• Similaritate maximă (maximum likelihood)
• Exemple
– Teoria detecției:
• Fundamente
• Metrici pentru eroare
• Exemple
Introducere - estimare
• Scopul nostru este de a estima valorile unui grup de parametri din date
• Exemple: radar, sonar, vorbire, analiza de imagini, biomedicină, comunicații,
control, seismologie, etc.
• Estimarea parametrilor:
– Fiind dat un set de date în N puncte 𝐱 = 𝑥 0 , 𝑥 1 , … , 𝑥[𝑁 − 1] care depinde de
parametrul necunoscut 𝜃 ∈ ℝ, dorim să găsim un estimator 𝑔 ∙ pentru 𝜃
𝜃መ = 𝑔 𝑥 0 , 𝑥 1 , … , 𝑥[𝑁 − 1]
• Întrebările fundamentale sunt:
– Care este modelul pentru datele noastre?
– Cum determinăm parametri săi?
Exemplu: o linie dreaptă
• Presupunând că avem seria de timp din graficul
alăturat și am dori să aproximăm relația dintre
cele două coordinate
• Relația pare liniară, deci am putea presupune
următorul model:
𝑦 𝑛 = 𝑎𝑥 𝑛 + 𝑏 + 𝑤 𝑛 ,
cu 𝑎 ∈ ℝ și 𝑏 ∈ ℝ necunoscute și
𝑤 𝑛 ~𝒩 0, 𝜎 2
• 𝒩 0, 𝜎 2 este distribuția normală cu media 0
și varianța 𝜎 2
Exemplu: o linie dreaptă

• Fiecare pereche de a și b
reprezintă o linie
• Care linie din cele trei ar descrie
cel mai bine setul de date?
• Sau oare altă linie ar fi mai
potrivită?
Exemplu: o linie dreaptă
• Poate fi arătat că cea mai bună soluție (în sensul celei mai bune
similitudini – definit mai târziu) este dată de:
𝑁−1 𝑁−1
6 12
𝑎ො = − ෍𝑦 𝑛 + ෍𝑥 𝑛 𝑦 𝑛
𝑁 𝑁+1 𝑁 𝑁2 − 1
𝑛=0 𝑛=0
𝑁−1 𝑁−1
2 2𝑁 − 1 6
𝑏෠ = ෍𝑦 𝑛 − ෍𝑥 𝑛 𝑦 𝑛
𝑁 𝑁+1 𝑁 𝑁+1
𝑛=0 𝑛=0
• Sau, așa cum vom vedea mai târziu, într-o formă matricială ușor de înțeles:
෡ = 𝑎ො = 𝐗 𝑇 𝐗 −1 𝐗 𝑇 𝐲
Θ
𝑏෠
Exemplu: o linie dreaptă

• În acest caz, 𝑎ො = 0.07401 și 𝑏෠ =


0.49319, care produce linia din
graficul din dreapta
• Linia de asemenea minimizează
pătratul distanțelor (liniile verzi
întrerupte) între model (linia
albastră) și date (puncte roșii)
Exemplu: sinusoidă

• Considerăm transmiterea sinusoidei de mai jos


Exemplu: sinusoidă
• Când datele sunt recepționate, ele sunt corupte de
zgomot și eșantioanele recepționate arată ca mai jos:

• Putem oare să regăsim parametri sinusoidei?


Exemplu: sinusoidă

• În acest caz, problema este de a găsi valori potrivite


pentru 𝐴, 𝑓0 și 𝜙 din următorul model:
𝑥 𝑛 = 𝐴 cos 2𝜋𝑓0 𝑛 + 𝜙 + 𝑤 𝑛 ,
cu 𝑤 𝑛 ~𝒩 0, 𝜎 2
Exemplu: sinusoidă
• Poate fi arătat că estimatorul de similaritate maximă (MLE – Maximum
Likelihood Estimator) pentru parametri 𝐴, 𝑓0 și 𝜙 sunt date de:
𝑁−1

𝑓መ0 = 𝑣𝑎𝑙𝑜𝑟𝑒𝑎 𝑓 𝑐𝑎𝑟𝑒 𝑚𝑎𝑥𝑖𝑚𝑖𝑧𝑒𝑎𝑧ă ෍ 𝑥 𝑛 𝑒 −2𝜋𝑖𝑓𝑛


𝑛=0
𝑁−1
2 መ
𝐴መ = ෍ 𝑥 𝑛 𝑒 −2𝜋𝑖𝑓0𝑛
𝑁
𝑛=0
− σ𝑁−1 መ
𝑛=0 𝑥 𝑛 sin 2𝜋 𝑓0 𝑛
𝜙෠ = arctan 𝑁−1
σ𝑛=0 𝑥 𝑛 cos 2𝜋𝑓መ0 𝑛
Exemplu: sinusoidă
• Se pare că estimarea parametrilor sinusoidei este cu succes:
𝑓መ0 = 0.068 0.068 ; 𝐴መ = 0.692 0.667 ; 𝜙෠ = 0.238 0.609

• Curba albastră este sinusoida originală, iar curba roșie este cea
estimată de punctele verzi
• Estimările sunt prezentate mai sus (valorile reale fiind în paranteze)
Exemplu: sinusoidă
• Cu toate acestea, rezultatele sunt diferite pentru fiecare valoare a zgomotului 𝑤 𝑛
Exemplu: sinusoidă
• Astfel, nu suntem interesați într-un caz individual, ci de
distribuția estimărilor
– Care sunt așteptările: 𝐸 𝑓መ0 , 𝐸 𝜙෠ și 𝐸 𝐴መ ?
– Care sunt varianțele lor?
– Poate exista o formulă mai bună care ar da o varianță
mai mică?
– Dacă da, cum putem determina estimatorii mai buni?
PROBABILITATE/SIMILARITATE MAXIMĂ
(MAXIMUM LIKELIHOOD)
Estimarea probabilității maxime
• Probabilitatea maximă (MLE) este cea mai populară abordare pentru
estimare datorită aplicabilității sale în probleme de estimare complexe
• Maximizarea probabilității apare deseori ca și criteriu optimal în machine
learning
• Metoda a fost propusă de Fisher în 1922, deși el a publicat principiul de
bază deja în 1912 ca și student în anul 3
• Principiul de bază este simplu: găsim parametrul 𝜃 care este cel mai
probabil să genereze instanța x
• Estimatorul MLE poate sau nu să fie optimal în sensul varianței minime. Nu
este neapărat nici imparțial
Funcția de probabilitate
• Să considerăm din nou problema estimării nivelului mediu A al datelor
zgomotoase
• Presupunem că datele provin din următorul model:
𝑥 𝑛 =𝐴+𝑤 𝑛 ,
unde 𝑤 𝑛 ~𝒩 0, 𝜎 2 : este constant plus un zgomot aleator cu medie
zero și varianță 𝜎 2
Funcția de probabilitate
• Cheia pentru probabilitatea maximă este funcția de
probabilitate (likelihood function)
• Dacă funcția de densitatea a probabilității (PDF) a datelor este
privită ca și o funcție a parametrului necunoscut (cu date fixe),
acesta este numit funcție de probabilitate
• Deseori funcția de probabilitate are o formă exponențială. În
acest sens este uzual să se aplice logaritmul natural pentru a
scăpa de exponent. De notat că maximul noii funcții log-
likelihood (probabilitate logoritmică) nu se schimbă
Funcția de probabilitate

PDF al A presupunând x[0] = 3


Exemplu MLE
• În cazul nostru de estimare a mediei unui semnal:
𝑥 𝑛 =𝐴+𝑤 𝑛 , 𝑛 = 0, 1, … , 𝑁 − 1,
funcția de probabilitate este ușor de construit
• Eșantioanele de zgomot 𝑤 𝑛 ~𝒩 0, 𝜎 2 sunt presupus a fi
independente, astfel PDF-ul întregului lot de eșantioane 𝐱 =
𝑥 0 , … , 𝑥 𝑁 − 1 este obținut prin regula produs:
𝑁−1 𝑁−1
1 1 2
𝑝 𝐱; 𝐴 = ෑ 𝑝 𝑥 𝑛 ; 𝐴 = 𝑁 exp − 2𝜎 2 ෍ 𝑥 𝑛 − 𝐴
𝑛=0 2𝜋𝜎 2 2 𝑛=0
Exemplu MLE
• După ce avem datele x, putem reformula problema și
considera care este cel mai probabil parametru A care a
generat datele
• Unii autori scot în evidență acest lucru prin inversarea
ordinii: 𝑝 𝐴; 𝐱 sau prin schimbarea denumirii funcției la
𝐿 𝐴; 𝐱 sau ℓ 𝐴; 𝐱
• Astfel, putem considera 𝑝 𝐱; 𝐴 ca și o funcție de A și am
putea să o maximizăm
Exemplu MLE
• Figura de mai jos arată funcția de probabilitate și funcția
logaritmică de probabilitate pentru un posibil set de date
• Datele constau din 50 de puncte, cu A original 5
• Funcția de probabilitate dă probabilitatea observării
acestor puncte pentru valori diferite ale lui A
Exemplu MLE
• În loc să găsim maximul din grafic, am dori să avem o soluție cu formă
închisă
• Forma închisă este mai rapidă, mai elegantă, mai exactă și numeric mai
stabilă
• Doar pentru exemplu, avem cod pentru o versiune foarte simplificată
# Exemplele sunt intr-un tablou numit x0

x = np.linspace(2, 8, 200)
likelihood = []
log_likelihood = []

for A in x:
likelihood.append(gaussian(x0, A, 1).prod())
log_likelihood.append(gaussian_log(x0, A, 1).sum())

print("Max likelihood este la %.2f" % (x[np.argmax(log_likelihood)]))


Exemplu MLE
• Maximizarea directă a este dificilă. Astfel, aplicăm logaritm și îl maximizăm pe
acesta:
𝑁−1
1 1 2
𝑝 𝐱; 𝐴 = 𝑁 exp − 2 ෍ 𝑥 𝑛 −𝐴
2𝜎
2𝜋𝜎 2 2 𝑛=0
𝑁−1
𝑁 2
1 2
ln 𝑝 𝐱; 𝐴 = − ln 2𝜋𝜎 − 2 ෍ 𝑥 𝑛 − 𝐴
2 2𝜎
𝑛=0
• Maximul este găsit aplicând diferențiala:
𝑁−1
𝛿 ln 𝑝 𝐱; 𝐴 1
= 2 ෍ 𝑥 𝑛 −𝐴
𝛿𝐴 𝜎
𝑛=0
Exemplu MLE
• Egalând expresia cu zero ne dă:
𝑁−1
1
෍ 𝑥 𝑛 −𝐴 =0
𝜎2
𝑛=0
𝑁−1

෍ 𝑥 𝑛 −𝐴 =0
𝑛=0
𝑁−1 𝑁−1

෍𝑥 𝑛 −෍𝐴=0
𝑛=0 𝑛=0
𝑁−1

෍ 𝑥 𝑛 − 𝑁𝐴 = 0
𝑛=0
𝑁−1

෍ 𝑥 𝑛 = 𝑁𝐴
𝑛=0
𝑁−1
1
𝐴= ෍𝑥 𝑛
𝑁
𝑛=0
Concluzie
• Ce anume am realizat?
– Am demonstrat că media exemplelor este estimatorul de
probabilitate maximă pentru media distribuției
• Dar am fi putut ghici acest rezultat de la început. Deci care
este rostul?
– Putem face același lucru pentru cazurile unde nu putem
ghici de la început
Exemplu: estimarea parametrilor sinusoidei
• Considerăm modelul:
𝑥 𝑛 = 𝐴 cos 2𝜋𝑓0 𝑛 + 𝜙 + 𝑤 𝑛

cu 𝑤 𝑛 ~𝒩 0, 𝜎 2 . Este posibil să găsim MLE pentru toți trei parametri:


𝜽 = 𝐴, 𝑓0 , 𝜙 𝑇

• PDF-ul este dat ca și:


𝑁−1
1 1 2
𝑝 𝐱; 𝜽 = 𝑁 exp − 2
෍ 𝑥 𝑛 − 𝐴 cos 2𝜋𝑓0 𝑛 + 𝜙
2𝜎
2𝜋𝜎 2 2 𝑛=0 𝑤𝑛
Exemplu: estimarea parametrilor sinusoidei
• În loc să continuăm cu funcția de probabilitate logaritmică,
observăm că funcția de mai înainte este maximizată când:
𝑁−1

𝐽 𝐴, 𝑓0 , 𝜙 = ෍ 𝑥 𝑛 − 𝐴 cos 2𝜋𝑓0 𝑛 + 𝜙 2

𝑛=0
este minimizat
• Minimul acestei funcții poate fi găsit, deși nu este foarte simplu.
• Trecem peste partea de derivare, dar pentru detalii puteți consulta
Kay și alții ”Statistical Signal Processing: Estimation Theory” 1993
Exemplu: estimarea parametrilor sinusoidei
• MLE-ul frecvenței 𝑓0 este obținută prin maximizarea periodogramei peste 𝑓0 :
𝑁−1

𝑓መ0 = arg 𝑚𝑎𝑥𝑓 ෍ 𝑥 𝑛 exp −𝑗2𝜋𝑓𝑛


𝑛=0
• Odată ce 𝑓መ0 este disponibil, continuăm prin calcularea celorlalți parametri:
𝑁−1
2

𝐴= ෍ 𝑥 𝑛 exp −𝑗2𝜋𝑓መ0 𝑛
𝑁
𝑛=0
σ𝑁−1 መ
𝑛=0 𝑥 𝑛 sin 2𝜋𝑓0 𝑛

𝜙 = arctan − 𝑁−1
σ𝑛=0 𝑥 𝑛 cos 2𝜋𝑓መ0 𝑛
Experimente – estimarea parametrilor sinusoidei

• Patru rulări ale algoritmului de estimare


sunt ilustrate în figuri
• Algoritmul a fost testat deasemenea
pentru 10000 de puncte a unei
sinusoide cu 𝜽 fix și 𝑁 = 160, 𝜎 2 = 1.2
• De notat că estimatorul nu este
imparțial
Sumar – Teoria estimării
• Am tratat pe scurt teoria estimării cu accent pe probabilitatea maximă
• Dacă problema de rezolvat este destul de simplă pentru a fi modelată de o
ecuație, atunci răspunsul este teoria estimării
– Estimarea frecvenței unei sinusoide este rezolvată de teoria clasică
– Estimarea vârstei unei persoane dintr-o poză nu poate fi modelat așa
de simplu și astfel teoriile clasice nu sunt o soluție
• Estimările bazate pe model sunt răspunsul cel mai bun atunci când există
un model
• Machine Learning poate fi privit ca și o abordare bazată pe date
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 03 – Teoria Detecției
prof. dr. ing. Robert Győrödi
Sumar
• În acest curs vom discuta despre teoria detecției
• Teoria detecției are multe părți comune cu machine learning
• Metodele sunt bazate pe teoria estimării și încearcă să răspundă la întrebări de genul:
– Este oare un semnal cu un model specific prezent în seria noastră de timp? Ex.
detectarea unei sinusoide zgomotoase; beep sau fără beep?
– Este oare pulsul transmis prezent în semnalul de radar la momentul t?
– Oare media unui semnal se schimbă la momentul t?
– După calcularea schimbării medii în valorile pixelilor în cadre succesive din video, este
oare ceva care se mișcă în scenă?
– Există oare o persoană în acest cadru din video?
• Aria este înrudită cu testarea ipotezelor, care este folosit pe scară largă de ex. în medicină:
Oare răspunsul pacienților este datorat noului medicament sau unei fluctuații aleatoare?
Teoria detecției

• Vom considera detecția următoarei forme de undă


Teoria detecției
• În cazul nostru, ipotezele ar putea fi următoarele:

ℋ1 : 𝑥 𝑛 = 𝐴 cos 2𝜋𝑓0 + 𝜙 + 𝑤 𝑛
ℋ0 : 𝑥 𝑛 = 𝑤 𝑛

• Acest exemplu corespunde detecției unei sinusoide zgomotoase


• Ipoteza H1 corespunde cazului în care sinusoida este prezentă și este
numită ipoteza alternativă
• Ipoteza H0 corespunde cazului în care măsurătorile constau doar din
zgomot și este numită ipoteza nulă
Un exemplu
• Considerăm o problemă simplă de detecție, unde observăm un singur
eșantion x[0] din una din două densități: 𝒩 0,1 sau 𝒩 1,1
• Problema este să alegem densitatea corectă într-o manieră optimă
Un exemplu
• Ipotezele sunt:
ℋ1 : 𝜇 = 1
ℋ0 : 𝜇 = 0
iar probabilitățile corespunzătoare sunt trasate mai jos.
Un exemplu
• O abordare evidentă pentru a decide densitatea ar alege pe cea care este mai
mare pentru un anumit x[0]
• Mai concret, studiem probabilitățile și alegem pe cel mai probabil
• Probabilitățile sunt
1 𝑥 0 −1 2
ℋ1 : 𝑝 𝑥 0 𝜇 = 1 = 𝑒𝑥𝑝 −
2𝜋 2
1 𝑥0 2
ℋ0 : 𝑝 𝑥 0 𝜇 = 0 = 𝑒𝑥𝑝 −
2𝜋 2
• Trebuie să selectăm ℋ1 dacă ”𝜇 = 1” este mai probabil decât ”𝜇 = 0”
• Cu alte cuvinte, 𝑝 𝑥 0 𝜇 = 1 > 𝑝 𝑥 0 𝜇 = 0
Un exemplu
• Să exprimăm asta în termeni de x[0]:
𝑝 𝑥 0 𝜇=1 >𝑝 𝑥 0 𝜇=0
𝑝 𝑥 0 𝜇 =1
 >1
𝑝 𝑥 0 𝜇 =0
1 𝑥 0 −1 2
𝑒𝑥𝑝 −
 2𝜋 2
1 𝑥0 2
>1
𝑒𝑥𝑝 − 2
2𝜋
𝑥 0 −1 2 −𝑥 02
 𝑒𝑥𝑝 − >1
2
Un exemplu
 𝑥 0 2− 𝑥 0 −1 2 >0
 2𝑥 0 − 1 > 0
1
𝑥0 >
2
• Cu alte cuvinte, alegem ℋ1 dacă 𝑥 0 > 0.5 și ℋ0 dacă 𝑥 0 < 0.5
• Studiul raportului probabilităților este cheia:
𝑝 𝑥 0 𝜇=1
>1
𝑝 𝑥 0 𝜇=0
• Acest raport este numit ”likelihood ratio” și comparația cu un prag (aici
𝛾 = 1) este numit ”likelihood ratio test” (LRT)
• Desigur pragul de detecție 𝛾 poate și ales și altceva decât 𝛾 = 1
Tipuri de erori

• Pot exista cazuri în care problema detecției nu este


simetrică și anumite erori sunt mai costisitoare decât
altele
• De exemplu, când detectăm o boală, o detecție ratată
este mai costisitoare decât o alarmă falsă
• Compromisul dintre ratări și alarme false poate fi
ajustat folosind pragul pentru LRT
Tipuri de erori
• Figura de mai jos ilustrează probabilitățile celor două tipuri de erori
• Zona albastră din stânga corespunde probabilității alegerii ℋ1 când de fapt
ℋ0 este adevărat (detecție falsă)
• Zona roșie este probabilitatea alegerii ℋ0 când de fapt ℋ1 este adevărat
(detecție ratată)
Tipuri de erori
• Poate fi observat că putem scădea oricare probabilitate prin ajustarea
pragului de detecție
Tipuri de erori
• De exemplu, presupunând că pragul este 𝛾 = 1.5. Cât sunt PFA și PD?
• Probabilitatea alarmelor false este găsită prin integrarea peste zona albastră:

1 𝑥0 2
𝑃𝐹𝐴 = 𝑃 𝑥 0 > 𝛾 𝜇 = 0 = න 𝑒𝑥𝑝 − ⅆ𝑥 0 ≈ 0.0668
1.5 2𝜋 2
• Probabilitatea detecțiilor ratate este zona marcată cu roșu:
1.5
1 𝑥 0 −1 2
𝑃𝑀 = 𝑃 𝑥 0 < 𝛾 𝜇 = 1 = න 𝑒𝑥𝑝 − ⅆ𝑥 0 ≈ 0.6915
−∞ 2𝜋 2
• Un termen echivalent, dar mai folositor este complementul lui PM: probabilitatea
detecției

1 𝑥 0 −1 2
𝑃𝐷 = 1 − 𝑃𝑀 = න 𝑒𝑥𝑝 − ⅆ𝑥 0 ≈ 0.3085
1.5 2𝜋 2
Alegerea pragului
• Adesea nu dorim să alegem pragul, ci mai degrabă cantitatea de alarme
false pe care o acceptăm
• De exemplu, presupunem că dorim să găsim cel mai bune detector pentru
exemplul nostru și putem tolera 10% alarme false (PFA = 0.1)
• Regula raportului de probabilitate a detecției este:
𝑝 𝑥𝜇 =1
Selectează ℋ1 dacă >𝛾
𝑝 𝑥𝜇 =0
• Singurul lucru care trebuie să îl găsim este pragul 𝛾 astfel încât

න 𝑝 𝑥 𝜇 = 0 ⅆ𝑥 = 0.1
𝛾
Alegerea pragului
• Acest lucru poate fi făcut cu funcția Python isf, care
rezolvă funcția de distribuție cumulativă inversă
import scipy.stats as stats
# Calculeaza pragul astfel incat P_FA = 0.1
T = stats.norm.isf(0.1, loc = 0, scale = 1)
print T
1.28155156554

• Parametri loc și scale sunt respectiv media și


devierea standard a densității Gaussiene
Detector pentru o formă de undă cunoscută
• Un caz special important este acela a unei forme de unde cunoscute s[n] incorporate în
secvența WGN w[n] (WGN – White Gaussian Noise)
ℋ1 : 𝑥 𝑛 = 𝑠 𝑛 + 𝑤 𝑛
ℋ0 : 𝑥 𝑛 = 𝑤 𝑛
• Un exemplu de caz unde forma de undă este cunoscută, poate fi detecția semnalelor radar,
unde un puls s[n] transmis de noi este reflectat înapoi după un anumit timp de propagare
Detector pentru o formă de undă cunoscută
• Pentru acest caz probabilitățile sunt
𝑁−1
2
1 𝑥 𝑛 −𝑠 𝑛
𝑝 x ℋ1 ෑ 𝑒𝑥𝑝 −
2𝜋𝜎 2 2𝜎 2
𝑛=0
𝑁−1
2
1 𝑥𝑛
𝑝 x ℋ0 ෑ 𝑒𝑥𝑝 −
2𝜋𝜎 2 2𝜎 2
𝑛=0
• Testul raportului de probabilități este obținut ușor
𝑁−1 𝑁−1
𝑝 x ℋ1 1 2 2
= 𝑒𝑥𝑝 − 2 ෍ 𝑥 𝑛 − 𝑠 𝑛 −෍ 𝑥𝑛 >𝛾
𝑝 x ℋ0 2𝜎
𝑛=0 𝑛=0
Detector pentru o formă de undă cunoscută

• Putem simplifica prin logaritmare în ambele părți


𝑁−1 𝑁−1
1 2 2
− 2 ෍ 𝑥 𝑛 −𝑠 𝑛 −෍ 𝑥𝑛 > ln 𝛾
2𝜎
𝑛=0 𝑛=0
• Mai departe se simplifică în
𝑁−1 𝑁−1
1 1 2
2
෍𝑥 𝑛 𝑠 𝑛 − 2෍ 𝑠 𝑛 > ln 𝛾
𝜎 2𝜎
𝑛=0 𝑛=0
Detector pentru o formă de undă cunoscută
• Deoarece s[n] este o formă de undă cunoscută (= constantă), putem
simplifica procedura prin trecerea în partea dreaptă și combinarea cu
pragul
𝑁−1 𝑁−1
1
෍ 𝑥 𝑛 𝑠 𝑛 > 𝜎 2 ln 𝛾 + ෍ 𝑠𝑛 2
2
𝑛=0 𝑛=0
• Putem numi în mod echivalent partea dreaptă ca și pragul nostru (să
spunem 𝛾 ′ ) pentru a ajunge la regula de decizie finală
𝑁−1

෍ 𝑥 𝑛 𝑠 𝑛 > 𝛾′
𝑛=0
Un alt exemplu
• Detectorul pentru un sinusoidal în WGN este:
𝑁−1 𝑁−1

෍ 𝐴 cos 2𝜋𝑓0 + 𝜙 + 𝑤 𝑛 > 𝛾 ⟹ 𝐴 ෍ cos 2𝜋𝑓0 + 𝜙 + 𝑤 𝑛 > 𝛾


𝑛=0 𝑛=0
• Din nou împărțim cu A pentru a obține
𝑁−1

෍ 𝐴 cos 2𝜋𝑓0 + 𝜙 + 𝑤 𝑛 > 𝛾′


𝑛=0
• Cu alte cuvinte, verificăm corelarea cu sinusoida. De notat că amplitudinea
A nu afectează statistica noastră, doar pragul, care este oricum selectat
conform raportului fixat PFA
Un alt exemplu
• Ca și exemplu, figura arată
procesul de detecție cu
𝜎 = 0.5
• De notat că aplicăm
detectorul cu o fereastră
glisantă, adică efectuăm
testul de ipoteză la fiecare
fereastră de lungime 100
Detecția unor semnale aleatorii
• Problema cu abordarea anterioară era că modelul era prea restrictiv,
rezultatele depindeau de cât de bine se potriveau fazele
• Modelul poate fi relaxat prin considerarea unor semnale aleatorii, a căror
formă exactă este necunoscută, dar structura de corelare este cunoscută. Din
moment ce corelarea captează frecvența (dar nu și faza), acesta este exact
ceea ce ne dorim.
• În general, detectarea unui semnal aleatoriu poate fi formulată în felul
următor.
• Presupunând 𝐬~𝒩 0, 𝐂𝑆 și 𝐰~𝒩 0, 𝜎 2 𝐈 . Atunci problema detecției este un
test de ipoteză:
ℋ0 : 𝐱~𝒩 0, 𝜎 2 𝐈
ℋ1 : 𝐱~𝒩 0, 𝐂𝑆 + 𝜎 2 𝐈
Detecția unor semnale aleatorii

• Poate fi arătat că regula de decizie devine


Decide ℋ1 , dacă 𝐱 𝑇 𝐬ො > 𝛾
unde
𝐬ො = 𝐂𝑆 𝐂𝑆 + 𝜎 2 𝐈 −𝟏 𝐱
Exemplu de detecție de semnal aleatoriu
• Fără să intrăm în detalii, să vedem direct regula de decizie pentru
sinusoidă:
𝑁−1

෍ 𝑥 𝑛 𝑒𝑥𝑝 −2𝜋𝑖𝑓0 𝑛 >𝛾


𝑛=0
• Ca și un exemplu, mai jos avem procesul de detecție cu 𝜎 = 0.5
• De observat simplitatea implementării Python
import numpy as np
h = np.exp(-2 * np.pi * 1j * f0 * n)
y = np.abs(np.convolve(h, xn, 'same'))
Exemplu de detecție de semnal aleatoriu
Receiver Operating Characteristics

• Un mod uzual de ilustrare a performanței unui


detector este curba Receiver Operating
Characteristics (curba ROC)
• Acesta descrie relația dintre PFA și PD pentru toate
valorile posibile ale pragului 𝛾
• Relația dintre PFA și PD depinde de problemă și de
detectorul selectat
Receiver Operating Characteristics
• În exemplul cu semnalul constant (DC)

1 𝑥−1 2
𝑃𝐷 𝛾 = න 𝑒𝑥𝑝 − ⅆ𝑥
𝛾 2𝜋 2

1 𝑥2
𝑃𝐹𝐴 𝛾 = න 𝑒𝑥𝑝 − ⅆ𝑥
𝛾 2𝜋 2
• Este ușor să vedem relația

1 𝑥2
𝑃𝐷 𝛾 = න 𝑒𝑥𝑝 − ⅆ𝑥 = 𝑃𝐹𝐴 𝛾 − 1
𝛾−1 2𝜋 2
• Trasarea curbei ROC pentru toate 𝛾 este în partea
dreaptă
Receiver Operating Characteristics
• Cu cât e mai înaltă curba ROC, cu atât
e mai bună performanța
• O decizie aleatorie are o curbă ROC
diagonală
• Astfel ajungem la o măsură folosită
pe scară largă pentru a măsura
performanța unui detector: Area
Under (ROC) Curve, sau criteriul AUC
• Beneficiul AUC este că este
independent de prag și arată
acuratețea tuturor pragurilor
AUC empiric
• Inițial, AUC și ROC provin din problemele de detectare
radar și radio
• Mai recent, AUC a devenit una dintre măsurile standard
pentru performanța clasificării
• În mod normal o expresie de formă închisă pentru PD și
PFA nu poate fi obținută
• Astfel, ROC și AUC de obicei sunt calculate empiric, prin
evaluarea rezultatelor predicției pe un set de date de
testare, care nu a fost folosit la antrenare
Exemplu de clasificare – ROC și AUC
• De exemplu, putem considera setul de date 2
dimensional din dreapta
• Datele sunt împărțite în date de antrenare și
de testare, ele fiind similare dar nu exact
identice
• O să antrenăm 4 clasificatori pe datele de sus
și calculăm curba ROC pentru fiecare pe
datele de jos
Exemplu de clasificare – ROC și AUC
• Un clasificator liniar, antrenat cu datele
de antrenare produce granița de
delimitare între clase afișată
• Granița are orientarea și locația care
minimizează eroarea globală de
clasificare pentru datele de antrenare
• Granița este definită de:
𝑦 = 𝑐1 𝑥 + 𝑐0
cu parametri c1 și c0 învățați din date
Exemplu de clasificare – ROC și AUC

• Putem ajusta sensibilitatea clasificării prin


mutarea graniței de decizie în sus sau în
jos
• Cu alte cuvinte, glisăm parametrul c0 în
𝑦 = 𝑐1 𝑥 + 𝑐0
• Aceasta poate fi văzută ca și parametru de
reglare pentru trasarea curbei ROC
Exemplu de clasificare – ROC și AUC
• Când granița glisează de jos în sus, trasăm curba ROC empirică
• Trasarea începe din colțul dreapta sus
• De fiecare dată când granița trece de o cruce albastră, curba se mută la stânga
• De fiecare dată când granița trece de un cerc roșu, curba se mută în jos
Exemplu de clasificare – ROC și AUC
• Se utilizează pentru compararea clasificatorilor
• Mai jos este un grafic al curbelor ROC pentru 4 clasificatori folosiți pe scară largă
• Fiecare clasificator produce un scor de apartenență la clasă peste care parametrul
de reglare glisează
Cod Python pentru ROC și AUC
classifiers = [(LogisticRegression(), "Logistic Regression"),
(SVC(probability = True), "Support Vector Machine"),
(RandomForestClassifier(n_estimators = 100), "Random Forest"),
(KNeighborsClassifier(), "Nearest Neighbor")]

for clf, name in classifiers:


clf.fit(X, y)

ROC = []
for gamma in np.linspace(0, 1, 1000):
err1 = np.count_nonzero(clf.predict_proba(X_test[y_test == 0, :])[:,1] <= gamma)
err2 = np.count_nonzero(clf.predict_proba(X_test[y_test == 1, :])[:,1] > gamma)

err1 = float(err1) / np.count_nonzero(y_test == 0)


err2 = float(err2) / np.count_nonzero(y_test == 1)

ROC.append([err1, err2])
ROC = np.array(ROC)

ROC = ROC[::-1, :]
auc = roc_auc_score(y_test, clf.predict_proba(X_test)[:,1])

plt.plot(1-ROC[:, 0], ROC[:, 1], linewidth = 2, label="%s (AUC = %.2f)" % (name, auc))
Precision și Recall
• Calcularea PFA din exemplele negative nu este întotdeauna posibilă: De
exemplu, în figurile din dreapta, există milioane de exemple negative
(locații)
• Astfel, în căutare și regăsire, sunt preferați alți metrici:
– Recall-ul (aducerea aminte) unui detector este definit ca proporția de
obiecte adevărate găsite
– Precizia unui detector este proporția de obiecte adevărate din toate
obiectele găsite
• De exemplu, în figura de jos:
– Recall = #obiecte adevărate găsite / #toate obiectele adevărate = 1/1
= 100%
– Precision = #obiecte adevărate găsite / #toate obiectele găsite = 1 / 5
= 20%
Compromisul Precision-Recall
• Deci, putem ajusta sensibilitatea (găsim multe obiecte) și
precizia (găsim doar obiecte adevărate) prin reglarea
pragului de detecție
• Cum am putea să studiem detectorul fără să fim nevoiți să
speculăm despre sensibilitate?
• Acest lucru se poate face prin trasarea graficului precizie
versus recall pentru toate pragurile relevante
• Un exemplu de curbă precision-recall este arătată în dreapta
• Este evident că clasificatorul RF (curba roșie) este superior
clasificatorului SVM (curba albastră)
• Dacă am privi doar la un anumit punct individual de operare
(ex. recall = 0.3, precision = 1.0), am putea să nu vedem
diferența
Precizia Medie
• Curba precision-recall produce o metrică
unică pentru performanța unui detector:
average precision (AP)
• Precizia medie este pur și simplu media
preciziei pentru toate recall-urile
• Aproximativ același cu area under
precision-recall curve
• Detaliile calculelor pot varia, de ex.
pragurile testate efectiv, etc.
Instanța Valoarea Clasa
P1 0.8 1 Un exemplu de trasare a ROC
P2 0.5 1
P3 0.6 0
P4 0.4 0 T = 0.0 PD = 2/2 = 1.0 PFA = 3/3 = 1.0

P5 0.2 0 T = 0.3 PD = 2/2 = 1.0 PFA = 2/3 = 0.66


T = 0.45 PD = 2/2 = 1.0 PFA = 1/3 = 0.33
T = 0.55 PD = 1/2 = 0.5 PFA = 1/3 = 0.33
T = 0.7 PD = 1/2 = 0.5 PFA = 0/3 = 0.0
PD
T = 0.9 PD = 0/2 = 0.0 PFA = 0/3 = 0.0

AUC = 1 – 0.5/3 = 5/6 = 0.83333

PFA
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 04 – Modele Liniare
prof. dr. ing. Robert Győrödi
Sumar
• Clasificare
– Vecini Apropiați
– Liniari
– Analiza discriminantă liniară
– Support Vector Machine
• Regresia
• Scikit-learn
• Set de imagini pentru proiecte ML de la Google
– http://storage.googleapis.com/openimages/web/index.html
Clasificarea
• Multe dintre problemele de machine learning pot fi de tip clasificare
• Multe clasificări pot fi considerate ca și o problemă de partiționare a
spațiului vectorial în regiuni disjuncte
• Aceste probleme constau din următoarele componente:
Exemple: 𝐱 0 , 𝐱 1 , … , 𝐱 𝑁 − 1 ∈ ℝ𝑃
Etichete de clase: 𝑦 0 , 𝑦 1 , … , 𝑦 𝑁 − 1 ∈ 1, 2, … , 𝐶
Clasificator: 𝐹 𝐱 ∶ ℝ𝑃 ↦ 1, 2, … , 𝐶
• Sarcina este de a găsi funcția F care mapează cât mai precis exemplele la
etichetele corespunzătoare
• De exemplu: găsirea funcției F care minimizează numărul de predicții
eronate, ex. cazurile F(x[k]) ≠ y[k]
Regresia
• A doua mare clasă de probleme machine learning constau din regresii
• Pentru regresii, rezultatul este o valoare reală în loc de categorică
• Aceste probleme constau din următoarele componente:
Intrări: 𝐱 0 , 𝐱 1 , … , 𝐱 𝑁 − 1 ∈ ℝ𝑃
Valori țintă: 𝑦 0 , 𝑦 1 , … , 𝑦 𝑁 − 1 ∈ ℝ
Predictor: 𝐹 𝐱 ∶ ℝ𝑃 ↦ ℝ
• De această dată, problema este de a găsi funcția F care mapează cât mai precis exemplele la valorile
corespunzătoare
• De exemplu: găsirea funcției F care minimizează suma pătratelor distanțelor dintre predicții și
valorile țintă:
𝑁−1
2
𝜀 = ෍ 𝑦 𝑘 −𝐹 𝐱 𝑘
𝑘=0
Exemplu de clasificare
• De exemplu, considerăm setul de date bi-
dimensionale din dreapta
• Datele constau din 200 de cruciulițe albastre și 200
de cercuri roșii
• Bazat pe aceste date, care ar fi o partiție bună a
spațiului 2D în regiuni ”roșii” și ”albastre”?
• Ce fel de granițe sunt permise între regiuni?
– Linii drepte?
– Granițe continue curbe?
– Granițe fără restricții?
• Notă: În 2D această problemă poate fi rezolvată
manual, dar nu în spații de dimensionalitate mare!
Exemplu de regresie
• De exemplu, considerăm datele 1 dimensionale
din dreapta
• Datele constau din 100 de puncte, unde
coordonata y este funcție de x
• Bazat pe aceste valori, care ar fi a predicție
bună a valorii țintă pentru x = 1.3 (linia
întreruptă)?
• O soluție evidentă este de a potrivi o curbă
peste puncte. Ce fel de formă ar putea avea
această curbă?
– Linie dreaptă?
– Curbe continue?
Diverși Clasificatori
• Vom studia următorii clasificatori folosiți pe scară largă:
– Clasificatorul Vecinului Cel Mai Apropiat
– Clasificatori Liniari (cu graniță liniară)
– Support Vector Machine (cu graniță neliniară)
– Clasificatori de ansamblu: Random Forest
– Cutii negre: Rețele neuronale și rețele neuronale profunde
• Pentru primele patru vom folosi Scikit-Learn https://scikit-learn.org
• Partea despre rețele neuronale va fi studiată cu pachetul Keras
https://keras.io
Scikit-Learn
• Scikit-learn a pornit ca și un proiect Google Summer of Code
• Proiectul a devenit un succes: Exista o nevoie clară pentru o
platformă elegantă gratuită care să aducă împreună metodele
folosite pe scară largă
• În loc ca fiecare contribuitor să ofere propriul pachet, scikit-
learn are un API unificat pentru fiecare metodă
• Pentru detalii: Pedregosa, et al. ”Scikit-learn: Machine
learning in Python”, The Journal of Machine Learning
Research, 2011
Metode Scikit-Learn
• API-ul scikit-learn este intuitiv:
– Inițializare: Fiecare model are propriul constructor, ex.
model = LogisticRegression(penalty = "l1", C = 0.1)
– Antrenare: Fiecare model implementează o metodă .fit(), care antrenează modelul,
ex.
model.fit(X_train, y_train)
– Predicție: Fiecare model implementează o metodă .predict(), care prezice valoare de
ieșire pentru intrări noi, ex.
y_hat = model.predict(X_test)
– Probabilități: Multe modele implementează deasemenea o metodă
.predict_proba(), care prezice probabilitățile de clase pentru intrări noi, ex.
p = model.predict_proba(X_test)
O sesiune exemplu Scikit-learn
# Cod de antrenare: • În codul exemplu, X constă din
from sklearn.linear_model import LogisticRegression 400 de exemple bi-
model = LogisticRegression(solver='lbfgs')
model.fit(X, y) dimensionale din două clase.
# Cod de testare:
>>> model.predict([[2,1]])
array([ 1.])

>>> model.predict([[0,-3]])
array([ 0.])

>>> model.predict_proba([[2,1], [0,-3]])


Out[35]:
array([[ 0.00014136, 0.99985864 ],
[ 0.53021870, 0.46978130]])

# [2,1] este clasa 1 cu 99.98 % confidenta.


# [0,-3] este clasa 0 cu 53.02 % confidenta.
Clasificatorul Vecinului cel mai Apropiat
• Probabil cea mai naturală abordare
pentru a decide clasa este pur și simplu a
vedea ce fel de exemple sunt în jur
• Aceasta este idea din spatele
clasificatorului Nearest Neighbor: se
copiază eticheta clasei exemplului cel mai
similar pentru elementul necunoscut
Clasificatorul celor mai Apropiați K Vecini
• Problema vecinului cel mai apropiat este
fragilitatea la schimbări în datele de antrenare
• Granița de clasificare se poate schimba destul
de mult prin mutarea unui singur exemplu de
antrenare
• Robustețea poate fi crescută prin luarea unui
vot majoritar a mai multe exemple apropiate
• Clasificatorul celor mai apropiați K vecini
selectează eticheta de clasă cea mai frecventă
dintre cele mai apropiate K exemple de
antrenare
Vecinul cel mai Apropiat în Scikit-learn
# Cod de antrenare: • Parametri constructorului includ:
from sklearn.neighbors import KNeighborsClassifier
– n_neighbors: numărul de
model = KNeighborsClassifier(n_neighbors = 5, metric = "euclidean") vecini K
model.fit(X, y)
– metric: cum se calculează
# Cod de testare: distanța
model.predict([[2,1], [4,-8]])
Out[]: array([1.00000000, 0.00000000]) – algorithm: care algoritm
model.predict_proba([[-3,0]])
găsește cel mai apropiat
Out[]: array([[0.40000000, 0.60000000]]) exemplu, ex. metode ca și K-D
# Putem vedea care sunt cei 5 vecini apropiati
Tree sau forța brută
# Intoarce distantele si indicii in X
distances, indices = model.kneighbors([[-3,0]])
• Predicția de probabilitate numără câți
Out[]: (array([[2.04410321, 2.43706157, 2.55839576, 2.57235904, 2.57758600]]), dintre cele K exemple apropiate
array([[340, 214, 27, 237, 11]], dtype=int64)) aparțin la fiecare clasă
# Care sunt clasele pentru aceste cinci exemple: • Astfel, probabilitățile sunt foarte
y[indices]
Out[]: array([[1.00000000, 1.00000000, 1.00000000, 0.00000000, 0.00000000]]) cuantificate și de multe ori 0 sau 1
Beneficiile Vecinului cel mai Apropiat
• Timpul de antrenare este minim:
– fie stocăm datele așa cum sunt,
– sau se poate reorganiza într-o structură de arbore pentru o
căutare eficientă
• Acuratețea în majoritatea cazurilor este relativ bună
• Permite o definiție complicată pentru distanță, ex.:
– Găsește cele mai apropiate 5 exemple care au atributele A
și B dar nu C
• Date noi pot fi adăugate/șterse fără a necesita re-antrenare
Probleme cu Vecinul cel mai Apropiat
• Vecinul cel mai apropiat este predispus la supra-potrivire: în mod
special 1-NN formează regiuni locale în jurul fiecărui punct izolat
• Este foarte puțin probabil că acestea reprezintă trendul general al
întregii populații
• În plus, etapa de învățare este foarte rapidă, pe când etapa de
clasificare devine foarte înceată (considerând date de antrenare cu
exemple de ordinul miliardelor, având dimensionalitate mare)
• Astfel, sunt preferate reprezentări mult mai compacte: timpul de
antrenare nu este în mod uzual critic, dar timpul de execuție este!
Clasificatori Liniari
• Un clasificator liniar învață o graniță de decizie liniară
între clase
• În termeni matematici, regula de clasificare poate fi
scrisă ca:
𝐶𝑙𝑎𝑠𝑎 1, 𝑑𝑎𝑐ă 𝐰 𝑇 𝐱 < 𝒃
𝐹 𝐱 =ቊ
𝐶𝑙𝑎𝑠𝑎 2, 𝑑𝑎𝑐ă 𝐰 𝑇 𝐱 ≥ 𝒃
unde ponderile w sunt învățate din date
• Expresia 𝐰 𝑇 𝐱 = σ𝒌 𝒘𝒌 𝒙𝒌 transformă defapt datele
multidimensionale x într-un număr real, care după
aceea este comparat cu un prag b
Diverși Clasificatori Liniari
• Există mai mulți algoritmi pentru învățarea ponderilor w, incluzând:
• Analiza Discriminant • Support Vector • Regresie Logistică (LR)
Liniară (LDA) Machine (SVM)
Diverși Clasificatori Liniari
• LDA
– Cel mai vechi dintre cei trei: Fisher, 1935
– ”Găsește proiecția care maximizează separarea claselor”, adică trage clasele cât mai departe posibil
unele de altele
– O soluție de formă închisă, rapid antrenabilă
• SVM
– Vapnik și Chervonenkis, 1963
– ”Maximizează marginea dintre clase”
– Cel mai încet dintre cei trei, se comportă bine cu date de dimensionalitate mare rare
• LR (Modelul liniar generalizat)
– Datează din anii 1700, dar o formulare adecvată și un algoritm de antrenare eficient a fost făcută de
Nelder și Wedderburn în 1972
– Algoritm statistic: ”Maximizează probabilitatea datelor”
– Produce deasemenea și probabilitatea clasei. A fost extins pentru selecția automată a caracteristicilor

Timpul de testare este același pentru toți algoritmii de mai sus.


Analiza Discriminantă Liniară
• LDA mapează date de
dimensionalitate mare
într-un singur scalar,
simultan separând clasele
individuale
• Astfel, sarcina este de a
găsi o proiecție liniară
bună ℝ𝑁 ↦ ℝ
Analiza Discriminantă Liniară
• O măsură bună pentru separarea claselor poate fi de ex. distanța dintre
proiecția centrelor acestora
• Cu toate acestea, aceasta depinde de scară și crește prin simpla
multiplicare cu un număr mare
• Astfel, dorim să separăm clasele ținând mică varianța fiecărei clase
• Ca și rezultat, ne uităm la următorul scor de separabilitate:
𝐷𝑖𝑠𝑡𝑎𝑛𝑡𝑎 𝑑𝑖𝑛𝑡𝑟𝑒 𝑐𝑒𝑛𝑡𝑟𝑒𝑙𝑒 𝑐𝑙𝑎𝑠𝑒𝑙𝑜𝑟 𝐰 𝑇 𝜇1 − 𝐰 𝑇 𝜇0 2
𝐽 𝐰 = = 𝑇
𝑉𝑎𝑟𝑖𝑎𝑛𝑡𝑎 𝑐𝑙𝑎𝑠𝑒𝑙𝑜𝑟 𝐰 Σ1 𝐰 + w 𝑻 𝚺𝟎 w
unde 𝜇1 și 𝜇0 sunt centrele claselor iar Σ1 și Σ0 matricele de covarianță ale
celor două clase
Maximizarea J(w)
• Scorul de separare Fisher poate fi maximizat analitic
• Prima dată simplificăm puțin J(w):
𝐰 𝑇 𝜇1 − 𝐰 𝑇 𝜇0 2 𝐰 𝑇 𝐒𝐵 𝐰
𝐽 𝐰 = 𝑇 = 𝑇
𝐰 Σ1 + 𝐰 𝑇 Σ0 𝐰 𝐰 𝐒𝑊 𝐰
cu 𝐒𝐵 = 𝜇1 − 𝜇0 𝜇1 − 𝜇0 𝑇 și 𝐒𝑊 = Σ1 + Σ0
• Această formă este cunoscută ca și Coficientul generalizat Rayleigh, acesta apare în
multe contexte
• Folosind multiplicatori Lagrange, se poate demonstra că maximul trebuie să
satisfacă
𝐒𝐵 𝐰 = 𝜆𝐒𝑊 𝐰
cu 𝜆 ∈ ℝ o constantă
Maximizarea J(w)
• Condiția de mai sus este o problemă generalizată de valori proprii
• Cu alte cuvinte, sunt mai multe soluții: una pentru fiecare valoare proprie
• Astfel, este simplu să concluzionăm cantitatea
𝐰 𝑇 𝐒𝐵 𝐰
𝐽 𝐰 = 𝑇
𝐰 𝐒𝑊 𝐰
este maximizată când
𝐒𝐵 𝐰 = λ𝐒𝑊 𝐰
sau echivalent
𝐰 𝑇 𝐒𝐵 𝐰 = λ𝐰 𝑇 𝐒𝑊 𝐰
• În final, raportul 𝐰 𝑇 𝐒𝐵 𝐰Τ𝐰 𝑇 𝐒𝑊 𝐰 este maximizat prin alegerea λ ca și cea mai
mare valoare proprie (și w ca și vectorul propriu corespunzător)
Soluția 1 folosind Valori Proprii
# Cod antrenare:
import numpy as np
from scipy.linalg import eig
• Trebuie să rezolvăm problema generalizată cu
valori proprii 𝐒𝐵 𝐰 = λ𝐒𝑊 𝐰
# X0 si X1 contin date pentru cele 2 clase
m0 = np.mean(X0, axis = 0)
m1 = np.mean(X1, axis = 0)
• scipy are o rezolvare pentru asta
C0 = np.cov(X0 - m0, rowvar = False)
C1 = np.cov(X1 - m1, rowvar = False)
• scipy.linalg.eig întoarce
SB = np.multiply.outer(m1 - m0, m1 - m0)
SW = C0 + C1
– Vector de valori proprii D în ordine
D, V = eig(SB, SW)
w = V[:, -1]
crescătoare
T = np.mean([np.dot(m0, w), np.dot(m1, w)])
– Matrice de vectori proprii V (pe coloane)
# Cod de testare: • Ne interesează coloana cea mai din dreapta (”a
print(w)
[0.17070018 0.98532302] -1 a”) coloană V[:, -1] (corespunzătoare celei
print(np.dot(w, [0,-2]) - T)
0.8433642815579159
mai mari valori proprii)
# Pozitiv -> in clasa "cercuri rosii"
print(np.dot(w, [0,-3]) - T) • Decizia este luată prin compararea vectorului
-0.14195873505794365
# Negativ -> in clasa "x-uri albastre"
proiectat cu pragul T; centrul mediilor
proiectate ale claselor
Proiecție LDA cu Prag
Soluția a 2-a fără Valori Proprii
• Defapt nu este necesară soluționarea problemei cu valori proprii 𝐒𝐵 𝐰 = λ𝐒𝑊 𝐰
−1
• Maximul J(w) trebuie să satisfacă 𝐒𝐵 𝐰 = λ𝐒𝑊 𝐰, sau echivalent, 𝐒𝑊 𝐒𝐵 𝐰 = λ𝐰
• Dacă inserăm definiția lui 𝐒𝐵 obținem:
−1
𝐒𝑊 𝜇1 − 𝜇0 𝜇1 − 𝜇0 𝑇 𝐰 = λ𝐰
𝑠𝑐𝑎𝑙𝑎𝑟𝑢𝑙 𝐶
sau,
−1
𝐶
𝐒𝑊 𝜇1 − 𝜇0 =𝐰
λ
• Deci, maximul J(w) trebuie să satisfacă și această condiție (independent de λ)
Soluția 2 fără Valori Proprii

• Căutăm un vector de direcție w, deci multiplicatorul


𝐶
𝐶 Τλ nu este nici el relevant ( 𝐰 are aceeași direcție
λ
ca și w)

• Deci, w este dat de


−1 −1
𝐰 = 𝐒𝑊 𝜇1 − 𝜇0 = Σ0 + Σ1 𝜇1 − 𝜇0
Soluția 2 fără Valori Proprii
# Cod antrenare: • Codul Python este foarte similar cu cel de la soluția
import numpy as np bazată pe valori proprii
from scipy.linalg import eig
• De observat că w rezultat nu este chiar la fel:
# X0 si X1 contin date pentru cele 2 clase
m0 = np.mean(X0.T, axis = 1) lungimile sunt diferite, dar direcțiile sunt la fel
m1 = np.mean(X1.T, axis = 1)
C0 = np.cov(X0 - m0, rowvar = False)
C1 = np.cov(X1 - m1, rowvar = False)
w = np.dot(np.linalg.inv(C0 + C1), (m1 - m0))
T = np.mean([np.dot(m0, w), np.dot(m1, w)])

# Cod de testare:
print(w)
[0.17110018 0.98763186]
print(np.dot(w, [0,-2]) - T)
0.8453404839089127
# Pozitiv -> in clasa "cercuri rosii"
print(np.dot(w, [0,-3]) - T)
-0.1422913780120032
# Negativ -> in clasa "x-uri albastre"
Soluția 3: Scikit-learn
# Cod antrenare: • Scikit-learn implementează LDA într-o
from sklearn.discriminant_analysis
import LinearDiscriminantAnalysis
manieră directă
clf = LinearDiscriminantAnalysis()
• Prima dată construim clasificatorul
# X contine toate exemplele, iar y clasele lor folosind
# etichete: y = [0,1,1,0,...]
clf.fit(X, y)
LinearDiscriminantAnalysis()
• După aceea antrenăm modelul folosind
fit()
# Cod de testare:
print(clf.coef_) # Acesta este vectorul nostru w • După aceea prezicem clasele folosind
[[0.34220035 1.97526372]]
print(clf.intercept_) # Acesta este pragul predict()
[5.64120842]
print(clf.predict([[0, -2]])) • Sau probabilitățile claselor folosind
[1.00000000]
print(clf.predict([[0, -3]]))
predict_proba()
[0.00000000]
print(clf.predict_proba([[0, -3]]))
[[0.57066939 0.42933061]]
LDA Multi-clasă
• LDA poate fi generalizat pentru a trata mai mult de 2
clase
• LDA multiclasă poate fi înțeles în două contexte:
– Ca și reducere de dimensionalitate: Căutăm un
set de proiecții, care reduc dimensionalitatea
datelor reținând totodată separabilitatea
originală
– Ca și clasificare: Căutăm un set de funcții
discriminant care dau un scor de probabilitate
pentru fiecare clasă
• Suntem mai interesați în cea de a doua interpretare
LDA Multi-clasă
• LDA multi-clasă este definită de un set de K funcții liniare
– una pe clasă
𝑔1 𝐱 = 𝐰1𝑇 𝐱 + 𝒘𝟏

𝑔𝐾 𝐱 = 𝐰𝐾𝑇 𝐱 + 𝒘𝑲
• După care vectorul x este asignat clasei k = 1, 2, ..., K dacă
𝑔𝑘 𝐱 > 𝑔𝑗 𝐱
pentru toate 𝑗 ≠ 𝑘
LDA Multi-clasă
# Cod antrenare:
• Modelul LinearDiscriminantAnalysis() se
import numpy as np aplică și la cazul multi-clasă
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
• Metoda fit() găsește cei trei discriminanți
clf = LinearDiscriminantAnalysis() arătați în graficul de mai jos
# X contine toate exemplele, iar y clasele corespunzatoare
# etichete: y = [1,3,1,2,...]
clf.fit(X, y)

# Cod de testare:
# Afiseaza cei trei discriminanti (linii):
print(clf.coef_)
[[-0.96066517 -0.98532847]
[-1.58373942 0.37636399]
[1.59025287 0.38060280]]
# Calculeaza discriminantii pentru [0,-2]
scores = np.dot(clf.coef_, [0,-2]) + clf.intercept_
print(scores)
[-1.03669054 1.45951335 -5.53009640]
# Clasa rosu (1) are cel mai mare scor
# Prezicem clasa mai usor folosind predict()
print(clf.predict([[0, -2], [0, -4], [4, -6]]))
[1.00000000 0.00000000 2.00000000]
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 05 – SVM & Regresie Logistică
prof. dr. ing. Robert Győrödi
Sumar
• Clasificare
– Vecini Apropiați
– Liniari
– Analiza discriminantă liniară
– Support Vector Machine
• Regresia
• Scikit-learn
• Set de imagini pentru proiecte ML de la Google
– http://storage.googleapis.com/openimages/web/index.html
Support Vector Machine
• Support Vector Machine (SVM) este
caracterizat prin proprietatea de margine
maximă (maximum margin property)
• Cu alte cuvinte, încearcă să maximizeze
marginea dintre clase
• În exemplul atașat, datele binare sunt
perfect separabile, și SVM setează granița la
mijlocul zonei dintre cele două clase
• Astfel, locația graniței este definită de doar
trei exemple, numiți vectori suport
Support Vector Machine
• Maximizarea marginii M pentru SVM poate fi
caracterizat ca și o problemă de optimizare
maximiz𝑒𝑎𝑧𝑎 𝑀,
𝐰,𝑏, 𝐰 =1
considerând că
𝑦𝑖 𝐱 𝑖𝑇 𝐰 + 𝑏 ≥ 𝑀, 𝑝𝑒𝑛𝑡𝑟𝑢 𝑖 = 1, 2, … , 𝑁
• Aici, 𝑦𝑖 codifică clasa ca și 𝑦𝑖 = −1, 1 , astfel
ultima condiție poate fi rescrisă ca:
𝐱 𝑖𝑇 𝐰 + 𝑏 ≥ 𝑀, 𝑑𝑎𝑐𝑎 𝑦𝑖 = 1
൝ 𝑇
𝐱 𝑖 𝐰 + 𝑏 ≤ −𝑀, 𝑑𝑎𝑐𝑎 𝑦𝑖 = −1
Support Vector Machine
• Alternativ, criteriul SVM poate fi simplificat într-o formă echivalentă
minimizeaza 𝐰 ,
𝐰,𝑏
considerând că
𝑦𝑖 𝐱 𝑖𝑇 𝐰 + 𝑏 ≥ 1, 𝑝𝑒𝑛𝑡𝑟𝑢 𝑖 = 1, 2, … , 𝑁
• Aceasta este o problemă de optimizare convexă cu constrângeri.
Există algoritmi eficienți specifici.
• Implementarea din Scikit-learn este bazată pe librăria larg folosită
LibSVM
Support Vector Machine
• Definiția anterioară a SVM presupune că clasele sunt separate
(și există o margine între clase)
• În realitate trebuie să permitem anumite exemple să fie pe
partea greșită a marginii
• Soluția este de a penaliza pentru exemple aflate pe partea
greșită
• Funcția rezultată a fi minimizată este:
𝑁

minimizeaza ෍ max 0, 1 − 𝑦𝑖 𝐰 𝑇 𝐱 𝑖 + 𝑏 +𝐶 𝐰 2
𝐰,𝑏
𝑖=1
• Pentru fiecare exemplu pe partea greșită, adăugăm o
penalizare (numită hinge loss) definit ca 𝑚𝑎𝑥 0, 𝑥
• De notat că aceasta crește numărul de VS-uri
SVM în Scikit-learn
• Parametrul C determină balanța dintre lățimea marginii și penalizarea
pentru a fi pe partea greșită
• De la stânga la dreapta: SVM-uri liniare cu penalizare descrescătoare
Artificiu cu Nucleu (Kernel Trick)
• SVM-ul poate fi extins la granițe neliniare folosind un artificiu
numit kernel trick
• Artificiul mapează datele într-o dimensionalitate mai mare și
proiectează SVM-ul liniar acolo
• De exemplu, graficul de sus poate fi generat după cum
urmează:
– Mapăm exemplele 2D în 3D: 𝑥, 𝑦 ↦ 𝑥 2 , 𝑦 2 , 2𝑥𝑦
– Antrenăm SVM-ul cu noile exemple 3D
– Granița de decizie este liniară în 3D, dar neliniare în 2D
• Însă, această transformare este înceată; artificiul cu nucleu
face același lucru implicit
Artificiu cu Nucleu (Kernel Trick)
• Poate fi arătat că substituția produsului punct printr-o anumită
funcție neliniară este echivalentă unei mapări explicite
• Mai specific, un algoritm poate fi nucleificat (kernelized) prin
inserarea unei funcții nucleu 𝜅 𝐱, 𝐲 în loc de produsul punct 𝐱 ⋅ 𝐲
• Poate fi arătat că în anumite condiții pe nucleu (ex. semidefinire
pozitivă), aceasta este echivalentă cu o mapare explicită
• Au fost realizate multe cercetări asupra relației unui nucleu și
maparea corespunzătoare
• Însă, vom lua o abordare mai practică și considerăm un exemplu
Artificiu cu Nucleu (Kernel Trick)
• Ca și un exemplu, examinăm ce se întâmplă când produsul
intern a vectorilor 2D 𝐱 = 𝑥1 , 𝑥2 și 𝐲 = 𝑦1 , 𝑦2 este înlocuit
cu pătratul acestora:
𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲 𝟐
• Putem extinde nucleul:
𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲 𝟐
= 𝑥1 𝑦1 + 𝑥2 𝑦2 2
= 𝑥1 𝑦1 2 + 𝑥2 𝑦2 2 + 2𝑥1 𝑦1 𝑥2 𝑦2
Artificiu cu Nucleu (Kernel Trick)

• Rezultatul poate fi rearanjat ingenios pentru a arăta


asemănător cu un produs punct în 3D:
𝜅 𝐱, 𝐲 = 𝑥1 𝑦1 2 + 𝑥2 𝑦2 2 + 2𝑥1 𝑦1 𝑥2 𝑦2
= 𝑥1 𝑦1 2 + 𝑥2 𝑦2 2 + 2𝑥1 𝑥2 2𝑦1 𝑦2
= 𝑥12 , 𝑥22 , 2𝑥1 𝑥2 ⋅ 𝑦12 , 𝑦22 , 2𝑦1 𝑦2
Artificiu cu Nucleu (Kernel Trick)
• Astfel, următoarele două sunt echivalente:
– Mapare explicită: Transformarea datelor 2D în 3D explicit
și potrivirea SVM cu datele transformate:
2
𝑢 𝑢
↦ 𝑣2
𝑣
2𝑢𝑣
– Mapare implicită: Substituirea fiecărui produs punct din
algoritmul SVM prin nucleul 𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲 𝟐 și potrivirea
cu datele originale 2D
Nuclee populare
• Așa cum am menționat, există multă literatură despre nuclee. Unele populare includ:
– Nucleu liniar: 𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲. Aceasta este SVM-ul de bază, fără mapare
– Nucleu polinomial: 𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲 𝒅 . Ridică produsul punct la puterea d
– Nucleu polinomial neomogen: 𝜅 𝐱, 𝐲 = 𝐱 ⋅ 𝐲 + 1 𝒅. Similar nucleului polinomial,
dar produce mai multe dimensiuni
– Nucleu sigmoidal: 𝜅 𝐱, 𝐲 = tanh 𝑎𝐱 ⋅ 𝐲 + 𝑏 , 𝑐𝑢 𝑎 > 0 𝑠𝑖 𝑏 < 0
𝐱−𝐲 2
– Nucleu gaussian: 𝜅 𝐱, 𝐲 = exp − . Probabil cel mai folosit nucleu.
2𝜎 2
Cunoscut ca și nucleul RBF (Radial Basis Function)
• Nucleul RBF este special în sensul că corespunde unei mapări într-un spațiu vectorial
infinit dimensional
• În plus, acest nucleu este adesea care se comportă cel mai bine
SVM în Scikit-learn
# Cod antrenare: • Scikit-learn împachetează librăriile LibSVM și
from sklearn.svm import SVC LibLinear (al doilea este un nucleu liniar optimizat)
# Alternativ: from sklearn.svm import LinearSVC
# Nucleele includ: "linear", "rbf", "poly", "sigmoid"
# C este termenul penalizare (implicit = 1)
clf = SVC(kernel = 'linear', C = 1)
# X contine toate exemplele, iar y clasele corespunzatoare
# etichete: y = [0,1,1,0,...]
clf.fit(X, y)

# Cod de testare:
print(clf.coef_) # Acesta este vectorul nostru w vector (cazul liniar)
[[0.73439694 0.28806980]]
print(clf.intercept_) # Acesta este pragul
[1.63787568]
print(clf.predict([[-4,-2], [-2,0]]))
[0.00000000 1.00000000]
print(clf.support_vectors_)
[[-2.40000000 -3.04024390]
[-0.38544996 -1.23082179]
[0.41606392 -3.27417889]]
SVM Multi-clasă
• SVM este inerent pentru două clase
• Generalizarea pentru mai multe clase este realizată prin
compararea de perechi de clase
• Pentru fiecare clasă, antrenăm un SVM care clasifică această clasă
versus toate celelalte
• Scikit-learn oferă câteva meta-clasificatori pentru acest lucru
– multiclass.OneVsRestClassifier compară fiecare clasă
vs. toate celelalte (necesită K clasificatori)
– multiclass.OneVsOneClassifier compară toate perechile
de clase (necesită K(K – 1)/2 clasificatori)
SVM Multi-clasă
• O extensie suplimentară este clasificarea multietichetă, unde
mai multe clase pot fi prezente simultan
• Țintele sunt prezentate ca și indicatori binari:
from sklearn.preprocessing import MultiLabelBinarizer
yc = [[2, 3, 4], [2], [0, 1, 3], [0, 1, 2, 3, 4], [0, 1, 2]]
MultiLabelBinarizer().fit_transform(yc)
array([[0, 0, 1, 1, 1], # Clasele 2,3,4 sunt "prezente"
[0, 0, 1, 0, 0], # Clasa 3 este "prezenta"
[1, 1, 0, 1, 0], # ...
[1, 1, 1, 1, 1],
[1, 1, 1, 0, 0]])

• Apar adesea de ex. în probleme de recunoaștere a imaginilor:


”Ce este în această imagine?”
• De exemplu, următoarele atribute sunt ”prezente” în
imaginea alăturată: {"muscă", "floare","vară"}
SVM Multi-clasă
• SVC() implementează euristica OvO
• LinearSVC() nu, o să folosim acesta
ca și exemplu
# Cod de antrenare:
from sklearn.svm import LinearSVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn.multiclass import OneVsOneClassifier
clf_ova = OneVsRestClassifier(LinearSVC(max_iter=1600))
clf_ova.fit(X, y)
clf_ovo = OneVsOneClassifier(LinearSVC(max_iter=1600))
clf_ovo.fit(X, y)

# Cod de testare:
print(clf_ova.predict(np.array([[2,-3.4], [4,-2]])))
[0.00000000 2.00000000]
print(clf_ovo.predict(np.array([[2,-3.4], [4,-2]])))
[1.00000000 2.00000000]
print(len(clf_ova.estimators_))
3
Regresia Logistică
• Al treilea membru a familiei de clasificatori liniari este Regresia Logistică
(LR)
• Spre deosebire de celelalte două, LR este probabilistic, adică modelează
probabilitățile claselor în loc de apartenența simplă la o clasă
• Pentru cazul cu două clase (𝑐 ∈ 0, 1 ), modelul este:
1
𝑝 𝑐=1𝐱 =
1 + exp − 𝐰 𝑇 𝐱 + 𝑏
• De asemenea: 𝑝 𝑐 = 0 𝐱 = 1 − 𝑝 𝑐 = 1 𝐱
• În esență, modelul mapează proiecția 𝐰 𝑇 𝐱 + 𝑏 prin funcția sigmoid (astfel
limitând intervalul la [0, 1]).
Regresia Logistică
• Modelul este ilustrat aici:
– Exemplele sunt proiectate în 1D
folosind ponderile învățate w și b
– ”Scorurile de clasă” rezultate sunt
mapate prin funcția logistică, care
transformă scorurile în
probabilități 𝑝 𝑐 = 1 𝐱 ∈ 0,1
• Estimările de probabilitate pot fi de
asemenea mapate înapoi în 2D, așa
cum este arătat în figura din dreapta
Antrenarea modelelor de regresie logistică
• Regresia logistică este antrenată prin probabilitatea maximă
• Cu alte cuvinte, maximizăm probabilitatea de observare a acestor puncte
corespunzător parametrilor modelului
• Probabilitatea exemplelor 𝐗 = 𝐱 0 , 𝐱1 , … , 𝐱 𝑁−1 cu etichetele de clasă
𝑦0 , 𝑦1 , … , 𝑦𝑁−1 ∈ 1,2, … , 𝐾 să fi apărut din modelul cu parametri 𝜃 este
𝑁−1

𝑝 𝐗 𝜃 = ෑ 𝑝 𝐱 𝑛 ; 𝜃, 𝑦𝑛
𝑛=0
• Ca de obicei, considerăm o probabilitate logaritmică în loc:
𝑁−1

ln 𝑝 𝐗 𝜃 = ෍ ln 𝑝 𝐱 𝑛 ; 𝜃, 𝑦𝑛
𝑛=0
Antrenarea modelelor de regresie logistică
• Pentru simplitate, vom continua doar cu cazul a două
clase
• Să etichetăm clasele ca 𝑦𝑘 ∈ −1,1 , deoarece astfel
simplificăm notația pentru mai târziu
• De asemenea: să ascundem termenul constant b prin
concatenarea la sfârșitul w:
𝐰 ← 𝐰, 𝑏 și 𝐱 ← 𝐱, 1
Antrenarea modelelor de regresie logistică
• Probabilitățile claselor -1 și 1 sunt acum:
1
𝑝 𝐱 𝑛 𝑦𝑛 = 1 =
1 + exp −𝐰 𝑇 𝐱 𝑛
1
𝑝 𝐱 𝑛 𝑦𝑛 = −1 = 1 −
1 + exp −𝐰 𝑇 𝐱 𝑛
1 + exp −𝐰 𝑇 𝐱 𝑛 − 1
=
1 + exp −𝐰 𝑇 𝐱 𝑛
exp −𝐰 𝑇 𝐱 𝑛
=
1 + exp −𝐰 𝑇 𝐱 𝑛
1 1
= =
exp 𝐰 𝑇 𝐱 𝑛 + 1 1 + exp 𝐰 𝑇 𝐱 𝑛
Antrenarea modelelor de regresie logistică
• 𝑝 𝐱𝑛 𝑦𝑛 = 1 și 𝑝 𝐱𝑛 𝑦𝑛 = −1 sunt aproape aceeași formă
și pot fi combinate într-o singură formulă:
1
𝑝 𝐱 𝑛 𝑦𝑛 =
1 + exp −𝑦𝑛 𝐰 𝑇 𝐱𝑛
• Probabilitatea pentru toate exemplele 𝐗 = 𝐱0 , 𝐱1 , … , 𝐱𝑁−1
este acum:
𝑁−1
1
𝑝 𝐗 𝐰, 𝐲 = ෑ
1 + exp −𝑦𝑛 𝐰 𝑇 𝐱 𝑛
𝑛=0
Antrenarea modelelor de regresie logistică

• Probabilitatea logaritmică devine:


𝑁−1

ln 𝑝 𝐗 𝐰, 𝐲 = ෍ ln 1 − ln 1 + exp −𝑦𝑛 𝐰 𝑇 𝐱 𝑛
𝑛=0
𝑁−1

= − ෍ ln 1 + exp −𝑦𝑛 𝐰 𝑇 𝐱 𝑛
𝑛=0
Antrenarea modelelor de regresie logistică
• Pentru a maximiza probabilitatea, putem minimiza la fel și funcția de pierdere
logistică (logistic loss function)
𝑁−1

ℓ 𝐰 = ෍ ln 1 + exp −𝑦𝑛 𝐰 𝑇 𝐱 𝑛
𝑛=0
• Există mai mulți algoritmi pentru minimizarea pierderii logistice, ex:
– Iterative Reweighted Least Squares (IRLS) este un algoritm calibrat special
pentru astfel de probleme. Folosit de statsmodels.api.Logit și
statsmodels.api.MNLogit
– Abordări bazate pe teoria optimizării. Deoarece ln 𝑝 𝐗 𝜃 este convex, în
principiu se poate folosi orice abordare de optimizare. Scikit-learn
folosește ceva numit Trust Region Newton Algorithm
Antrenarea modelelor de regresie logistică
• Abordarea bazată pe teoria optimizării a devenit dominantă, pentru două motive:
1. Antrenarea SVM poate fi pusă în același cadru: minimizarea hinge loss:
hinge_loss = max 0,1 − 𝑦𝑛 𝐰 𝑇 𝐱 𝑛
2. Un optimizator generic poate minimiza de asemenea și pierderile
modificate. Mai important, putem adăuga un termen de penalizare în
funcția de pierdere; ex.
𝑁−1

penalized log_loss = ෍ ln 1 + exp −𝑦𝑛 𝐰 𝑇 𝐱 𝑛 + 𝐶𝐰 𝑇 𝐰


𝑛=0
unde ultimul termen favorizează coeficienții mici din w. Ne vom întoarce la această tehnică,
numită regularizare, puțin mai târziu.
Antrenarea modelelor de regresie logistică
• În exerciții, vom implementa
minimizarea pierderii logaritmice
pentru date bi-dimensionale
1. Inițializare w cu valori aleatoare
2. Ajustare w spre gradientul
negativ:
𝐰 = 𝐰 − 𝜖 ∙ ℓ′ 𝐰
3. Întoarcere la pasul 2
• Rezultatul este afișat în imaginile
din dreapta
Exemplu: Efectul parametrului de regularizare C
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
• În acest exemplu antrenăm
clasificatorul LR cu un
# Impartim datele in antrenare si testare
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2) interval de valori pentru
# Valori de test pentru C: -4, -3, ..., 2
parametrul C
C_range = 10.0 ** np.arange(-4, 3)
clf = LogisticRegression(solver='lbfgs', multi_class='auto') • Fiecare valoare C poate fi
for C in C_range:
clf.C = C
setată în interiorul unui
clf.fit(X_train, y_train)
y_hat = clf.predict(X_test)
ciclu for ca și:
accuracy = 100.0 * np.mean(y_hat == y_test) clf.C = <valoare noua>
print ("Accuracy for C = %.2e is %.1f %% (||w|| = %.4f)" %
(C, accuracy, np.linalg.norm(clf.coef_)))
• Testăm acuratețea pe un
set de date separat, extras
# Rezultat pentru datele exemplu pentru 3 clase
Accuracy for C = 1.00e-04 is 51.1 % (||w|| = 0.0399)
din setul de date complet
Accuracy for C = 1.00e-03 is 93.6 % (||w|| = 0.3021)
Accuracy for C = 1.00e-02 is 92.6 % (||w|| = 1.1025)
Accuracy for C = 1.00e-01 is 94.7 % (||w|| = 2.2699)
Accuracy for C = 1.00e+00 is 94.7 % (||w|| = 3.5367)
Accuracy for C = 1.00e+01 is 94.7 % (||w|| = 4.3114)
Accuracy for C = 1.00e+02 is 94.7 % (||w|| = 4.4789)
Regresia Logistică Multi-clasă
• Există două moduri de a extinde LR la multi-clasă
1. Un mod direct ar normaliza termenii exponențiali pentru a da suma 1:
exp 𝐰𝑘𝑇 𝐱 + 𝑏𝑘
𝑝 𝑐=𝑘𝐱 = 𝐾
σ𝑗=1 exp 𝐰𝑗𝑇 𝐱 + 𝑏𝑗
însă, unul dintre termeni nu este necesar, deoarece probabilitățile însumate dau 1
2. Astfel, putem avea un model alternativ cu mai puțini parametri:
exp 𝐰𝑘𝑇 𝐱 + 𝑏𝑘
𝑝 𝑐=𝑘𝐱 = 𝐾−1 𝑇
, 𝑘 = 1, 2, … , 𝐾 − 1
σ
1 + 𝑗=1 exp 𝐰𝑗 𝐱 + 𝑏𝑗
1
𝑝 𝑐=𝐾𝐱 =
1 + σ𝐾−1 𝑇
𝑗=1 exp 𝐰𝑗 𝐱 + 𝑏𝑗
Versiunea 1 Multi-clasă
• Prima abordare generează un model de probabilitate 𝑝 𝑐 = 𝑘 𝐱 pentru
fiecare clasă
• Totuși, modelul nu este adecvat: sunt un număr infinit de soluții (prin
scalare)
• Astfel, modelul trebuie să fie regularizat pentru a crea o soluție unică
• Acesta este modelul dat de scikit-learn
# Cod de antrenare:
from sklearn.linear_model import LogisticRegression

clf = LogisticRegression(solver='lbfgs', multi_class='auto') # Parametri modelului:


clf.fit(X, y) print(clf.coef_)
[[-0.93349507 -1.24913676]
[-0.89366715 0.79864276]
# Cod de testare: [1.82716222 0.45049400]]
print(clf.predict([[1,-2], [4, -6]]))
[1.00000000 2.00000000] print(clf.intercept_)
[-2.00001286 4.41793321 -2.41792035]
print(clf.predict_proba([[1,-2], [4, -6]]))
[[0.08359735 0.88733866 0.02906399]
[0.39434184 0.00130708 0.60435107]]
Versiunea 2 Multi-clasă
• A doua versiune este mai veche
• Are o soluție unică chiar și fără regularizare
• Nu este implementat în scikit-learn, dar poate fi găsit în
librăria statsmodels
# Cod de antrenare:
from statsmodels.api import MNLogit

# statsmodel are un API un pic diferit.


# In realitate, X ar trebui sa aibe o medie 0, dar
# putem simplifica putin codul. # Parametri modelului:
clf = MNLogit(y, X) print(clf.params)
clf = clf.fit() [[0.69060867 1.46679893]
[0.68023711 0.93667422]]
# Nota: doar doua seturi de ponderi.
# Cod de testare: # Nota2: fara intercept; presupune medie 0
print(clf.predict([[1,-2], [4, -6]]))
[[0.45919554 0.23500589 0.30579857]
[0.39249897 0.10495650 0.50254454]]
# clf.predict() intoarce probabilitati.
# Pentru a gasi clasele, gasim maximul:
print(clf.predict([[1,-2], [4, -6]]).argmax(axis = 1))
[0 2]
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 06 – Rețele Neuronale și Învățare Profundă
prof. dr. ing. Robert Győrödi
Sumar

• În acest curs vom discuta despre rețele neuronale


– Tradiționale
– Deep Learning (Învățare Profundă)
Rețele Neuronale Tradiționale
• Rețelele neuronale au fost studiate de decenii
• Rețelele tradiționale erau rețele total conectate (denumite dense) constând din 1-3 nivele
• Dimensiunile de intrare erau tipic de ordinul a câteva sute dintr-o mulțime de categorii
• Astăzi, intrările pot avea 10k...100k variabile din mii de clase și rețeaua poate avea peste 1000
de nivele
Rețele Neuronale Tradiționale
• Neuronul unei rețele simple este ilustrat mai jos
• În esență, neuronul este un produs punct dintre intrări și ponderi urmat de o
neliniaritate, de obicei logsig sau tanh

• Cu alte cuvinte: este un model de regresie logistică, iar întreaga rețea este pur și
simplu o stivă de modele logreg
Antrenarea Rețelei
• În trecut, a fost un accent destul de mare pe
algoritmii de antrenare: gradient conjugat,
Levenberg-Marquardt, etc.
• Astăzi, optimizatoarele sunt mai puțin matematici:
stohastic gradient descent, RMSProp, Adam
Backpropagation
• Rețeaua este antrenată prin ajustarea ponderilor
corespunzător cu derivatele parțiale
𝜕ℇ
𝑤𝑖𝑗 ← 𝑤𝑖𝑗 − 𝜂
𝜕𝑤𝑖𝑗
• Cu alte cuvinte, ponderea a j-a a nodului al i-lea
trece spre gradientul negativ cu pasul 𝜂 > 0
• În anii 1990 structura rețelei era destul de fixă și
formula era derivată manual
• Astăzi, se aplică același principiu, dar forma
exactă este calculată simbolic
Backpropagation în Haykin:
Neural networks, 1999
Înainte și Înapoi
• Antrenarea are două treceri: pasul înainte și pasul înapoi
• Pasul înainte alimentează rețeaua cu una (sau mai multe) exemple
• Pasul înapoi calculează eroarea (medie) și propagă gradienții înapoi ajustând ponderile una câte una
• Când rețeaua a fost alimentată cu toate exemplele, a trecut o epocă. În mod tipic rețeaua rulează
pentru mii de epoci
Pachete Software pentru Rețele Neuronale
• Tensorflow: Motor de deep learning de la Google. A fost deschis în 2015 noiembrie.
– Suportat de Keras, care este integrat cu TF de la versiunea 2.0 a TF
• MS Cognitive TK (CNTK): Motor de deep learning de la Microsoft.
– Suportat de Keras
• mxnet: Deep learning scalabil (ex. Android). Primul în multi-gpu. Mulți contributori.
– Suportat de Keras
• PlaidML: Backend OpenCL.
– Suportat de Keras
• Torch: Librărie implementată în limbajul Lua (Facebook). Interfață Python via pyTorch

• Toate în afară de PlaidML folosesc ca și nivel intermediar cuDNN de la Nvidia


Popularitatea platformelor de deep learning

https://towardsdatascience.com/deep-
https://madhav.run/tag/c/ learning-framework-power-scores-2018-
23607ddf297a
Antrenarea unei rețele cu 2 nivele folosind Keras
# Cod de antrenare:
import tensorflow as tf

# Prima data initializam modelul. "Sequential" inseamna ca nu sunt cicluri.


clf = tf.keras.models.Sequential()

# Adaugam nivele unul cate unul. Fiecare cu cate 100 noduri.


clf.add(tf.keras.layers.Dense(100, input_dim=2, activation = 'sigmoid'))
clf.add(tf.keras.layers.Dense(100, activation = 'sigmoid'))
clf.add(tf.keras.layers.Dense(1, activation = 'sigmoid'))

# Codul este compilat pentru CUDA sau C++


clf.compile(loss='mean_squared_error', optimizer='sgd')
clf.fit(X, y, epochs = 20, batch_size = 16) # ia cateva secunde

# Cod de testare:
# Probabilitati
print(clf.predict(np.array([[1, -2], [-3, -5]])))
[[0.5212911]
[0.4997456]]

# Clase
print(clf.predict(np.array([[1, -2], [-3, -5]])) > 0.5)
[[ True]
[False]]
Deep Learning
• Cercetarea în domeniul rețelelor neuronale a fost destul de redus după rapida
expansiune din anii 1990
• Subiectul fierbinte al anilor 2000 au fost SVM și big data
• Totuși, la sfârșitul decadei, rețelele neuronale au început să câștige în
popularitate din nou: Un grup de la Univ. Toronto, condus de Prof. Geoffrey
Hinton a studiat rețele adânci neconvenționale folosind pre-antrenare ne-
supervizată
• Ei au descoperit că antrenarea unor rețele neuronale mari este într-adevăr
posibilă cu un pas de pre-antrenare nesupervizată care inițializează ponderile
rețelei într-o manieră pe nivele
• Un alt factor cheie pentru succes a fost creșterea rapidă a puterii
computaționale aduse de Unitățile de Procesare Grafică (GPU) recente
Pre-antrenare Nesupervizată
• Au existat două probleme principale pentru cauza limitării la 2-3 nivele a rețelelor neuronale:
1. Eroarea are zone de minim local mari pentru rețele adânci: Antrenarea rămâne blocată la
una dintre acestea
2. Gradientul dispare la nivelele inferioare: Funcția de activare logistică tinde să scadă
magnitudinea gradientului la fiecare nivel; eventual gradientul la nivelele inferioare este
foarte mic astfel acestea nu se mai antrenează deloc
• Acum 10 ani s-a descoperit că ambele probleme pot fi corectate prin pre-antrenare ne-supervizată:
– Antrenarea modelelor pe nivele care au învățat să reprezinte datele (fără etichete de clase, fără
clasificare, doar să încerce să învețe să reproducă datele)
– Inițializarea rețelei cu ponderi ale modelului ne-supervizat și antrenează într-un mod
supervizat
– Unelte uzuale: restricted Boltzmann machine (RBM), deep belief network (DBN), autoencoders,
etc.
Înapoi la Antrenarea Supervizată
• După ce s-a declanșat entuziasmul pentru rețele adânci, a pornit și studiul
abordărilor total supervizate (antrenarea pur supervizată este mai
familiară, bine explorată și o abordare mai puțin înfricoșată)
• Câteva descoperiri cheie evită nevoia pre-antrenării:
– Funcții noi de activare care conservă mai bine gradientul peste nivele;
cel mai important Rectified Linear Unita: ReLU(x)=max(0,x).
– Tehnici inedite de inițializare a ponderilor; ex. inițializarea Glorot
(inițializarea Xavier) ajusetază magnitudinea ponderilor inițiali pe
niveleb.
– Regularizarea dropout (lăsarea pe dinafară); evitarea supra-potrivirii
prin injectarea de zgomot în rețeac. Neuroni individuali sunt opriți
aleator în faza de antrenare.
aGlorot, Bordes și Bengio. ”Deep sparse rectifier neural networks”
bGlorot și Bengio. ”Understanding the difficulty of training deep feedforward neural networks”
cSrivastava, Hinton, Krizhevsky, Sutskever și Salakhutdinov. ”Dropout: A simple way to prevent neural networks from overfitting”
Nivele Convoluționale
• În plus față de tehnicile inovative pentru antrenare, au
fost adoptate și noi arhitecturi de rețele
• Cel mai important dintre acestea este nivelul
convoluțional, care conservă topologia intrărilor
• Rețele convoluționale au fost propuse deja în 1989, dar
au avut un rol destul de marginal cât timp dimensiunile
imaginilor erau mici (ex. setul de date MNIST din 1990
are dimensiunile 28 x 28, comparat cu referința curenta
ImageNet cu dimensiunea 256 x 256)
Rețele Convoluționale
• Structura tipică a unei rețele convoluționale repetă următoarele elemente:
convoluție  neliniaritate  subeșantionare
1. Convoluția filtrează intrarea cu un număr de nuclee convoluționale. În primul nivel acestea
pot fi, ex. 9 x 9 x 3; adică acestea văd o fereastră locală pentru toate nivelele RGB
• Rezultatele sunt numite feature maps și în mod tipic sunt o mulțime de acest fel
2. ReLU transmite hărțile de caracteristici printr-un Rectified Linear Unit pe pixeli
• ReLU(x) = max(0, x)
3. Subeșantionarea contractă dimensiunile de intrare printr-un factor întreg
• Original acest lucru a fost realizată prin medierea fiecărui bloc 2 x 2
• Astăzi, maxpooling este mai folosit (preia maximul fiecărui bloc 2 x 2)
• Subeșantionarea reduce dimensiunea datelor și îmbunătățește invarianța spațială
Rețele Convoluționale: Exemple
• Hai să antrenăm un convnet cu faimosul set de date
MNIST
• MNIST constă din 60000 imagini de antrenare și 10000
imagini de testare, reprezentând numere scrise de mână
de la poșta SUA
• Fiecare imagine are 28 x 28 pixeli și sunt 10 categorii
• În general este considerat o problemă ușoară: Regresia
logistică oferă o acuratețe de peste 90% iar convnet
poate atinge (aproape) 100%
• Totuși, acum 10 ani, cea mai bună eroare era încă peste
1%
Rețele Convoluționale: Exemple
# Cod de antrenare model = Sequential()
from tensorflow.keras.datasets import mnist # Layer 1: necesita si input_shape.
from tensorflow.keras.models import Sequential model.add(Conv2D(num_featmaps, (w, h),
from tensorflow.keras.layers import Dense, Activation, Flatten, input_shape=(28, 28, 1),
Conv2D, MaxPooling2D activation = 'relu'))
from tensorflow.keras.utils import to_categorical
import numpy as np # Layer 2:
import os model.add(Conv2D(num_featmaps, (w, h), activation = 'relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# Folosim baza de date de cifre scrise de mana "MNIST".
# 60000 imagini de antrenare si 10000 imagini de testare # Layer 3: nivel dens cu 128 noduri
# cu dimensiunea 28x28 # Flatten() vectorizeaza datele: 32x10x10 -> 3200
(X_train, y_train), (X_test, y_test) = mnist.load_data() # (10x10 in loc de 14x14 datorita efectului de margine)
model.add(Flatten())
# Keras presupune intrare 4D, dar MNIST nu are canalul de culoare. model.add(Dense(128, activation = 'relu'))
# -> Adaugam o dimensiune falsa la capat.
X_train = X_train[..., np.newaxis] / 255.0 # Layer 4: Ultimul nivel producand 10 iesiri.
X_test = X_test[..., np.newaxis] / 255.0 model.add(Dense(num_classes, activation='softmax'))

# Rezultatul trebuie sa fie one-hot-encoded # Compilare si antrenare


y_train = to_categorical(y_train) model.compile(loss='categorical_crossentropy',
y_test = to_categorical(y_test) optimizer='adam',
num_featmaps = 32 # Numarul de filtre pe nivel metrics = ['accuracy'])
num_classes = 10 # Cifre 0,1,...,9
num_epochs = 50 # Arata toate exemplele de 50 de ori model.fit(X_train, y_train, epochs = 10,
w, h = 5, 5 # Dimensiunea ferestrei de convolutie validation_data = (X_test, y_test))
Rețele Convoluționale: Log Antrenare
• Codul rulează cam 1 minut pe un GPU
• Pe un CPU, ar lua cam 30 minute (1 epocă ≈ 200 sec)
Train on 60000 samples, validate on 10000 samples
Epoch 1/10
60000/60000 [==============================] - 75s 1ms/sample - loss: 0.1107 - accuracy: 0.9669 - val_loss: 0.0428 - val_accuracy: 0.9850
Epoch 2/10
60000/60000 [==============================] - 72s 1ms/sample - loss: 0.0373 - accuracy: 0.9880 - val_loss: 0.0333 - val_accuracy: 0.9889
Epoch 3/10
60000/60000 [==============================] - 74s 1ms/sample - loss: 0.0268 - accuracy: 0.9912 - val_loss: 0.0299 - val_accuracy: 0.9898
Epoch 4/10
60000/60000 [==============================] - 73s 1ms/sample - loss: 0.0175 - accuracy: 0.9943 - val_loss: 0.0264 - val_accuracy: 0.9908
Epoch 5/10
60000/60000 [==============================] - 73s 1ms/sample - loss: 0.0142 - accuracy: 0.9956 - val_loss: 0.0345 - val_accuracy: 0.9901
Epoch 6/10
60000/60000 [==============================] - 73s 1ms/sample - loss: 0.0110 - accuracy: 0.9964 - val_loss: 0.0381 - val_accuracy: 0.9900
Epoch 7/10
60000/60000 [==============================] - 73s 1ms/sample - loss: 0.0092 - accuracy: 0.9970 - val_loss: 0.0364 - val_accuracy: 0.9906
Epoch 8/10
60000/60000 [==============================] - 72s 1ms/sample - loss: 0.0073 - accuracy: 0.9977 - val_loss: 0.0401 - val_accuracy: 0.9910
Epoch 9/10
60000/60000 [==============================] - 75s 1ms/sample - loss: 0.0078 - accuracy: 0.9975 - val_loss: 0.0354 - val_accuracy: 0.9918
Epoch 10/10
60000/60000 [==============================] - 81s 1ms/sample - loss: 0.0066 - accuracy: 0.9978 - val_loss: 0.0391 - val_accuracy: 0.9914
Salvarea și Încărcarea Rețelei
• Rețeaua poate fi salvată și încărcată pe/de pe disc într-o manieră simplă:
– Salvarea:
model.save('my_net.h5')

– Încărcarea:
from tensorflow.keras.models import load_model
load_model('my_net.h5')

• Rețeaua este salvată în formatul HDF5. HDF5 este un format de serializare similar .mat sau .pkl, dar mult mai eficient
• Folosim HDF5 pentru stocarea datelor cu h5py
# Salvare np.array X in fisier h5:
import h5py
with h5py.File('my_data.h5', 'w') as h5:
h5['X'] = X

# Incarca np.array X din fisier h5:


import h5py
with h5py.File('my_data.h5', 'r') as h5:
X = np.array(h5['X'])

# Nota: Nu faceti cast la numpy decat daca este necesar.


# Datele pot fi accesate din h5 direct.
Structura Rețelei
• Este posibil să ne uităm peste filtrele din nivelele convoluționale
# Ponderile de pe primul nivel (figurile din dreapta):
weights = model.layers[0].get_weights()[0]

• Nivelul secundar este dificil să fie vizualizat, deoarece intrarea este


32-dimensional:
# Ponderile nivelului 0:
print(model.layers[0].get_weights()[0].shape)
(5, 5, 1, 32)
# Ponderile nivelului 1:
print(model.layers[1].get_weights()[0].shape)
(5, 5, 32, 32)

• Nivelul dens este al 5-lea (conv → conv → maxpool → dropout →


flatten → dense)
# Ponderile nivelului 4 mapeaza 3200 intrari la 128 iesiri.
# Acesta este exact o multiplicare de matrici.
print(model.layers[4].get_weights()[0].shape)
(3200, 128)
Activările Rețelei

• Ieșirile nivelului sunt de obicei


mai interesante decât filtrele
• Și acestea pot fi vizualizate
• Pentru detalii vedeți Keras FAQ
Activările Nivelului Secundar

• Pe următorul nivel, figurile sunt


sub-eșantionate la 12 x 12
• Acest lucru oferă invarianță
spațială: Rezultă aceeași activare
deși intrarea ar fi puțin deplasată
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 07 – Aplicații și Învățare Profundă – Stare curentă
prof. dr. ing. Robert Győrödi
Sumar

• În acest curs vom discuta despre rețele neuronale


– Ce este învățarea profundă (Deep Learning)?
• Rețele recurente
• Modelarea textului (LSTM)
Ce este învățarea profundă?
https://www.youtube.com/watch?v=7V8jrdH5tAQ
• Listă lungă de operații de https://www.youtube.com/watch?v=PL3xJErjEgU

procesare
• Proiectată prin arătarea
de exemple
• Exemple:
Recunoașterea imaginilor
• Imagenet este setul de imagini de
referință standard pentru
recunoașterea imaginilor
• Clasificarea unor imagini 256x256 în
1000 de categorii, cum ar fi
”persoană”, ”bicicletă”, ”animal”, etc.
• În total 1.3M imagini
• Multe metrici pentru erori, incluzând
top-5 erori: rata erorii cu 5 estimări
ImageNet classification with deep convolutional neural networks
Alex Krizhevsky et al., 2012
Computer Vision
• Folosit pentru logistică din 1994
• Plăcuțe de înmatriculare (LRP), coduri containere, ...
• Cum se poate crește într-un mediu cu competiție acerbă?
– Agil
– Inovativ
– Credibil
– Orientat spre client
– Folosind tehnologie de vârf
Ce s-a schimbat în 20 de ani?
• În 1996: • În 2016:
– Imagini mici (10x10) – Imagini mari (256x256)
– Puține clase (< 100) – Multe clase (> 1K)
– Rețele mici (< 4 nivele) – Rețele adânci (> 100 kerrosta)
– Date puține (< 50K imagini) – Date multe (> 1M imagini)
Evoluția adâncimii rețelelor din 2012
• ILSVRC Image Recognition Task
– 1.3 milioane imagini
Echipa Anul Loc Eroare Nivele
– 1000 categorii (top-5)
SuperVision 2012 1 15.30% 8

VGG 2014 2 7.32% 16


• Înainte de 2012: 25.7% GoogLeNet 2014 1 6.67% 22

MSRA 2015 1 3.57% 152

Trimps-Soushen (multe rețele) 2016 1 2.99% 152

Uni Oxford (multe rețele, nivele 2017 1 2.25% 101


bloc)
ILSVRC2012
• Imagenet Large Scale Visual Recognition Challenge
2012 a fost un punct de cotitură
• ConvNet-urile au scăzut eroarea top-5 de la 26.2% la
15.3%
• Rețeaua se numește AlexNet după primul autor
• Rețeaua conține 8 nivele (5 convoluționale urmate de
3 dense) – în total 60 milioane parametri
Rețeaua AlexNet
• Arhitectura este ilustrată în figura de mai jos
• Fluxul de procesare este divizat pe două căi (sus și jos) pentru a se încadra
în memoria de 3GB a GPU disponibilă la acel moment (rulând pe 2 GPU-
uri)
• A introdus multe trucuri pentru augmentarea datelor
• Întoarcere stânga-dreapta
• Decupare sub-imagini (224x224)

ImageNet classification with deep convolutional neural networks


Alex Krizhevsky et al., 2012
ILSVRC2014
• Din 2012, ConvNet-urile au dominat competiția
• În 2014 au fost două echipe aproape egale:
– GoogLeNet cu 6.66% top-5 eroare
– VGG cu 7.33% top-5 eroare
• În anumite sub categorii VGG a fost câștigător
• GoogLeNet: 22 nivele, doar 7M parametri datorită unei
structuri total convoluționale și a unei arhitecturi de
inițializare ingenioase
• VGG: 16 nivele, 144M parametri
Modulul de inițializare
• Câștigătorul din 2014 al ILSVRC (Google) a introdus un
”inception module” în soluția lor GoogLeNet
• Idea era să se aplice mai multe nuclee convoluționale la
fiecare nivel, astfel reducând calculele necesare comparativ
cu convoluțiile comune la acea vreme de 5x5 sau 7x7
• Deasemenea, adâncimea a fost crescută de pierderi auxiliare

Szegedy, et. al. ”Going deeper with convolutions” CVPR 2015


Câteva rețele renumite

https://ai.googleblog.com/2017/11/automl-for-large-scale-image.html Sandler et. al. ”MobileNetV2: Inverted Residuals and Linear Bottlenecks”, 2018
ILSVRC2015
• Câștigător MSRA (Microsoft Research)
cu eroarea top-5 3.57%
• 152 nivele! 51M parametri
• Construit din blocuri reziduale (care
includ trucul de inițializare din anul
precedent)
• Idea principală este de a adăuga
scurtături de identitate, care fac
antrenarea mai ușoară

ICML 2016 Tutorial on Deep Residual Networks


Mobilenets
• Pe partea inferioară, alegerea obișnuită
este de a folosi mobilenets, introduse de
Google în 2017
• Încărcarea computațională a fost redusă
prin convoluții separabile: fiecare
convoluție 3x3 este înlocuită de o
convoluție pe adâncime și punctuală
• Deasemenea folosește și un multiplicator
de adâncime, care reduce adâncimea
canalului cu un factor
𝛼 ∈ 0.25, 0.5, 0.75, 1.0
Howard, Andrew G. et. al. ”MobileNets: Efficient Convolutional
Neural Networks for Mobile Vision Applications” (2017)
Pre-antrenarea
• Cu date puține, de multe ori
se inițializează rețeaua cu o
rețea pre-antrenată
• Acesta poate fi unul dintre
câștigătorii imagnet;
VGG16, ResNet
• Vedeți pentru exemple:
keras.applications
Modelul VGG16
Exemple: Pisici vs. Câini
• Putem studia efectul pre-antrenării cu o
problemă clasică de recunoaștere a
imaginilor: învățarea clasificării imaginilor în
pisici și câini
• Putem folosi baza de date Oxford Cats and
Dogs
• Subset de 7349 imagini din tot setul de date
(2371 pisici, 4978 câni) pentru care există
locația adevărată a capului animalului
Exemplul 1: Proiectare și antrenare de la zero
# Initializarea modelului
model = Sequential()
shape = (64, 64, 3)

# Adaugam sase nivele convolutionale. Adaugam cate un nivel Maxpool dupa fiecare a doua convolutie.
model.add(Conv2D(filters=32, kernel_size=3, padding="same", activation="relu", input_shape=shape))
model.add(Conv2D(filters=32, kernel_size=3, padding="same", activation="relu"))
model.add(MaxPooling2D(2, 2)) # Micsoram caracteristicile la 32x32

model.add(Conv2D(filters=48, kernel_size=3, padding="same", activation="relu"))


model.add(Conv2D(filters=48, kernel_size=3, padding="same", activation="relu"))
model.add(MaxPooling2D(2, 2)) # Micsoram caracteristicile la 16x16

model.add(Conv2D(filters=64, kernel_size=3, padding="same", activation="relu"))


model.add(Conv2D(filters=64, kernel_size=3, padding="same", activation="relu"))
model.add(MaxPooling2D(2, 2)) # Micsoram caracteristicile la 8x8

# Vectorizam reprezentarea 8x8x64 la un vector 4096x1


model.add(Flatten())

# Adaugam un nivel dense cu 128 noduri


model.add(Dense(128, activation="relu"))
model.add(Dropout(0.5))

# In final, nivelul de iesire are 1 iesire cu o neliniaritate logistic sigmoida


model.add(Dense(1, activation="sigmoid"))
Exemplul 1: Proiectare și antrenare de la zero
Exemplul 1: Proiectare și antrenare de la zero

model.compile(loss='sparse_categorical_crossentropy',
optimizer=tf.keras.optimizers.Adam(0.001),
metrics=['accuracy'])

model.fit(
ds_train,
epochs=6,
validation_data=ds_test
)
Întrebări?
Sisteme de Recunoaștere a Formelor
(Machine Learning & Data Mining)
Curs 08 – Data Mining
prof. dr. ing. Robert Győrödi
What is Data Mining?
• Knowledge discovery from data

• Data contains value and knowledge

• But first some figures to consider …


2011
http://www.go-gulf.com/blog/60-seconds/
Data Mining
• But to extract the knowledge data needs to be
– Stored
– Managed
– Analyzed

Data Mining  Big Data 


Predictive Analytics Data Science
What is Data Mining?
• Given lots of data
• Discover patterns and models that are:
– Valid: hold on new data with some certainty
– Useful: should be possible to act on them
– Unexpected: non-obvious to the system
– Undestandable: humans should be able to interpret
the pattern
Short Example
• Student table
Applying Data Mining
• Decision tree
Business Problems for Data Mining

• Churn analysis
• Cross-selling
• Fraud detection
• Risk management
• Customer segmentation
• Targeted ads
• Sales forecast
Domain
• Machine Learning
– Is a scientific discipline that explores the construction and study of algorithms that can learn from data
– In particular you can use Machine Learning algorithms to predict future trends, better structure your
knowledge in a certain domain and gain some meaningful business insights

• In Supervised Learning scenarios you will typically know exactly what you are trying to predict
– For example, numerical or non-numerical values predictions
• Regression
• Classification

• In Unsupervised Learning scenarios you may be lacking a good enough understanding of the problem
domain, in fact typically knowing roughly what you may be looking for, thus you may be relying on the
system to provide some hints to gain a better understanding of the problem domain
– For example, grouping info in logical way or detecting deviations from normal system behaviour
• Clustering
• Anomaly detection
Machine
Learning
Domain

Supervised Unsupervised
Learning Learning

Anomaly
Regression Classification Clustering
Detection
Microsoft Azure
https://searchcloudcomputing.techtarget.com/definition/Windows-Azure

What is Microsoft Azure?


• Microsoft Azure, formerly known as Windows Azure, is
an ever-expanding set of cloud computing services.
– Management portal
– Integrated billing

• A major player in the enterprise public cloud market


– https://searchcloudcomputing.techtarget.com/feature/Expl
oring-capabilities-costs-of-Microsoft-Azure-cloud
Microsoft Azure – Portal
• https://portal.azure.com/
– Multiple services available
Microsoft Azure – Overview
• Combines IaaS and PaaS
• Allows organizations to choose between:
– Public
– Private
– Hybrid clouds environments
• The platform supports popular operating systems, tools,
languages and frameworks, including Windows, Linux,
SQL Server, C# and Java.
• Azure has 99.95% availability
Microsoft Azure – Key Cloud Services
• Compute
– Windows and Linux VMs
• Web and mobile
– Websites, mobile app back-ends
• Data and storage
– SQL, NoSQL (DocumentDB)
• Analytics
– HDInsight (Hadoop), Machine Learning
• Networking
Microsoft Azure – Pricing
• Free one-month trial
• Pay per minute, and only for services you’re using
• Available in a pay-as-you-go model
• Prices vary depending on the type of service
– Free tier
– Standard tier
– VM pricing
– SQL database pricing
Introduction to Azure Machine Learning
• Azure ML is a complete cloud service

• Enables analysts, data scientists, and developers to:


– build, test, and deploy predictive analytics into
• their applications or
• a standalone analysis
Azure Machine Learning Studio
• ML Studio is the development
environment for Azure ML

• Provides a visual workspace to:


– build, test, and iterate on a predictive
model easily and interactively
https://docs.microsoft.com/en-us/azure/machine-learning/studio/what-is-ml-studio

• Allows you to extend your experiment by


writing code in either R or Python scripting
Data Exploration and Visualization
• A dataset is a set of observations Name Age Gender Monthly Income
($)

• Rows or records in the dataset are also Person A 20 Male 2000

known as examples (observations) in the Person B 45 Female 5000

machine learning context Person C 36 Male 3000


Person D 55 Male 6500
Person E 27 Female 2800
• An example (observation) is characterized Person F 31 Male 5900
by a set of features Person G 33 Male 4800
Person X 59 Female 2400

• A feature can be numeric or categorical. Person Y 42 Male 7200


Person Z 29 Female 3100
The Mean
• The mean is the average of numbers
• It is the sum of the sampled values divided by the number of
items in the sample: µ

• Mean of age in the previous dataset:


The Median
• The median is the middle number in a sorted list of numbers

• In a set of numbers where the count is even, the median will


be average of the middle two numbers

• The median for the age from the dataset:


20, 27, 29, 31, 33, 36, 42, 45, 55, and 59
is (33 + 36) / 2 = 34.5
Standard deviation and variance
• The variance (σ2) is the average of the squared
differences from the mean

• Standard deviation (σ) is the square root of variance


Sample statistics for the dataset

Name Age Gender Monthly Income ($)


Mean NaN 37.7 NaN 4270
Median NaN 34.5 NaN 3950
Min NaN 20 NaN 2000
Max NaN 59 NaN 7200
Standard NaN 12.4637 NaN 1850.5555
Deviation
Unique Values 10 10 2 10
Missing Values 0 0 0 0
Feature Type String Feature Numeric Feature String Feature Numeric Feature
Histogram
• A histogram visually shows how data is distributed using bars
of different heights
The box and whiskers plot
• The Box plot is another way to graphically show how the
data is distributed.
– It shows three quartiles of data, Q1, Q2 and Q3 at the
bottom, middle, and top of the box, respectively
• Q1 = 25th percentile = 29.5
• Q2 = Median (50th percentile) = 34.5
• Q3 = 75th percentile = 44.25
• IQR (Interquartile Range) = Q3 – Q1 = 14.75
• Lower Wisker = Max(Min, Q1 – 1.5 * IQR) = 20
• Upper Wisker = Min(Max, Q3 + 1.5 * IQR) = 59
A scatter plot
• A scatter plot is a
graphical representation of two sets of
variables
• A scatter plot visually shows the
relationship between two sets of data
Data Preparation
• In the real world, data is always messy
– missing values
– duplicate records
– data in different formats
– data scattered all around

• Data is required in a proper format or needs some


preprocessing, before applying ML algorithms
Data Manipulation
• Clean missing data
• Removing duplicate rows
• Project columns
• Splitting data
• Removing outliers
• Data normalization
• Feature selection
Feature Selection & Customizations
• ML Studio comes with two modules for feature selection
– Filter Based Feature Selection
– Fisher Linear Discriminant Analysis
Math Models
• Regression
– In statistics regression analysis is a statistical process for
estimating the relationships among variables. Regression
analysis is widely used for prediction and forecasting
– Example: Machine Log (Predicting numeric values)
Understanding regression algorithms
• A regression algorithm predicts a
number for a target variable based on
different features or dependent
variables.
– A target variable in machine learning is
also known as a label
• Before making a prediction, you need
to train an algorithm with a training
dataset where the target value or
the label is known.
• After training the model, you can
make a prediction with the trained
model.
Understanding regression algorithms
• You have to build a model from a given
dataset
– you split the dataset into two sets and
use one as a training dataset and the
other as a test dataset.
• After the model is trained with the
training data, you use the test dataset to
see how the model is performing, that is,
how many errors it has.
Statistics to measure how a model is
performing
• The mean absolute error

• The root mean squared error

• The relative absolute error

• The relative squared error


Statistics to measure how a model is
performing
• The coefficient of determination
Linear regression
• Tries to fit a line to the dataset.

• It is a popular algorithm and probably the oldest


regression algorithm.
Decision forest regression
• Decision forest, or random forest as it is widely known,
is a very popular algorithm.

• Internally, it constructs many decision trees and then


ensembles them as a forest.

• Each decision tree generates a prediction and in the


forest, the predicted values of each tree is averaged out.

• It works well even in the case of noisy data.


Neural network regression
• Neural network is a kind of machine learning algorithm
inspired by the computational models of a human brain.
No free lunch
• There is no model that fits the best for every problem.
– So, one model that fits well for one problem in a domain may not
hold good for another.
Math Models
• Classification
– In statistics classification is the problem of identifying to which of a set
of categories a new observation belongs on the basis of a training set of
data containing observations whose category membership is known
– Example: Machine Log (Predicting non-numeric values)
Classification Models
• Classification is another kind of supervised machine learning.

• In classification you need to predict the class of the


dependent variable

• In a classification problem, you predict a categorical value,


though it may be represented with a number, such as 0 or 1.

• You build a classification model by training an algorithm with


the given training data. In the training dataset, the class or
target variable is already known.
Evaluation Metrics
• True positive (TP)

• False positive (FP)

• True negative (TN)

• False negative (FN)

• Accuracy = (TP + TN) / (TP + TN + FP + FN)


Evaluation Metrics
• Precision P = TP / (TP + FP)

• Recall R = TP / (TP + FN)

• F1 score = 2TP / (2TP + FP + FN) = 2PR / (P + R)

• Threshold
Understanding ROC and AUC
• The receiver operating
characteristics (ROC) graph is a two-
dimensional graph in which the true
positive rate (TP) is plotted on the y axis
and the false positive rate (FP) is plotted on
the x axis.

• The Area Under the Curve (AUC) is a


portion of the area under the ROC curve of
the unit square; its value will always
be between 0 and 1, where 1 is the best
case or everything is predicted correctly.
Classification by Decision Tree Induction

• Decision tree
– A flow-chart-like tree structure
– Internal node denotes a test on an attribute
– Branch represents an outcome of the test
– Leaf nodes represent class labels or class distribution
• Decision tree generation consists of two phases
– Tree construction
• At start, all the training examples are at the root
• Partition examples recursively based on selected attributes
– Tree pruning
• Identify and remove branches that reflect noise or outliers
• Use of decision tree: Classifying an unknown sample
– Test the attribute values of the sample against the decision tree
Training Dataset
• This follows an example from Quinlan’s ID3
age income student credit_rating buys_computer
<=30 high no fair no
<=30 high no excellent no
31…40 high no fair yes
>40 medium no fair yes
>40 low yes fair yes
>40 low yes excellent no
31…40 low yes excellent yes
<=30 medium no fair no
<=30 low yes fair yes
>40 medium yes fair yes
<=30 medium yes excellent yes
31…40 medium no excellent yes
31…40 high yes fair yes
>40 medium no excellent no
Output: A Decision Tree for
“buys_computer”
age?

<=30 30..40 >40

student? yes credit rating?

no yes excellent fair

no yes no yes
Algorithm for Decision Tree Induction

• Basic algorithm (a greedy algorithm)


– Tree is constructed in a top-down recursive divide-and-conquer manner
– At start, all the training examples are at the root
– Attributes are categorical (if continuous-valued, they are discretized in advance)
– Examples are partitioned recursively based on selected attributes
– Test attributes are selected on the basis of a heuristic or statistical measure
(e.g., information gain)
• Conditions for stopping partitioning
– All samples for a given node belong to the same class
– There are no remaining attributes for further partitioning – majority voting is
employed for classifying the leaf
– There are no samples left
Algorithm for Decision Tree Induction
Algorithm: Generate_decision_tree. Generate a decision tree from the training tuples of data partition D.
Input:
• Data partition, D, which is a set of training tuples and their associated class labels;
• attribute_list, the set of candidate attributes;
• Attribute_selection_method, a procedure to determine the splitting criterion that “best” partitions the data tuples into individual classes. This criterion consists of a
splitting_attribute and, possibly, either a split point or splitting subset.
Output: A decision tree.
Method:
(1) create a node N;
(2) if tuples in D are all of the same class, C then
(3) return N as a leaf node labeled with the class C;
(4) if attribute_list is empty then
(5) return N as a leaf node labeled with the majority class in D; // majority voting
(6) apply Attribute_selection_method(D, attribute_list) to find the “best” splitting_criterion;
(7) label node N with splitting_criterion;
(8) if splitting_attribute is discrete-valued and multiway splits allowed then // not restricted to binary trees
(9) attribute_list <= attribute_list – splitting_attribute; // remove splitting_attribute
(10) for each outcome j of splitting_criterion // partition the tuples and grow subtrees for each partition
(11) let Dj be the set of data tuples in D satisfying outcome j; // a partition
(12) if Dj is empty then
(13) attach a leaf labeled with the majority class in D to node N;
(14) else attach the node returned by Generate_decision_tree(Dj, attribute_list) to node N;
(15) endfor
(16) return N;
Information Gain - Attribute selection
method
• The expected information needed to classify a tuple in D
is given by:
𝐼𝑛𝑓𝑜 𝐷 = − σ𝑚 𝑖=1 𝑝𝑖 log 2 𝑝𝑖
• Information needed after partitioning on A to achieve
an exact classification:
𝑣 𝐷𝑗
𝐼𝑛𝑓𝑜𝐴 𝐷 = σ𝑗=1× 𝐼𝑛𝑓𝑜 𝐷𝑗
𝐷
• Information gain:
𝐺𝑎𝑖𝑛 𝐴 = 𝐼𝑛𝑓𝑜 𝐷 − 𝐼𝑛𝑓𝑜𝐴 (𝐷)
DT Example (1)
• Considering the data in the table and the
Name Gender Height Output1 Output2
Kristina F 1.6 m Short Medium

correct classification in Output1, we have: Jim


Maggie
M
F
2m
1.9 m
Tall
Medium
Medium
Tall

– Short (4/15) Martha


Stephanie
F
F
1.88 m
1.7 m
Medium
Short
Tall
Medium
– Medium (8/15) Bob
Kathy
M
F
1.85 m
1.6 m
Medium
Short
Medium
Medium
– Tall (3/15) Dave
Worth
M
M
1.7 m
2.2 m
Short
Tall
Medium
Tall
Steven M 2.1 m Tall Tall
Debbie F 1.8 m Medium Medium

• Entropy = 4/15 log2(15/4) + 8/15


Todd M 1.95 m Medium Medium
Kim F 1.9 m Medium Tall
Amy F 1.8 m Medium Medium
log2(15/8) + 3/15 log2(15/3) = 1.456565 Wynette F 1.75 m Medium Medium

Entropy(F) = 3/9 log2(9/3) +


6/9 log2(9/6) = 0.918296
• Choosing the gender as the splitting
Entropy(M) = 1/6 log2(6/1) + 2/6
attribute we have: log2(6/2) + 3/6 log2(6/3) = 1.459148
DT Example (2)
• The algorithm must determine what the gain in
information is by using this split.
• To do this, we calculate the weighted sum of these last
two entropies to get:
((9/15) 0.918296) + ((6/15) 1.459148) = 1.134637

• The gain in entropy by using the gender attribute is


thus:
1.456565 – 1.134637 = 0.321928
DT Example (3)
• Looking at the height attribute, we divide it into ranges:
(0, 1.6], (1.6, 1.7], (1.7, 1.8], (1.8, 1.9], (1.9, 2.0], (2.0, )

• Now we can compute the entropy


– 2 in (0, 1.6]  (2/2(0)+0+0)=0
– 2 in (1.6, 1.7]  (2/2(0)+0+0)=0
– 3 in (1.7, 1.8]  (0+3/3(0)+0)=0
– 4 in (1.8, 1.9]  (0+4/4(0)+0)=0
– 2 in (1.9, 2.0]  (0+1/2(0.5)+1/2(0.5))=0.5
– 2 in (2.0, ]  (0+0+2/2(0))=0
DT Example (4)
• All the states are completely ordered (entropy 0) except for
the (1.9, 2.0] state.
• The gain in entropy by using the height attribute is:
1.456565 – 2/15(0.5) = 1.389898

• Thus, this has the greater gain (1.389898 > 0.321928), and
we choose this over gender as the first splitting attribute
DT Example (5)
Height

<=1.6m >2.0m

>1.6m >1.7m >1.8m >1.9m


<=1.7m <=1.8m <=1.9m <=2.0m
Short Short Medium Medium Height Tall
<=1.95m >1.95m

• (1.9, 2.0] – is too large !!! Medium Tall

• A further subdivision on height is needed Height

• We can optimize the tree


<=1.7m >1.7m >1.95m
<=1.95m
Short Medium Tall
Multiclass Classification
• In multiclass classification, you classify in more than two classes

• An evaluation of your model can be done with an accuracy that is


calculated as a ratio of the number of correct predictions versus the
incorrect ones
Math Models
• Clustering
– Clustering is the task of grouping a set of objects in such a way that
objects in the same group (called a cluster) are more similar (in some
sense or another) to each other than to those in other groups (clusters)
– Example: Machine Log (Grouping information)
Clustering
• It's an unsupervised learning where the class or label is
not known.

• With the algorithm, you divide and group the instances


into different clusters with an objective of keeping all
the similar ones together
K-means clustering algorithm
• The most popular clustering algorithm
• The algorithm creates K clusters out of
the dataset where K is a number you
decide
• With the K-means algorithm, K
centroids are determined for K clusters.
– All the points in a cluster are closest to
its centroid than to any other centroids.
Clustering versus classification
• Classification is fundamentally different from clustering

• Classification is a supervised learning problem where


your class or target variable is known to train a dataset.

• Clustering, being an unsupervised learning, it works on a


dataset with no label or class variable.
Math Models
• Anomaly Detection
– In data mining, anomaly detection (or outlier detection) is the
identification of the items, events or observations which do not
conform to an expected pattern or other items in a dataset
– Example: Operator Log (Erroneous data entry)
Demo
• Machine Learning Studio
– Build your own experiment!
– Example: Regression

– How do I create an experiment?


– How do I use math model?
– How do I work with data?
– How do I interpret the result?
Consumption
• Machine Learning as a Service
– Web Service
Publishing a Model as a Web Service
• To be able to use your predictive models in real-life projects
you need to make them available in an environment

• Azure ML allows us to publish a model in an experiment and


make it available as a web service API for others to consume

• You can publish your model in the following simple steps:


– Prepare your model to be published as a web service.
– Prepare a scoring experiment.
– Specify the input and output for the web service.
– Publish and test it as a web service.
Association Rules Mining
What Is Frequent Pattern Analysis?

• Frequent pattern: a pattern (a set of items, subsequences, substructures, etc.) that


occurs frequently in a data set
• First proposed by Agrawal, Imielinski, and Swami [AIS93] in the context of frequent
itemsets and association rule mining
• Motivation: Finding inherent regularities in data
– What products were often purchased together?— Beer and diapers?!
– What are the subsequent purchases after buying a PC?
– What kinds of DNA are sensitive to this new drug?
– Can we automatically classify web documents?
What Is Association Mining?
• Association rule mining:
– Finding frequent patterns, associations, correlations, or causal
structures among sets of items or objects in transaction
databases, relational databases, and other information
repositories.
• Applications:
– Basket data analysis, cross-marketing, catalog design, loss-leader
analysis, clustering, classification, etc.
• Examples:
– Rule form: “Body → Head [support, confidence]”.
– buys(x, “diapers”) → buys(x, “beers”) [0.5%, 60%]
– major(x, “CS”) ^ takes(x, “DB”) → grade(x, “A”) [1%, 75%]
Association Rule: Basic Concepts

• Given: (1) database of transactions, (2) each transaction is a list of items


(purchased by a customer in a visit)
• Find: all rules that correlate the presence of one set of items with that
of another set of items
– E.g., 98% of people who purchase tires and auto accessories also get automotive
services done
• Applications
– *  Maintenance Agreement (What the store should do to boost Maintenance
Agreement sales)
– Home Electronics  * (What other products should the store stocks up?)
– Attached mailing in direct marketing
– Detecting “ping-pong”ing of patients, faulty “collisions”
Rule Measures: Support and Confidence
Customer
Customer
Find all the rules X & Y  Z with
buys both
buys diaper •
minimum confidence and support
– support, s, probability that a
transaction contains {X ^ Y ^ Z}
– confidence, c, conditional probability
that a transaction having {X ^ Y} also
contains Z
Customer
• Let minimum support 50%, and
buys beer minimum confidence 50%, we have
– A  C (50%, 66.6%)
– C  A (50%, 100%)
Transaction ID Items Bought
1000 A,B,C
2000 A,C
3000 A,D
4000 B,E,F
Association Rule Mining: A Road Map

• Boolean vs. quantitative associations (Based on the types of values handled)


– buys(x, “SQLServer”) ^ buys(x, “DMBook”) → buys(x, “DBMiner”) [0.2%, 60%]

– age(x, “30..39”) ^ income(x, “42..48K”) → buys(x, “PC”) [1%, 75%]


• Single dimension vs. multiple dimensional associations (see ex. Above)
• Single level vs. multiple-level analysis
– What brands of beers are associated with what brands of diapers?
• Various extensions
– Correlation, causality analysis
• Association does not necessarily imply correlation or causality
– Maxpatterns and closed itemsets
– Constraints enforced
• E.g., small sales (sum < 100) trigger big buys (sum > 1,000)?
Mining Association Rules — An Example

Transaction ID Items Bought Min. support 50%


1000 A,B,C Min. confidence 50%
2000 A,C
Frequent Itemset Support
3000 A,D
{A} 75%
4000 B,E,F
{B} 50%
{C} 50%
For rule A  C: {A,C} 50%
support = support({A ^ C}) = 50%
confidence = support({A ^ C})/support({A}) = 66.6%
The Apriori principle:
Any subset of a frequent itemset must be frequent
Mining Frequent Itemsets: the Key Step

• Find the frequent itemsets: the sets of items that have minimum
support
– A subset of a frequent itemset must also be a frequent itemset
• i.e., if {AB} is a frequent itemset, both {A} and {B} should be a frequent itemset
– Iteratively find frequent itemsets with cardinality from 1 to k (k-itemset)
• Use the frequent itemsets to generate association rules.
The Apriori Algorithm
• Join Step: Ck is generated by joining Lk-1with itself
• Prune Step: Any (k-1)-itemset that is not frequent cannot be a subset of a
frequent k-itemset
• Pseudo-code:
Ck: Candidate itemset of size k
Lk : frequent itemset of size k
L1 = {frequent items};
for (k = 1; Lk !=; k++) do begin
Ck+1 = candidates generated from Lk;
for each transaction t in database do
increment the count of all candidates in Ck+1 that are contained in t
Lk+1 = candidates in Ck+1 with min_support
end
return k Lk;
The Apriori Algorithm — Example
Database D itemset sup.
L1 itemset sup.
TID Items C1 {1} 2 {1} 2
100 134 {2} 3 {2} 3
200 235 Scan D {3} 3 {3} 3
300 1235 {4} 1 {5} 3
400 25 {5} 3
C2 itemset sup C2 itemset
L2 itemset sup {1 2} 1 Scan D {1 2}
{1 3} 2 {1 3} 2 {1 3}
{2 3} 2 {1 5} 1 {1 5}
{2 3} 2 {2 3}
{2 5} 3
{2 5} 3 {2 5}
{3 5} 2
{3 5} 2 {3 5}
C3 itemset Scan D L3 itemset sup
{2 3 5} {2 3 5} 2
How to Generate Candidates?
• Suppose the items in Lk-1 are listed in an order
• Step 1: self-joining Lk-1
insert into Ck
select p.item1, p.item2, …, p.itemk-1, q.itemk-1
from Lk-1 p, Lk-1 q
where p.item1=q.item1, …, p.itemk-2=q.itemk-2, p.itemk-1 < q.itemk-1

• Step 2: pruning
forall itemsets c in Ck do
forall (k-1)-subsets s of c do
if (s is not in Lk-1) then delete c from Ck
How to Count Supports of Candidates?

• Why counting supports of candidates a problem?


– The total number of candidates can be very huge
– One transaction may contain many candidates
• Method:
– Candidate itemsets are stored in a hash-tree
– Leaf node of hash-tree contains a list of itemsets and counts
– Interior node contains a hash table
– Subset function: finds all the candidates contained in a
transaction
Example of Generating Candidates

• L3={abc, abd, acd, ace, bcd}


• Self-joining: L3*L3
– abcd from abc and abd
– acde from acd and ace

• Pruning:
– acde is removed because ade is not in L3

• C4={abcd}
Methods to Improve Apriori’s Efficiency

• Hash-based itemset counting: A k-itemset whose corresponding hashing


bucket count is below the threshold cannot be frequent
• Transaction reduction: A transaction that does not contain any frequent
k-itemset is useless in subsequent scans
• Partitioning: Any itemset that is potentially frequent in DB must be
frequent in at least one of the partitions of DB
• Sampling: mining on a subset of given data, lower support threshold + a
method to determine the completeness
• Dynamic itemset counting: add new candidate itemsets only when all of
their subsets are estimated to be frequent
Is Apriori Fast Enough? Performance
Bottlenecks
• The core of the Apriori algorithm:
– Use frequent (k – 1)-itemsets to generate candidate frequent k-itemsets
– Use database scan and pattern matching to collect counts for the candidate itemsets
• The bottleneck of Apriori: candidate generation
– Huge candidate sets:
• 104 frequent 1-itemset will generate 107 candidate 2-itemsets
• To discover a frequent pattern of size 100, e.g., {a1, a2, …,
a100}, one needs to generate 2100  1030 candidates.
– Multiple scans of database:
• Needs (n +1 ) scans, n is the length of the longest pattern
Presentation of Association Rules (Table Form )
Visualization of Association Rule
Using Plane Graph
Visualization of Association Rule
Using Rule Graph
Social Impact of Data Mining
Data Mining:
Merely Managers' Business or Everyone's?
• Data mining will surely be an important tool for managers’ decision
making
– Bill Gates: “Business @ the speed of thought”
• The amount of the available data is increasing, and data mining systems
will be more affordable
• Multiple personal uses
– Mine your family's medical history to identify genetically-related medical
conditions
– Mine the records of the companies you deal with
– Mine data on stocks and company performance, etc.
• Invisible data mining
– Build data mining functions into many intelligent tools
Social Impacts:
Threat to Privacy and Data Security?
• Is data mining a threat to privacy and data security?
– “Big Brother”, “Big Banker”, and “Big Business” are carefully
watching you
– Profiling information is collected every time
• You use your credit card, debit card, supermarket loyalty card, or
frequent flyer card, or apply for any of the above
• You surf the Web, reply to an Internet newsgroup, subscribe to a
magazine, rent a video, join a club, fill out a contest entry form,
• You pay for prescription drugs, or present you medical care number
when visiting the doctor
– Collection of personal data may be beneficial for companies
and consumers, there is also potential for misuse
Protect Privacy and Data Security

• Fair information practices


– International guidelines for data privacy protection
– Cover aspects relating to data collection, purpose, use, quality, openness,
individual participation, and accountability
– Purpose specification and use limitation
– Openness: Individuals have the right to know what information is collected
about them, who has access to the data, and how the data are being used
• Develop and use data security-enhancing techniques
– Blind signatures
– Biometric encryption
– Anonymous databases
• GDPR !!!
Întrebări?

S-ar putea să vă placă și

  • Proiect Arhitectura Sistemelor de Calcul (DOCA, PATER, KOVACS 1631)
    Proiect Arhitectura Sistemelor de Calcul (DOCA, PATER, KOVACS 1631)
    Document20 pagini
    Proiect Arhitectura Sistemelor de Calcul (DOCA, PATER, KOVACS 1631)
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document40 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Problema UBD
    Problema UBD
    Document20 pagini
    Problema UBD
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document39 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document44 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document44 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document35 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document40 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document38 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document35 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări
  • Curs PCLP
    Curs PCLP
    Document37 pagini
    Curs PCLP
    Bogdan Sopota
    Încă nu există evaluări