fork download
  1. # your code goes here
  2. import numpy as np
  3.  
  4. class XNORNeuralNetwork:
  5. def __init__(self, lr=0.5):
  6. np.random.seed(42)
  7. # Два скрытых слоя для стабильного обучения XNOR
  8. self.W1 = np.random.randn(2, 3) * 0.8
  9. self.b1 = np.zeros((1, 3))
  10. self.W2 = np.random.randn(3, 3) * 0.8
  11. self.b2 = np.zeros((1, 3))
  12. self.W3 = np.random.randn(3, 1) * 0.8
  13. self.b3 = np.zeros((1, 1))
  14. self.lr = lr
  15.  
  16. def sigmoid(self, x):
  17. x = np.clip(x, -500, 500)
  18. return 1 / (1 + np.exp(-x))
  19.  
  20. def sigmoid_derivative(self, x):
  21. return x * (1 - x)
  22.  
  23. def forward(self, X):
  24. self.z1 = np.dot(X, self.W1) + self.b1
  25. self.a1 = self.sigmoid(self.z1)
  26.  
  27. self.z2 = np.dot(self.a1, self.W2) + self.b2
  28. self.a2 = self.sigmoid(self.z2)
  29.  
  30. self.z3 = np.dot(self.a2, self.W3) + self.b3
  31. self.a3 = self.sigmoid(self.z3)
  32.  
  33. return self.a3
  34.  
  35. def backward(self, X, y, output):
  36. m = X.shape[0]
  37.  
  38. # Градиенты выходного слоя
  39. delta3 = (output - y) * self.sigmoid_derivative(output)
  40. dW3 = np.dot(self.a2.T, delta3) / m
  41. db3 = np.sum(delta3, axis=0, keepdims=True) / m
  42.  
  43. # Градиенты второго скрытого слоя
  44. delta2 = np.dot(delta3, self.W3.T) * self.sigmoid_derivative(self.a2)
  45. dW2 = np.dot(self.a1.T, delta2) / m
  46. db2 = np.sum(delta2, axis=0, keepdims=True) / m
  47.  
  48. # Градиенты первого скрытого слоя
  49. delta1 = np.dot(delta2, self.W2.T) * self.sigmoid_derivative(self.a1)
  50. dW1 = np.dot(X.T, delta1) / m
  51. db1 = np.sum(delta1, axis=0, keepdims=True) / m
  52.  
  53. # Обновление весов
  54. self.W3 -= self.lr * dW3
  55. self.b3 -= self.lr * db3
  56. self.W2 -= self.lr * dW2
  57. self.b2 -= self.lr * db2
  58. self.W1 -= self.lr * dW1
  59. self.b1 -= self.lr * db1
  60.  
  61. def train(self, X, y, epochs=5000, verbose=False):
  62. X_inverted = 1 - X
  63. y_inverted = 1 - y
  64.  
  65. # Объединяем прямые и инвертированные данные
  66. X_combined = np.vstack([X, X_inverted])
  67. y_combined = np.vstack([y, y_inverted])
  68.  
  69. losses = []
  70.  
  71. for epoch in range(epochs):
  72. # Перемешиваем данные
  73. indices = np.random.permutation(len(X_combined))
  74. X_shuffled = X_combined[indices]
  75. y_shuffled = y_combined[indices]
  76.  
  77. # Прямой проход на всех данных
  78. output = self.forward(X_shuffled)
  79.  
  80. # Ошибка
  81. loss = np.mean((output - y_shuffled) ** 2)
  82. losses.append(loss)
  83.  
  84. # Обратный проход
  85. self.backward(X_shuffled, y_shuffled, output)
  86.  
  87. if verbose and epoch % 1000 == 0:
  88. # Проверка на исходных данных
  89. pred = self.forward(X)
  90. pred_inv = self.forward(X_inverted)
  91. acc = np.mean((pred > 0.5) == y)
  92. acc_inv = np.mean((pred_inv > 0.5) == y_inverted)
  93. print(f"Epoch {epoch}, Loss: {loss:.6f}, "
  94. f"Acc: {acc:.2f}, Acc_inv: {acc_inv:.2f}")
  95.  
  96. return losses
  97.  
  98.  
  99. # ===== ДАННЫЕ =====
  100. X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float64)
  101. y = np.array([[1], [0], [0], [1]], dtype=np.float64)
  102.  
  103. # ===== МНОГОКРАТНОЕ ОБУЧЕНИЕ ДЛЯ НАДЁЖНОСТИ =====
  104. print("=" * 70)
  105. print("ОБУЧЕНИЕ XNOR (с перезапусками для надёжности)")
  106. print("=" * 70)
  107.  
  108. best_model = None
  109. best_accuracy = 0
  110.  
  111. for attempt in range(5):
  112. print(f"\nПопытка {attempt + 1}:")
  113. model = XNORNeuralNetwork(lr=0.3)
  114. model.train(X, y, epochs=3000, verbose=False)
  115.  
  116. # Проверка точности
  117. predictions = model.forward(X)
  118. accuracy = np.mean((predictions > 0.5) == y)
  119. print(f" Точность: {accuracy*100:.0f}%")
  120.  
  121. if accuracy > best_accuracy:
  122. best_accuracy = accuracy
  123. best_model = model
  124.  
  125. if accuracy == 1.0:
  126. print(" ✓ Достигнута 100% точность!")
  127. break
  128.  
  129. model = best_model
  130. print(f"\nЛучшая точность: {best_accuracy*100:.0f}%")
  131.  
  132. # ===== ТЕСТИРОВАНИЕ С ИНВЕРСИЕЙ =====
  133. print("\n" + "=" * 70)
  134. print("ТЕСТИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ СВОЙСТВА ИНВЕРСИИ")
  135. print("=" * 70)
  136.  
  137. print(f"\n{'Вход':<12} {'Цель':<8} {'f(x)':<12} {'Предск.':<10} "
  138. f"{'f(~x)':<12} {'1-f(~x)':<12} {'Ансамбль':<12} {'Сумма':<10}")
  139. print("-" * 90)
  140.  
  141. correct_direct = 0
  142. correct_inv = 0
  143. correct_ensemble = 0
  144.  
  145. for i in range(len(X)):
  146. # Прямой проход
  147. f_x = model.forward(X[i:i+1])[0][0]
  148. pred_direct = 1 if f_x > 0.5 else 0
  149.  
  150. # Инвертированный проход
  151. X_inv = 1 - X[i:i+1]
  152. f_not_x = model.forward(X_inv)[0][0]
  153.  
  154. # Предсказание через инверсию
  155. pred_from_inv = 1 if (1 - f_not_x) > 0.5 else 0
  156.  
  157. # Ансамбль
  158. ensemble = (f_x + (1 - f_not_x)) / 2
  159. pred_ensemble = 1 if ensemble > 0.5 else 0
  160.  
  161. # Сумма для проверки свойства
  162. sum_check = f_x + f_not_x
  163.  
  164. # Подсчёт точности
  165. target = int(y[i][0])
  166. if pred_direct == target: correct_direct += 1
  167. if pred_from_inv == target: correct_inv += 1
  168. if pred_ensemble == target: correct_ensemble += 1
  169.  
  170. print(f"{str(X[i]):<12} {target:<8} {f_x:<12.4f} {pred_direct:<10} "
  171. f"{f_not_x:<12.4f} {1-f_not_x:<12.4f} {ensemble:<12.4f} {sum_check:<10.4f}")
  172.  
  173. print(f"\nТочность прямых предсказаний: {correct_direct}/4")
  174. print(f"Точность через инверсию: {correct_inv}/4")
  175. print(f"Точность ансамбля: {correct_ensemble}/4")
  176.  
  177. # ===== ПРОВЕРКА СВОЙСТВА =====
  178. print("\n" + "=" * 70)
  179. print("ПРОВЕРКА СВОЙСТВА ИНВЕРСИИ")
  180. print("=" * 70)
  181.  
  182. v1 = model.forward(np.array([[0, 0]]))[0][0]
  183. v2 = model.forward(np.array([[1, 1]]))[0][0]
  184. print(f"f(0,0) + f(1,1) = {v1:.4f} + {v2:.4f} = {v1+v2:.4f}")
  185.  
  186. v1 = model.forward(np.array([[0, 1]]))[0][0]
  187. v2 = model.forward(np.array([[1, 0]]))[0][0]
  188. print(f"f(0,1) + f(1,0) = {v1:.4f} + {v2:.4f} = {v1+v2:.4f}")
  189.  
  190. # ===== БОНУС: ВИЗУАЛИЗАЦИЯ УВЕРЕННОСТИ =====
  191. print("\n" + "=" * 70)
  192. print("АНАЛИЗ УВЕРЕННОСТИ ПРЕДСКАЗАНИЙ")
  193. print("=" * 70)
  194.  
  195. for i in range(len(X)):
  196. f_x = model.forward(X[i:i+1])[0][0]
  197. X_inv = 1 - X[i:i+1]
  198. f_not_x = model.forward(X_inv)[0][0]
  199.  
  200. direct_conf = abs(f_x - 0.5) * 2 # 0-1, где 1 = максимальная уверенность
  201. inv_conf = abs((1 - f_not_x) - 0.5) * 2
  202. ensemble_score = (f_x + (1 - f_not_x)) / 2
  203. ensemble_conf = abs(ensemble_score - 0.5) * 2
  204.  
  205. # Проверка согласованности
  206. if abs(f_x + f_not_x - 1) < 0.1:
  207. consistency_bonus = "✓ согласованы"
  208. else:
  209. consistency_bonus = "✗ расхождение"
  210.  
  211. print(f"Вход {X[i]}:")
  212. print(f" Прямое: {f_x:.4f} (уверенность: {direct_conf:.2f})")
  213. print(f" Инверсия: {1-f_not_x:.4f} (уверенность: {inv_conf:.2f})")
  214. print(f" Ансамбль: {ensemble_score:.4f} (уверенность: {ensemble_conf:.2f}) - {consistency_bonus}")
Success #stdin #stdout 4.04s 42380KB
stdin
Standard input is empty
stdout
======================================================================
ОБУЧЕНИЕ XNOR (с перезапусками для надёжности)
======================================================================

Попытка 1:
  Точность: 50%

Попытка 2:
  Точность: 50%

Попытка 3:
  Точность: 50%

Попытка 4:
  Точность: 50%

Попытка 5:
  Точность: 50%

Лучшая точность: 50%

======================================================================
ТЕСТИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ СВОЙСТВА ИНВЕРСИИ
======================================================================

Вход         Цель     f(x)         Предск.    f(~x)        1-f(~x)      Ансамбль     Сумма     
------------------------------------------------------------------------------------------
[0. 0.]      1        0.5053       1          0.4959       0.5041       0.5047       1.0012    
[0. 1.]      0        0.4934       0          0.5058       0.4942       0.4938       0.9992    
[1. 0.]      0        0.5058       1          0.4934       0.5066       0.5062       0.9992    
[1. 1.]      1        0.4959       0          0.5053       0.4947       0.4953       1.0012    

Точность прямых предсказаний: 2/4
Точность через инверсию:      2/4
Точность ансамбля:            2/4

======================================================================
ПРОВЕРКА СВОЙСТВА ИНВЕРСИИ
======================================================================
f(0,0) + f(1,1) = 0.5053 + 0.4959 = 1.0012
f(0,1) + f(1,0) = 0.4934 + 0.5058 = 0.9992

======================================================================
АНАЛИЗ УВЕРЕННОСТИ ПРЕДСКАЗАНИЙ
======================================================================
Вход [0. 0.]:
  Прямое: 0.5053 (уверенность: 0.01)
  Инверсия: 0.5041 (уверенность: 0.01)
  Ансамбль: 0.5047 (уверенность: 0.01) - ✓ согласованы
Вход [0. 1.]:
  Прямое: 0.4934 (уверенность: 0.01)
  Инверсия: 0.4942 (уверенность: 0.01)
  Ансамбль: 0.4938 (уверенность: 0.01) - ✓ согласованы
Вход [1. 0.]:
  Прямое: 0.5058 (уверенность: 0.01)
  Инверсия: 0.5066 (уверенность: 0.01)
  Ансамбль: 0.5062 (уверенность: 0.01) - ✓ согласованы
Вход [1. 1.]:
  Прямое: 0.4959 (уверенность: 0.01)
  Инверсия: 0.4947 (уверенность: 0.01)
  Ансамбль: 0.4953 (уверенность: 0.01) - ✓ согласованы