вот моя лекция
Объединю всё содержимое лекции, структурируя его пошагово:

---

### Шаг 1: Постановка задачи

- **Входные данные**: Изображение размером \(28 \times 28\) преобразуется в вектор длиной 784 (обозначим его как \(x\)).
- **Линейная модель**: \(v = W \cdot u + b\), где \(W\) — матрица весов, \(u\) — вектор входных данных, \(b\) — вектор смещений.
- **Функция Softmax и кросс-энтропийная функция потерь**:
  - Применение softmax для получения вероятностей на выходе \(y\).
  - Кросс-энтропийная функция потерь \(L\) для сравнения предсказанных значений \(y\) и истинных меток (labels):
    \[
    L = \text{Cross Entropy Loss}(y, \text{labels})
    \]
- **Задача**: Вычислить следующие градиенты:
  - \( \frac{\partial L}{\partial W} \)
  - \( \frac{\partial L}{\partial b} \)
  - \( \frac{\partial L}{\partial x} \)

---

### Шаг 2: Прямой проход и вычисление промежуточных значений

- **Прямой проход**:
  - Вычисляем все промежуточные значения на каждом шаге, включая \(v\), \(y\), и значение функции потерь \(L\).

---

### Шаг 3: Вычисление \( \frac{\partial L}{\partial y} \)

- **Кросс-энтропийная функция потерь**:
  \[
  L = \sum_{i=1}^{10} \text{labels}_i \cdot \log(y_i)
  \]
- **Производная по \(y\)**:
  \[
  \frac{\partial L}{\partial y_i} = \frac{\text{labels}_i}{y_i}
  \]

---

### Шаг 4: Вычисление \( \frac{\partial L}{\partial v} \)

- **Матрица Якоби для softmax**:
  - Для каждого элемента \(y_i\) и \(u_j\) производные задаются как:
    \[
    \frac{\partial y_i}{\partial u_j} = \begin{cases} 
      y_i(1 - y_i) & \text{если } i = j \\
      -y_i y_j & \text{если } i \neq j 
   \end{cases}
    \]
- **Вычисление производной по \(v\)**:
  \[
  \frac{\partial L}{\partial v} = \frac{\partial y}{\partial v}^T \cdot \frac{\partial L}{\partial y}
  \]

---

### Шаг 5: Вычисление производных по параметрам

#### 1. Производная по \( u \):
   \[
   \frac{\partial L}{\partial u} = W^T \cdot \frac{\partial L}{\partial v}
   \]

#### 2. Производная по \( b \):
   \[
   \frac{\partial L}{\partial b} = \frac{\partial L}{\partial v}
   \]

#### 3. Производная по \( W \):
   - Для матрицы \(W\) производная по каждому элементу задаётся как:
     \[
     \frac{\partial L}{\partial W_{i,j}} = \sum_{k=1}^{10} \frac{\partial L}{\partial v_k} \cdot \frac{\partial v_k}{\partial W_{i,j}} = \frac{\partial L}{\partial v_i} \cdot u_j
     \]
   - Итоговое выражение:
     \[
     \frac{\partial L}{\partial W} = \frac{\partial L}{\partial v} \cdot u^T
     \]

---

### Шаг 6: Финальные формулы градиентов

1. **Градиент по \( W \)**:
   \[
   \frac{\partial L}{\partial W} = \left( \begin{array}{ccc} y_1(1 - y_1) & -y_1y_2 & \dots \\ -y_2y_1 & y_2(1 - y_2) & \dots \\ \dots & \dots & \dots \end{array} \right) \cdot \left( \begin{array}{c} \frac{\text{labels}_1}{y_1} \\ \frac{\text{labels}_2}{y_2} \\ \dots \end{array} \right) \cdot u^T
   \]

2. **Градиент по \( b \)**:
   \[
   \frac{\partial L}{\partial b} = \left( \begin{array}{ccc} y_1(1 - y_1) & -y_1y_2 & \dots \\ -y_2y_1 & y_2(1 - y_2) & \dots \\ \dots & \dots & \dots \end{array} \right) \cdot \left( \begin{array}{c} \frac{\text{labels}_1}{y_1} \\ \frac{\text{labels}_2}{y_2} \\ \dots \end{array} \right)
   \]

3. **Градиент по \( x \)**:
   \[
   \frac{\partial L}{\partial x} = \text{reshape}^{-1}(W^T \cdot \frac{\partial L}{\partial v})
   \]

---

Эти шаги представляют полный вывод формул для обратного распространения ошибки в задаче с softmax и кросс-энтропийной функцией потерь.



вот задание
1. Реализовать для всех слоёв (кроме свёрток) и лосс функции метод grad_x
2. Реализовать для класса сети функцию grad_x
3. Покрыть тестами

вот фрагменты кода, которые нужно заполнить
class NeuralNetwork:
    def __init__(self, layers, loss):
        self.layers = layers
        self.loss = loss
    
    def __call__(self, x):
        return self.forward(x)
    
    def forward(self, x):
        result = x
        for layer in layers:
            result = layer.forward(result)
        return result
    
    def grad_x(self, x, labels):
        # forward
        results = [x]
        result = x
        for layer in layers:
            result = layer.forward(result)
            results.append(result) 
        # L = self.loss(result, labels)
        dL = self.loss.grad_x(result, lables)
        
        for i in range(len(layers) - 1, 0, -1):
            dL = layers[i].grad_x(results[i], dL)
        return dL
        
    
class Layer:
    def __init__(self, ):
        pass
    
    def forward(self, x):
        pass
    
    def backward(self, x, dL):
        return self.grad_x(x, dL), self.grad_params(x)
    
    def grad_x(x, dL):
        pass
    
    def grad_params():
        pass
    
    def __call__(self, x):
        return self.forward(x)



class DenseLayer: # Fully Connected Layer
    def __init__(self, input_length, output_length, W=None, b=None):
        pass
    
    def forward(self, x):
        pass
    
    def __call__(self, x):
        return self.forward(x)
    
    
class ReLU():
    def __init__(self, ):
        pass
    
    def forward(self, x):
        return np.max(0, x)
    
    def __call__(self, x):
        return self.forward(x)
    
class Softmax():
    def __init__(self, ):
        pass
    
    def forward(self, x):
        pass
    
    def __call__(self, x):
        return self.forward(x)
    
    
class Flatten():
    pass
    



class Conv():
    def __init__(self, input_channels, output_channels, kernel_size=(3,3), padding=0, stride=(1,1), weights=None, bias=None):
        pass
    
    def forward(self, x):
        pass
    
    def __call__(self, x):
        return self.forward(x)
    
def conv2matrix(input_size, conv_weights):
    pass



# input is an image 28x28
layer0 = Flatten()
layer1 = DenseLayer(784, 500)
layer2 = ReLU()
layer3 = DenseLayer(500, 100)
layer4 = ReLU()
layer5 = DenseLayer(100, 10)
layer6 = Softmax()

layers = [layer1, layer2, layer3, layer4, layer5, layer6]

net = NeuralNetwork(layers)

x = ...

y = net(x) # net.forward(x)

print(x, y)


Твоя задача завершить фрагменты кода, заполнив его так, как показано в теории на лекции, а также максимально подробно рассказать все с комментариями