Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f85c0adbc | |||
| 0182800043 |
@@ -12,10 +12,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to registry
|
- name: Login to registry
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.GIT_PASS }}" | \
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
|
||||||
docker login git.ada-dev.ru -u ${{ secrets.GIT_USER }} --password-stdin
|
docker login git.ada-dev.ru -u ${{ secrets.REGISTRY_USER }} --password-stdin
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
run: |
|
run: |
|
||||||
docker build -t git.ada-dev.ru/${{ gitea.repository }}:latest .
|
docker build -t git.ada-dev.ru/ada/${{ gitea.repository }}:latest .
|
||||||
docker push git.ada-dev.ru/${{ gitea.repository }}:latest
|
docker push git.ada-dev.ru/ada/${{ gitea.repository }}:latest
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# Как работает приложение
|
|
||||||
|
|
||||||
## Запуск
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bundle install
|
|
||||||
ruby app.rb # веб-интерфейс на http://localhost:4567
|
|
||||||
# или
|
|
||||||
ruby main.rb # только CLI: загружает паттерны, обучает, выводит инфо
|
|
||||||
```
|
|
||||||
|
|
||||||
В Docker: собирается образ, `generate_excel.rb` генерирует `patterns.xlsx` при старте, Sinatra слушает на 4567.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Данные
|
|
||||||
|
|
||||||
Паттерны хранятся в `patterns.xlsx`. Каждый лист = один символ (T, H, E, X...).
|
|
||||||
Ячейка `x` → `1`, остальное → `-1`. Размер: 8×8 = вектор из 64 значений.
|
|
||||||
|
|
||||||
`loader.rb` читает Excel через гем `roo` и возвращает `{name => matrix_8x8}`.
|
|
||||||
В вычислениях матрицы разворачиваются в векторы через `flatten`.
|
|
||||||
|
|
||||||
Если хочешь добавить/изменить паттерны — правь `generate_excel.rb` и перезапусти.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Веб-интерфейс
|
|
||||||
|
|
||||||
Одна страница (`views/index.erb`), тёмная тема, 8×8 кликабельная сетка ввода.
|
|
||||||
|
|
||||||
**Что можно сделать:**
|
|
||||||
- Нарисовать паттерн кликами (или добавить шум кнопкой)
|
|
||||||
- Нажать «Распознать» — сервер прогоняет через обе сети
|
|
||||||
- Включить «Пошаговый режим» — видно, как Хопфилд сходится шаг за шагом
|
|
||||||
- Включить «Показывать формулы» — рядом с анимацией появляются LaTeX-формулы вычислений
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Маршруты (`app.rb`)
|
|
||||||
|
|
||||||
| Маршрут | Что делает |
|
|
||||||
|---|---|
|
|
||||||
| `GET /` | Загружает паттерны, отдаёт HTML |
|
|
||||||
| `POST /recall` | Быстро: вектор → итоговый результат обеих сетей |
|
|
||||||
| `POST /recall_steps` | То же + все промежуточные состояния для анимации |
|
|
||||||
| `POST /recall_trace` | То же + net-значения, сколько нейронов изменилось на каждом шаге, трассировка MAXNET |
|
|
||||||
|
|
||||||
Все POST принимают JSON `{vector: [...64 числа...]}`, возвращают JSON.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Алгоритмы
|
|
||||||
|
|
||||||
### Хопфилд (`hopfield.rb`)
|
|
||||||
|
|
||||||
**Обучение** — один раз при запуске:
|
|
||||||
```
|
|
||||||
W[i][j] += v[i] * v[j] для каждого паттерна v, i ≠ j
|
|
||||||
```
|
|
||||||
Матрица весов 64×64, кэшируется в `weights.cache`.
|
|
||||||
|
|
||||||
**Recall** — итерации до сходимости:
|
|
||||||
```
|
|
||||||
new[i] = sign( Σ_j W[i][j] * x[j] ) # sign: ≥0 → 1, <0 → -1
|
|
||||||
```
|
|
||||||
Все нейроны обновляются синхронно. Стоп: состояние не изменилось (EPS=0.01) или 200 итераций.
|
|
||||||
|
|
||||||
### Хэмминг (`hamming.rb`)
|
|
||||||
|
|
||||||
**Шаг 1 — слой Хэмминга** (один раз):
|
|
||||||
```
|
|
||||||
output[k] = (dot(pattern_k, input) + 64) / 2
|
|
||||||
```
|
|
||||||
Результат: число от 0 до 64 — сколько бит совпало с k-м эталоном.
|
|
||||||
|
|
||||||
**Шаг 2 — MAXNET** (итерации до одного победителя):
|
|
||||||
```
|
|
||||||
new[i] = max(output[i] - eps * Σ_{j≠i} output[j], 0) # eps = 0.9 / кол-во паттернов
|
|
||||||
```
|
|
||||||
Нейроны конкурируют: слабые гаснут, остаётся один. Его индекс = ближайший паттерн.
|
|
||||||
+6
-4
@@ -17,11 +17,13 @@ MAX_MAXNET_ITER = 100
|
|||||||
|
|
||||||
def recall_hamming(pattern_vectors, input_vec)
|
def recall_hamming(pattern_vectors, input_vec)
|
||||||
eps = 0.9 / pattern_vectors.length
|
eps = 0.9 / pattern_vectors.length
|
||||||
|
|
||||||
outputs = hamming_layer(pattern_vectors, input_vec)
|
outputs = hamming_layer(pattern_vectors, input_vec)
|
||||||
iter = 0
|
MAX_MAXNET_ITER.times do
|
||||||
while outputs.count { |v| v > 1e-9 } > 1 && iter < MAX_MAXNET_ITER
|
next_out = maxnet_step(outputs, eps)
|
||||||
outputs = maxnet_step(outputs, eps)
|
return next_out.each_with_index.max_by { |v, _| v }[1] if next_out.count { |v| v > 1e-9 } <= 1
|
||||||
iter += 1
|
outputs = next_out
|
||||||
end
|
end
|
||||||
|
|
||||||
outputs.each_with_index.max_by { |v, _| v }[1]
|
outputs.each_with_index.max_by { |v, _| v }[1]
|
||||||
end
|
end
|
||||||
|
|||||||
+4
-6
@@ -40,12 +40,10 @@ MAX_HOPFIELD_ITER = 200
|
|||||||
|
|
||||||
def recall_hopfield(weights, input_vec)
|
def recall_hopfield(weights, input_vec)
|
||||||
current = input_vec.dup
|
current = input_vec.dup
|
||||||
next_vec = step_hopfield(weights, current)
|
MAX_HOPFIELD_ITER.times do
|
||||||
iter = 1
|
|
||||||
while !vectors_equal?(current, next_vec) && iter < MAX_HOPFIELD_ITER
|
|
||||||
current = next_vec
|
|
||||||
next_vec = step_hopfield(weights, current)
|
next_vec = step_hopfield(weights, current)
|
||||||
iter += 1
|
return current if vectors_equal?(current, next_vec)
|
||||||
|
current = next_vec
|
||||||
end
|
end
|
||||||
next_vec
|
current
|
||||||
end
|
end
|
||||||
+1
-5
@@ -3,7 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Сети Хопфилда и Хэмминга</title>
|
<title>Сети Хопфилда и Хэмминга</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%231a1a2e'/%3E%3Cline x1='6' y1='10' x2='16' y2='6' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='6' y1='10' x2='16' y2='16' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='6' y1='10' x2='16' y2='26' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='6' y1='22' x2='16' y2='6' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='6' y1='22' x2='16' y2='16' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='6' y1='22' x2='16' y2='26' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='16' y1='6' x2='26' y2='16' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='16' y1='16' x2='26' y2='16' stroke='%238ab4f8' stroke-width='1'/%3E%3Cline x1='16' y1='26' x2='26' y2='16' stroke='%238ab4f8' stroke-width='1'/%3E%3Ccircle cx='6' cy='10' r='3' fill='%23a0c4ff'/%3E%3Ccircle cx='6' cy='22' r='3' fill='%23a0c4ff'/%3E%3Ccircle cx='16' cy='6' r='3' fill='%23a0c4ff'/%3E%3Ccircle cx='16' cy='16' r='3' fill='%23a0c4ff'/%3E%3Ccircle cx='16' cy='26' r='3' fill='%23a0c4ff'/%3E%3Ccircle cx='26' cy='16' r='3' fill='%23a0c4ff'/%3E%3C/svg%3E">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
@@ -264,10 +263,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div style="display:flex; align-items:center; gap:1rem; margin-bottom:2rem;">
|
<h1>Сети Хопфилда и Хэмминга</h1>
|
||||||
<h1 style="margin-bottom:0;">Сети Хопфилда и Хэмминга</h1>
|
|
||||||
<a href="https://ada-dev.ru" class="secondary" style="padding:0.5rem 1.5rem; background:#2a2a4a; color:#8ab4f8; border:1px solid #8ab4f8; border-radius:4px; cursor:pointer; font-family:monospace; font-size:0.9rem; font-weight:bold; text-decoration:none;">Домой</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>Эталонные образы</h2>
|
<h2>Эталонные образы</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user