MartialTerran commited on
Commit
9f84fa6
·
verified ·
1 Parent(s): b3ce37b

Create 8BitsBinary-to-Reverse8BitsBinary_Task_is_LinearlySeparable

Browse files
8BitsBinary-to-Reverse8BitsBinary_Task_is_LinearlySeparable ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ # The `8BitsBinary2Reverse8BitsBinary` Task
3
+
4
+ Query: Is 8BitsBinary2Reverse8BitsBinar "Linearly Separable"? [Can a NN or MLP having no nonlinear-Activation Function e.g., ReLU classify it?]
5
+
6
+ This synthetic dataset provides a classic example of a **linearly separable** problem.
7
+ It is designed to be a simple, yet illustrative, test case for an MLP's ability to learn a basic permutation.
8
+
9
+ ### Task Description
10
+
11
+ The model is given an 8-bit binary vector as input and must learn to output the exact reverse of that vector.
12
+
13
+ The mapping is a direct one-to-one permutation:
14
+ * **Input:** `[x₁, x₂, x₃, x₄, x₅, x₆, x₇, x₈]`
15
+ * **Target:** `[x₈, x₇, x₆, x₅, x₄, x₃, x₂, x₁]`
16
+
17
+ #### Text Illustration
18
+
19
+ A concrete example of a single data sample would be:
20
+ ```
21
+ Input: [1, 1, 0, 0, 1, 0, 1, 0]
22
+ Target: [0, 1, 0, 1, 0, 0, 1, 1]
23
+ ```
24
+
25
+ ### Why a Linear (Identity Activation) MLP Can Achieve 100% Accuracy
26
+
27
+ The fundamental reason this problem is perfectly solvable by a model with Null or Identity (`f(x) = x`) activation functions is that the relationship between each input bit and its corresponding output bit is **purely linear**.
28
+
29
+ There is no complex, non-linear logic required (like an `XOR` or `AND` gate). The model does not need to learn relationships *between* different input bits to calculate an output; it only needs to learn a direct "re-wiring" scheme. An MLP with only linear activation functions is essentially a powerful linear transformer.
30
+
31
+ #### A Worked Example: The "Perfect" Weight Matrix
32
+
33
+ Consider a simple MLP with one layer. To calculate the **first output bit (`y₁`)**, the model must learn that `y₁` is always equal to the **eighth input bit (`x₈`)**.
34
+
35
+ A neuron with an Identity activation function calculates its output as: `output = f( (w · x) + b ) = (w · x) + b`.
36
+
37
+ The ideal solution that a gradient descent optimizer can easily find for the first output neuron is:
38
+
39
+ ```
40
+ To compute y₁ (which must equal x₈):
41
+
42
+ - Set the weight connecting x₈ to the neuron to 1.0
43
+ - Set all other weights (from x₁ to x₇) to 0.0
44
+ - Set the neuron's bias to 0.0
45
+
46
+ Input Vector (x) = [x₁, x₂, x₃, x₄, x₅, x₆, x₇, x₈]
47
+ Weight Vector (w) = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
48
+ Bias (b) = 0.0
49
+ ```
50
+
51
+ Let's test this:
52
+ * **If `x₈ = 1`**: The calculation is `(0*x₁ + ... + 0*x₇ + 1*1) + 0 = 1`. The output is **1**. Correct.
53
+ * **If `x₈ = 0`**: The calculation is `(0*x₁ + ... + 0*x₇ + 1*0) + 0 = 0`. The output is **0**. Correct.
54
+
55
+ The model simply needs to learn the following weight matrix to solve the entire problem, where each row of the matrix corresponds to the weights for one output neuron. This is a classic **permutation matrix**.
56
+
57
+ ```
58
+ x₁ x₂ x₃ x₄ x₅ x₆ x₇ x₈ (Inputs)
59
+ +-----------------------------------------+
60
+ y₁ -> | 0 0 0 0 0 0 0 1 |
61
+ y₂ -> | 0 0 0 0 0 0 1 0 |
62
+ y₃ -> | 0 0 0 0 0 1 0 0 |
63
+ y₄ -> | 0 0 0 0 1 0 0 0 |
64
+ y₅ -> | 0 0 0 1 0 0 0 0 |
65
+ y₆ -> | 0 0 1 0 0 0 0 0 |
66
+ y₇ -> | 0 1 0 0 0 0 0 0 |
67
+ y₈ -> | 1 0 0 0 0 0 0 0 |
68
+ +-----------------------------------------+
69
+ (Each row is the weight vector for an output neuron)
70
+ ```
71
+
72
+ Because this perfect, simple linear solution exists, an MLP using only Identity activation functions does not need to learn any complex non-linear transformations. Its entire task is to adjust its weights to match this permutation matrix, which it can do with 100% accuracy.
73
+
74
+ def get_dataset(mode):
75
+ print(f"Generating dataset for mode: {mode}...")
76
+ if mode == 'Analog2Thermometer':
77
+ inputs = np.random.uniform(-1, 1, (NUM_SAMPLES, 1)).astype(np.float32)
78
+ int_values = np.floor((inputs.flatten() + 1) / 2 * NUM_THERMOMETER_LEVELS).astype(int)
79
+ int_values = np.clip(int_values, 0, NUM_THERMOMETER_LEVELS - 1)
80
+ targets = np.zeros((NUM_SAMPLES, NUM_THERMOMETER_LEVELS), dtype=np.float32)
81
+ for i, val in enumerate(int_values): targets[i, :val] = 1.0
82
+ return TensorDataset(torch.from_numpy(inputs), torch.from_numpy(targets))
83
+ elif mode == 'Analog2Binary':
84
+ inputs = np.random.uniform(-1, 1, (NUM_SAMPLES, 1)).astype(np.float32)
85
+ int_values = np.floor((inputs.flatten() + 1) / 2 * NUM_THERMOMETER_LEVELS).astype(int)
86
+ int_values = np.clip(int_values, 0, NUM_THERMOMETER_LEVELS - 1)
87
+ targets = np.array([list(np.binary_repr(val, width=PRECISION_BITS)) for val in int_values], dtype=np.float32)
88
+ return TensorDataset(torch.from_numpy(inputs), torch.from_numpy(targets))
89
+ elif mode == '8BitsBinary2Reverse8BitsBinary':
90
+ inputs = np.random.randint(0, 2, (NUM_SAMPLES, PRECISION_BITS)).astype(np.float32)
91
+ targets = np.fliplr(inputs).copy().astype(np.float32) # Use fliplr for reversing
92
+ return TensorDataset(torch.from_numpy(inputs), torch.from_numpy(targets))
93
+ elif mode == '8BitsBinary2ThermometerCode':
94
+ int_values = np.random.randint(0, NUM_THERMOMETER_LEVELS, NUM_SAMPLES)
95
+ inputs = np.array([list(np.binary_repr(val, width=PRECISION_BITS)) for val in int_values], dtype=np.float32)
96
+ targets = np.zeros((NUM_SAMPLES, NUM_THERMOMETER_LEVELS), dtype=np.float32)
97
+ for i, val in enumerate(int_values): targets[i, :val] = 1.0
98
+ return TensorDataset(torch.from_numpy(inputs), torch.from_numpy(targets))
99
+
100
+
101
+
102
+ # --- --- --- --- --- --- --- ---
103
+ # --- B. BAKE-OFF HYPERPARAMETERS ---
104
+ # --- --- --- --- --- --- --- ---
105
+
106
+ BAKEOFF_CONFIGS = [
107
+ {'name': 'Baseline_NONE', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.Identity()}, # Added NONE model
108
+ {'name': 'Baseline_IDENTITY', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.Identity()}, # Added IDENTITY model
109
+ {'name': 'Baseline_Low_LR_ReLU', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.ReLU()},
110
+ {'name': 'Baseline_GeLU', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.GELU()},
111
+ {'name': 'Baseline_Swish', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.SiLU()},
112
+ {'name': 'Low_LR_PReLU', 'hidden_layers': [128], 'lr': 0.0001, 'activation': nn.PReLU()},
113
+
114
+ Actual bakeoff Training Results:
115
+
116
+ --- Script Objective: Evaluate and Optimize Neural Network Architectures for Digital Conversion ---
117
+ Mode: 8BitsBinary2Reverse8BitsBinary
118
+ Precision Bits: 64 #Hidden Dim = 128 MLP Models solved 100% for 8 bits, 16, bits, 32 bits and 64 bits. [can you estimate or find the limit?]
119
+ Number of Epochs: 31
120
+ Batch Size: 64
121
+ Number of Samples: 10000
122
+ Enable Overfitting (No Dropout): True
123
+ Generating dataset for mode: 8BitsBinary2Reverse8BitsBinary...
124
+ ...
125
+ --- Epoch 31/31 ---
126
+ Activation: NONE | T Loss: 0.0631 | V Loss: 0.0639 | Acc: 100.00% | Hamming Dist: Max: 0 Avg: 0.0000 Min: 0
127
+ Activation: IDENTITY | T Loss: 0.0613 | V Loss: 0.0638 | Acc: 100.00% | Hamming Dist: Max: 0 Avg: 0.0000 Min: 0
128
+ Activation: ReLU | T Loss: 0.1124 | V Loss: 0.1182 | Acc: 99.75% | Hamming Dist: Max: 2 Avg: 0.0029 Min: 0
129
+ Activation: GeLU | T Loss: 0.1075 | V Loss: 0.1108 | Acc: 99.85% | Hamming Dist: Max: 1 Avg: 0.0015 Min: 0
130
+ Activation: Swish | T Loss: 0.1063 | V Loss: 0.1067 | Acc: 99.95% | Hamming Dist: Max: 1 Avg: 0.0005 Min: 0
131
+
132
+ This gets to the very heart of a problem's fundamental complexity.
133
+
134
+ The definitive answer is: **Yes, the 8BitsBinary2Reverse8BitsBinary dataset is linearly separable.**
135
+
136
+ Let's break down exactly why.
137
+
138
+ ### 1. What "Linearly Separable" Means
139
+
140
+ A problem is linearly separable if you can draw a single straight line (or a flat hyperplane in more than two dimensions) that perfectly separates the data points of one class from the data points of another.
141
+
142
+ In the context of neural networks, it means that a **single-layer perceptron** (a model with no hidden layers, just an input layer connected directly to an output layer) can solve the problem perfectly.
143
+
144
+ For a multi-output problem like this one, we analyze it on a per-output basis. The entire problem is considered linearly separable if *each individual output bit's classification task* is linearly separable.
145
+
146
+ ### 2. The Proof: Analyzing a Single Output Bit
147
+
148
+ Let's analyze the task of predicting just the **first output bit (`y₁`)**.
149
+
150
+ The rule for this dataset is: `y₁` must be the value of the **last input bit (`x₈`)**. All other input bits (`x₁` through `x₇`) are completely irrelevant for calculating `y₁`.
151
+
152
+ The task for `y₁` is to classify the 8-bit input vector into two groups:
153
+ * **Class 1 (Output 1):** All input vectors where `x₈ = 1`.
154
+ * **Class 0 (Output 0):** All input vectors where `x₈ = 0`.
155
+
156
+ Can a single linear equation separate these two groups? Yes, easily. A linear model calculates its output using the formula: `activation(w · x + b)`, where `w` is a vector of weights and `b` is a bias.
157
+
158
+ We can define a perfect set of weights and a bias for `y₁`:
159
+
160
+ * **Weights (`w`):** `[0, 0, 0, 0, 0, 0, 0, 1]`
161
+ * **Bias (`b`):** `-0.5`
162
+
163
+ Let's test this:
164
+ * **Case 1: `x₈ = 1`** (e.g., input is `[1,0,1,1,0,1,0,1]`)
165
+ * The calculation is `(0*x₁ + 0*x₂ + ... + 0*x₇ + 1*x₈) - 0.5`
166
+ * This simplifies to `x₈ - 0.5`
167
+ * Result: `1 - 0.5 = 0.5`. Since `0.5` is positive, the model correctly outputs **1**.
168
+
169
+ * **Case 2: `x₈ = 0`** (e.g., input is `[1,0,1,1,0,1,0,0]`)
170
+ * The calculation is `x₈ - 0.5`
171
+ * Result: `0 - 0.5 = -0.5`. Since `-0.5` is negative, the model correctly outputs **0**.
172
+
173
+ Since we found a simple linear formula that works for all possible inputs, the task of predicting `y₁` is linearly separable.
174
+
175
+ ### 3. Generalizing to All Outputs
176
+
177
+ The exact same logic applies to every other output bit:
178
+
179
+ * To predict `y₂ = x₇`, the weights would be `[0, 0, 0, 0, 0, 0, 1, 0]` with a bias of `-0.5`.
180
+ * To predict `y₃ = x₆`, the weights would be `[0, 0, 0, 0, 0, 1, 0, 0]` with a bias of `-0.5`.
181
+ * ...and so on.
182
+
183
+ Since a linear solution exists for each of the 8 output tasks, the entire problem is linearly separable.
184
+
185
+ ### Contrast with a Non-Linearly Separable Problem: XOR
186
+
187
+ The classic example of a problem that is *not* linearly separable is XOR. For a 2-input XOR, the outputs are:
188
+ * `0, 0` -> `0`
189
+ * `0, 1` -> `1`
190
+ * `1, 0` -> `1`
191
+ * `1, 1` -> `0`
192
+
193
+ You cannot draw a single straight line to separate the `0` outputs from the `1` outputs. You need a hidden layer to create a non-linear decision boundary. The key difference is that XOR's output depends on a **combination of inputs in a non-linear way**, whereas the bit-reversal problem has outputs that depend on **single inputs in a very simple, linear way.**
194
+
195
+ This provides an excellent way to build a comprehensive understanding of what makes a problem "hard" or "easy" for a simple neural network.
196
+
197
+ The fundamental dividing line is this:
198
+
199
+ * A bitwise transformation is **linearly separable** if the value of every single output bit can be determined by looking at the value of **at most one** input bit. The model only needs to learn a simple "re-wiring" (permutation) and/or "flipping" (inversion) scheme.
200
+ * A bitwise transformation is **not linearly separable** if the value of at least one output bit *requires* combining or comparing the values of **two or more** input bits. The model must learn logical relationships like `AND`, `OR`, or `XOR`.
201
+
202
+ Here are the lists based on that principle.
203
+
204
+ ---
205
+
206
+ ### Linearly Separable Bitwise Transformations
207
+
208
+ These are tasks where a simple MLP with no hidden layers (or with identity/linear activation functions) can achieve 100% accuracy. They are fundamentally about mapping single inputs to single outputs.
209
+
210
+ | Transformation | Description | Text Illustration (`Input: [1,1,0,0,1,0,1,0]`) |
211
+ | :--- | :--- | :--- |
212
+ | **Identity** | The output is an exact copy of the input. The model learns an identity matrix. | `Output: [1,1,0,0,1,0,1,0]` |
213
+ | **Bitwise NOT (Inversion)** | Every output bit is the inverse of the corresponding input bit (`yᵢ = NOT xᵢ`). | `Output: [0,0,1,1,0,1,0,1]` |
214
+ | **Permutations (Shuffle)** | The output bits are the same as the input bits, just in a different order. | |
215
+ | ↳ **Reverse** | The specific permutation where the order of bits is reversed. | `Output: [0,1,0,1,0,0,1,1]` |
216
+ | ↳ **Cyclic Shift (Rotate)** | Bits are shifted left or right, with bits from one end wrapping around to the other. | `Rotate Left by 2: [0,0,1,0,1,0,1,1]` |
217
+ | ↳ **Arbitrary Shuffle** | Any fixed, consistent re-ordering of the input bits. | `Shuffle: [0,0,1,1,1,0,1,0]` |
218
+ | **Masking & Selection** | Some output bits are forced to a constant value, while others copy an input bit. | |
219
+ | ↳ **Set High Bits to Zero** | The first N bits are set to 0, the rest are copied from the input. | `Set 4 high bits to 0: [0,0,0,0,1,0,1,0]` |
220
+ | ↳ **Select Even Bits** | Bits in even positions are copied; bits in odd positions are set to 0. | `Output: [0,1,0,0,0,0,0,0]` |
221
+ | **Combined Permutation & Inversion** | The output is a shuffled and inverted version of the input. | `Reverse and Invert: [1,0,1,0,1,1,0,0]` |
222
+
223
+ ---
224
+
225
+ ### Non-Linearly Separable Bitwise Transformations
226
+
227
+ These are tasks where a simple linear model will fail. They require at least one hidden layer with a non-linear activation function (like ReLU, Sigmoid, etc.) to learn the complex relationships between input bits.
228
+
229
+ | Transformation | Description | Text Illustration (`Input: [1,1,0,0,1,0,1,0]`) |
230
+ | :--- | :--- | :--- |
231
+ | **Bitwise Logic Gates** | The output is the result of a logical operation between two inputs (e.g., the input and a fixed key, or the input and a shifted version of itself). | `Key: [0,1,0,1,0,1,0,1]` |
232
+ | **XOR** | The canonical non-linear problem. Each output bit `yᵢ = xᵢ XOR kᵢ`. | `Input XOR Key: [1,0,0,1,1,1,1,1]` |
233
+ | **AND / OR** | `yᵢ = xᵢ AND kᵢ`. The output can only be 1 if *both* corresponding input bits are 1. | `Input AND Key: [0,1,0,0,0,0,0,0]` |
234
+ | **Arithmetic Operations** | These require combining bits with logic for carrying/borrowing, making them highly non-linear. | `Add 1 (Increment): [1,1,0,0,1,0,1,1]` |
235
+ | **Binary Addition/Subtraction** | `y = x + k`. The value of `yᵢ` depends on `xᵢ`, `kᵢ`, and the carry from the `i-1` position. | `Input + Key: [0,0,0,1,1,1,1,1]` (with carry) |
236
+ | **Two's Complement (Negation)** | Invert all bits (linear step), then add one (non-linear step). | `Negate Input: [0,0,1,1,0,1,1,0]` |
237
+ | **Parity Check** | The output indicates if the number of 1s in the input is even or odd. | |
238
+ | **Single Parity Bit** | A single output bit is the result of `x₁ XOR x₂ XOR ... XOR x₈`. | `Parity (even=0): [0,0,0,0,0,0,0,0]` |
239
+ | **Conditional Logic** | The operation depends on a condition involving multiple bits. | |
240
+ | **Conditional Inversion** | "If the first two bits are `1,1`, then invert the last four bits." The `AND` logic of the condition is non-linear. | `Output: [1,1,0,0,0,1,0,1]` |
241
+ | **Counting / Population Count**| The output is the binary representation of the number of 1s in the input. | `Input has 4 ones: [0,0,0,0,0,1,0,0]` |