Чернетка

Пошук ознак у маленькій мережі: яскравість, контраст і три нейрони

У попередній статті про те, що насправді робить вагова матриця, ми стежили за введенням через вагову матрицю та спостерігали, як вона перетворюється на точку в прихованому просторі. Тепер ми попрацюємо у зворотному напрямку: враховуючи цей прихований простір, чи можемо ми знайти напрямки, які представляють розпізнавані властивості вхідних даних?

Для цього експерименту ми перейдемо від класифікації XOR до лінійного автокодувальника: зображення з двома пікселями, прихований шар із трьома нейронами та вихідний рівень, який реконструює два пікселі. Зображення мають дві властивості, якими ми можемо керувати незалежно: яскравість і контраст ліворуч-праворуч.

Ми навмисне спрощуємо завдання, щоб ці властивості мали точне представлення, яке можна перевірити. Це дозволяє нам зосередитися на тому, що проекції, ортонормовані основи та матричні розкладання говорять нам про прихований простір. Нелінійність може повернутися, коли ми зрозуміємо ці інструменти в найпростішому випадку.

Ми навчимо мережу, заморозимо її ваги та дослідимо, куди поділися ці властивості. Кожна претензія щодо представництва матиме щось, що ми можемо обчислити або змінити, щоб перевірити це.

Два пікселі, дві властивості

Піксель відтінків сірого — це число від 0 до 1. Наше зображення — це два таких числа, розташованих зліва направо:

x=[xLxR]=[b+cb−c].x=\begin{bmatrix}x_L\\x_R\end{bmatrix} =\begin{bmatrix}b+c\\b-c\end{bmatrix}.

Середня яскравість b=(xL+xR)/2b=(x_L+x_R)/2. Контраст зі знаком c=(xL−xR)/2c=(x_L-x_R)/2: позитивний означає, що лівий піксель світліший; негативний означає, що правий піксель світліший. Це визначення контрасту є специфічним для нашого експерименту.

Яскравість bbКонтраст ccПікселі [xL,xR][x_L,x_R]Зображення
0.30[0.3,0.3][0.3,0.3]Обидва темні
0.70[0.7,0.7][0.7,0.7]Обидва світла
0.50.2[0.7,0.3][0.7,0.3]Ліва запальничка
0.5−0.2[0.3,0.7][0.3,0.7]Права запальничка

Ми рівномірно відбираємо bb з [0.25,0.75][0.25,0.75] і cc незалежно від [−0.25,0.25][-0.25,0.25]. Ці діапазони зберігають обидва пікселі всередині [0,1][0,1] без відсікання, яке інакше змінило б співвідношення між властивостями та пікселями.

Ціллю навчання є саме зображення. Ми зберігаємо мітки властивостей для аналізу, але мережа отримує лише значення двох пікселів.

Мережа з дванадцятьма вагами

Кодер WW робить три прихованих активації. Декодер DD перетворює їх назад на два пікселі:

x∈R2⏟pixels→  W∈R3×2  h∈R3⏟hidden activations→  D∈R2×3  x^∈R2⏟reconstruction.\underbrace{x\in\mathbb R^2}_{\text{pixels}} \xrightarrow{\;W\in\mathbb R^{3\times2}\;} \underbrace{h\in\mathbb R^3}_{\text{hidden activations}} \xrightarrow{\;D\in\mathbb R^{2\times3}\;} \underbrace{\hat x\in\mathbb R^2}_{\text{reconstruction}}.

Є шість ваг кодера та шість ваг декодера. Ми починаємо з випадкових ваг і мінімізуємо середній квадрат відстані реконструкції:

L=1N∑i=1N∥DWxi−xi∥2.\mathcal L=\frac1N\sum_{i=1}^{N}\|DWx_i-x_i\|^2.

Обидва шари є лінійними, без зміщень або нелінійних активацій. Їхня композиція є іншою лінійною картою. Завдання вимагає лише вивчення карти ідентичності на цих входах, тому цього достатньо. Додаткова прихована координата дає нам простір, який ми можемо перевірити в 3D; він не додає інформацію та не стискає вхідні дані.

Це робить перший експеримент корисним, тому що ми можемо отримати саме те, що має виявити аналіз. Пізніше нелінійна активація дасть нам привід запитати, які висновки вціліли.

У наведеному нижче інтерактиві використовуються вагові коефіцієнти реального тренувального прогону NumPy: 2048 зображень, 10 000 кроків градієнта та початкове значення 7. На 512 нових зображеннях його MSE реконструкції на піксель становить приблизно 8.6×10−318.6\times10^{-31}. Це чисельна точність для цього розрахунку, а не доказ складного узагальнення: модель навчилася майже точної лінійної тотожності.

Two pixels → three neurons → two pixels

Move one property while keeping the other fixed. The white point is this image’s hidden activation.

Input pixels
L 0.7000R 0.3000
Hidden activations h
h1 = -0.3887h2 = -0.0629h3 = -0.5877
Reconstruction
L 0.7000R 0.3000
h1h2h3b = 0.75, c = 0.25b = 0.70, c = 0.25b = 0.65, c = 0.25b = 0.60, c = 0.25b = 0.55, c = 0.25b = 0.50, c = 0.25b = 0.45, c = 0.25b = 0.40, c = 0.25b = 0.35, c = 0.25b = 0.30, c = 0.25b = 0.25, c = 0.25b = 0.75, c = 0.20b = 0.70, c = 0.20b = 0.65, c = 0.20b = 0.60, c = 0.20b = 0.55, c = 0.20b = 0.50, c = 0.20b = 0.45, c = 0.20b = 0.40, c = 0.20b = 0.35, c = 0.20b = 0.30, c = 0.20b = 0.25, c = 0.20b = 0.75, c = 0.15b = 0.70, c = 0.15b = 0.65, c = 0.15b = 0.60, c = 0.15b = 0.55, c = 0.15b = 0.50, c = 0.15b = 0.45, c = 0.15b = 0.40, c = 0.15b = 0.35, c = 0.15b = 0.30, c = 0.15b = 0.25, c = 0.15b = 0.75, c = 0.10b = 0.70, c = 0.10b = 0.65, c = 0.10b = 0.60, c = 0.10b = 0.55, c = 0.10b = 0.50, c = 0.10b = 0.45, c = 0.10b = 0.40, c = 0.10b = 0.35, c = 0.10b = 0.30, c = 0.10b = 0.25, c = 0.10b = 0.75, c = 0.05b = 0.70, c = 0.05b = 0.65, c = 0.05b = 0.60, c = 0.05b = 0.55, c = 0.05b = 0.50, c = 0.05b = 0.45, c = 0.05b = 0.40, c = 0.05b = 0.35, c = 0.05b = 0.30, c = 0.05b = 0.25, c = 0.05b = 0.75, c = 0.00b = 0.70, c = 0.00b = 0.65, c = 0.00b = 0.60, c = 0.00b = 0.55, c = 0.00b = 0.50, c = 0.00b = 0.45, c = 0.00b = 0.40, c = 0.00b = 0.35, c = 0.00b = 0.30, c = 0.00b = 0.25, c = 0.00b = 0.75, c = -0.05b = 0.70, c = -0.05b = 0.65, c = -0.05b = 0.60, c = -0.05b = 0.55, c = -0.05b = 0.50, c = -0.05b = 0.45, c = -0.05b = 0.40, c = -0.05b = 0.35, c = -0.05b = 0.30, c = -0.05b = 0.25, c = -0.05b = 0.75, c = -0.10b = 0.70, c = -0.10b = 0.65, c = -0.10b = 0.60, c = -0.10b = 0.55, c = -0.10b = 0.50, c = -0.10b = 0.45, c = -0.10b = 0.40, c = -0.10b = 0.35, c = -0.10b = 0.30, c = -0.10b = 0.25, c = -0.10b = 0.75, c = -0.15b = 0.70, c = -0.15b = 0.65, c = -0.15b = 0.60, c = -0.15b = 0.55, c = -0.15b = 0.50, c = -0.15b = 0.45, c = -0.15b = 0.40, c = -0.15b = 0.35, c = -0.15b = 0.30, c = -0.15b = 0.25, c = -0.15b = 0.75, c = -0.20b = 0.70, c = -0.20b = 0.65, c = -0.20b = 0.60, c = -0.20b = 0.55, c = -0.20b = 0.50, c = -0.20b = 0.45, c = -0.20b = 0.40, c = -0.20b = 0.35, c = -0.20b = 0.30, c = -0.20b = 0.25, c = -0.20b = 0.75, c = -0.25b = 0.70, c = -0.25b = 0.65, c = -0.25b = 0.60, c = -0.25b = 0.55, c = -0.25b = 0.50, c = -0.25b = 0.45, c = -0.25b = 0.40, c = -0.25b = 0.35, c = -0.25b = 0.30, c = -0.25b = 0.25, c = -0.25v_bv_c0h

Gold v_b changes brightness; blue v_c changes contrast. Their cosine is -0.155. Dashed segments add b v_b and c v_c to reach h. Basis arrows are drawn at 0.45× their lengths. A 3D right angle can look oblique in this view.

Read brightness and contrast from h
All methods read the original white point h.
MethodBrightnessContrast
Known input properties0.50000.2000
Separate scalar projections0.46760.1260
QR + back-substitution0.50000.2000
Fitted linear probe0.50000.2000

QR first gives z₁ = 0.6470, z₂ = 0.2859. Then c = z₂ / 1.4297 and b = (z₁ − (-0.2239)c) / 1.3836.

Intervene on the hidden activation
Decoded intervention
L 0.7000R 0.3000
Output brightness: 0.5000
Output contrast: 0.2000
Pixel change: [0.0000, 0.0000]

Choose an operation to create the pink point h′, then send it through the same decoder.

Training record and learned weights

Frozen NumPy run, seed 7: 2,048 training images, 10,000 gradient steps, learning rate 0.08. Reconstruction MSE on 512 held-out images: 8.58e-31.

Encoder W (3 × 2)
[-0.1191, -1.0177]
[0.0408, -0.3048]
[-0.9118, 0.1686]
Decoder D (2 × 3)
[-0.1834, 0.0194, -1.0719]
[-0.8363, -0.4388, 0.0896]

Centered activation singular values: 9.96e+0, 8.43e+0, 3.36e-15. The first two span the occupied plane.

Почніть із Інструкції щодо функцій. Зберігайте постійний контраст і змінюйте яскравість. Обидва пікселі змінюються разом, і біла точка йде по прямій лінії через прихований простір. Тепер залишайте яскравість фіксованою та змінюйте контраст: пікселі змінюються в протилежних напрямках, а прихована точка слідує за іншою лінією. Поверніть графік, щоб побачити, що сітка займає площину.

Знайдіть напрямок, керуючи введенням

Збільшення яскравості на Δb\Delta b додає однакову кількість до обох вхідних пікселів. Прихована активація змінюється:

h(b+Δb,c)−h(b,c)=W[ΔbΔb]=Δb W[11]⏟vb.h(b+\Delta b,c)-h(b,c) =W\begin{bmatrix}\Delta b\\\Delta b\end{bmatrix} =\Delta b\,\underbrace{W\begin{bmatrix}1\\1\end{bmatrix}}_{v_b}.

Це визначає напрямок яскравості vbv_b. Зміна контрасту визначає інший напрямок:

vc=W[1−1].v_c=W\begin{bmatrix}1\\-1\end{bmatrix}.

Ми могли б оцінити ці напрямки за парами активацій, поділивши їх різницю на зміну властивості. Тут ми також можемо прочитати їх з WW, що дає нам точну перевірку.

Для навченого кодувальника округлено до чотирьох десяткових знаків:

vb≈[−1.1369−0.2640−0.7432],vc≈[0.89860.3456−1.0804].v_b\approx\begin{bmatrix}-1.1369\\-0.2640\\-0.7432\end{bmatrix}, \qquad v_c\approx\begin{bmatrix}0.8986\\0.3456\\-1.0804\end{bmatrix}.

Кожна координата відповідає обом властивостям. Жоден з трьох нейронів не є виключно нейроном яскравості або нейроном контрасту. Підвищення яскравості навіть робить усі три приховані активації більш негативними; прихована координата не повинна нагадувати інтенсивність пікселя.

Лінійність дає нам повне розкладання:

h=b vb+c vc.\boxed{h=b\,v_b+c\,v_c.}

Властивості є коефіцієнтами напрямків у представленні. Прихованими активаціями є координати результуючого вектора вздовж осей нейронів. Це два різних координатних описи однієї точки.

Три координати, два зайняті виміри

Прихований простір навколишнього середовища — R3\mathbb R^3. Два незалежних напрямки об’єктів охоплюють площину:

S=span⁡(vb,vc)⊂R3.S=\operatorname{span}(v_b,v_c)\subset\mathbb R^3.

Кожна активація лежить у цій площині. Обмежена колекція активацій зображень є латкою в ній; цей патч сам по собі не є векторним простором, оскільки довільне масштабування та додавання можуть залишати його.

Тут ранг стає питанням про представлення. Матриця активації може мати три стовпці, по одному на нейрон, але тільки два незалежних напрямки варіації. Дві незалежні властивості були розподілені по трьох координатах. Ми не упаковували більше незалежних функцій, ніж розміри, тому цей приклад не демонструє суперпозицію.

Проекція не є автоматично вимірюванням властивості

Косинус між нашими напрямками об’єктів становить приблизно −0.155-0.155. Вони незалежні, але не перпендикулярні.

Припустімо, ми спробуємо прочитати яскравість, спроектувавши hh на vbv_b і взявши коефіцієнт:

b~=vb⊤hvb⊤vb=b+c vb⊤vcvb⊤vb.\tilde b=\frac{v_b^\top h}{v_b^\top v_b} =b+c\,\frac{v_b^\top v_c}{v_b^\top v_b}.

Додатковий член є внеском контрасту. Для цієї моделі b~≈b−0.162c\tilde b\approx b-0.162c. З b=0.5b=0.5 і c=0.2c=0.2 повідомляє про 0.46760.4676.

Відкрийте Зчитувати яскравість і контраст із h у віджеті. Тримайте фіксовану яскравість і змінюйте контраст: оцінка окремої проекції змінюється, навіть якщо яскравість не змінюється.

Це також пояснює, що означають неортогональні напрямки, а що ні. Додавання αvb\alpha v_b до активації змінює його коефіцієнт яскравості на α\alpha, залишаючи без змін коефіцієнт контрастності. Але він може змінити скалярний добуток із vcv_c. Коефіцієнт ознаки та скалярний добуток на його напрямок є різними величинами, якщо основа не ортогональна.

Грам–Шмідт дає площині ортонормований базис

Почніть із нормалізації напрямку яскравості:

q1=vb∥vb∥.q_1=\frac{v_b}{\|v_b\|}.

Потім видаліть частину напрямку контрасту, паралельну q1q_1, і нормалізуйте те, що залишилося:

u2=vc−(q1⊤vc)q1,q2=u2∥u2∥.u_2=v_c-(q_1^\top v_c)q_1, \qquad q_2=\frac{u_2}{\|u_2\|}.

Тепер q1⊤q2=0q_1^\top q_2=0 і обидва вектори мають довжину 1. Вони охоплюють ту саму площину, що й vbv_b і vcv_c.

Виберіть Gram–Schmidt у віджеті. Точки даних залишаються там, де вони були; змінюються лише наші опорні стрілки. Ортогоналізація основи не перенавчає мережу та не змінює її активації.

Нові координати z1=q1⊤hz_1=q_1^\top h і z2=q2⊤hz_2=q_2^\top h. Оскільки q2q_2 перпендикулярний до vbv_b, z2z_2 не має внеску яскравості. Але z1z_1 може містити обидві властивості. Зміна порядку Грама-Шмідта спочатку збереже напрямок контрасту та дасть іншу основу.

Отже, ортонормований базис забезпечує зручні координати. Його конструкція сама по собі не надає семантичних позначок цим координатам.

QR повертає ці координати на яскравість і контраст

Помістіть початкові напрямки в матрицю V=[vb  vc]V=[v_b\;v_c], а ортонормовані напрямки — у Q=[q1  q2]Q=[q_1\;q_2]. Коефіцієнти, використані Грамом–Шмідтом, утворюють верхньотрикутну матрицю RR:

V=QR,R=[∥vb∥q1⊤vc0∥u2∥]≈[1.3836−0.223901.4297].V=QR, \qquad R=\begin{bmatrix} \|v_b\| & q_1^\top v_c\\ 0 & \|u_2\| \end{bmatrix} \approx\begin{bmatrix} 1.3836 & -0.2239\\ 0 & 1.4297 \end{bmatrix}.

Оскільки h=V[b,c]⊤h=V[b,c]^\top і Q⊤Q=IQ^\top Q=I, проектування в ортонормований базис дає:

[z1z2]=Q⊤h=R[bc].\begin{bmatrix}z_1\\z_2\end{bmatrix} =Q^\top h =R\begin{bmatrix}b\\c\end{bmatrix}.

Прочитайте спочатку другий рядок, потім перший:

c=z2r22,b=z1−r12cr11.c=\frac{z_2}{r_{22}}, \qquad b=\frac{z_1-r_{12}c}{r_{11}}.

Це зворотна заміна. Ми відновили коефіцієнти властивостей, врахувавши перекриття та довжину оригінальних напрямків. Віджет виконує ці обчислення з вагами повної точності.

Якби активація мала компонент поза площиною, ця сама процедура відновила б коефіцієнти його ортогональної проекції на площину: рішення Vs≈hVs\approx h методом найменших квадратів. Усі наші вихідні активації зображень лежать у площині, тому їх залишковий відображення дорівнює нулю з точністю до числової помилки.

Встановіть показання без надання вказівок

Ми також можемо запитати, чи можна лінійно відновити яскравість і контраст шляхом встановлення окремої моделі. Зберіть активації замороженої мережі в H∈RN×3H\in\mathbb R^{N\times3} і відомі властивості в Y∈RN×2Y\in\mathbb R^{N\times2}. знайти:

P∗=arg⁡min⁡P∥HP−Y∥F2.P^*=\arg\min_P\|HP-Y\|_F^2.

Це зонд лінійної регресії. Він залишає вихідну мережу без змін і вчиться читати інформацію з її активацій. Ален і Бенгіо робота над зондами лінійного класифікатора використовує той самий поділ між замороженим представленням і незалежно навченим діагностичним зчитуванням із цілями класифікації.

H = X_train @ W.T
probe = np.linalg.lstsq(H, properties_train, rcond=None)[0]
predicted_properties = (X_test @ W.T) @ probe

HH має другий ранг, тому існує кілька трьохкоординатних ваг зонда, які погоджуються для кожної активації зображення. lstsq усуває цей недолік рангу та повертає рішення мінімальної норми. Наївне трикутне розв’язання повного рангу на всіх трьох стовпцях HH було б недоречним. У попередньому розрахунку QR натомість використовувалися два незалежні стовпці VV.

Для вектора зчитування яскравості wbw_b мають значення такі умови:

wb⊤vb=1,wb⊤vc=0.w_b^\top v_b=1, \qquad w_b^\top v_c=0.

vbv_b описує, як яскравість вписується у прихований простір. wbw_b описує, як з нього зчитується яскравість. Вони не повинні вказувати в одному напрямку. У наших відкладених прикладах підігнаний зонд відновлює обидві властивості з чисельною точністю.

PCA знаходить зайняту площину без міток властивостей

Відцентруйте матрицю активації, а потім обчисліть її сингулярний розклад:

H_centered = H - H.mean(axis=0)
U, singular_values, Vt = np.linalg.svd(H_centered, full_matrices=False)
pca_axes = Vt[:2]  # Two orthonormal directions in hidden space
scores = H_centered @ pca_axes.T

Сингулярні значення приблизно дорівнюють 9.9579.957, 8.4318.431 і 3.4×10−153.4\times10^{-15}. Останній — числовий залишок: є два незалежних напрямки варіації. Їх частки дисперсії становлять близько 58,2% і 41,8%.

Виберіть PCA у віджеті. Його стрілки починаються від середнього значення активації навчання, оскільки PCA аналізує центровані дані. Вони охоплюють ту саму площину, що й наші напрямки об’єктів і базис Грама–Шмідта. Але PCA обирає напрямки за дисперсією; він не знає, яку властивість ми називаємо яскравістю. Його перший компонент не обов’язково повинен бути віссю яскравості.

Це дає нам три способи описати одну площину: керовані напрямки об’єктів, ортонормальний базис, побудований з цих напрямків, і осі максимізації дисперсії, знайдені без міток. Вони відповідають на різні питання про ті самі активації.

Змініть приховану активацію та перевірте результат

Успішне дослідження встановлює можливість відновлення. Ми можемо досліджувати поведінку більш безпосередньо, змінивши активацію, надіслану до оригінального декодера:

h′=h+αvb.h'=h+\alpha v_b.

Оскільки навчена мережа реконструює точно, Dvb≈[1,1]⊤Dv_b\approx[1,1]^\top. Обидва декодовані пікселі мають збільшитися на α\alpha. Так само Dvc≈[1,−1]⊤Dv_c\approx[1,-1]^\top, тому додавання αvc\alpha v_c має змінити контраст, зберігаючи яскравість.

Відкрийте Втручатися в приховану активацію. З початковими пікселями [0.7,0.3][0.7,0.3] додавання 0.1vb0.1v_b дає приблизно [0.8,0.4][0.8,0.4]. Додавання 0.1vc0.1v_c дає приблизно [0.8,0.2][0.8,0.2]. Вхід залишається фіксованим, тоді як рожева прихована точка та розшифроване втручання змінюються.

Віджет показує необроблені числові виходи. Тільки зразки пікселів обрізаються до [0,1][0,1], коли втручання виходить за межі відображуваного діапазону; що вирізка не є частиною мережі.

Є ще одне корисне порівняння: відніміть ортогональну проекцію на vbv_b. Результат перпендикулярний vbv_b, але декодована яскравість не обов’язково дорівнює нулю:

h−proj⁡vb(h)=c(vc−vb⊤vcvb⊤vbvb).h-\operatorname{proj}_{v_b}(h) =c\left(v_c-\frac{v_b^\top v_c}{v_b^\top v_b}v_b\right).

Це усуває залежність від оригінального bb, одночасно вводячи внесок яскравості, визначений cc. Щоб встановити коефіцієнт яскравості до нуля, ми повинні відняти bvbb v_b. Видалення геометричної проекції та встановлення властивості на нуль є різними операціями.

Тут пряма карта досить проста, щоб довести ефект втручання. Це невелике механістичне пояснення: властивість контрольованого входу змінює відомий прихований напрямок, і декодер відображає цей напрямок на передбачувану вихідну зміну.

Відтворіть експеримент

Завантажте повний експеримент NumPy. Він навчає мережу, реалізує модифікований Грам-Шмідт, підганяє зонд, обчислює PCA та перевіряє реконструкцію, зчитування та втручання на невідомих прикладах. Він також перевіряє, що PCA і Грама-Шмідта створюють ту саму площину, порівнюючи їх матриці проекцій.

python3 -m pip install numpy
python3 two_pixel_experiment.py
python3 two_pixel_experiment.py --seed 11

Сценарій друкує свої ваги та вимірювання. Його необов’язковий аргумент --export model.json записує знімок у форматі, який використовується віджетом; зареєстрований знімок є початковим 7. Браузер запускає заморожений кодер, декодер і обчислення аналізу, а не навчання під час завантаження сторінки.

Інша ініціалізація може створити іншу площину та інші кути елементів під час реконструкції тих самих пікселів. Загалом, заміна WW на AWAW і DD на DA−1DA^{-1} для будь-якої оборотної 3×33\times3 матриці AA залишає DWDW без змін. Кути та координати нейронів описують це конкретне вивчене уявлення; сама по собі реконструкція не визначає їх однозначно.

Ускладніть наступний експеримент одним способом

Тепер ми маємо базову лінію з відомими властивостями, точну декомпозицію, кілька зчитувань і перевірку поведінки. Це дає нам змогу переглянути конкретні речі:

ЗмінаРозслідування
Співвідносьте яскравість і контрастність данихПорівняйте напрямки, оцінені на основі неконтрольованих асоціацій, із напрямками на основі відповідних змін вхідних даних. Зберігайте незалежні тестові приклади.
Додайте прихований ReLUПеревірте, чи один глобальний напрям все ще описує властивість, чи напрям залежить від того, які нейрони активні.
Додайте шум або третю незалежну власністьВивчіть, коли третє значення однини стає істотним і яку інформацію відновлює зонд. Третя властивість вимагає розширення двопіксельного введення.
Використовуйте більше функцій, ніж приховані розміри, активність розріджених функцій і нелінійну реконструкціюДослідіть інтерференцію та стиснення, дотримуючись таких експериментів, як Іграшкові моделі суперпозиції.

Наступним кроком, який я б зробив, є експеримент із корельованими даними. Він зберігає ту саму дванадцятивагову мережу та ставить складніше питання щодо інтерпретації: коли напрямок представляє яскравість, наскільки цей висновок випливає з того, як ми відбирали зображення?

Перегляд зображення

Змінюйте масштаб жестом щипка або клавішами + / −. Переміщуйте зображення перетягуванням або стрілками. Esc — закрити.