TipCo se naučíte

V této kapitole se naučíte:

  • Pravidlo pro součet a rozdíl
  • Pravidlo pro součin a podíl
  • Řetízkové pravidlo (chain rule) - klíč k backpropagation
  • Derivace složených funkcí
  • Symbolické derivace pomocí SymPy

13.1 Proč potřebujeme pravidla?

V praxi se setkáváme se složitými funkcemi, které jsou kombinací jednoduchých. Potřebujeme pravidla, jak derivovat:

  • Součet funkcí: \(f(x) + g(x)\)
  • Součin funkcí: \(f(x) \cdot g(x)\)
  • Složené funkce: \(f(g(x))\)

Tato pravidla jsou základem backpropagation v neuronových sítích!


13.2 Pravidlo pro konstantní násobek

\[(c \cdot f(x))' = c \cdot f'(x)\]

Konstanta “projde” derivací beze změny.

import numpy as np
import matplotlib.pyplot as plt

# Příklad: derivace 3x²
# (3x²)' = 3 · (x²)' = 3 · 2x = 6x

def f(x):
    return 3 * x**2

def f_derivace(x):
    return 6 * x

x = np.linspace(-2, 2, 100)

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, f(x), 'b-', linewidth=2, label='f(x) = 3x²')
ax.plot(x, f_derivace(x), 'r--', linewidth=2, label="f'(x) = 6x")
ax.legend()
ax.grid(True, alpha=0.3)
ax.axhline(y=0, color='k', linewidth=0.5)
ax.set_title("(3x²)' = 3 · (x²)' = 3 · 2x = 6x")
plt.show()


13.3 Pravidlo pro součet a rozdíl

\[(f(x) + g(x))' = f'(x) + g'(x)\]

\[(f(x) - g(x))' = f'(x) - g'(x)\]

Derivace součtu je součet derivací.

# Příklad: (x² + 3x)' = (x²)' + (3x)' = 2x + 3

def f(x):
    return x**2 + 3*x

def f_derivace(x):
    return 2*x + 3

# Ověření numericky
x = 2
h = 0.0001
numericka = (f(x + h) - f(x)) / h
analyticka = f_derivace(x)

print("f(x) = x² + 3x")
print("f'(x) = 2x + 3")
print(f"\nf'(2):")
print(f"  Analyticky: 2·2 + 3 = {analyticka}")
print(f"  Numericky: {numericka:.4f}")
f(x) = x² + 3x
f'(x) = 2x + 3

f'(2):
  Analyticky: 2·2 + 3 = 7
  Numericky: 7.0001

13.4 Pravidlo pro součin

\[(f(x) \cdot g(x))' = f'(x) \cdot g(x) + f(x) \cdot g'(x)\]

PoznámkaPamatovačka

“Derivace prvního krát druhá PLUS první krát derivace druhé”

# Příklad: (x² · sin(x))'
# = (x²)' · sin(x) + x² · (sin(x))'
# = 2x · sin(x) + x² · cos(x)

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return x**2 * np.sin(x)

def f_derivace(x):
    return 2*x * np.sin(x) + x**2 * np.cos(x)

x = np.linspace(0, 2*np.pi, 100)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, f(x), 'b-', linewidth=2, label='f(x) = x² · sin(x)')
ax.plot(x, f_derivace(x), 'r--', linewidth=2, label="f'(x) = 2x·sin(x) + x²·cos(x)")
ax.legend()
ax.grid(True, alpha=0.3)
ax.axhline(y=0, color='k', linewidth=0.5)
ax.set_title("Pravidlo pro součin: (f·g)' = f'·g + f·g'")
plt.show()


13.5 Pravidlo pro podíl

\[\left(\frac{f(x)}{g(x)}\right)' = \frac{f'(x) \cdot g(x) - f(x) \cdot g'(x)}{(g(x))^2}\]

PoznámkaPamatovačka

“Derivace čitatele krát jmenovatel MINUS čitatel krát derivace jmenovatele, to celé děleno jmenovatelem na druhou”

# Příklad: (x / (x+1))'
# f = x, f' = 1
# g = x+1, g' = 1
# = (1·(x+1) - x·1) / (x+1)² = (x+1-x) / (x+1)² = 1 / (x+1)²

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return x / (x + 1)

def f_derivace(x):
    return 1 / (x + 1)**2

x = np.linspace(0.1, 5, 100)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, f(x), 'b-', linewidth=2, label='f(x) = x/(x+1)')
ax.plot(x, f_derivace(x), 'r--', linewidth=2, label="f'(x) = 1/(x+1)²")
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_title("Pravidlo pro podíl")
plt.show()


13.6 Řetízkové pravidlo (Chain Rule)

Řetízkové pravidlo je nejdůležitější pravidlo pro strojové učení. Říká nám, jak derivovat složenou funkci \(f(g(x))\):

\[(f(g(x)))' = f'(g(x)) \cdot g'(x)\]

Nebo v Leibnizově notaci:

\[\frac{df}{dx} = \frac{df}{dg} \cdot \frac{dg}{dx}\]

VarováníProč je to klíčové?

Backpropagation v neuronových sítích je opakované použití řetízkového pravidla! Gradient se “řetězí” zpět přes všechny vrstvy.

13.6.1 Příklad: Složená funkce

Derivujme \(f(x) = (x^2 + 1)^3\)

  • Vnější funkce: \(h(u) = u^3\)\(h'(u) = 3u^2\)
  • Vnitřní funkce: \(u(x) = x^2 + 1\)\(u'(x) = 2x\)

\[f'(x) = 3(x^2 + 1)^2 \cdot 2x = 6x(x^2 + 1)^2\]

def f(x):
    return (x**2 + 1)**3

def f_derivace(x):
    return 6 * x * (x**2 + 1)**2

# Ověření
x = 2
h = 0.0001
numericka = (f(x + h) - f(x)) / h
analyticka = f_derivace(x)

print("f(x) = (x² + 1)³")
print("f'(x) = 6x(x² + 1)²")
print(f"\nf'(2):")
print(f"  Analyticky: 6·2·(4+1)² = 12·25 = {analyticka}")
print(f"  Numericky: {numericka:.2f}")
f(x) = (x² + 1)³
f'(x) = 6x(x² + 1)²

f'(2):
  Analyticky: 6·2·(4+1)² = 12·25 = 300
  Numericky: 300.03
Kód
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(12, 4))

# Graf řetězce
ax.text(1, 0.5, 'x', fontsize=20, ha='center', va='center',
        bbox=dict(boxstyle='circle', facecolor='lightblue'))
ax.annotate('', xy=(2.3, 0.5), xytext=(1.5, 0.5),
            arrowprops=dict(arrowstyle='->', lw=2))
ax.text(1.9, 0.7, 'g(x) = x²+1', fontsize=12, ha='center')

ax.text(3, 0.5, 'u', fontsize=20, ha='center', va='center',
        bbox=dict(boxstyle='circle', facecolor='lightgreen'))
ax.annotate('', xy=(4.3, 0.5), xytext=(3.5, 0.5),
            arrowprops=dict(arrowstyle='->', lw=2))
ax.text(3.9, 0.7, 'f(u) = u³', fontsize=12, ha='center')

ax.text(5, 0.5, 'y', fontsize=20, ha='center', va='center',
        bbox=dict(boxstyle='circle', facecolor='lightyellow'))

# Zpětný tok (derivace)
ax.annotate('', xy=(3.5, 0.1), xytext=(4.3, 0.1),
            arrowprops=dict(arrowstyle='->', color='red', lw=2))
ax.text(3.9, -0.1, "df/du = 3u²", fontsize=10, ha='center', color='red')

ax.annotate('', xy=(1.5, 0.1), xytext=(2.3, 0.1),
            arrowprops=dict(arrowstyle='->', color='red', lw=2))
ax.text(1.9, -0.1, "du/dx = 2x", fontsize=10, ha='center', color='red')

ax.text(3, -0.4, "df/dx = df/du · du/dx = 3u² · 2x = 6x(x²+1)²",
        fontsize=12, ha='center', color='red')

ax.set_xlim(0, 6)
ax.set_ylim(-0.6, 1)
ax.axis('off')
ax.set_title('Řetízkové pravidlo: derivace se "řetězí" zpět')
plt.show()

Vizualizace řetízkového pravidla

13.6.2 Více vrstev řetězení

Pro \(f(g(h(x)))\):

\[\frac{df}{dx} = \frac{df}{dg} \cdot \frac{dg}{dh} \cdot \frac{dh}{dx}\]

# f(x) = sin(exp(x²))
# h(x) = x², h'(x) = 2x
# g(u) = exp(u), g'(u) = exp(u)
# f(v) = sin(v), f'(v) = cos(v)

# f'(x) = cos(exp(x²)) · exp(x²) · 2x

import numpy as np

def f(x):
    return np.sin(np.exp(x**2))

def f_derivace(x):
    return np.cos(np.exp(x**2)) * np.exp(x**2) * 2*x

x = 0.5
h = 0.00001
numericka = (f(x + h) - f(x)) / h
analyticka = f_derivace(x)

print("f(x) = sin(exp(x²))")
print("f'(x) = cos(exp(x²)) · exp(x²) · 2x")
print(f"\nf'(0.5):")
print(f"  Analyticky: {analyticka:.6f}")
print(f"  Numericky: {numericka:.6f}")
f(x) = sin(exp(x²))
f'(x) = cos(exp(x²)) · exp(x²) · 2x

f'(0.5):
  Analyticky: 0.363195
  Numericky: 0.363192

13.7 Aplikace: Backpropagation

V neuronové síti máme řetězec operací:

\[\text{input} \xrightarrow{W_1} h_1 \xrightarrow{\sigma} a_1 \xrightarrow{W_2} h_2 \xrightarrow{\sigma} \text{output} \rightarrow \text{Loss}\]

Gradient loss podle \(W_1\) vypočítáme řetízkovým pravidlem:

\[\frac{\partial \text{Loss}}{\partial W_1} = \frac{\partial \text{Loss}}{\partial \text{output}} \cdot \frac{\partial \text{output}}{\partial a_1} \cdot \frac{\partial a_1}{\partial h_1} \cdot \frac{\partial h_1}{\partial W_1}\]

Kód
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(14, 5))

# Forward pass (nahoře)
nodes = ['x', 'W₁x', 'σ(·)', 'W₂·', 'σ(·)', 'Loss']
x_pos = [1, 2.5, 4, 5.5, 7, 8.5]

for i, (node, x) in enumerate(zip(nodes, x_pos)):
    color = 'lightblue' if i < len(nodes)-1 else 'lightyellow'
    ax.add_patch(plt.Rectangle((x-0.4, 0.6), 0.8, 0.6, facecolor=color, edgecolor='blue'))
    ax.text(x, 0.9, node, ha='center', va='center', fontsize=11)
    if i < len(nodes)-1:
        ax.annotate('', xy=(x_pos[i+1]-0.4, 0.9), xytext=(x+0.4, 0.9),
                    arrowprops=dict(arrowstyle='->', color='blue', lw=1.5))

ax.text(5, 1.4, 'Forward pass →', fontsize=12, ha='center', color='blue')

# Backward pass (dole)
for i in range(len(nodes)-1, 0, -1):
    ax.annotate('', xy=(x_pos[i-1]+0.4, 0.3), xytext=(x_pos[i]-0.4, 0.3),
                arrowprops=dict(arrowstyle='->', color='red', lw=1.5))

ax.text(5, 0.1, '← Backward pass (gradients)', fontsize=12, ha='center', color='red')

# Rovnice
ax.text(5, -0.3, r'$\frac{\partial Loss}{\partial W_1} = \frac{\partial Loss}{\partial out} \cdot \frac{\partial out}{\partial h_2} \cdot \frac{\partial h_2}{\partial a_1} \cdot \frac{\partial a_1}{\partial h_1} \cdot \frac{\partial h_1}{\partial W_1}$',
        fontsize=12, ha='center')

ax.set_xlim(0, 10)
ax.set_ylim(-0.5, 1.6)
ax.axis('off')
ax.set_title('Backpropagation: opakované použití řetízkového pravidla')
plt.show()

Backpropagation = řetízkové pravidlo

13.8 Symbolické derivace s SymPy

Pro složité výrazy můžeme použít symbolickou matematiku:

from sympy import symbols, diff, sin, cos, exp, sqrt, simplify

x = symbols('x')

# Definujeme funkci
f = (x**2 + 1)**3

# Derivujeme
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
print(f"f'(x) zjednodušeno = {simplify(f_prime)}")
f(x) = (x**2 + 1)**3
f'(x) = 6*x*(x**2 + 1)**2
f'(x) zjednodušeno = 6*x*(x**2 + 1)**2
# Složitější příklady
priklady = [
    x**5 - 3*x**2 + 2*x - 7,
    sin(x) * cos(x),
    exp(x**2),
    x / (x**2 + 1),
    sqrt(x**2 + 1)
]

print("Symbolické derivace:")
print("-" * 50)
for expr in priklady:
    deriv = diff(expr, x)
    print(f"f(x) = {expr}")
    print(f"f'(x) = {simplify(deriv)}")
    print()
Symbolické derivace:
--------------------------------------------------
f(x) = x**5 - 3*x**2 + 2*x - 7
f'(x) = 5*x**4 - 6*x + 2

f(x) = sin(x)*cos(x)
f'(x) = cos(2*x)

f(x) = exp(x**2)
f'(x) = 2*x*exp(x**2)

f(x) = x/(x**2 + 1)
f'(x) = (1 - x**2)/(x**4 + 2*x**2 + 1)

f(x) = sqrt(x**2 + 1)
f'(x) = x/sqrt(x**2 + 1)

13.8.1 Vyhodnocení v bodě

from sympy import symbols, diff, lambdify
import numpy as np

x = symbols('x')
f = x**3 - 2*x**2 + x

# Derivace
f_prime = diff(f, x)

# Převedeme na Python funkci
f_num = lambdify(x, f, 'numpy')
f_prime_num = lambdify(x, f_prime, 'numpy')

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")

# Vyhodnotíme
bod = 2
print(f"\nf({bod}) = {f_num(bod)}")
print(f"f'({bod}) = {f_prime_num(bod)}")
f(x) = x**3 - 2*x**2 + x
f'(x) = 3*x**2 - 4*x + 1

f(2) = 2
f'(2) = 5

13.9 Tabulka derivací

Funkce \(f(x)\) Derivace \(f'(x)\)
\(c\) \(0\)
\(x^n\) \(n x^{n-1}\)
\(e^x\) \(e^x\)
\(a^x\) \(a^x \ln(a)\)
\(\ln(x)\) \(\frac{1}{x}\)
\(\log_a(x)\) \(\frac{1}{x \ln(a)}\)
\(\sin(x)\) \(\cos(x)\)
\(\cos(x)\) \(-\sin(x)\)
\(\tan(x)\) \(\frac{1}{\cos^2(x)}\)

13.10 Řešené příklady

13.10.1 Příklad 1: Součet

Derivujte \(f(x) = x^4 - 3x^2 + 5x - 2\)

from sympy import symbols, diff

x = symbols('x')
f = x**4 - 3*x**2 + 5*x - 2
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
print("\nPostup:")
print("(x⁴)' = 4x³")
print("(-3x²)' = -6x")
print("(5x)' = 5")
print("(-2)' = 0")
print("Součet: 4x³ - 6x + 5")
f(x) = x**4 - 3*x**2 + 5*x - 2
f'(x) = 4*x**3 - 6*x + 5

Postup:
(x⁴)' = 4x³
(-3x²)' = -6x
(5x)' = 5
(-2)' = 0
Součet: 4x³ - 6x + 5

13.10.2 Příklad 2: Součin

Derivujte \(f(x) = x^2 \cdot e^x\)

from sympy import symbols, diff, exp

x = symbols('x')
f = x**2 * exp(x)
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
print("\nPostup (pravidlo pro součin):")
print("f' = (x²)' · eˣ + x² · (eˣ)'")
print("f' = 2x · eˣ + x² · eˣ")
print("f' = eˣ(2x + x²) = eˣ(x² + 2x)")
f(x) = x**2*exp(x)
f'(x) = x**2*exp(x) + 2*x*exp(x)

Postup (pravidlo pro součin):
f' = (x²)' · eˣ + x² · (eˣ)'
f' = 2x · eˣ + x² · eˣ
f' = eˣ(2x + x²) = eˣ(x² + 2x)

13.10.3 Příklad 3: Podíl

Derivujte \(f(x) = \frac{x^2}{x + 1}\)

from sympy import symbols, diff, simplify

x = symbols('x')
f = x**2 / (x + 1)
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {simplify(f_prime)}")
print("\nPostup (pravidlo pro podíl):")
print("f' = [(x²)'·(x+1) - x²·(x+1)'] / (x+1)²")
print("f' = [2x·(x+1) - x²·1] / (x+1)²")
print("f' = [2x² + 2x - x²] / (x+1)²")
print("f' = (x² + 2x) / (x+1)²")
f(x) = x**2/(x + 1)
f'(x) = x*(x + 2)/(x**2 + 2*x + 1)

Postup (pravidlo pro podíl):
f' = [(x²)'·(x+1) - x²·(x+1)'] / (x+1)²
f' = [2x·(x+1) - x²·1] / (x+1)²
f' = [2x² + 2x - x²] / (x+1)²
f' = (x² + 2x) / (x+1)²

13.10.4 Příklad 4: Řetízkové pravidlo

Derivujte \(f(x) = \sin(x^2)\)

from sympy import symbols, diff, sin, cos

x = symbols('x')
f = sin(x**2)
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
print("\nPostup (řetízkové pravidlo):")
print("Vnější: sin(u), derivace: cos(u)")
print("Vnitřní: u = x², derivace: 2x")
print("f'(x) = cos(x²) · 2x = 2x·cos(x²)")
f(x) = sin(x**2)
f'(x) = 2*x*cos(x**2)

Postup (řetízkové pravidlo):
Vnější: sin(u), derivace: cos(u)
Vnitřní: u = x², derivace: 2x
f'(x) = cos(x²) · 2x = 2x·cos(x²)

13.10.5 Příklad 5: Více vrstev

Derivujte \(f(x) = e^{\sin(x)}\)

from sympy import symbols, diff, sin, exp

x = symbols('x')
f = exp(sin(x))
f_prime = diff(f, x)

print(f"f(x) = {f}")
print(f"f'(x) = {f_prime}")
print("\nPostup:")
print("Vnější: eᵘ, derivace: eᵘ")
print("Vnitřní: u = sin(x), derivace: cos(x)")
print("f'(x) = eˢⁱⁿ⁽ˣ⁾ · cos(x)")
f(x) = exp(sin(x))
f'(x) = exp(sin(x))*cos(x)

Postup:
Vnější: eᵘ, derivace: eᵘ
Vnitřní: u = sin(x), derivace: cos(x)
f'(x) = eˢⁱⁿ⁽ˣ⁾ · cos(x)

13.11 Cvičení

VarováníCvičení 1: Součet

Derivujte \(f(x) = 3x^5 - 2x^3 + x - 7\)

Výsledek: \(f'(x) = 15x^4 - 6x^2 + 1\)

VarováníCvičení 2: Součin

Derivujte \(f(x) = x \cdot \ln(x)\)

Výsledek: \(f'(x) = \ln(x) + 1\)

Řešení \((x)' \cdot \ln(x) + x \cdot (\ln(x))' = 1 \cdot \ln(x) + x \cdot \frac{1}{x} = \ln(x) + 1\)
VarováníCvičení 3: Řetízkové pravidlo

Derivujte \(f(x) = (2x + 1)^4\)

Výsledek: \(f'(x) = 8(2x + 1)^3\)

Řešení

Vnější: \(u^4\), derivace: \(4u^3\)

Vnitřní: \(u = 2x + 1\), derivace: \(2\)

\(f'(x) = 4(2x+1)^3 \cdot 2 = 8(2x+1)^3\)
VarováníCvičení 4: Složená funkce

Derivujte \(f(x) = \sqrt{x^2 + 1}\)

Výsledek: \(f'(x) = \frac{x}{\sqrt{x^2 + 1}}\)

Řešení

\(f(x) = (x^2 + 1)^{1/2}\)

\(f'(x) = \frac{1}{2}(x^2+1)^{-1/2} \cdot 2x = \frac{x}{\sqrt{x^2+1}}\)
VarováníCvičení 5: SymPy

Použijte SymPy k derivaci \(f(x) = \frac{\sin(x)}{x}\)

Řešení
from sympy import symbols, diff, sin, simplify
x = symbols('x')
f = sin(x) / x
print(simplify(diff(f, x)))
# Výsledek: (x*cos(x) - sin(x))/x²
VarováníCvičení 6: Aktivační funkce

Derivujte sigmoid: \(\sigma(x) = \frac{1}{1 + e^{-x}}\)

Výsledek: \(\sigma'(x) = \sigma(x)(1 - \sigma(x))\)

Řešení Toto je slavná vlastnost sigmoidu - jeho derivace se dá vyjádřit pomocí něj samého!

13.12 Shrnutí

PoznámkaCo si zapamatovat
  • Konstantní násobek: \((cf)' = c \cdot f'\)
  • Součet: \((f + g)' = f' + g'\)
  • Součin: \((fg)' = f'g + fg'\)
  • Podíl: \((f/g)' = (f'g - fg')/g^2\)
  • Řetízkové pravidlo: \((f(g(x)))' = f'(g(x)) \cdot g'(x)\)
  • Řetízkové pravidlo = základ backpropagation
  • SymPy umí symbolicky derivovat

V další kapitole rozšíříme derivace na funkce více proměnných – parciální derivace a gradient.