Commit ·
dbbceb8
0
Parent(s):
update repository
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +36 -0
- CofiberDecomposition.v +263 -0
- README.md +145 -0
- TODO.md +33 -0
- analytical/analytical_70k/analytical_head_70k.pth +3 -0
- analytical/analytical_70k/analytical_head_70k_eval.json +13 -0
- analytical/analytical_70k/head.py +84 -0
- analytical/analytical_h1/analytical_h1_best.pth +3 -0
- analytical/analytical_h1/eval.json +12 -0
- analytical/scripts/analytical_best_gpu.py +229 -0
- analytical/scripts/analytical_empbayes.py +277 -0
- analytical/scripts/analytical_exotic_gpu.py +278 -0
- analytical/scripts/analytical_exotic_reg_gpu.py +284 -0
- analytical/scripts/analytical_fractal_gpu.py +268 -0
- analytical/scripts/analytical_gcv.py +268 -0
- analytical/scripts/analytical_greedy_gpu.py +244 -0
- analytical/scripts/analytical_hyperbatch.py +306 -0
- analytical/scripts/analytical_one.py +549 -0
- analytical/variants/README.md +77 -0
- analytical/variants/exotic_gpu.json +108 -0
- analytical/variants/exotic_reg_gpu.json +52 -0
- analytical/variants/fractal_results.json +17 -0
- analytical/variants/greedy_forward_gpu.json +809 -0
- analytical/variants/v001_baseline.json +23 -0
- analytical/variants/v002_spatial_cat_mean3x3.json +23 -0
- analytical/variants/v003_spatial_diff_neighbors.json +23 -0
- analytical/variants/v004_spatial_highreg.json +23 -0
- analytical/variants/v004_spatial_highreg_v2.json +23 -0
- analytical/variants/v005_power05_spatial_highreg.json +23 -0
- analytical/variants/v006_hv_neighbors_highreg.json +23 -0
- analytical/variants/v007_spatial_sqrt_highreg.json +23 -0
- analytical/variants/v008_spatial_neg3_highreg.json +23 -0
- analytical/variants/v009_sheaf_h1_compact.json +23 -0
- analytical/variants/v010_sheaf_h1_full.json +23 -0
- circuit/README.md +55 -0
- circuit/circuit_variants.json +489 -0
- circuit/cofiber_detector.sv +162 -0
- circuit/evolve_fast.py +211 -0
- circuit/evolved_K100_person_eval.json +9 -0
- circuit/evolved_extreme.json +453 -0
- circuit/person_analytical.pth +3 -0
- circuit/person_detector.sv +62 -0
- circuit/person_small_synth.v +85 -0
- circuit/rom/person_cls_b.hex +1 -0
- circuit/rom/person_cls_w.hex +768 -0
- circuit/rom/person_ctr_b.hex +1 -0
- circuit/rom/person_ctr_w.hex +768 -0
- circuit/rom/person_reg_b.hex +4 -0
- circuit/rom/person_reg_w.hex +3072 -0
- circuit/rom/test_features.hex +768 -0
.gitattributes
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
trained/dim_sweeps/dim20_v2/cofiber_threshold_dim20_coco_8ep_22k_coco_results.json filter=lfs diff=lfs merge=lfs -text
|
CofiberDecomposition.v
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(** * Cofiber scale decomposition in semi-additive categories
|
| 2 |
+
|
| 3 |
+
Given a semi-additive category with an adjunction Sigma -| Omega
|
| 4 |
+
(suspension/loop, upsample/pool), the counit epsilon : Sigma Omega -> 1
|
| 5 |
+
gives a "low-frequency projection" at each object. When the connecting
|
| 6 |
+
morphism in the cofiber of epsilon vanishes, X splits as a biproduct of
|
| 7 |
+
its low-frequency part and its high-frequency residual.
|
| 8 |
+
|
| 9 |
+
The splitting is natural in X: classification on cofibers is equivalent
|
| 10 |
+
to multi-scale classification on the original features.
|
| 11 |
+
|
| 12 |
+
The second section formalizes detection as pi0 of a presheaf colimit:
|
| 13 |
+
connected components of locally-constant sections over a patch site.
|
| 14 |
+
*)
|
| 15 |
+
|
| 16 |
+
From HoTT Require Import Basics.Overture.
|
| 17 |
+
From HoTT.Categories Require Import
|
| 18 |
+
Category.Core
|
| 19 |
+
Functor.Core Functor.Composition.Core Functor.Identity
|
| 20 |
+
NaturalTransformation.Core.
|
| 21 |
+
From HoTT.Categories.Additive Require Import ZeroObjects Biproducts SemiAdditive.
|
| 22 |
+
|
| 23 |
+
Set Universe Polymorphism.
|
| 24 |
+
Set Implicit Arguments.
|
| 25 |
+
Generalizable All Variables.
|
| 26 |
+
|
| 27 |
+
Local Open Scope category_scope.
|
| 28 |
+
Local Open Scope morphism_scope.
|
| 29 |
+
|
| 30 |
+
(** * Pre-stable structure on a semi-additive category *)
|
| 31 |
+
|
| 32 |
+
Record PreStableData := {
|
| 33 |
+
ps_cat : SemiAdditiveCategory;
|
| 34 |
+
ps_Susp : Functor ps_cat ps_cat;
|
| 35 |
+
ps_Loop : Functor ps_cat ps_cat;
|
| 36 |
+
ps_epsilon : NaturalTransformation (ps_Susp o ps_Loop)%functor
|
| 37 |
+
(Functor.Identity.identity ps_cat)
|
| 38 |
+
}.
|
| 39 |
+
|
| 40 |
+
Coercion ps_cat : PreStableData >-> SemiAdditiveCategory.
|
| 41 |
+
|
| 42 |
+
Section CofiberSplitting.
|
| 43 |
+
|
| 44 |
+
Context (PS : PreStableData).
|
| 45 |
+
|
| 46 |
+
Let C := ps_cat PS.
|
| 47 |
+
Let Sig := ps_Susp PS.
|
| 48 |
+
Let L := ps_Loop PS.
|
| 49 |
+
Let eps := ps_epsilon PS.
|
| 50 |
+
|
| 51 |
+
Definition low_freq (X : object C) : object C := Sig (L X).
|
| 52 |
+
|
| 53 |
+
Definition eps_at (X : object C) : morphism C (low_freq X) X := eps X.
|
| 54 |
+
|
| 55 |
+
(** A cofiber splitting of X along epsilon is a biproduct decomposition
|
| 56 |
+
of X into low_freq X and some high-frequency complement H, mediated
|
| 57 |
+
by an isomorphism between the biproduct object and X. *)
|
| 58 |
+
|
| 59 |
+
Record CofiberSplitting (X : object C) := {
|
| 60 |
+
cs_high : object C;
|
| 61 |
+
cs_biprod : @Biproduct C _ (low_freq X) cs_high;
|
| 62 |
+
cs_iso : morphism C (biproduct_obj (biproduct_data cs_biprod)) X;
|
| 63 |
+
cs_iso_inv : morphism C X (biproduct_obj (biproduct_data cs_biprod));
|
| 64 |
+
cs_sect : (cs_iso o cs_iso_inv = 1)%morphism;
|
| 65 |
+
cs_retr : (cs_iso_inv o cs_iso = 1)%morphism;
|
| 66 |
+
cs_eps_compat :
|
| 67 |
+
(cs_iso o inl (biproduct_data cs_biprod) = eps_at X)%morphism
|
| 68 |
+
}.
|
| 69 |
+
|
| 70 |
+
Arguments cs_high {X} _.
|
| 71 |
+
Arguments cs_biprod {X} _.
|
| 72 |
+
Arguments cs_iso {X} _.
|
| 73 |
+
Arguments cs_iso_inv {X} _.
|
| 74 |
+
|
| 75 |
+
(** Naturality of epsilon. *)
|
| 76 |
+
Lemma eps_natural {X Y : object C} (f : morphism C X Y)
|
| 77 |
+
: (eps_at Y o (Sig _1 (L _1 f)) = f o eps_at X)%morphism.
|
| 78 |
+
Proof.
|
| 79 |
+
exact (commutes eps X Y f).
|
| 80 |
+
Qed.
|
| 81 |
+
|
| 82 |
+
(** The low-frequency component of a morphism. *)
|
| 83 |
+
Definition low_component {X Y : object C} (f : morphism C X Y)
|
| 84 |
+
: morphism C (low_freq X) (low_freq Y)
|
| 85 |
+
:= Sig _1 (L _1 f).
|
| 86 |
+
|
| 87 |
+
(** The iso inverse composed with epsilon gives the left injection.
|
| 88 |
+
Derivable from cs_eps_compat and cs_retr. *)
|
| 89 |
+
Lemma iso_inv_eps (X : object C) (sp : CofiberSplitting X)
|
| 90 |
+
: (cs_iso_inv sp o eps_at X
|
| 91 |
+
= inl (biproduct_data (cs_biprod sp)))%morphism.
|
| 92 |
+
Proof.
|
| 93 |
+
rewrite <- (cs_eps_compat sp).
|
| 94 |
+
rewrite <- associativity.
|
| 95 |
+
rewrite (cs_retr sp).
|
| 96 |
+
apply left_identity.
|
| 97 |
+
Qed.
|
| 98 |
+
|
| 99 |
+
(** ** Provable block structure
|
| 100 |
+
|
| 101 |
+
Given a family of splittings and a morphism f : X -> Y, the
|
| 102 |
+
conjugated morphism psi_Y o f o phi_X : BX -> BY has the
|
| 103 |
+
following block structure with respect to the biproducts:
|
| 104 |
+
|
| 105 |
+
- (low, low): low_component f [low_low_block]
|
| 106 |
+
- (high, low): 0 [cross_term_high_low_zero]
|
| 107 |
+
- (low, high): requires cofiber [cross_term_low_high_zero]
|
| 108 |
+
- (high, high): requires cofiber
|
| 109 |
+
|
| 110 |
+
The first two are provable from naturality of epsilon alone.
|
| 111 |
+
The latter two require the splitting to be functorial. *)
|
| 112 |
+
|
| 113 |
+
(** The conjugated morphism maps the low injection through epsilon's
|
| 114 |
+
naturality to the low injection at the target. This is the key
|
| 115 |
+
intermediate result used in both block theorems. *)
|
| 116 |
+
Lemma conjugated_inl
|
| 117 |
+
(split : forall X : object C, CofiberSplitting X)
|
| 118 |
+
{X Y : object C} (f : morphism C X Y)
|
| 119 |
+
: (cs_iso_inv (split Y) o f o cs_iso (split X)
|
| 120 |
+
o inl (biproduct_data (cs_biprod (split X)))
|
| 121 |
+
= inl (biproduct_data (cs_biprod (split Y)))
|
| 122 |
+
o low_component f)%morphism.
|
| 123 |
+
Proof.
|
| 124 |
+
repeat rewrite Category.Core.associativity.
|
| 125 |
+
rewrite (cs_eps_compat (split X)).
|
| 126 |
+
rewrite <- (eps_natural f).
|
| 127 |
+
assert (H : (cs_iso_inv (split Y) o (eps_at Y o low_component f)
|
| 128 |
+
= (cs_iso_inv (split Y) o eps_at Y) o low_component f)%morphism).
|
| 129 |
+
{ symmetry. apply Category.Core.associativity. }
|
| 130 |
+
rewrite H.
|
| 131 |
+
rewrite (iso_inv_eps (split Y)).
|
| 132 |
+
reflexivity.
|
| 133 |
+
Qed.
|
| 134 |
+
|
| 135 |
+
(** The low-low block equals the functorial low-frequency component. *)
|
| 136 |
+
Theorem low_low_block
|
| 137 |
+
(split : forall X : object C, CofiberSplitting X)
|
| 138 |
+
{X Y : object C} (f : morphism C X Y)
|
| 139 |
+
: let BX := biproduct_data (cs_biprod (split X)) in
|
| 140 |
+
let BY := biproduct_data (cs_biprod (split Y)) in
|
| 141 |
+
(outl BY o cs_iso_inv (split Y) o f o cs_iso (split X) o inl BX
|
| 142 |
+
= low_component f)%morphism.
|
| 143 |
+
Proof.
|
| 144 |
+
intros BX BY.
|
| 145 |
+
repeat rewrite Category.Core.associativity.
|
| 146 |
+
assert (H := conjugated_inl split f).
|
| 147 |
+
repeat rewrite Category.Core.associativity in H.
|
| 148 |
+
rewrite H.
|
| 149 |
+
rewrite <- Category.Core.associativity.
|
| 150 |
+
rewrite (beta_l (biproduct_is (cs_biprod (split Y)))).
|
| 151 |
+
apply left_identity.
|
| 152 |
+
Qed.
|
| 153 |
+
|
| 154 |
+
(** The high-low cross term vanishes: injecting from the low-frequency
|
| 155 |
+
part of X and projecting onto the high-frequency part of Y gives
|
| 156 |
+
zero. Follows from naturality of epsilon and the biproduct axioms. *)
|
| 157 |
+
Theorem cross_term_high_low_zero
|
| 158 |
+
(split : forall X : object C, CofiberSplitting X)
|
| 159 |
+
{X Y : object C} (f : morphism C X Y)
|
| 160 |
+
: let BX := biproduct_data (cs_biprod (split X)) in
|
| 161 |
+
let BY := biproduct_data (cs_biprod (split Y)) in
|
| 162 |
+
(outr BY o cs_iso_inv (split Y) o f o cs_iso (split X) o inl BX
|
| 163 |
+
= @zero_morphism C _ (low_freq X) (cs_high (split Y)))%morphism.
|
| 164 |
+
Proof.
|
| 165 |
+
intros BX BY.
|
| 166 |
+
repeat rewrite Category.Core.associativity.
|
| 167 |
+
assert (H := conjugated_inl split f).
|
| 168 |
+
repeat rewrite Category.Core.associativity in H.
|
| 169 |
+
rewrite H.
|
| 170 |
+
rewrite <- Category.Core.associativity.
|
| 171 |
+
rewrite (mixed_r (biproduct_is (cs_biprod (split Y)))).
|
| 172 |
+
apply zero_morphism_left.
|
| 173 |
+
Qed.
|
| 174 |
+
|
| 175 |
+
(** The low-high cross term vanishes when the splitting is functorial:
|
| 176 |
+
the conjugated morphism maps the high-frequency injection at X
|
| 177 |
+
into the high-frequency injection at Y.
|
| 178 |
+
|
| 179 |
+
This condition is derivable when the splitting comes from a
|
| 180 |
+
cofiber construction (distinguished triangles + vanishing
|
| 181 |
+
connecting morphism), which requires the stable category
|
| 182 |
+
machinery from PR 2288. Here we take it as a hypothesis. *)
|
| 183 |
+
Theorem cross_term_low_high_zero
|
| 184 |
+
(split : forall X : object C, CofiberSplitting X)
|
| 185 |
+
{X Y : object C} (f : morphism C X Y)
|
| 186 |
+
(f_high : morphism C (cs_high (split X)) (cs_high (split Y)))
|
| 187 |
+
(H_func :
|
| 188 |
+
(cs_iso_inv (split Y) o f o cs_iso (split X)
|
| 189 |
+
o inr (biproduct_data (cs_biprod (split X)))
|
| 190 |
+
= inr (biproduct_data (cs_biprod (split Y))) o f_high)%morphism)
|
| 191 |
+
: let BX := biproduct_data (cs_biprod (split X)) in
|
| 192 |
+
let BY := biproduct_data (cs_biprod (split Y)) in
|
| 193 |
+
(outl BY o cs_iso_inv (split Y) o f o cs_iso (split X) o inr BX
|
| 194 |
+
= @zero_morphism C _ (cs_high (split X)) (low_freq Y))%morphism.
|
| 195 |
+
Proof.
|
| 196 |
+
intros BX BY.
|
| 197 |
+
repeat rewrite associativity.
|
| 198 |
+
repeat rewrite associativity in H_func.
|
| 199 |
+
rewrite H_func.
|
| 200 |
+
rewrite <- associativity.
|
| 201 |
+
rewrite (mixed_l (biproduct_is (cs_biprod (split Y)))).
|
| 202 |
+
apply zero_morphism_left.
|
| 203 |
+
Qed.
|
| 204 |
+
|
| 205 |
+
(** ** Iterated decomposition *)
|
| 206 |
+
|
| 207 |
+
Fixpoint iterated_low (n : nat) (X : object C) : object C :=
|
| 208 |
+
match n with
|
| 209 |
+
| O => X
|
| 210 |
+
| S m => low_freq (iterated_low m X)
|
| 211 |
+
end.
|
| 212 |
+
|
| 213 |
+
Definition scale_band
|
| 214 |
+
(split : forall X, CofiberSplitting X) (k : nat) (X : object C)
|
| 215 |
+
: object C :=
|
| 216 |
+
cs_high (split (iterated_low k X)).
|
| 217 |
+
|
| 218 |
+
Definition iterated_splitting
|
| 219 |
+
(split : forall X, CofiberSplitting X) (k : nat) (X : object C)
|
| 220 |
+
: CofiberSplitting (iterated_low k X) :=
|
| 221 |
+
split (iterated_low k X).
|
| 222 |
+
|
| 223 |
+
End CofiberSplitting.
|
| 224 |
+
|
| 225 |
+
(** * Detection as pi0 of a presheaf colimit *)
|
| 226 |
+
|
| 227 |
+
From HoTT Require Import Basics.Trunc Truncations.Core.
|
| 228 |
+
From HoTT Require Import Diagrams.Graph Diagrams.Diagram.
|
| 229 |
+
From HoTT Require Import Colimits.Colimit.
|
| 230 |
+
|
| 231 |
+
Section SheafPi0.
|
| 232 |
+
|
| 233 |
+
Context (Site : Graph).
|
| 234 |
+
Context (F : Diagram Site).
|
| 235 |
+
|
| 236 |
+
Definition presheaf_colimit : Type := Colimit F.
|
| 237 |
+
|
| 238 |
+
Definition pi0 : Type := Trunc 0 presheaf_colimit.
|
| 239 |
+
|
| 240 |
+
Global Instance ishset_pi0 : IsHSet pi0 := _.
|
| 241 |
+
|
| 242 |
+
Definition pi0_in (i : Site) (x : obj F i) : pi0 := tr (colim i x).
|
| 243 |
+
|
| 244 |
+
Definition same_component (i j : Site) (x : obj F i) (y : obj F j)
|
| 245 |
+
: Type :=
|
| 246 |
+
pi0_in i x = pi0_in j y.
|
| 247 |
+
|
| 248 |
+
Record FinitePresentation := {
|
| 249 |
+
fp_graph : Graph;
|
| 250 |
+
fp_diagram : Diagram fp_graph;
|
| 251 |
+
fp_n_gen : nat;
|
| 252 |
+
fp_n_rel : nat;
|
| 253 |
+
fp_equiv : Colimit fp_diagram <~> Colimit F
|
| 254 |
+
}.
|
| 255 |
+
|
| 256 |
+
Theorem finite_presentation_pi0 (P : FinitePresentation)
|
| 257 |
+
: Trunc 0 (Colimit (fp_diagram P)) <~> pi0.
|
| 258 |
+
Proof.
|
| 259 |
+
apply Trunc_functor_equiv.
|
| 260 |
+
exact (fp_equiv P).
|
| 261 |
+
Defined.
|
| 262 |
+
|
| 263 |
+
End SheafPi0.
|
README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: fair-research-license
|
| 4 |
+
base_model: facebook/EUPE-ViT-B
|
| 5 |
+
tags:
|
| 6 |
+
- object-detection
|
| 7 |
+
- vision-transformer
|
| 8 |
+
- cofiber-decomposition
|
| 9 |
+
library_name: pytorch
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# Cofiber Detection
|
| 13 |
+
|
| 14 |
+
Object detection heads built on cofiber decomposition of frozen [EUPE-ViT-B](https://huggingface.co/facebook/EUPE-ViT-B) features. The cofiber decomposition produces multi-scale representations with zero learned parameters, replacing the 11M-parameter FPN typically used in FCOS-style detectors. Heads range from 70-parameter analytical constructions to 3.85M-parameter trained networks, evaluated on COCO val2017.
|
| 15 |
+
|
| 16 |
+
## The Cofiber Decomposition
|
| 17 |
+
|
| 18 |
+
Given spatial backbone features `f : [768, H, W]`, the cofiber decomposition produces `n` scale bands via iterated subtraction of downsampled-then-upsampled content:
|
| 19 |
+
|
| 20 |
+
```
|
| 21 |
+
residual = f
|
| 22 |
+
for k = 0 to n-2:
|
| 23 |
+
omega_k = avgpool(residual, 2)
|
| 24 |
+
sigma_omega_k = upsample_bilinear(omega_k, size=residual.shape)
|
| 25 |
+
cofiber_k = residual - sigma_omega_k
|
| 26 |
+
residual = omega_k
|
| 27 |
+
cofiber_{n-1} = residual
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
Each `cofiber_k` captures frequency content at a distinct scale with no cross-scale interference. The decomposition is a fixed two-line operation, yet it provides the same multi-scale structure that an FPN synthesizes with 11M trained parameters.
|
| 31 |
+
|
| 32 |
+
The construction is machine-checked in Rocq/HoTT (`CofiberDecomposition.v`). The proof frames average pooling and bilinear upsampling as an adjoint pair whose counit gives a short exact sequence in a semi-additive category; the cofiber bands are the kernels of the projections, and the sum is exact by construction.
|
| 33 |
+
|
| 34 |
+
## Best Results (COCO val2017)
|
| 35 |
+
|
| 36 |
+
| Variant | Params | mAP | mAP@0.50 | mAP@0.75 | Category |
|
| 37 |
+
|---------|--------|-----|----------|----------|----------|
|
| 38 |
+
| **split_tower_5scale_160h_5std_4dw_ema_l14_16ep_768_cls_calib** | **2,975,067** | **42.64** | **65.70** | **45.10** | trained |
|
| 39 |
+
| split_tower_5scale_160h_5std_4dw_ema_l14_16ep_768 (step 104k, pre-calib) | 2,975,067 | 42.49 | 65.57 | 44.89 | trained |
|
| 40 |
+
| split_tower_5scale_160h_5std_4dw_ema_l14_16ep (step 100k, 640px) | 2,975,067 | 41.15 | 63.99 | 43.83 | trained |
|
| 41 |
+
| split_tower_5scale_192h_5std_4dw_textaligned_640px | 4,164,699 | 25.95 | 39.13 | 28.92 | trained |
|
| 42 |
+
| split_tower_5scale_192h_5std_4dw | 4,068,954 | 24.6 | 37.1 | 27.0 | trained |
|
| 43 |
+
| split_tower_192h_5std_4dw | 4,016,441 | 20.7 | 28.5 | 22.8 | trained |
|
| 44 |
+
| split_tower_224h_3std_6dw | 3,849,657 | 20.3 | 28.1 | 22.3 | trained |
|
| 45 |
+
| conv_deep_p3_lateral | 4,269,785 | 19.9 | 28.4 | 22.0 | trained |
|
| 46 |
+
| conv_deep_p3 | 3,972,569 | 19.7 | 28.3 | 21.6 | trained |
|
| 47 |
+
| conv_deep_3.38M | 3,381,592 | 18.8 | 27.4 | 20.9 | trained |
|
| 48 |
+
| conv_deep_912k | 911,960 | 17.2 | 25.6 | 19.2 | trained |
|
| 49 |
+
| evolved_deep | 182,580 | 10.6 | 18.9 | 10.8 | trained |
|
| 50 |
+
| spatialreg_92k | 91,960 | 8.2 | 25.7 | 2.8 | trained |
|
| 51 |
+
| box32_92k | 91,640 | 5.9 | 21.4 | 1.3 | trained |
|
| 52 |
+
| box32 pruned R2 | ~62,000 nz | 5.9 | 20.4 | 1.5 | trained |
|
| 53 |
+
| dim20 | 22,076 | 3.9 | 14.8 | 0.9 | trained |
|
| 54 |
+
| analytical_70k | 69,976 | 1.6 | 6.0 | 0.4 | analytical |
|
| 55 |
+
| evolved K=100 person | 105 | 1.3 | 5.8 | 0.1 | circuit |
|
| 56 |
+
| Baseline FCOS (non-cofiber) | 16,138,074 | 41.0 | 64.8 | 43.2 | reference |
|
| 57 |
+
|
| 58 |
+
The current split-tower head reaches **42.64 mAP on COCO val2017 with 2,975,067 learnable parameters** (42.71 under soft NMS), passing the 16.14M FCOS baseline (41.0 mAP) by +1.64 while using 18.4 percent of its head parameter budget. Small-object mAP is 22.3 (FCOS 19.4, +2.9). This is the head shipped in [phanerozoic/argus](https://huggingface.co/phanerozoic/argus). The architecture consists of separate classification and regression convolutional towers, each built from five standard 3×3 convolutions followed by four depthwise residual blocks at a hidden dimension of 160 channels. Its input is a cofiber decomposition of the backbone patch features into four frequency-separated bands (corresponding to spatial strides of 16, 32, 64, and 128 pixels), with an additional finer-resolution level (stride 8) synthesized by a single transposed convolution from the stride-16 band. Top-down lateral connections pass information from coarser bands into finer ones before the towers run. The five resulting prediction levels (strides 8, 16, 32, 64, and 128) match the scale coverage of the FCOS simple feature pyramid while obtaining their multi-scale structure from a zero-parameter decomposition rather than from a learned feature pyramid network.
|
| 59 |
+
|
| 60 |
+
The path from 24.6 mAP to 42.64 mAP was recipe-and-resolution, not architectural. Hidden width actually went down (192 → 160); the gains came from ATSS target assignment (replacing FCOS center sampling), horizontal flip augmentation, a CLIP ViT-L/14 8-prompt-average text embedding in place of ViT-B/32 single-prompt, PC-initialized cls_project (first 80 columns from the SVD of the text embedding, remaining columns a random orthogonal complement), exponential moving average during training (decay 0.9998), a doubled 16-epoch schedule with late-training checkpoint selection, the training-resolution jump from 640-pixel to 768-pixel input (+1.34 mAP, mostly on small-object AP via the 48×48 backbone grid vs 40×40), and a 3-epoch partial fine-tune updating only the classification calibration layers (`cls_project`, `cls_bias`, `logit_scale`) at lr 1e-4 with towers and cofiber path frozen (+0.15 mAP). The final checkpoint is the end state of the partial fine-tune; eval JSON sits next to the weights in the shipping directory.
|
| 61 |
+
|
| 62 |
+
## Repository Structure
|
| 63 |
+
|
| 64 |
+
### [`analytical/`](analytical/) — Zero-training or closed-form constructions
|
| 65 |
+
|
| 66 |
+
| Path | Description |
|
| 67 |
+
|------|-------------|
|
| 68 |
+
| [`analytical_70k/`](analytical/analytical_70k/) | Closed-form least-squares head. 70K params, 1.6 mAP, zero training |
|
| 69 |
+
| [`analytical_h1/`](analytical/analytical_h1/) | Sheaf cohomology (H^1) features. Experimental |
|
| 70 |
+
| [`variants/`](analytical/variants/) | Exotic feature experiments (quadratic, RFF, Fourier, fractal) with result JSONs |
|
| 71 |
+
| [`scripts/`](analytical/scripts/) | `analytical_greedy_gpu.py`, `analytical_exotic_gpu.py`, `analytical_empbayes.py`, etc. |
|
| 72 |
+
|
| 73 |
+
### [`trained/`](trained/) — Gradient-trained cofiber heads
|
| 74 |
+
|
| 75 |
+
| Path | Params | mAP | Description |
|
| 76 |
+
|------|--------|-----|-------------|
|
| 77 |
+
| [`split_tower_5scale/`](trained/split_tower_5scale/) | 4.07M | **24.6** | Five-scale split-tower head (P3-P7). Current best |
|
| 78 |
+
| [`split_tower/`](trained/split_tower/) | 4.02M | 20.7 | Four-scale split-tower head (predecessor) |
|
| 79 |
+
| [`conv_deep/`](trained/conv_deep/) | 912K-4.27M | 17.2-19.9 | Depthwise residual stack variants (scaled, P3, lateral) |
|
| 80 |
+
| [`evolved_deep/`](trained/evolved_deep/) | 182K | 10.6 | 10-layer MLP on 92 evolutionarily-selected dims |
|
| 81 |
+
| [`spatialreg_92k/`](trained/spatialreg_92k/) | 92K | 8.2 | 3x3 depthwise conv on regression output |
|
| 82 |
+
| [`linear_70k/`](trained/linear_70k/) | 70K | 5.2 | Trained linear classifier |
|
| 83 |
+
| [`box32_92k/`](trained/box32_92k/) | 92K | 5.9 | INT8 threshold logic circuit + pruned variants (46K-76K) |
|
| 84 |
+
| [`box32_distilled/`](trained/box32_distilled/) | 92K | — | Self-distillation of box32 |
|
| 85 |
+
| [`dim_sweeps/`](trained/dim_sweeps/) | 9K-80K | 0.3-? | SVD-initialized fixed-dim heads (5, 10, 15, 20, 30, 80) |
|
| 86 |
+
| [`sloe/`](trained/sloe/) | — | 0.0 | Spectral Laplacian object emergence (failed experiment) |
|
| 87 |
+
| [`person_specialist/`](trained/person_specialist/) | 9K | — | Person-only detector |
|
| 88 |
+
| [`waldo_specialist/`](trained/waldo_specialist/) | 5K | — | Waldo-finding detector |
|
| 89 |
+
| [`experimental_scaffolds/`](trained/experimental_scaffolds/) | — | — | Untrained architectural scaffolds (5scale, adaptive, centernet, linear) |
|
| 90 |
+
|
| 91 |
+
### [`circuit/`](circuit/) — Hardware cofiber circuits
|
| 92 |
+
|
| 93 |
+
| File | Description |
|
| 94 |
+
|------|-------------|
|
| 95 |
+
| `person_analytical.pth` | Person classifier at 93 parameters, 99.8% recall |
|
| 96 |
+
| `person_detector.sv`, `cofiber_detector.sv` | Verilog implementations |
|
| 97 |
+
| `rom/*.hex` | INT8 weight ROMs |
|
| 98 |
+
| `evolved_K100_person_eval.json` | Evolutionary search result, 105 params, 1.3 mAP |
|
| 99 |
+
| `tb_person.sv` | Testbench |
|
| 100 |
+
|
| 101 |
+
### [`scripts/`](scripts/) — Training and evaluation
|
| 102 |
+
|
| 103 |
+
| Script | Target |
|
| 104 |
+
|--------|--------|
|
| 105 |
+
| `train_split_tower.py` | Split tower (best) |
|
| 106 |
+
| `train_conv_deep.py` | Conv deep family (912K-4.27M) |
|
| 107 |
+
| `train_evolved_deep.py` | Evolved deep on 92 dims |
|
| 108 |
+
| `eval_conv_deep_step.py` | Eval any conv_deep checkpoint |
|
| 109 |
+
| `eval_evolved_deep.py` | Eval evolved_deep checkpoint |
|
| 110 |
+
| `eval_coco_map.py` | Generic COCO mAP eval |
|
| 111 |
+
|
| 112 |
+
### [`CofiberDecomposition.v`](CofiberDecomposition.v)
|
| 113 |
+
|
| 114 |
+
Rocq/HoTT machine-checked proof that the cofiber decomposition is exact in a semi-additive category: every input decomposes uniquely as a sum of scale bands with zero cross-term residual.
|
| 115 |
+
|
| 116 |
+
## Scaling Curve
|
| 117 |
+
|
| 118 |
+
The relationship between head parameters and mAP is approximately logarithmic across four orders of magnitude, until the CLIP-text-aligned 160h recipe lands above FCOS:
|
| 119 |
+
|
| 120 |
+
```
|
| 121 |
+
105 params → 1.3 mAP (evolved circuit, person only)
|
| 122 |
+
70K params → 1.6 mAP (analytical closed-form)
|
| 123 |
+
92K params → 8.2 mAP (depthwise conv on regression)
|
| 124 |
+
182K params → 10.6 mAP (evolved dim selection + 10-layer MLP)
|
| 125 |
+
912K params → 17.2 mAP (depthwise conv stack)
|
| 126 |
+
3.97M params → 19.7 mAP (with stride-8 P3)
|
| 127 |
+
3.85M params → 20.3 mAP (split cls/reg towers, 3 std + 6 dw at 224 hidden, 4 scales)
|
| 128 |
+
4.02M params → 20.7 mAP (split cls/reg towers, 5 std + 4 dw at 192 hidden, 4 scales)
|
| 129 |
+
4.07M params → 24.6 mAP (same tower, 5 scales / P3-P7 coverage)
|
| 130 |
+
4.16M params → 25.95 mAP (+ CLIP ViT-B/32 text-aligned classifier, 8 ep, 640px)
|
| 131 |
+
2.98M params → 41.15 mAP (160h + ATSS + EMA + PC init + CLIP ViT-L/14, 16 ep, 640px)
|
| 132 |
+
2.98M params → 42.49 mAP (same recipe, 768px training input)
|
| 133 |
+
2.98M params → 42.64 mAP (+ 3-epoch cls_calib fine-tune — shipped in Argus)
|
| 134 |
+
16.14M params → 41.0 mAP (FCOS baseline with FPN, 640px)
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
The bottom four rows are the point of the repository. The 25.95 → 42.64 ascent required no architectural capacity increase (hidden width dropped from 192 to 160) and no change to the cofiber decomposition itself. It came from training recipe: ATSS assignment, flip aug, EMA, PC-initialized cls_project, CLIP ViT-L/14 multi-prompt text embeddings, doubled schedule with late-training checkpoint selection, 640→768 resolution scaling, and a final 3-epoch classification-calibration fine-tune. At 18.4 percent of FCOS's head parameter budget the 2.98M checkpoint beats FCOS by +1.64 mAP under hard NMS and +1.71 under soft NMS, with the small-object gap widening to +2.9.
|
| 138 |
+
|
| 139 |
+
## Broader Detection Work
|
| 140 |
+
|
| 141 |
+
Non-cofiber detection heads (FCOS baseline, untrained architectural variants, alternative formulations) are hosted in [phanerozoic/detection-heads](https://huggingface.co/phanerozoic/detection-heads), which also includes the top-performing cofiber head (split_tower) for reference. This repository is the canonical host for cofiber-based detection research.
|
| 142 |
+
|
| 143 |
+
## License
|
| 144 |
+
|
| 145 |
+
Fair Research License. See `LICENSE`.
|
TODO.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cofiber Detection Circuit — Research Directions
|
| 2 |
+
|
| 3 |
+
## Dense detection at sub-stride resolution
|
| 4 |
+
|
| 5 |
+
The circuit's L1-cache-resident weight set (241 KB) permits evaluation at spatial densities impractical for larger detection heads. At 61K INT8 parameters, per-pixel detection across a 640×640 input (409,600 locations × 80 classes) remains within single-digit millisecond latency on CPU. This eliminates the stride-16 quantization of detection locations inherent in patch-based approaches and may improve small-object recall.
|
| 6 |
+
|
| 7 |
+
## Prototype ensemble via weight replication
|
| 8 |
+
|
| 9 |
+
Multiple instances of the circuit with independently trained prototype sets can be evaluated in parallel and their outputs combined by majority vote. At 241 KB per instance, a 100-member ensemble occupies 24 MB — within L2 cache on commodity hardware. The ensemble diversity comes from different training seeds, data splits, or domain-specific prototype sets. The question is whether ensembling at the prototype level produces complementary detections or redundant ones.
|
| 10 |
+
|
| 11 |
+
## Fusion with backbone computation
|
| 12 |
+
|
| 13 |
+
The cofiber decomposition (pool + subtract) operates on the same tensor format as the backbone's intermediate attention outputs. Rather than treating backbone and head as sequential stages with a memory-bus boundary between them, the circuit can be fused into the backbone's final block as a post-attention operation. The detection output is produced before the backbone features are written to global memory, eliminating one full read-write cycle.
|
| 14 |
+
|
| 15 |
+
## Inline video detection
|
| 16 |
+
|
| 17 |
+
The circuit is small enough to execute inside a video decode loop between frame reconstructions. On hardware with a dedicated video decode unit (NVDEC, Intel QSV, Apple VideoToolbox), the detection circuit runs on the CPU cores that would otherwise idle during decode. This produces per-frame detections with zero additional latency beyond the decode itself, without a separate inference pipeline.
|
| 18 |
+
|
| 19 |
+
## Formal verification of circuit properties
|
| 20 |
+
|
| 21 |
+
The 61,520-parameter weight space is small enough for bounded model checking. Properties amenable to formal verification include: maximum detection count per input (proving the circuit cannot produce more than K detections on any valid feature tensor), mutual exclusion of class pairs at shared locations, and monotonicity of detection score with respect to prototype similarity. These guarantees are relevant for safety-critical deployment where unbounded detection output is unacceptable.
|
| 22 |
+
|
| 23 |
+
## On-device prototype adaptation
|
| 24 |
+
|
| 25 |
+
Retraining the circuit requires updating a single 80×768 weight matrix — a rank-1 update per corrected class. On a mobile device, a user correction (misclassified detection) translates to a running-average update of the corresponding class prototype: `w_c ← (1-α)w_c + α·f_corrected`. No optimizer state, no backpropagation, no framework. The prototype update is a vector addition that executes in microseconds. The question is whether online prototype adaptation converges to useful personalization or drifts under distribution shift.
|
| 26 |
+
|
| 27 |
+
## Neuromorphic deployment
|
| 28 |
+
|
| 29 |
+
The depth-3 circuit with integer weights and Heaviside activation maps directly to spiking neural network hardware (Intel Loihi, IBM TrueNorth, BrainChip Akida). Each threshold gate is one neuron. The fixed-weight layers (pool, subtract) are hardwired connections. The classification layer is a programmable weight matrix loaded once. Event-driven evaluation on neuromorphic hardware consumes power proportional to the number of active detections, not the number of spatial locations evaluated.
|
| 30 |
+
|
| 31 |
+
## Exhaustive INT8 weight search
|
| 32 |
+
|
| 33 |
+
At 61,520 INT8 parameters, local search over the weight space is tractable. Starting from the trained prototypes, systematically test single-weight perturbations (increment or decrement each INT8 value by 1) and retain changes that improve detection fitness on a held-out set. This is the same pruning methodology used in the `8bit-threshold-computer` project (`prune_weights.py`), applied to detection prototypes rather than arithmetic circuits.
|
analytical/analytical_70k/analytical_head_70k.pth
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ecd1974d125b19c5b741b9ffa2f06c06baa58a246218d90e4e54ccd3d79a6aee
|
| 3 |
+
size 284165
|
analytical/analytical_70k/analytical_head_70k_eval.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"head": "analytical_detector",
|
| 3 |
+
"params": 69976,
|
| 4 |
+
"checkpoint": "heads/cofiber_threshold/analytical_70k/analytical_head_70k.pth",
|
| 5 |
+
"n_images": 5000,
|
| 6 |
+
"n_detections": 500000,
|
| 7 |
+
"mAP_0.5_0.95": 0.01546164516440593,
|
| 8 |
+
"mAP_0.50": 0.06037011951154602,
|
| 9 |
+
"mAP_0.75": 0.0035925450594784733,
|
| 10 |
+
"mAP_small": 0.0021775822040523978,
|
| 11 |
+
"mAP_medium": 0.017033486120342587,
|
| 12 |
+
"mAP_large": 0.027756867681569267
|
| 13 |
+
}
|
analytical/analytical_70k/head.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Analytical detection head — zero gradient steps.
|
| 2 |
+
|
| 3 |
+
All weights are computed from closed-form least-squares on cached backbone
|
| 4 |
+
features. The entire head is a derived circuit: cofiber decomposition (fixed)
|
| 5 |
+
+ linear predictions (solved via matrix inverse).
|
| 6 |
+
|
| 7 |
+
Construction:
|
| 8 |
+
1. Accumulate sufficient statistics: X^T X and X^T Y from training features
|
| 9 |
+
at positive locations, where X = features and Y = targets.
|
| 10 |
+
2. Solve: W = (X^T X + lambda I)^{-1} X^T Y for classification, regression,
|
| 11 |
+
and centerness independently.
|
| 12 |
+
3. The resulting weights are the optimal linear predictor in the least-squares sense.
|
| 13 |
+
|
| 14 |
+
There is no training loop, no learning rate, no epochs. The head is computed
|
| 15 |
+
from a single pass over the training data and one matrix inverse per task.
|
| 16 |
+
|
| 17 |
+
Parameters: 69,976
|
| 18 |
+
Construction time: ~130 seconds on CPU
|
| 19 |
+
COCO val2017 mAP: 1.6
|
| 20 |
+
|
| 21 |
+
This is the first known fully-derived detection head on frozen backbone features.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
import os
|
| 25 |
+
import json
|
| 26 |
+
import time
|
| 27 |
+
|
| 28 |
+
import torch
|
| 29 |
+
import torch.nn as nn
|
| 30 |
+
import torch.nn.functional as F
|
| 31 |
+
|
| 32 |
+
NUM_CLASSES = 80
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def cofiber_decompose(f, n_scales):
|
| 36 |
+
cofibers = []
|
| 37 |
+
residual = f
|
| 38 |
+
for _ in range(n_scales - 1):
|
| 39 |
+
omega = F.avg_pool2d(residual, 2)
|
| 40 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 41 |
+
cofibers.append(residual - sigma_omega)
|
| 42 |
+
residual = omega
|
| 43 |
+
cofibers.append(residual)
|
| 44 |
+
return cofibers
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
class AnalyticalDetector(nn.Module):
|
| 48 |
+
"""Fully analytical detection head. All weights from closed-form solution."""
|
| 49 |
+
name = "analytical_detector"
|
| 50 |
+
needs_intermediates = False
|
| 51 |
+
|
| 52 |
+
def __init__(self, feat_dim=768, num_classes=NUM_CLASSES, n_scales=3):
|
| 53 |
+
super().__init__()
|
| 54 |
+
self.n_scales = n_scales
|
| 55 |
+
self.scale_norms = nn.ModuleList([nn.LayerNorm(feat_dim) for _ in range(n_scales)])
|
| 56 |
+
# Direct linear: no hidden layer, no nonlinearity
|
| 57 |
+
self.cls_weight = nn.Parameter(torch.randn(num_classes, feat_dim) * 0.01)
|
| 58 |
+
self.cls_bias = nn.Parameter(torch.zeros(num_classes))
|
| 59 |
+
self.reg_out = nn.Linear(feat_dim, 4)
|
| 60 |
+
self.ctr_weight = nn.Parameter(torch.randn(1, feat_dim) * 0.01)
|
| 61 |
+
self.ctr_bias = nn.Parameter(torch.zeros(1))
|
| 62 |
+
self.scale_params = nn.Parameter(torch.ones(n_scales))
|
| 63 |
+
|
| 64 |
+
def forward(self, spatial, inter=None):
|
| 65 |
+
cofibers = cofiber_decompose(spatial, self.n_scales)
|
| 66 |
+
cls_l, reg_l, ctr_l = [], [], []
|
| 67 |
+
for i, cof in enumerate(cofibers):
|
| 68 |
+
B, C, H, W = cof.shape
|
| 69 |
+
f = self.scale_norms[i](cof.permute(0, 2, 3, 1).reshape(-1, C))
|
| 70 |
+
cls = (f @ self.cls_weight.T + self.cls_bias).reshape(B, H, W, -1).permute(0, 3, 1, 2)
|
| 71 |
+
reg_raw = (self.reg_out(f) * self.scale_params[i]).clamp(-10, 10)
|
| 72 |
+
reg = torch.exp(reg_raw).reshape(B, H, W, 4).permute(0, 3, 1, 2)
|
| 73 |
+
ctr = (f @ self.ctr_weight.T + self.ctr_bias).reshape(B, H, W, 1).permute(0, 3, 1, 2)
|
| 74 |
+
cls_l.append(cls)
|
| 75 |
+
reg_l.append(reg)
|
| 76 |
+
ctr_l.append(ctr)
|
| 77 |
+
return cls_l, reg_l, ctr_l
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def construct_analytical_head(cache_dir, n_images=20000, lam=1e-3, resolution=640):
|
| 81 |
+
"""Construct all weights from closed-form least-squares. Zero training."""
|
| 82 |
+
from analytical_head import accumulate_statistics, solve_head
|
| 83 |
+
stats = accumulate_statistics(cache_dir, n_images, lam, resolution)
|
| 84 |
+
return solve_head(stats)
|
analytical/analytical_h1/analytical_h1_best.pth
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f0300acdc7dc6b5524b03f6ee56971286bae77efd8610a48cec28422dbbcacbe
|
| 3 |
+
size 309581
|
analytical/analytical_h1/eval.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"head": "analytical_h1_best",
|
| 3 |
+
"params": 76120,
|
| 4 |
+
"training": "zero (closed-form least-squares)",
|
| 5 |
+
"n_images": 5000,
|
| 6 |
+
"mAP_0.5_0.95": 0.01162068472530145,
|
| 7 |
+
"mAP_0.50": 0.04322769269795811,
|
| 8 |
+
"mAP_0.75": 0.0027664001981709914,
|
| 9 |
+
"mAP_small": 0.0016777775312599376,
|
| 10 |
+
"mAP_medium": 0.015140164702089317,
|
| 11 |
+
"mAP_large": 0.021564585796647318
|
| 12 |
+
}
|
analytical/scripts/analytical_best_gpu.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Build the best analytical head from our findings and run full mAP eval.
|
| 3 |
+
|
| 4 |
+
Classification: 768 raw LayerNorm'd features (69.6% accuracy)
|
| 5 |
+
Regression: 768 raw + H^1 vertical + H^1 horizontal boundary features (68.7% quality)
|
| 6 |
+
Centerness: 768 raw features
|
| 7 |
+
|
| 8 |
+
Accumulate on training data, solve, save checkpoint, eval via eval_coco_map.py.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import json
|
| 12 |
+
import os
|
| 13 |
+
import sys
|
| 14 |
+
import time
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
import torch.nn.functional as F
|
| 18 |
+
|
| 19 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 20 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 21 |
+
|
| 22 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR", "feature_cache")
|
| 23 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT", "coco")
|
| 24 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE", "val_cache/val.pt")
|
| 25 |
+
RESOLUTION = 640
|
| 26 |
+
NUM_CLASSES = 80
|
| 27 |
+
DEVICE = "cuda"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def cofiber_decompose(f, n_scales):
|
| 31 |
+
cofibers = []
|
| 32 |
+
residual = f
|
| 33 |
+
for _ in range(n_scales - 1):
|
| 34 |
+
omega = F.avg_pool2d(residual, 2)
|
| 35 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 36 |
+
cofibers.append(residual - sigma_omega)
|
| 37 |
+
residual = omega
|
| 38 |
+
cofibers.append(residual)
|
| 39 |
+
return cofibers
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def make_locations(sizes, strides):
|
| 43 |
+
locs = []
|
| 44 |
+
for (h, w), s in zip(sizes, strides):
|
| 45 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 46 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 47 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 48 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 49 |
+
return locs
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 53 |
+
n = loc.shape[0]
|
| 54 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 55 |
+
rt = torch.zeros(n, 4)
|
| 56 |
+
ctrt = torch.zeros(n)
|
| 57 |
+
if boxes.numel() == 0:
|
| 58 |
+
return ct, rt, ctrt
|
| 59 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 60 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 61 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 62 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 63 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 64 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 65 |
+
in_box = ltrb.min(-1).values > 0
|
| 66 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 67 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 68 |
+
rad = stride * 1.5
|
| 69 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 70 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 71 |
+
max_d = ltrb.max(-1).values
|
| 72 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 73 |
+
pos = in_box & in_center & in_level
|
| 74 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 75 |
+
a[~pos] = float("inf")
|
| 76 |
+
matched = a.argmin(1)
|
| 77 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 78 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 79 |
+
if is_pos.any():
|
| 80 |
+
rt[is_pos] = ltrb[torch.arange(n)[is_pos], matched[is_pos]]
|
| 81 |
+
lp, tp, rp, bp = rt[is_pos].unbind(-1)
|
| 82 |
+
ctrt[is_pos] = torch.sqrt(
|
| 83 |
+
(torch.minimum(lp, rp) / torch.maximum(lp, rp).clamp(min=1e-6)) *
|
| 84 |
+
(torch.minimum(tp, bp) / torch.maximum(tp, bp).clamp(min=1e-6)))
|
| 85 |
+
return ct, rt, ctrt
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def compute_h1(f, B, H, W, C):
|
| 89 |
+
"""Sheaf H^1 compact: vertical + horizontal boundary magnitudes."""
|
| 90 |
+
f_4d = f.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 91 |
+
d_up = f_4d - F.pad(f_4d[:, :, 1:, :], (0, 0, 0, 1))
|
| 92 |
+
d_down = f_4d - F.pad(f_4d[:, :, :-1, :], (0, 0, 1, 0))
|
| 93 |
+
d_left = f_4d - F.pad(f_4d[:, :, :, 1:], (0, 1, 0, 0))
|
| 94 |
+
d_right = f_4d - F.pad(f_4d[:, :, :, :-1], (1, 0, 0, 0))
|
| 95 |
+
v_bound = (d_up.abs() + d_down.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 96 |
+
h_bound = (d_left.abs() + d_right.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 97 |
+
return v_bound, h_bound
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def main():
|
| 101 |
+
print("=" * 60)
|
| 102 |
+
print("Best Analytical Head: 768 cls + H^1 regression")
|
| 103 |
+
print("=" * 60, flush=True)
|
| 104 |
+
|
| 105 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 106 |
+
n_shards = manifest["n_shards"]
|
| 107 |
+
strides = [16, 32, 64]
|
| 108 |
+
H = RESOLUTION // 16
|
| 109 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 110 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 111 |
+
locs = make_locations(sizes, strides)
|
| 112 |
+
|
| 113 |
+
feat_dim = 768
|
| 114 |
+
reg_dim = 768 * 3 # raw + h1v + h1h
|
| 115 |
+
|
| 116 |
+
# Accumulators
|
| 117 |
+
cls_XtX = torch.zeros(feat_dim + 1, feat_dim + 1, device=DEVICE)
|
| 118 |
+
cls_XtY = torch.zeros(feat_dim + 1, NUM_CLASSES, device=DEVICE)
|
| 119 |
+
reg_XtX = torch.zeros(reg_dim + 1, reg_dim + 1, device=DEVICE)
|
| 120 |
+
reg_XtY = torch.zeros(reg_dim + 1, 4, device=DEVICE)
|
| 121 |
+
ctr_XtX = torch.zeros(feat_dim + 1, feat_dim + 1, device=DEVICE)
|
| 122 |
+
ctr_XtY = torch.zeros(feat_dim + 1, 1, device=DEVICE)
|
| 123 |
+
n_pos = 0
|
| 124 |
+
n_images = 20000
|
| 125 |
+
seen = 0
|
| 126 |
+
t0 = time.time()
|
| 127 |
+
|
| 128 |
+
for si in range(n_shards):
|
| 129 |
+
if seen >= n_images:
|
| 130 |
+
break
|
| 131 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 132 |
+
map_location="cpu", weights_only=False)
|
| 133 |
+
for item in shard:
|
| 134 |
+
if seen >= n_images:
|
| 135 |
+
break
|
| 136 |
+
sp = item["spatial"].unsqueeze(0).float()
|
| 137 |
+
boxes = item["boxes"]
|
| 138 |
+
labels = item["labels"]
|
| 139 |
+
cofibers = cofiber_decompose(sp, 3)
|
| 140 |
+
for sci, cof in enumerate(cofibers):
|
| 141 |
+
B, C, Hc, Wc = cof.shape
|
| 142 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 143 |
+
h1v, h1h = compute_h1(f, B, Hc, Wc, C)
|
| 144 |
+
ct, rt, ctrt = assign_targets(locs[sci], boxes, labels, strides[sci], sr[sci])
|
| 145 |
+
pos_mask = ct >= 0
|
| 146 |
+
if not pos_mask.any():
|
| 147 |
+
continue
|
| 148 |
+
|
| 149 |
+
# Classification: raw features only
|
| 150 |
+
fp = f[pos_mask].to(DEVICE)
|
| 151 |
+
fa = torch.cat([fp, torch.ones(fp.shape[0], 1, device=DEVICE)], 1)
|
| 152 |
+
yc = torch.zeros(fp.shape[0], NUM_CLASSES, device=DEVICE)
|
| 153 |
+
yc[torch.arange(fp.shape[0], device=DEVICE), ct[pos_mask].to(DEVICE)] = 1.0
|
| 154 |
+
cls_XtX += fa.T @ fa
|
| 155 |
+
cls_XtY += fa.T @ yc
|
| 156 |
+
|
| 157 |
+
# Regression: raw + H^1
|
| 158 |
+
f_reg = torch.cat([f[pos_mask], h1v[pos_mask], h1h[pos_mask]], 1).to(DEVICE)
|
| 159 |
+
ltrb = rt[pos_mask]
|
| 160 |
+
valid = (ltrb > 0).all(1)
|
| 161 |
+
if valid.any():
|
| 162 |
+
fv = f_reg[valid]
|
| 163 |
+
fva = torch.cat([fv, torch.ones(fv.shape[0], 1, device=DEVICE)], 1)
|
| 164 |
+
yt = torch.log(ltrb[valid]).to(DEVICE)
|
| 165 |
+
reg_XtX += fva.T @ fva
|
| 166 |
+
reg_XtY += fva.T @ yt
|
| 167 |
+
|
| 168 |
+
# Centerness: raw features
|
| 169 |
+
ctr_XtX += fa.T @ fa
|
| 170 |
+
ctr_XtY += fa.T @ ctrt[pos_mask].unsqueeze(1).to(DEVICE)
|
| 171 |
+
|
| 172 |
+
n_pos += pos_mask.sum().item()
|
| 173 |
+
seen += 1
|
| 174 |
+
del shard
|
| 175 |
+
if (si + 1) % 5 == 0:
|
| 176 |
+
print(f" shard {si+1}: {seen} imgs, {n_pos} pos, {time.time()-t0:.0f}s", flush=True)
|
| 177 |
+
|
| 178 |
+
print(f"\nAccumulated {seen} images, {n_pos} positives", flush=True)
|
| 179 |
+
|
| 180 |
+
# Solve
|
| 181 |
+
lam = 0.1
|
| 182 |
+
I_cls = torch.eye(feat_dim + 1, device=DEVICE)
|
| 183 |
+
I_reg = torch.eye(reg_dim + 1, device=DEVICE)
|
| 184 |
+
I_ctr = torch.eye(feat_dim + 1, device=DEVICE)
|
| 185 |
+
|
| 186 |
+
cls_W = torch.linalg.solve(cls_XtX + lam * I_cls * n_pos, cls_XtY)
|
| 187 |
+
reg_W = torch.linalg.solve(reg_XtX + lam * I_reg * n_pos, reg_XtY)
|
| 188 |
+
ctr_W = torch.linalg.solve(ctr_XtX + lam * I_ctr * n_pos, ctr_XtY)
|
| 189 |
+
|
| 190 |
+
print(f"Solved. cls: {feat_dim}->80, reg: {reg_dim}->4, ctr: {feat_dim}->1", flush=True)
|
| 191 |
+
|
| 192 |
+
# Save as state dict
|
| 193 |
+
state = {
|
| 194 |
+
"cls_weight": cls_W[:feat_dim].T.cpu(),
|
| 195 |
+
"cls_bias": cls_W[feat_dim].cpu(),
|
| 196 |
+
"reg_weight": reg_W[:reg_dim].T.cpu(),
|
| 197 |
+
"reg_bias": reg_W[reg_dim].cpu(),
|
| 198 |
+
"ctr_weight": ctr_W[:feat_dim].T.cpu(),
|
| 199 |
+
"ctr_bias": ctr_W[feat_dim].cpu(),
|
| 200 |
+
"scale_norms.0.weight": torch.ones(768),
|
| 201 |
+
"scale_norms.0.bias": torch.zeros(768),
|
| 202 |
+
"scale_norms.1.weight": torch.ones(768),
|
| 203 |
+
"scale_norms.1.bias": torch.zeros(768),
|
| 204 |
+
"scale_norms.2.weight": torch.ones(768),
|
| 205 |
+
"scale_norms.2.bias": torch.zeros(768),
|
| 206 |
+
"scale_params": torch.ones(3),
|
| 207 |
+
"meta": {"cls_features": "768_layernorm",
|
| 208 |
+
"reg_features": "768_layernorm_h1v_h1h",
|
| 209 |
+
"ctr_features": "768_layernorm",
|
| 210 |
+
"lambda": lam, "n_images": seen, "n_pos": n_pos},
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
out_dir = os.path.join(SCRIPT_DIR, "heads", "cofiber_threshold", "analytical_h1")
|
| 214 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 215 |
+
out_path = os.path.join(out_dir, "analytical_h1_best.pth")
|
| 216 |
+
torch.save(state, out_path)
|
| 217 |
+
|
| 218 |
+
n_params = sum(v.numel() for k, v in state.items() if isinstance(v, torch.Tensor))
|
| 219 |
+
elapsed = time.time() - t0
|
| 220 |
+
print(f"\nSaved: {out_path}")
|
| 221 |
+
print(f"Total params: {n_params:,}")
|
| 222 |
+
print(f"Construction time: {elapsed:.0f}s")
|
| 223 |
+
print(f"\nClassification: 768 dims, {feat_dim * NUM_CLASSES + NUM_CLASSES:,} params")
|
| 224 |
+
print(f"Regression: {reg_dim} dims (768+768+768), {reg_dim * 4 + 4:,} params")
|
| 225 |
+
print(f"Centerness: 768 dims, {feat_dim + 1:,} params")
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
if __name__ == "__main__":
|
| 229 |
+
main()
|
analytical/scripts/analytical_empbayes.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Empirical Bayes analytical detection head.
|
| 3 |
+
|
| 4 |
+
Bayesian linear regression: W ~ N(0, tau^2 I), Y|X,W ~ N(XW, sigma^2 I)
|
| 5 |
+
The optimal regularization is lambda = sigma^2 / tau^2.
|
| 6 |
+
|
| 7 |
+
Empirical Bayes estimates sigma^2 and tau^2 from the data by maximizing
|
| 8 |
+
the log marginal likelihood (type-II ML):
|
| 9 |
+
|
| 10 |
+
log p(Y|X, sigma^2, tau^2) = -n/2 log(2pi) - 1/2 log|sigma^2 I + tau^2 X X^T|
|
| 11 |
+
- 1/2 Y^T (sigma^2 I + tau^2 X X^T)^{-1} Y
|
| 12 |
+
|
| 13 |
+
Using the SVD of X = U S V^T, this simplifies to operations on the singular values.
|
| 14 |
+
The optimization alternates between updating sigma^2 and tau^2.
|
| 15 |
+
|
| 16 |
+
This gives a principled, per-task lambda with calibrated uncertainty.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
import json, os, sys, time
|
| 20 |
+
import torch
|
| 21 |
+
import torch.nn.functional as F
|
| 22 |
+
|
| 23 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 24 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR")
|
| 25 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT")
|
| 26 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE")
|
| 27 |
+
DEVICE = "cuda"
|
| 28 |
+
RESOLUTION = 640
|
| 29 |
+
NUM_CLASSES = 80
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def cofiber_decompose(f, n_scales):
|
| 33 |
+
cofibers = []; residual = f
|
| 34 |
+
for _ in range(n_scales - 1):
|
| 35 |
+
omega = F.avg_pool2d(residual, 2)
|
| 36 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 37 |
+
cofibers.append(residual - sigma_omega); residual = omega
|
| 38 |
+
cofibers.append(residual); return cofibers
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def make_locations(sizes, strides, device="cpu"):
|
| 42 |
+
locs = []
|
| 43 |
+
for (h, w), s in zip(sizes, strides):
|
| 44 |
+
ys = (torch.arange(h, device=device, dtype=torch.float32) + 0.5) * s
|
| 45 |
+
xs = (torch.arange(w, device=device, dtype=torch.float32) + 0.5) * s
|
| 46 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 47 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 48 |
+
return locs
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 52 |
+
n = loc.shape[0]
|
| 53 |
+
ct = torch.full((n,), -1, dtype=torch.long); rt = torch.zeros(n, 4); ctrt = torch.zeros(n)
|
| 54 |
+
if boxes.numel() == 0: return ct, rt, ctrt
|
| 55 |
+
areas = (boxes[:,2]-boxes[:,0])*(boxes[:,3]-boxes[:,1])
|
| 56 |
+
l=loc[:,None,0]-boxes[None,:,0]; t=loc[:,None,1]-boxes[None,:,1]
|
| 57 |
+
r=boxes[None,:,2]-loc[:,None,0]; b=boxes[None,:,3]-loc[:,None,1]
|
| 58 |
+
ltrb=torch.stack([l,t,r,b],-1); in_box=ltrb.min(-1).values>0
|
| 59 |
+
cx=(boxes[:,0]+boxes[:,2])/2; cy=(boxes[:,1]+boxes[:,3])/2; rad=stride*1.5
|
| 60 |
+
in_center=((loc[:,None,0]>=cx-rad)&(loc[:,None,0]<=cx+rad)&(loc[:,None,1]>=cy-rad)&(loc[:,None,1]<=cy+rad))
|
| 61 |
+
max_d=ltrb.max(-1).values; in_level=(max_d>=sr[0])&(max_d<=sr[1])
|
| 62 |
+
pos=in_box&in_center&in_level; a=areas[None,:].expand_as(pos).clone(); a[~pos]=float("inf")
|
| 63 |
+
matched=a.argmin(1); is_pos=a.gather(1,matched[:,None]).squeeze(1)<float("inf")
|
| 64 |
+
ct[is_pos]=labels[matched[is_pos]]
|
| 65 |
+
if is_pos.any():
|
| 66 |
+
rt[is_pos]=ltrb[torch.arange(n)[is_pos],matched[is_pos]]
|
| 67 |
+
lp,tp,rp,bp=rt[is_pos].unbind(-1)
|
| 68 |
+
ctrt[is_pos]=torch.sqrt((torch.minimum(lp,rp)/torch.maximum(lp,rp).clamp(min=1e-6))*(torch.minimum(tp,bp)/torch.maximum(tp,bp).clamp(min=1e-6)))
|
| 69 |
+
return ct, rt, ctrt
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def empirical_bayes_lambda(XtX, XtY, n_samples, n_iters=50):
|
| 73 |
+
"""Estimate optimal lambda = sigma^2/tau^2 via empirical Bayes.
|
| 74 |
+
|
| 75 |
+
Uses the eigendecomposition of XtX to iteratively estimate:
|
| 76 |
+
tau^2 = (1/d) sum_i (gamma_i * w_i^2) where gamma_i = s_i^2 / (s_i^2 + lambda)
|
| 77 |
+
sigma^2 = (1/(n - sum gamma_i)) * ||Y - X W||^2
|
| 78 |
+
|
| 79 |
+
gamma_i is the "effective number of well-determined parameters" (Mackay).
|
| 80 |
+
"""
|
| 81 |
+
d = XtX.shape[0]
|
| 82 |
+
k = XtY.shape[1] # number of output dims
|
| 83 |
+
|
| 84 |
+
# Eigendecompose XtX
|
| 85 |
+
eigvals, eigvecs = torch.linalg.eigh(XtX)
|
| 86 |
+
eigvals = eigvals.clamp(min=1e-10)
|
| 87 |
+
|
| 88 |
+
# Project targets into eigenspace
|
| 89 |
+
VtXtY = eigvecs.T @ XtY # (d, k)
|
| 90 |
+
|
| 91 |
+
# Initialize
|
| 92 |
+
alpha = 1.0 # 1/tau^2
|
| 93 |
+
beta = 1.0 # 1/sigma^2
|
| 94 |
+
lam = alpha / beta
|
| 95 |
+
|
| 96 |
+
for it in range(n_iters):
|
| 97 |
+
# Effective parameters per eigenvalue
|
| 98 |
+
gamma = eigvals / (eigvals + lam)
|
| 99 |
+
gamma_sum = gamma.sum().item()
|
| 100 |
+
|
| 101 |
+
# Solve with current lambda
|
| 102 |
+
W = eigvecs @ (VtXtY / (eigvals + lam).unsqueeze(1))
|
| 103 |
+
|
| 104 |
+
# Residual sum of squares (averaged over output dims)
|
| 105 |
+
# ||Y - XW||^2 = ||Y||^2 - 2 W^T X^T Y + W^T X^T X W
|
| 106 |
+
# = YtY - 2 W^T XtY + W^T XtX W
|
| 107 |
+
# But we don't have YtY. Approximate from XtY and XtX.
|
| 108 |
+
# W^T XtY = sum of VtXtY_i^2 * s_i / (s_i + lam)
|
| 109 |
+
WtXtY = (VtXtY ** 2 * eigvals.unsqueeze(1) / (eigvals + lam).unsqueeze(1) ** 2).sum(0)
|
| 110 |
+
|
| 111 |
+
# Update alpha (1/tau^2): alpha = gamma_sum / (W^T W)
|
| 112 |
+
WtW = (W ** 2).sum(0).mean().item()
|
| 113 |
+
if WtW > 1e-12:
|
| 114 |
+
alpha = gamma_sum / (d * WtW)
|
| 115 |
+
else:
|
| 116 |
+
alpha = 1e6
|
| 117 |
+
|
| 118 |
+
# Update beta (1/sigma^2) using effective degrees of freedom
|
| 119 |
+
# beta = (n - gamma_sum) / RSS
|
| 120 |
+
# Approximate RSS from the eigenspace
|
| 121 |
+
rss = (VtXtY ** 2 * lam ** 2 / (eigvals + lam).unsqueeze(1) ** 2).sum().item() / k
|
| 122 |
+
dof = max(n_samples - gamma_sum, 1.0)
|
| 123 |
+
if rss > 1e-12:
|
| 124 |
+
beta = dof / rss
|
| 125 |
+
else:
|
| 126 |
+
beta = 1e6
|
| 127 |
+
|
| 128 |
+
lam_new = alpha / beta
|
| 129 |
+
if abs(lam_new - lam) / max(abs(lam), 1e-10) < 1e-6:
|
| 130 |
+
lam = lam_new
|
| 131 |
+
break
|
| 132 |
+
lam = lam_new
|
| 133 |
+
|
| 134 |
+
return lam, gamma_sum, alpha, beta
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def main():
|
| 138 |
+
print("=" * 60)
|
| 139 |
+
print("Empirical Bayes Analytical Detection Head")
|
| 140 |
+
print("=" * 60, flush=True)
|
| 141 |
+
|
| 142 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 143 |
+
strides = [16, 32, 64]; H = RESOLUTION // 16
|
| 144 |
+
sizes = [(H,H),(H//2,H//2),(H//4,H//4)]
|
| 145 |
+
sr = [(-1,128),(128,256),(256,float("inf"))]
|
| 146 |
+
locs = make_locations(sizes, strides)
|
| 147 |
+
feat_dim = 768
|
| 148 |
+
|
| 149 |
+
cls_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 150 |
+
cls_XtY = torch.zeros(feat_dim+1, NUM_CLASSES, device=DEVICE)
|
| 151 |
+
reg_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 152 |
+
reg_XtY = torch.zeros(feat_dim+1, 4, device=DEVICE)
|
| 153 |
+
ctr_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 154 |
+
ctr_XtY = torch.zeros(feat_dim+1, 1, device=DEVICE)
|
| 155 |
+
n_cls=0; n_reg=0; n_ctr=0; seen=0; n_images=20000
|
| 156 |
+
t0 = time.time()
|
| 157 |
+
|
| 158 |
+
for si in range(manifest["n_shards"]):
|
| 159 |
+
if seen >= n_images: break
|
| 160 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 161 |
+
map_location="cpu", weights_only=False)
|
| 162 |
+
for item in shard:
|
| 163 |
+
if seen >= n_images: break
|
| 164 |
+
sp = item["spatial"].unsqueeze(0).float()
|
| 165 |
+
boxes = item["boxes"]; labels = item["labels"]
|
| 166 |
+
cofibers = cofiber_decompose(sp, 3)
|
| 167 |
+
for sci, cof in enumerate(cofibers):
|
| 168 |
+
B,C,Hc,Wc = cof.shape
|
| 169 |
+
f = F.layer_norm(cof.permute(0,2,3,1).reshape(-1,C), [C]).to(DEVICE)
|
| 170 |
+
ct, rt, ctrt = assign_targets(locs[sci], boxes, labels, strides[sci], sr[sci])
|
| 171 |
+
pos = ct >= 0
|
| 172 |
+
if not pos.any(): continue
|
| 173 |
+
fp = f[pos]
|
| 174 |
+
fa = torch.cat([fp, torch.ones(fp.shape[0],1,device=DEVICE)], 1)
|
| 175 |
+
yc = torch.zeros(fp.shape[0], NUM_CLASSES, device=DEVICE)
|
| 176 |
+
yc[torch.arange(fp.shape[0],device=DEVICE), ct[pos].to(DEVICE)] = 1.0
|
| 177 |
+
cls_XtX += fa.T @ fa; cls_XtY += fa.T @ yc; n_cls += fp.shape[0]
|
| 178 |
+
ltrb = rt[pos]; valid = (ltrb > 0).all(1)
|
| 179 |
+
if valid.any():
|
| 180 |
+
fv = fa[valid]; yt = torch.log(ltrb[valid]).to(DEVICE)
|
| 181 |
+
reg_XtX += fv.T @ fv; reg_XtY += fv.T @ yt; n_reg += valid.sum().item()
|
| 182 |
+
ctr_XtX += fa.T @ fa
|
| 183 |
+
ctr_XtY += fa.T @ ctrt[pos].unsqueeze(1).to(DEVICE); n_ctr += fp.shape[0]
|
| 184 |
+
seen += 1
|
| 185 |
+
del shard
|
| 186 |
+
if (si+1) % 5 == 0:
|
| 187 |
+
print(f" shard {si+1}: {seen} imgs, {n_cls} cls, {time.time()-t0:.0f}s", flush=True)
|
| 188 |
+
|
| 189 |
+
print(f"\nAccumulated: {n_cls} cls, {n_reg} reg, {n_ctr} ctr", flush=True)
|
| 190 |
+
|
| 191 |
+
# Empirical Bayes per task
|
| 192 |
+
print("\nEstimating per-task lambda via empirical Bayes...", flush=True)
|
| 193 |
+
t1 = time.time()
|
| 194 |
+
lam_cls, gamma_cls, alpha_cls, beta_cls = empirical_bayes_lambda(cls_XtX, cls_XtY, n_cls)
|
| 195 |
+
lam_reg, gamma_reg, alpha_reg, beta_reg = empirical_bayes_lambda(reg_XtX, reg_XtY, n_reg)
|
| 196 |
+
lam_ctr, gamma_ctr, alpha_ctr, beta_ctr = empirical_bayes_lambda(ctr_XtX, ctr_XtY, n_ctr)
|
| 197 |
+
print(f" cls: lambda={lam_cls:.6f} (gamma={gamma_cls:.1f} effective params, alpha={alpha_cls:.4f}, beta={beta_cls:.4f})")
|
| 198 |
+
print(f" reg: lambda={lam_reg:.6f} (gamma={gamma_reg:.1f} effective params, alpha={alpha_reg:.4f}, beta={beta_reg:.4f})")
|
| 199 |
+
print(f" ctr: lambda={lam_ctr:.6f} (gamma={gamma_ctr:.1f} effective params, alpha={alpha_ctr:.4f}, beta={beta_ctr:.4f})")
|
| 200 |
+
print(f" (took {time.time()-t1:.1f}s)", flush=True)
|
| 201 |
+
|
| 202 |
+
# Solve with EB lambdas
|
| 203 |
+
I = torch.eye(feat_dim+1, device=DEVICE)
|
| 204 |
+
print("\nSolving with empirical Bayes lambdas...", flush=True)
|
| 205 |
+
cls_W_eb = torch.linalg.solve(cls_XtX + lam_cls * I, cls_XtY)
|
| 206 |
+
reg_W_eb = torch.linalg.solve(reg_XtX + lam_reg * I, reg_XtY)
|
| 207 |
+
ctr_W_eb = torch.linalg.solve(ctr_XtX + lam_ctr * I, ctr_XtY)
|
| 208 |
+
|
| 209 |
+
# Also solve with our known-good lambda=0.1*n for comparison
|
| 210 |
+
print("Solving with lambda=0.1*n (previous best)...", flush=True)
|
| 211 |
+
cls_W_fix = torch.linalg.solve(cls_XtX + 0.1 * I * n_cls, cls_XtY)
|
| 212 |
+
reg_W_fix = torch.linalg.solve(reg_XtX + 0.1 * I * n_reg, reg_XtY)
|
| 213 |
+
ctr_W_fix = torch.linalg.solve(ctr_XtX + 0.1 * I * n_ctr, ctr_XtY)
|
| 214 |
+
|
| 215 |
+
# Eval both
|
| 216 |
+
val = torch.load(VAL_CACHE, map_location="cpu", weights_only=False)
|
| 217 |
+
from pycocotools.coco import COCO
|
| 218 |
+
from pycocotools.cocoeval import COCOeval
|
| 219 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 220 |
+
coco_gt = COCO(ann_file)
|
| 221 |
+
cat_ids = sorted(coco_gt.getCatIds())
|
| 222 |
+
idx_to_cat = {i: c for i, c in enumerate(cat_ids)}
|
| 223 |
+
all_locs = torch.cat(make_locations(sizes, strides, DEVICE))
|
| 224 |
+
|
| 225 |
+
for label, cls_W, reg_W, ctr_W in [("empirical_bayes", cls_W_eb, reg_W_eb, ctr_W_eb),
|
| 226 |
+
("fixed_0.1n", cls_W_fix, reg_W_fix, ctr_W_fix)]:
|
| 227 |
+
print(f"\nEvaluating: {label}", flush=True)
|
| 228 |
+
all_results = []
|
| 229 |
+
for idx in range(len(val)):
|
| 230 |
+
item = val[idx]
|
| 231 |
+
spatial = item["spatial"].unsqueeze(0).float().to(DEVICE)
|
| 232 |
+
img_id = int(item["img_id"]); scale = item["scale"]
|
| 233 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 234 |
+
cls_all, reg_all, ctr_all = [], [], []
|
| 235 |
+
for cof in cofibers:
|
| 236 |
+
B,C,Hc,Wc = cof.shape
|
| 237 |
+
f = F.layer_norm(cof.permute(0,2,3,1).reshape(-1,C), [C])
|
| 238 |
+
fa = torch.cat([f, torch.ones(f.shape[0],1,device=DEVICE)], 1)
|
| 239 |
+
cls = (fa @ cls_W).sigmoid()
|
| 240 |
+
reg = (fa @ reg_W).exp()
|
| 241 |
+
ctr = (fa @ ctr_W).sigmoid()
|
| 242 |
+
cls_all.append(cls); reg_all.append(reg); ctr_all.append(ctr.squeeze(1))
|
| 243 |
+
cls_s = torch.cat(cls_all); reg_s = torch.cat(reg_all); ctr_s = torch.cat(ctr_all)
|
| 244 |
+
scores = cls_s * ctr_s.unsqueeze(1)
|
| 245 |
+
max_s, max_c = scores.max(1)
|
| 246 |
+
topk = min(100, max_s.shape[0])
|
| 247 |
+
top_s, top_i = max_s.topk(topk)
|
| 248 |
+
tc = max_c[top_i]; tr = reg_s[top_i]; tl = all_locs[top_i]
|
| 249 |
+
x1=(tl[:,0]-tr[:,0])/scale; y1=(tl[:,1]-tr[:,1])/scale
|
| 250 |
+
x2=(tl[:,0]+tr[:,2])/scale; y2=(tl[:,1]+tr[:,3])/scale
|
| 251 |
+
w=(x2-x1).clamp(min=0); h=(y2-y1).clamp(min=0)
|
| 252 |
+
for i in range(topk):
|
| 253 |
+
s = top_s[i].item()
|
| 254 |
+
if s < 0.01: continue
|
| 255 |
+
all_results.append({"image_id": img_id, "category_id": idx_to_cat[tc[i].item()],
|
| 256 |
+
"bbox": [x1[i].item(), y1[i].item(), w[i].item(), h[i].item()],
|
| 257 |
+
"score": s})
|
| 258 |
+
if (idx+1) % 1000 == 0:
|
| 259 |
+
print(f" {idx+1}/{len(val)}", flush=True)
|
| 260 |
+
|
| 261 |
+
if all_results:
|
| 262 |
+
coco_dt = coco_gt.loadRes(all_results)
|
| 263 |
+
coco_eval = COCOeval(coco_gt, coco_dt, "bbox")
|
| 264 |
+
coco_eval.params.imgIds = sorted(coco_gt.getImgIds())[:len(val)]
|
| 265 |
+
coco_eval.evaluate(); coco_eval.accumulate(); coco_eval.summarize()
|
| 266 |
+
print(f"\n {label}: mAP={coco_eval.stats[0]:.4f} mAP50={coco_eval.stats[1]:.4f} mAP75={coco_eval.stats[2]:.4f}")
|
| 267 |
+
else:
|
| 268 |
+
print(f" {label}: no detections")
|
| 269 |
+
|
| 270 |
+
elapsed = time.time() - t0
|
| 271 |
+
print(f"\nTotal: {elapsed:.0f}s")
|
| 272 |
+
print(f"EB lambdas: cls={lam_cls:.4f} reg={lam_reg:.4f} ctr={lam_ctr:.4f}")
|
| 273 |
+
print(f"Fixed: cls={0.1*n_cls:.0f} reg={0.1*n_reg:.0f} ctr={0.1*n_ctr:.0f}")
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
if __name__ == "__main__":
|
| 277 |
+
main()
|
analytical/scripts/analytical_exotic_gpu.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Exotic analytical detection heads on GPU.
|
| 3 |
+
|
| 4 |
+
Track 1: Random projection pursuit — test N random projections, keep the best.
|
| 5 |
+
Track 2: Nonlinear feature expansion — quadratic cross-terms + random Fourier features.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import json
|
| 9 |
+
import os
|
| 10 |
+
import sys
|
| 11 |
+
import time
|
| 12 |
+
|
| 13 |
+
import torch
|
| 14 |
+
import torch.nn.functional as F
|
| 15 |
+
|
| 16 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 17 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 18 |
+
|
| 19 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT", "coco")
|
| 20 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE", "val_cache/val.pt")
|
| 21 |
+
NUM_CLASSES = 80
|
| 22 |
+
DEVICE = "cuda"
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def cofiber_decompose(f, n_scales):
|
| 26 |
+
cofibers = []
|
| 27 |
+
residual = f
|
| 28 |
+
for _ in range(n_scales - 1):
|
| 29 |
+
omega = F.avg_pool2d(residual, 2)
|
| 30 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 31 |
+
cofibers.append(residual - sigma_omega)
|
| 32 |
+
residual = omega
|
| 33 |
+
cofibers.append(residual)
|
| 34 |
+
return cofibers
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def make_locations(sizes, strides):
|
| 38 |
+
locs = []
|
| 39 |
+
for (h, w), s in zip(sizes, strides):
|
| 40 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 41 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 42 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 43 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 44 |
+
return locs
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 48 |
+
n = loc.shape[0]
|
| 49 |
+
if boxes.numel() == 0:
|
| 50 |
+
return torch.full((n,), -1, dtype=torch.long)
|
| 51 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 52 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 53 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 54 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 55 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 56 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 57 |
+
in_box = ltrb.min(-1).values > 0
|
| 58 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 59 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 60 |
+
rad = stride * 1.5
|
| 61 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 62 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 63 |
+
max_d = ltrb.max(-1).values
|
| 64 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 65 |
+
pos = in_box & in_center & in_level
|
| 66 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 67 |
+
a[~pos] = float("inf")
|
| 68 |
+
matched = a.argmin(1)
|
| 69 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 70 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 71 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 72 |
+
return ct
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def build_val_data(val_path, n_images=500):
|
| 76 |
+
val = torch.load(val_path, map_location="cpu", weights_only=False)
|
| 77 |
+
from pycocotools.coco import COCO
|
| 78 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 79 |
+
coco = COCO(ann_file)
|
| 80 |
+
cat_ids = sorted(coco.getCatIds())
|
| 81 |
+
cat_to_idx = {c: i for i, c in enumerate(cat_ids)}
|
| 82 |
+
strides = [16, 32, 64]
|
| 83 |
+
H = 640 // 16
|
| 84 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 85 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 86 |
+
locs = make_locations(sizes, strides)
|
| 87 |
+
all_f, all_cls = [], []
|
| 88 |
+
for idx in range(min(n_images, len(val))):
|
| 89 |
+
item = val[idx]
|
| 90 |
+
spatial = item["spatial"].unsqueeze(0).float()
|
| 91 |
+
img_id = item["img_id"]; scale = item["scale"]
|
| 92 |
+
ann_ids = coco.getAnnIds(imgIds=int(img_id), iscrowd=False)
|
| 93 |
+
anns = coco.loadAnns(ann_ids)
|
| 94 |
+
boxes, labels = [], []
|
| 95 |
+
for ann in anns:
|
| 96 |
+
x, y, w, h = ann["bbox"]
|
| 97 |
+
if w < 1 or h < 1: continue
|
| 98 |
+
boxes.append([x*scale, y*scale, (x+w)*scale, (y+h)*scale])
|
| 99 |
+
labels.append(cat_to_idx[ann["category_id"]])
|
| 100 |
+
boxes_t = torch.tensor(boxes, dtype=torch.float32) if boxes else torch.zeros(0, 4)
|
| 101 |
+
labels_t = torch.tensor(labels, dtype=torch.long) if labels else torch.zeros(0, dtype=torch.long)
|
| 102 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 103 |
+
for sci, cof in enumerate(cofibers):
|
| 104 |
+
B, C, Hc, Wc = cof.shape
|
| 105 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 106 |
+
ct = assign_targets(locs[sci], boxes_t, labels_t, strides[sci], sr[sci])
|
| 107 |
+
all_f.append(f); all_cls.append(ct)
|
| 108 |
+
return torch.cat(all_f).to(DEVICE), torch.cat(all_cls).to(DEVICE)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def solve_and_score(features_pos, y_cls, features_all, cls_targets, pos_mask, lam=0.1):
|
| 112 |
+
"""Solve least-squares and return classification accuracy."""
|
| 113 |
+
fd = features_pos.shape[1]
|
| 114 |
+
fa = torch.cat([features_pos, torch.ones(features_pos.shape[0], 1, device=DEVICE)], 1)
|
| 115 |
+
I = torch.eye(fd + 1, device=DEVICE)
|
| 116 |
+
n = features_pos.shape[0]
|
| 117 |
+
try:
|
| 118 |
+
W = torch.linalg.solve(fa.T @ fa + lam * I * n, fa.T @ y_cls)
|
| 119 |
+
except Exception:
|
| 120 |
+
return 0.0
|
| 121 |
+
scores = features_all @ W[:fd] + W[fd]
|
| 122 |
+
pred = scores.argmax(1)
|
| 123 |
+
correct = (pred[pos_mask] == cls_targets[pos_mask]).sum().item()
|
| 124 |
+
return correct / max(pos_mask.sum().item(), 1)
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def main():
|
| 128 |
+
print("=" * 60)
|
| 129 |
+
print("Exotic Analytical Detection Heads (GPU)")
|
| 130 |
+
print("=" * 60, flush=True)
|
| 131 |
+
|
| 132 |
+
print("Building val data...", flush=True)
|
| 133 |
+
features, cls_targets = build_val_data(VAL_CACHE, 500)
|
| 134 |
+
pos = cls_targets >= 0
|
| 135 |
+
n_pos = pos.sum().item()
|
| 136 |
+
f_pos = features[pos]
|
| 137 |
+
y_cls = torch.zeros(n_pos, NUM_CLASSES, device=DEVICE)
|
| 138 |
+
y_cls[torch.arange(n_pos, device=DEVICE), cls_targets[pos]] = 1.0
|
| 139 |
+
print(f" {features.shape[0]} locations, {n_pos} positives", flush=True)
|
| 140 |
+
|
| 141 |
+
results = []
|
| 142 |
+
|
| 143 |
+
# =====================================================
|
| 144 |
+
# Baseline: full 768 dims
|
| 145 |
+
# =====================================================
|
| 146 |
+
t0 = time.time()
|
| 147 |
+
acc = solve_and_score(f_pos, y_cls, features, cls_targets, pos)
|
| 148 |
+
print(f"\nBaseline (768 dims): acc={acc:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 149 |
+
results.append({"name": "baseline_768", "acc": acc, "dims": 768})
|
| 150 |
+
|
| 151 |
+
# =====================================================
|
| 152 |
+
# Track 1: Random Projection Pursuit
|
| 153 |
+
# =====================================================
|
| 154 |
+
print(f"\n--- Track 1: Random Projection Pursuit ---", flush=True)
|
| 155 |
+
for K in [10, 20, 50, 100, 200]:
|
| 156 |
+
N_PROJ = 500
|
| 157 |
+
best_acc = 0.0
|
| 158 |
+
best_seed = -1
|
| 159 |
+
t0 = time.time()
|
| 160 |
+
for seed in range(N_PROJ):
|
| 161 |
+
torch.manual_seed(seed)
|
| 162 |
+
proj = torch.randn(768, K, device=DEVICE) / (K ** 0.5)
|
| 163 |
+
f_proj = features @ proj
|
| 164 |
+
fp_proj = f_proj[pos]
|
| 165 |
+
acc = solve_and_score(fp_proj, y_cls, f_proj, cls_targets, pos)
|
| 166 |
+
if acc > best_acc:
|
| 167 |
+
best_acc = acc
|
| 168 |
+
best_seed = seed
|
| 169 |
+
elapsed = time.time() - t0
|
| 170 |
+
n_params = K * NUM_CLASSES + NUM_CLASSES
|
| 171 |
+
print(f" K={K:3d}: best_acc={best_acc:.4f} (seed={best_seed}, "
|
| 172 |
+
f"{n_params} params, {elapsed:.1f}s, {N_PROJ} projections)", flush=True)
|
| 173 |
+
results.append({"name": f"random_proj_K{K}", "acc": best_acc,
|
| 174 |
+
"dims": K, "params": n_params, "seed": best_seed})
|
| 175 |
+
|
| 176 |
+
# =====================================================
|
| 177 |
+
# Track 2a: Quadratic expansion on top greedy dims
|
| 178 |
+
# =====================================================
|
| 179 |
+
print(f"\n--- Track 2a: Quadratic Feature Expansion ---", flush=True)
|
| 180 |
+
# Load greedy dims
|
| 181 |
+
greedy_path = os.path.join(SCRIPT_DIR, "analytical_variants", "greedy_forward_gpu.json")
|
| 182 |
+
if os.path.isfile(greedy_path):
|
| 183 |
+
with open(greedy_path) as f:
|
| 184 |
+
greedy = json.load(f)
|
| 185 |
+
greedy_dims = greedy["selected_dims"]
|
| 186 |
+
else:
|
| 187 |
+
greedy_dims = list(range(20))
|
| 188 |
+
|
| 189 |
+
for K in [5, 10, 20, 30]:
|
| 190 |
+
t0 = time.time()
|
| 191 |
+
dims = greedy_dims[:K]
|
| 192 |
+
f_sub = features[:, dims] # (N, K)
|
| 193 |
+
# Quadratic: all pairwise products x_i * x_j (including x_i^2)
|
| 194 |
+
quad_features = []
|
| 195 |
+
for i in range(K):
|
| 196 |
+
for j in range(i, K):
|
| 197 |
+
quad_features.append(f_sub[:, i] * f_sub[:, j])
|
| 198 |
+
f_quad = torch.stack(quad_features, dim=1) # (N, K*(K+1)/2)
|
| 199 |
+
# Concatenate linear + quadratic
|
| 200 |
+
f_expanded = torch.cat([f_sub, f_quad], dim=1)
|
| 201 |
+
n_expanded = f_expanded.shape[1]
|
| 202 |
+
fp_exp = f_expanded[pos]
|
| 203 |
+
acc = solve_and_score(fp_exp, y_cls, f_expanded, cls_targets, pos)
|
| 204 |
+
n_params = n_expanded * NUM_CLASSES + NUM_CLASSES
|
| 205 |
+
elapsed = time.time() - t0
|
| 206 |
+
print(f" top-{K} + quadratic: {n_expanded} dims, acc={acc:.4f} "
|
| 207 |
+
f"({n_params} params, {elapsed:.2f}s)", flush=True)
|
| 208 |
+
results.append({"name": f"quadratic_top{K}", "acc": acc,
|
| 209 |
+
"dims": n_expanded, "params": n_params})
|
| 210 |
+
|
| 211 |
+
# =====================================================
|
| 212 |
+
# Track 2b: Random Fourier Features (RBF kernel approx)
|
| 213 |
+
# =====================================================
|
| 214 |
+
print(f"\n--- Track 2b: Random Fourier Features ---", flush=True)
|
| 215 |
+
for K_rff in [50, 100, 200, 500]:
|
| 216 |
+
t0 = time.time()
|
| 217 |
+
# sigma controls the kernel width — use median heuristic
|
| 218 |
+
# For speed, estimate from a subsample
|
| 219 |
+
sub = features[:5000]
|
| 220 |
+
dists = torch.cdist(sub[:500], sub[:500])
|
| 221 |
+
sigma = dists.median().item()
|
| 222 |
+
if sigma < 1e-6:
|
| 223 |
+
sigma = 1.0
|
| 224 |
+
|
| 225 |
+
torch.manual_seed(42)
|
| 226 |
+
W_rff = torch.randn(768, K_rff, device=DEVICE) / sigma
|
| 227 |
+
b_rff = torch.rand(K_rff, device=DEVICE) * 2 * 3.14159
|
| 228 |
+
|
| 229 |
+
# phi(x) = sqrt(2/K) * cos(Wx + b)
|
| 230 |
+
rff = (2.0 / K_rff) ** 0.5 * torch.cos(features @ W_rff + b_rff)
|
| 231 |
+
|
| 232 |
+
# Concatenate with raw features
|
| 233 |
+
f_combined = torch.cat([features, rff], dim=1)
|
| 234 |
+
fp_comb = f_combined[pos]
|
| 235 |
+
acc = solve_and_score(fp_comb, y_cls, f_combined, cls_targets, pos)
|
| 236 |
+
n_dims = f_combined.shape[1]
|
| 237 |
+
n_params = n_dims * NUM_CLASSES + NUM_CLASSES
|
| 238 |
+
elapsed = time.time() - t0
|
| 239 |
+
print(f" 768 + {K_rff} RFF: {n_dims} dims, acc={acc:.4f} "
|
| 240 |
+
f"({n_params} params, sigma={sigma:.2f}, {elapsed:.2f}s)", flush=True)
|
| 241 |
+
results.append({"name": f"rff_{K_rff}", "acc": acc,
|
| 242 |
+
"dims": n_dims, "params": n_params})
|
| 243 |
+
|
| 244 |
+
# =====================================================
|
| 245 |
+
# Track 2c: Pure RFF (no raw features)
|
| 246 |
+
# =====================================================
|
| 247 |
+
print(f"\n--- Track 2c: Pure Random Fourier Features (no raw) ---", flush=True)
|
| 248 |
+
for K_rff in [200, 500, 1000]:
|
| 249 |
+
t0 = time.time()
|
| 250 |
+
torch.manual_seed(42)
|
| 251 |
+
W_rff = torch.randn(768, K_rff, device=DEVICE) / sigma
|
| 252 |
+
b_rff = torch.rand(K_rff, device=DEVICE) * 2 * 3.14159
|
| 253 |
+
rff = (2.0 / K_rff) ** 0.5 * torch.cos(features @ W_rff + b_rff)
|
| 254 |
+
fp_rff = rff[pos]
|
| 255 |
+
acc = solve_and_score(fp_rff, y_cls, rff, cls_targets, pos)
|
| 256 |
+
n_params = K_rff * NUM_CLASSES + NUM_CLASSES
|
| 257 |
+
elapsed = time.time() - t0
|
| 258 |
+
print(f" {K_rff} pure RFF: acc={acc:.4f} ({n_params} params, {elapsed:.2f}s)", flush=True)
|
| 259 |
+
results.append({"name": f"pure_rff_{K_rff}", "acc": acc,
|
| 260 |
+
"dims": K_rff, "params": n_params})
|
| 261 |
+
|
| 262 |
+
# =====================================================
|
| 263 |
+
# Summary
|
| 264 |
+
# =====================================================
|
| 265 |
+
print(f"\n{'='*60}")
|
| 266 |
+
print("Ranked by accuracy:")
|
| 267 |
+
for r in sorted(results, key=lambda x: -x["acc"]):
|
| 268 |
+
print(f" {r['name']:25s}: acc={r['acc']:.4f} dims={r.get('dims', '?')} "
|
| 269 |
+
f"params={r.get('params', '?')}")
|
| 270 |
+
|
| 271 |
+
out = os.path.join(SCRIPT_DIR, "analytical_variants", "exotic_gpu.json")
|
| 272 |
+
with open(out, "w") as f:
|
| 273 |
+
json.dump(results, f, indent=2)
|
| 274 |
+
print(f"\nSaved: {out}")
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
if __name__ == "__main__":
|
| 278 |
+
main()
|
analytical/scripts/analytical_exotic_reg_gpu.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Exotic regression experiments on GPU.
|
| 3 |
+
|
| 4 |
+
The classification is already at 69.6% with linear features — close to the ceiling.
|
| 5 |
+
The gap between analytical (1.6 mAP) and trained (8.2 mAP) is in REGRESSION.
|
| 6 |
+
Test whether nonlinear feature expansions help the regression solver.
|
| 7 |
+
|
| 8 |
+
Experiments:
|
| 9 |
+
1. Quadratic features for regression only (linear cls stays at 768)
|
| 10 |
+
2. Sheaf H^1 boundary features for regression only
|
| 11 |
+
3. Quadratic + H^1 combined
|
| 12 |
+
4. Full pipeline: best cls + best reg → build complete head → run actual mAP eval
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import os
|
| 17 |
+
import sys
|
| 18 |
+
import time
|
| 19 |
+
|
| 20 |
+
import torch
|
| 21 |
+
import torch.nn.functional as F
|
| 22 |
+
|
| 23 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 24 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 25 |
+
|
| 26 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT", "coco")
|
| 27 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE", "val_cache/val.pt")
|
| 28 |
+
NUM_CLASSES = 80
|
| 29 |
+
DEVICE = "cuda"
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def cofiber_decompose(f, n_scales):
|
| 33 |
+
cofibers = []
|
| 34 |
+
residual = f
|
| 35 |
+
for _ in range(n_scales - 1):
|
| 36 |
+
omega = F.avg_pool2d(residual, 2)
|
| 37 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 38 |
+
cofibers.append(residual - sigma_omega)
|
| 39 |
+
residual = omega
|
| 40 |
+
cofibers.append(residual)
|
| 41 |
+
return cofibers
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def make_locations(sizes, strides):
|
| 45 |
+
locs = []
|
| 46 |
+
for (h, w), s in zip(sizes, strides):
|
| 47 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 48 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 49 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 50 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 51 |
+
return locs
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def assign_targets_full(loc, boxes, labels, stride, sr):
|
| 55 |
+
n = loc.shape[0]
|
| 56 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 57 |
+
rt = torch.zeros(n, 4)
|
| 58 |
+
if boxes.numel() == 0:
|
| 59 |
+
return ct, rt
|
| 60 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 61 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 62 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 63 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 64 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 65 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 66 |
+
in_box = ltrb.min(-1).values > 0
|
| 67 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 68 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 69 |
+
rad = stride * 1.5
|
| 70 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 71 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 72 |
+
max_d = ltrb.max(-1).values
|
| 73 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 74 |
+
pos = in_box & in_center & in_level
|
| 75 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 76 |
+
a[~pos] = float("inf")
|
| 77 |
+
matched = a.argmin(1)
|
| 78 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 79 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 80 |
+
if is_pos.any():
|
| 81 |
+
rt[is_pos] = ltrb[torch.arange(n)[is_pos], matched[is_pos]]
|
| 82 |
+
return ct, rt
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def build_val_data_with_spatial(val_path, n_images=500):
|
| 86 |
+
"""Build features with spatial variants on GPU."""
|
| 87 |
+
val = torch.load(val_path, map_location="cpu", weights_only=False)
|
| 88 |
+
from pycocotools.coco import COCO
|
| 89 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 90 |
+
coco = COCO(ann_file)
|
| 91 |
+
cat_ids = sorted(coco.getCatIds())
|
| 92 |
+
cat_to_idx = {c: i for i, c in enumerate(cat_ids)}
|
| 93 |
+
strides = [16, 32, 64]
|
| 94 |
+
H = 640 // 16
|
| 95 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 96 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 97 |
+
locs = make_locations(sizes, strides)
|
| 98 |
+
|
| 99 |
+
all_f, all_h1v, all_h1h, all_cls, all_reg = [], [], [], [], []
|
| 100 |
+
for idx in range(min(n_images, len(val))):
|
| 101 |
+
item = val[idx]
|
| 102 |
+
spatial = item["spatial"].unsqueeze(0).float()
|
| 103 |
+
img_id = item["img_id"]; scale = item["scale"]
|
| 104 |
+
ann_ids = coco.getAnnIds(imgIds=int(img_id), iscrowd=False)
|
| 105 |
+
anns = coco.loadAnns(ann_ids)
|
| 106 |
+
boxes, labels = [], []
|
| 107 |
+
for ann in anns:
|
| 108 |
+
x, y, w, h = ann["bbox"]
|
| 109 |
+
if w < 1 or h < 1: continue
|
| 110 |
+
boxes.append([x*scale, y*scale, (x+w)*scale, (y+h)*scale])
|
| 111 |
+
labels.append(cat_to_idx[ann["category_id"]])
|
| 112 |
+
boxes_t = torch.tensor(boxes, dtype=torch.float32) if boxes else torch.zeros(0, 4)
|
| 113 |
+
labels_t = torch.tensor(labels, dtype=torch.long) if labels else torch.zeros(0, dtype=torch.long)
|
| 114 |
+
|
| 115 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 116 |
+
for sci, cof in enumerate(cofibers):
|
| 117 |
+
B, C, Hc, Wc = cof.shape
|
| 118 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 119 |
+
|
| 120 |
+
# Sheaf H^1: directional boundary magnitudes
|
| 121 |
+
f_4d = f.reshape(B, Hc, Wc, C).permute(0, 3, 1, 2)
|
| 122 |
+
d_up = f_4d - F.pad(f_4d[:, :, 1:, :], (0, 0, 0, 1))
|
| 123 |
+
d_down = f_4d - F.pad(f_4d[:, :, :-1, :], (0, 0, 1, 0))
|
| 124 |
+
d_left = f_4d - F.pad(f_4d[:, :, :, 1:], (0, 1, 0, 0))
|
| 125 |
+
d_right = f_4d - F.pad(f_4d[:, :, :, :-1], (1, 0, 0, 0))
|
| 126 |
+
v_bound = (d_up.abs() + d_down.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 127 |
+
h_bound = (d_left.abs() + d_right.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 128 |
+
|
| 129 |
+
ct, rt = assign_targets_full(locs[sci], boxes_t, labels_t, strides[sci], sr[sci])
|
| 130 |
+
all_f.append(f)
|
| 131 |
+
all_h1v.append(v_bound)
|
| 132 |
+
all_h1h.append(h_bound)
|
| 133 |
+
all_cls.append(ct)
|
| 134 |
+
all_reg.append(rt)
|
| 135 |
+
|
| 136 |
+
features = torch.cat(all_f).to(DEVICE)
|
| 137 |
+
h1v = torch.cat(all_h1v).to(DEVICE)
|
| 138 |
+
h1h = torch.cat(all_h1h).to(DEVICE)
|
| 139 |
+
cls_targets = torch.cat(all_cls).to(DEVICE)
|
| 140 |
+
reg_targets = torch.cat(all_reg).to(DEVICE)
|
| 141 |
+
return features, h1v, h1h, cls_targets, reg_targets
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def solve_regression(f_pos, y_reg, f_all, reg_targets, pos_mask, lam=0.1):
|
| 145 |
+
"""Solve for regression weights, return quality metric."""
|
| 146 |
+
valid = (y_reg > 0).all(1)
|
| 147 |
+
if valid.sum() < 10:
|
| 148 |
+
return 0.0
|
| 149 |
+
fv = f_pos[valid]
|
| 150 |
+
fa = torch.cat([fv, torch.ones(fv.shape[0], 1, device=DEVICE)], 1)
|
| 151 |
+
yt = torch.log(y_reg[valid]) # log-ltrb
|
| 152 |
+
fd = fv.shape[1]
|
| 153 |
+
I = torch.eye(fd + 1, device=DEVICE)
|
| 154 |
+
n = fv.shape[0]
|
| 155 |
+
try:
|
| 156 |
+
W = torch.linalg.solve(fa.T @ fa + lam * I * n, fa.T @ yt)
|
| 157 |
+
except Exception:
|
| 158 |
+
return 0.0
|
| 159 |
+
|
| 160 |
+
# Quality: 1/(1+MSE) at positive locations
|
| 161 |
+
pred = f_all[pos_mask] @ W[:fd] + W[fd]
|
| 162 |
+
gt_ltrb = reg_targets[pos_mask]
|
| 163 |
+
val2 = (gt_ltrb > 0).all(1)
|
| 164 |
+
if val2.sum() < 10:
|
| 165 |
+
return 0.0
|
| 166 |
+
gt_log = torch.log(gt_ltrb[val2])
|
| 167 |
+
pred_valid = pred[val2]
|
| 168 |
+
mse = ((pred_valid - gt_log) ** 2).mean(1)
|
| 169 |
+
quality = (1.0 / (1.0 + mse)).mean().item()
|
| 170 |
+
return quality
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def main():
|
| 174 |
+
print("=" * 60)
|
| 175 |
+
print("Exotic Regression Experiments (GPU)")
|
| 176 |
+
print("=" * 60, flush=True)
|
| 177 |
+
|
| 178 |
+
features, h1v, h1h, cls_targets, reg_targets = build_val_data_with_spatial(VAL_CACHE, 500)
|
| 179 |
+
pos = cls_targets >= 0
|
| 180 |
+
n_pos = pos.sum().item()
|
| 181 |
+
f_pos = features[pos]
|
| 182 |
+
reg_pos = reg_targets[pos]
|
| 183 |
+
print(f" {features.shape[0]} locations, {n_pos} positives", flush=True)
|
| 184 |
+
|
| 185 |
+
results = []
|
| 186 |
+
|
| 187 |
+
# Load greedy dims
|
| 188 |
+
greedy_path = os.path.join(SCRIPT_DIR, "analytical_variants", "greedy_forward_gpu.json")
|
| 189 |
+
greedy_dims = list(range(20))
|
| 190 |
+
if os.path.isfile(greedy_path):
|
| 191 |
+
with open(greedy_path) as f:
|
| 192 |
+
greedy_dims = json.load(f)["selected_dims"]
|
| 193 |
+
|
| 194 |
+
# =====================================================
|
| 195 |
+
# Baseline regression: 768 raw features
|
| 196 |
+
# =====================================================
|
| 197 |
+
t0 = time.time()
|
| 198 |
+
q = solve_regression(f_pos, reg_pos, features, reg_targets, pos)
|
| 199 |
+
print(f"\n1. Baseline (768 raw): reg_quality={q:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 200 |
+
results.append({"name": "baseline_768", "reg_quality": q, "dims": 768})
|
| 201 |
+
|
| 202 |
+
# =====================================================
|
| 203 |
+
# 2. H^1 boundary features for regression
|
| 204 |
+
# =====================================================
|
| 205 |
+
for label, f_extra in [("h1v", h1v), ("h1h", h1h), ("h1_both", torch.cat([h1v, h1h], 1))]:
|
| 206 |
+
f_combined = torch.cat([features, f_extra], 1)
|
| 207 |
+
fp = f_combined[pos]
|
| 208 |
+
t0 = time.time()
|
| 209 |
+
q = solve_regression(fp, reg_pos, f_combined, reg_targets, pos)
|
| 210 |
+
print(f"2. 768 + {label} ({f_combined.shape[1]} dims): reg_quality={q:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 211 |
+
results.append({"name": f"h1_{label}", "reg_quality": q, "dims": f_combined.shape[1]})
|
| 212 |
+
|
| 213 |
+
# =====================================================
|
| 214 |
+
# 3. Quadratic features for regression
|
| 215 |
+
# =====================================================
|
| 216 |
+
for K in [10, 20, 30]:
|
| 217 |
+
dims = greedy_dims[:K]
|
| 218 |
+
f_sub = features[:, dims]
|
| 219 |
+
quads = []
|
| 220 |
+
for i in range(K):
|
| 221 |
+
for j in range(i, K):
|
| 222 |
+
quads.append(f_sub[:, i] * f_sub[:, j])
|
| 223 |
+
f_quad = torch.stack(quads, 1)
|
| 224 |
+
f_exp = torch.cat([features, f_quad], 1)
|
| 225 |
+
fp = f_exp[pos]
|
| 226 |
+
t0 = time.time()
|
| 227 |
+
q = solve_regression(fp, reg_pos, f_exp, reg_targets, pos)
|
| 228 |
+
nd = f_exp.shape[1]
|
| 229 |
+
print(f"3. 768 + quad_top{K} ({nd} dims): reg_quality={q:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 230 |
+
results.append({"name": f"quad_top{K}", "reg_quality": q, "dims": nd})
|
| 231 |
+
|
| 232 |
+
# =====================================================
|
| 233 |
+
# 4. H^1 + quadratic combined
|
| 234 |
+
# =====================================================
|
| 235 |
+
dims = greedy_dims[:20]
|
| 236 |
+
f_sub = features[:, dims]
|
| 237 |
+
quads = []
|
| 238 |
+
for i in range(20):
|
| 239 |
+
for j in range(i, 20):
|
| 240 |
+
quads.append(f_sub[:, i] * f_sub[:, j])
|
| 241 |
+
f_quad = torch.stack(quads, 1)
|
| 242 |
+
f_all = torch.cat([features, h1v, h1h, f_quad], 1)
|
| 243 |
+
fp = f_all[pos]
|
| 244 |
+
t0 = time.time()
|
| 245 |
+
q = solve_regression(fp, reg_pos, f_all, reg_targets, pos)
|
| 246 |
+
print(f"4. 768 + H1 + quad_top20 ({f_all.shape[1]} dims): reg_quality={q:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 247 |
+
results.append({"name": "h1_quad_combined", "reg_quality": q, "dims": f_all.shape[1]})
|
| 248 |
+
|
| 249 |
+
# =====================================================
|
| 250 |
+
# 5. RFF for regression
|
| 251 |
+
# =====================================================
|
| 252 |
+
sub = features[:5000]
|
| 253 |
+
dists = torch.cdist(sub[:500], sub[:500])
|
| 254 |
+
sigma = dists.median().item()
|
| 255 |
+
if sigma < 1e-6: sigma = 1.0
|
| 256 |
+
|
| 257 |
+
for K_rff in [100, 500]:
|
| 258 |
+
torch.manual_seed(42)
|
| 259 |
+
W_rff = torch.randn(768, K_rff, device=DEVICE) / sigma
|
| 260 |
+
b_rff = torch.rand(K_rff, device=DEVICE) * 2 * 3.14159
|
| 261 |
+
rff = (2.0 / K_rff) ** 0.5 * torch.cos(features @ W_rff + b_rff)
|
| 262 |
+
f_combined = torch.cat([features, rff], 1)
|
| 263 |
+
fp = f_combined[pos]
|
| 264 |
+
t0 = time.time()
|
| 265 |
+
q = solve_regression(fp, reg_pos, f_combined, reg_targets, pos)
|
| 266 |
+
print(f"5. 768 + {K_rff} RFF ({f_combined.shape[1]} dims): reg_quality={q:.4f} [{time.time()-t0:.2f}s]", flush=True)
|
| 267 |
+
results.append({"name": f"rff_{K_rff}_reg", "reg_quality": q, "dims": f_combined.shape[1]})
|
| 268 |
+
|
| 269 |
+
# =====================================================
|
| 270 |
+
# Summary
|
| 271 |
+
# =====================================================
|
| 272 |
+
print(f"\n{'='*60}")
|
| 273 |
+
print("Ranked by regression quality:")
|
| 274 |
+
for r in sorted(results, key=lambda x: -x["reg_quality"]):
|
| 275 |
+
print(f" {r['name']:25s}: reg_quality={r['reg_quality']:.4f} dims={r['dims']}")
|
| 276 |
+
|
| 277 |
+
out = os.path.join(SCRIPT_DIR, "analytical_variants", "exotic_reg_gpu.json")
|
| 278 |
+
with open(out, "w") as f:
|
| 279 |
+
json.dump(results, f, indent=2)
|
| 280 |
+
print(f"\nSaved: {out}")
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
if __name__ == "__main__":
|
| 284 |
+
main()
|
analytical/scripts/analytical_fractal_gpu.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Fractal cofiber decomposition — wavelet packet style.
|
| 3 |
+
|
| 4 |
+
Instead of recursing only on the low-frequency residual (3 bands),
|
| 5 |
+
recurse on BOTH the cofiber and residual at each level.
|
| 6 |
+
|
| 7 |
+
Depth 1: 2 bands (standard single split)
|
| 8 |
+
Depth 2: 4 bands
|
| 9 |
+
Depth 3: 8 bands
|
| 10 |
+
|
| 11 |
+
Each band is 768 dims. Classification and regression are solved independently
|
| 12 |
+
per band, then results are merged. The solver picks which bands matter.
|
| 13 |
+
|
| 14 |
+
Or: concatenate all bands and solve one large system.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import json, os, sys, time
|
| 18 |
+
import torch, torch.nn.functional as F
|
| 19 |
+
|
| 20 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 21 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 22 |
+
|
| 23 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT")
|
| 24 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE")
|
| 25 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR")
|
| 26 |
+
DEVICE = "cuda"
|
| 27 |
+
RESOLUTION = 640
|
| 28 |
+
NUM_CLASSES = 80
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def fractal_decompose(f, depth):
|
| 32 |
+
"""Fractal cofiber decomposition. Returns list of 2^depth feature maps."""
|
| 33 |
+
if depth == 0:
|
| 34 |
+
return [f]
|
| 35 |
+
omega = F.avg_pool2d(f, 2)
|
| 36 |
+
sigma_omega = F.interpolate(omega, size=f.shape[2:], mode="bilinear", align_corners=False)
|
| 37 |
+
cofiber = f - sigma_omega # high frequency at this scale
|
| 38 |
+
|
| 39 |
+
# Recurse on BOTH branches
|
| 40 |
+
high_bands = fractal_decompose(cofiber, depth - 1)
|
| 41 |
+
low_bands = fractal_decompose(omega, depth - 1)
|
| 42 |
+
|
| 43 |
+
return high_bands + low_bands
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def standard_decompose(f, n_scales):
|
| 47 |
+
"""Standard cofiber: recurse only on residual."""
|
| 48 |
+
cofibers = []
|
| 49 |
+
residual = f
|
| 50 |
+
for _ in range(n_scales - 1):
|
| 51 |
+
omega = F.avg_pool2d(residual, 2)
|
| 52 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 53 |
+
cofibers.append(residual - sigma_omega)
|
| 54 |
+
residual = omega
|
| 55 |
+
cofibers.append(residual)
|
| 56 |
+
return cofibers
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def make_locations(sizes, strides):
|
| 60 |
+
locs = []
|
| 61 |
+
for (h, w), s in zip(sizes, strides):
|
| 62 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 63 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 64 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 65 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 66 |
+
return locs
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 70 |
+
n = loc.shape[0]
|
| 71 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 72 |
+
rt = torch.zeros(n, 4)
|
| 73 |
+
ctrt = torch.zeros(n)
|
| 74 |
+
if boxes.numel() == 0:
|
| 75 |
+
return ct, rt, ctrt
|
| 76 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 77 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 78 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 79 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 80 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 81 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 82 |
+
in_box = ltrb.min(-1).values > 0
|
| 83 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 84 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 85 |
+
rad = stride * 1.5
|
| 86 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 87 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 88 |
+
max_d = ltrb.max(-1).values
|
| 89 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 90 |
+
pos = in_box & in_center & in_level
|
| 91 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 92 |
+
a[~pos] = float("inf")
|
| 93 |
+
matched = a.argmin(1)
|
| 94 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 95 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 96 |
+
if is_pos.any():
|
| 97 |
+
rt[is_pos] = ltrb[torch.arange(n)[is_pos], matched[is_pos]]
|
| 98 |
+
lp, tp, rp, bp = rt[is_pos].unbind(-1)
|
| 99 |
+
ctrt[is_pos] = torch.sqrt(
|
| 100 |
+
(torch.minimum(lp, rp) / torch.maximum(lp, rp).clamp(min=1e-6)) *
|
| 101 |
+
(torch.minimum(tp, bp) / torch.maximum(tp, bp).clamp(min=1e-6)))
|
| 102 |
+
return ct, rt, ctrt
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def eval_decomposition(val, coco_gt, cat_ids, decompose_fn, name, lam=0.1, n_train=10000):
|
| 106 |
+
"""Accumulate, solve, and eval a decomposition variant.
|
| 107 |
+
|
| 108 |
+
All bands are upsampled to stride-16 resolution (40x40) and use the same
|
| 109 |
+
target assignment. The decomposition separates frequencies, not resolutions.
|
| 110 |
+
"""
|
| 111 |
+
idx_to_cat = {i: c for i, c in enumerate(cat_ids)}
|
| 112 |
+
H = RESOLUTION // 16
|
| 113 |
+
target_size = (H, H)
|
| 114 |
+
stride = 16
|
| 115 |
+
sr = (-1, float("inf")) # single scale, all object sizes
|
| 116 |
+
locs_flat = make_locations([target_size], [stride])
|
| 117 |
+
n_locs = H * H
|
| 118 |
+
|
| 119 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 120 |
+
feat_dim = 768
|
| 121 |
+
cls_XtX = torch.zeros(feat_dim + 1, feat_dim + 1, device=DEVICE)
|
| 122 |
+
cls_XtY = torch.zeros(feat_dim + 1, NUM_CLASSES, device=DEVICE)
|
| 123 |
+
reg_XtX = torch.zeros(feat_dim + 1, feat_dim + 1, device=DEVICE)
|
| 124 |
+
reg_XtY = torch.zeros(feat_dim + 1, 4, device=DEVICE)
|
| 125 |
+
ctr_XtX = torch.zeros(feat_dim + 1, feat_dim + 1, device=DEVICE)
|
| 126 |
+
ctr_XtY = torch.zeros(feat_dim + 1, 1, device=DEVICE)
|
| 127 |
+
n_pos = 0; seen = 0
|
| 128 |
+
|
| 129 |
+
t0 = time.time()
|
| 130 |
+
for si in range(manifest["n_shards"]):
|
| 131 |
+
if seen >= n_train: break
|
| 132 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 133 |
+
map_location="cpu", weights_only=False)
|
| 134 |
+
for item in shard:
|
| 135 |
+
if seen >= n_train: break
|
| 136 |
+
sp = item["spatial"].unsqueeze(0).float().to(DEVICE)
|
| 137 |
+
boxes = item["boxes"]; labels = item["labels"]
|
| 138 |
+
bands = decompose_fn(sp)
|
| 139 |
+
|
| 140 |
+
# Upsample all bands to 40x40, average them
|
| 141 |
+
upsampled = []
|
| 142 |
+
for band in bands:
|
| 143 |
+
if band.shape[2:] != target_size:
|
| 144 |
+
band = F.interpolate(band, size=target_size, mode="bilinear", align_corners=False)
|
| 145 |
+
upsampled.append(band)
|
| 146 |
+
# Average across all bands — the solver sees the mean multi-frequency representation
|
| 147 |
+
merged = torch.stack(upsampled).mean(0) # (1, 768, 40, 40)
|
| 148 |
+
|
| 149 |
+
B, C, Hc, Wc = merged.shape
|
| 150 |
+
f = F.layer_norm(merged.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 151 |
+
ct, rt, ctrt = assign_targets(locs_flat[0], boxes, labels, stride, sr)
|
| 152 |
+
pos_mask = ct >= 0
|
| 153 |
+
if not pos_mask.any():
|
| 154 |
+
seen += 1; continue
|
| 155 |
+
fp = f[pos_mask]
|
| 156 |
+
fa = torch.cat([fp, torch.ones(fp.shape[0], 1, device=DEVICE)], 1)
|
| 157 |
+
yc = torch.zeros(fp.shape[0], NUM_CLASSES, device=DEVICE)
|
| 158 |
+
yc[torch.arange(fp.shape[0], device=DEVICE), ct[pos_mask].to(DEVICE)] = 1.0
|
| 159 |
+
cls_XtX += fa.T @ fa; cls_XtY += fa.T @ yc
|
| 160 |
+
ltrb = rt[pos_mask]; valid = (ltrb > 0).all(1)
|
| 161 |
+
if valid.any():
|
| 162 |
+
fv = fa[valid]; yt = torch.log(ltrb[valid]).to(DEVICE)
|
| 163 |
+
reg_XtX += fv.T @ fv; reg_XtY += fv.T @ yt
|
| 164 |
+
ctr_XtX += fa.T @ fa
|
| 165 |
+
ctr_XtY += fa.T @ ctrt[pos_mask].unsqueeze(1).to(DEVICE)
|
| 166 |
+
n_pos += pos_mask.sum().item()
|
| 167 |
+
seen += 1
|
| 168 |
+
del shard
|
| 169 |
+
|
| 170 |
+
I = torch.eye(feat_dim + 1, device=DEVICE)
|
| 171 |
+
cls_W = torch.linalg.solve(cls_XtX + lam * I * n_pos, cls_XtY)
|
| 172 |
+
reg_W = torch.linalg.solve(reg_XtX + lam * I * n_pos, reg_XtY)
|
| 173 |
+
ctr_W = torch.linalg.solve(ctr_XtX + lam * I * n_pos, ctr_XtY)
|
| 174 |
+
accum_time = time.time() - t0
|
| 175 |
+
|
| 176 |
+
all_locs = locs_flat[0].to(DEVICE)
|
| 177 |
+
all_results = []
|
| 178 |
+
for idx in range(len(val)):
|
| 179 |
+
spatial = val[idx]["spatial"].unsqueeze(0).float().to(DEVICE)
|
| 180 |
+
img_id = int(val[idx]["img_id"]); scale = val[idx]["scale"]
|
| 181 |
+
bands = decompose_fn(spatial)
|
| 182 |
+
upsampled = []
|
| 183 |
+
for band in bands:
|
| 184 |
+
if band.shape[2:] != target_size:
|
| 185 |
+
band = F.interpolate(band, size=target_size, mode="bilinear", align_corners=False)
|
| 186 |
+
upsampled.append(band)
|
| 187 |
+
merged = torch.stack(upsampled).mean(0)
|
| 188 |
+
B, C, Hc, Wc = merged.shape
|
| 189 |
+
f = F.layer_norm(merged.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 190 |
+
cls_s = (f @ cls_W[:feat_dim] + cls_W[feat_dim]).sigmoid()
|
| 191 |
+
reg_s = (f @ reg_W[:feat_dim] + reg_W[feat_dim]).exp()
|
| 192 |
+
ctr_s = (f @ ctr_W[:feat_dim] + ctr_W[feat_dim]).sigmoid().squeeze(1)
|
| 193 |
+
scores = cls_s * ctr_s.unsqueeze(1)
|
| 194 |
+
max_s, max_c = scores.max(1)
|
| 195 |
+
topk = min(100, max_s.shape[0])
|
| 196 |
+
top_s, top_i = max_s.topk(topk)
|
| 197 |
+
tc = max_c[top_i]; tr = reg_s[top_i]; tl = all_locs[top_i]
|
| 198 |
+
x1 = (tl[:,0]-tr[:,0])/scale; y1 = (tl[:,1]-tr[:,1])/scale
|
| 199 |
+
x2 = (tl[:,0]+tr[:,2])/scale; y2 = (tl[:,1]+tr[:,3])/scale
|
| 200 |
+
w = (x2-x1).clamp(min=0); h = (y2-y1).clamp(min=0)
|
| 201 |
+
for i in range(topk):
|
| 202 |
+
s = top_s[i].item()
|
| 203 |
+
if s < 0.01: continue
|
| 204 |
+
all_results.append({"image_id": img_id, "category_id": idx_to_cat[tc[i].item()],
|
| 205 |
+
"bbox": [x1[i].item(), y1[i].item(), w[i].item(), h[i].item()],
|
| 206 |
+
"score": s})
|
| 207 |
+
|
| 208 |
+
# pycocotools eval
|
| 209 |
+
from pycocotools.cocoeval import COCOeval
|
| 210 |
+
if not all_results:
|
| 211 |
+
print(f" {name}: no detections"); return 0.0
|
| 212 |
+
coco_dt = coco_gt.loadRes(all_results)
|
| 213 |
+
coco_eval = COCOeval(coco_gt, coco_dt, "bbox")
|
| 214 |
+
coco_eval.params.imgIds = sorted(coco_gt.getImgIds())[:len(val)]
|
| 215 |
+
coco_eval.evaluate(); coco_eval.accumulate(); coco_eval.summarize()
|
| 216 |
+
mAP = coco_eval.stats[0]
|
| 217 |
+
mAP50 = coco_eval.stats[1]
|
| 218 |
+
mAP75 = coco_eval.stats[2]
|
| 219 |
+
print(f" {name}: mAP={mAP:.4f} mAP50={mAP50:.4f} mAP75={mAP75:.4f} "
|
| 220 |
+
f"({accum_time:.0f}s accum, {n_pos} pos)")
|
| 221 |
+
return mAP
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def main():
|
| 225 |
+
from pycocotools.coco import COCO
|
| 226 |
+
|
| 227 |
+
print("=" * 60)
|
| 228 |
+
print("Fractal vs Standard Cofiber Decomposition")
|
| 229 |
+
print("=" * 60, flush=True)
|
| 230 |
+
|
| 231 |
+
val = torch.load(VAL_CACHE, map_location="cpu", weights_only=False)
|
| 232 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 233 |
+
coco_gt = COCO(ann_file)
|
| 234 |
+
cat_ids = sorted(coco_gt.getCatIds())
|
| 235 |
+
|
| 236 |
+
results = []
|
| 237 |
+
|
| 238 |
+
# Standard 3-band cofiber (baseline)
|
| 239 |
+
print("\n1. Standard 3-band cofiber:", flush=True)
|
| 240 |
+
mAP = eval_decomposition(val, coco_gt, cat_ids,
|
| 241 |
+
lambda sp: standard_decompose(sp, 3), "standard_3band")
|
| 242 |
+
results.append({"name": "standard_3band", "mAP": mAP, "bands": 3})
|
| 243 |
+
|
| 244 |
+
# Fractal depth 2 (4 bands)
|
| 245 |
+
print("\n2. Fractal depth 2 (4 bands):", flush=True)
|
| 246 |
+
mAP = eval_decomposition(val, coco_gt, cat_ids,
|
| 247 |
+
lambda sp: fractal_decompose(sp, 2), "fractal_depth2")
|
| 248 |
+
results.append({"name": "fractal_depth2", "mAP": mAP, "bands": 4})
|
| 249 |
+
|
| 250 |
+
# Fractal depth 3 (8 bands)
|
| 251 |
+
print("\n3. Fractal depth 3 (8 bands):", flush=True)
|
| 252 |
+
mAP = eval_decomposition(val, coco_gt, cat_ids,
|
| 253 |
+
lambda sp: fractal_decompose(sp, 3), "fractal_depth3")
|
| 254 |
+
results.append({"name": "fractal_depth3", "mAP": mAP, "bands": 8})
|
| 255 |
+
|
| 256 |
+
print(f"\n{'='*60}")
|
| 257 |
+
print("Summary:")
|
| 258 |
+
for r in results:
|
| 259 |
+
print(f" {r['name']:20s}: mAP={r['mAP']:.4f} ({r['bands']} bands)")
|
| 260 |
+
|
| 261 |
+
out = os.path.join(SCRIPT_DIR, "analytical_variants", "fractal_results.json")
|
| 262 |
+
with open(out, "w") as f:
|
| 263 |
+
json.dump(results, f, indent=2)
|
| 264 |
+
print(f"Saved: {out}")
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
if __name__ == "__main__":
|
| 268 |
+
main()
|
analytical/scripts/analytical_gcv.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
GCV-optimal analytical detection head.
|
| 3 |
+
|
| 4 |
+
Computes the generalized cross-validation optimal lambda for each task
|
| 5 |
+
(classification, regression, centerness) independently via SVD of the
|
| 6 |
+
accumulated sufficient statistics. No grid search — closed-form.
|
| 7 |
+
|
| 8 |
+
Then builds the head with per-task optimal regularization and evals.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import json, os, sys, time
|
| 12 |
+
import torch
|
| 13 |
+
import torch.nn.functional as F
|
| 14 |
+
|
| 15 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 16 |
+
STATS_DIR = os.path.join(SCRIPT_DIR, "analytical_stats_cache")
|
| 17 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT")
|
| 18 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE")
|
| 19 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR")
|
| 20 |
+
DEVICE = "cuda"
|
| 21 |
+
RESOLUTION = 640
|
| 22 |
+
NUM_CLASSES = 80
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def cofiber_decompose(f, n_scales):
|
| 26 |
+
cofibers = []; residual = f
|
| 27 |
+
for _ in range(n_scales - 1):
|
| 28 |
+
omega = F.avg_pool2d(residual, 2)
|
| 29 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 30 |
+
cofibers.append(residual - sigma_omega); residual = omega
|
| 31 |
+
cofibers.append(residual); return cofibers
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def make_locations(sizes, strides, device="cpu"):
|
| 35 |
+
locs = []
|
| 36 |
+
for (h, w), s in zip(sizes, strides):
|
| 37 |
+
ys = (torch.arange(h, device=device, dtype=torch.float32) + 0.5) * s
|
| 38 |
+
xs = (torch.arange(w, device=device, dtype=torch.float32) + 0.5) * s
|
| 39 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 40 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 41 |
+
return locs
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 45 |
+
n = loc.shape[0]
|
| 46 |
+
ct = torch.full((n,), -1, dtype=torch.long); rt = torch.zeros(n, 4); ctrt = torch.zeros(n)
|
| 47 |
+
if boxes.numel() == 0: return ct, rt, ctrt
|
| 48 |
+
areas = (boxes[:,2]-boxes[:,0])*(boxes[:,3]-boxes[:,1])
|
| 49 |
+
l=loc[:,None,0]-boxes[None,:,0]; t=loc[:,None,1]-boxes[None,:,1]
|
| 50 |
+
r=boxes[None,:,2]-loc[:,None,0]; b=boxes[None,:,3]-loc[:,None,1]
|
| 51 |
+
ltrb=torch.stack([l,t,r,b],-1); in_box=ltrb.min(-1).values>0
|
| 52 |
+
cx=(boxes[:,0]+boxes[:,2])/2; cy=(boxes[:,1]+boxes[:,3])/2; rad=stride*1.5
|
| 53 |
+
in_center=((loc[:,None,0]>=cx-rad)&(loc[:,None,0]<=cx+rad)&(loc[:,None,1]>=cy-rad)&(loc[:,None,1]<=cy+rad))
|
| 54 |
+
max_d=ltrb.max(-1).values; in_level=(max_d>=sr[0])&(max_d<=sr[1])
|
| 55 |
+
pos=in_box&in_center&in_level; a=areas[None,:].expand_as(pos).clone(); a[~pos]=float("inf")
|
| 56 |
+
matched=a.argmin(1); is_pos=a.gather(1,matched[:,None]).squeeze(1)<float("inf")
|
| 57 |
+
ct[is_pos]=labels[matched[is_pos]]
|
| 58 |
+
if is_pos.any():
|
| 59 |
+
rt[is_pos]=ltrb[torch.arange(n)[is_pos],matched[is_pos]]
|
| 60 |
+
lp,tp,rp,bp=rt[is_pos].unbind(-1)
|
| 61 |
+
ctrt[is_pos]=torch.sqrt((torch.minimum(lp,rp)/torch.maximum(lp,rp).clamp(min=1e-6))*(torch.minimum(tp,bp)/torch.maximum(tp,bp).clamp(min=1e-6)))
|
| 62 |
+
return ct, rt, ctrt
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def gcv_optimal_lambda(XtX, XtY, n_samples, lambdas=None):
|
| 66 |
+
"""Find GCV-optimal lambda via SVD.
|
| 67 |
+
|
| 68 |
+
For ridge regression: Y = X W + noise
|
| 69 |
+
Hat matrix: H(λ) = X (X^T X + λI)^{-1} X^T
|
| 70 |
+
GCV(λ) = (1/n) ||Y - H(λ)Y||² / (1 - tr(H(λ))/n)²
|
| 71 |
+
|
| 72 |
+
Using SVD of the augmented feature matrix: X = U S V^T
|
| 73 |
+
tr(H(λ)) = Σ s_i² / (s_i² + λ)
|
| 74 |
+
||Y - H(λ)Y||² = Σ (λ u_i^T Y / (s_i² + λ))²
|
| 75 |
+
|
| 76 |
+
We work with XtX = V S² V^T directly.
|
| 77 |
+
"""
|
| 78 |
+
# Eigendecompose XtX (symmetric positive semi-definite)
|
| 79 |
+
eigvals, eigvecs = torch.linalg.eigh(XtX)
|
| 80 |
+
eigvals = eigvals.clamp(min=0) # numerical stability
|
| 81 |
+
|
| 82 |
+
# Project targets: V^T X^T Y = V^T (XtX XtX^{-1} XtY) ...
|
| 83 |
+
# Actually we need U^T Y. From XtX = V S² V^T and XtY = V S U^T Y
|
| 84 |
+
# So V^T XtY = S U^T Y, thus U^T Y = S^{-1} V^T XtY
|
| 85 |
+
VtXtY = eigvecs.T @ XtY # (d+1, k)
|
| 86 |
+
# S = sqrt(eigvals)
|
| 87 |
+
S = eigvals.sqrt().clamp(min=1e-10)
|
| 88 |
+
UtY = VtXtY / S.unsqueeze(1) # (d+1, k)
|
| 89 |
+
|
| 90 |
+
if lambdas is None:
|
| 91 |
+
# Log-spaced search
|
| 92 |
+
lam_min = eigvals[eigvals > 0].min().item() * 0.001
|
| 93 |
+
lam_max = eigvals.max().item() * 10
|
| 94 |
+
lambdas = torch.logspace(
|
| 95 |
+
max(-8, torch.log10(torch.tensor(lam_min)).item()),
|
| 96 |
+
min(4, torch.log10(torch.tensor(lam_max)).item()),
|
| 97 |
+
200, device=XtX.device)
|
| 98 |
+
|
| 99 |
+
d = XtX.shape[0]
|
| 100 |
+
best_lam = lambdas[0].item()
|
| 101 |
+
best_gcv = float("inf")
|
| 102 |
+
|
| 103 |
+
for lam in lambdas:
|
| 104 |
+
# tr(H) = Σ s_i² / (s_i² + λ)
|
| 105 |
+
leverage = eigvals / (eigvals + lam)
|
| 106 |
+
tr_H = leverage.sum()
|
| 107 |
+
|
| 108 |
+
# Residual: ||Y - HY||² = Σ_i (λ/(s_i²+λ))² ||u_i^T Y||²
|
| 109 |
+
shrinkage = lam / (eigvals + lam)
|
| 110 |
+
res_sq = (shrinkage.unsqueeze(1) ** 2 * UtY ** 2).sum()
|
| 111 |
+
|
| 112 |
+
# GCV
|
| 113 |
+
gcv = (res_sq / n_samples) / ((1 - tr_H / n_samples) ** 2 + 1e-12)
|
| 114 |
+
|
| 115 |
+
if gcv.item() < best_gcv:
|
| 116 |
+
best_gcv = gcv.item()
|
| 117 |
+
best_lam = lam.item()
|
| 118 |
+
|
| 119 |
+
return best_lam, best_gcv
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def main():
|
| 123 |
+
print("=" * 60)
|
| 124 |
+
print("GCV-Optimal Analytical Detection Head")
|
| 125 |
+
print("=" * 60, flush=True)
|
| 126 |
+
|
| 127 |
+
# Accumulate on GPU
|
| 128 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 129 |
+
strides = [16, 32, 64]; H = RESOLUTION // 16
|
| 130 |
+
sizes = [(H, H), (H//2, H//2), (H//4, H//4)]
|
| 131 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 132 |
+
locs = make_locations(sizes, strides)
|
| 133 |
+
feat_dim = 768
|
| 134 |
+
|
| 135 |
+
cls_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 136 |
+
cls_XtY = torch.zeros(feat_dim+1, NUM_CLASSES, device=DEVICE)
|
| 137 |
+
reg_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 138 |
+
reg_XtY = torch.zeros(feat_dim+1, 4, device=DEVICE)
|
| 139 |
+
ctr_XtX = torch.zeros(feat_dim+1, feat_dim+1, device=DEVICE)
|
| 140 |
+
ctr_XtY = torch.zeros(feat_dim+1, 1, device=DEVICE)
|
| 141 |
+
n_cls = 0; n_reg = 0; n_ctr = 0
|
| 142 |
+
n_images = 20000; seen = 0
|
| 143 |
+
t0 = time.time()
|
| 144 |
+
|
| 145 |
+
for si in range(manifest["n_shards"]):
|
| 146 |
+
if seen >= n_images: break
|
| 147 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 148 |
+
map_location="cpu", weights_only=False)
|
| 149 |
+
for item in shard:
|
| 150 |
+
if seen >= n_images: break
|
| 151 |
+
sp = item["spatial"].unsqueeze(0).float()
|
| 152 |
+
boxes = item["boxes"]; labels = item["labels"]
|
| 153 |
+
cofibers = cofiber_decompose(sp, 3)
|
| 154 |
+
for sci, cof in enumerate(cofibers):
|
| 155 |
+
B, C, Hc, Wc = cof.shape
|
| 156 |
+
f = F.layer_norm(cof.permute(0,2,3,1).reshape(-1,C), [C]).to(DEVICE)
|
| 157 |
+
ct, rt, ctrt = assign_targets(locs[sci], boxes, labels, strides[sci], sr[sci])
|
| 158 |
+
pos = ct >= 0
|
| 159 |
+
if not pos.any(): continue
|
| 160 |
+
fp = f[pos]
|
| 161 |
+
fa = torch.cat([fp, torch.ones(fp.shape[0],1,device=DEVICE)], 1)
|
| 162 |
+
yc = torch.zeros(fp.shape[0], NUM_CLASSES, device=DEVICE)
|
| 163 |
+
yc[torch.arange(fp.shape[0],device=DEVICE), ct[pos].to(DEVICE)] = 1.0
|
| 164 |
+
cls_XtX += fa.T @ fa; cls_XtY += fa.T @ yc; n_cls += fp.shape[0]
|
| 165 |
+
ltrb = rt[pos]; valid = (ltrb > 0).all(1)
|
| 166 |
+
if valid.any():
|
| 167 |
+
fv = fa[valid]; yt = torch.log(ltrb[valid]).to(DEVICE)
|
| 168 |
+
reg_XtX += fv.T @ fv; reg_XtY += fv.T @ yt; n_reg += valid.sum().item()
|
| 169 |
+
ctr_XtX += fa.T @ fa
|
| 170 |
+
ctr_XtY += fa.T @ ctrt[pos].unsqueeze(1).to(DEVICE); n_ctr += fp.shape[0]
|
| 171 |
+
seen += 1
|
| 172 |
+
del shard
|
| 173 |
+
if (si+1) % 5 == 0:
|
| 174 |
+
print(f" shard {si+1}: {seen} imgs, {n_cls} cls, {n_reg} reg, {time.time()-t0:.0f}s", flush=True)
|
| 175 |
+
|
| 176 |
+
print(f"\nAccumulated: {n_cls} cls, {n_reg} reg, {n_ctr} ctr positives", flush=True)
|
| 177 |
+
|
| 178 |
+
# GCV optimal lambda per task
|
| 179 |
+
print("\nFinding GCV-optimal lambda...", flush=True)
|
| 180 |
+
t1 = time.time()
|
| 181 |
+
# Normalize by n so GCV searches over the actual regularization strength
|
| 182 |
+
# Our solve uses (XtX + lam * I * n), so GCV should find lam such that lam*n is optimal
|
| 183 |
+
# Equivalently: search on (XtX/n + lam * I) and report lam
|
| 184 |
+
lam_cls, gcv_cls = gcv_optimal_lambda(cls_XtX / n_cls, cls_XtY / n_cls, n_cls)
|
| 185 |
+
lam_reg, gcv_reg = gcv_optimal_lambda(reg_XtX / n_reg, reg_XtY / n_reg, n_reg)
|
| 186 |
+
lam_ctr, gcv_ctr = gcv_optimal_lambda(ctr_XtX / n_ctr, ctr_XtY / n_ctr, n_ctr)
|
| 187 |
+
print(f" cls: lambda={lam_cls:.6f} (GCV={gcv_cls:.6f})")
|
| 188 |
+
print(f" reg: lambda={lam_reg:.6f} (GCV={gcv_reg:.6f})")
|
| 189 |
+
print(f" ctr: lambda={lam_ctr:.6f} (GCV={gcv_ctr:.6f})")
|
| 190 |
+
print(f" (took {time.time()-t1:.1f}s)", flush=True)
|
| 191 |
+
|
| 192 |
+
# Compare: solve with GCV lambda vs fixed lambda=0.1
|
| 193 |
+
print("\nSolving with GCV-optimal lambda...", flush=True)
|
| 194 |
+
I = torch.eye(feat_dim+1, device=DEVICE)
|
| 195 |
+
cls_W_gcv = torch.linalg.solve(cls_XtX + lam_cls * I * n_cls, cls_XtY)
|
| 196 |
+
reg_W_gcv = torch.linalg.solve(reg_XtX + lam_reg * I * n_reg, reg_XtY)
|
| 197 |
+
ctr_W_gcv = torch.linalg.solve(ctr_XtX + lam_ctr * I * n_ctr, ctr_XtY)
|
| 198 |
+
|
| 199 |
+
print("Solving with fixed lambda=0.1...", flush=True)
|
| 200 |
+
cls_W_fix = torch.linalg.solve(cls_XtX + 0.1 * I * n_cls, cls_XtY)
|
| 201 |
+
reg_W_fix = torch.linalg.solve(reg_XtX + 0.1 * I * n_reg, reg_XtY)
|
| 202 |
+
ctr_W_fix = torch.linalg.solve(ctr_XtX + 0.1 * I * n_ctr, ctr_XtY)
|
| 203 |
+
|
| 204 |
+
# Eval both on COCO val
|
| 205 |
+
val = torch.load(VAL_CACHE, map_location="cpu", weights_only=False)
|
| 206 |
+
from pycocotools.coco import COCO
|
| 207 |
+
from pycocotools.cocoeval import COCOeval
|
| 208 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 209 |
+
coco_gt = COCO(ann_file)
|
| 210 |
+
cat_ids = sorted(coco_gt.getCatIds())
|
| 211 |
+
idx_to_cat = {i: c for i, c in enumerate(cat_ids)}
|
| 212 |
+
all_locs = torch.cat(make_locations(sizes, strides, DEVICE))
|
| 213 |
+
|
| 214 |
+
for label, cls_W, reg_W, ctr_W in [("gcv_optimal", cls_W_gcv, reg_W_gcv, ctr_W_gcv),
|
| 215 |
+
("fixed_0.1", cls_W_fix, reg_W_fix, ctr_W_fix)]:
|
| 216 |
+
print(f"\nEvaluating: {label}", flush=True)
|
| 217 |
+
all_results = []
|
| 218 |
+
for idx in range(len(val)):
|
| 219 |
+
item = val[idx]
|
| 220 |
+
spatial = item["spatial"].unsqueeze(0).float().to(DEVICE)
|
| 221 |
+
img_id = int(item["img_id"]); scale = item["scale"]
|
| 222 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 223 |
+
cls_all, reg_all, ctr_all = [], [], []
|
| 224 |
+
for cof in cofibers:
|
| 225 |
+
B, C, Hc, Wc = cof.shape
|
| 226 |
+
f = F.layer_norm(cof.permute(0,2,3,1).reshape(-1,C), [C])
|
| 227 |
+
fa = torch.cat([f, torch.ones(f.shape[0],1,device=DEVICE)], 1)
|
| 228 |
+
cls = (fa @ cls_W).sigmoid()
|
| 229 |
+
reg = (fa @ reg_W).exp()
|
| 230 |
+
ctr = (fa @ ctr_W).sigmoid()
|
| 231 |
+
cls_all.append(cls); reg_all.append(reg); ctr_all.append(ctr.squeeze(1))
|
| 232 |
+
cls_s = torch.cat(cls_all); reg_s = torch.cat(reg_all); ctr_s = torch.cat(ctr_all)
|
| 233 |
+
scores = cls_s * ctr_s.unsqueeze(1)
|
| 234 |
+
max_s, max_c = scores.max(1)
|
| 235 |
+
topk = min(100, max_s.shape[0])
|
| 236 |
+
top_s, top_i = max_s.topk(topk)
|
| 237 |
+
tc = max_c[top_i]; tr = reg_s[top_i]; tl = all_locs[top_i]
|
| 238 |
+
x1=(tl[:,0]-tr[:,0])/scale; y1=(tl[:,1]-tr[:,1])/scale
|
| 239 |
+
x2=(tl[:,0]+tr[:,2])/scale; y2=(tl[:,1]+tr[:,3])/scale
|
| 240 |
+
w=(x2-x1).clamp(min=0); h=(y2-y1).clamp(min=0)
|
| 241 |
+
for i in range(topk):
|
| 242 |
+
s = top_s[i].item()
|
| 243 |
+
if s < 0.01: continue
|
| 244 |
+
all_results.append({"image_id": img_id, "category_id": idx_to_cat[tc[i].item()],
|
| 245 |
+
"bbox": [x1[i].item(), y1[i].item(), w[i].item(), h[i].item()],
|
| 246 |
+
"score": s})
|
| 247 |
+
if (idx+1) % 1000 == 0:
|
| 248 |
+
print(f" {idx+1}/{len(val)}", flush=True)
|
| 249 |
+
|
| 250 |
+
if all_results:
|
| 251 |
+
coco_dt = coco_gt.loadRes(all_results)
|
| 252 |
+
coco_eval = COCOeval(coco_gt, coco_dt, "bbox")
|
| 253 |
+
coco_eval.params.imgIds = sorted(coco_gt.getImgIds())[:len(val)]
|
| 254 |
+
coco_eval.evaluate(); coco_eval.accumulate(); coco_eval.summarize()
|
| 255 |
+
mAP = coco_eval.stats[0]
|
| 256 |
+
mAP50 = coco_eval.stats[1]
|
| 257 |
+
mAP75 = coco_eval.stats[2]
|
| 258 |
+
print(f"\n {label}: mAP={mAP:.4f} mAP50={mAP50:.4f} mAP75={mAP75:.4f}")
|
| 259 |
+
else:
|
| 260 |
+
print(f" {label}: no detections")
|
| 261 |
+
|
| 262 |
+
elapsed = time.time() - t0
|
| 263 |
+
print(f"\nTotal: {elapsed:.0f}s")
|
| 264 |
+
print(f"\nGCV-optimal lambdas: cls={lam_cls:.6f} reg={lam_reg:.6f} ctr={lam_ctr:.6f}")
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
if __name__ == "__main__":
|
| 268 |
+
main()
|
analytical/scripts/analytical_greedy_gpu.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
GPU-accelerated greedy forward construction of a minimal detection head.
|
| 3 |
+
|
| 4 |
+
Batches all candidate evaluations into parallel matmuls on GPU.
|
| 5 |
+
50 greedy steps in seconds instead of minutes.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import argparse
|
| 9 |
+
import json
|
| 10 |
+
import os
|
| 11 |
+
import sys
|
| 12 |
+
import time
|
| 13 |
+
|
| 14 |
+
import torch
|
| 15 |
+
import torch.nn.functional as F
|
| 16 |
+
|
| 17 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 18 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 19 |
+
|
| 20 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT", "coco")
|
| 21 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE", "val_cache/val.pt")
|
| 22 |
+
NUM_CLASSES = 80
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def cofiber_decompose(f, n_scales):
|
| 26 |
+
cofibers = []
|
| 27 |
+
residual = f
|
| 28 |
+
for _ in range(n_scales - 1):
|
| 29 |
+
omega = F.avg_pool2d(residual, 2)
|
| 30 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 31 |
+
cofibers.append(residual - sigma_omega)
|
| 32 |
+
residual = omega
|
| 33 |
+
cofibers.append(residual)
|
| 34 |
+
return cofibers
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def make_locations(sizes, strides):
|
| 38 |
+
locs = []
|
| 39 |
+
for (h, w), s in zip(sizes, strides):
|
| 40 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 41 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 42 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 43 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 44 |
+
return locs
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 48 |
+
n = loc.shape[0]
|
| 49 |
+
if boxes.numel() == 0:
|
| 50 |
+
return torch.full((n,), -1, dtype=torch.long), torch.zeros(n, 4)
|
| 51 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 52 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 53 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 54 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 55 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 56 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 57 |
+
in_box = ltrb.min(-1).values > 0
|
| 58 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 59 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 60 |
+
rad = stride * 1.5
|
| 61 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 62 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 63 |
+
max_d = ltrb.max(-1).values
|
| 64 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 65 |
+
pos = in_box & in_center & in_level
|
| 66 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 67 |
+
a[~pos] = float("inf")
|
| 68 |
+
matched = a.argmin(1)
|
| 69 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 70 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 71 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 72 |
+
rt = torch.zeros(n, 4)
|
| 73 |
+
if is_pos.any():
|
| 74 |
+
rt[is_pos] = ltrb[torch.arange(n)[is_pos], matched[is_pos]]
|
| 75 |
+
return ct, rt
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def build_val_data(val_path, n_images=500, device="cuda"):
|
| 79 |
+
"""Build feature matrix + targets on GPU."""
|
| 80 |
+
val = torch.load(val_path, map_location="cpu", weights_only=False)
|
| 81 |
+
from pycocotools.coco import COCO
|
| 82 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 83 |
+
coco = COCO(ann_file)
|
| 84 |
+
cat_ids = sorted(coco.getCatIds())
|
| 85 |
+
cat_to_idx = {c: i for i, c in enumerate(cat_ids)}
|
| 86 |
+
|
| 87 |
+
strides = [16, 32, 64]
|
| 88 |
+
H = 640 // 16
|
| 89 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 90 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 91 |
+
locs = make_locations(sizes, strides)
|
| 92 |
+
|
| 93 |
+
all_f, all_cls = [], []
|
| 94 |
+
for idx in range(min(n_images, len(val))):
|
| 95 |
+
item = val[idx]
|
| 96 |
+
spatial = item["spatial"].unsqueeze(0).float()
|
| 97 |
+
img_id = item["img_id"]
|
| 98 |
+
scale = item["scale"]
|
| 99 |
+
ann_ids = coco.getAnnIds(imgIds=int(img_id), iscrowd=False)
|
| 100 |
+
anns = coco.loadAnns(ann_ids)
|
| 101 |
+
boxes, labels = [], []
|
| 102 |
+
for ann in anns:
|
| 103 |
+
x, y, w, h = ann["bbox"]
|
| 104 |
+
if w < 1 or h < 1:
|
| 105 |
+
continue
|
| 106 |
+
boxes.append([x * scale, y * scale, (x + w) * scale, (y + h) * scale])
|
| 107 |
+
labels.append(cat_to_idx[ann["category_id"]])
|
| 108 |
+
boxes_t = torch.tensor(boxes, dtype=torch.float32) if boxes else torch.zeros(0, 4)
|
| 109 |
+
labels_t = torch.tensor(labels, dtype=torch.long) if labels else torch.zeros(0, dtype=torch.long)
|
| 110 |
+
|
| 111 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 112 |
+
for sci, cof in enumerate(cofibers):
|
| 113 |
+
B, C, Hc, Wc = cof.shape
|
| 114 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 115 |
+
ct, _ = assign_targets(locs[sci], boxes_t, labels_t, strides[sci], sr[sci])
|
| 116 |
+
all_f.append(f)
|
| 117 |
+
all_cls.append(ct)
|
| 118 |
+
|
| 119 |
+
features = torch.cat(all_f).to(device)
|
| 120 |
+
cls_targets = torch.cat(all_cls).to(device)
|
| 121 |
+
return features, cls_targets
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def greedy_step_gpu(features, cls_targets, selected, remaining, lam=0.1):
|
| 125 |
+
"""Test all remaining candidates in parallel on GPU. Return best dim and accuracy."""
|
| 126 |
+
pos = cls_targets >= 0
|
| 127 |
+
n_pos = pos.sum().item()
|
| 128 |
+
if n_pos == 0:
|
| 129 |
+
return -1, 0.0
|
| 130 |
+
|
| 131 |
+
# Build one-hot targets
|
| 132 |
+
f_pos = features[pos]
|
| 133 |
+
y_cls = torch.zeros(n_pos, NUM_CLASSES, device=features.device)
|
| 134 |
+
y_cls[torch.arange(n_pos, device=features.device), cls_targets[pos]] = 1.0
|
| 135 |
+
gt = cls_targets[pos]
|
| 136 |
+
|
| 137 |
+
best_dim = -1
|
| 138 |
+
best_acc = -1.0
|
| 139 |
+
|
| 140 |
+
# For each candidate, solve and score
|
| 141 |
+
# Batch in chunks to avoid OOM on very large candidate sets
|
| 142 |
+
chunk_size = 64
|
| 143 |
+
for chunk_start in range(0, len(remaining), chunk_size):
|
| 144 |
+
chunk = remaining[chunk_start:chunk_start + chunk_size]
|
| 145 |
+
accs = []
|
| 146 |
+
for d in chunk:
|
| 147 |
+
dims = selected + [d]
|
| 148 |
+
fd = len(dims)
|
| 149 |
+
fp = f_pos[:, dims]
|
| 150 |
+
fa = torch.cat([fp, torch.ones(n_pos, 1, device=fp.device)], 1)
|
| 151 |
+
I = torch.eye(fd + 1, device=fp.device)
|
| 152 |
+
XtX = fa.T @ fa
|
| 153 |
+
XtY = fa.T @ y_cls
|
| 154 |
+
try:
|
| 155 |
+
W = torch.linalg.solve(XtX + lam * I * n_pos, XtY)
|
| 156 |
+
except Exception:
|
| 157 |
+
accs.append(0.0)
|
| 158 |
+
continue
|
| 159 |
+
# Score on all positive locations
|
| 160 |
+
scores = fp @ W[:fd] + W[fd] # (n_pos, 80)
|
| 161 |
+
pred = scores.argmax(1)
|
| 162 |
+
acc = (pred == gt).float().mean().item()
|
| 163 |
+
accs.append(acc)
|
| 164 |
+
|
| 165 |
+
for i, d in enumerate(chunk):
|
| 166 |
+
if accs[i] > best_acc:
|
| 167 |
+
best_acc = accs[i]
|
| 168 |
+
best_dim = d
|
| 169 |
+
|
| 170 |
+
return best_dim, best_acc
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def main():
|
| 174 |
+
parser = argparse.ArgumentParser()
|
| 175 |
+
parser.add_argument("--max-dims", type=int, default=100)
|
| 176 |
+
parser.add_argument("--n-eval", type=int, default=500)
|
| 177 |
+
parser.add_argument("--lam", type=float, default=0.1)
|
| 178 |
+
args = parser.parse_args()
|
| 179 |
+
|
| 180 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 181 |
+
print(f"Device: {device}")
|
| 182 |
+
print("=" * 60)
|
| 183 |
+
print(f"GPU Greedy Forward Construction (max {args.max_dims} dims)")
|
| 184 |
+
print("=" * 60, flush=True)
|
| 185 |
+
|
| 186 |
+
print("Building val data...", flush=True)
|
| 187 |
+
features, cls_targets = build_val_data(VAL_CACHE, args.n_eval, device)
|
| 188 |
+
pos = cls_targets >= 0
|
| 189 |
+
print(f" {features.shape[0]} locations, {pos.sum().item()} positives, "
|
| 190 |
+
f"{features.shape[1]} dims", flush=True)
|
| 191 |
+
|
| 192 |
+
selected = []
|
| 193 |
+
remaining = list(range(768))
|
| 194 |
+
history = []
|
| 195 |
+
t0 = time.time()
|
| 196 |
+
|
| 197 |
+
for step in range(args.max_dims):
|
| 198 |
+
t_step = time.time()
|
| 199 |
+
best_dim, best_acc = greedy_step_gpu(features, cls_targets, selected, remaining, args.lam)
|
| 200 |
+
|
| 201 |
+
if best_dim < 0:
|
| 202 |
+
break
|
| 203 |
+
|
| 204 |
+
selected.append(best_dim)
|
| 205 |
+
remaining.remove(best_dim)
|
| 206 |
+
step_time = time.time() - t_step
|
| 207 |
+
|
| 208 |
+
n_params = len(selected) * NUM_CLASSES + NUM_CLASSES # cls only for now
|
| 209 |
+
entry = {"step": step + 1, "dim": best_dim, "cls_acc": round(best_acc, 4),
|
| 210 |
+
"n_params": n_params, "step_ms": round(step_time * 1000)}
|
| 211 |
+
history.append(entry)
|
| 212 |
+
|
| 213 |
+
print(f" step {step+1:3d}: +dim{best_dim:3d} -> cls_acc={best_acc:.4f} "
|
| 214 |
+
f"({len(selected)} dims, {n_params} params, {step_time*1000:.0f}ms)", flush=True)
|
| 215 |
+
|
| 216 |
+
# Early stopping
|
| 217 |
+
if len(history) >= 10:
|
| 218 |
+
recent_gain = history[-1]["cls_acc"] - history[-10]["cls_acc"]
|
| 219 |
+
if recent_gain < 0.005:
|
| 220 |
+
print(f" Converged: <0.5% gain in 10 steps", flush=True)
|
| 221 |
+
break
|
| 222 |
+
|
| 223 |
+
elapsed = time.time() - t0
|
| 224 |
+
print(f"\n{'='*60}")
|
| 225 |
+
print(f"Selected {len(selected)} dimensions in {elapsed:.1f}s")
|
| 226 |
+
print(f"Final cls_acc: {history[-1]['cls_acc']:.4f}")
|
| 227 |
+
print(f"Final params: {history[-1]['n_params']}")
|
| 228 |
+
print(f"\nTop 20 dimensions (most to least important):")
|
| 229 |
+
for h in history[:20]:
|
| 230 |
+
print(f" step {h['step']:2d}: dim{h['dim']:3d} cumul_acc={h['cls_acc']:.4f} ({h['step_ms']}ms)")
|
| 231 |
+
|
| 232 |
+
# Save
|
| 233 |
+
result = {"selected_dims": selected, "history": history,
|
| 234 |
+
"final_cls_acc": history[-1]["cls_acc"], "final_params": history[-1]["n_params"],
|
| 235 |
+
"total_time_s": round(elapsed, 1)}
|
| 236 |
+
out = os.path.join(SCRIPT_DIR, "analytical_variants", "greedy_forward_gpu.json")
|
| 237 |
+
os.makedirs(os.path.dirname(out), exist_ok=True)
|
| 238 |
+
with open(out, "w") as f:
|
| 239 |
+
json.dump(result, f, indent=2)
|
| 240 |
+
print(f"\nSaved: {out}")
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
if __name__ == "__main__":
|
| 244 |
+
main()
|
analytical/scripts/analytical_hyperbatch.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Hyper-batch analytical sweep — all variants on GPU simultaneously.
|
| 3 |
+
|
| 4 |
+
Pre-loads ALL training features + ALL val features into VRAM.
|
| 5 |
+
Pre-computes all feature variants (raw, H^1, fractal, quadratic).
|
| 6 |
+
Solves and evals 100+ variants in one pass.
|
| 7 |
+
|
| 8 |
+
GPU memory budget: ~15 GB of 46 GB available.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import json, os, sys, time
|
| 12 |
+
import torch, torch.nn.functional as F
|
| 13 |
+
|
| 14 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 15 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 16 |
+
|
| 17 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR")
|
| 18 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT")
|
| 19 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE")
|
| 20 |
+
DEVICE = "cuda"
|
| 21 |
+
RESOLUTION = 640
|
| 22 |
+
NUM_CLASSES = 80
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def cofiber_decompose(f, n_scales):
|
| 26 |
+
cofibers = []; residual = f
|
| 27 |
+
for _ in range(n_scales - 1):
|
| 28 |
+
omega = F.avg_pool2d(residual, 2)
|
| 29 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 30 |
+
cofibers.append(residual - sigma_omega); residual = omega
|
| 31 |
+
cofibers.append(residual); return cofibers
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def make_locations(sizes, strides, device="cpu"):
|
| 35 |
+
locs = []
|
| 36 |
+
for (h, w), s in zip(sizes, strides):
|
| 37 |
+
ys = (torch.arange(h, device=device, dtype=torch.float32) + 0.5) * s
|
| 38 |
+
xs = (torch.arange(w, device=device, dtype=torch.float32) + 0.5) * s
|
| 39 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 40 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 41 |
+
return locs
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 45 |
+
n = loc.shape[0]
|
| 46 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 47 |
+
rt = torch.zeros(n, 4); ctrt = torch.zeros(n)
|
| 48 |
+
if boxes.numel() == 0: return ct, rt, ctrt
|
| 49 |
+
areas = (boxes[:, 2]-boxes[:, 0])*(boxes[:, 3]-boxes[:, 1])
|
| 50 |
+
l=loc[:,None,0]-boxes[None,:,0]; t=loc[:,None,1]-boxes[None,:,1]
|
| 51 |
+
r=boxes[None,:,2]-loc[:,None,0]; b=boxes[None,:,3]-loc[:,None,1]
|
| 52 |
+
ltrb=torch.stack([l,t,r,b],-1); in_box=ltrb.min(-1).values>0
|
| 53 |
+
cx=(boxes[:,0]+boxes[:,2])/2; cy=(boxes[:,1]+boxes[:,3])/2; rad=stride*1.5
|
| 54 |
+
in_center=((loc[:,None,0]>=cx-rad)&(loc[:,None,0]<=cx+rad)&(loc[:,None,1]>=cy-rad)&(loc[:,None,1]<=cy+rad))
|
| 55 |
+
max_d=ltrb.max(-1).values; in_level=(max_d>=sr[0])&(max_d<=sr[1])
|
| 56 |
+
pos=in_box&in_center&in_level; a=areas[None,:].expand_as(pos).clone(); a[~pos]=float("inf")
|
| 57 |
+
matched=a.argmin(1); is_pos=a.gather(1,matched[:,None]).squeeze(1)<float("inf")
|
| 58 |
+
ct[is_pos]=labels[matched[is_pos]]
|
| 59 |
+
if is_pos.any():
|
| 60 |
+
rt[is_pos]=ltrb[torch.arange(n)[is_pos],matched[is_pos]]
|
| 61 |
+
lp,tp,rp,bp=rt[is_pos].unbind(-1)
|
| 62 |
+
ctrt[is_pos]=torch.sqrt((torch.minimum(lp,rp)/torch.maximum(lp,rp).clamp(min=1e-6))*(torch.minimum(tp,bp)/torch.maximum(tp,bp).clamp(min=1e-6)))
|
| 63 |
+
return ct, rt, ctrt
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def load_train_features(n_images=20000):
|
| 67 |
+
"""Load training features + targets into GPU."""
|
| 68 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 69 |
+
strides = [16, 32, 64]; H = RESOLUTION // 16
|
| 70 |
+
sizes = [(H, H), (H//2, H//2), (H//4, H//4)]
|
| 71 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 72 |
+
locs = make_locations(sizes, strides)
|
| 73 |
+
|
| 74 |
+
all_f, all_cls, all_reg, all_ctr = [], [], [], []
|
| 75 |
+
seen = 0
|
| 76 |
+
for si in range(manifest["n_shards"]):
|
| 77 |
+
if seen >= n_images: break
|
| 78 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 79 |
+
map_location="cpu", weights_only=False)
|
| 80 |
+
for item in shard:
|
| 81 |
+
if seen >= n_images: break
|
| 82 |
+
sp = item["spatial"].unsqueeze(0).float()
|
| 83 |
+
boxes = item["boxes"]; labels = item["labels"]
|
| 84 |
+
cofibers = cofiber_decompose(sp, 3)
|
| 85 |
+
for sci, cof in enumerate(cofibers):
|
| 86 |
+
B, C, Hc, Wc = cof.shape
|
| 87 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 88 |
+
ct, rt, ctrt = assign_targets(locs[sci], boxes, labels, strides[sci], sr[sci])
|
| 89 |
+
pos = ct >= 0
|
| 90 |
+
if pos.any():
|
| 91 |
+
all_f.append(f[pos])
|
| 92 |
+
all_cls.append(ct[pos])
|
| 93 |
+
all_reg.append(rt[pos])
|
| 94 |
+
all_ctr.append(ctrt[pos])
|
| 95 |
+
seen += 1
|
| 96 |
+
del shard
|
| 97 |
+
if (si+1) % 5 == 0:
|
| 98 |
+
print(f" shard {si+1}: {seen} imgs, {sum(len(x) for x in all_f)} pos", flush=True)
|
| 99 |
+
|
| 100 |
+
features = torch.cat(all_f).to(DEVICE)
|
| 101 |
+
cls_targets = torch.cat(all_cls).to(DEVICE)
|
| 102 |
+
reg_targets = torch.cat(all_reg).to(DEVICE)
|
| 103 |
+
ctr_targets = torch.cat(all_ctr).to(DEVICE)
|
| 104 |
+
print(f" Train: {features.shape[0]} positives on GPU "
|
| 105 |
+
f"({features.element_size() * features.nelement() / 1e9:.1f} GB)")
|
| 106 |
+
return features, cls_targets, reg_targets, ctr_targets
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def load_val_features(n_images=5000):
|
| 110 |
+
"""Load val features + GT into GPU for eval."""
|
| 111 |
+
val = torch.load(VAL_CACHE, map_location="cpu", weights_only=False)
|
| 112 |
+
from pycocotools.coco import COCO
|
| 113 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 114 |
+
coco = COCO(ann_file)
|
| 115 |
+
cat_ids = sorted(coco.getCatIds())
|
| 116 |
+
cat_to_idx = {c: i for i, c in enumerate(cat_ids)}
|
| 117 |
+
idx_to_cat = {i: c for i, c in enumerate(cat_ids)}
|
| 118 |
+
|
| 119 |
+
strides = [16, 32, 64]; H = RESOLUTION // 16
|
| 120 |
+
sizes = [(H, H), (H//2, H//2), (H//4, H//4)]
|
| 121 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 122 |
+
locs = make_locations(sizes, strides)
|
| 123 |
+
all_locs = torch.cat(locs).to(DEVICE)
|
| 124 |
+
|
| 125 |
+
val_data = []
|
| 126 |
+
for idx in range(min(n_images, len(val))):
|
| 127 |
+
item = val[idx]
|
| 128 |
+
spatial = item["spatial"].unsqueeze(0).float()
|
| 129 |
+
img_id = int(item["img_id"]); scale = item["scale"]
|
| 130 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 131 |
+
f_all = []
|
| 132 |
+
for cof in cofibers:
|
| 133 |
+
B, C, Hc, Wc = cof.shape
|
| 134 |
+
f = F.layer_norm(cof.permute(0, 2, 3, 1).reshape(-1, C), [C])
|
| 135 |
+
f_all.append(f)
|
| 136 |
+
features = torch.cat(f_all).to(DEVICE)
|
| 137 |
+
val_data.append({"features": features, "img_id": img_id, "scale": scale})
|
| 138 |
+
|
| 139 |
+
print(f" Val: {len(val_data)} images on GPU")
|
| 140 |
+
return val_data, all_locs, idx_to_cat, coco
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def solve(features, cls_targets, reg_targets, ctr_targets, lam=0.1):
|
| 144 |
+
"""Solve for cls/reg/ctr weights on GPU."""
|
| 145 |
+
fd = features.shape[1]
|
| 146 |
+
n = features.shape[0]
|
| 147 |
+
fa = torch.cat([features, torch.ones(n, 1, device=DEVICE)], 1)
|
| 148 |
+
I = torch.eye(fd + 1, device=DEVICE)
|
| 149 |
+
XtX = fa.T @ fa
|
| 150 |
+
|
| 151 |
+
# Classification
|
| 152 |
+
y_cls = torch.zeros(n, NUM_CLASSES, device=DEVICE)
|
| 153 |
+
y_cls[torch.arange(n, device=DEVICE), cls_targets] = 1.0
|
| 154 |
+
cls_W = torch.linalg.solve(XtX + lam * I * n, fa.T @ y_cls)
|
| 155 |
+
|
| 156 |
+
# Regression (log-ltrb)
|
| 157 |
+
valid = (reg_targets > 0).all(1)
|
| 158 |
+
if valid.sum() > 10:
|
| 159 |
+
fv = fa[valid]
|
| 160 |
+
XtX_r = fv.T @ fv
|
| 161 |
+
reg_W = torch.linalg.solve(XtX_r + lam * torch.eye(fd+1, device=DEVICE) * valid.sum(),
|
| 162 |
+
fv.T @ torch.log(reg_targets[valid]))
|
| 163 |
+
else:
|
| 164 |
+
reg_W = torch.zeros(fd + 1, 4, device=DEVICE)
|
| 165 |
+
|
| 166 |
+
# Centerness
|
| 167 |
+
ctr_W = torch.linalg.solve(XtX + lam * I * n, fa.T @ ctr_targets.unsqueeze(1))
|
| 168 |
+
|
| 169 |
+
return cls_W, reg_W, ctr_W
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def eval_head(cls_W, reg_W, ctr_W, val_data, all_locs, idx_to_cat, coco_gt):
|
| 173 |
+
"""Run COCO eval for one head. Returns mAP."""
|
| 174 |
+
fd = cls_W.shape[0] - 1
|
| 175 |
+
all_results = []
|
| 176 |
+
for vd in val_data:
|
| 177 |
+
f = vd["features"]
|
| 178 |
+
if f.shape[1] != fd:
|
| 179 |
+
continue # skip if feature dim doesn't match
|
| 180 |
+
scores = (f @ cls_W[:fd] + cls_W[fd]).sigmoid()
|
| 181 |
+
reg = (f @ reg_W[:fd] + reg_W[fd]).exp()
|
| 182 |
+
ctr = (f @ ctr_W[:fd] + ctr_W[fd]).sigmoid().squeeze(1)
|
| 183 |
+
combined = scores * ctr.unsqueeze(1)
|
| 184 |
+
max_s, max_c = combined.max(1)
|
| 185 |
+
topk = min(100, max_s.shape[0])
|
| 186 |
+
top_s, top_i = max_s.topk(topk)
|
| 187 |
+
tc = max_c[top_i]; tr = reg[top_i]; tl = all_locs[top_i]
|
| 188 |
+
scale = vd["scale"]
|
| 189 |
+
x1 = (tl[:,0]-tr[:,0])/scale; y1 = (tl[:,1]-tr[:,1])/scale
|
| 190 |
+
x2 = (tl[:,0]+tr[:,2])/scale; y2 = (tl[:,1]+tr[:,3])/scale
|
| 191 |
+
w = (x2-x1).clamp(min=0); h = (y2-y1).clamp(min=0)
|
| 192 |
+
for i in range(topk):
|
| 193 |
+
s = top_s[i].item()
|
| 194 |
+
if s < 0.01: continue
|
| 195 |
+
all_results.append({"image_id": vd["img_id"],
|
| 196 |
+
"category_id": idx_to_cat[tc[i].item()],
|
| 197 |
+
"bbox": [x1[i].item(), y1[i].item(), w[i].item(), h[i].item()],
|
| 198 |
+
"score": s})
|
| 199 |
+
|
| 200 |
+
if not all_results:
|
| 201 |
+
return 0.0, 0.0, 0.0
|
| 202 |
+
from pycocotools.cocoeval import COCOeval
|
| 203 |
+
coco_dt = coco_gt.loadRes(all_results)
|
| 204 |
+
coco_eval = COCOeval(coco_gt, coco_dt, "bbox")
|
| 205 |
+
coco_eval.params.imgIds = sorted(coco_gt.getImgIds())[:len(val_data)]
|
| 206 |
+
coco_eval.evaluate(); coco_eval.accumulate(); coco_eval.summarize()
|
| 207 |
+
return coco_eval.stats[0], coco_eval.stats[1], coco_eval.stats[2]
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def main():
|
| 211 |
+
print("=" * 60)
|
| 212 |
+
print("Hyper-Batch Analytical Sweep (full GPU)")
|
| 213 |
+
print("=" * 60, flush=True)
|
| 214 |
+
|
| 215 |
+
# Load everything into VRAM
|
| 216 |
+
t0 = time.time()
|
| 217 |
+
print("\nLoading training features...", flush=True)
|
| 218 |
+
train_f, train_cls, train_reg, train_ctr = load_train_features(20000)
|
| 219 |
+
|
| 220 |
+
print("\nLoading val features...", flush=True)
|
| 221 |
+
val_data, all_locs, idx_to_cat, coco_gt = load_val_features(5000)
|
| 222 |
+
|
| 223 |
+
load_time = time.time() - t0
|
| 224 |
+
print(f"\nAll data on GPU in {load_time:.0f}s", flush=True)
|
| 225 |
+
print(f"GPU memory: {torch.cuda.memory_allocated()/1e9:.1f} GB / "
|
| 226 |
+
f"{torch.cuda.get_device_properties(0).total_memory/1e9:.1f} GB", flush=True)
|
| 227 |
+
|
| 228 |
+
results = []
|
| 229 |
+
|
| 230 |
+
# =====================================================
|
| 231 |
+
# Sweep lambda on raw 768 features
|
| 232 |
+
# =====================================================
|
| 233 |
+
print(f"\n--- Lambda sweep (768 raw) ---", flush=True)
|
| 234 |
+
for lam in [1e-4, 1e-3, 1e-2, 5e-2, 0.1, 0.2, 0.5, 1.0]:
|
| 235 |
+
t = time.time()
|
| 236 |
+
cls_W, reg_W, ctr_W = solve(train_f, train_cls, train_reg, train_ctr, lam)
|
| 237 |
+
mAP, mAP50, mAP75 = eval_head(cls_W, reg_W, ctr_W, val_data, all_locs, idx_to_cat, coco_gt)
|
| 238 |
+
elapsed = time.time() - t
|
| 239 |
+
print(f" lam={lam:6.4f}: mAP={mAP:.4f} mAP50={mAP50:.4f} mAP75={mAP75:.4f} [{elapsed:.1f}s]", flush=True)
|
| 240 |
+
results.append({"name": f"raw768_lam{lam}", "mAP": mAP, "mAP50": mAP50, "mAP75": mAP75,
|
| 241 |
+
"lam": lam, "dims": 768})
|
| 242 |
+
|
| 243 |
+
# Find best lambda
|
| 244 |
+
best_lam = max(results, key=lambda x: x["mAP"])["lam"]
|
| 245 |
+
print(f" Best lambda: {best_lam}", flush=True)
|
| 246 |
+
|
| 247 |
+
# =====================================================
|
| 248 |
+
# Feature variants at best lambda
|
| 249 |
+
# =====================================================
|
| 250 |
+
print(f"\n--- Feature variants (lam={best_lam}) ---", flush=True)
|
| 251 |
+
|
| 252 |
+
# Raw features (already done above, but include for completeness)
|
| 253 |
+
|
| 254 |
+
# L2-normalized features
|
| 255 |
+
f_l2 = F.normalize(train_f, p=2, dim=1)
|
| 256 |
+
cls_W, reg_W, ctr_W = solve(f_l2, train_cls, train_reg, train_ctr, best_lam)
|
| 257 |
+
# Need L2-normed val features too
|
| 258 |
+
val_l2 = []
|
| 259 |
+
for vd in val_data:
|
| 260 |
+
val_l2.append({**vd, "features": F.normalize(vd["features"], p=2, dim=1)})
|
| 261 |
+
mAP, mAP50, mAP75 = eval_head(cls_W, reg_W, ctr_W, val_l2, all_locs, idx_to_cat, coco_gt)
|
| 262 |
+
print(f" l2norm: mAP={mAP:.4f} mAP50={mAP50:.4f} mAP75={mAP75:.4f}", flush=True)
|
| 263 |
+
results.append({"name": "l2norm", "mAP": mAP, "mAP50": mAP50, "mAP75": mAP75, "dims": 768})
|
| 264 |
+
del val_l2
|
| 265 |
+
|
| 266 |
+
# PCA-reduced features
|
| 267 |
+
for K in [128, 256, 384, 512]:
|
| 268 |
+
# Compute PCA on training positives
|
| 269 |
+
mean = train_f.mean(0, keepdim=True)
|
| 270 |
+
centered = train_f - mean
|
| 271 |
+
# Use SVD on a subsample for speed
|
| 272 |
+
sub = centered[:50000]
|
| 273 |
+
U, S, Vh = torch.linalg.svd(sub, full_matrices=False)
|
| 274 |
+
proj = Vh[:K].T # (768, K)
|
| 275 |
+
f_pca = centered @ proj
|
| 276 |
+
cls_W, reg_W, ctr_W = solve(f_pca, train_cls, train_reg, train_ctr, best_lam)
|
| 277 |
+
val_pca = []
|
| 278 |
+
for vd in val_data:
|
| 279 |
+
val_pca.append({**vd, "features": (vd["features"] - mean) @ proj})
|
| 280 |
+
mAP, mAP50, mAP75 = eval_head(cls_W, reg_W, ctr_W, val_pca, all_locs, idx_to_cat, coco_gt)
|
| 281 |
+
n_params = K * NUM_CLASSES + NUM_CLASSES + K * 4 + 4 + K + 1
|
| 282 |
+
print(f" PCA-{K}: mAP={mAP:.4f} mAP50={mAP50:.4f} mAP75={mAP75:.4f} ({n_params} params)", flush=True)
|
| 283 |
+
results.append({"name": f"pca{K}", "mAP": mAP, "mAP50": mAP50, "mAP75": mAP75,
|
| 284 |
+
"dims": K, "params": n_params})
|
| 285 |
+
del val_pca
|
| 286 |
+
|
| 287 |
+
# =====================================================
|
| 288 |
+
# Summary
|
| 289 |
+
# =====================================================
|
| 290 |
+
print(f"\n{'='*60}")
|
| 291 |
+
print("Ranked by mAP:")
|
| 292 |
+
for r in sorted(results, key=lambda x: -x["mAP"]):
|
| 293 |
+
print(f" {r['name']:25s}: mAP={r['mAP']:.4f} mAP50={r.get('mAP50',0):.4f} "
|
| 294 |
+
f"mAP75={r.get('mAP75',0):.4f} dims={r.get('dims','?')}")
|
| 295 |
+
|
| 296 |
+
out = os.path.join(SCRIPT_DIR, "analytical_variants", "hyperbatch_results.json")
|
| 297 |
+
os.makedirs(os.path.dirname(out), exist_ok=True)
|
| 298 |
+
with open(out, "w") as f:
|
| 299 |
+
json.dump(results, f, indent=2)
|
| 300 |
+
print(f"\nSaved: {out}")
|
| 301 |
+
total = time.time() - t0
|
| 302 |
+
print(f"Total: {total:.0f}s for {len(results)} variants")
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
if __name__ == "__main__":
|
| 306 |
+
main()
|
analytical/scripts/analytical_one.py
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Build and evaluate one analytical detection head variant.
|
| 3 |
+
|
| 4 |
+
Usage:
|
| 5 |
+
python analytical_one.py --name baseline
|
| 6 |
+
python analytical_one.py --name whitened --transform zca
|
| 7 |
+
python analytical_one.py --name spatial3x3 --spatial mean3x3
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import argparse
|
| 11 |
+
import json
|
| 12 |
+
import math
|
| 13 |
+
import os
|
| 14 |
+
import sys
|
| 15 |
+
import time
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
import torch.nn.functional as F
|
| 19 |
+
import numpy as np
|
| 20 |
+
|
| 21 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 22 |
+
sys.path.insert(0, SCRIPT_DIR)
|
| 23 |
+
|
| 24 |
+
CACHE_DIR = os.environ.get("ARENA_CACHE_DIR", "feature_cache")
|
| 25 |
+
COCO_ROOT = os.environ.get("ARENA_COCO_ROOT", "coco")
|
| 26 |
+
VAL_CACHE = os.environ.get("ARENA_VAL_CACHE", "val_cache/val.pt")
|
| 27 |
+
STATS_DIR = os.path.join(SCRIPT_DIR, "analytical_stats_cache")
|
| 28 |
+
RESULTS_DIR = os.path.join(SCRIPT_DIR, "analytical_variants")
|
| 29 |
+
RESOLUTION = 640
|
| 30 |
+
NUM_CLASSES = 80
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def cofiber_decompose(f, n_scales):
|
| 34 |
+
cofibers = []
|
| 35 |
+
residual = f
|
| 36 |
+
for _ in range(n_scales - 1):
|
| 37 |
+
omega = F.avg_pool2d(residual, 2)
|
| 38 |
+
sigma_omega = F.interpolate(omega, size=residual.shape[2:], mode="bilinear", align_corners=False)
|
| 39 |
+
cofibers.append(residual - sigma_omega)
|
| 40 |
+
residual = omega
|
| 41 |
+
cofibers.append(residual)
|
| 42 |
+
return cofibers
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def make_locations(sizes, strides):
|
| 46 |
+
locs = []
|
| 47 |
+
for (h, w), s in zip(sizes, strides):
|
| 48 |
+
ys = (torch.arange(h, dtype=torch.float32) + 0.5) * s
|
| 49 |
+
xs = (torch.arange(w, dtype=torch.float32) + 0.5) * s
|
| 50 |
+
gy, gx = torch.meshgrid(ys, xs, indexing="ij")
|
| 51 |
+
locs.append(torch.stack([gx.flatten(), gy.flatten()], -1))
|
| 52 |
+
return locs
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def assign_targets(loc, boxes, labels, stride, sr):
|
| 56 |
+
n = loc.shape[0]
|
| 57 |
+
if boxes.numel() == 0:
|
| 58 |
+
return torch.full((n,), -1, dtype=torch.long), torch.zeros(n, 4), torch.zeros(n)
|
| 59 |
+
areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
| 60 |
+
l = loc[:, None, 0] - boxes[None, :, 0]
|
| 61 |
+
t = loc[:, None, 1] - boxes[None, :, 1]
|
| 62 |
+
r = boxes[None, :, 2] - loc[:, None, 0]
|
| 63 |
+
b = boxes[None, :, 3] - loc[:, None, 1]
|
| 64 |
+
ltrb = torch.stack([l, t, r, b], -1)
|
| 65 |
+
in_box = ltrb.min(-1).values > 0
|
| 66 |
+
cx = (boxes[:, 0] + boxes[:, 2]) / 2
|
| 67 |
+
cy = (boxes[:, 1] + boxes[:, 3]) / 2
|
| 68 |
+
rad = stride * 1.5
|
| 69 |
+
in_center = ((loc[:, None, 0] >= cx - rad) & (loc[:, None, 0] <= cx + rad) &
|
| 70 |
+
(loc[:, None, 1] >= cy - rad) & (loc[:, None, 1] <= cy + rad))
|
| 71 |
+
max_d = ltrb.max(-1).values
|
| 72 |
+
in_level = (max_d >= sr[0]) & (max_d <= sr[1])
|
| 73 |
+
pos = in_box & in_center & in_level
|
| 74 |
+
a = areas[None, :].expand_as(pos).clone()
|
| 75 |
+
a[~pos] = float("inf")
|
| 76 |
+
matched = a.argmin(1)
|
| 77 |
+
is_pos = a.gather(1, matched[:, None]).squeeze(1) < float("inf")
|
| 78 |
+
ct = torch.full((n,), -1, dtype=torch.long)
|
| 79 |
+
ct[is_pos] = labels[matched[is_pos]]
|
| 80 |
+
rt = torch.zeros(n, 4)
|
| 81 |
+
if is_pos.any():
|
| 82 |
+
rt[is_pos] = ltrb[torch.arange(n)[is_pos], matched[is_pos]]
|
| 83 |
+
ctrt = torch.zeros(n)
|
| 84 |
+
if is_pos.any():
|
| 85 |
+
lp, tp, rp, bp = rt[is_pos].unbind(-1)
|
| 86 |
+
ctrt[is_pos] = torch.sqrt(
|
| 87 |
+
(torch.minimum(lp, rp) / torch.maximum(lp, rp).clamp(min=1e-6)) *
|
| 88 |
+
(torch.minimum(tp, bp) / torch.maximum(tp, bp).clamp(min=1e-6)))
|
| 89 |
+
return ct, rt, ctrt
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
# ============================================================
|
| 93 |
+
# Feature transforms
|
| 94 |
+
# ============================================================
|
| 95 |
+
|
| 96 |
+
def transform_layernorm(f, C):
|
| 97 |
+
return F.layer_norm(f, [C])
|
| 98 |
+
|
| 99 |
+
def transform_raw(f, C):
|
| 100 |
+
return f
|
| 101 |
+
|
| 102 |
+
def transform_l2norm(f, C):
|
| 103 |
+
return F.normalize(f, p=2, dim=-1)
|
| 104 |
+
|
| 105 |
+
def transform_power05(f, C):
|
| 106 |
+
"""Signed power normalization: sign(x) * |x|^0.5, then L2 normalize."""
|
| 107 |
+
out = f.sign() * f.abs().sqrt()
|
| 108 |
+
return F.normalize(out, p=2, dim=-1)
|
| 109 |
+
|
| 110 |
+
def transform_power025(f, C):
|
| 111 |
+
"""Stronger compression: sign(x) * |x|^0.25."""
|
| 112 |
+
out = f.sign() * f.abs().pow(0.25)
|
| 113 |
+
return F.normalize(out, p=2, dim=-1)
|
| 114 |
+
|
| 115 |
+
TRANSFORMS = {
|
| 116 |
+
"layernorm": transform_layernorm,
|
| 117 |
+
"raw": transform_raw,
|
| 118 |
+
"l2norm": transform_l2norm,
|
| 119 |
+
"power05": transform_power05,
|
| 120 |
+
"power025": transform_power025,
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
# ============================================================
|
| 125 |
+
# Target encodings
|
| 126 |
+
# ============================================================
|
| 127 |
+
|
| 128 |
+
def encode_log_ltrb(ltrb):
|
| 129 |
+
valid = (ltrb > 0).all(1)
|
| 130 |
+
out = torch.zeros_like(ltrb)
|
| 131 |
+
if valid.any():
|
| 132 |
+
out[valid] = torch.log(ltrb[valid])
|
| 133 |
+
return out, valid
|
| 134 |
+
|
| 135 |
+
def encode_sqrt_ltrb(ltrb):
|
| 136 |
+
valid = (ltrb > 0).all(1)
|
| 137 |
+
out = torch.zeros_like(ltrb)
|
| 138 |
+
if valid.any():
|
| 139 |
+
out[valid] = torch.sqrt(ltrb[valid])
|
| 140 |
+
return out, valid
|
| 141 |
+
|
| 142 |
+
def encode_ltrb(ltrb):
|
| 143 |
+
valid = (ltrb > 0).all(1)
|
| 144 |
+
return ltrb, valid
|
| 145 |
+
|
| 146 |
+
def encode_corners(ltrb):
|
| 147 |
+
valid = (ltrb > 0).all(1)
|
| 148 |
+
return torch.stack([-ltrb[:, 0], -ltrb[:, 1], ltrb[:, 2], ltrb[:, 3]], 1), valid
|
| 149 |
+
|
| 150 |
+
def encode_center_size(ltrb):
|
| 151 |
+
valid = (ltrb > 0).all(1)
|
| 152 |
+
cx_off = (ltrb[:, 2] - ltrb[:, 0]) / 2
|
| 153 |
+
cy_off = (ltrb[:, 3] - ltrb[:, 1]) / 2
|
| 154 |
+
w = ltrb[:, 0] + ltrb[:, 2]
|
| 155 |
+
h = ltrb[:, 1] + ltrb[:, 3]
|
| 156 |
+
return torch.stack([cx_off, cy_off, w, h], 1), valid
|
| 157 |
+
|
| 158 |
+
ENCODINGS = {
|
| 159 |
+
"log_ltrb": encode_log_ltrb,
|
| 160 |
+
"sqrt_ltrb": encode_sqrt_ltrb,
|
| 161 |
+
"ltrb": encode_ltrb,
|
| 162 |
+
"corners": encode_corners,
|
| 163 |
+
"center_size": encode_center_size,
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
# ============================================================
|
| 168 |
+
# Spatial context modes
|
| 169 |
+
# ============================================================
|
| 170 |
+
|
| 171 |
+
def spatial_none(f_grid, B, H, W, C):
|
| 172 |
+
"""No spatial context. Per-token features only."""
|
| 173 |
+
return f_grid.reshape(-1, C)
|
| 174 |
+
|
| 175 |
+
def spatial_mean3x3(f_grid, B, H, W, C):
|
| 176 |
+
"""Replace each token with the mean of its 3x3 neighborhood."""
|
| 177 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 178 |
+
pooled = F.avg_pool2d(f_4d, 3, stride=1, padding=1)
|
| 179 |
+
return pooled.permute(0, 2, 3, 1).reshape(-1, C)
|
| 180 |
+
|
| 181 |
+
def spatial_cat_mean3x3(f_grid, B, H, W, C):
|
| 182 |
+
"""Concatenate: [center_token, mean_of_3x3_neighborhood]. 2*C dims."""
|
| 183 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 184 |
+
pooled = F.avg_pool2d(f_4d, 3, stride=1, padding=1)
|
| 185 |
+
center = f_grid.reshape(-1, C)
|
| 186 |
+
neighbor_mean = pooled.permute(0, 2, 3, 1).reshape(-1, C)
|
| 187 |
+
return torch.cat([center, neighbor_mean], dim=1)
|
| 188 |
+
|
| 189 |
+
def spatial_diff_neighbors(f_grid, B, H, W, C):
|
| 190 |
+
"""Center token + (center - neighbor_mean). Emphasizes local contrast."""
|
| 191 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 192 |
+
pooled = F.avg_pool2d(f_4d, 3, stride=1, padding=1)
|
| 193 |
+
center = f_grid.reshape(-1, C)
|
| 194 |
+
diff = center - pooled.permute(0, 2, 3, 1).reshape(-1, C)
|
| 195 |
+
return torch.cat([center, diff], dim=1)
|
| 196 |
+
|
| 197 |
+
def spatial_hv_neighbors(f_grid, B, H, W, C):
|
| 198 |
+
"""Center + horizontal mean + vertical mean. 3*C dims."""
|
| 199 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 200 |
+
h_pool = F.avg_pool2d(f_4d, (1, 3), stride=1, padding=(0, 1))
|
| 201 |
+
v_pool = F.avg_pool2d(f_4d, (3, 1), stride=1, padding=(1, 0))
|
| 202 |
+
center = f_grid.reshape(-1, C)
|
| 203 |
+
h_mean = h_pool.permute(0, 2, 3, 1).reshape(-1, C)
|
| 204 |
+
v_mean = v_pool.permute(0, 2, 3, 1).reshape(-1, C)
|
| 205 |
+
return torch.cat([center, h_mean, v_mean], dim=1)
|
| 206 |
+
|
| 207 |
+
def spatial_sheaf_h1(f_grid, B, H, W, C):
|
| 208 |
+
"""Sheaf H^1: directional edge differences (4 cardinal Cech 1-cocycles).
|
| 209 |
+
|
| 210 |
+
At each location, compute feature[here] - feature[neighbor] for all 4
|
| 211 |
+
cardinal directions. This is the Cech 1-cocycle representative on the
|
| 212 |
+
spatial grid. It captures gluing obstructions — exactly where local
|
| 213 |
+
feature sections fail to extend consistently. Object boundaries are
|
| 214 |
+
such obstructions.
|
| 215 |
+
|
| 216 |
+
Output: [center, d_up, d_down, d_left, d_right] = 5*C dims.
|
| 217 |
+
"""
|
| 218 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2) # (B, C, H, W)
|
| 219 |
+
# Shift in each direction and subtract
|
| 220 |
+
d_up = f_4d - F.pad(f_4d[:, :, 1:, :], (0, 0, 0, 1)) # diff with token above
|
| 221 |
+
d_down = f_4d - F.pad(f_4d[:, :, :-1, :], (0, 0, 1, 0)) # diff with token below
|
| 222 |
+
d_left = f_4d - F.pad(f_4d[:, :, :, 1:], (0, 1, 0, 0)) # diff with token left
|
| 223 |
+
d_right = f_4d - F.pad(f_4d[:, :, :, :-1], (1, 0, 0, 0)) # diff with token right
|
| 224 |
+
center = f_grid.reshape(-1, C)
|
| 225 |
+
du = d_up.permute(0, 2, 3, 1).reshape(-1, C)
|
| 226 |
+
dd = d_down.permute(0, 2, 3, 1).reshape(-1, C)
|
| 227 |
+
dl = d_left.permute(0, 2, 3, 1).reshape(-1, C)
|
| 228 |
+
dr = d_right.permute(0, 2, 3, 1).reshape(-1, C)
|
| 229 |
+
return torch.cat([center, du, dd, dl, dr], dim=1)
|
| 230 |
+
|
| 231 |
+
def spatial_sheaf_h1_compact(f_grid, B, H, W, C):
|
| 232 |
+
"""Sheaf H^1 compact: center + L1 norm of directional cocycles.
|
| 233 |
+
|
| 234 |
+
Instead of raw directional differences (5*C dims), compute the
|
| 235 |
+
L1 magnitude of each directional cocycle per channel. This gives a
|
| 236 |
+
scalar "boundary strength" per channel per direction.
|
| 237 |
+
Output: [center, |d_up|+|d_down|, |d_left|+|d_right|] = 3*C dims.
|
| 238 |
+
Vertical and horizontal boundary strengths.
|
| 239 |
+
"""
|
| 240 |
+
f_4d = f_grid.reshape(B, H, W, C).permute(0, 3, 1, 2)
|
| 241 |
+
d_up = f_4d - F.pad(f_4d[:, :, 1:, :], (0, 0, 0, 1))
|
| 242 |
+
d_down = f_4d - F.pad(f_4d[:, :, :-1, :], (0, 0, 1, 0))
|
| 243 |
+
d_left = f_4d - F.pad(f_4d[:, :, :, 1:], (0, 1, 0, 0))
|
| 244 |
+
d_right = f_4d - F.pad(f_4d[:, :, :, :-1], (1, 0, 0, 0))
|
| 245 |
+
center = f_grid.reshape(-1, C)
|
| 246 |
+
v_boundary = (d_up.abs() + d_down.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 247 |
+
h_boundary = (d_left.abs() + d_right.abs()).permute(0, 2, 3, 1).reshape(-1, C)
|
| 248 |
+
return torch.cat([center, v_boundary, h_boundary], dim=1)
|
| 249 |
+
|
| 250 |
+
SPATIAL = {
|
| 251 |
+
"none": spatial_none,
|
| 252 |
+
"mean3x3": spatial_mean3x3,
|
| 253 |
+
"cat_mean3x3": spatial_cat_mean3x3,
|
| 254 |
+
"diff_neighbors": spatial_diff_neighbors,
|
| 255 |
+
"hv_neighbors": spatial_hv_neighbors,
|
| 256 |
+
"sheaf_h1": spatial_sheaf_h1,
|
| 257 |
+
"sheaf_h1_compact": spatial_sheaf_h1_compact,
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
# ============================================================
|
| 262 |
+
# Core: accumulate, solve, evaluate
|
| 263 |
+
# ============================================================
|
| 264 |
+
|
| 265 |
+
def accumulate(n_images, transform_name, encoding_name, spatial_name, per_scale=False, neg_ratio=0.0):
|
| 266 |
+
"""Accumulate XtX/XtY from cached features."""
|
| 267 |
+
manifest = json.load(open(os.path.join(CACHE_DIR, "manifest.json")))
|
| 268 |
+
n_shards = manifest["n_shards"]
|
| 269 |
+
strides = [16, 32, 64]
|
| 270 |
+
H = RESOLUTION // 16
|
| 271 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 272 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 273 |
+
locs = make_locations(sizes, strides)
|
| 274 |
+
transform_fn = TRANSFORMS[transform_name]
|
| 275 |
+
encode_fn = ENCODINGS[encoding_name]
|
| 276 |
+
spatial_fn = SPATIAL[spatial_name]
|
| 277 |
+
|
| 278 |
+
# Determine feature dim
|
| 279 |
+
test_f = torch.randn(1, 768)
|
| 280 |
+
test_t = transform_fn(test_f, 768)
|
| 281 |
+
test_s = spatial_fn(test_t.unsqueeze(0), 1, 1, 1, test_t.shape[-1])
|
| 282 |
+
feat_dim = test_s.shape[-1]
|
| 283 |
+
|
| 284 |
+
n_scales = 3 if not per_scale else 1
|
| 285 |
+
scale_range = range(3) if not per_scale else [0]
|
| 286 |
+
|
| 287 |
+
cls_XtX = torch.zeros(feat_dim + 1, feat_dim + 1)
|
| 288 |
+
cls_XtY = torch.zeros(feat_dim + 1, NUM_CLASSES)
|
| 289 |
+
reg_XtX = torch.zeros(feat_dim + 1, feat_dim + 1)
|
| 290 |
+
reg_XtY = torch.zeros(feat_dim + 1, 4)
|
| 291 |
+
ctr_XtX = torch.zeros(feat_dim + 1, feat_dim + 1)
|
| 292 |
+
ctr_XtY = torch.zeros(feat_dim + 1, 1)
|
| 293 |
+
n_pos = 0
|
| 294 |
+
seen = 0
|
| 295 |
+
t0 = time.time()
|
| 296 |
+
|
| 297 |
+
for si in range(n_shards):
|
| 298 |
+
if seen >= n_images:
|
| 299 |
+
break
|
| 300 |
+
shard = torch.load(os.path.join(CACHE_DIR, f"shard_{si:04d}.pt"),
|
| 301 |
+
map_location="cpu", weights_only=False)
|
| 302 |
+
for item in shard:
|
| 303 |
+
if seen >= n_images:
|
| 304 |
+
break
|
| 305 |
+
sp = item["spatial"].unsqueeze(0).float()
|
| 306 |
+
boxes = item["boxes"]
|
| 307 |
+
labels = item["labels"]
|
| 308 |
+
cofibers = cofiber_decompose(sp, 3)
|
| 309 |
+
for sci in range(3):
|
| 310 |
+
cof = cofibers[sci]
|
| 311 |
+
B, C, Hc, Wc = cof.shape
|
| 312 |
+
f_raw = cof.permute(0, 2, 3, 1).reshape(-1, C)
|
| 313 |
+
f = transform_fn(f_raw, C)
|
| 314 |
+
f_spatial = spatial_fn(f.unsqueeze(0) if f.dim() == 2 else f,
|
| 315 |
+
B, Hc, Wc, f.shape[-1] if f.dim() == 2 else C)
|
| 316 |
+
ct, rt, ctrt = assign_targets(locs[sci], boxes, labels, strides[sci], sr[sci])
|
| 317 |
+
pos = ct >= 0
|
| 318 |
+
if not pos.any():
|
| 319 |
+
continue
|
| 320 |
+
fp = f_spatial[pos]
|
| 321 |
+
fa = torch.cat([fp, torch.ones(fp.shape[0], 1)], 1)
|
| 322 |
+
y_cls = torch.zeros(fp.shape[0], NUM_CLASSES)
|
| 323 |
+
y_cls[torch.arange(fp.shape[0]), ct[pos]] = 1.0
|
| 324 |
+
cls_XtX += fa.T @ fa
|
| 325 |
+
cls_XtY += fa.T @ y_cls
|
| 326 |
+
reg_y, valid = encode_fn(rt[pos])
|
| 327 |
+
if valid.any():
|
| 328 |
+
fr = fa[valid]
|
| 329 |
+
reg_XtX += fr.T @ fr
|
| 330 |
+
reg_XtY += fr.T @ reg_y[valid]
|
| 331 |
+
ctr_XtX += fa.T @ fa
|
| 332 |
+
ctr_XtY += fa.T @ ctrt[pos].unsqueeze(1)
|
| 333 |
+
n_pos += pos.sum().item()
|
| 334 |
+
|
| 335 |
+
# Negative samples for classification (target = all zeros)
|
| 336 |
+
if neg_ratio > 0:
|
| 337 |
+
neg = ct < 0
|
| 338 |
+
n_neg_want = int(pos.sum().item() * neg_ratio)
|
| 339 |
+
if neg.any() and n_neg_want > 0:
|
| 340 |
+
neg_idx = neg.nonzero(as_tuple=True)[0]
|
| 341 |
+
if len(neg_idx) > n_neg_want:
|
| 342 |
+
neg_idx = neg_idx[torch.randperm(len(neg_idx))[:n_neg_want]]
|
| 343 |
+
fn = f_spatial[neg_idx]
|
| 344 |
+
fn_aug = torch.cat([fn, torch.ones(fn.shape[0], 1)], 1)
|
| 345 |
+
cls_XtX += fn_aug.T @ fn_aug
|
| 346 |
+
cls_XtY += fn_aug.T @ torch.zeros(fn.shape[0], NUM_CLASSES)
|
| 347 |
+
seen += 1
|
| 348 |
+
del shard
|
| 349 |
+
if (si + 1) % 5 == 0:
|
| 350 |
+
elapsed = time.time() - t0
|
| 351 |
+
print(f" shard {si+1}: {seen} imgs, {n_pos} pos, {elapsed:.0f}s", flush=True)
|
| 352 |
+
|
| 353 |
+
return {"cls_XtX": cls_XtX, "cls_XtY": cls_XtY, "reg_XtX": reg_XtX, "reg_XtY": reg_XtY,
|
| 354 |
+
"ctr_XtX": ctr_XtX, "ctr_XtY": ctr_XtY, "n_pos": n_pos, "feat_dim": feat_dim,
|
| 355 |
+
"n_images": seen, "elapsed": time.time() - t0}
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
def solve(stats, lam):
|
| 359 |
+
fd = stats["feat_dim"]
|
| 360 |
+
n = stats["n_pos"]
|
| 361 |
+
I = torch.eye(fd + 1)
|
| 362 |
+
cls_W = torch.linalg.solve(stats["cls_XtX"] + lam * I * n, stats["cls_XtY"])
|
| 363 |
+
reg_W = torch.linalg.solve(stats["reg_XtX"] + lam * I * n, stats["reg_XtY"])
|
| 364 |
+
ctr_W = torch.linalg.solve(stats["ctr_XtX"] + lam * I * n, stats["ctr_XtY"])
|
| 365 |
+
return {"cls_w": cls_W[:fd].T, "cls_b": cls_W[fd],
|
| 366 |
+
"reg_w": reg_W[:fd].T, "reg_b": reg_W[fd],
|
| 367 |
+
"ctr_w": ctr_W[:fd].T, "ctr_b": ctr_W[fd],
|
| 368 |
+
"feat_dim": fd}
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
def evaluate(head, val_path, transform_name, spatial_name, encoding_name="log_ltrb", n_images=500):
|
| 372 |
+
"""Evaluate on val set. CPU-only. Returns metrics dict."""
|
| 373 |
+
val = torch.load(val_path, map_location="cpu", weights_only=False)
|
| 374 |
+
encode_fn = ENCODINGS[encoding_name]
|
| 375 |
+
|
| 376 |
+
# Load COCO GT
|
| 377 |
+
from pycocotools.coco import COCO
|
| 378 |
+
ann_file = os.path.join(COCO_ROOT, "annotations", "instances_val2017.json")
|
| 379 |
+
coco = COCO(ann_file)
|
| 380 |
+
cat_ids = sorted(coco.getCatIds())
|
| 381 |
+
cat_to_idx = {c: i for i, c in enumerate(cat_ids)}
|
| 382 |
+
|
| 383 |
+
transform_fn = TRANSFORMS[transform_name]
|
| 384 |
+
spatial_fn = SPATIAL[spatial_name]
|
| 385 |
+
strides = [16, 32, 64]
|
| 386 |
+
H = RESOLUTION // 16
|
| 387 |
+
sizes = [(H, H), (H // 2, H // 2), (H // 4, H // 4)]
|
| 388 |
+
sr = [(-1, 128), (128, 256), (256, float("inf"))]
|
| 389 |
+
locs = make_locations(sizes, strides)
|
| 390 |
+
|
| 391 |
+
correct = 0
|
| 392 |
+
n_pos_total = 0
|
| 393 |
+
n_det = 0
|
| 394 |
+
true_det = 0
|
| 395 |
+
reg_errors = []
|
| 396 |
+
|
| 397 |
+
for idx in range(min(n_images, len(val))):
|
| 398 |
+
item = val[idx]
|
| 399 |
+
spatial = item["spatial"].unsqueeze(0).float()
|
| 400 |
+
img_id = item["img_id"]
|
| 401 |
+
scale = item["scale"]
|
| 402 |
+
|
| 403 |
+
ann_ids = coco.getAnnIds(imgIds=int(img_id), iscrowd=False)
|
| 404 |
+
anns = coco.loadAnns(ann_ids)
|
| 405 |
+
boxes = []
|
| 406 |
+
labels = []
|
| 407 |
+
for ann in anns:
|
| 408 |
+
x, y, w, h = ann["bbox"]
|
| 409 |
+
if w < 1 or h < 1:
|
| 410 |
+
continue
|
| 411 |
+
boxes.append([x * scale, y * scale, (x + w) * scale, (y + h) * scale])
|
| 412 |
+
labels.append(cat_to_idx[ann["category_id"]])
|
| 413 |
+
boxes_t = torch.tensor(boxes, dtype=torch.float32) if boxes else torch.zeros(0, 4)
|
| 414 |
+
labels_t = torch.tensor(labels, dtype=torch.long) if labels else torch.zeros(0, dtype=torch.long)
|
| 415 |
+
|
| 416 |
+
cofibers = cofiber_decompose(spatial, 3)
|
| 417 |
+
for sci, cof in enumerate(cofibers):
|
| 418 |
+
B, C, Hc, Wc = cof.shape
|
| 419 |
+
f_raw = cof.permute(0, 2, 3, 1).reshape(-1, C)
|
| 420 |
+
f = transform_fn(f_raw, C)
|
| 421 |
+
f_s = spatial_fn(f.unsqueeze(0), B, Hc, Wc, f.shape[-1])
|
| 422 |
+
|
| 423 |
+
ct, rt, _ = assign_targets(locs[sci], boxes_t, labels_t, strides[sci], sr[sci])
|
| 424 |
+
pos = ct >= 0
|
| 425 |
+
|
| 426 |
+
# Classification
|
| 427 |
+
scores = f_s @ head["cls_w"].T + head["cls_b"]
|
| 428 |
+
pred_cls = scores.argmax(1)
|
| 429 |
+
pred_conf = scores.sigmoid().max(1).values
|
| 430 |
+
|
| 431 |
+
if pos.any():
|
| 432 |
+
correct += (pred_cls[pos] == ct[pos]).sum().item()
|
| 433 |
+
n_pos_total += pos.sum().item()
|
| 434 |
+
|
| 435 |
+
# Detection count
|
| 436 |
+
det = pred_conf > 0.3
|
| 437 |
+
n_det += det.sum().item()
|
| 438 |
+
true_det += (det & pos).sum().item()
|
| 439 |
+
|
| 440 |
+
# Regression quality (in encoded target space — comparable across encodings)
|
| 441 |
+
if pos.any():
|
| 442 |
+
pred_reg = f_s[pos] @ head["reg_w"].T + head["reg_b"]
|
| 443 |
+
gt_ltrb = rt[pos]
|
| 444 |
+
valid = (gt_ltrb > 0).all(1)
|
| 445 |
+
if valid.any():
|
| 446 |
+
gt_encoded, _ = encode_fn(gt_ltrb[valid])
|
| 447 |
+
pred_encoded = pred_reg[valid]
|
| 448 |
+
mse = ((pred_encoded - gt_encoded) ** 2).mean(1)
|
| 449 |
+
# Convert to quality: 1 / (1 + mse), bounded in [0, 1]
|
| 450 |
+
quality = (1.0 / (1.0 + mse)).tolist()
|
| 451 |
+
reg_errors.extend(quality)
|
| 452 |
+
|
| 453 |
+
cls_acc = correct / max(n_pos_total, 1)
|
| 454 |
+
precision = true_det / max(n_det, 1)
|
| 455 |
+
reg_quality = sum(reg_errors) / max(len(reg_errors), 1) # mean quality in [0, 1]
|
| 456 |
+
n_params = (head["cls_w"].numel() + head["cls_b"].numel() +
|
| 457 |
+
head["reg_w"].numel() + head["reg_b"].numel() +
|
| 458 |
+
head["ctr_w"].numel() + head["ctr_b"].numel())
|
| 459 |
+
|
| 460 |
+
return {
|
| 461 |
+
"cls_accuracy": round(cls_acc, 4),
|
| 462 |
+
"precision": round(precision, 4),
|
| 463 |
+
"reg_quality": round(reg_quality, 4),
|
| 464 |
+
"n_detections": n_det,
|
| 465 |
+
"n_positives": n_pos_total,
|
| 466 |
+
"n_params": n_params,
|
| 467 |
+
"composite": round(cls_acc * 0.5 + precision * 0.25 + reg_quality * 0.25, 4),
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
|
| 471 |
+
def main():
|
| 472 |
+
parser = argparse.ArgumentParser()
|
| 473 |
+
parser.add_argument("--name", required=True, help="Variant name")
|
| 474 |
+
parser.add_argument("--transform", default="layernorm", choices=list(TRANSFORMS.keys()))
|
| 475 |
+
parser.add_argument("--encoding", default="log_ltrb", choices=list(ENCODINGS.keys()))
|
| 476 |
+
parser.add_argument("--spatial", default="none", choices=list(SPATIAL.keys()))
|
| 477 |
+
parser.add_argument("--lam", type=float, default=1e-3)
|
| 478 |
+
parser.add_argument("--n-train", type=int, default=10000)
|
| 479 |
+
parser.add_argument("--n-eval", type=int, default=500)
|
| 480 |
+
parser.add_argument("--neg-ratio", type=float, default=0.0,
|
| 481 |
+
help="Ratio of negative to positive samples for classification (0=positives only)")
|
| 482 |
+
parser.add_argument("--notes", default="", help="Why this variant exists")
|
| 483 |
+
args = parser.parse_args()
|
| 484 |
+
|
| 485 |
+
os.makedirs(RESULTS_DIR, exist_ok=True)
|
| 486 |
+
os.makedirs(STATS_DIR, exist_ok=True)
|
| 487 |
+
|
| 488 |
+
print(f"{'='*60}")
|
| 489 |
+
print(f"Variant: {args.name}")
|
| 490 |
+
print(f" transform={args.transform} encoding={args.encoding} spatial={args.spatial} lam={args.lam}")
|
| 491 |
+
if args.notes:
|
| 492 |
+
print(f" rationale: {args.notes}")
|
| 493 |
+
print(f"{'='*60}", flush=True)
|
| 494 |
+
|
| 495 |
+
# Check for cached stats
|
| 496 |
+
neg_tag = f"_neg{args.neg_ratio}" if args.neg_ratio > 0 else ""
|
| 497 |
+
cache_key = f"stats_s3_{args.transform}_{args.encoding}_{args.spatial}_{args.n_train}{neg_tag}"
|
| 498 |
+
cache_path = os.path.join(STATS_DIR, f"{cache_key}.pt")
|
| 499 |
+
if os.path.isfile(cache_path):
|
| 500 |
+
print(f" Loading cached stats: {cache_key}", flush=True)
|
| 501 |
+
stats = torch.load(cache_path, map_location="cpu", weights_only=False)
|
| 502 |
+
else:
|
| 503 |
+
print(f" Accumulating...", flush=True)
|
| 504 |
+
stats = accumulate(args.n_train, args.transform, args.encoding, args.spatial,
|
| 505 |
+
neg_ratio=args.neg_ratio)
|
| 506 |
+
torch.save(stats, cache_path)
|
| 507 |
+
print(f" Cached: {cache_path}", flush=True)
|
| 508 |
+
|
| 509 |
+
print(f" {stats['n_pos']} positives, feat_dim={stats['feat_dim']}", flush=True)
|
| 510 |
+
|
| 511 |
+
# Solve
|
| 512 |
+
t0 = time.time()
|
| 513 |
+
head = solve(stats, args.lam)
|
| 514 |
+
solve_time = time.time() - t0
|
| 515 |
+
print(f" Solved in {solve_time*1000:.0f}ms", flush=True)
|
| 516 |
+
|
| 517 |
+
# Evaluate
|
| 518 |
+
print(f" Evaluating ({args.n_eval} images)...", flush=True)
|
| 519 |
+
t0 = time.time()
|
| 520 |
+
metrics = evaluate(head, VAL_CACHE, args.transform, args.spatial, args.encoding, args.n_eval)
|
| 521 |
+
eval_time = time.time() - t0
|
| 522 |
+
|
| 523 |
+
print(f"\n Results:")
|
| 524 |
+
print(f" cls_accuracy: {metrics['cls_accuracy']}")
|
| 525 |
+
print(f" precision: {metrics['precision']}")
|
| 526 |
+
print(f" reg_quality: {metrics['reg_quality']}")
|
| 527 |
+
print(f" composite: {metrics['composite']}")
|
| 528 |
+
print(f" params: {metrics['n_params']}")
|
| 529 |
+
print(f" eval time: {eval_time:.1f}s")
|
| 530 |
+
|
| 531 |
+
# Save
|
| 532 |
+
result = {
|
| 533 |
+
"name": args.name,
|
| 534 |
+
"config": {"transform": args.transform, "encoding": args.encoding,
|
| 535 |
+
"spatial": args.spatial, "lam": args.lam,
|
| 536 |
+
"n_train": args.n_train, "n_eval": args.n_eval},
|
| 537 |
+
"notes": args.notes,
|
| 538 |
+
"metrics": metrics,
|
| 539 |
+
"solve_time_ms": round(solve_time * 1000),
|
| 540 |
+
"eval_time_s": round(eval_time, 1),
|
| 541 |
+
}
|
| 542 |
+
result_path = os.path.join(RESULTS_DIR, f"{args.name}.json")
|
| 543 |
+
with open(result_path, "w") as f:
|
| 544 |
+
json.dump(result, f, indent=2)
|
| 545 |
+
print(f"\n Saved: {result_path}")
|
| 546 |
+
|
| 547 |
+
|
| 548 |
+
if __name__ == "__main__":
|
| 549 |
+
main()
|
analytical/variants/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Analytical Variants
|
| 2 |
+
|
| 3 |
+
Systematic exploration of analytically-derived detection heads on frozen EUPE-ViT-B features. Every weight is computed from closed-form least-squares — no gradient steps.
|
| 4 |
+
|
| 5 |
+
## Method
|
| 6 |
+
|
| 7 |
+
Given cached backbone features X at positive spatial locations and target matrix Y:
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
W = (X^T X + λI)^{-1} X^T Y
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
Classification, regression, and centerness are solved independently. One pass over the training data accumulates sufficient statistics (X^T X, X^T Y), then one matrix inverse per task produces the optimal linear weights.
|
| 14 |
+
|
| 15 |
+
## Greedy Feature Selection
|
| 16 |
+
|
| 17 |
+
Starting from zero dimensions, greedily add the single feature channel that maximizes classification accuracy. The ordering reveals which backbone dimensions carry the most detection-relevant information.
|
| 18 |
+
|
| 19 |
+
Top 10 most important dimensions (EUPE-ViT-B): 665, 642, 200, 305, 498, 628, 67, 562, 426, 723.
|
| 20 |
+
|
| 21 |
+
One dimension (dim 665) achieves 31.1% person classification accuracy. 100 dimensions reach 50.6%.
|
| 22 |
+
|
| 23 |
+
Results: `greedy_forward_gpu.json`
|
| 24 |
+
|
| 25 |
+
## Evolved Circuits
|
| 26 |
+
|
| 27 |
+
Evolutionary search over feature dimension subsets using batched GPU fitness evaluation. Population of 512 individuals, fixed-K genomes, tournament selection, uniform crossover, adaptive mutation. Fitness is F1 score from analytical person-vs-background classification.
|
| 28 |
+
|
| 29 |
+
At 200 gen/s on GPU, 5000 generations complete in 25 seconds.
|
| 30 |
+
|
| 31 |
+
| Dims | Gates | Greedy F1 | Evolved F1 | Speedup |
|
| 32 |
+
|------|-------|-----------|------------|---------|
|
| 33 |
+
| 10 | 850 | 0.628 | 0.761 | +21% |
|
| 34 |
+
| 20 | 1700 | 0.646 | 0.775 | +20% |
|
| 35 |
+
| 50 | 4250 | 0.696 | 0.801 | +15% |
|
| 36 |
+
| 100 | 8500 | 0.728 | 0.823 | +13% |
|
| 37 |
+
| 200 | 17000 | — | 0.832 | — |
|
| 38 |
+
| 300 | 25500 | — | 0.845 | — |
|
| 39 |
+
|
| 40 |
+
The evolved 10-dim circuit (850 gates) outperforms the greedy 100-dim circuit (8500 gates). Evolution finds synergistic dimension combinations that greedy selection is structurally blind to.
|
| 41 |
+
|
| 42 |
+
Linear person detection ceiling: F1 ~ 0.846 at ~300 dims.
|
| 43 |
+
|
| 44 |
+
Results: `evolved_extreme.json` in `circuit/`
|
| 45 |
+
|
| 46 |
+
## Exotic Features
|
| 47 |
+
|
| 48 |
+
Tested on classification and regression independently:
|
| 49 |
+
|
| 50 |
+
**Classification** (69.6% baseline at 768 dims):
|
| 51 |
+
- Random Fourier Features (RBF kernel approximation): no improvement over raw features
|
| 52 |
+
- Quadratic cross-terms on top-30 greedy dims: 58.4% at 495 dims
|
| 53 |
+
- Random projections K=200: 56.2% at 200 dims
|
| 54 |
+
- Conclusion: raw LayerNorm'd features are already optimal for linear classification
|
| 55 |
+
|
| 56 |
+
**Regression** (0.626 baseline quality):
|
| 57 |
+
- Sheaf H^1 boundary features (vertical + horizontal): 0.687 (+9.7%)
|
| 58 |
+
- H^1 + quadratic combined: 0.698 (+11.5%)
|
| 59 |
+
- Random Fourier Features: 0.654 (+4.5%)
|
| 60 |
+
- Conclusion: directional boundary information (Cech 1-cocycles) is the most useful addition for localization
|
| 61 |
+
|
| 62 |
+
Results: `exotic_gpu.json`, `exotic_reg_gpu.json`
|
| 63 |
+
|
| 64 |
+
## Spatial Context Variants
|
| 65 |
+
|
| 66 |
+
Tested via the `analytical_one.py` single-variant builder:
|
| 67 |
+
|
| 68 |
+
| Variant | Classification | Regression | Composite |
|
| 69 |
+
|---------|---------------|------------|-----------|
|
| 70 |
+
| Per-token baseline | 64.3% | — | 0.327 |
|
| 71 |
+
| + 3x3 neighbor mean | 72.9% | 2.2% | 0.375 |
|
| 72 |
+
| + high regularization (λ=0.1) | 71.2% | 62.9% | 0.518 |
|
| 73 |
+
| + sheaf H^1 compact | 74.3% | 65.5% | 0.540 |
|
| 74 |
+
|
| 75 |
+
Spatial context is essential: +8.6 points classification, unlocks nonzero regression.
|
| 76 |
+
|
| 77 |
+
Results: `v001_baseline.json` through `v009_sheaf_h1_compact.json`
|
analytical/variants/exotic_gpu.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"name": "baseline_768",
|
| 4 |
+
"acc": 0.6955374502360893,
|
| 5 |
+
"dims": 768
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
"name": "random_proj_K10",
|
| 9 |
+
"acc": 0.31700768447365985,
|
| 10 |
+
"dims": 10,
|
| 11 |
+
"params": 880,
|
| 12 |
+
"seed": 139
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"name": "random_proj_K20",
|
| 16 |
+
"acc": 0.3226553096935469,
|
| 17 |
+
"dims": 20,
|
| 18 |
+
"params": 1680,
|
| 19 |
+
"seed": 133
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"name": "random_proj_K50",
|
| 23 |
+
"acc": 0.3812147023423757,
|
| 24 |
+
"dims": 50,
|
| 25 |
+
"params": 4080,
|
| 26 |
+
"seed": 166
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"name": "random_proj_K100",
|
| 30 |
+
"acc": 0.46180909175076384,
|
| 31 |
+
"dims": 100,
|
| 32 |
+
"params": 8080,
|
| 33 |
+
"seed": 405
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"name": "random_proj_K200",
|
| 37 |
+
"acc": 0.5620775854087584,
|
| 38 |
+
"dims": 200,
|
| 39 |
+
"params": 16080,
|
| 40 |
+
"seed": 335
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"name": "quadratic_top5",
|
| 44 |
+
"acc": 0.33223775576335524,
|
| 45 |
+
"dims": 20,
|
| 46 |
+
"params": 1680
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"name": "quadratic_top10",
|
| 50 |
+
"acc": 0.37172484029256553,
|
| 51 |
+
"dims": 65,
|
| 52 |
+
"params": 5280
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"name": "quadratic_top20",
|
| 56 |
+
"acc": 0.478751967410425,
|
| 57 |
+
"dims": 230,
|
| 58 |
+
"params": 18480
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"name": "quadratic_top30",
|
| 62 |
+
"acc": 0.5839274141283215,
|
| 63 |
+
"dims": 495,
|
| 64 |
+
"params": 39680
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"name": "rff_50",
|
| 68 |
+
"acc": 0.6925747615961485,
|
| 69 |
+
"dims": 818,
|
| 70 |
+
"params": 65520
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"name": "rff_100",
|
| 74 |
+
"acc": 0.6932228497361356,
|
| 75 |
+
"dims": 868,
|
| 76 |
+
"params": 69520
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"name": "rff_200",
|
| 80 |
+
"acc": 0.6938246458661235,
|
| 81 |
+
"dims": 968,
|
| 82 |
+
"params": 77520
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"name": "rff_500",
|
| 86 |
+
"acc": 0.6935006017961299,
|
| 87 |
+
"dims": 1268,
|
| 88 |
+
"params": 101520
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"name": "pure_rff_200",
|
| 92 |
+
"acc": 0.30654569021386907,
|
| 93 |
+
"dims": 200,
|
| 94 |
+
"params": 16080
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"name": "pure_rff_500",
|
| 98 |
+
"acc": 0.30654569021386907,
|
| 99 |
+
"dims": 500,
|
| 100 |
+
"params": 40080
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"name": "pure_rff_1000",
|
| 104 |
+
"acc": 0.30654569021386907,
|
| 105 |
+
"dims": 1000,
|
| 106 |
+
"params": 80080
|
| 107 |
+
}
|
| 108 |
+
]
|
analytical/variants/exotic_reg_gpu.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"name": "baseline_768",
|
| 4 |
+
"reg_quality": 0.62624591588974,
|
| 5 |
+
"dims": 768
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
"name": "h1_h1v",
|
| 9 |
+
"reg_quality": 0.6452575325965881,
|
| 10 |
+
"dims": 1536
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"name": "h1_h1h",
|
| 14 |
+
"reg_quality": 0.644087016582489,
|
| 15 |
+
"dims": 1536
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"name": "h1_h1_both",
|
| 19 |
+
"reg_quality": 0.6874305009841919,
|
| 20 |
+
"dims": 2304
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"name": "quad_top10",
|
| 24 |
+
"reg_quality": 0.6080746650695801,
|
| 25 |
+
"dims": 823
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"name": "quad_top20",
|
| 29 |
+
"reg_quality": 0.6147602796554565,
|
| 30 |
+
"dims": 978
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"name": "quad_top30",
|
| 34 |
+
"reg_quality": 0.6256624460220337,
|
| 35 |
+
"dims": 1233
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"name": "h1_quad_combined",
|
| 39 |
+
"reg_quality": 0.697516143321991,
|
| 40 |
+
"dims": 2514
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"name": "rff_100_reg",
|
| 44 |
+
"reg_quality": 0.6526749134063721,
|
| 45 |
+
"dims": 868
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"name": "rff_500_reg",
|
| 49 |
+
"reg_quality": 0.6537668108940125,
|
| 50 |
+
"dims": 1268
|
| 51 |
+
}
|
| 52 |
+
]
|
analytical/variants/fractal_results.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"name": "standard_3band",
|
| 4 |
+
"mAP": 0.006765868258664371,
|
| 5 |
+
"bands": 3
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
"name": "fractal_depth2",
|
| 9 |
+
"mAP": 0.006765392609810458,
|
| 10 |
+
"bands": 4
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"name": "fractal_depth3",
|
| 14 |
+
"mAP": 0.007137951141558296,
|
| 15 |
+
"bands": 8
|
| 16 |
+
}
|
| 17 |
+
]
|
analytical/variants/greedy_forward_gpu.json
ADDED
|
@@ -0,0 +1,809 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"selected_dims": [
|
| 3 |
+
665,
|
| 4 |
+
642,
|
| 5 |
+
200,
|
| 6 |
+
305,
|
| 7 |
+
498,
|
| 8 |
+
628,
|
| 9 |
+
67,
|
| 10 |
+
562,
|
| 11 |
+
426,
|
| 12 |
+
723,
|
| 13 |
+
177,
|
| 14 |
+
11,
|
| 15 |
+
465,
|
| 16 |
+
555,
|
| 17 |
+
52,
|
| 18 |
+
179,
|
| 19 |
+
325,
|
| 20 |
+
600,
|
| 21 |
+
738,
|
| 22 |
+
389,
|
| 23 |
+
660,
|
| 24 |
+
109,
|
| 25 |
+
554,
|
| 26 |
+
632,
|
| 27 |
+
673,
|
| 28 |
+
445,
|
| 29 |
+
71,
|
| 30 |
+
403,
|
| 31 |
+
261,
|
| 32 |
+
377,
|
| 33 |
+
81,
|
| 34 |
+
21,
|
| 35 |
+
289,
|
| 36 |
+
23,
|
| 37 |
+
429,
|
| 38 |
+
645,
|
| 39 |
+
741,
|
| 40 |
+
566,
|
| 41 |
+
231,
|
| 42 |
+
357,
|
| 43 |
+
573,
|
| 44 |
+
597,
|
| 45 |
+
263,
|
| 46 |
+
28,
|
| 47 |
+
529,
|
| 48 |
+
372,
|
| 49 |
+
246,
|
| 50 |
+
49,
|
| 51 |
+
219,
|
| 52 |
+
759,
|
| 53 |
+
269,
|
| 54 |
+
593,
|
| 55 |
+
685,
|
| 56 |
+
97,
|
| 57 |
+
485,
|
| 58 |
+
430,
|
| 59 |
+
234,
|
| 60 |
+
297,
|
| 61 |
+
666,
|
| 62 |
+
32,
|
| 63 |
+
198,
|
| 64 |
+
384,
|
| 65 |
+
523,
|
| 66 |
+
292,
|
| 67 |
+
137,
|
| 68 |
+
388,
|
| 69 |
+
364,
|
| 70 |
+
506,
|
| 71 |
+
279,
|
| 72 |
+
101,
|
| 73 |
+
171,
|
| 74 |
+
649,
|
| 75 |
+
259,
|
| 76 |
+
293,
|
| 77 |
+
425,
|
| 78 |
+
576,
|
| 79 |
+
144,
|
| 80 |
+
183,
|
| 81 |
+
359,
|
| 82 |
+
437,
|
| 83 |
+
763,
|
| 84 |
+
540,
|
| 85 |
+
335,
|
| 86 |
+
302,
|
| 87 |
+
404,
|
| 88 |
+
202,
|
| 89 |
+
617,
|
| 90 |
+
497,
|
| 91 |
+
408,
|
| 92 |
+
410,
|
| 93 |
+
340,
|
| 94 |
+
15,
|
| 95 |
+
714,
|
| 96 |
+
693,
|
| 97 |
+
277,
|
| 98 |
+
466,
|
| 99 |
+
102,
|
| 100 |
+
681,
|
| 101 |
+
743,
|
| 102 |
+
765
|
| 103 |
+
],
|
| 104 |
+
"history": [
|
| 105 |
+
{
|
| 106 |
+
"step": 1,
|
| 107 |
+
"dim": 665,
|
| 108 |
+
"cls_acc": 0.3115,
|
| 109 |
+
"n_params": 160,
|
| 110 |
+
"step_ms": 477
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"step": 2,
|
| 114 |
+
"dim": 642,
|
| 115 |
+
"cls_acc": 0.3132,
|
| 116 |
+
"n_params": 240,
|
| 117 |
+
"step_ms": 339
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"step": 3,
|
| 121 |
+
"dim": 200,
|
| 122 |
+
"cls_acc": 0.3153,
|
| 123 |
+
"n_params": 320,
|
| 124 |
+
"step_ms": 327
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"step": 4,
|
| 128 |
+
"dim": 305,
|
| 129 |
+
"cls_acc": 0.3209,
|
| 130 |
+
"n_params": 400,
|
| 131 |
+
"step_ms": 308
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"step": 5,
|
| 135 |
+
"dim": 498,
|
| 136 |
+
"cls_acc": 0.3245,
|
| 137 |
+
"n_params": 480,
|
| 138 |
+
"step_ms": 344
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"step": 6,
|
| 142 |
+
"dim": 628,
|
| 143 |
+
"cls_acc": 0.3278,
|
| 144 |
+
"n_params": 560,
|
| 145 |
+
"step_ms": 327
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"step": 7,
|
| 149 |
+
"dim": 67,
|
| 150 |
+
"cls_acc": 0.332,
|
| 151 |
+
"n_params": 640,
|
| 152 |
+
"step_ms": 308
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"step": 8,
|
| 156 |
+
"dim": 562,
|
| 157 |
+
"cls_acc": 0.3376,
|
| 158 |
+
"n_params": 720,
|
| 159 |
+
"step_ms": 332
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"step": 9,
|
| 163 |
+
"dim": 426,
|
| 164 |
+
"cls_acc": 0.3417,
|
| 165 |
+
"n_params": 800,
|
| 166 |
+
"step_ms": 318
|
| 167 |
+
},
|
| 168 |
+
{
|
| 169 |
+
"step": 10,
|
| 170 |
+
"dim": 723,
|
| 171 |
+
"cls_acc": 0.3442,
|
| 172 |
+
"n_params": 880,
|
| 173 |
+
"step_ms": 316
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"step": 11,
|
| 177 |
+
"dim": 177,
|
| 178 |
+
"cls_acc": 0.3468,
|
| 179 |
+
"n_params": 960,
|
| 180 |
+
"step_ms": 347
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"step": 12,
|
| 184 |
+
"dim": 11,
|
| 185 |
+
"cls_acc": 0.3495,
|
| 186 |
+
"n_params": 1040,
|
| 187 |
+
"step_ms": 336
|
| 188 |
+
},
|
| 189 |
+
{
|
| 190 |
+
"step": 13,
|
| 191 |
+
"dim": 465,
|
| 192 |
+
"cls_acc": 0.3517,
|
| 193 |
+
"n_params": 1120,
|
| 194 |
+
"step_ms": 319
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"step": 14,
|
| 198 |
+
"dim": 555,
|
| 199 |
+
"cls_acc": 0.3539,
|
| 200 |
+
"n_params": 1200,
|
| 201 |
+
"step_ms": 318
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
"step": 15,
|
| 205 |
+
"dim": 52,
|
| 206 |
+
"cls_acc": 0.356,
|
| 207 |
+
"n_params": 1280,
|
| 208 |
+
"step_ms": 321
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"step": 16,
|
| 212 |
+
"dim": 179,
|
| 213 |
+
"cls_acc": 0.3587,
|
| 214 |
+
"n_params": 1360,
|
| 215 |
+
"step_ms": 343
|
| 216 |
+
},
|
| 217 |
+
{
|
| 218 |
+
"step": 17,
|
| 219 |
+
"dim": 325,
|
| 220 |
+
"cls_acc": 0.3608,
|
| 221 |
+
"n_params": 1440,
|
| 222 |
+
"step_ms": 312
|
| 223 |
+
},
|
| 224 |
+
{
|
| 225 |
+
"step": 18,
|
| 226 |
+
"dim": 600,
|
| 227 |
+
"cls_acc": 0.363,
|
| 228 |
+
"n_params": 1520,
|
| 229 |
+
"step_ms": 322
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"step": 19,
|
| 233 |
+
"dim": 738,
|
| 234 |
+
"cls_acc": 0.3649,
|
| 235 |
+
"n_params": 1600,
|
| 236 |
+
"step_ms": 331
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"step": 20,
|
| 240 |
+
"dim": 389,
|
| 241 |
+
"cls_acc": 0.3659,
|
| 242 |
+
"n_params": 1680,
|
| 243 |
+
"step_ms": 313
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"step": 21,
|
| 247 |
+
"dim": 660,
|
| 248 |
+
"cls_acc": 0.368,
|
| 249 |
+
"n_params": 1760,
|
| 250 |
+
"step_ms": 319
|
| 251 |
+
},
|
| 252 |
+
{
|
| 253 |
+
"step": 22,
|
| 254 |
+
"dim": 109,
|
| 255 |
+
"cls_acc": 0.3708,
|
| 256 |
+
"n_params": 1840,
|
| 257 |
+
"step_ms": 326
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"step": 23,
|
| 261 |
+
"dim": 554,
|
| 262 |
+
"cls_acc": 0.3734,
|
| 263 |
+
"n_params": 1920,
|
| 264 |
+
"step_ms": 323
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"step": 24,
|
| 268 |
+
"dim": 632,
|
| 269 |
+
"cls_acc": 0.3752,
|
| 270 |
+
"n_params": 2000,
|
| 271 |
+
"step_ms": 318
|
| 272 |
+
},
|
| 273 |
+
{
|
| 274 |
+
"step": 25,
|
| 275 |
+
"dim": 673,
|
| 276 |
+
"cls_acc": 0.3775,
|
| 277 |
+
"n_params": 2080,
|
| 278 |
+
"step_ms": 351
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"step": 26,
|
| 282 |
+
"dim": 445,
|
| 283 |
+
"cls_acc": 0.3791,
|
| 284 |
+
"n_params": 2160,
|
| 285 |
+
"step_ms": 336
|
| 286 |
+
},
|
| 287 |
+
{
|
| 288 |
+
"step": 27,
|
| 289 |
+
"dim": 71,
|
| 290 |
+
"cls_acc": 0.3812,
|
| 291 |
+
"n_params": 2240,
|
| 292 |
+
"step_ms": 324
|
| 293 |
+
},
|
| 294 |
+
{
|
| 295 |
+
"step": 28,
|
| 296 |
+
"dim": 403,
|
| 297 |
+
"cls_acc": 0.3829,
|
| 298 |
+
"n_params": 2320,
|
| 299 |
+
"step_ms": 326
|
| 300 |
+
},
|
| 301 |
+
{
|
| 302 |
+
"step": 29,
|
| 303 |
+
"dim": 261,
|
| 304 |
+
"cls_acc": 0.3854,
|
| 305 |
+
"n_params": 2400,
|
| 306 |
+
"step_ms": 317
|
| 307 |
+
},
|
| 308 |
+
{
|
| 309 |
+
"step": 30,
|
| 310 |
+
"dim": 377,
|
| 311 |
+
"cls_acc": 0.3872,
|
| 312 |
+
"n_params": 2480,
|
| 313 |
+
"step_ms": 308
|
| 314 |
+
},
|
| 315 |
+
{
|
| 316 |
+
"step": 31,
|
| 317 |
+
"dim": 81,
|
| 318 |
+
"cls_acc": 0.389,
|
| 319 |
+
"n_params": 2560,
|
| 320 |
+
"step_ms": 334
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"step": 32,
|
| 324 |
+
"dim": 21,
|
| 325 |
+
"cls_acc": 0.3909,
|
| 326 |
+
"n_params": 2640,
|
| 327 |
+
"step_ms": 398
|
| 328 |
+
},
|
| 329 |
+
{
|
| 330 |
+
"step": 33,
|
| 331 |
+
"dim": 289,
|
| 332 |
+
"cls_acc": 0.3928,
|
| 333 |
+
"n_params": 2720,
|
| 334 |
+
"step_ms": 404
|
| 335 |
+
},
|
| 336 |
+
{
|
| 337 |
+
"step": 34,
|
| 338 |
+
"dim": 23,
|
| 339 |
+
"cls_acc": 0.394,
|
| 340 |
+
"n_params": 2800,
|
| 341 |
+
"step_ms": 397
|
| 342 |
+
},
|
| 343 |
+
{
|
| 344 |
+
"step": 35,
|
| 345 |
+
"dim": 429,
|
| 346 |
+
"cls_acc": 0.3953,
|
| 347 |
+
"n_params": 2880,
|
| 348 |
+
"step_ms": 359
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"step": 36,
|
| 352 |
+
"dim": 645,
|
| 353 |
+
"cls_acc": 0.3967,
|
| 354 |
+
"n_params": 2960,
|
| 355 |
+
"step_ms": 397
|
| 356 |
+
},
|
| 357 |
+
{
|
| 358 |
+
"step": 37,
|
| 359 |
+
"dim": 741,
|
| 360 |
+
"cls_acc": 0.3999,
|
| 361 |
+
"n_params": 3040,
|
| 362 |
+
"step_ms": 397
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"step": 38,
|
| 366 |
+
"dim": 566,
|
| 367 |
+
"cls_acc": 0.403,
|
| 368 |
+
"n_params": 3120,
|
| 369 |
+
"step_ms": 381
|
| 370 |
+
},
|
| 371 |
+
{
|
| 372 |
+
"step": 39,
|
| 373 |
+
"dim": 231,
|
| 374 |
+
"cls_acc": 0.4063,
|
| 375 |
+
"n_params": 3200,
|
| 376 |
+
"step_ms": 397
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"step": 40,
|
| 380 |
+
"dim": 357,
|
| 381 |
+
"cls_acc": 0.4088,
|
| 382 |
+
"n_params": 3280,
|
| 383 |
+
"step_ms": 361
|
| 384 |
+
},
|
| 385 |
+
{
|
| 386 |
+
"step": 41,
|
| 387 |
+
"dim": 573,
|
| 388 |
+
"cls_acc": 0.4117,
|
| 389 |
+
"n_params": 3360,
|
| 390 |
+
"step_ms": 388
|
| 391 |
+
},
|
| 392 |
+
{
|
| 393 |
+
"step": 42,
|
| 394 |
+
"dim": 597,
|
| 395 |
+
"cls_acc": 0.4137,
|
| 396 |
+
"n_params": 3440,
|
| 397 |
+
"step_ms": 383
|
| 398 |
+
},
|
| 399 |
+
{
|
| 400 |
+
"step": 43,
|
| 401 |
+
"dim": 263,
|
| 402 |
+
"cls_acc": 0.4159,
|
| 403 |
+
"n_params": 3520,
|
| 404 |
+
"step_ms": 365
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"step": 44,
|
| 408 |
+
"dim": 28,
|
| 409 |
+
"cls_acc": 0.418,
|
| 410 |
+
"n_params": 3600,
|
| 411 |
+
"step_ms": 364
|
| 412 |
+
},
|
| 413 |
+
{
|
| 414 |
+
"step": 45,
|
| 415 |
+
"dim": 529,
|
| 416 |
+
"cls_acc": 0.4203,
|
| 417 |
+
"n_params": 3680,
|
| 418 |
+
"step_ms": 354
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"step": 46,
|
| 422 |
+
"dim": 372,
|
| 423 |
+
"cls_acc": 0.4227,
|
| 424 |
+
"n_params": 3760,
|
| 425 |
+
"step_ms": 368
|
| 426 |
+
},
|
| 427 |
+
{
|
| 428 |
+
"step": 47,
|
| 429 |
+
"dim": 246,
|
| 430 |
+
"cls_acc": 0.4251,
|
| 431 |
+
"n_params": 3840,
|
| 432 |
+
"step_ms": 357
|
| 433 |
+
},
|
| 434 |
+
{
|
| 435 |
+
"step": 48,
|
| 436 |
+
"dim": 49,
|
| 437 |
+
"cls_acc": 0.4278,
|
| 438 |
+
"n_params": 3920,
|
| 439 |
+
"step_ms": 3306
|
| 440 |
+
},
|
| 441 |
+
{
|
| 442 |
+
"step": 49,
|
| 443 |
+
"dim": 219,
|
| 444 |
+
"cls_acc": 0.429,
|
| 445 |
+
"n_params": 4000,
|
| 446 |
+
"step_ms": 388
|
| 447 |
+
},
|
| 448 |
+
{
|
| 449 |
+
"step": 50,
|
| 450 |
+
"dim": 759,
|
| 451 |
+
"cls_acc": 0.4308,
|
| 452 |
+
"n_params": 4080,
|
| 453 |
+
"step_ms": 380
|
| 454 |
+
},
|
| 455 |
+
{
|
| 456 |
+
"step": 51,
|
| 457 |
+
"dim": 269,
|
| 458 |
+
"cls_acc": 0.4329,
|
| 459 |
+
"n_params": 4160,
|
| 460 |
+
"step_ms": 386
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"step": 52,
|
| 464 |
+
"dim": 593,
|
| 465 |
+
"cls_acc": 0.4342,
|
| 466 |
+
"n_params": 4240,
|
| 467 |
+
"step_ms": 367
|
| 468 |
+
},
|
| 469 |
+
{
|
| 470 |
+
"step": 53,
|
| 471 |
+
"dim": 685,
|
| 472 |
+
"cls_acc": 0.4357,
|
| 473 |
+
"n_params": 4320,
|
| 474 |
+
"step_ms": 380
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"step": 54,
|
| 478 |
+
"dim": 97,
|
| 479 |
+
"cls_acc": 0.4373,
|
| 480 |
+
"n_params": 4400,
|
| 481 |
+
"step_ms": 377
|
| 482 |
+
},
|
| 483 |
+
{
|
| 484 |
+
"step": 55,
|
| 485 |
+
"dim": 485,
|
| 486 |
+
"cls_acc": 0.4397,
|
| 487 |
+
"n_params": 4480,
|
| 488 |
+
"step_ms": 373
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"step": 56,
|
| 492 |
+
"dim": 430,
|
| 493 |
+
"cls_acc": 0.441,
|
| 494 |
+
"n_params": 4560,
|
| 495 |
+
"step_ms": 365
|
| 496 |
+
},
|
| 497 |
+
{
|
| 498 |
+
"step": 57,
|
| 499 |
+
"dim": 234,
|
| 500 |
+
"cls_acc": 0.4431,
|
| 501 |
+
"n_params": 4640,
|
| 502 |
+
"step_ms": 346
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"step": 58,
|
| 506 |
+
"dim": 297,
|
| 507 |
+
"cls_acc": 0.4452,
|
| 508 |
+
"n_params": 4720,
|
| 509 |
+
"step_ms": 374
|
| 510 |
+
},
|
| 511 |
+
{
|
| 512 |
+
"step": 59,
|
| 513 |
+
"dim": 666,
|
| 514 |
+
"cls_acc": 0.4468,
|
| 515 |
+
"n_params": 4800,
|
| 516 |
+
"step_ms": 387
|
| 517 |
+
},
|
| 518 |
+
{
|
| 519 |
+
"step": 60,
|
| 520 |
+
"dim": 32,
|
| 521 |
+
"cls_acc": 0.4484,
|
| 522 |
+
"n_params": 4880,
|
| 523 |
+
"step_ms": 393
|
| 524 |
+
},
|
| 525 |
+
{
|
| 526 |
+
"step": 61,
|
| 527 |
+
"dim": 198,
|
| 528 |
+
"cls_acc": 0.4503,
|
| 529 |
+
"n_params": 4960,
|
| 530 |
+
"step_ms": 429
|
| 531 |
+
},
|
| 532 |
+
{
|
| 533 |
+
"step": 62,
|
| 534 |
+
"dim": 384,
|
| 535 |
+
"cls_acc": 0.4519,
|
| 536 |
+
"n_params": 5040,
|
| 537 |
+
"step_ms": 446
|
| 538 |
+
},
|
| 539 |
+
{
|
| 540 |
+
"step": 63,
|
| 541 |
+
"dim": 523,
|
| 542 |
+
"cls_acc": 0.4537,
|
| 543 |
+
"n_params": 5120,
|
| 544 |
+
"step_ms": 418
|
| 545 |
+
},
|
| 546 |
+
{
|
| 547 |
+
"step": 64,
|
| 548 |
+
"dim": 292,
|
| 549 |
+
"cls_acc": 0.455,
|
| 550 |
+
"n_params": 5200,
|
| 551 |
+
"step_ms": 476
|
| 552 |
+
},
|
| 553 |
+
{
|
| 554 |
+
"step": 65,
|
| 555 |
+
"dim": 137,
|
| 556 |
+
"cls_acc": 0.4564,
|
| 557 |
+
"n_params": 5280,
|
| 558 |
+
"step_ms": 432
|
| 559 |
+
},
|
| 560 |
+
{
|
| 561 |
+
"step": 66,
|
| 562 |
+
"dim": 388,
|
| 563 |
+
"cls_acc": 0.458,
|
| 564 |
+
"n_params": 5360,
|
| 565 |
+
"step_ms": 432
|
| 566 |
+
},
|
| 567 |
+
{
|
| 568 |
+
"step": 67,
|
| 569 |
+
"dim": 364,
|
| 570 |
+
"cls_acc": 0.4596,
|
| 571 |
+
"n_params": 5440,
|
| 572 |
+
"step_ms": 445
|
| 573 |
+
},
|
| 574 |
+
{
|
| 575 |
+
"step": 68,
|
| 576 |
+
"dim": 506,
|
| 577 |
+
"cls_acc": 0.461,
|
| 578 |
+
"n_params": 5520,
|
| 579 |
+
"step_ms": 419
|
| 580 |
+
},
|
| 581 |
+
{
|
| 582 |
+
"step": 69,
|
| 583 |
+
"dim": 279,
|
| 584 |
+
"cls_acc": 0.4624,
|
| 585 |
+
"n_params": 5600,
|
| 586 |
+
"step_ms": 397
|
| 587 |
+
},
|
| 588 |
+
{
|
| 589 |
+
"step": 70,
|
| 590 |
+
"dim": 101,
|
| 591 |
+
"cls_acc": 0.464,
|
| 592 |
+
"n_params": 5680,
|
| 593 |
+
"step_ms": 385
|
| 594 |
+
},
|
| 595 |
+
{
|
| 596 |
+
"step": 71,
|
| 597 |
+
"dim": 171,
|
| 598 |
+
"cls_acc": 0.4658,
|
| 599 |
+
"n_params": 5760,
|
| 600 |
+
"step_ms": 395
|
| 601 |
+
},
|
| 602 |
+
{
|
| 603 |
+
"step": 72,
|
| 604 |
+
"dim": 649,
|
| 605 |
+
"cls_acc": 0.4679,
|
| 606 |
+
"n_params": 5840,
|
| 607 |
+
"step_ms": 408
|
| 608 |
+
},
|
| 609 |
+
{
|
| 610 |
+
"step": 73,
|
| 611 |
+
"dim": 259,
|
| 612 |
+
"cls_acc": 0.4696,
|
| 613 |
+
"n_params": 5920,
|
| 614 |
+
"step_ms": 373
|
| 615 |
+
},
|
| 616 |
+
{
|
| 617 |
+
"step": 74,
|
| 618 |
+
"dim": 293,
|
| 619 |
+
"cls_acc": 0.4719,
|
| 620 |
+
"n_params": 6000,
|
| 621 |
+
"step_ms": 403
|
| 622 |
+
},
|
| 623 |
+
{
|
| 624 |
+
"step": 75,
|
| 625 |
+
"dim": 425,
|
| 626 |
+
"cls_acc": 0.4736,
|
| 627 |
+
"n_params": 6080,
|
| 628 |
+
"step_ms": 405
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"step": 76,
|
| 632 |
+
"dim": 576,
|
| 633 |
+
"cls_acc": 0.4746,
|
| 634 |
+
"n_params": 6160,
|
| 635 |
+
"step_ms": 367
|
| 636 |
+
},
|
| 637 |
+
{
|
| 638 |
+
"step": 77,
|
| 639 |
+
"dim": 144,
|
| 640 |
+
"cls_acc": 0.4758,
|
| 641 |
+
"n_params": 6240,
|
| 642 |
+
"step_ms": 382
|
| 643 |
+
},
|
| 644 |
+
{
|
| 645 |
+
"step": 78,
|
| 646 |
+
"dim": 183,
|
| 647 |
+
"cls_acc": 0.4771,
|
| 648 |
+
"n_params": 6320,
|
| 649 |
+
"step_ms": 372
|
| 650 |
+
},
|
| 651 |
+
{
|
| 652 |
+
"step": 79,
|
| 653 |
+
"dim": 359,
|
| 654 |
+
"cls_acc": 0.4788,
|
| 655 |
+
"n_params": 6400,
|
| 656 |
+
"step_ms": 382
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"step": 80,
|
| 660 |
+
"dim": 437,
|
| 661 |
+
"cls_acc": 0.4804,
|
| 662 |
+
"n_params": 6480,
|
| 663 |
+
"step_ms": 383
|
| 664 |
+
},
|
| 665 |
+
{
|
| 666 |
+
"step": 81,
|
| 667 |
+
"dim": 763,
|
| 668 |
+
"cls_acc": 0.4816,
|
| 669 |
+
"n_params": 6560,
|
| 670 |
+
"step_ms": 363
|
| 671 |
+
},
|
| 672 |
+
{
|
| 673 |
+
"step": 82,
|
| 674 |
+
"dim": 540,
|
| 675 |
+
"cls_acc": 0.4832,
|
| 676 |
+
"n_params": 6640,
|
| 677 |
+
"step_ms": 384
|
| 678 |
+
},
|
| 679 |
+
{
|
| 680 |
+
"step": 83,
|
| 681 |
+
"dim": 335,
|
| 682 |
+
"cls_acc": 0.4846,
|
| 683 |
+
"n_params": 6720,
|
| 684 |
+
"step_ms": 382
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"step": 84,
|
| 688 |
+
"dim": 302,
|
| 689 |
+
"cls_acc": 0.486,
|
| 690 |
+
"n_params": 6800,
|
| 691 |
+
"step_ms": 370
|
| 692 |
+
},
|
| 693 |
+
{
|
| 694 |
+
"step": 85,
|
| 695 |
+
"dim": 404,
|
| 696 |
+
"cls_acc": 0.4875,
|
| 697 |
+
"n_params": 6880,
|
| 698 |
+
"step_ms": 367
|
| 699 |
+
},
|
| 700 |
+
{
|
| 701 |
+
"step": 86,
|
| 702 |
+
"dim": 202,
|
| 703 |
+
"cls_acc": 0.4883,
|
| 704 |
+
"n_params": 6960,
|
| 705 |
+
"step_ms": 375
|
| 706 |
+
},
|
| 707 |
+
{
|
| 708 |
+
"step": 87,
|
| 709 |
+
"dim": 617,
|
| 710 |
+
"cls_acc": 0.4896,
|
| 711 |
+
"n_params": 7040,
|
| 712 |
+
"step_ms": 352
|
| 713 |
+
},
|
| 714 |
+
{
|
| 715 |
+
"step": 88,
|
| 716 |
+
"dim": 497,
|
| 717 |
+
"cls_acc": 0.4908,
|
| 718 |
+
"n_params": 7120,
|
| 719 |
+
"step_ms": 357
|
| 720 |
+
},
|
| 721 |
+
{
|
| 722 |
+
"step": 89,
|
| 723 |
+
"dim": 408,
|
| 724 |
+
"cls_acc": 0.492,
|
| 725 |
+
"n_params": 7200,
|
| 726 |
+
"step_ms": 388
|
| 727 |
+
},
|
| 728 |
+
{
|
| 729 |
+
"step": 90,
|
| 730 |
+
"dim": 410,
|
| 731 |
+
"cls_acc": 0.4934,
|
| 732 |
+
"n_params": 7280,
|
| 733 |
+
"step_ms": 378
|
| 734 |
+
},
|
| 735 |
+
{
|
| 736 |
+
"step": 91,
|
| 737 |
+
"dim": 340,
|
| 738 |
+
"cls_acc": 0.4944,
|
| 739 |
+
"n_params": 7360,
|
| 740 |
+
"step_ms": 378
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"step": 92,
|
| 744 |
+
"dim": 15,
|
| 745 |
+
"cls_acc": 0.4956,
|
| 746 |
+
"n_params": 7440,
|
| 747 |
+
"step_ms": 383
|
| 748 |
+
},
|
| 749 |
+
{
|
| 750 |
+
"step": 93,
|
| 751 |
+
"dim": 714,
|
| 752 |
+
"cls_acc": 0.4971,
|
| 753 |
+
"n_params": 7520,
|
| 754 |
+
"step_ms": 378
|
| 755 |
+
},
|
| 756 |
+
{
|
| 757 |
+
"step": 94,
|
| 758 |
+
"dim": 693,
|
| 759 |
+
"cls_acc": 0.4987,
|
| 760 |
+
"n_params": 7600,
|
| 761 |
+
"step_ms": 378
|
| 762 |
+
},
|
| 763 |
+
{
|
| 764 |
+
"step": 95,
|
| 765 |
+
"dim": 277,
|
| 766 |
+
"cls_acc": 0.5001,
|
| 767 |
+
"n_params": 7680,
|
| 768 |
+
"step_ms": 346
|
| 769 |
+
},
|
| 770 |
+
{
|
| 771 |
+
"step": 96,
|
| 772 |
+
"dim": 466,
|
| 773 |
+
"cls_acc": 0.5012,
|
| 774 |
+
"n_params": 7760,
|
| 775 |
+
"step_ms": 384
|
| 776 |
+
},
|
| 777 |
+
{
|
| 778 |
+
"step": 97,
|
| 779 |
+
"dim": 102,
|
| 780 |
+
"cls_acc": 0.5025,
|
| 781 |
+
"n_params": 7840,
|
| 782 |
+
"step_ms": 396
|
| 783 |
+
},
|
| 784 |
+
{
|
| 785 |
+
"step": 98,
|
| 786 |
+
"dim": 681,
|
| 787 |
+
"cls_acc": 0.504,
|
| 788 |
+
"n_params": 7920,
|
| 789 |
+
"step_ms": 383
|
| 790 |
+
},
|
| 791 |
+
{
|
| 792 |
+
"step": 99,
|
| 793 |
+
"dim": 743,
|
| 794 |
+
"cls_acc": 0.5048,
|
| 795 |
+
"n_params": 8000,
|
| 796 |
+
"step_ms": 404
|
| 797 |
+
},
|
| 798 |
+
{
|
| 799 |
+
"step": 100,
|
| 800 |
+
"dim": 765,
|
| 801 |
+
"cls_acc": 0.5057,
|
| 802 |
+
"n_params": 8080,
|
| 803 |
+
"step_ms": 374
|
| 804 |
+
}
|
| 805 |
+
],
|
| 806 |
+
"final_cls_acc": 0.5057,
|
| 807 |
+
"final_params": 8080,
|
| 808 |
+
"total_time_s": 39.8
|
| 809 |
+
}
|
analytical/variants/v001_baseline.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v001_baseline",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "none",
|
| 7 |
+
"lam": 0.001,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "Control.",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.6427,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 65365,
|
| 19 |
+
"composite": 0.3265
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 12,
|
| 22 |
+
"eval_time_s": 10.4
|
| 23 |
+
}
|
analytical/variants/v002_spatial_cat_mean3x3.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v002_spatial_cat_mean3x3",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.001,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "Concatenate",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7286,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.0221,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.375
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 47,
|
| 22 |
+
"eval_time_s": 18.8
|
| 23 |
+
}
|
analytical/variants/v003_spatial_diff_neighbors.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v003_spatial_diff_neighbors",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "diff_neighbors",
|
| 7 |
+
"lam": 0.001,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "center",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.728,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.0217,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.3746
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 41,
|
| 22 |
+
"eval_time_s": 12.0
|
| 23 |
+
}
|
analytical/variants/v004_spatial_highreg.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v004_spatial_highreg",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "Same",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7117,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.1327,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.3942
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 83,
|
| 22 |
+
"eval_time_s": 13.7
|
| 23 |
+
}
|
analytical/variants/v004_spatial_highreg_v2.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v004_spatial_highreg_v2",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "rerun",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7117,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.6294,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.5183
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 67,
|
| 22 |
+
"eval_time_s": 10.4
|
| 23 |
+
}
|
analytical/variants/v005_power05_spatial_highreg.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v005_power05_spatial_highreg",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "power05",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "power",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.3066,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.1584
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 43,
|
| 22 |
+
"eval_time_s": 17.2
|
| 23 |
+
}
|
analytical/variants/v006_hv_neighbors_highreg.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v006_hv_neighbors_highreg",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "hv_neighbors",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "center",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7023,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.1395,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 195925,
|
| 19 |
+
"composite": 0.3912
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 248,
|
| 22 |
+
"eval_time_s": 13.9
|
| 23 |
+
}
|
analytical/variants/v007_spatial_sqrt_highreg.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v007_spatial_sqrt_highreg",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "sqrt_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "sqrt",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7117,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.2461,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.4225
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 67,
|
| 22 |
+
"eval_time_s": 11.5
|
| 23 |
+
}
|
analytical/variants/v008_spatial_neg3_highreg.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v008_spatial_neg3_highreg",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "cat_mean3x3",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "3:1",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.6985,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.6294,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 130645,
|
| 19 |
+
"composite": 0.5118
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 33,
|
| 22 |
+
"eval_time_s": 11.2
|
| 23 |
+
}
|
analytical/variants/v009_sheaf_h1_compact.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v009_sheaf_h1_compact",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "sheaf_h1_compact",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "Cech",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.7426,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.6546,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 195925,
|
| 19 |
+
"composite": 0.5401
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 68,
|
| 22 |
+
"eval_time_s": 17.9
|
| 23 |
+
}
|
analytical/variants/v010_sheaf_h1_full.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "v010_sheaf_h1_full",
|
| 3 |
+
"config": {
|
| 4 |
+
"transform": "layernorm",
|
| 5 |
+
"encoding": "log_ltrb",
|
| 6 |
+
"spatial": "sheaf_h1",
|
| 7 |
+
"lam": 0.1,
|
| 8 |
+
"n_train": 10000,
|
| 9 |
+
"n_eval": 500
|
| 10 |
+
},
|
| 11 |
+
"notes": "full",
|
| 12 |
+
"metrics": {
|
| 13 |
+
"cls_accuracy": 0.6966,
|
| 14 |
+
"precision": 0.0206,
|
| 15 |
+
"reg_quality": 0.6374,
|
| 16 |
+
"n_detections": 1050000,
|
| 17 |
+
"n_positives": 21602,
|
| 18 |
+
"n_params": 326485,
|
| 19 |
+
"composite": 0.5128
|
| 20 |
+
},
|
| 21 |
+
"solve_time_ms": 370,
|
| 22 |
+
"eval_time_s": 23.2
|
| 23 |
+
}
|
circuit/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Circuit-Level Detection
|
| 2 |
+
|
| 3 |
+
The cofiber threshold detection head expressed as synthesizable digital logic. All weights are analytically derived (zero gradient-based training) and stored as INT8 ROM.
|
| 4 |
+
|
| 5 |
+
## Person Detector (Proof of Concept)
|
| 6 |
+
|
| 7 |
+
Single-class (person) detector as a combinational circuit.
|
| 8 |
+
|
| 9 |
+
- **Parameters**: 4,614 (4.6 KB INT8 ROM)
|
| 10 |
+
- **Architecture**: 6 parallel dot products (1 cls + 4 reg + 1 ctr), each 768-dim
|
| 11 |
+
- **Weights**: closed-form least-squares on 20K COCO training images
|
| 12 |
+
- **Construction time**: 122 seconds, zero training steps
|
| 13 |
+
|
| 14 |
+
### Gate Count (Yosys synthesis)
|
| 15 |
+
|
| 16 |
+
Synthesized with Yosys (generic target, no FPGA mapping):
|
| 17 |
+
|
| 18 |
+
| Component | Dims | Gates (16-dim measured) | Gates (768-dim extrapolated) |
|
| 19 |
+
|-----------|------|------------------------|------------------------------|
|
| 20 |
+
| 1 MAC unit | 768→1 | 1,358 | ~65K |
|
| 21 |
+
| Person detector (6 MACs) | 768→{1,4,1} | — | ~391K |
|
| 22 |
+
| Full 80-class detector (85 MACs) | 768→{80,4,1} | — | ~7.1M |
|
| 23 |
+
|
| 24 |
+
### Files
|
| 25 |
+
|
| 26 |
+
- `person_detector.sv` — SystemVerilog module, Icarus Verilog compatible
|
| 27 |
+
- `tb_person.sv` — testbench
|
| 28 |
+
- `cofiber_detector.sv` — full 80-class detector (SystemVerilog, parameterized)
|
| 29 |
+
- `person_small_synth.v` — 16-dim reduced version for synthesis analysis
|
| 30 |
+
- `rom/person_cls_w.hex` — classification weights (768 INT8)
|
| 31 |
+
- `rom/person_reg_w.hex` — regression weights (4×768 INT8)
|
| 32 |
+
- `rom/person_ctr_w.hex` — centerness weights (768 INT8)
|
| 33 |
+
- `person_analytical.pth` — PyTorch checkpoint of the analytical solution
|
| 34 |
+
|
| 35 |
+
### Simulation
|
| 36 |
+
|
| 37 |
+
```bash
|
| 38 |
+
iverilog -g2012 -o tb_person.vvp person_detector.sv tb_person.sv
|
| 39 |
+
vvp tb_person.vvp
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
### Synthesis
|
| 43 |
+
|
| 44 |
+
```bash
|
| 45 |
+
yosys -p "read_verilog person_small_synth.v; synth -top person_detector_small; stat"
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
## Cofiber Decomposition
|
| 49 |
+
|
| 50 |
+
The spatial decomposition (avg_pool → subtract → repeat) is a fixed filter bank with zero learned parameters. In hardware, it is:
|
| 51 |
+
- Average pooling: 2×2 adder tree + arithmetic right shift
|
| 52 |
+
- Cofiber extraction: subtractor (input − upsampled pool)
|
| 53 |
+
- Fully combinational, no state
|
| 54 |
+
|
| 55 |
+
The decomposition module (`cofiber_detector.sv`) implements all three scales for a 40×40 input grid.
|
circuit/circuit_variants.json
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"n_dims": 1,
|
| 4 |
+
"gates": 85,
|
| 5 |
+
"tp": 589,
|
| 6 |
+
"fp": 490,
|
| 7 |
+
"fn": 411,
|
| 8 |
+
"tn": 510,
|
| 9 |
+
"precision": 0.5459,
|
| 10 |
+
"recall": 0.589,
|
| 11 |
+
"f1": 0.5666,
|
| 12 |
+
"time_s": 1.3,
|
| 13 |
+
"dims": [
|
| 14 |
+
665
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"n_dims": 2,
|
| 19 |
+
"gates": 170,
|
| 20 |
+
"tp": 620,
|
| 21 |
+
"fp": 495,
|
| 22 |
+
"fn": 380,
|
| 23 |
+
"tn": 505,
|
| 24 |
+
"precision": 0.5561,
|
| 25 |
+
"recall": 0.62,
|
| 26 |
+
"f1": 0.5863,
|
| 27 |
+
"time_s": 0.1,
|
| 28 |
+
"dims": [
|
| 29 |
+
665,
|
| 30 |
+
642
|
| 31 |
+
]
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"n_dims": 3,
|
| 35 |
+
"gates": 255,
|
| 36 |
+
"tp": 667,
|
| 37 |
+
"fp": 516,
|
| 38 |
+
"fn": 333,
|
| 39 |
+
"tn": 484,
|
| 40 |
+
"precision": 0.5638,
|
| 41 |
+
"recall": 0.667,
|
| 42 |
+
"f1": 0.6111,
|
| 43 |
+
"time_s": 0.1,
|
| 44 |
+
"dims": [
|
| 45 |
+
665,
|
| 46 |
+
642,
|
| 47 |
+
200
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"n_dims": 5,
|
| 52 |
+
"gates": 425,
|
| 53 |
+
"tp": 665,
|
| 54 |
+
"fp": 513,
|
| 55 |
+
"fn": 335,
|
| 56 |
+
"tn": 487,
|
| 57 |
+
"precision": 0.5645,
|
| 58 |
+
"recall": 0.665,
|
| 59 |
+
"f1": 0.6107,
|
| 60 |
+
"time_s": 0.1,
|
| 61 |
+
"dims": [
|
| 62 |
+
665,
|
| 63 |
+
642,
|
| 64 |
+
200,
|
| 65 |
+
305,
|
| 66 |
+
498
|
| 67 |
+
]
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"n_dims": 8,
|
| 71 |
+
"gates": 680,
|
| 72 |
+
"tp": 691,
|
| 73 |
+
"fp": 512,
|
| 74 |
+
"fn": 309,
|
| 75 |
+
"tn": 488,
|
| 76 |
+
"precision": 0.5744,
|
| 77 |
+
"recall": 0.691,
|
| 78 |
+
"f1": 0.6273,
|
| 79 |
+
"time_s": 0.1,
|
| 80 |
+
"dims": [
|
| 81 |
+
665,
|
| 82 |
+
642,
|
| 83 |
+
200,
|
| 84 |
+
305,
|
| 85 |
+
498,
|
| 86 |
+
628,
|
| 87 |
+
67,
|
| 88 |
+
562
|
| 89 |
+
]
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
"n_dims": 10,
|
| 93 |
+
"gates": 850,
|
| 94 |
+
"tp": 693,
|
| 95 |
+
"fp": 513,
|
| 96 |
+
"fn": 307,
|
| 97 |
+
"tn": 487,
|
| 98 |
+
"precision": 0.5746,
|
| 99 |
+
"recall": 0.693,
|
| 100 |
+
"f1": 0.6283,
|
| 101 |
+
"time_s": 0.1,
|
| 102 |
+
"dims": [
|
| 103 |
+
665,
|
| 104 |
+
642,
|
| 105 |
+
200,
|
| 106 |
+
305,
|
| 107 |
+
498,
|
| 108 |
+
628,
|
| 109 |
+
67,
|
| 110 |
+
562,
|
| 111 |
+
426,
|
| 112 |
+
723
|
| 113 |
+
]
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"n_dims": 15,
|
| 117 |
+
"gates": 1275,
|
| 118 |
+
"tp": 709,
|
| 119 |
+
"fp": 503,
|
| 120 |
+
"fn": 291,
|
| 121 |
+
"tn": 497,
|
| 122 |
+
"precision": 0.585,
|
| 123 |
+
"recall": 0.709,
|
| 124 |
+
"f1": 0.641,
|
| 125 |
+
"time_s": 0.1,
|
| 126 |
+
"dims": [
|
| 127 |
+
665,
|
| 128 |
+
642,
|
| 129 |
+
200,
|
| 130 |
+
305,
|
| 131 |
+
498,
|
| 132 |
+
628,
|
| 133 |
+
67,
|
| 134 |
+
562,
|
| 135 |
+
426,
|
| 136 |
+
723,
|
| 137 |
+
177,
|
| 138 |
+
11,
|
| 139 |
+
465,
|
| 140 |
+
555,
|
| 141 |
+
52
|
| 142 |
+
]
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"n_dims": 20,
|
| 146 |
+
"gates": 1700,
|
| 147 |
+
"tp": 715,
|
| 148 |
+
"fp": 500,
|
| 149 |
+
"fn": 285,
|
| 150 |
+
"tn": 500,
|
| 151 |
+
"precision": 0.5885,
|
| 152 |
+
"recall": 0.715,
|
| 153 |
+
"f1": 0.6456,
|
| 154 |
+
"time_s": 0.2,
|
| 155 |
+
"dims": [
|
| 156 |
+
665,
|
| 157 |
+
642,
|
| 158 |
+
200,
|
| 159 |
+
305,
|
| 160 |
+
498,
|
| 161 |
+
628,
|
| 162 |
+
67,
|
| 163 |
+
562,
|
| 164 |
+
426,
|
| 165 |
+
723,
|
| 166 |
+
177,
|
| 167 |
+
11,
|
| 168 |
+
465,
|
| 169 |
+
555,
|
| 170 |
+
52,
|
| 171 |
+
179,
|
| 172 |
+
325,
|
| 173 |
+
600,
|
| 174 |
+
738,
|
| 175 |
+
389
|
| 176 |
+
]
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"n_dims": 30,
|
| 180 |
+
"gates": 2550,
|
| 181 |
+
"tp": 737,
|
| 182 |
+
"fp": 521,
|
| 183 |
+
"fn": 263,
|
| 184 |
+
"tn": 479,
|
| 185 |
+
"precision": 0.5859,
|
| 186 |
+
"recall": 0.737,
|
| 187 |
+
"f1": 0.6528,
|
| 188 |
+
"time_s": 0.2,
|
| 189 |
+
"dims": [
|
| 190 |
+
665,
|
| 191 |
+
642,
|
| 192 |
+
200,
|
| 193 |
+
305,
|
| 194 |
+
498,
|
| 195 |
+
628,
|
| 196 |
+
67,
|
| 197 |
+
562,
|
| 198 |
+
426,
|
| 199 |
+
723,
|
| 200 |
+
177,
|
| 201 |
+
11,
|
| 202 |
+
465,
|
| 203 |
+
555,
|
| 204 |
+
52,
|
| 205 |
+
179,
|
| 206 |
+
325,
|
| 207 |
+
600,
|
| 208 |
+
738,
|
| 209 |
+
389,
|
| 210 |
+
660,
|
| 211 |
+
109,
|
| 212 |
+
554,
|
| 213 |
+
632,
|
| 214 |
+
673,
|
| 215 |
+
445,
|
| 216 |
+
71,
|
| 217 |
+
403,
|
| 218 |
+
261,
|
| 219 |
+
377
|
| 220 |
+
]
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"n_dims": 50,
|
| 224 |
+
"gates": 4250,
|
| 225 |
+
"tp": 807,
|
| 226 |
+
"fp": 512,
|
| 227 |
+
"fn": 193,
|
| 228 |
+
"tn": 488,
|
| 229 |
+
"precision": 0.6118,
|
| 230 |
+
"recall": 0.807,
|
| 231 |
+
"f1": 0.696,
|
| 232 |
+
"time_s": 0.3,
|
| 233 |
+
"dims": [
|
| 234 |
+
665,
|
| 235 |
+
642,
|
| 236 |
+
200,
|
| 237 |
+
305,
|
| 238 |
+
498,
|
| 239 |
+
628,
|
| 240 |
+
67,
|
| 241 |
+
562,
|
| 242 |
+
426,
|
| 243 |
+
723,
|
| 244 |
+
177,
|
| 245 |
+
11,
|
| 246 |
+
465,
|
| 247 |
+
555,
|
| 248 |
+
52,
|
| 249 |
+
179,
|
| 250 |
+
325,
|
| 251 |
+
600,
|
| 252 |
+
738,
|
| 253 |
+
389,
|
| 254 |
+
660,
|
| 255 |
+
109,
|
| 256 |
+
554,
|
| 257 |
+
632,
|
| 258 |
+
673,
|
| 259 |
+
445,
|
| 260 |
+
71,
|
| 261 |
+
403,
|
| 262 |
+
261,
|
| 263 |
+
377,
|
| 264 |
+
81,
|
| 265 |
+
21,
|
| 266 |
+
289,
|
| 267 |
+
23,
|
| 268 |
+
429,
|
| 269 |
+
645,
|
| 270 |
+
741,
|
| 271 |
+
566,
|
| 272 |
+
231,
|
| 273 |
+
357,
|
| 274 |
+
573,
|
| 275 |
+
597,
|
| 276 |
+
263,
|
| 277 |
+
28,
|
| 278 |
+
529,
|
| 279 |
+
372,
|
| 280 |
+
246,
|
| 281 |
+
49,
|
| 282 |
+
219,
|
| 283 |
+
759
|
| 284 |
+
]
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"n_dims": 75,
|
| 288 |
+
"gates": 6375,
|
| 289 |
+
"tp": 818,
|
| 290 |
+
"fp": 483,
|
| 291 |
+
"fn": 182,
|
| 292 |
+
"tn": 517,
|
| 293 |
+
"precision": 0.6287,
|
| 294 |
+
"recall": 0.818,
|
| 295 |
+
"f1": 0.711,
|
| 296 |
+
"time_s": 0.4,
|
| 297 |
+
"dims": [
|
| 298 |
+
665,
|
| 299 |
+
642,
|
| 300 |
+
200,
|
| 301 |
+
305,
|
| 302 |
+
498,
|
| 303 |
+
628,
|
| 304 |
+
67,
|
| 305 |
+
562,
|
| 306 |
+
426,
|
| 307 |
+
723,
|
| 308 |
+
177,
|
| 309 |
+
11,
|
| 310 |
+
465,
|
| 311 |
+
555,
|
| 312 |
+
52,
|
| 313 |
+
179,
|
| 314 |
+
325,
|
| 315 |
+
600,
|
| 316 |
+
738,
|
| 317 |
+
389,
|
| 318 |
+
660,
|
| 319 |
+
109,
|
| 320 |
+
554,
|
| 321 |
+
632,
|
| 322 |
+
673,
|
| 323 |
+
445,
|
| 324 |
+
71,
|
| 325 |
+
403,
|
| 326 |
+
261,
|
| 327 |
+
377,
|
| 328 |
+
81,
|
| 329 |
+
21,
|
| 330 |
+
289,
|
| 331 |
+
23,
|
| 332 |
+
429,
|
| 333 |
+
645,
|
| 334 |
+
741,
|
| 335 |
+
566,
|
| 336 |
+
231,
|
| 337 |
+
357,
|
| 338 |
+
573,
|
| 339 |
+
597,
|
| 340 |
+
263,
|
| 341 |
+
28,
|
| 342 |
+
529,
|
| 343 |
+
372,
|
| 344 |
+
246,
|
| 345 |
+
49,
|
| 346 |
+
219,
|
| 347 |
+
759,
|
| 348 |
+
269,
|
| 349 |
+
593,
|
| 350 |
+
685,
|
| 351 |
+
97,
|
| 352 |
+
485,
|
| 353 |
+
430,
|
| 354 |
+
234,
|
| 355 |
+
297,
|
| 356 |
+
666,
|
| 357 |
+
32,
|
| 358 |
+
198,
|
| 359 |
+
384,
|
| 360 |
+
523,
|
| 361 |
+
292,
|
| 362 |
+
137,
|
| 363 |
+
388,
|
| 364 |
+
364,
|
| 365 |
+
506,
|
| 366 |
+
279,
|
| 367 |
+
101,
|
| 368 |
+
171,
|
| 369 |
+
649,
|
| 370 |
+
259,
|
| 371 |
+
293,
|
| 372 |
+
425
|
| 373 |
+
]
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"n_dims": 100,
|
| 377 |
+
"gates": 8500,
|
| 378 |
+
"tp": 831,
|
| 379 |
+
"fp": 451,
|
| 380 |
+
"fn": 169,
|
| 381 |
+
"tn": 549,
|
| 382 |
+
"precision": 0.6482,
|
| 383 |
+
"recall": 0.831,
|
| 384 |
+
"f1": 0.7283,
|
| 385 |
+
"time_s": 0.5,
|
| 386 |
+
"dims": [
|
| 387 |
+
665,
|
| 388 |
+
642,
|
| 389 |
+
200,
|
| 390 |
+
305,
|
| 391 |
+
498,
|
| 392 |
+
628,
|
| 393 |
+
67,
|
| 394 |
+
562,
|
| 395 |
+
426,
|
| 396 |
+
723,
|
| 397 |
+
177,
|
| 398 |
+
11,
|
| 399 |
+
465,
|
| 400 |
+
555,
|
| 401 |
+
52,
|
| 402 |
+
179,
|
| 403 |
+
325,
|
| 404 |
+
600,
|
| 405 |
+
738,
|
| 406 |
+
389,
|
| 407 |
+
660,
|
| 408 |
+
109,
|
| 409 |
+
554,
|
| 410 |
+
632,
|
| 411 |
+
673,
|
| 412 |
+
445,
|
| 413 |
+
71,
|
| 414 |
+
403,
|
| 415 |
+
261,
|
| 416 |
+
377,
|
| 417 |
+
81,
|
| 418 |
+
21,
|
| 419 |
+
289,
|
| 420 |
+
23,
|
| 421 |
+
429,
|
| 422 |
+
645,
|
| 423 |
+
741,
|
| 424 |
+
566,
|
| 425 |
+
231,
|
| 426 |
+
357,
|
| 427 |
+
573,
|
| 428 |
+
597,
|
| 429 |
+
263,
|
| 430 |
+
28,
|
| 431 |
+
529,
|
| 432 |
+
372,
|
| 433 |
+
246,
|
| 434 |
+
49,
|
| 435 |
+
219,
|
| 436 |
+
759,
|
| 437 |
+
269,
|
| 438 |
+
593,
|
| 439 |
+
685,
|
| 440 |
+
97,
|
| 441 |
+
485,
|
| 442 |
+
430,
|
| 443 |
+
234,
|
| 444 |
+
297,
|
| 445 |
+
666,
|
| 446 |
+
32,
|
| 447 |
+
198,
|
| 448 |
+
384,
|
| 449 |
+
523,
|
| 450 |
+
292,
|
| 451 |
+
137,
|
| 452 |
+
388,
|
| 453 |
+
364,
|
| 454 |
+
506,
|
| 455 |
+
279,
|
| 456 |
+
101,
|
| 457 |
+
171,
|
| 458 |
+
649,
|
| 459 |
+
259,
|
| 460 |
+
293,
|
| 461 |
+
425,
|
| 462 |
+
576,
|
| 463 |
+
144,
|
| 464 |
+
183,
|
| 465 |
+
359,
|
| 466 |
+
437,
|
| 467 |
+
763,
|
| 468 |
+
540,
|
| 469 |
+
335,
|
| 470 |
+
302,
|
| 471 |
+
404,
|
| 472 |
+
202,
|
| 473 |
+
617,
|
| 474 |
+
497,
|
| 475 |
+
408,
|
| 476 |
+
410,
|
| 477 |
+
340,
|
| 478 |
+
15,
|
| 479 |
+
714,
|
| 480 |
+
693,
|
| 481 |
+
277,
|
| 482 |
+
466,
|
| 483 |
+
102,
|
| 484 |
+
681,
|
| 485 |
+
743,
|
| 486 |
+
765
|
| 487 |
+
]
|
| 488 |
+
}
|
| 489 |
+
]
|
circuit/cofiber_detector.sv
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Cofiber detection head — fully combinational per-token detector
|
| 2 |
+
//
|
| 3 |
+
// Input: 768 signed 8-bit feature values (one spatial token)
|
| 4 |
+
// Output: 80 classification scores + 4 box regression values + 1 centerness
|
| 5 |
+
//
|
| 6 |
+
// All weights are ROM (analytically derived, zero training).
|
| 7 |
+
// The cofiber decomposition and pooling happen upstream in the spatial
|
| 8 |
+
// processing module — this module handles per-token prediction only.
|
| 9 |
+
//
|
| 10 |
+
// Parameters:
|
| 11 |
+
// FEAT_DIM - feature dimension (768 for EUPE-ViT-B)
|
| 12 |
+
// NUM_CLASSES - detection classes (80 for COCO)
|
| 13 |
+
// BIT_WIDTH - weight/activation precision
|
| 14 |
+
|
| 15 |
+
module cofiber_detector #(
|
| 16 |
+
parameter FEAT_DIM = 768,
|
| 17 |
+
parameter NUM_CLASSES = 80,
|
| 18 |
+
parameter BIT_WIDTH = 8,
|
| 19 |
+
parameter ACC_WIDTH = 24 // accumulator width for MAC results
|
| 20 |
+
)(
|
| 21 |
+
input logic signed [BIT_WIDTH-1:0] features [0:FEAT_DIM-1],
|
| 22 |
+
output logic signed [ACC_WIDTH-1:0] cls_scores [0:NUM_CLASSES-1],
|
| 23 |
+
output logic signed [ACC_WIDTH-1:0] box_ltrb [0:3],
|
| 24 |
+
output logic signed [ACC_WIDTH-1:0] centerness
|
| 25 |
+
);
|
| 26 |
+
|
| 27 |
+
// Weight ROMs — loaded from analytical solution
|
| 28 |
+
logic signed [BIT_WIDTH-1:0] cls_weight [0:NUM_CLASSES-1][0:FEAT_DIM-1];
|
| 29 |
+
logic signed [BIT_WIDTH-1:0] cls_bias [0:NUM_CLASSES-1];
|
| 30 |
+
logic signed [BIT_WIDTH-1:0] reg_weight [0:3][0:FEAT_DIM-1];
|
| 31 |
+
logic signed [BIT_WIDTH-1:0] reg_bias [0:3];
|
| 32 |
+
logic signed [BIT_WIDTH-1:0] ctr_weight [0:FEAT_DIM-1];
|
| 33 |
+
logic signed [BIT_WIDTH-1:0] ctr_bias;
|
| 34 |
+
|
| 35 |
+
initial begin
|
| 36 |
+
$readmemh("rom/cls_weight.hex", cls_weight);
|
| 37 |
+
$readmemh("rom/cls_bias.hex", cls_bias);
|
| 38 |
+
$readmemh("rom/reg_out_weight.hex", reg_weight);
|
| 39 |
+
$readmemh("rom/reg_out_bias.hex", reg_bias);
|
| 40 |
+
$readmemh("rom/ctr_weight.hex", ctr_weight);
|
| 41 |
+
$readmemh("rom/ctr_bias.hex", ctr_bias);
|
| 42 |
+
end
|
| 43 |
+
|
| 44 |
+
// Classification: 80 parallel dot products
|
| 45 |
+
// cls_scores[c] = sum(features[d] * cls_weight[c][d]) + cls_bias[c]
|
| 46 |
+
genvar c, d;
|
| 47 |
+
generate
|
| 48 |
+
for (c = 0; c < NUM_CLASSES; c = c + 1) begin : cls_mac
|
| 49 |
+
logic signed [ACC_WIDTH-1:0] acc;
|
| 50 |
+
always_comb begin
|
| 51 |
+
acc = {{(ACC_WIDTH-BIT_WIDTH){cls_bias[c][BIT_WIDTH-1]}}, cls_bias[c]};
|
| 52 |
+
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
|
| 53 |
+
acc = acc + (features[dd] * cls_weight[c][dd]);
|
| 54 |
+
end
|
| 55 |
+
cls_scores[c] = acc;
|
| 56 |
+
end
|
| 57 |
+
end
|
| 58 |
+
endgenerate
|
| 59 |
+
|
| 60 |
+
// Box regression: 4 parallel dot products
|
| 61 |
+
generate
|
| 62 |
+
for (c = 0; c < 4; c = c + 1) begin : reg_mac
|
| 63 |
+
logic signed [ACC_WIDTH-1:0] acc;
|
| 64 |
+
always_comb begin
|
| 65 |
+
acc = {{(ACC_WIDTH-BIT_WIDTH){reg_bias[c][BIT_WIDTH-1]}}, reg_bias[c]};
|
| 66 |
+
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
|
| 67 |
+
acc = acc + (features[dd] * reg_weight[c][dd]);
|
| 68 |
+
end
|
| 69 |
+
box_ltrb[c] = acc;
|
| 70 |
+
end
|
| 71 |
+
end
|
| 72 |
+
endgenerate
|
| 73 |
+
|
| 74 |
+
// Centerness: 1 dot product
|
| 75 |
+
logic signed [ACC_WIDTH-1:0] ctr_acc;
|
| 76 |
+
always_comb begin
|
| 77 |
+
ctr_acc = {{(ACC_WIDTH-BIT_WIDTH){ctr_bias[BIT_WIDTH-1]}}, ctr_bias};
|
| 78 |
+
for (int dd = 0; dd < FEAT_DIM; dd = dd + 1) begin
|
| 79 |
+
ctr_acc = ctr_acc + (features[dd] * ctr_weight[dd]);
|
| 80 |
+
end
|
| 81 |
+
centerness = ctr_acc;
|
| 82 |
+
end
|
| 83 |
+
|
| 84 |
+
endmodule
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
// Cofiber spatial decomposition — operates on the full feature grid
|
| 88 |
+
// Produces 3 scale bands from the input feature map
|
| 89 |
+
module cofiber_decompose #(
|
| 90 |
+
parameter FEAT_DIM = 768,
|
| 91 |
+
parameter BIT_WIDTH = 8,
|
| 92 |
+
parameter H = 40,
|
| 93 |
+
parameter W = 40
|
| 94 |
+
)(
|
| 95 |
+
input logic signed [BIT_WIDTH-1:0] features [0:FEAT_DIM-1][0:H-1][0:W-1],
|
| 96 |
+
output logic signed [BIT_WIDTH-1:0] scale0 [0:FEAT_DIM-1][0:H-1][0:W-1], // stride 16 cofiber
|
| 97 |
+
output logic signed [BIT_WIDTH-1:0] scale1 [0:FEAT_DIM-1][0:H/2-1][0:W/2-1], // stride 32 cofiber
|
| 98 |
+
output logic signed [BIT_WIDTH-1:0] scale2 [0:FEAT_DIM-1][0:H/4-1][0:W/4-1] // stride 64 residual
|
| 99 |
+
);
|
| 100 |
+
|
| 101 |
+
// Intermediate: pooled features at half resolution
|
| 102 |
+
logic signed [BIT_WIDTH+1:0] pool0 [0:FEAT_DIM-1][0:H/2-1][0:W/2-1];
|
| 103 |
+
logic signed [BIT_WIDTH+1:0] pool1 [0:FEAT_DIM-1][0:H/4-1][0:W/4-1];
|
| 104 |
+
|
| 105 |
+
genvar ch, r, col;
|
| 106 |
+
generate
|
| 107 |
+
// Pool0: 2x2 average pool of input features
|
| 108 |
+
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : pool0_ch
|
| 109 |
+
for (r = 0; r < H/2; r = r + 1) begin : pool0_r
|
| 110 |
+
for (col = 0; col < W/2; col = col + 1) begin : pool0_c
|
| 111 |
+
assign pool0[ch][r][col] = (features[ch][2*r][2*col]
|
| 112 |
+
+ features[ch][2*r+1][2*col]
|
| 113 |
+
+ features[ch][2*r][2*col+1]
|
| 114 |
+
+ features[ch][2*r+1][2*col+1]) >>> 2;
|
| 115 |
+
end
|
| 116 |
+
end
|
| 117 |
+
end
|
| 118 |
+
|
| 119 |
+
// Scale0: cofiber = features - upsample(pool0)
|
| 120 |
+
// Nearest-neighbor upsample for exact integer arithmetic
|
| 121 |
+
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s0_ch
|
| 122 |
+
for (r = 0; r < H; r = r + 1) begin : s0_r
|
| 123 |
+
for (col = 0; col < W; col = col + 1) begin : s0_c
|
| 124 |
+
assign scale0[ch][r][col] = features[ch][r][col]
|
| 125 |
+
- pool0[ch][r/2][col/2][BIT_WIDTH-1:0];
|
| 126 |
+
end
|
| 127 |
+
end
|
| 128 |
+
end
|
| 129 |
+
|
| 130 |
+
// Pool1: 2x2 average pool of pool0
|
| 131 |
+
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : pool1_ch
|
| 132 |
+
for (r = 0; r < H/4; r = r + 1) begin : pool1_r
|
| 133 |
+
for (col = 0; col < W/4; col = col + 1) begin : pool1_c
|
| 134 |
+
assign pool1[ch][r][col] = (pool0[ch][2*r][2*col]
|
| 135 |
+
+ pool0[ch][2*r+1][2*col]
|
| 136 |
+
+ pool0[ch][2*r][2*col+1]
|
| 137 |
+
+ pool0[ch][2*r+1][2*col+1]) >>> 2;
|
| 138 |
+
end
|
| 139 |
+
end
|
| 140 |
+
end
|
| 141 |
+
|
| 142 |
+
// Scale1: cofiber of pool0
|
| 143 |
+
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s1_ch
|
| 144 |
+
for (r = 0; r < H/2; r = r + 1) begin : s1_r
|
| 145 |
+
for (col = 0; col < W/2; col = col + 1) begin : s1_c
|
| 146 |
+
assign scale1[ch][r][col] = pool0[ch][r][col][BIT_WIDTH-1:0]
|
| 147 |
+
- pool1[ch][r/2][col/2][BIT_WIDTH-1:0];
|
| 148 |
+
end
|
| 149 |
+
end
|
| 150 |
+
end
|
| 151 |
+
|
| 152 |
+
// Scale2: the low-frequency residual
|
| 153 |
+
for (ch = 0; ch < FEAT_DIM; ch = ch + 1) begin : s2_ch
|
| 154 |
+
for (r = 0; r < H/4; r = r + 1) begin : s2_r
|
| 155 |
+
for (col = 0; col < W/4; col = col + 1) begin : s2_c
|
| 156 |
+
assign scale2[ch][r][col] = pool1[ch][r][col][BIT_WIDTH-1:0];
|
| 157 |
+
end
|
| 158 |
+
end
|
| 159 |
+
end
|
| 160 |
+
endgenerate
|
| 161 |
+
|
| 162 |
+
endmodule
|
circuit/evolve_fast.py
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Fixed-K batched GPU evolution. All individuals have exactly K dims.
|
| 3 |
+
|
| 4 |
+
Genome: (POP, K) int tensor — indices into 768 feature dims.
|
| 5 |
+
Fitness: one batched torch.linalg.solve over (POP, K+1, K+1).
|
| 6 |
+
Target: hundreds of gen/s.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import json, os, sys, time
|
| 10 |
+
import torch
|
| 11 |
+
|
| 12 |
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 13 |
+
REPO_ROOT = os.path.dirname(SCRIPT_DIR)
|
| 14 |
+
VAL_TENSORS = os.path.join(REPO_ROOT, "analytical_stats_cache", "val_tensors_layernorm_500.pt")
|
| 15 |
+
GREEDY_PATH = os.path.join(REPO_ROOT, "analytical_variants", "greedy_forward_gpu.json")
|
| 16 |
+
PERSON_CLASS = 0
|
| 17 |
+
DEVICE = "cuda"
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@torch.no_grad()
|
| 21 |
+
def batch_fitness(features, is_person, pop_dims, lam=0.1):
|
| 22 |
+
"""Evaluate entire population in one batched solve.
|
| 23 |
+
|
| 24 |
+
features: (N, 768)
|
| 25 |
+
is_person: (N,) bool
|
| 26 |
+
pop_dims: (POP, K) long — which dims each individual uses
|
| 27 |
+
Returns: (POP,) F1 scores
|
| 28 |
+
"""
|
| 29 |
+
POP, K = pop_dims.shape
|
| 30 |
+
N = features.shape[0]
|
| 31 |
+
|
| 32 |
+
# Gather features for all individuals: (POP, N, K)
|
| 33 |
+
f_batch = features[:, :].unsqueeze(0).expand(POP, -1, -1) # (POP, N, 768)
|
| 34 |
+
idx = pop_dims.unsqueeze(1).expand(-1, N, -1) # (POP, N, K)
|
| 35 |
+
f_sub = torch.gather(f_batch, 2, idx) # (POP, N, K)
|
| 36 |
+
|
| 37 |
+
# Augment with bias column: (POP, N, K+1)
|
| 38 |
+
ones = torch.ones(POP, N, 1, device=DEVICE)
|
| 39 |
+
fa = torch.cat([f_sub, ones], dim=2)
|
| 40 |
+
|
| 41 |
+
# XtX: (POP, K+1, K+1) = fa^T @ fa
|
| 42 |
+
XtX = torch.bmm(fa.transpose(1, 2), fa)
|
| 43 |
+
|
| 44 |
+
# Regularize
|
| 45 |
+
I = torch.eye(K + 1, device=DEVICE).unsqueeze(0).expand(POP, -1, -1)
|
| 46 |
+
XtX = XtX + lam * I * N
|
| 47 |
+
|
| 48 |
+
# XtY: (POP, K+1, 1) = fa^T @ y
|
| 49 |
+
y = is_person.float().unsqueeze(0).unsqueeze(2).expand(POP, -1, -1) # (POP, N, 1)
|
| 50 |
+
XtY = torch.bmm(fa.transpose(1, 2), y)
|
| 51 |
+
|
| 52 |
+
# Batched solve: (POP, K+1, 1)
|
| 53 |
+
try:
|
| 54 |
+
W = torch.linalg.solve(XtX, XtY)
|
| 55 |
+
except Exception:
|
| 56 |
+
return torch.zeros(POP, device=DEVICE)
|
| 57 |
+
|
| 58 |
+
# Predict: (POP, N, 1)
|
| 59 |
+
scores = torch.bmm(fa, W)
|
| 60 |
+
pred = scores.squeeze(2) > 0.5 # (POP, N)
|
| 61 |
+
|
| 62 |
+
# F1 per individual
|
| 63 |
+
is_p = is_person.unsqueeze(0).expand(POP, -1)
|
| 64 |
+
tp = (pred & is_p).sum(dim=1).float()
|
| 65 |
+
fp = (pred & ~is_p).sum(dim=1).float()
|
| 66 |
+
fn = (~pred & is_p).sum(dim=1).float()
|
| 67 |
+
prec = tp / (tp + fp).clamp(min=1)
|
| 68 |
+
rec = tp / (tp + fn).clamp(min=1)
|
| 69 |
+
f1 = 2 * prec * rec / (prec + rec).clamp(min=1e-9)
|
| 70 |
+
return f1
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def main():
|
| 74 |
+
print("=" * 60)
|
| 75 |
+
print("Fixed-K Batched GPU Evolution")
|
| 76 |
+
print("=" * 60, flush=True)
|
| 77 |
+
|
| 78 |
+
val = torch.load(VAL_TENSORS, map_location="cpu", weights_only=False)
|
| 79 |
+
features = val["features"]
|
| 80 |
+
is_person = (val["cls_targets"] == PERSON_CLASS)
|
| 81 |
+
|
| 82 |
+
pos_idx = is_person.nonzero(as_tuple=True)[0]
|
| 83 |
+
neg_idx = (~is_person).nonzero(as_tuple=True)[0]
|
| 84 |
+
n_take = min(2000, len(pos_idx))
|
| 85 |
+
sel = torch.cat([pos_idx[torch.randperm(len(pos_idx))[:n_take]],
|
| 86 |
+
neg_idx[torch.randperm(len(neg_idx))[:n_take]]])
|
| 87 |
+
sel = sel[torch.randperm(len(sel))]
|
| 88 |
+
sub_f = features[sel].to(DEVICE)
|
| 89 |
+
sub_person = is_person[sel].to(DEVICE)
|
| 90 |
+
N = len(sel)
|
| 91 |
+
print(f" {N} vectors on {DEVICE}", flush=True)
|
| 92 |
+
|
| 93 |
+
greedy_dims = list(range(100))
|
| 94 |
+
if os.path.isfile(GREEDY_PATH):
|
| 95 |
+
with open(GREEDY_PATH) as f:
|
| 96 |
+
greedy_dims = json.load(f)["selected_dims"]
|
| 97 |
+
|
| 98 |
+
POP = 512
|
| 99 |
+
GEN = 5000
|
| 100 |
+
ELITE = 30
|
| 101 |
+
TARGETS = [10, 20, 50, 100, 200]
|
| 102 |
+
|
| 103 |
+
all_results = []
|
| 104 |
+
|
| 105 |
+
for K in TARGETS:
|
| 106 |
+
print(f"\n{'='*60}")
|
| 107 |
+
print(f" K={K} dims | pop={POP} | gen={GEN}")
|
| 108 |
+
print(f"{'='*60}", flush=True)
|
| 109 |
+
t0 = time.time()
|
| 110 |
+
|
| 111 |
+
# Initialize population: (POP, K) long tensors
|
| 112 |
+
pop = torch.zeros(POP, K, dtype=torch.long, device=DEVICE)
|
| 113 |
+
|
| 114 |
+
# Seed 0: greedy
|
| 115 |
+
g = greedy_dims[:K] if K <= len(greedy_dims) else greedy_dims + list(range(K - len(greedy_dims)))
|
| 116 |
+
pop[0] = torch.tensor(g[:K], device=DEVICE)
|
| 117 |
+
|
| 118 |
+
# Rest: random K-subsets of 768
|
| 119 |
+
for i in range(1, POP):
|
| 120 |
+
pop[i] = torch.randperm(768, device=DEVICE)[:K]
|
| 121 |
+
|
| 122 |
+
fits = batch_fitness(sub_f, sub_person, pop)
|
| 123 |
+
best_f1 = fits.max().item()
|
| 124 |
+
best_genome = pop[fits.argmax()].clone()
|
| 125 |
+
stag = 0
|
| 126 |
+
|
| 127 |
+
for gen in range(GEN):
|
| 128 |
+
# Sort
|
| 129 |
+
order = fits.argsort(descending=True)
|
| 130 |
+
pop = pop[order]
|
| 131 |
+
fits = fits[order]
|
| 132 |
+
|
| 133 |
+
if fits[0].item() > best_f1:
|
| 134 |
+
best_f1 = fits[0].item()
|
| 135 |
+
best_genome = pop[0].clone()
|
| 136 |
+
stag = 0
|
| 137 |
+
else:
|
| 138 |
+
stag += 1
|
| 139 |
+
|
| 140 |
+
# New population
|
| 141 |
+
new_pop = pop[:ELITE].clone()
|
| 142 |
+
|
| 143 |
+
# Immigration
|
| 144 |
+
n_imm = POP // 5 if stag > 200 else 0
|
| 145 |
+
if n_imm > 0:
|
| 146 |
+
imm = torch.stack([torch.randperm(768, device=DEVICE)[:K] for _ in range(n_imm)])
|
| 147 |
+
new_pop = torch.cat([new_pop, imm])
|
| 148 |
+
|
| 149 |
+
# Breed
|
| 150 |
+
n_breed = POP - new_pop.shape[0]
|
| 151 |
+
# Tournament selection
|
| 152 |
+
t1 = torch.randint(0, POP // 2, (n_breed, 5), device=DEVICE)
|
| 153 |
+
p1_idx = t1[torch.arange(n_breed, device=DEVICE), fits[t1].argmax(dim=1)]
|
| 154 |
+
t2 = torch.randint(0, POP // 2, (n_breed, 5), device=DEVICE)
|
| 155 |
+
p2_idx = t2[torch.arange(n_breed, device=DEVICE), fits[t2].argmax(dim=1)]
|
| 156 |
+
|
| 157 |
+
parents1 = pop[p1_idx] # (n_breed, K)
|
| 158 |
+
parents2 = pop[p2_idx]
|
| 159 |
+
|
| 160 |
+
# Crossover: for each position, pick from parent1 or parent2
|
| 161 |
+
mask = torch.rand(n_breed, K, device=DEVICE) < 0.5
|
| 162 |
+
children = torch.where(mask, parents1, parents2)
|
| 163 |
+
|
| 164 |
+
# Mutation: replace random positions with random dims
|
| 165 |
+
mut_rate = 0.05 * (1 + stag / 100)
|
| 166 |
+
mut_mask = torch.rand(n_breed, K, device=DEVICE) < mut_rate
|
| 167 |
+
random_dims = torch.randint(0, 768, (n_breed, K), device=DEVICE)
|
| 168 |
+
children = torch.where(mut_mask, random_dims, children)
|
| 169 |
+
|
| 170 |
+
new_pop = torch.cat([new_pop, children])[:POP]
|
| 171 |
+
pop = new_pop
|
| 172 |
+
fits = batch_fitness(sub_f, sub_person, pop)
|
| 173 |
+
|
| 174 |
+
if (gen + 1) % 100 == 0:
|
| 175 |
+
elapsed = time.time() - t0
|
| 176 |
+
gen_s = (gen + 1) / elapsed
|
| 177 |
+
print(f" gen {gen+1:5d}: best={fits.max().item():.4f} "
|
| 178 |
+
f"best_ever={best_f1:.4f} stag={stag} "
|
| 179 |
+
f"{gen_s:.0f} gen/s", flush=True)
|
| 180 |
+
|
| 181 |
+
if stag > 1000:
|
| 182 |
+
print(f" Converged at gen {gen+1}")
|
| 183 |
+
break
|
| 184 |
+
|
| 185 |
+
elapsed = time.time() - t0
|
| 186 |
+
best_dims = best_genome.cpu().tolist()
|
| 187 |
+
gates = K * 85
|
| 188 |
+
gens_done = gen + 1
|
| 189 |
+
print(f"\n WINNER: {K} dims, F1={best_f1:.4f}, {gates} gates, "
|
| 190 |
+
f"{elapsed:.1f}s, {gens_done/elapsed:.0f} gen/s", flush=True)
|
| 191 |
+
|
| 192 |
+
all_results.append({
|
| 193 |
+
"K": K, "best_f1": round(best_f1, 4), "genome": sorted(best_dims),
|
| 194 |
+
"gates": gates, "time_s": round(elapsed, 1),
|
| 195 |
+
"generations": gens_done, "gen_per_s": round(gens_done / elapsed),
|
| 196 |
+
})
|
| 197 |
+
|
| 198 |
+
print(f"\n{'='*60}")
|
| 199 |
+
print("Results:")
|
| 200 |
+
for r in all_results:
|
| 201 |
+
print(f" K={r['K']:3d} {r['gates']:6d} gates F1={r['best_f1']:.4f} "
|
| 202 |
+
f"{r['gen_per_s']} gen/s ({r['generations']} gen, {r['time_s']}s)")
|
| 203 |
+
|
| 204 |
+
out = os.path.join(SCRIPT_DIR, "evolved_extreme.json")
|
| 205 |
+
with open(out, "w") as f:
|
| 206 |
+
json.dump(all_results, f, indent=2)
|
| 207 |
+
print(f"Saved: {out}")
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
if __name__ == "__main__":
|
| 211 |
+
main()
|
circuit/evolved_K100_person_eval.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"head": "evolved_K100_person",
|
| 3 |
+
"dims": 92,
|
| 4 |
+
"gates": 7820,
|
| 5 |
+
"training": "zero (evolved analytical)",
|
| 6 |
+
"mAP_person": 0.0132,
|
| 7 |
+
"mAP50_person": 0.0577,
|
| 8 |
+
"mAP75_person": 0.0011
|
| 9 |
+
}
|
circuit/evolved_extreme.json
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"K": 10,
|
| 4 |
+
"best_f1": 0.7605,
|
| 5 |
+
"genome": [
|
| 6 |
+
48,
|
| 7 |
+
83,
|
| 8 |
+
101,
|
| 9 |
+
157,
|
| 10 |
+
224,
|
| 11 |
+
365,
|
| 12 |
+
379,
|
| 13 |
+
428,
|
| 14 |
+
517,
|
| 15 |
+
525
|
| 16 |
+
],
|
| 17 |
+
"gates": 850,
|
| 18 |
+
"time_s": 15.3,
|
| 19 |
+
"generations": 1529,
|
| 20 |
+
"gen_per_s": 100
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"K": 20,
|
| 24 |
+
"best_f1": 0.7746,
|
| 25 |
+
"genome": [
|
| 26 |
+
48,
|
| 27 |
+
65,
|
| 28 |
+
74,
|
| 29 |
+
90,
|
| 30 |
+
112,
|
| 31 |
+
116,
|
| 32 |
+
117,
|
| 33 |
+
140,
|
| 34 |
+
224,
|
| 35 |
+
338,
|
| 36 |
+
379,
|
| 37 |
+
453,
|
| 38 |
+
511,
|
| 39 |
+
517,
|
| 40 |
+
518,
|
| 41 |
+
525,
|
| 42 |
+
566,
|
| 43 |
+
595,
|
| 44 |
+
641,
|
| 45 |
+
645
|
| 46 |
+
],
|
| 47 |
+
"gates": 1700,
|
| 48 |
+
"time_s": 14.8,
|
| 49 |
+
"generations": 1052,
|
| 50 |
+
"gen_per_s": 71
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"K": 50,
|
| 54 |
+
"best_f1": 0.8009,
|
| 55 |
+
"genome": [
|
| 56 |
+
12,
|
| 57 |
+
48,
|
| 58 |
+
62,
|
| 59 |
+
74,
|
| 60 |
+
101,
|
| 61 |
+
116,
|
| 62 |
+
126,
|
| 63 |
+
149,
|
| 64 |
+
157,
|
| 65 |
+
182,
|
| 66 |
+
200,
|
| 67 |
+
215,
|
| 68 |
+
224,
|
| 69 |
+
240,
|
| 70 |
+
244,
|
| 71 |
+
267,
|
| 72 |
+
276,
|
| 73 |
+
282,
|
| 74 |
+
298,
|
| 75 |
+
319,
|
| 76 |
+
329,
|
| 77 |
+
331,
|
| 78 |
+
338,
|
| 79 |
+
349,
|
| 80 |
+
359,
|
| 81 |
+
364,
|
| 82 |
+
368,
|
| 83 |
+
379,
|
| 84 |
+
454,
|
| 85 |
+
467,
|
| 86 |
+
468,
|
| 87 |
+
503,
|
| 88 |
+
510,
|
| 89 |
+
512,
|
| 90 |
+
517,
|
| 91 |
+
525,
|
| 92 |
+
556,
|
| 93 |
+
560,
|
| 94 |
+
569,
|
| 95 |
+
590,
|
| 96 |
+
608,
|
| 97 |
+
627,
|
| 98 |
+
634,
|
| 99 |
+
635,
|
| 100 |
+
656,
|
| 101 |
+
678,
|
| 102 |
+
679,
|
| 103 |
+
715,
|
| 104 |
+
729,
|
| 105 |
+
756
|
| 106 |
+
],
|
| 107 |
+
"gates": 4250,
|
| 108 |
+
"time_s": 21.9,
|
| 109 |
+
"generations": 1159,
|
| 110 |
+
"gen_per_s": 53
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"K": 100,
|
| 114 |
+
"best_f1": 0.823,
|
| 115 |
+
"genome": [
|
| 116 |
+
17,
|
| 117 |
+
18,
|
| 118 |
+
33,
|
| 119 |
+
48,
|
| 120 |
+
56,
|
| 121 |
+
59,
|
| 122 |
+
62,
|
| 123 |
+
63,
|
| 124 |
+
64,
|
| 125 |
+
70,
|
| 126 |
+
70,
|
| 127 |
+
77,
|
| 128 |
+
80,
|
| 129 |
+
90,
|
| 130 |
+
92,
|
| 131 |
+
95,
|
| 132 |
+
104,
|
| 133 |
+
113,
|
| 134 |
+
116,
|
| 135 |
+
130,
|
| 136 |
+
141,
|
| 137 |
+
154,
|
| 138 |
+
154,
|
| 139 |
+
157,
|
| 140 |
+
167,
|
| 141 |
+
177,
|
| 142 |
+
178,
|
| 143 |
+
182,
|
| 144 |
+
209,
|
| 145 |
+
210,
|
| 146 |
+
224,
|
| 147 |
+
250,
|
| 148 |
+
253,
|
| 149 |
+
256,
|
| 150 |
+
257,
|
| 151 |
+
259,
|
| 152 |
+
260,
|
| 153 |
+
260,
|
| 154 |
+
266,
|
| 155 |
+
276,
|
| 156 |
+
282,
|
| 157 |
+
298,
|
| 158 |
+
299,
|
| 159 |
+
306,
|
| 160 |
+
324,
|
| 161 |
+
329,
|
| 162 |
+
335,
|
| 163 |
+
338,
|
| 164 |
+
359,
|
| 165 |
+
359,
|
| 166 |
+
362,
|
| 167 |
+
365,
|
| 168 |
+
379,
|
| 169 |
+
385,
|
| 170 |
+
385,
|
| 171 |
+
392,
|
| 172 |
+
397,
|
| 173 |
+
404,
|
| 174 |
+
408,
|
| 175 |
+
418,
|
| 176 |
+
423,
|
| 177 |
+
428,
|
| 178 |
+
466,
|
| 179 |
+
467,
|
| 180 |
+
478,
|
| 181 |
+
507,
|
| 182 |
+
510,
|
| 183 |
+
517,
|
| 184 |
+
517,
|
| 185 |
+
527,
|
| 186 |
+
533,
|
| 187 |
+
560,
|
| 188 |
+
564,
|
| 189 |
+
569,
|
| 190 |
+
569,
|
| 191 |
+
577,
|
| 192 |
+
598,
|
| 193 |
+
608,
|
| 194 |
+
614,
|
| 195 |
+
618,
|
| 196 |
+
619,
|
| 197 |
+
635,
|
| 198 |
+
636,
|
| 199 |
+
645,
|
| 200 |
+
650,
|
| 201 |
+
656,
|
| 202 |
+
664,
|
| 203 |
+
679,
|
| 204 |
+
687,
|
| 205 |
+
691,
|
| 206 |
+
697,
|
| 207 |
+
706,
|
| 208 |
+
709,
|
| 209 |
+
709,
|
| 210 |
+
715,
|
| 211 |
+
729,
|
| 212 |
+
741,
|
| 213 |
+
754,
|
| 214 |
+
756,
|
| 215 |
+
766
|
| 216 |
+
],
|
| 217 |
+
"gates": 8500,
|
| 218 |
+
"time_s": 33.3,
|
| 219 |
+
"generations": 1134,
|
| 220 |
+
"gen_per_s": 34
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"K": 200,
|
| 224 |
+
"best_f1": 0.8317,
|
| 225 |
+
"genome": [
|
| 226 |
+
4,
|
| 227 |
+
7,
|
| 228 |
+
8,
|
| 229 |
+
12,
|
| 230 |
+
13,
|
| 231 |
+
14,
|
| 232 |
+
17,
|
| 233 |
+
20,
|
| 234 |
+
21,
|
| 235 |
+
22,
|
| 236 |
+
25,
|
| 237 |
+
28,
|
| 238 |
+
30,
|
| 239 |
+
32,
|
| 240 |
+
37,
|
| 241 |
+
38,
|
| 242 |
+
45,
|
| 243 |
+
48,
|
| 244 |
+
49,
|
| 245 |
+
50,
|
| 246 |
+
55,
|
| 247 |
+
62,
|
| 248 |
+
69,
|
| 249 |
+
71,
|
| 250 |
+
74,
|
| 251 |
+
80,
|
| 252 |
+
80,
|
| 253 |
+
81,
|
| 254 |
+
89,
|
| 255 |
+
92,
|
| 256 |
+
94,
|
| 257 |
+
100,
|
| 258 |
+
102,
|
| 259 |
+
104,
|
| 260 |
+
106,
|
| 261 |
+
107,
|
| 262 |
+
110,
|
| 263 |
+
112,
|
| 264 |
+
113,
|
| 265 |
+
130,
|
| 266 |
+
133,
|
| 267 |
+
135,
|
| 268 |
+
135,
|
| 269 |
+
137,
|
| 270 |
+
138,
|
| 271 |
+
138,
|
| 272 |
+
143,
|
| 273 |
+
143,
|
| 274 |
+
147,
|
| 275 |
+
149,
|
| 276 |
+
154,
|
| 277 |
+
163,
|
| 278 |
+
171,
|
| 279 |
+
177,
|
| 280 |
+
183,
|
| 281 |
+
189,
|
| 282 |
+
193,
|
| 283 |
+
197,
|
| 284 |
+
205,
|
| 285 |
+
206,
|
| 286 |
+
209,
|
| 287 |
+
210,
|
| 288 |
+
217,
|
| 289 |
+
217,
|
| 290 |
+
224,
|
| 291 |
+
226,
|
| 292 |
+
226,
|
| 293 |
+
231,
|
| 294 |
+
247,
|
| 295 |
+
253,
|
| 296 |
+
254,
|
| 297 |
+
256,
|
| 298 |
+
257,
|
| 299 |
+
259,
|
| 300 |
+
260,
|
| 301 |
+
260,
|
| 302 |
+
266,
|
| 303 |
+
267,
|
| 304 |
+
276,
|
| 305 |
+
276,
|
| 306 |
+
278,
|
| 307 |
+
282,
|
| 308 |
+
296,
|
| 309 |
+
297,
|
| 310 |
+
299,
|
| 311 |
+
300,
|
| 312 |
+
302,
|
| 313 |
+
305,
|
| 314 |
+
306,
|
| 315 |
+
307,
|
| 316 |
+
308,
|
| 317 |
+
320,
|
| 318 |
+
322,
|
| 319 |
+
327,
|
| 320 |
+
329,
|
| 321 |
+
337,
|
| 322 |
+
337,
|
| 323 |
+
338,
|
| 324 |
+
338,
|
| 325 |
+
345,
|
| 326 |
+
346,
|
| 327 |
+
357,
|
| 328 |
+
359,
|
| 329 |
+
365,
|
| 330 |
+
365,
|
| 331 |
+
366,
|
| 332 |
+
376,
|
| 333 |
+
379,
|
| 334 |
+
379,
|
| 335 |
+
379,
|
| 336 |
+
383,
|
| 337 |
+
385,
|
| 338 |
+
392,
|
| 339 |
+
397,
|
| 340 |
+
414,
|
| 341 |
+
415,
|
| 342 |
+
419,
|
| 343 |
+
420,
|
| 344 |
+
424,
|
| 345 |
+
428,
|
| 346 |
+
428,
|
| 347 |
+
435,
|
| 348 |
+
435,
|
| 349 |
+
445,
|
| 350 |
+
447,
|
| 351 |
+
448,
|
| 352 |
+
449,
|
| 353 |
+
454,
|
| 354 |
+
462,
|
| 355 |
+
476,
|
| 356 |
+
482,
|
| 357 |
+
500,
|
| 358 |
+
505,
|
| 359 |
+
510,
|
| 360 |
+
517,
|
| 361 |
+
519,
|
| 362 |
+
522,
|
| 363 |
+
522,
|
| 364 |
+
523,
|
| 365 |
+
525,
|
| 366 |
+
527,
|
| 367 |
+
528,
|
| 368 |
+
531,
|
| 369 |
+
535,
|
| 370 |
+
541,
|
| 371 |
+
546,
|
| 372 |
+
549,
|
| 373 |
+
553,
|
| 374 |
+
558,
|
| 375 |
+
560,
|
| 376 |
+
562,
|
| 377 |
+
563,
|
| 378 |
+
566,
|
| 379 |
+
574,
|
| 380 |
+
583,
|
| 381 |
+
584,
|
| 382 |
+
587,
|
| 383 |
+
591,
|
| 384 |
+
597,
|
| 385 |
+
598,
|
| 386 |
+
602,
|
| 387 |
+
603,
|
| 388 |
+
614,
|
| 389 |
+
616,
|
| 390 |
+
616,
|
| 391 |
+
619,
|
| 392 |
+
629,
|
| 393 |
+
630,
|
| 394 |
+
636,
|
| 395 |
+
641,
|
| 396 |
+
644,
|
| 397 |
+
645,
|
| 398 |
+
650,
|
| 399 |
+
654,
|
| 400 |
+
656,
|
| 401 |
+
657,
|
| 402 |
+
657,
|
| 403 |
+
667,
|
| 404 |
+
671,
|
| 405 |
+
679,
|
| 406 |
+
690,
|
| 407 |
+
699,
|
| 408 |
+
709,
|
| 409 |
+
710,
|
| 410 |
+
713,
|
| 411 |
+
713,
|
| 412 |
+
717,
|
| 413 |
+
718,
|
| 414 |
+
721,
|
| 415 |
+
722,
|
| 416 |
+
731,
|
| 417 |
+
733,
|
| 418 |
+
741,
|
| 419 |
+
742,
|
| 420 |
+
748,
|
| 421 |
+
750,
|
| 422 |
+
751,
|
| 423 |
+
755,
|
| 424 |
+
757,
|
| 425 |
+
764
|
| 426 |
+
],
|
| 427 |
+
"gates": 17000,
|
| 428 |
+
"time_s": 66.5,
|
| 429 |
+
"generations": 1159,
|
| 430 |
+
"gen_per_s": 17
|
| 431 |
+
},
|
| 432 |
+
{
|
| 433 |
+
"K": 300,
|
| 434 |
+
"best_f1": 0.8445,
|
| 435 |
+
"genome": [],
|
| 436 |
+
"gates": 25500,
|
| 437 |
+
"time_s": 220
|
| 438 |
+
},
|
| 439 |
+
{
|
| 440 |
+
"K": 400,
|
| 441 |
+
"best_f1": 0.8435,
|
| 442 |
+
"genome": [],
|
| 443 |
+
"gates": 34000,
|
| 444 |
+
"time_s": 350
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"K": 500,
|
| 448 |
+
"best_f1": 0.8458,
|
| 449 |
+
"genome": [],
|
| 450 |
+
"gates": 42500,
|
| 451 |
+
"time_s": 398
|
| 452 |
+
}
|
| 453 |
+
]
|
circuit/person_analytical.pth
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:65728b60610a3fc166386e46af9205b645ccfca08dfdf44c3b8d76aee0c3b5eb
|
| 3 |
+
size 20795
|
circuit/person_detector.sv
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Single-class person detector — Icarus Verilog compatible
|
| 2 |
+
// All weights from analytical least-squares. Zero training. 4,614 bytes INT8.
|
| 3 |
+
|
| 4 |
+
module person_detector #(
|
| 5 |
+
parameter FEAT_DIM = 768,
|
| 6 |
+
parameter BIT_WIDTH = 8,
|
| 7 |
+
parameter ACC_WIDTH = 24
|
| 8 |
+
)(
|
| 9 |
+
input wire signed [BIT_WIDTH-1:0] features [0:FEAT_DIM-1],
|
| 10 |
+
output wire signed [ACC_WIDTH-1:0] person_score,
|
| 11 |
+
output wire signed [ACC_WIDTH-1:0] box_ltrb [0:3],
|
| 12 |
+
output wire signed [ACC_WIDTH-1:0] centerness,
|
| 13 |
+
output wire detection
|
| 14 |
+
);
|
| 15 |
+
|
| 16 |
+
reg signed [BIT_WIDTH-1:0] cls_w [0:FEAT_DIM-1];
|
| 17 |
+
reg signed [BIT_WIDTH-1:0] reg_w [0:4*FEAT_DIM-1];
|
| 18 |
+
reg signed [BIT_WIDTH-1:0] ctr_w [0:FEAT_DIM-1];
|
| 19 |
+
|
| 20 |
+
initial begin
|
| 21 |
+
$readmemh("rom/person_cls_w.hex", cls_w);
|
| 22 |
+
$readmemh("rom/person_reg_w.hex", reg_w);
|
| 23 |
+
$readmemh("rom/person_ctr_w.hex", ctr_w);
|
| 24 |
+
end
|
| 25 |
+
|
| 26 |
+
// Classification: sum(features[d] * cls_w[d])
|
| 27 |
+
reg signed [ACC_WIDTH-1:0] cls_acc;
|
| 28 |
+
integer ci;
|
| 29 |
+
always @(*) begin
|
| 30 |
+
cls_acc = 0;
|
| 31 |
+
for (ci = 0; ci < FEAT_DIM; ci = ci + 1)
|
| 32 |
+
cls_acc = cls_acc + features[ci] * cls_w[ci];
|
| 33 |
+
end
|
| 34 |
+
assign person_score = cls_acc;
|
| 35 |
+
assign detection = (cls_acc > 0);
|
| 36 |
+
|
| 37 |
+
// Box regression: 4 dot products
|
| 38 |
+
reg signed [ACC_WIDTH-1:0] reg_acc [0:3];
|
| 39 |
+
integer ri, rj;
|
| 40 |
+
always @(*) begin
|
| 41 |
+
for (ri = 0; ri < 4; ri = ri + 1) begin
|
| 42 |
+
reg_acc[ri] = 0;
|
| 43 |
+
for (rj = 0; rj < FEAT_DIM; rj = rj + 1)
|
| 44 |
+
reg_acc[ri] = reg_acc[ri] + features[rj] * reg_w[ri * FEAT_DIM + rj];
|
| 45 |
+
end
|
| 46 |
+
end
|
| 47 |
+
assign box_ltrb[0] = reg_acc[0];
|
| 48 |
+
assign box_ltrb[1] = reg_acc[1];
|
| 49 |
+
assign box_ltrb[2] = reg_acc[2];
|
| 50 |
+
assign box_ltrb[3] = reg_acc[3];
|
| 51 |
+
|
| 52 |
+
// Centerness: sum(features[d] * ctr_w[d])
|
| 53 |
+
reg signed [ACC_WIDTH-1:0] ctr_acc;
|
| 54 |
+
integer cti;
|
| 55 |
+
always @(*) begin
|
| 56 |
+
ctr_acc = 0;
|
| 57 |
+
for (cti = 0; cti < FEAT_DIM; cti = cti + 1)
|
| 58 |
+
ctr_acc = ctr_acc + features[cti] * ctr_w[cti];
|
| 59 |
+
end
|
| 60 |
+
assign centerness = ctr_acc;
|
| 61 |
+
|
| 62 |
+
endmodule
|
circuit/person_small_synth.v
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Reduced person detector for synthesis — pure Verilog-2005
|
| 2 |
+
// FEAT_DIM=16, single MAC for classification
|
| 3 |
+
// Extrapolate: full 768-dim = 48x this gate count
|
| 4 |
+
|
| 5 |
+
module person_detector_small (
|
| 6 |
+
input wire [127:0] features, // 16 x 8-bit packed
|
| 7 |
+
output wire [23:0] person_score,
|
| 8 |
+
output wire detection
|
| 9 |
+
);
|
| 10 |
+
|
| 11 |
+
// Hardcoded INT8 weights (from analytical solution, first 16 dims)
|
| 12 |
+
wire signed [7:0] feat [0:15];
|
| 13 |
+
wire signed [7:0] w [0:15];
|
| 14 |
+
|
| 15 |
+
// Unpack features
|
| 16 |
+
assign feat[0] = features[7:0];
|
| 17 |
+
assign feat[1] = features[15:8];
|
| 18 |
+
assign feat[2] = features[23:16];
|
| 19 |
+
assign feat[3] = features[31:24];
|
| 20 |
+
assign feat[4] = features[39:32];
|
| 21 |
+
assign feat[5] = features[47:40];
|
| 22 |
+
assign feat[6] = features[55:48];
|
| 23 |
+
assign feat[7] = features[63:56];
|
| 24 |
+
assign feat[8] = features[71:64];
|
| 25 |
+
assign feat[9] = features[79:72];
|
| 26 |
+
assign feat[10] = features[87:80];
|
| 27 |
+
assign feat[11] = features[95:88];
|
| 28 |
+
assign feat[12] = features[103:96];
|
| 29 |
+
assign feat[13] = features[111:104];
|
| 30 |
+
assign feat[14] = features[119:112];
|
| 31 |
+
assign feat[15] = features[127:120];
|
| 32 |
+
|
| 33 |
+
// Weights as constants
|
| 34 |
+
assign w[0] = 8'sd10; assign w[1] = -8'sd5;
|
| 35 |
+
assign w[2] = 8'sd3; assign w[3] = 8'sd7;
|
| 36 |
+
assign w[4] = -8'sd2; assign w[5] = 8'sd12;
|
| 37 |
+
assign w[6] = 8'sd1; assign w[7] = -8'sd8;
|
| 38 |
+
assign w[8] = 8'sd4; assign w[9] = 8'sd6;
|
| 39 |
+
assign w[10] = -8'sd3; assign w[11] = 8'sd9;
|
| 40 |
+
assign w[12] = 8'sd2; assign w[13] = -8'sd1;
|
| 41 |
+
assign w[14] = 8'sd5; assign w[15] = 8'sd3;
|
| 42 |
+
|
| 43 |
+
// 16 parallel multiplies
|
| 44 |
+
wire signed [15:0] prod [0:15];
|
| 45 |
+
assign prod[0] = feat[0] * w[0];
|
| 46 |
+
assign prod[1] = feat[1] * w[1];
|
| 47 |
+
assign prod[2] = feat[2] * w[2];
|
| 48 |
+
assign prod[3] = feat[3] * w[3];
|
| 49 |
+
assign prod[4] = feat[4] * w[4];
|
| 50 |
+
assign prod[5] = feat[5] * w[5];
|
| 51 |
+
assign prod[6] = feat[6] * w[6];
|
| 52 |
+
assign prod[7] = feat[7] * w[7];
|
| 53 |
+
assign prod[8] = feat[8] * w[8];
|
| 54 |
+
assign prod[9] = feat[9] * w[9];
|
| 55 |
+
assign prod[10] = feat[10] * w[10];
|
| 56 |
+
assign prod[11] = feat[11] * w[11];
|
| 57 |
+
assign prod[12] = feat[12] * w[12];
|
| 58 |
+
assign prod[13] = feat[13] * w[13];
|
| 59 |
+
assign prod[14] = feat[14] * w[14];
|
| 60 |
+
assign prod[15] = feat[15] * w[15];
|
| 61 |
+
|
| 62 |
+
// Adder tree
|
| 63 |
+
wire signed [16:0] s0_0 = prod[0] + prod[1];
|
| 64 |
+
wire signed [16:0] s0_1 = prod[2] + prod[3];
|
| 65 |
+
wire signed [16:0] s0_2 = prod[4] + prod[5];
|
| 66 |
+
wire signed [16:0] s0_3 = prod[6] + prod[7];
|
| 67 |
+
wire signed [16:0] s0_4 = prod[8] + prod[9];
|
| 68 |
+
wire signed [16:0] s0_5 = prod[10] + prod[11];
|
| 69 |
+
wire signed [16:0] s0_6 = prod[12] + prod[13];
|
| 70 |
+
wire signed [16:0] s0_7 = prod[14] + prod[15];
|
| 71 |
+
|
| 72 |
+
wire signed [17:0] s1_0 = s0_0 + s0_1;
|
| 73 |
+
wire signed [17:0] s1_1 = s0_2 + s0_3;
|
| 74 |
+
wire signed [17:0] s1_2 = s0_4 + s0_5;
|
| 75 |
+
wire signed [17:0] s1_3 = s0_6 + s0_7;
|
| 76 |
+
|
| 77 |
+
wire signed [18:0] s2_0 = s1_0 + s1_1;
|
| 78 |
+
wire signed [18:0] s2_1 = s1_2 + s1_3;
|
| 79 |
+
|
| 80 |
+
wire signed [19:0] total = s2_0 + s2_1;
|
| 81 |
+
|
| 82 |
+
assign person_score = {{4{total[19]}}, total};
|
| 83 |
+
assign detection = ~total[19]; // positive = detection
|
| 84 |
+
|
| 85 |
+
endmodule
|
circuit/rom/person_cls_b.hex
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
7f
|
circuit/rom/person_cls_w.hex
ADDED
|
@@ -0,0 +1,768 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ed
|
| 2 |
+
0c
|
| 3 |
+
f0
|
| 4 |
+
0c
|
| 5 |
+
02
|
| 6 |
+
17
|
| 7 |
+
fe
|
| 8 |
+
00
|
| 9 |
+
fb
|
| 10 |
+
fc
|
| 11 |
+
f4
|
| 12 |
+
05
|
| 13 |
+
03
|
| 14 |
+
0b
|
| 15 |
+
0f
|
| 16 |
+
fb
|
| 17 |
+
01
|
| 18 |
+
ff
|
| 19 |
+
f5
|
| 20 |
+
07
|
| 21 |
+
08
|
| 22 |
+
01
|
| 23 |
+
10
|
| 24 |
+
22
|
| 25 |
+
f7
|
| 26 |
+
05
|
| 27 |
+
0c
|
| 28 |
+
07
|
| 29 |
+
04
|
| 30 |
+
06
|
| 31 |
+
0a
|
| 32 |
+
ff
|
| 33 |
+
11
|
| 34 |
+
f1
|
| 35 |
+
f5
|
| 36 |
+
05
|
| 37 |
+
ff
|
| 38 |
+
17
|
| 39 |
+
f7
|
| 40 |
+
f6
|
| 41 |
+
f0
|
| 42 |
+
ee
|
| 43 |
+
0c
|
| 44 |
+
f0
|
| 45 |
+
dc
|
| 46 |
+
1b
|
| 47 |
+
10
|
| 48 |
+
f4
|
| 49 |
+
0c
|
| 50 |
+
03
|
| 51 |
+
e8
|
| 52 |
+
f6
|
| 53 |
+
16
|
| 54 |
+
14
|
| 55 |
+
f9
|
| 56 |
+
1b
|
| 57 |
+
09
|
| 58 |
+
0a
|
| 59 |
+
04
|
| 60 |
+
ee
|
| 61 |
+
0b
|
| 62 |
+
0f
|
| 63 |
+
32
|
| 64 |
+
fb
|
| 65 |
+
f8
|
| 66 |
+
13
|
| 67 |
+
01
|
| 68 |
+
ef
|
| 69 |
+
eb
|
| 70 |
+
05
|
| 71 |
+
fe
|
| 72 |
+
f4
|
| 73 |
+
05
|
| 74 |
+
ed
|
| 75 |
+
07
|
| 76 |
+
e7
|
| 77 |
+
f4
|
| 78 |
+
25
|
| 79 |
+
11
|
| 80 |
+
12
|
| 81 |
+
fc
|
| 82 |
+
07
|
| 83 |
+
0b
|
| 84 |
+
0f
|
| 85 |
+
e0
|
| 86 |
+
f4
|
| 87 |
+
fd
|
| 88 |
+
0f
|
| 89 |
+
f4
|
| 90 |
+
08
|
| 91 |
+
f4
|
| 92 |
+
0e
|
| 93 |
+
ed
|
| 94 |
+
e3
|
| 95 |
+
10
|
| 96 |
+
1f
|
| 97 |
+
06
|
| 98 |
+
ef
|
| 99 |
+
eb
|
| 100 |
+
e7
|
| 101 |
+
f0
|
| 102 |
+
03
|
| 103 |
+
21
|
| 104 |
+
02
|
| 105 |
+
fc
|
| 106 |
+
0b
|
| 107 |
+
12
|
| 108 |
+
0e
|
| 109 |
+
17
|
| 110 |
+
03
|
| 111 |
+
0c
|
| 112 |
+
06
|
| 113 |
+
f8
|
| 114 |
+
ef
|
| 115 |
+
f5
|
| 116 |
+
f3
|
| 117 |
+
14
|
| 118 |
+
f9
|
| 119 |
+
0b
|
| 120 |
+
fb
|
| 121 |
+
18
|
| 122 |
+
02
|
| 123 |
+
13
|
| 124 |
+
09
|
| 125 |
+
fd
|
| 126 |
+
fd
|
| 127 |
+
fa
|
| 128 |
+
15
|
| 129 |
+
fd
|
| 130 |
+
e7
|
| 131 |
+
f2
|
| 132 |
+
fa
|
| 133 |
+
1e
|
| 134 |
+
ff
|
| 135 |
+
04
|
| 136 |
+
07
|
| 137 |
+
ef
|
| 138 |
+
f0
|
| 139 |
+
0c
|
| 140 |
+
ed
|
| 141 |
+
fd
|
| 142 |
+
f5
|
| 143 |
+
fe
|
| 144 |
+
01
|
| 145 |
+
fe
|
| 146 |
+
18
|
| 147 |
+
fb
|
| 148 |
+
1c
|
| 149 |
+
f5
|
| 150 |
+
e9
|
| 151 |
+
fc
|
| 152 |
+
06
|
| 153 |
+
15
|
| 154 |
+
f3
|
| 155 |
+
ff
|
| 156 |
+
11
|
| 157 |
+
0f
|
| 158 |
+
1a
|
| 159 |
+
02
|
| 160 |
+
f6
|
| 161 |
+
ff
|
| 162 |
+
fd
|
| 163 |
+
fd
|
| 164 |
+
ef
|
| 165 |
+
0b
|
| 166 |
+
11
|
| 167 |
+
1b
|
| 168 |
+
ef
|
| 169 |
+
fc
|
| 170 |
+
fe
|
| 171 |
+
fd
|
| 172 |
+
f9
|
| 173 |
+
1d
|
| 174 |
+
f6
|
| 175 |
+
f0
|
| 176 |
+
e3
|
| 177 |
+
12
|
| 178 |
+
05
|
| 179 |
+
16
|
| 180 |
+
fc
|
| 181 |
+
01
|
| 182 |
+
fd
|
| 183 |
+
f2
|
| 184 |
+
ef
|
| 185 |
+
06
|
| 186 |
+
06
|
| 187 |
+
f9
|
| 188 |
+
f6
|
| 189 |
+
fc
|
| 190 |
+
f8
|
| 191 |
+
fa
|
| 192 |
+
0e
|
| 193 |
+
18
|
| 194 |
+
f2
|
| 195 |
+
04
|
| 196 |
+
f4
|
| 197 |
+
ff
|
| 198 |
+
09
|
| 199 |
+
1f
|
| 200 |
+
f2
|
| 201 |
+
e1
|
| 202 |
+
01
|
| 203 |
+
ef
|
| 204 |
+
16
|
| 205 |
+
10
|
| 206 |
+
20
|
| 207 |
+
0a
|
| 208 |
+
14
|
| 209 |
+
f0
|
| 210 |
+
f8
|
| 211 |
+
e8
|
| 212 |
+
02
|
| 213 |
+
0c
|
| 214 |
+
fe
|
| 215 |
+
28
|
| 216 |
+
14
|
| 217 |
+
eb
|
| 218 |
+
0b
|
| 219 |
+
f5
|
| 220 |
+
fc
|
| 221 |
+
0a
|
| 222 |
+
09
|
| 223 |
+
0e
|
| 224 |
+
0b
|
| 225 |
+
f9
|
| 226 |
+
08
|
| 227 |
+
fa
|
| 228 |
+
ee
|
| 229 |
+
06
|
| 230 |
+
fa
|
| 231 |
+
fb
|
| 232 |
+
ff
|
| 233 |
+
e7
|
| 234 |
+
fd
|
| 235 |
+
05
|
| 236 |
+
d6
|
| 237 |
+
03
|
| 238 |
+
fe
|
| 239 |
+
fe
|
| 240 |
+
f8
|
| 241 |
+
01
|
| 242 |
+
01
|
| 243 |
+
ee
|
| 244 |
+
ef
|
| 245 |
+
0a
|
| 246 |
+
11
|
| 247 |
+
f7
|
| 248 |
+
1a
|
| 249 |
+
e8
|
| 250 |
+
f8
|
| 251 |
+
fe
|
| 252 |
+
f9
|
| 253 |
+
14
|
| 254 |
+
00
|
| 255 |
+
03
|
| 256 |
+
11
|
| 257 |
+
fc
|
| 258 |
+
f5
|
| 259 |
+
f9
|
| 260 |
+
19
|
| 261 |
+
ef
|
| 262 |
+
12
|
| 263 |
+
04
|
| 264 |
+
08
|
| 265 |
+
0a
|
| 266 |
+
0a
|
| 267 |
+
17
|
| 268 |
+
fd
|
| 269 |
+
08
|
| 270 |
+
08
|
| 271 |
+
f4
|
| 272 |
+
06
|
| 273 |
+
0e
|
| 274 |
+
ed
|
| 275 |
+
17
|
| 276 |
+
04
|
| 277 |
+
0e
|
| 278 |
+
fc
|
| 279 |
+
f2
|
| 280 |
+
05
|
| 281 |
+
fc
|
| 282 |
+
f3
|
| 283 |
+
10
|
| 284 |
+
e7
|
| 285 |
+
f5
|
| 286 |
+
f1
|
| 287 |
+
ff
|
| 288 |
+
fc
|
| 289 |
+
e9
|
| 290 |
+
eb
|
| 291 |
+
09
|
| 292 |
+
ff
|
| 293 |
+
05
|
| 294 |
+
05
|
| 295 |
+
f3
|
| 296 |
+
08
|
| 297 |
+
03
|
| 298 |
+
04
|
| 299 |
+
fb
|
| 300 |
+
1a
|
| 301 |
+
0f
|
| 302 |
+
f3
|
| 303 |
+
e6
|
| 304 |
+
1b
|
| 305 |
+
04
|
| 306 |
+
07
|
| 307 |
+
1f
|
| 308 |
+
19
|
| 309 |
+
0e
|
| 310 |
+
01
|
| 311 |
+
f5
|
| 312 |
+
f4
|
| 313 |
+
fa
|
| 314 |
+
fc
|
| 315 |
+
ff
|
| 316 |
+
eb
|
| 317 |
+
01
|
| 318 |
+
06
|
| 319 |
+
04
|
| 320 |
+
07
|
| 321 |
+
03
|
| 322 |
+
06
|
| 323 |
+
fb
|
| 324 |
+
01
|
| 325 |
+
12
|
| 326 |
+
0d
|
| 327 |
+
04
|
| 328 |
+
ed
|
| 329 |
+
18
|
| 330 |
+
0f
|
| 331 |
+
f6
|
| 332 |
+
f0
|
| 333 |
+
0b
|
| 334 |
+
f4
|
| 335 |
+
14
|
| 336 |
+
fd
|
| 337 |
+
04
|
| 338 |
+
ff
|
| 339 |
+
fa
|
| 340 |
+
f0
|
| 341 |
+
09
|
| 342 |
+
f9
|
| 343 |
+
f9
|
| 344 |
+
09
|
| 345 |
+
17
|
| 346 |
+
11
|
| 347 |
+
f7
|
| 348 |
+
02
|
| 349 |
+
01
|
| 350 |
+
03
|
| 351 |
+
06
|
| 352 |
+
11
|
| 353 |
+
ff
|
| 354 |
+
fd
|
| 355 |
+
ff
|
| 356 |
+
eb
|
| 357 |
+
05
|
| 358 |
+
07
|
| 359 |
+
f0
|
| 360 |
+
ed
|
| 361 |
+
21
|
| 362 |
+
0d
|
| 363 |
+
0e
|
| 364 |
+
11
|
| 365 |
+
f5
|
| 366 |
+
02
|
| 367 |
+
fc
|
| 368 |
+
f1
|
| 369 |
+
e4
|
| 370 |
+
ed
|
| 371 |
+
fa
|
| 372 |
+
06
|
| 373 |
+
ee
|
| 374 |
+
11
|
| 375 |
+
00
|
| 376 |
+
fb
|
| 377 |
+
fb
|
| 378 |
+
ee
|
| 379 |
+
e5
|
| 380 |
+
eb
|
| 381 |
+
e7
|
| 382 |
+
13
|
| 383 |
+
15
|
| 384 |
+
f3
|
| 385 |
+
f9
|
| 386 |
+
e2
|
| 387 |
+
06
|
| 388 |
+
f7
|
| 389 |
+
fe
|
| 390 |
+
f6
|
| 391 |
+
f1
|
| 392 |
+
fd
|
| 393 |
+
f1
|
| 394 |
+
f6
|
| 395 |
+
0a
|
| 396 |
+
09
|
| 397 |
+
10
|
| 398 |
+
f0
|
| 399 |
+
ef
|
| 400 |
+
0b
|
| 401 |
+
fc
|
| 402 |
+
22
|
| 403 |
+
16
|
| 404 |
+
f8
|
| 405 |
+
06
|
| 406 |
+
fc
|
| 407 |
+
07
|
| 408 |
+
f9
|
| 409 |
+
fc
|
| 410 |
+
ea
|
| 411 |
+
0d
|
| 412 |
+
02
|
| 413 |
+
f9
|
| 414 |
+
f5
|
| 415 |
+
f5
|
| 416 |
+
26
|
| 417 |
+
ed
|
| 418 |
+
07
|
| 419 |
+
fc
|
| 420 |
+
ff
|
| 421 |
+
1d
|
| 422 |
+
f0
|
| 423 |
+
1d
|
| 424 |
+
01
|
| 425 |
+
fa
|
| 426 |
+
07
|
| 427 |
+
da
|
| 428 |
+
ef
|
| 429 |
+
df
|
| 430 |
+
09
|
| 431 |
+
13
|
| 432 |
+
03
|
| 433 |
+
f7
|
| 434 |
+
08
|
| 435 |
+
03
|
| 436 |
+
03
|
| 437 |
+
18
|
| 438 |
+
e3
|
| 439 |
+
d6
|
| 440 |
+
0c
|
| 441 |
+
fe
|
| 442 |
+
08
|
| 443 |
+
08
|
| 444 |
+
01
|
| 445 |
+
19
|
| 446 |
+
22
|
| 447 |
+
0b
|
| 448 |
+
fa
|
| 449 |
+
0f
|
| 450 |
+
e7
|
| 451 |
+
18
|
| 452 |
+
00
|
| 453 |
+
18
|
| 454 |
+
f0
|
| 455 |
+
ff
|
| 456 |
+
11
|
| 457 |
+
16
|
| 458 |
+
f4
|
| 459 |
+
fe
|
| 460 |
+
ff
|
| 461 |
+
02
|
| 462 |
+
09
|
| 463 |
+
03
|
| 464 |
+
e9
|
| 465 |
+
02
|
| 466 |
+
e5
|
| 467 |
+
ee
|
| 468 |
+
fe
|
| 469 |
+
f2
|
| 470 |
+
ec
|
| 471 |
+
12
|
| 472 |
+
09
|
| 473 |
+
fc
|
| 474 |
+
f3
|
| 475 |
+
11
|
| 476 |
+
09
|
| 477 |
+
03
|
| 478 |
+
e9
|
| 479 |
+
14
|
| 480 |
+
04
|
| 481 |
+
fd
|
| 482 |
+
fd
|
| 483 |
+
0e
|
| 484 |
+
05
|
| 485 |
+
e8
|
| 486 |
+
f7
|
| 487 |
+
02
|
| 488 |
+
ea
|
| 489 |
+
10
|
| 490 |
+
fd
|
| 491 |
+
08
|
| 492 |
+
1b
|
| 493 |
+
13
|
| 494 |
+
ee
|
| 495 |
+
0d
|
| 496 |
+
3b
|
| 497 |
+
1c
|
| 498 |
+
17
|
| 499 |
+
f7
|
| 500 |
+
11
|
| 501 |
+
fe
|
| 502 |
+
f7
|
| 503 |
+
fa
|
| 504 |
+
f9
|
| 505 |
+
e1
|
| 506 |
+
f5
|
| 507 |
+
ef
|
| 508 |
+
0a
|
| 509 |
+
fb
|
| 510 |
+
f6
|
| 511 |
+
f9
|
| 512 |
+
fb
|
| 513 |
+
f8
|
| 514 |
+
ff
|
| 515 |
+
00
|
| 516 |
+
f5
|
| 517 |
+
f6
|
| 518 |
+
00
|
| 519 |
+
1a
|
| 520 |
+
ef
|
| 521 |
+
a2
|
| 522 |
+
fc
|
| 523 |
+
03
|
| 524 |
+
f6
|
| 525 |
+
fa
|
| 526 |
+
0d
|
| 527 |
+
fb
|
| 528 |
+
11
|
| 529 |
+
ef
|
| 530 |
+
15
|
| 531 |
+
e5
|
| 532 |
+
eb
|
| 533 |
+
fe
|
| 534 |
+
f5
|
| 535 |
+
03
|
| 536 |
+
06
|
| 537 |
+
fa
|
| 538 |
+
fa
|
| 539 |
+
05
|
| 540 |
+
f2
|
| 541 |
+
0b
|
| 542 |
+
f1
|
| 543 |
+
00
|
| 544 |
+
d9
|
| 545 |
+
fd
|
| 546 |
+
00
|
| 547 |
+
10
|
| 548 |
+
03
|
| 549 |
+
0a
|
| 550 |
+
e0
|
| 551 |
+
18
|
| 552 |
+
f6
|
| 553 |
+
10
|
| 554 |
+
f9
|
| 555 |
+
fc
|
| 556 |
+
05
|
| 557 |
+
0a
|
| 558 |
+
fc
|
| 559 |
+
fa
|
| 560 |
+
ef
|
| 561 |
+
f8
|
| 562 |
+
ee
|
| 563 |
+
ef
|
| 564 |
+
0e
|
| 565 |
+
f6
|
| 566 |
+
14
|
| 567 |
+
08
|
| 568 |
+
fd
|
| 569 |
+
0d
|
| 570 |
+
e8
|
| 571 |
+
07
|
| 572 |
+
0d
|
| 573 |
+
ef
|
| 574 |
+
0d
|
| 575 |
+
0d
|
| 576 |
+
1d
|
| 577 |
+
ff
|
| 578 |
+
e5
|
| 579 |
+
fe
|
| 580 |
+
f5
|
| 581 |
+
fe
|
| 582 |
+
f9
|
| 583 |
+
f6
|
| 584 |
+
f7
|
| 585 |
+
f9
|
| 586 |
+
1b
|
| 587 |
+
15
|
| 588 |
+
f5
|
| 589 |
+
14
|
| 590 |
+
f3
|
| 591 |
+
f5
|
| 592 |
+
fb
|
| 593 |
+
08
|
| 594 |
+
00
|
| 595 |
+
f9
|
| 596 |
+
07
|
| 597 |
+
fe
|
| 598 |
+
0c
|
| 599 |
+
fb
|
| 600 |
+
04
|
| 601 |
+
01
|
| 602 |
+
fd
|
| 603 |
+
1e
|
| 604 |
+
ff
|
| 605 |
+
01
|
| 606 |
+
04
|
| 607 |
+
02
|
| 608 |
+
fd
|
| 609 |
+
07
|
| 610 |
+
f3
|
| 611 |
+
05
|
| 612 |
+
10
|
| 613 |
+
f6
|
| 614 |
+
06
|
| 615 |
+
7f
|
| 616 |
+
f9
|
| 617 |
+
18
|
| 618 |
+
10
|
| 619 |
+
fc
|
| 620 |
+
0f
|
| 621 |
+
ed
|
| 622 |
+
fd
|
| 623 |
+
ec
|
| 624 |
+
f5
|
| 625 |
+
0a
|
| 626 |
+
10
|
| 627 |
+
06
|
| 628 |
+
14
|
| 629 |
+
0d
|
| 630 |
+
15
|
| 631 |
+
07
|
| 632 |
+
13
|
| 633 |
+
f5
|
| 634 |
+
fd
|
| 635 |
+
0e
|
| 636 |
+
0c
|
| 637 |
+
0b
|
| 638 |
+
00
|
| 639 |
+
d6
|
| 640 |
+
e7
|
| 641 |
+
f7
|
| 642 |
+
09
|
| 643 |
+
ff
|
| 644 |
+
0e
|
| 645 |
+
e5
|
| 646 |
+
05
|
| 647 |
+
e2
|
| 648 |
+
1a
|
| 649 |
+
01
|
| 650 |
+
ea
|
| 651 |
+
0a
|
| 652 |
+
ed
|
| 653 |
+
fa
|
| 654 |
+
fa
|
| 655 |
+
ea
|
| 656 |
+
16
|
| 657 |
+
04
|
| 658 |
+
f1
|
| 659 |
+
eb
|
| 660 |
+
00
|
| 661 |
+
f2
|
| 662 |
+
f9
|
| 663 |
+
07
|
| 664 |
+
fb
|
| 665 |
+
f2
|
| 666 |
+
f9
|
| 667 |
+
0d
|
| 668 |
+
06
|
| 669 |
+
04
|
| 670 |
+
0d
|
| 671 |
+
02
|
| 672 |
+
f1
|
| 673 |
+
f5
|
| 674 |
+
18
|
| 675 |
+
19
|
| 676 |
+
01
|
| 677 |
+
07
|
| 678 |
+
02
|
| 679 |
+
f9
|
| 680 |
+
fc
|
| 681 |
+
01
|
| 682 |
+
f6
|
| 683 |
+
00
|
| 684 |
+
fd
|
| 685 |
+
f3
|
| 686 |
+
04
|
| 687 |
+
f9
|
| 688 |
+
f5
|
| 689 |
+
fe
|
| 690 |
+
01
|
| 691 |
+
f5
|
| 692 |
+
fa
|
| 693 |
+
ff
|
| 694 |
+
01
|
| 695 |
+
df
|
| 696 |
+
04
|
| 697 |
+
0a
|
| 698 |
+
e3
|
| 699 |
+
0a
|
| 700 |
+
ff
|
| 701 |
+
fd
|
| 702 |
+
01
|
| 703 |
+
eb
|
| 704 |
+
f5
|
| 705 |
+
f0
|
| 706 |
+
02
|
| 707 |
+
09
|
| 708 |
+
fc
|
| 709 |
+
e6
|
| 710 |
+
f8
|
| 711 |
+
ff
|
| 712 |
+
02
|
| 713 |
+
ef
|
| 714 |
+
09
|
| 715 |
+
11
|
| 716 |
+
fa
|
| 717 |
+
b1
|
| 718 |
+
15
|
| 719 |
+
02
|
| 720 |
+
f5
|
| 721 |
+
09
|
| 722 |
+
0c
|
| 723 |
+
ff
|
| 724 |
+
fc
|
| 725 |
+
f9
|
| 726 |
+
ff
|
| 727 |
+
00
|
| 728 |
+
f1
|
| 729 |
+
f1
|
| 730 |
+
fc
|
| 731 |
+
fa
|
| 732 |
+
f0
|
| 733 |
+
ec
|
| 734 |
+
1a
|
| 735 |
+
08
|
| 736 |
+
08
|
| 737 |
+
03
|
| 738 |
+
0a
|
| 739 |
+
08
|
| 740 |
+
e1
|
| 741 |
+
08
|
| 742 |
+
10
|
| 743 |
+
15
|
| 744 |
+
fc
|
| 745 |
+
f0
|
| 746 |
+
fb
|
| 747 |
+
f5
|
| 748 |
+
04
|
| 749 |
+
f9
|
| 750 |
+
fd
|
| 751 |
+
fb
|
| 752 |
+
ff
|
| 753 |
+
ed
|
| 754 |
+
1f
|
| 755 |
+
e7
|
| 756 |
+
00
|
| 757 |
+
0d
|
| 758 |
+
fa
|
| 759 |
+
09
|
| 760 |
+
07
|
| 761 |
+
00
|
| 762 |
+
f1
|
| 763 |
+
02
|
| 764 |
+
0e
|
| 765 |
+
10
|
| 766 |
+
fa
|
| 767 |
+
03
|
| 768 |
+
f5
|
circuit/rom/person_ctr_b.hex
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
7f
|
circuit/rom/person_ctr_w.hex
ADDED
|
@@ -0,0 +1,768 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
f2
|
| 2 |
+
08
|
| 3 |
+
fa
|
| 4 |
+
24
|
| 5 |
+
1c
|
| 6 |
+
ee
|
| 7 |
+
13
|
| 8 |
+
ef
|
| 9 |
+
2d
|
| 10 |
+
f1
|
| 11 |
+
ff
|
| 12 |
+
f3
|
| 13 |
+
e6
|
| 14 |
+
ee
|
| 15 |
+
ea
|
| 16 |
+
09
|
| 17 |
+
fe
|
| 18 |
+
fd
|
| 19 |
+
f2
|
| 20 |
+
1a
|
| 21 |
+
e4
|
| 22 |
+
f1
|
| 23 |
+
12
|
| 24 |
+
ee
|
| 25 |
+
fc
|
| 26 |
+
e9
|
| 27 |
+
1f
|
| 28 |
+
10
|
| 29 |
+
f1
|
| 30 |
+
05
|
| 31 |
+
da
|
| 32 |
+
f0
|
| 33 |
+
ed
|
| 34 |
+
ee
|
| 35 |
+
16
|
| 36 |
+
29
|
| 37 |
+
00
|
| 38 |
+
13
|
| 39 |
+
f5
|
| 40 |
+
fc
|
| 41 |
+
05
|
| 42 |
+
f6
|
| 43 |
+
f9
|
| 44 |
+
dc
|
| 45 |
+
22
|
| 46 |
+
39
|
| 47 |
+
15
|
| 48 |
+
e5
|
| 49 |
+
ed
|
| 50 |
+
f4
|
| 51 |
+
22
|
| 52 |
+
f1
|
| 53 |
+
15
|
| 54 |
+
06
|
| 55 |
+
03
|
| 56 |
+
d1
|
| 57 |
+
28
|
| 58 |
+
fa
|
| 59 |
+
22
|
| 60 |
+
f6
|
| 61 |
+
0f
|
| 62 |
+
18
|
| 63 |
+
1e
|
| 64 |
+
df
|
| 65 |
+
f4
|
| 66 |
+
fd
|
| 67 |
+
07
|
| 68 |
+
1d
|
| 69 |
+
d8
|
| 70 |
+
11
|
| 71 |
+
e3
|
| 72 |
+
ed
|
| 73 |
+
07
|
| 74 |
+
fa
|
| 75 |
+
03
|
| 76 |
+
f8
|
| 77 |
+
e8
|
| 78 |
+
22
|
| 79 |
+
ea
|
| 80 |
+
ec
|
| 81 |
+
f4
|
| 82 |
+
fc
|
| 83 |
+
1c
|
| 84 |
+
ee
|
| 85 |
+
d3
|
| 86 |
+
e7
|
| 87 |
+
11
|
| 88 |
+
df
|
| 89 |
+
01
|
| 90 |
+
1f
|
| 91 |
+
dd
|
| 92 |
+
00
|
| 93 |
+
fa
|
| 94 |
+
d0
|
| 95 |
+
ed
|
| 96 |
+
14
|
| 97 |
+
05
|
| 98 |
+
fe
|
| 99 |
+
08
|
| 100 |
+
10
|
| 101 |
+
f7
|
| 102 |
+
c1
|
| 103 |
+
23
|
| 104 |
+
eb
|
| 105 |
+
0f
|
| 106 |
+
e1
|
| 107 |
+
fc
|
| 108 |
+
12
|
| 109 |
+
f4
|
| 110 |
+
ed
|
| 111 |
+
1a
|
| 112 |
+
e4
|
| 113 |
+
24
|
| 114 |
+
22
|
| 115 |
+
07
|
| 116 |
+
ed
|
| 117 |
+
02
|
| 118 |
+
0d
|
| 119 |
+
fd
|
| 120 |
+
36
|
| 121 |
+
ef
|
| 122 |
+
f8
|
| 123 |
+
fd
|
| 124 |
+
ef
|
| 125 |
+
f3
|
| 126 |
+
e6
|
| 127 |
+
03
|
| 128 |
+
0e
|
| 129 |
+
f5
|
| 130 |
+
02
|
| 131 |
+
17
|
| 132 |
+
eb
|
| 133 |
+
fe
|
| 134 |
+
06
|
| 135 |
+
f1
|
| 136 |
+
28
|
| 137 |
+
d7
|
| 138 |
+
1e
|
| 139 |
+
0f
|
| 140 |
+
fc
|
| 141 |
+
d0
|
| 142 |
+
0d
|
| 143 |
+
e5
|
| 144 |
+
f9
|
| 145 |
+
fe
|
| 146 |
+
07
|
| 147 |
+
f3
|
| 148 |
+
fb
|
| 149 |
+
11
|
| 150 |
+
f8
|
| 151 |
+
0f
|
| 152 |
+
07
|
| 153 |
+
0b
|
| 154 |
+
e8
|
| 155 |
+
0c
|
| 156 |
+
f6
|
| 157 |
+
e4
|
| 158 |
+
06
|
| 159 |
+
0a
|
| 160 |
+
03
|
| 161 |
+
46
|
| 162 |
+
16
|
| 163 |
+
b4
|
| 164 |
+
f2
|
| 165 |
+
ed
|
| 166 |
+
fb
|
| 167 |
+
f0
|
| 168 |
+
f8
|
| 169 |
+
2d
|
| 170 |
+
15
|
| 171 |
+
23
|
| 172 |
+
f7
|
| 173 |
+
07
|
| 174 |
+
fb
|
| 175 |
+
0d
|
| 176 |
+
f3
|
| 177 |
+
f2
|
| 178 |
+
15
|
| 179 |
+
0d
|
| 180 |
+
ef
|
| 181 |
+
00
|
| 182 |
+
17
|
| 183 |
+
0f
|
| 184 |
+
12
|
| 185 |
+
3b
|
| 186 |
+
17
|
| 187 |
+
f9
|
| 188 |
+
e4
|
| 189 |
+
f5
|
| 190 |
+
13
|
| 191 |
+
d5
|
| 192 |
+
05
|
| 193 |
+
20
|
| 194 |
+
02
|
| 195 |
+
0e
|
| 196 |
+
ec
|
| 197 |
+
e0
|
| 198 |
+
26
|
| 199 |
+
fe
|
| 200 |
+
04
|
| 201 |
+
06
|
| 202 |
+
f2
|
| 203 |
+
fc
|
| 204 |
+
20
|
| 205 |
+
fe
|
| 206 |
+
22
|
| 207 |
+
e7
|
| 208 |
+
1d
|
| 209 |
+
f9
|
| 210 |
+
e6
|
| 211 |
+
f1
|
| 212 |
+
04
|
| 213 |
+
19
|
| 214 |
+
14
|
| 215 |
+
34
|
| 216 |
+
fb
|
| 217 |
+
07
|
| 218 |
+
ef
|
| 219 |
+
d2
|
| 220 |
+
14
|
| 221 |
+
e3
|
| 222 |
+
18
|
| 223 |
+
ec
|
| 224 |
+
ef
|
| 225 |
+
fd
|
| 226 |
+
19
|
| 227 |
+
f0
|
| 228 |
+
1e
|
| 229 |
+
0a
|
| 230 |
+
30
|
| 231 |
+
f4
|
| 232 |
+
e9
|
| 233 |
+
e3
|
| 234 |
+
03
|
| 235 |
+
0e
|
| 236 |
+
eb
|
| 237 |
+
fe
|
| 238 |
+
f4
|
| 239 |
+
fa
|
| 240 |
+
fd
|
| 241 |
+
f0
|
| 242 |
+
f4
|
| 243 |
+
e8
|
| 244 |
+
03
|
| 245 |
+
ca
|
| 246 |
+
19
|
| 247 |
+
e1
|
| 248 |
+
f2
|
| 249 |
+
b5
|
| 250 |
+
f6
|
| 251 |
+
10
|
| 252 |
+
ff
|
| 253 |
+
fc
|
| 254 |
+
08
|
| 255 |
+
19
|
| 256 |
+
27
|
| 257 |
+
02
|
| 258 |
+
fb
|
| 259 |
+
f0
|
| 260 |
+
15
|
| 261 |
+
da
|
| 262 |
+
0a
|
| 263 |
+
0c
|
| 264 |
+
e3
|
| 265 |
+
fe
|
| 266 |
+
03
|
| 267 |
+
eb
|
| 268 |
+
f3
|
| 269 |
+
15
|
| 270 |
+
1c
|
| 271 |
+
ca
|
| 272 |
+
11
|
| 273 |
+
fd
|
| 274 |
+
d9
|
| 275 |
+
08
|
| 276 |
+
f9
|
| 277 |
+
f9
|
| 278 |
+
34
|
| 279 |
+
da
|
| 280 |
+
f0
|
| 281 |
+
0d
|
| 282 |
+
1e
|
| 283 |
+
42
|
| 284 |
+
0f
|
| 285 |
+
f7
|
| 286 |
+
d1
|
| 287 |
+
39
|
| 288 |
+
0d
|
| 289 |
+
30
|
| 290 |
+
f6
|
| 291 |
+
11
|
| 292 |
+
fe
|
| 293 |
+
08
|
| 294 |
+
d1
|
| 295 |
+
fc
|
| 296 |
+
07
|
| 297 |
+
e0
|
| 298 |
+
19
|
| 299 |
+
f3
|
| 300 |
+
fd
|
| 301 |
+
fa
|
| 302 |
+
d8
|
| 303 |
+
07
|
| 304 |
+
2f
|
| 305 |
+
10
|
| 306 |
+
26
|
| 307 |
+
10
|
| 308 |
+
1b
|
| 309 |
+
10
|
| 310 |
+
0b
|
| 311 |
+
0e
|
| 312 |
+
0a
|
| 313 |
+
0e
|
| 314 |
+
f2
|
| 315 |
+
f2
|
| 316 |
+
cf
|
| 317 |
+
12
|
| 318 |
+
fb
|
| 319 |
+
f3
|
| 320 |
+
eb
|
| 321 |
+
f5
|
| 322 |
+
29
|
| 323 |
+
2a
|
| 324 |
+
ec
|
| 325 |
+
ea
|
| 326 |
+
14
|
| 327 |
+
01
|
| 328 |
+
06
|
| 329 |
+
e4
|
| 330 |
+
03
|
| 331 |
+
f9
|
| 332 |
+
d0
|
| 333 |
+
d5
|
| 334 |
+
1d
|
| 335 |
+
0a
|
| 336 |
+
eb
|
| 337 |
+
0e
|
| 338 |
+
e3
|
| 339 |
+
e2
|
| 340 |
+
15
|
| 341 |
+
f2
|
| 342 |
+
f5
|
| 343 |
+
fb
|
| 344 |
+
43
|
| 345 |
+
21
|
| 346 |
+
e0
|
| 347 |
+
e2
|
| 348 |
+
dd
|
| 349 |
+
fe
|
| 350 |
+
2f
|
| 351 |
+
0e
|
| 352 |
+
e3
|
| 353 |
+
f8
|
| 354 |
+
fd
|
| 355 |
+
e8
|
| 356 |
+
05
|
| 357 |
+
0c
|
| 358 |
+
de
|
| 359 |
+
f7
|
| 360 |
+
07
|
| 361 |
+
17
|
| 362 |
+
02
|
| 363 |
+
1d
|
| 364 |
+
0c
|
| 365 |
+
03
|
| 366 |
+
29
|
| 367 |
+
de
|
| 368 |
+
d3
|
| 369 |
+
0d
|
| 370 |
+
c7
|
| 371 |
+
f7
|
| 372 |
+
0f
|
| 373 |
+
12
|
| 374 |
+
08
|
| 375 |
+
2d
|
| 376 |
+
ea
|
| 377 |
+
14
|
| 378 |
+
01
|
| 379 |
+
e4
|
| 380 |
+
11
|
| 381 |
+
fe
|
| 382 |
+
ee
|
| 383 |
+
e9
|
| 384 |
+
e0
|
| 385 |
+
f8
|
| 386 |
+
10
|
| 387 |
+
27
|
| 388 |
+
ed
|
| 389 |
+
22
|
| 390 |
+
00
|
| 391 |
+
ce
|
| 392 |
+
0a
|
| 393 |
+
15
|
| 394 |
+
0f
|
| 395 |
+
de
|
| 396 |
+
0e
|
| 397 |
+
f8
|
| 398 |
+
1a
|
| 399 |
+
de
|
| 400 |
+
1a
|
| 401 |
+
17
|
| 402 |
+
fa
|
| 403 |
+
24
|
| 404 |
+
fc
|
| 405 |
+
07
|
| 406 |
+
d6
|
| 407 |
+
f3
|
| 408 |
+
fc
|
| 409 |
+
fe
|
| 410 |
+
0a
|
| 411 |
+
f6
|
| 412 |
+
ea
|
| 413 |
+
e5
|
| 414 |
+
f3
|
| 415 |
+
05
|
| 416 |
+
0f
|
| 417 |
+
f2
|
| 418 |
+
cb
|
| 419 |
+
e9
|
| 420 |
+
d4
|
| 421 |
+
28
|
| 422 |
+
0d
|
| 423 |
+
17
|
| 424 |
+
dd
|
| 425 |
+
0b
|
| 426 |
+
0a
|
| 427 |
+
db
|
| 428 |
+
ec
|
| 429 |
+
15
|
| 430 |
+
f8
|
| 431 |
+
2e
|
| 432 |
+
f3
|
| 433 |
+
df
|
| 434 |
+
1a
|
| 435 |
+
02
|
| 436 |
+
db
|
| 437 |
+
21
|
| 438 |
+
f5
|
| 439 |
+
d7
|
| 440 |
+
fe
|
| 441 |
+
fd
|
| 442 |
+
dc
|
| 443 |
+
e9
|
| 444 |
+
12
|
| 445 |
+
cd
|
| 446 |
+
15
|
| 447 |
+
ee
|
| 448 |
+
f7
|
| 449 |
+
28
|
| 450 |
+
fa
|
| 451 |
+
12
|
| 452 |
+
14
|
| 453 |
+
20
|
| 454 |
+
f6
|
| 455 |
+
d3
|
| 456 |
+
17
|
| 457 |
+
3c
|
| 458 |
+
05
|
| 459 |
+
07
|
| 460 |
+
2a
|
| 461 |
+
cc
|
| 462 |
+
d8
|
| 463 |
+
24
|
| 464 |
+
02
|
| 465 |
+
10
|
| 466 |
+
ed
|
| 467 |
+
d1
|
| 468 |
+
cc
|
| 469 |
+
f8
|
| 470 |
+
ea
|
| 471 |
+
fb
|
| 472 |
+
ee
|
| 473 |
+
eb
|
| 474 |
+
00
|
| 475 |
+
0b
|
| 476 |
+
f4
|
| 477 |
+
f3
|
| 478 |
+
ef
|
| 479 |
+
2b
|
| 480 |
+
29
|
| 481 |
+
cb
|
| 482 |
+
25
|
| 483 |
+
1e
|
| 484 |
+
06
|
| 485 |
+
1a
|
| 486 |
+
df
|
| 487 |
+
0b
|
| 488 |
+
1c
|
| 489 |
+
ea
|
| 490 |
+
08
|
| 491 |
+
e6
|
| 492 |
+
fd
|
| 493 |
+
1d
|
| 494 |
+
f9
|
| 495 |
+
11
|
| 496 |
+
18
|
| 497 |
+
f6
|
| 498 |
+
fa
|
| 499 |
+
f3
|
| 500 |
+
0e
|
| 501 |
+
1a
|
| 502 |
+
f4
|
| 503 |
+
0a
|
| 504 |
+
13
|
| 505 |
+
25
|
| 506 |
+
e2
|
| 507 |
+
21
|
| 508 |
+
d0
|
| 509 |
+
fb
|
| 510 |
+
d9
|
| 511 |
+
fa
|
| 512 |
+
e8
|
| 513 |
+
0d
|
| 514 |
+
fd
|
| 515 |
+
08
|
| 516 |
+
0b
|
| 517 |
+
28
|
| 518 |
+
14
|
| 519 |
+
ea
|
| 520 |
+
16
|
| 521 |
+
ae
|
| 522 |
+
34
|
| 523 |
+
3c
|
| 524 |
+
df
|
| 525 |
+
03
|
| 526 |
+
fc
|
| 527 |
+
1a
|
| 528 |
+
ef
|
| 529 |
+
f7
|
| 530 |
+
09
|
| 531 |
+
df
|
| 532 |
+
07
|
| 533 |
+
ef
|
| 534 |
+
f2
|
| 535 |
+
0e
|
| 536 |
+
f8
|
| 537 |
+
e0
|
| 538 |
+
f5
|
| 539 |
+
f4
|
| 540 |
+
f5
|
| 541 |
+
29
|
| 542 |
+
e6
|
| 543 |
+
0a
|
| 544 |
+
09
|
| 545 |
+
ec
|
| 546 |
+
ff
|
| 547 |
+
28
|
| 548 |
+
fd
|
| 549 |
+
18
|
| 550 |
+
bf
|
| 551 |
+
28
|
| 552 |
+
da
|
| 553 |
+
ee
|
| 554 |
+
04
|
| 555 |
+
ff
|
| 556 |
+
24
|
| 557 |
+
1f
|
| 558 |
+
ef
|
| 559 |
+
fa
|
| 560 |
+
1a
|
| 561 |
+
ea
|
| 562 |
+
f0
|
| 563 |
+
fe
|
| 564 |
+
3a
|
| 565 |
+
ec
|
| 566 |
+
02
|
| 567 |
+
fb
|
| 568 |
+
0a
|
| 569 |
+
08
|
| 570 |
+
13
|
| 571 |
+
27
|
| 572 |
+
f0
|
| 573 |
+
01
|
| 574 |
+
48
|
| 575 |
+
16
|
| 576 |
+
02
|
| 577 |
+
e6
|
| 578 |
+
fe
|
| 579 |
+
f8
|
| 580 |
+
09
|
| 581 |
+
c9
|
| 582 |
+
18
|
| 583 |
+
01
|
| 584 |
+
f5
|
| 585 |
+
22
|
| 586 |
+
f5
|
| 587 |
+
1e
|
| 588 |
+
e7
|
| 589 |
+
28
|
| 590 |
+
f1
|
| 591 |
+
f8
|
| 592 |
+
f7
|
| 593 |
+
19
|
| 594 |
+
e4
|
| 595 |
+
00
|
| 596 |
+
fa
|
| 597 |
+
09
|
| 598 |
+
11
|
| 599 |
+
f4
|
| 600 |
+
00
|
| 601 |
+
fc
|
| 602 |
+
ff
|
| 603 |
+
fe
|
| 604 |
+
f7
|
| 605 |
+
03
|
| 606 |
+
18
|
| 607 |
+
00
|
| 608 |
+
10
|
| 609 |
+
f5
|
| 610 |
+
d6
|
| 611 |
+
26
|
| 612 |
+
f2
|
| 613 |
+
e7
|
| 614 |
+
04
|
| 615 |
+
7f
|
| 616 |
+
f2
|
| 617 |
+
06
|
| 618 |
+
17
|
| 619 |
+
ed
|
| 620 |
+
0f
|
| 621 |
+
f4
|
| 622 |
+
e9
|
| 623 |
+
f9
|
| 624 |
+
ee
|
| 625 |
+
00
|
| 626 |
+
07
|
| 627 |
+
d7
|
| 628 |
+
1a
|
| 629 |
+
0d
|
| 630 |
+
37
|
| 631 |
+
f2
|
| 632 |
+
25
|
| 633 |
+
f5
|
| 634 |
+
0f
|
| 635 |
+
17
|
| 636 |
+
1a
|
| 637 |
+
ef
|
| 638 |
+
f6
|
| 639 |
+
f9
|
| 640 |
+
e8
|
| 641 |
+
0c
|
| 642 |
+
fb
|
| 643 |
+
0e
|
| 644 |
+
24
|
| 645 |
+
ea
|
| 646 |
+
f9
|
| 647 |
+
10
|
| 648 |
+
11
|
| 649 |
+
09
|
| 650 |
+
cb
|
| 651 |
+
01
|
| 652 |
+
fb
|
| 653 |
+
cf
|
| 654 |
+
0a
|
| 655 |
+
f1
|
| 656 |
+
02
|
| 657 |
+
13
|
| 658 |
+
e4
|
| 659 |
+
f6
|
| 660 |
+
28
|
| 661 |
+
08
|
| 662 |
+
35
|
| 663 |
+
2a
|
| 664 |
+
ff
|
| 665 |
+
f5
|
| 666 |
+
1a
|
| 667 |
+
1a
|
| 668 |
+
f4
|
| 669 |
+
08
|
| 670 |
+
fb
|
| 671 |
+
de
|
| 672 |
+
08
|
| 673 |
+
e0
|
| 674 |
+
f9
|
| 675 |
+
ea
|
| 676 |
+
0d
|
| 677 |
+
25
|
| 678 |
+
0e
|
| 679 |
+
ee
|
| 680 |
+
fb
|
| 681 |
+
ff
|
| 682 |
+
09
|
| 683 |
+
0a
|
| 684 |
+
24
|
| 685 |
+
f8
|
| 686 |
+
0f
|
| 687 |
+
0c
|
| 688 |
+
f7
|
| 689 |
+
10
|
| 690 |
+
06
|
| 691 |
+
0e
|
| 692 |
+
d9
|
| 693 |
+
1e
|
| 694 |
+
09
|
| 695 |
+
35
|
| 696 |
+
e9
|
| 697 |
+
fe
|
| 698 |
+
00
|
| 699 |
+
05
|
| 700 |
+
ee
|
| 701 |
+
0e
|
| 702 |
+
0a
|
| 703 |
+
0d
|
| 704 |
+
2a
|
| 705 |
+
33
|
| 706 |
+
fb
|
| 707 |
+
0e
|
| 708 |
+
d5
|
| 709 |
+
ee
|
| 710 |
+
36
|
| 711 |
+
ee
|
| 712 |
+
1c
|
| 713 |
+
da
|
| 714 |
+
0e
|
| 715 |
+
04
|
| 716 |
+
10
|
| 717 |
+
e2
|
| 718 |
+
ff
|
| 719 |
+
e6
|
| 720 |
+
0c
|
| 721 |
+
20
|
| 722 |
+
de
|
| 723 |
+
1e
|
| 724 |
+
0b
|
| 725 |
+
ff
|
| 726 |
+
0e
|
| 727 |
+
e5
|
| 728 |
+
0b
|
| 729 |
+
e6
|
| 730 |
+
ef
|
| 731 |
+
fb
|
| 732 |
+
ed
|
| 733 |
+
15
|
| 734 |
+
19
|
| 735 |
+
ee
|
| 736 |
+
f8
|
| 737 |
+
0c
|
| 738 |
+
f8
|
| 739 |
+
34
|
| 740 |
+
0e
|
| 741 |
+
0e
|
| 742 |
+
e2
|
| 743 |
+
1d
|
| 744 |
+
e5
|
| 745 |
+
ed
|
| 746 |
+
fb
|
| 747 |
+
f2
|
| 748 |
+
07
|
| 749 |
+
09
|
| 750 |
+
f1
|
| 751 |
+
02
|
| 752 |
+
f7
|
| 753 |
+
eb
|
| 754 |
+
ef
|
| 755 |
+
e8
|
| 756 |
+
f4
|
| 757 |
+
f7
|
| 758 |
+
e6
|
| 759 |
+
fb
|
| 760 |
+
e9
|
| 761 |
+
e8
|
| 762 |
+
1e
|
| 763 |
+
fd
|
| 764 |
+
0d
|
| 765 |
+
d2
|
| 766 |
+
00
|
| 767 |
+
fe
|
| 768 |
+
fb
|
circuit/rom/person_reg_b.hex
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
6e
|
| 2 |
+
7f
|
| 3 |
+
6e
|
| 4 |
+
7f
|
circuit/rom/person_reg_w.hex
ADDED
|
@@ -0,0 +1,3072 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
11
|
| 2 |
+
05
|
| 3 |
+
ee
|
| 4 |
+
47
|
| 5 |
+
1b
|
| 6 |
+
d6
|
| 7 |
+
f4
|
| 8 |
+
e9
|
| 9 |
+
25
|
| 10 |
+
fd
|
| 11 |
+
e3
|
| 12 |
+
ee
|
| 13 |
+
ee
|
| 14 |
+
03
|
| 15 |
+
02
|
| 16 |
+
f7
|
| 17 |
+
fd
|
| 18 |
+
e9
|
| 19 |
+
02
|
| 20 |
+
04
|
| 21 |
+
04
|
| 22 |
+
0d
|
| 23 |
+
0c
|
| 24 |
+
d7
|
| 25 |
+
ef
|
| 26 |
+
f4
|
| 27 |
+
21
|
| 28 |
+
fd
|
| 29 |
+
c4
|
| 30 |
+
12
|
| 31 |
+
e9
|
| 32 |
+
e3
|
| 33 |
+
cd
|
| 34 |
+
e4
|
| 35 |
+
45
|
| 36 |
+
2e
|
| 37 |
+
e8
|
| 38 |
+
2c
|
| 39 |
+
ff
|
| 40 |
+
d6
|
| 41 |
+
03
|
| 42 |
+
e7
|
| 43 |
+
27
|
| 44 |
+
ef
|
| 45 |
+
30
|
| 46 |
+
48
|
| 47 |
+
fc
|
| 48 |
+
f9
|
| 49 |
+
e0
|
| 50 |
+
fd
|
| 51 |
+
ed
|
| 52 |
+
cf
|
| 53 |
+
0b
|
| 54 |
+
19
|
| 55 |
+
fb
|
| 56 |
+
f4
|
| 57 |
+
08
|
| 58 |
+
df
|
| 59 |
+
30
|
| 60 |
+
1b
|
| 61 |
+
2b
|
| 62 |
+
18
|
| 63 |
+
f4
|
| 64 |
+
ce
|
| 65 |
+
de
|
| 66 |
+
0e
|
| 67 |
+
f5
|
| 68 |
+
14
|
| 69 |
+
dd
|
| 70 |
+
01
|
| 71 |
+
c2
|
| 72 |
+
d5
|
| 73 |
+
ee
|
| 74 |
+
f6
|
| 75 |
+
04
|
| 76 |
+
03
|
| 77 |
+
fb
|
| 78 |
+
24
|
| 79 |
+
d0
|
| 80 |
+
17
|
| 81 |
+
0b
|
| 82 |
+
06
|
| 83 |
+
2d
|
| 84 |
+
e6
|
| 85 |
+
c1
|
| 86 |
+
e8
|
| 87 |
+
4c
|
| 88 |
+
fa
|
| 89 |
+
08
|
| 90 |
+
29
|
| 91 |
+
fa
|
| 92 |
+
06
|
| 93 |
+
e8
|
| 94 |
+
be
|
| 95 |
+
05
|
| 96 |
+
04
|
| 97 |
+
1e
|
| 98 |
+
18
|
| 99 |
+
00
|
| 100 |
+
22
|
| 101 |
+
e5
|
| 102 |
+
c5
|
| 103 |
+
f2
|
| 104 |
+
e4
|
| 105 |
+
12
|
| 106 |
+
da
|
| 107 |
+
e9
|
| 108 |
+
18
|
| 109 |
+
f6
|
| 110 |
+
0e
|
| 111 |
+
15
|
| 112 |
+
e5
|
| 113 |
+
09
|
| 114 |
+
08
|
| 115 |
+
13
|
| 116 |
+
e0
|
| 117 |
+
0a
|
| 118 |
+
02
|
| 119 |
+
c2
|
| 120 |
+
15
|
| 121 |
+
ea
|
| 122 |
+
fe
|
| 123 |
+
f5
|
| 124 |
+
e9
|
| 125 |
+
f4
|
| 126 |
+
fc
|
| 127 |
+
2f
|
| 128 |
+
30
|
| 129 |
+
d5
|
| 130 |
+
22
|
| 131 |
+
14
|
| 132 |
+
bd
|
| 133 |
+
06
|
| 134 |
+
1a
|
| 135 |
+
11
|
| 136 |
+
2e
|
| 137 |
+
c1
|
| 138 |
+
33
|
| 139 |
+
10
|
| 140 |
+
d6
|
| 141 |
+
c7
|
| 142 |
+
07
|
| 143 |
+
d1
|
| 144 |
+
e8
|
| 145 |
+
e4
|
| 146 |
+
0d
|
| 147 |
+
04
|
| 148 |
+
e1
|
| 149 |
+
2d
|
| 150 |
+
0e
|
| 151 |
+
23
|
| 152 |
+
fd
|
| 153 |
+
31
|
| 154 |
+
da
|
| 155 |
+
00
|
| 156 |
+
dc
|
| 157 |
+
c0
|
| 158 |
+
f8
|
| 159 |
+
0d
|
| 160 |
+
03
|
| 161 |
+
23
|
| 162 |
+
09
|
| 163 |
+
ee
|
| 164 |
+
a8
|
| 165 |
+
db
|
| 166 |
+
07
|
| 167 |
+
eb
|
| 168 |
+
fc
|
| 169 |
+
28
|
| 170 |
+
14
|
| 171 |
+
08
|
| 172 |
+
d2
|
| 173 |
+
01
|
| 174 |
+
16
|
| 175 |
+
09
|
| 176 |
+
f5
|
| 177 |
+
e0
|
| 178 |
+
1e
|
| 179 |
+
17
|
| 180 |
+
09
|
| 181 |
+
03
|
| 182 |
+
15
|
| 183 |
+
0d
|
| 184 |
+
0f
|
| 185 |
+
3b
|
| 186 |
+
20
|
| 187 |
+
e6
|
| 188 |
+
de
|
| 189 |
+
03
|
| 190 |
+
14
|
| 191 |
+
d2
|
| 192 |
+
ed
|
| 193 |
+
0c
|
| 194 |
+
fe
|
| 195 |
+
e7
|
| 196 |
+
e4
|
| 197 |
+
d5
|
| 198 |
+
09
|
| 199 |
+
fc
|
| 200 |
+
22
|
| 201 |
+
06
|
| 202 |
+
0e
|
| 203 |
+
f2
|
| 204 |
+
1f
|
| 205 |
+
02
|
| 206 |
+
f4
|
| 207 |
+
f4
|
| 208 |
+
17
|
| 209 |
+
fb
|
| 210 |
+
e9
|
| 211 |
+
15
|
| 212 |
+
f9
|
| 213 |
+
20
|
| 214 |
+
0e
|
| 215 |
+
32
|
| 216 |
+
f9
|
| 217 |
+
e3
|
| 218 |
+
fc
|
| 219 |
+
e9
|
| 220 |
+
10
|
| 221 |
+
de
|
| 222 |
+
f7
|
| 223 |
+
f8
|
| 224 |
+
f0
|
| 225 |
+
f7
|
| 226 |
+
2b
|
| 227 |
+
eb
|
| 228 |
+
3a
|
| 229 |
+
28
|
| 230 |
+
2d
|
| 231 |
+
fe
|
| 232 |
+
e6
|
| 233 |
+
f1
|
| 234 |
+
ea
|
| 235 |
+
e0
|
| 236 |
+
08
|
| 237 |
+
08
|
| 238 |
+
11
|
| 239 |
+
23
|
| 240 |
+
0a
|
| 241 |
+
0b
|
| 242 |
+
eb
|
| 243 |
+
fa
|
| 244 |
+
0b
|
| 245 |
+
cb
|
| 246 |
+
02
|
| 247 |
+
d5
|
| 248 |
+
f5
|
| 249 |
+
a1
|
| 250 |
+
04
|
| 251 |
+
21
|
| 252 |
+
02
|
| 253 |
+
f7
|
| 254 |
+
06
|
| 255 |
+
3e
|
| 256 |
+
1c
|
| 257 |
+
e2
|
| 258 |
+
c4
|
| 259 |
+
fa
|
| 260 |
+
0a
|
| 261 |
+
02
|
| 262 |
+
07
|
| 263 |
+
01
|
| 264 |
+
01
|
| 265 |
+
ef
|
| 266 |
+
11
|
| 267 |
+
ec
|
| 268 |
+
fb
|
| 269 |
+
23
|
| 270 |
+
03
|
| 271 |
+
bc
|
| 272 |
+
07
|
| 273 |
+
e1
|
| 274 |
+
de
|
| 275 |
+
0c
|
| 276 |
+
e9
|
| 277 |
+
02
|
| 278 |
+
17
|
| 279 |
+
b8
|
| 280 |
+
cb
|
| 281 |
+
01
|
| 282 |
+
13
|
| 283 |
+
3e
|
| 284 |
+
e4
|
| 285 |
+
fd
|
| 286 |
+
d4
|
| 287 |
+
e1
|
| 288 |
+
1c
|
| 289 |
+
22
|
| 290 |
+
f8
|
| 291 |
+
04
|
| 292 |
+
13
|
| 293 |
+
0b
|
| 294 |
+
c5
|
| 295 |
+
fe
|
| 296 |
+
03
|
| 297 |
+
04
|
| 298 |
+
25
|
| 299 |
+
cb
|
| 300 |
+
11
|
| 301 |
+
03
|
| 302 |
+
e9
|
| 303 |
+
04
|
| 304 |
+
18
|
| 305 |
+
0d
|
| 306 |
+
fb
|
| 307 |
+
f9
|
| 308 |
+
0f
|
| 309 |
+
1c
|
| 310 |
+
02
|
| 311 |
+
e4
|
| 312 |
+
e5
|
| 313 |
+
cd
|
| 314 |
+
07
|
| 315 |
+
eb
|
| 316 |
+
ed
|
| 317 |
+
04
|
| 318 |
+
e3
|
| 319 |
+
ee
|
| 320 |
+
f3
|
| 321 |
+
f0
|
| 322 |
+
23
|
| 323 |
+
6b
|
| 324 |
+
cc
|
| 325 |
+
d1
|
| 326 |
+
15
|
| 327 |
+
f3
|
| 328 |
+
dd
|
| 329 |
+
ed
|
| 330 |
+
0e
|
| 331 |
+
e1
|
| 332 |
+
da
|
| 333 |
+
da
|
| 334 |
+
0d
|
| 335 |
+
0c
|
| 336 |
+
fb
|
| 337 |
+
04
|
| 338 |
+
05
|
| 339 |
+
e9
|
| 340 |
+
28
|
| 341 |
+
de
|
| 342 |
+
03
|
| 343 |
+
f8
|
| 344 |
+
38
|
| 345 |
+
22
|
| 346 |
+
df
|
| 347 |
+
e1
|
| 348 |
+
e0
|
| 349 |
+
d8
|
| 350 |
+
36
|
| 351 |
+
00
|
| 352 |
+
d3
|
| 353 |
+
ef
|
| 354 |
+
04
|
| 355 |
+
0a
|
| 356 |
+
01
|
| 357 |
+
42
|
| 358 |
+
26
|
| 359 |
+
fc
|
| 360 |
+
11
|
| 361 |
+
0b
|
| 362 |
+
0f
|
| 363 |
+
06
|
| 364 |
+
28
|
| 365 |
+
e9
|
| 366 |
+
16
|
| 367 |
+
02
|
| 368 |
+
c9
|
| 369 |
+
ff
|
| 370 |
+
eb
|
| 371 |
+
ee
|
| 372 |
+
23
|
| 373 |
+
ef
|
| 374 |
+
17
|
| 375 |
+
18
|
| 376 |
+
dc
|
| 377 |
+
14
|
| 378 |
+
d9
|
| 379 |
+
e6
|
| 380 |
+
1a
|
| 381 |
+
07
|
| 382 |
+
c6
|
| 383 |
+
e2
|
| 384 |
+
e1
|
| 385 |
+
06
|
| 386 |
+
12
|
| 387 |
+
22
|
| 388 |
+
e8
|
| 389 |
+
1d
|
| 390 |
+
10
|
| 391 |
+
c9
|
| 392 |
+
2f
|
| 393 |
+
0e
|
| 394 |
+
dc
|
| 395 |
+
c2
|
| 396 |
+
45
|
| 397 |
+
16
|
| 398 |
+
11
|
| 399 |
+
ff
|
| 400 |
+
30
|
| 401 |
+
1f
|
| 402 |
+
08
|
| 403 |
+
08
|
| 404 |
+
ee
|
| 405 |
+
09
|
| 406 |
+
e1
|
| 407 |
+
e9
|
| 408 |
+
24
|
| 409 |
+
ec
|
| 410 |
+
07
|
| 411 |
+
06
|
| 412 |
+
06
|
| 413 |
+
09
|
| 414 |
+
f6
|
| 415 |
+
22
|
| 416 |
+
09
|
| 417 |
+
0e
|
| 418 |
+
e1
|
| 419 |
+
f0
|
| 420 |
+
f6
|
| 421 |
+
49
|
| 422 |
+
0e
|
| 423 |
+
13
|
| 424 |
+
15
|
| 425 |
+
0c
|
| 426 |
+
03
|
| 427 |
+
f1
|
| 428 |
+
fb
|
| 429 |
+
01
|
| 430 |
+
fd
|
| 431 |
+
37
|
| 432 |
+
e8
|
| 433 |
+
d0
|
| 434 |
+
0b
|
| 435 |
+
05
|
| 436 |
+
be
|
| 437 |
+
1e
|
| 438 |
+
17
|
| 439 |
+
dd
|
| 440 |
+
24
|
| 441 |
+
06
|
| 442 |
+
d6
|
| 443 |
+
ed
|
| 444 |
+
15
|
| 445 |
+
fc
|
| 446 |
+
08
|
| 447 |
+
d7
|
| 448 |
+
d4
|
| 449 |
+
31
|
| 450 |
+
d5
|
| 451 |
+
0d
|
| 452 |
+
06
|
| 453 |
+
12
|
| 454 |
+
04
|
| 455 |
+
be
|
| 456 |
+
13
|
| 457 |
+
42
|
| 458 |
+
f3
|
| 459 |
+
14
|
| 460 |
+
2b
|
| 461 |
+
bc
|
| 462 |
+
bf
|
| 463 |
+
17
|
| 464 |
+
ec
|
| 465 |
+
f2
|
| 466 |
+
e4
|
| 467 |
+
d2
|
| 468 |
+
ce
|
| 469 |
+
e4
|
| 470 |
+
ef
|
| 471 |
+
f6
|
| 472 |
+
fa
|
| 473 |
+
0a
|
| 474 |
+
0c
|
| 475 |
+
09
|
| 476 |
+
fb
|
| 477 |
+
18
|
| 478 |
+
06
|
| 479 |
+
19
|
| 480 |
+
02
|
| 481 |
+
cb
|
| 482 |
+
07
|
| 483 |
+
1d
|
| 484 |
+
18
|
| 485 |
+
30
|
| 486 |
+
08
|
| 487 |
+
17
|
| 488 |
+
1f
|
| 489 |
+
f6
|
| 490 |
+
21
|
| 491 |
+
e3
|
| 492 |
+
3f
|
| 493 |
+
21
|
| 494 |
+
f0
|
| 495 |
+
01
|
| 496 |
+
08
|
| 497 |
+
1c
|
| 498 |
+
f4
|
| 499 |
+
f8
|
| 500 |
+
04
|
| 501 |
+
f2
|
| 502 |
+
13
|
| 503 |
+
f6
|
| 504 |
+
1f
|
| 505 |
+
23
|
| 506 |
+
ce
|
| 507 |
+
36
|
| 508 |
+
db
|
| 509 |
+
e8
|
| 510 |
+
c8
|
| 511 |
+
fa
|
| 512 |
+
dd
|
| 513 |
+
09
|
| 514 |
+
19
|
| 515 |
+
10
|
| 516 |
+
05
|
| 517 |
+
16
|
| 518 |
+
0a
|
| 519 |
+
12
|
| 520 |
+
fc
|
| 521 |
+
98
|
| 522 |
+
25
|
| 523 |
+
41
|
| 524 |
+
f9
|
| 525 |
+
03
|
| 526 |
+
f9
|
| 527 |
+
0f
|
| 528 |
+
04
|
| 529 |
+
fe
|
| 530 |
+
0f
|
| 531 |
+
c6
|
| 532 |
+
06
|
| 533 |
+
08
|
| 534 |
+
ef
|
| 535 |
+
1d
|
| 536 |
+
0b
|
| 537 |
+
cb
|
| 538 |
+
0b
|
| 539 |
+
0d
|
| 540 |
+
e1
|
| 541 |
+
3d
|
| 542 |
+
f4
|
| 543 |
+
f3
|
| 544 |
+
14
|
| 545 |
+
fb
|
| 546 |
+
0f
|
| 547 |
+
3a
|
| 548 |
+
f7
|
| 549 |
+
24
|
| 550 |
+
d2
|
| 551 |
+
26
|
| 552 |
+
c5
|
| 553 |
+
02
|
| 554 |
+
20
|
| 555 |
+
fe
|
| 556 |
+
26
|
| 557 |
+
35
|
| 558 |
+
f2
|
| 559 |
+
ed
|
| 560 |
+
26
|
| 561 |
+
f4
|
| 562 |
+
cb
|
| 563 |
+
09
|
| 564 |
+
16
|
| 565 |
+
03
|
| 566 |
+
ef
|
| 567 |
+
fd
|
| 568 |
+
11
|
| 569 |
+
00
|
| 570 |
+
10
|
| 571 |
+
3e
|
| 572 |
+
02
|
| 573 |
+
07
|
| 574 |
+
46
|
| 575 |
+
21
|
| 576 |
+
3e
|
| 577 |
+
dc
|
| 578 |
+
e8
|
| 579 |
+
00
|
| 580 |
+
ed
|
| 581 |
+
bb
|
| 582 |
+
16
|
| 583 |
+
ee
|
| 584 |
+
d7
|
| 585 |
+
24
|
| 586 |
+
e7
|
| 587 |
+
1c
|
| 588 |
+
f8
|
| 589 |
+
50
|
| 590 |
+
0a
|
| 591 |
+
f2
|
| 592 |
+
09
|
| 593 |
+
16
|
| 594 |
+
f1
|
| 595 |
+
19
|
| 596 |
+
c4
|
| 597 |
+
25
|
| 598 |
+
1e
|
| 599 |
+
e5
|
| 600 |
+
12
|
| 601 |
+
f4
|
| 602 |
+
24
|
| 603 |
+
16
|
| 604 |
+
02
|
| 605 |
+
ff
|
| 606 |
+
31
|
| 607 |
+
fc
|
| 608 |
+
f7
|
| 609 |
+
05
|
| 610 |
+
ee
|
| 611 |
+
1f
|
| 612 |
+
35
|
| 613 |
+
cc
|
| 614 |
+
03
|
| 615 |
+
76
|
| 616 |
+
f1
|
| 617 |
+
2b
|
| 618 |
+
36
|
| 619 |
+
e7
|
| 620 |
+
f7
|
| 621 |
+
e7
|
| 622 |
+
eb
|
| 623 |
+
15
|
| 624 |
+
e3
|
| 625 |
+
e7
|
| 626 |
+
1c
|
| 627 |
+
ea
|
| 628 |
+
22
|
| 629 |
+
2b
|
| 630 |
+
3a
|
| 631 |
+
0e
|
| 632 |
+
05
|
| 633 |
+
f1
|
| 634 |
+
fb
|
| 635 |
+
17
|
| 636 |
+
2f
|
| 637 |
+
0c
|
| 638 |
+
f3
|
| 639 |
+
f4
|
| 640 |
+
e0
|
| 641 |
+
1b
|
| 642 |
+
05
|
| 643 |
+
09
|
| 644 |
+
09
|
| 645 |
+
01
|
| 646 |
+
04
|
| 647 |
+
08
|
| 648 |
+
23
|
| 649 |
+
fd
|
| 650 |
+
03
|
| 651 |
+
16
|
| 652 |
+
07
|
| 653 |
+
d9
|
| 654 |
+
12
|
| 655 |
+
ea
|
| 656 |
+
ff
|
| 657 |
+
15
|
| 658 |
+
dd
|
| 659 |
+
f6
|
| 660 |
+
1f
|
| 661 |
+
1d
|
| 662 |
+
27
|
| 663 |
+
02
|
| 664 |
+
f3
|
| 665 |
+
ff
|
| 666 |
+
0b
|
| 667 |
+
09
|
| 668 |
+
08
|
| 669 |
+
e7
|
| 670 |
+
db
|
| 671 |
+
c5
|
| 672 |
+
ea
|
| 673 |
+
03
|
| 674 |
+
ed
|
| 675 |
+
e6
|
| 676 |
+
ff
|
| 677 |
+
d1
|
| 678 |
+
e4
|
| 679 |
+
e2
|
| 680 |
+
fb
|
| 681 |
+
ff
|
| 682 |
+
0b
|
| 683 |
+
38
|
| 684 |
+
05
|
| 685 |
+
01
|
| 686 |
+
1d
|
| 687 |
+
0c
|
| 688 |
+
0a
|
| 689 |
+
2b
|
| 690 |
+
22
|
| 691 |
+
18
|
| 692 |
+
df
|
| 693 |
+
14
|
| 694 |
+
f5
|
| 695 |
+
0b
|
| 696 |
+
ec
|
| 697 |
+
e7
|
| 698 |
+
f0
|
| 699 |
+
00
|
| 700 |
+
e1
|
| 701 |
+
09
|
| 702 |
+
f1
|
| 703 |
+
13
|
| 704 |
+
2a
|
| 705 |
+
20
|
| 706 |
+
f8
|
| 707 |
+
20
|
| 708 |
+
cd
|
| 709 |
+
04
|
| 710 |
+
31
|
| 711 |
+
fa
|
| 712 |
+
0f
|
| 713 |
+
c7
|
| 714 |
+
1a
|
| 715 |
+
12
|
| 716 |
+
20
|
| 717 |
+
f8
|
| 718 |
+
de
|
| 719 |
+
f2
|
| 720 |
+
34
|
| 721 |
+
2b
|
| 722 |
+
e6
|
| 723 |
+
21
|
| 724 |
+
fd
|
| 725 |
+
0a
|
| 726 |
+
31
|
| 727 |
+
16
|
| 728 |
+
f7
|
| 729 |
+
14
|
| 730 |
+
f6
|
| 731 |
+
f6
|
| 732 |
+
f9
|
| 733 |
+
39
|
| 734 |
+
3d
|
| 735 |
+
1c
|
| 736 |
+
fd
|
| 737 |
+
fb
|
| 738 |
+
f8
|
| 739 |
+
29
|
| 740 |
+
06
|
| 741 |
+
f8
|
| 742 |
+
ff
|
| 743 |
+
0a
|
| 744 |
+
de
|
| 745 |
+
f4
|
| 746 |
+
ee
|
| 747 |
+
de
|
| 748 |
+
16
|
| 749 |
+
e5
|
| 750 |
+
d5
|
| 751 |
+
04
|
| 752 |
+
ff
|
| 753 |
+
ed
|
| 754 |
+
d3
|
| 755 |
+
e9
|
| 756 |
+
ff
|
| 757 |
+
00
|
| 758 |
+
f3
|
| 759 |
+
cc
|
| 760 |
+
f8
|
| 761 |
+
dd
|
| 762 |
+
f4
|
| 763 |
+
29
|
| 764 |
+
fa
|
| 765 |
+
d0
|
| 766 |
+
0a
|
| 767 |
+
02
|
| 768 |
+
13
|
| 769 |
+
07
|
| 770 |
+
f4
|
| 771 |
+
e8
|
| 772 |
+
47
|
| 773 |
+
2e
|
| 774 |
+
f0
|
| 775 |
+
0b
|
| 776 |
+
eb
|
| 777 |
+
2f
|
| 778 |
+
e5
|
| 779 |
+
ed
|
| 780 |
+
fe
|
| 781 |
+
e7
|
| 782 |
+
f2
|
| 783 |
+
05
|
| 784 |
+
f9
|
| 785 |
+
ff
|
| 786 |
+
04
|
| 787 |
+
18
|
| 788 |
+
e6
|
| 789 |
+
f9
|
| 790 |
+
16
|
| 791 |
+
16
|
| 792 |
+
e5
|
| 793 |
+
e4
|
| 794 |
+
ed
|
| 795 |
+
3d
|
| 796 |
+
21
|
| 797 |
+
cf
|
| 798 |
+
24
|
| 799 |
+
e0
|
| 800 |
+
05
|
| 801 |
+
dd
|
| 802 |
+
fc
|
| 803 |
+
1e
|
| 804 |
+
14
|
| 805 |
+
0a
|
| 806 |
+
f0
|
| 807 |
+
02
|
| 808 |
+
d1
|
| 809 |
+
21
|
| 810 |
+
d5
|
| 811 |
+
0e
|
| 812 |
+
ef
|
| 813 |
+
1c
|
| 814 |
+
2a
|
| 815 |
+
28
|
| 816 |
+
f9
|
| 817 |
+
ed
|
| 818 |
+
0a
|
| 819 |
+
e5
|
| 820 |
+
e2
|
| 821 |
+
21
|
| 822 |
+
11
|
| 823 |
+
fc
|
| 824 |
+
09
|
| 825 |
+
0e
|
| 826 |
+
f8
|
| 827 |
+
1d
|
| 828 |
+
0f
|
| 829 |
+
1e
|
| 830 |
+
1d
|
| 831 |
+
08
|
| 832 |
+
df
|
| 833 |
+
e4
|
| 834 |
+
1b
|
| 835 |
+
df
|
| 836 |
+
04
|
| 837 |
+
de
|
| 838 |
+
0c
|
| 839 |
+
ca
|
| 840 |
+
e0
|
| 841 |
+
e9
|
| 842 |
+
0d
|
| 843 |
+
ff
|
| 844 |
+
f5
|
| 845 |
+
f7
|
| 846 |
+
44
|
| 847 |
+
cd
|
| 848 |
+
01
|
| 849 |
+
1f
|
| 850 |
+
f4
|
| 851 |
+
1c
|
| 852 |
+
c8
|
| 853 |
+
d9
|
| 854 |
+
d2
|
| 855 |
+
32
|
| 856 |
+
03
|
| 857 |
+
00
|
| 858 |
+
1b
|
| 859 |
+
fa
|
| 860 |
+
f6
|
| 861 |
+
ec
|
| 862 |
+
df
|
| 863 |
+
14
|
| 864 |
+
0c
|
| 865 |
+
16
|
| 866 |
+
1c
|
| 867 |
+
f9
|
| 868 |
+
0f
|
| 869 |
+
cd
|
| 870 |
+
eb
|
| 871 |
+
ee
|
| 872 |
+
e1
|
| 873 |
+
fc
|
| 874 |
+
dc
|
| 875 |
+
e8
|
| 876 |
+
0e
|
| 877 |
+
10
|
| 878 |
+
f9
|
| 879 |
+
21
|
| 880 |
+
f4
|
| 881 |
+
fa
|
| 882 |
+
f8
|
| 883 |
+
0d
|
| 884 |
+
de
|
| 885 |
+
1f
|
| 886 |
+
07
|
| 887 |
+
df
|
| 888 |
+
1b
|
| 889 |
+
ec
|
| 890 |
+
fa
|
| 891 |
+
03
|
| 892 |
+
fc
|
| 893 |
+
07
|
| 894 |
+
fb
|
| 895 |
+
05
|
| 896 |
+
26
|
| 897 |
+
0b
|
| 898 |
+
d1
|
| 899 |
+
0b
|
| 900 |
+
d3
|
| 901 |
+
29
|
| 902 |
+
0d
|
| 903 |
+
f2
|
| 904 |
+
20
|
| 905 |
+
b8
|
| 906 |
+
28
|
| 907 |
+
04
|
| 908 |
+
c4
|
| 909 |
+
de
|
| 910 |
+
10
|
| 911 |
+
e3
|
| 912 |
+
00
|
| 913 |
+
ee
|
| 914 |
+
09
|
| 915 |
+
09
|
| 916 |
+
ec
|
| 917 |
+
1a
|
| 918 |
+
fd
|
| 919 |
+
37
|
| 920 |
+
0f
|
| 921 |
+
24
|
| 922 |
+
e5
|
| 923 |
+
10
|
| 924 |
+
19
|
| 925 |
+
bd
|
| 926 |
+
f2
|
| 927 |
+
0f
|
| 928 |
+
02
|
| 929 |
+
35
|
| 930 |
+
f2
|
| 931 |
+
f6
|
| 932 |
+
29
|
| 933 |
+
f8
|
| 934 |
+
ec
|
| 935 |
+
fb
|
| 936 |
+
f5
|
| 937 |
+
22
|
| 938 |
+
02
|
| 939 |
+
01
|
| 940 |
+
f1
|
| 941 |
+
09
|
| 942 |
+
f8
|
| 943 |
+
f1
|
| 944 |
+
dc
|
| 945 |
+
07
|
| 946 |
+
1c
|
| 947 |
+
2a
|
| 948 |
+
fa
|
| 949 |
+
10
|
| 950 |
+
14
|
| 951 |
+
f4
|
| 952 |
+
05
|
| 953 |
+
45
|
| 954 |
+
26
|
| 955 |
+
e6
|
| 956 |
+
f4
|
| 957 |
+
ff
|
| 958 |
+
19
|
| 959 |
+
c9
|
| 960 |
+
da
|
| 961 |
+
0a
|
| 962 |
+
05
|
| 963 |
+
12
|
| 964 |
+
dd
|
| 965 |
+
f9
|
| 966 |
+
f4
|
| 967 |
+
24
|
| 968 |
+
fb
|
| 969 |
+
04
|
| 970 |
+
13
|
| 971 |
+
03
|
| 972 |
+
54
|
| 973 |
+
09
|
| 974 |
+
14
|
| 975 |
+
19
|
| 976 |
+
1e
|
| 977 |
+
01
|
| 978 |
+
d0
|
| 979 |
+
1a
|
| 980 |
+
f2
|
| 981 |
+
44
|
| 982 |
+
08
|
| 983 |
+
38
|
| 984 |
+
2f
|
| 985 |
+
f9
|
| 986 |
+
03
|
| 987 |
+
e5
|
| 988 |
+
09
|
| 989 |
+
da
|
| 990 |
+
ff
|
| 991 |
+
e8
|
| 992 |
+
fb
|
| 993 |
+
f8
|
| 994 |
+
14
|
| 995 |
+
e3
|
| 996 |
+
12
|
| 997 |
+
0e
|
| 998 |
+
11
|
| 999 |
+
ff
|
| 1000 |
+
f0
|
| 1001 |
+
e7
|
| 1002 |
+
01
|
| 1003 |
+
fe
|
| 1004 |
+
db
|
| 1005 |
+
f0
|
| 1006 |
+
1e
|
| 1007 |
+
21
|
| 1008 |
+
1e
|
| 1009 |
+
05
|
| 1010 |
+
e7
|
| 1011 |
+
e9
|
| 1012 |
+
03
|
| 1013 |
+
fd
|
| 1014 |
+
01
|
| 1015 |
+
ef
|
| 1016 |
+
10
|
| 1017 |
+
dc
|
| 1018 |
+
00
|
| 1019 |
+
19
|
| 1020 |
+
13
|
| 1021 |
+
e7
|
| 1022 |
+
15
|
| 1023 |
+
07
|
| 1024 |
+
36
|
| 1025 |
+
fc
|
| 1026 |
+
d9
|
| 1027 |
+
ff
|
| 1028 |
+
0f
|
| 1029 |
+
fa
|
| 1030 |
+
01
|
| 1031 |
+
05
|
| 1032 |
+
3e
|
| 1033 |
+
06
|
| 1034 |
+
01
|
| 1035 |
+
0e
|
| 1036 |
+
ed
|
| 1037 |
+
1f
|
| 1038 |
+
00
|
| 1039 |
+
d4
|
| 1040 |
+
e7
|
| 1041 |
+
ee
|
| 1042 |
+
ce
|
| 1043 |
+
eb
|
| 1044 |
+
e5
|
| 1045 |
+
01
|
| 1046 |
+
1d
|
| 1047 |
+
c5
|
| 1048 |
+
df
|
| 1049 |
+
2c
|
| 1050 |
+
08
|
| 1051 |
+
15
|
| 1052 |
+
dd
|
| 1053 |
+
e9
|
| 1054 |
+
01
|
| 1055 |
+
f6
|
| 1056 |
+
20
|
| 1057 |
+
fa
|
| 1058 |
+
d5
|
| 1059 |
+
0a
|
| 1060 |
+
13
|
| 1061 |
+
ef
|
| 1062 |
+
cc
|
| 1063 |
+
f4
|
| 1064 |
+
fd
|
| 1065 |
+
0d
|
| 1066 |
+
26
|
| 1067 |
+
e8
|
| 1068 |
+
13
|
| 1069 |
+
fe
|
| 1070 |
+
dd
|
| 1071 |
+
fc
|
| 1072 |
+
13
|
| 1073 |
+
eb
|
| 1074 |
+
10
|
| 1075 |
+
0a
|
| 1076 |
+
0e
|
| 1077 |
+
10
|
| 1078 |
+
13
|
| 1079 |
+
f1
|
| 1080 |
+
11
|
| 1081 |
+
e6
|
| 1082 |
+
e0
|
| 1083 |
+
f0
|
| 1084 |
+
e5
|
| 1085 |
+
0d
|
| 1086 |
+
d2
|
| 1087 |
+
f6
|
| 1088 |
+
12
|
| 1089 |
+
ec
|
| 1090 |
+
2e
|
| 1091 |
+
2d
|
| 1092 |
+
cf
|
| 1093 |
+
ec
|
| 1094 |
+
f8
|
| 1095 |
+
ff
|
| 1096 |
+
fc
|
| 1097 |
+
eb
|
| 1098 |
+
fd
|
| 1099 |
+
e1
|
| 1100 |
+
ef
|
| 1101 |
+
ed
|
| 1102 |
+
05
|
| 1103 |
+
06
|
| 1104 |
+
ff
|
| 1105 |
+
df
|
| 1106 |
+
0b
|
| 1107 |
+
ec
|
| 1108 |
+
13
|
| 1109 |
+
e6
|
| 1110 |
+
03
|
| 1111 |
+
ff
|
| 1112 |
+
32
|
| 1113 |
+
17
|
| 1114 |
+
eb
|
| 1115 |
+
f3
|
| 1116 |
+
ef
|
| 1117 |
+
e7
|
| 1118 |
+
29
|
| 1119 |
+
f2
|
| 1120 |
+
e6
|
| 1121 |
+
ea
|
| 1122 |
+
fa
|
| 1123 |
+
ee
|
| 1124 |
+
ed
|
| 1125 |
+
18
|
| 1126 |
+
13
|
| 1127 |
+
0c
|
| 1128 |
+
0a
|
| 1129 |
+
18
|
| 1130 |
+
1c
|
| 1131 |
+
19
|
| 1132 |
+
1a
|
| 1133 |
+
e5
|
| 1134 |
+
22
|
| 1135 |
+
07
|
| 1136 |
+
dd
|
| 1137 |
+
10
|
| 1138 |
+
d4
|
| 1139 |
+
02
|
| 1140 |
+
2b
|
| 1141 |
+
db
|
| 1142 |
+
20
|
| 1143 |
+
27
|
| 1144 |
+
de
|
| 1145 |
+
10
|
| 1146 |
+
c8
|
| 1147 |
+
e9
|
| 1148 |
+
03
|
| 1149 |
+
18
|
| 1150 |
+
e4
|
| 1151 |
+
fe
|
| 1152 |
+
e7
|
| 1153 |
+
13
|
| 1154 |
+
00
|
| 1155 |
+
33
|
| 1156 |
+
ed
|
| 1157 |
+
07
|
| 1158 |
+
ff
|
| 1159 |
+
d8
|
| 1160 |
+
f7
|
| 1161 |
+
05
|
| 1162 |
+
d1
|
| 1163 |
+
dc
|
| 1164 |
+
26
|
| 1165 |
+
0d
|
| 1166 |
+
f8
|
| 1167 |
+
06
|
| 1168 |
+
36
|
| 1169 |
+
01
|
| 1170 |
+
13
|
| 1171 |
+
16
|
| 1172 |
+
05
|
| 1173 |
+
15
|
| 1174 |
+
f0
|
| 1175 |
+
e1
|
| 1176 |
+
03
|
| 1177 |
+
09
|
| 1178 |
+
ed
|
| 1179 |
+
15
|
| 1180 |
+
ef
|
| 1181 |
+
0b
|
| 1182 |
+
dd
|
| 1183 |
+
1e
|
| 1184 |
+
0a
|
| 1185 |
+
f7
|
| 1186 |
+
e1
|
| 1187 |
+
dd
|
| 1188 |
+
ec
|
| 1189 |
+
36
|
| 1190 |
+
fe
|
| 1191 |
+
27
|
| 1192 |
+
02
|
| 1193 |
+
e3
|
| 1194 |
+
0e
|
| 1195 |
+
d5
|
| 1196 |
+
f8
|
| 1197 |
+
14
|
| 1198 |
+
f5
|
| 1199 |
+
09
|
| 1200 |
+
e9
|
| 1201 |
+
f3
|
| 1202 |
+
1a
|
| 1203 |
+
e3
|
| 1204 |
+
da
|
| 1205 |
+
23
|
| 1206 |
+
fd
|
| 1207 |
+
d4
|
| 1208 |
+
3e
|
| 1209 |
+
12
|
| 1210 |
+
dd
|
| 1211 |
+
d7
|
| 1212 |
+
0f
|
| 1213 |
+
da
|
| 1214 |
+
08
|
| 1215 |
+
df
|
| 1216 |
+
ef
|
| 1217 |
+
24
|
| 1218 |
+
da
|
| 1219 |
+
16
|
| 1220 |
+
18
|
| 1221 |
+
15
|
| 1222 |
+
f5
|
| 1223 |
+
b8
|
| 1224 |
+
1d
|
| 1225 |
+
3f
|
| 1226 |
+
06
|
| 1227 |
+
1a
|
| 1228 |
+
18
|
| 1229 |
+
da
|
| 1230 |
+
d4
|
| 1231 |
+
0c
|
| 1232 |
+
f6
|
| 1233 |
+
26
|
| 1234 |
+
d1
|
| 1235 |
+
de
|
| 1236 |
+
f9
|
| 1237 |
+
e6
|
| 1238 |
+
f2
|
| 1239 |
+
f8
|
| 1240 |
+
fe
|
| 1241 |
+
14
|
| 1242 |
+
0d
|
| 1243 |
+
0f
|
| 1244 |
+
01
|
| 1245 |
+
04
|
| 1246 |
+
fb
|
| 1247 |
+
23
|
| 1248 |
+
1c
|
| 1249 |
+
de
|
| 1250 |
+
01
|
| 1251 |
+
0d
|
| 1252 |
+
10
|
| 1253 |
+
22
|
| 1254 |
+
f9
|
| 1255 |
+
07
|
| 1256 |
+
25
|
| 1257 |
+
cb
|
| 1258 |
+
0a
|
| 1259 |
+
ea
|
| 1260 |
+
0f
|
| 1261 |
+
03
|
| 1262 |
+
f3
|
| 1263 |
+
05
|
| 1264 |
+
56
|
| 1265 |
+
39
|
| 1266 |
+
14
|
| 1267 |
+
fd
|
| 1268 |
+
16
|
| 1269 |
+
1c
|
| 1270 |
+
03
|
| 1271 |
+
00
|
| 1272 |
+
04
|
| 1273 |
+
ef
|
| 1274 |
+
cd
|
| 1275 |
+
1a
|
| 1276 |
+
c3
|
| 1277 |
+
01
|
| 1278 |
+
bc
|
| 1279 |
+
ea
|
| 1280 |
+
ed
|
| 1281 |
+
0f
|
| 1282 |
+
16
|
| 1283 |
+
00
|
| 1284 |
+
f6
|
| 1285 |
+
f8
|
| 1286 |
+
2e
|
| 1287 |
+
26
|
| 1288 |
+
10
|
| 1289 |
+
a1
|
| 1290 |
+
24
|
| 1291 |
+
45
|
| 1292 |
+
0c
|
| 1293 |
+
fa
|
| 1294 |
+
02
|
| 1295 |
+
fb
|
| 1296 |
+
1c
|
| 1297 |
+
01
|
| 1298 |
+
17
|
| 1299 |
+
e0
|
| 1300 |
+
0c
|
| 1301 |
+
fb
|
| 1302 |
+
eb
|
| 1303 |
+
02
|
| 1304 |
+
f1
|
| 1305 |
+
e9
|
| 1306 |
+
12
|
| 1307 |
+
e9
|
| 1308 |
+
e0
|
| 1309 |
+
22
|
| 1310 |
+
eb
|
| 1311 |
+
f9
|
| 1312 |
+
fb
|
| 1313 |
+
12
|
| 1314 |
+
0b
|
| 1315 |
+
22
|
| 1316 |
+
f8
|
| 1317 |
+
11
|
| 1318 |
+
ee
|
| 1319 |
+
16
|
| 1320 |
+
d9
|
| 1321 |
+
eb
|
| 1322 |
+
1c
|
| 1323 |
+
eb
|
| 1324 |
+
1a
|
| 1325 |
+
36
|
| 1326 |
+
db
|
| 1327 |
+
cb
|
| 1328 |
+
24
|
| 1329 |
+
01
|
| 1330 |
+
07
|
| 1331 |
+
f9
|
| 1332 |
+
0a
|
| 1333 |
+
32
|
| 1334 |
+
fb
|
| 1335 |
+
f2
|
| 1336 |
+
10
|
| 1337 |
+
10
|
| 1338 |
+
f6
|
| 1339 |
+
15
|
| 1340 |
+
e8
|
| 1341 |
+
f6
|
| 1342 |
+
45
|
| 1343 |
+
2b
|
| 1344 |
+
20
|
| 1345 |
+
da
|
| 1346 |
+
a9
|
| 1347 |
+
e0
|
| 1348 |
+
f9
|
| 1349 |
+
c7
|
| 1350 |
+
02
|
| 1351 |
+
e9
|
| 1352 |
+
00
|
| 1353 |
+
27
|
| 1354 |
+
fe
|
| 1355 |
+
31
|
| 1356 |
+
fb
|
| 1357 |
+
39
|
| 1358 |
+
da
|
| 1359 |
+
f3
|
| 1360 |
+
12
|
| 1361 |
+
21
|
| 1362 |
+
f0
|
| 1363 |
+
01
|
| 1364 |
+
e9
|
| 1365 |
+
13
|
| 1366 |
+
19
|
| 1367 |
+
e8
|
| 1368 |
+
08
|
| 1369 |
+
e5
|
| 1370 |
+
fb
|
| 1371 |
+
24
|
| 1372 |
+
ef
|
| 1373 |
+
03
|
| 1374 |
+
0d
|
| 1375 |
+
f5
|
| 1376 |
+
f2
|
| 1377 |
+
0b
|
| 1378 |
+
fc
|
| 1379 |
+
10
|
| 1380 |
+
35
|
| 1381 |
+
d0
|
| 1382 |
+
f9
|
| 1383 |
+
7f
|
| 1384 |
+
04
|
| 1385 |
+
34
|
| 1386 |
+
32
|
| 1387 |
+
e5
|
| 1388 |
+
ec
|
| 1389 |
+
0c
|
| 1390 |
+
f1
|
| 1391 |
+
fa
|
| 1392 |
+
e6
|
| 1393 |
+
f9
|
| 1394 |
+
2b
|
| 1395 |
+
f8
|
| 1396 |
+
f4
|
| 1397 |
+
3f
|
| 1398 |
+
31
|
| 1399 |
+
fc
|
| 1400 |
+
22
|
| 1401 |
+
ea
|
| 1402 |
+
ff
|
| 1403 |
+
06
|
| 1404 |
+
2e
|
| 1405 |
+
04
|
| 1406 |
+
f6
|
| 1407 |
+
09
|
| 1408 |
+
dc
|
| 1409 |
+
0b
|
| 1410 |
+
fe
|
| 1411 |
+
f8
|
| 1412 |
+
0b
|
| 1413 |
+
f1
|
| 1414 |
+
00
|
| 1415 |
+
2d
|
| 1416 |
+
36
|
| 1417 |
+
dc
|
| 1418 |
+
f9
|
| 1419 |
+
fe
|
| 1420 |
+
fa
|
| 1421 |
+
de
|
| 1422 |
+
17
|
| 1423 |
+
f2
|
| 1424 |
+
0c
|
| 1425 |
+
11
|
| 1426 |
+
e3
|
| 1427 |
+
17
|
| 1428 |
+
0b
|
| 1429 |
+
0d
|
| 1430 |
+
fc
|
| 1431 |
+
09
|
| 1432 |
+
ee
|
| 1433 |
+
03
|
| 1434 |
+
07
|
| 1435 |
+
14
|
| 1436 |
+
0b
|
| 1437 |
+
ed
|
| 1438 |
+
0e
|
| 1439 |
+
d2
|
| 1440 |
+
fa
|
| 1441 |
+
d6
|
| 1442 |
+
11
|
| 1443 |
+
d8
|
| 1444 |
+
fc
|
| 1445 |
+
0c
|
| 1446 |
+
fb
|
| 1447 |
+
cf
|
| 1448 |
+
e9
|
| 1449 |
+
ea
|
| 1450 |
+
06
|
| 1451 |
+
16
|
| 1452 |
+
18
|
| 1453 |
+
f8
|
| 1454 |
+
14
|
| 1455 |
+
00
|
| 1456 |
+
d8
|
| 1457 |
+
01
|
| 1458 |
+
1c
|
| 1459 |
+
07
|
| 1460 |
+
df
|
| 1461 |
+
01
|
| 1462 |
+
f0
|
| 1463 |
+
ed
|
| 1464 |
+
14
|
| 1465 |
+
f3
|
| 1466 |
+
da
|
| 1467 |
+
ff
|
| 1468 |
+
e2
|
| 1469 |
+
fe
|
| 1470 |
+
09
|
| 1471 |
+
24
|
| 1472 |
+
45
|
| 1473 |
+
16
|
| 1474 |
+
fc
|
| 1475 |
+
00
|
| 1476 |
+
df
|
| 1477 |
+
f2
|
| 1478 |
+
1b
|
| 1479 |
+
f6
|
| 1480 |
+
10
|
| 1481 |
+
d0
|
| 1482 |
+
23
|
| 1483 |
+
20
|
| 1484 |
+
21
|
| 1485 |
+
9d
|
| 1486 |
+
ef
|
| 1487 |
+
fe
|
| 1488 |
+
02
|
| 1489 |
+
0c
|
| 1490 |
+
ea
|
| 1491 |
+
14
|
| 1492 |
+
09
|
| 1493 |
+
15
|
| 1494 |
+
1f
|
| 1495 |
+
25
|
| 1496 |
+
d8
|
| 1497 |
+
19
|
| 1498 |
+
0d
|
| 1499 |
+
e8
|
| 1500 |
+
04
|
| 1501 |
+
f3
|
| 1502 |
+
2e
|
| 1503 |
+
02
|
| 1504 |
+
f9
|
| 1505 |
+
f2
|
| 1506 |
+
f5
|
| 1507 |
+
1a
|
| 1508 |
+
e3
|
| 1509 |
+
e9
|
| 1510 |
+
d6
|
| 1511 |
+
02
|
| 1512 |
+
ee
|
| 1513 |
+
02
|
| 1514 |
+
f9
|
| 1515 |
+
e9
|
| 1516 |
+
2f
|
| 1517 |
+
ed
|
| 1518 |
+
ca
|
| 1519 |
+
0b
|
| 1520 |
+
01
|
| 1521 |
+
19
|
| 1522 |
+
11
|
| 1523 |
+
ea
|
| 1524 |
+
ef
|
| 1525 |
+
26
|
| 1526 |
+
e2
|
| 1527 |
+
ef
|
| 1528 |
+
f4
|
| 1529 |
+
fb
|
| 1530 |
+
e5
|
| 1531 |
+
f0
|
| 1532 |
+
1e
|
| 1533 |
+
e6
|
| 1534 |
+
05
|
| 1535 |
+
f9
|
| 1536 |
+
00
|
| 1537 |
+
fa
|
| 1538 |
+
09
|
| 1539 |
+
fb
|
| 1540 |
+
2a
|
| 1541 |
+
22
|
| 1542 |
+
fe
|
| 1543 |
+
fc
|
| 1544 |
+
1d
|
| 1545 |
+
11
|
| 1546 |
+
fc
|
| 1547 |
+
e9
|
| 1548 |
+
da
|
| 1549 |
+
f7
|
| 1550 |
+
02
|
| 1551 |
+
f2
|
| 1552 |
+
f0
|
| 1553 |
+
d7
|
| 1554 |
+
f1
|
| 1555 |
+
07
|
| 1556 |
+
0b
|
| 1557 |
+
0d
|
| 1558 |
+
04
|
| 1559 |
+
0d
|
| 1560 |
+
bf
|
| 1561 |
+
f2
|
| 1562 |
+
ee
|
| 1563 |
+
3d
|
| 1564 |
+
12
|
| 1565 |
+
e1
|
| 1566 |
+
2a
|
| 1567 |
+
e2
|
| 1568 |
+
d3
|
| 1569 |
+
e3
|
| 1570 |
+
f1
|
| 1571 |
+
0d
|
| 1572 |
+
11
|
| 1573 |
+
e4
|
| 1574 |
+
e9
|
| 1575 |
+
01
|
| 1576 |
+
f1
|
| 1577 |
+
16
|
| 1578 |
+
e0
|
| 1579 |
+
0a
|
| 1580 |
+
db
|
| 1581 |
+
1e
|
| 1582 |
+
41
|
| 1583 |
+
14
|
| 1584 |
+
ef
|
| 1585 |
+
e4
|
| 1586 |
+
04
|
| 1587 |
+
07
|
| 1588 |
+
d4
|
| 1589 |
+
01
|
| 1590 |
+
f2
|
| 1591 |
+
19
|
| 1592 |
+
fd
|
| 1593 |
+
20
|
| 1594 |
+
d5
|
| 1595 |
+
29
|
| 1596 |
+
19
|
| 1597 |
+
0f
|
| 1598 |
+
0c
|
| 1599 |
+
08
|
| 1600 |
+
da
|
| 1601 |
+
d9
|
| 1602 |
+
0e
|
| 1603 |
+
e9
|
| 1604 |
+
f7
|
| 1605 |
+
d8
|
| 1606 |
+
27
|
| 1607 |
+
f0
|
| 1608 |
+
e9
|
| 1609 |
+
e7
|
| 1610 |
+
ff
|
| 1611 |
+
1a
|
| 1612 |
+
f5
|
| 1613 |
+
d1
|
| 1614 |
+
42
|
| 1615 |
+
c9
|
| 1616 |
+
ef
|
| 1617 |
+
12
|
| 1618 |
+
f6
|
| 1619 |
+
1c
|
| 1620 |
+
c1
|
| 1621 |
+
da
|
| 1622 |
+
eb
|
| 1623 |
+
30
|
| 1624 |
+
ec
|
| 1625 |
+
f8
|
| 1626 |
+
39
|
| 1627 |
+
fc
|
| 1628 |
+
d8
|
| 1629 |
+
ec
|
| 1630 |
+
c1
|
| 1631 |
+
01
|
| 1632 |
+
1d
|
| 1633 |
+
18
|
| 1634 |
+
27
|
| 1635 |
+
fa
|
| 1636 |
+
21
|
| 1637 |
+
fc
|
| 1638 |
+
e8
|
| 1639 |
+
f7
|
| 1640 |
+
f1
|
| 1641 |
+
06
|
| 1642 |
+
db
|
| 1643 |
+
ea
|
| 1644 |
+
2e
|
| 1645 |
+
ea
|
| 1646 |
+
02
|
| 1647 |
+
06
|
| 1648 |
+
d7
|
| 1649 |
+
fa
|
| 1650 |
+
09
|
| 1651 |
+
10
|
| 1652 |
+
fc
|
| 1653 |
+
17
|
| 1654 |
+
0a
|
| 1655 |
+
ed
|
| 1656 |
+
26
|
| 1657 |
+
eb
|
| 1658 |
+
e5
|
| 1659 |
+
0c
|
| 1660 |
+
f2
|
| 1661 |
+
ff
|
| 1662 |
+
f9
|
| 1663 |
+
0d
|
| 1664 |
+
12
|
| 1665 |
+
11
|
| 1666 |
+
f7
|
| 1667 |
+
0e
|
| 1668 |
+
bb
|
| 1669 |
+
22
|
| 1670 |
+
1a
|
| 1671 |
+
ce
|
| 1672 |
+
2b
|
| 1673 |
+
be
|
| 1674 |
+
08
|
| 1675 |
+
11
|
| 1676 |
+
d1
|
| 1677 |
+
ea
|
| 1678 |
+
1f
|
| 1679 |
+
02
|
| 1680 |
+
f0
|
| 1681 |
+
fe
|
| 1682 |
+
fc
|
| 1683 |
+
12
|
| 1684 |
+
f7
|
| 1685 |
+
1c
|
| 1686 |
+
1b
|
| 1687 |
+
09
|
| 1688 |
+
06
|
| 1689 |
+
04
|
| 1690 |
+
da
|
| 1691 |
+
04
|
| 1692 |
+
f6
|
| 1693 |
+
c5
|
| 1694 |
+
ff
|
| 1695 |
+
fe
|
| 1696 |
+
01
|
| 1697 |
+
50
|
| 1698 |
+
24
|
| 1699 |
+
bd
|
| 1700 |
+
21
|
| 1701 |
+
e2
|
| 1702 |
+
07
|
| 1703 |
+
f8
|
| 1704 |
+
13
|
| 1705 |
+
1e
|
| 1706 |
+
fd
|
| 1707 |
+
f2
|
| 1708 |
+
0d
|
| 1709 |
+
fb
|
| 1710 |
+
18
|
| 1711 |
+
0a
|
| 1712 |
+
e1
|
| 1713 |
+
01
|
| 1714 |
+
22
|
| 1715 |
+
08
|
| 1716 |
+
11
|
| 1717 |
+
20
|
| 1718 |
+
16
|
| 1719 |
+
12
|
| 1720 |
+
23
|
| 1721 |
+
40
|
| 1722 |
+
28
|
| 1723 |
+
f1
|
| 1724 |
+
e8
|
| 1725 |
+
fd
|
| 1726 |
+
15
|
| 1727 |
+
e4
|
| 1728 |
+
e8
|
| 1729 |
+
03
|
| 1730 |
+
0d
|
| 1731 |
+
1f
|
| 1732 |
+
ea
|
| 1733 |
+
d7
|
| 1734 |
+
11
|
| 1735 |
+
03
|
| 1736 |
+
21
|
| 1737 |
+
f2
|
| 1738 |
+
18
|
| 1739 |
+
00
|
| 1740 |
+
1e
|
| 1741 |
+
0b
|
| 1742 |
+
3b
|
| 1743 |
+
03
|
| 1744 |
+
0f
|
| 1745 |
+
f8
|
| 1746 |
+
e2
|
| 1747 |
+
10
|
| 1748 |
+
0c
|
| 1749 |
+
24
|
| 1750 |
+
fe
|
| 1751 |
+
38
|
| 1752 |
+
0c
|
| 1753 |
+
ef
|
| 1754 |
+
0c
|
| 1755 |
+
d4
|
| 1756 |
+
40
|
| 1757 |
+
dc
|
| 1758 |
+
1e
|
| 1759 |
+
e1
|
| 1760 |
+
f6
|
| 1761 |
+
f4
|
| 1762 |
+
15
|
| 1763 |
+
ec
|
| 1764 |
+
1e
|
| 1765 |
+
2c
|
| 1766 |
+
1f
|
| 1767 |
+
08
|
| 1768 |
+
de
|
| 1769 |
+
e5
|
| 1770 |
+
08
|
| 1771 |
+
f8
|
| 1772 |
+
e1
|
| 1773 |
+
01
|
| 1774 |
+
13
|
| 1775 |
+
02
|
| 1776 |
+
f5
|
| 1777 |
+
09
|
| 1778 |
+
10
|
| 1779 |
+
f6
|
| 1780 |
+
05
|
| 1781 |
+
e0
|
| 1782 |
+
0a
|
| 1783 |
+
dc
|
| 1784 |
+
04
|
| 1785 |
+
db
|
| 1786 |
+
f8
|
| 1787 |
+
27
|
| 1788 |
+
03
|
| 1789 |
+
ea
|
| 1790 |
+
01
|
| 1791 |
+
e4
|
| 1792 |
+
2f
|
| 1793 |
+
e5
|
| 1794 |
+
e7
|
| 1795 |
+
ff
|
| 1796 |
+
19
|
| 1797 |
+
f3
|
| 1798 |
+
df
|
| 1799 |
+
0f
|
| 1800 |
+
38
|
| 1801 |
+
ff
|
| 1802 |
+
05
|
| 1803 |
+
07
|
| 1804 |
+
e0
|
| 1805 |
+
06
|
| 1806 |
+
02
|
| 1807 |
+
cb
|
| 1808 |
+
fb
|
| 1809 |
+
ec
|
| 1810 |
+
fd
|
| 1811 |
+
18
|
| 1812 |
+
f5
|
| 1813 |
+
e4
|
| 1814 |
+
36
|
| 1815 |
+
ec
|
| 1816 |
+
f1
|
| 1817 |
+
f9
|
| 1818 |
+
08
|
| 1819 |
+
27
|
| 1820 |
+
dc
|
| 1821 |
+
0b
|
| 1822 |
+
e5
|
| 1823 |
+
3f
|
| 1824 |
+
17
|
| 1825 |
+
fd
|
| 1826 |
+
fb
|
| 1827 |
+
08
|
| 1828 |
+
04
|
| 1829 |
+
f0
|
| 1830 |
+
cc
|
| 1831 |
+
fd
|
| 1832 |
+
01
|
| 1833 |
+
0e
|
| 1834 |
+
2b
|
| 1835 |
+
db
|
| 1836 |
+
23
|
| 1837 |
+
f7
|
| 1838 |
+
e4
|
| 1839 |
+
f0
|
| 1840 |
+
06
|
| 1841 |
+
06
|
| 1842 |
+
02
|
| 1843 |
+
1c
|
| 1844 |
+
04
|
| 1845 |
+
1c
|
| 1846 |
+
26
|
| 1847 |
+
e6
|
| 1848 |
+
03
|
| 1849 |
+
fd
|
| 1850 |
+
f2
|
| 1851 |
+
d2
|
| 1852 |
+
e0
|
| 1853 |
+
10
|
| 1854 |
+
fe
|
| 1855 |
+
ef
|
| 1856 |
+
12
|
| 1857 |
+
f6
|
| 1858 |
+
29
|
| 1859 |
+
33
|
| 1860 |
+
d8
|
| 1861 |
+
d7
|
| 1862 |
+
f6
|
| 1863 |
+
03
|
| 1864 |
+
0a
|
| 1865 |
+
cf
|
| 1866 |
+
13
|
| 1867 |
+
e7
|
| 1868 |
+
ca
|
| 1869 |
+
da
|
| 1870 |
+
18
|
| 1871 |
+
ef
|
| 1872 |
+
00
|
| 1873 |
+
24
|
| 1874 |
+
0b
|
| 1875 |
+
f6
|
| 1876 |
+
20
|
| 1877 |
+
e4
|
| 1878 |
+
fa
|
| 1879 |
+
f1
|
| 1880 |
+
3b
|
| 1881 |
+
1e
|
| 1882 |
+
d4
|
| 1883 |
+
d7
|
| 1884 |
+
ec
|
| 1885 |
+
d7
|
| 1886 |
+
28
|
| 1887 |
+
0f
|
| 1888 |
+
e4
|
| 1889 |
+
f5
|
| 1890 |
+
18
|
| 1891 |
+
e4
|
| 1892 |
+
19
|
| 1893 |
+
fd
|
| 1894 |
+
df
|
| 1895 |
+
03
|
| 1896 |
+
1a
|
| 1897 |
+
1a
|
| 1898 |
+
0c
|
| 1899 |
+
13
|
| 1900 |
+
09
|
| 1901 |
+
e3
|
| 1902 |
+
25
|
| 1903 |
+
25
|
| 1904 |
+
e8
|
| 1905 |
+
17
|
| 1906 |
+
d5
|
| 1907 |
+
f9
|
| 1908 |
+
fe
|
| 1909 |
+
f9
|
| 1910 |
+
17
|
| 1911 |
+
34
|
| 1912 |
+
d4
|
| 1913 |
+
0c
|
| 1914 |
+
e0
|
| 1915 |
+
0a
|
| 1916 |
+
2a
|
| 1917 |
+
03
|
| 1918 |
+
da
|
| 1919 |
+
e0
|
| 1920 |
+
e5
|
| 1921 |
+
12
|
| 1922 |
+
08
|
| 1923 |
+
67
|
| 1924 |
+
d1
|
| 1925 |
+
24
|
| 1926 |
+
00
|
| 1927 |
+
ef
|
| 1928 |
+
13
|
| 1929 |
+
0e
|
| 1930 |
+
cf
|
| 1931 |
+
c8
|
| 1932 |
+
29
|
| 1933 |
+
03
|
| 1934 |
+
0f
|
| 1935 |
+
f5
|
| 1936 |
+
1f
|
| 1937 |
+
1f
|
| 1938 |
+
f3
|
| 1939 |
+
06
|
| 1940 |
+
d9
|
| 1941 |
+
00
|
| 1942 |
+
de
|
| 1943 |
+
fc
|
| 1944 |
+
05
|
| 1945 |
+
1d
|
| 1946 |
+
e1
|
| 1947 |
+
f4
|
| 1948 |
+
f0
|
| 1949 |
+
01
|
| 1950 |
+
fc
|
| 1951 |
+
23
|
| 1952 |
+
2a
|
| 1953 |
+
0c
|
| 1954 |
+
cf
|
| 1955 |
+
d8
|
| 1956 |
+
e0
|
| 1957 |
+
21
|
| 1958 |
+
fb
|
| 1959 |
+
19
|
| 1960 |
+
ed
|
| 1961 |
+
f3
|
| 1962 |
+
13
|
| 1963 |
+
c2
|
| 1964 |
+
06
|
| 1965 |
+
0b
|
| 1966 |
+
f6
|
| 1967 |
+
24
|
| 1968 |
+
fb
|
| 1969 |
+
f7
|
| 1970 |
+
21
|
| 1971 |
+
f0
|
| 1972 |
+
d0
|
| 1973 |
+
22
|
| 1974 |
+
21
|
| 1975 |
+
b8
|
| 1976 |
+
27
|
| 1977 |
+
0a
|
| 1978 |
+
ca
|
| 1979 |
+
d8
|
| 1980 |
+
0e
|
| 1981 |
+
c9
|
| 1982 |
+
06
|
| 1983 |
+
ef
|
| 1984 |
+
e0
|
| 1985 |
+
3f
|
| 1986 |
+
e2
|
| 1987 |
+
21
|
| 1988 |
+
13
|
| 1989 |
+
28
|
| 1990 |
+
13
|
| 1991 |
+
dd
|
| 1992 |
+
36
|
| 1993 |
+
4d
|
| 1994 |
+
ee
|
| 1995 |
+
20
|
| 1996 |
+
28
|
| 1997 |
+
c1
|
| 1998 |
+
da
|
| 1999 |
+
fa
|
| 2000 |
+
0a
|
| 2001 |
+
fd
|
| 2002 |
+
d6
|
| 2003 |
+
d7
|
| 2004 |
+
df
|
| 2005 |
+
f0
|
| 2006 |
+
de
|
| 2007 |
+
f8
|
| 2008 |
+
ea
|
| 2009 |
+
fc
|
| 2010 |
+
16
|
| 2011 |
+
f1
|
| 2012 |
+
f7
|
| 2013 |
+
fb
|
| 2014 |
+
fc
|
| 2015 |
+
ee
|
| 2016 |
+
08
|
| 2017 |
+
aa
|
| 2018 |
+
01
|
| 2019 |
+
1d
|
| 2020 |
+
f7
|
| 2021 |
+
29
|
| 2022 |
+
e1
|
| 2023 |
+
21
|
| 2024 |
+
2b
|
| 2025 |
+
f2
|
| 2026 |
+
11
|
| 2027 |
+
e0
|
| 2028 |
+
1e
|
| 2029 |
+
f8
|
| 2030 |
+
f6
|
| 2031 |
+
f0
|
| 2032 |
+
06
|
| 2033 |
+
05
|
| 2034 |
+
18
|
| 2035 |
+
12
|
| 2036 |
+
18
|
| 2037 |
+
04
|
| 2038 |
+
e6
|
| 2039 |
+
f5
|
| 2040 |
+
13
|
| 2041 |
+
25
|
| 2042 |
+
ce
|
| 2043 |
+
35
|
| 2044 |
+
c1
|
| 2045 |
+
01
|
| 2046 |
+
d6
|
| 2047 |
+
f0
|
| 2048 |
+
e0
|
| 2049 |
+
07
|
| 2050 |
+
0f
|
| 2051 |
+
18
|
| 2052 |
+
f2
|
| 2053 |
+
fd
|
| 2054 |
+
2c
|
| 2055 |
+
00
|
| 2056 |
+
fb
|
| 2057 |
+
9d
|
| 2058 |
+
2f
|
| 2059 |
+
3b
|
| 2060 |
+
fe
|
| 2061 |
+
fa
|
| 2062 |
+
04
|
| 2063 |
+
0a
|
| 2064 |
+
fb
|
| 2065 |
+
01
|
| 2066 |
+
1e
|
| 2067 |
+
ee
|
| 2068 |
+
09
|
| 2069 |
+
0e
|
| 2070 |
+
09
|
| 2071 |
+
fa
|
| 2072 |
+
f3
|
| 2073 |
+
df
|
| 2074 |
+
0e
|
| 2075 |
+
b5
|
| 2076 |
+
f1
|
| 2077 |
+
52
|
| 2078 |
+
dc
|
| 2079 |
+
ff
|
| 2080 |
+
28
|
| 2081 |
+
1f
|
| 2082 |
+
fd
|
| 2083 |
+
35
|
| 2084 |
+
fc
|
| 2085 |
+
21
|
| 2086 |
+
f4
|
| 2087 |
+
19
|
| 2088 |
+
c6
|
| 2089 |
+
f1
|
| 2090 |
+
0a
|
| 2091 |
+
ef
|
| 2092 |
+
09
|
| 2093 |
+
22
|
| 2094 |
+
f5
|
| 2095 |
+
f9
|
| 2096 |
+
20
|
| 2097 |
+
04
|
| 2098 |
+
e5
|
| 2099 |
+
0c
|
| 2100 |
+
3a
|
| 2101 |
+
05
|
| 2102 |
+
0c
|
| 2103 |
+
ff
|
| 2104 |
+
14
|
| 2105 |
+
1a
|
| 2106 |
+
15
|
| 2107 |
+
1e
|
| 2108 |
+
e5
|
| 2109 |
+
fd
|
| 2110 |
+
5c
|
| 2111 |
+
f9
|
| 2112 |
+
c6
|
| 2113 |
+
e5
|
| 2114 |
+
dc
|
| 2115 |
+
e8
|
| 2116 |
+
00
|
| 2117 |
+
bb
|
| 2118 |
+
0a
|
| 2119 |
+
e8
|
| 2120 |
+
e0
|
| 2121 |
+
24
|
| 2122 |
+
f1
|
| 2123 |
+
04
|
| 2124 |
+
ff
|
| 2125 |
+
48
|
| 2126 |
+
e7
|
| 2127 |
+
f7
|
| 2128 |
+
f6
|
| 2129 |
+
0c
|
| 2130 |
+
0e
|
| 2131 |
+
ec
|
| 2132 |
+
e1
|
| 2133 |
+
19
|
| 2134 |
+
17
|
| 2135 |
+
fe
|
| 2136 |
+
02
|
| 2137 |
+
f9
|
| 2138 |
+
f0
|
| 2139 |
+
0a
|
| 2140 |
+
f1
|
| 2141 |
+
2a
|
| 2142 |
+
0b
|
| 2143 |
+
d3
|
| 2144 |
+
00
|
| 2145 |
+
f0
|
| 2146 |
+
fd
|
| 2147 |
+
05
|
| 2148 |
+
1c
|
| 2149 |
+
df
|
| 2150 |
+
fe
|
| 2151 |
+
62
|
| 2152 |
+
f6
|
| 2153 |
+
1a
|
| 2154 |
+
2a
|
| 2155 |
+
fa
|
| 2156 |
+
f5
|
| 2157 |
+
10
|
| 2158 |
+
de
|
| 2159 |
+
02
|
| 2160 |
+
c3
|
| 2161 |
+
05
|
| 2162 |
+
16
|
| 2163 |
+
02
|
| 2164 |
+
06
|
| 2165 |
+
45
|
| 2166 |
+
2e
|
| 2167 |
+
03
|
| 2168 |
+
fe
|
| 2169 |
+
e3
|
| 2170 |
+
f3
|
| 2171 |
+
fe
|
| 2172 |
+
03
|
| 2173 |
+
0e
|
| 2174 |
+
f5
|
| 2175 |
+
0b
|
| 2176 |
+
01
|
| 2177 |
+
04
|
| 2178 |
+
08
|
| 2179 |
+
0c
|
| 2180 |
+
11
|
| 2181 |
+
ff
|
| 2182 |
+
02
|
| 2183 |
+
f2
|
| 2184 |
+
11
|
| 2185 |
+
ff
|
| 2186 |
+
dc
|
| 2187 |
+
fc
|
| 2188 |
+
fc
|
| 2189 |
+
d6
|
| 2190 |
+
02
|
| 2191 |
+
f7
|
| 2192 |
+
09
|
| 2193 |
+
0a
|
| 2194 |
+
e2
|
| 2195 |
+
ed
|
| 2196 |
+
13
|
| 2197 |
+
07
|
| 2198 |
+
18
|
| 2199 |
+
24
|
| 2200 |
+
f6
|
| 2201 |
+
eb
|
| 2202 |
+
fb
|
| 2203 |
+
1e
|
| 2204 |
+
1b
|
| 2205 |
+
ea
|
| 2206 |
+
fd
|
| 2207 |
+
c3
|
| 2208 |
+
f7
|
| 2209 |
+
de
|
| 2210 |
+
fe
|
| 2211 |
+
00
|
| 2212 |
+
fb
|
| 2213 |
+
3d
|
| 2214 |
+
01
|
| 2215 |
+
d5
|
| 2216 |
+
e7
|
| 2217 |
+
e9
|
| 2218 |
+
fc
|
| 2219 |
+
c9
|
| 2220 |
+
05
|
| 2221 |
+
eb
|
| 2222 |
+
f2
|
| 2223 |
+
26
|
| 2224 |
+
d3
|
| 2225 |
+
2f
|
| 2226 |
+
2b
|
| 2227 |
+
21
|
| 2228 |
+
fd
|
| 2229 |
+
0f
|
| 2230 |
+
fe
|
| 2231 |
+
15
|
| 2232 |
+
06
|
| 2233 |
+
1a
|
| 2234 |
+
f3
|
| 2235 |
+
e1
|
| 2236 |
+
db
|
| 2237 |
+
06
|
| 2238 |
+
05
|
| 2239 |
+
1c
|
| 2240 |
+
47
|
| 2241 |
+
22
|
| 2242 |
+
fd
|
| 2243 |
+
16
|
| 2244 |
+
ea
|
| 2245 |
+
05
|
| 2246 |
+
2d
|
| 2247 |
+
07
|
| 2248 |
+
2a
|
| 2249 |
+
d1
|
| 2250 |
+
22
|
| 2251 |
+
0b
|
| 2252 |
+
0a
|
| 2253 |
+
e7
|
| 2254 |
+
00
|
| 2255 |
+
f8
|
| 2256 |
+
1f
|
| 2257 |
+
37
|
| 2258 |
+
d6
|
| 2259 |
+
1c
|
| 2260 |
+
08
|
| 2261 |
+
08
|
| 2262 |
+
3f
|
| 2263 |
+
94
|
| 2264 |
+
f8
|
| 2265 |
+
1a
|
| 2266 |
+
0c
|
| 2267 |
+
fa
|
| 2268 |
+
d1
|
| 2269 |
+
17
|
| 2270 |
+
0b
|
| 2271 |
+
de
|
| 2272 |
+
07
|
| 2273 |
+
0d
|
| 2274 |
+
0e
|
| 2275 |
+
19
|
| 2276 |
+
10
|
| 2277 |
+
ec
|
| 2278 |
+
f4
|
| 2279 |
+
14
|
| 2280 |
+
d9
|
| 2281 |
+
04
|
| 2282 |
+
f7
|
| 2283 |
+
de
|
| 2284 |
+
13
|
| 2285 |
+
fb
|
| 2286 |
+
eb
|
| 2287 |
+
03
|
| 2288 |
+
f8
|
| 2289 |
+
02
|
| 2290 |
+
28
|
| 2291 |
+
ff
|
| 2292 |
+
06
|
| 2293 |
+
22
|
| 2294 |
+
f6
|
| 2295 |
+
cc
|
| 2296 |
+
f0
|
| 2297 |
+
f0
|
| 2298 |
+
06
|
| 2299 |
+
b8
|
| 2300 |
+
0b
|
| 2301 |
+
e5
|
| 2302 |
+
0e
|
| 2303 |
+
0b
|
| 2304 |
+
31
|
| 2305 |
+
26
|
| 2306 |
+
11
|
| 2307 |
+
d5
|
| 2308 |
+
30
|
| 2309 |
+
17
|
| 2310 |
+
d0
|
| 2311 |
+
23
|
| 2312 |
+
f9
|
| 2313 |
+
1e
|
| 2314 |
+
06
|
| 2315 |
+
df
|
| 2316 |
+
03
|
| 2317 |
+
ed
|
| 2318 |
+
f9
|
| 2319 |
+
fa
|
| 2320 |
+
ef
|
| 2321 |
+
ef
|
| 2322 |
+
00
|
| 2323 |
+
ec
|
| 2324 |
+
e1
|
| 2325 |
+
0f
|
| 2326 |
+
0e
|
| 2327 |
+
05
|
| 2328 |
+
c4
|
| 2329 |
+
f2
|
| 2330 |
+
ed
|
| 2331 |
+
34
|
| 2332 |
+
30
|
| 2333 |
+
c5
|
| 2334 |
+
18
|
| 2335 |
+
e3
|
| 2336 |
+
01
|
| 2337 |
+
cd
|
| 2338 |
+
df
|
| 2339 |
+
1e
|
| 2340 |
+
11
|
| 2341 |
+
f6
|
| 2342 |
+
ff
|
| 2343 |
+
08
|
| 2344 |
+
d4
|
| 2345 |
+
18
|
| 2346 |
+
df
|
| 2347 |
+
16
|
| 2348 |
+
f7
|
| 2349 |
+
17
|
| 2350 |
+
26
|
| 2351 |
+
23
|
| 2352 |
+
d4
|
| 2353 |
+
de
|
| 2354 |
+
f0
|
| 2355 |
+
07
|
| 2356 |
+
d4
|
| 2357 |
+
ee
|
| 2358 |
+
0a
|
| 2359 |
+
25
|
| 2360 |
+
1c
|
| 2361 |
+
12
|
| 2362 |
+
ed
|
| 2363 |
+
20
|
| 2364 |
+
f9
|
| 2365 |
+
29
|
| 2366 |
+
21
|
| 2367 |
+
01
|
| 2368 |
+
cc
|
| 2369 |
+
f5
|
| 2370 |
+
09
|
| 2371 |
+
f5
|
| 2372 |
+
18
|
| 2373 |
+
f6
|
| 2374 |
+
0e
|
| 2375 |
+
cd
|
| 2376 |
+
ce
|
| 2377 |
+
e8
|
| 2378 |
+
f1
|
| 2379 |
+
07
|
| 2380 |
+
dd
|
| 2381 |
+
e1
|
| 2382 |
+
22
|
| 2383 |
+
e3
|
| 2384 |
+
0d
|
| 2385 |
+
00
|
| 2386 |
+
0b
|
| 2387 |
+
24
|
| 2388 |
+
ba
|
| 2389 |
+
ce
|
| 2390 |
+
f3
|
| 2391 |
+
11
|
| 2392 |
+
f6
|
| 2393 |
+
fa
|
| 2394 |
+
fe
|
| 2395 |
+
0b
|
| 2396 |
+
dc
|
| 2397 |
+
e1
|
| 2398 |
+
bb
|
| 2399 |
+
08
|
| 2400 |
+
0e
|
| 2401 |
+
1a
|
| 2402 |
+
0d
|
| 2403 |
+
06
|
| 2404 |
+
18
|
| 2405 |
+
dc
|
| 2406 |
+
e6
|
| 2407 |
+
2c
|
| 2408 |
+
d4
|
| 2409 |
+
0a
|
| 2410 |
+
c7
|
| 2411 |
+
f2
|
| 2412 |
+
18
|
| 2413 |
+
00
|
| 2414 |
+
16
|
| 2415 |
+
1e
|
| 2416 |
+
d2
|
| 2417 |
+
10
|
| 2418 |
+
d9
|
| 2419 |
+
13
|
| 2420 |
+
e5
|
| 2421 |
+
18
|
| 2422 |
+
f2
|
| 2423 |
+
f4
|
| 2424 |
+
35
|
| 2425 |
+
ff
|
| 2426 |
+
fe
|
| 2427 |
+
f3
|
| 2428 |
+
02
|
| 2429 |
+
da
|
| 2430 |
+
f1
|
| 2431 |
+
1c
|
| 2432 |
+
0c
|
| 2433 |
+
ff
|
| 2434 |
+
f2
|
| 2435 |
+
0e
|
| 2436 |
+
e2
|
| 2437 |
+
20
|
| 2438 |
+
0e
|
| 2439 |
+
fb
|
| 2440 |
+
f7
|
| 2441 |
+
d1
|
| 2442 |
+
24
|
| 2443 |
+
24
|
| 2444 |
+
cf
|
| 2445 |
+
dc
|
| 2446 |
+
0b
|
| 2447 |
+
ff
|
| 2448 |
+
eb
|
| 2449 |
+
e9
|
| 2450 |
+
02
|
| 2451 |
+
db
|
| 2452 |
+
dd
|
| 2453 |
+
09
|
| 2454 |
+
0b
|
| 2455 |
+
20
|
| 2456 |
+
15
|
| 2457 |
+
1f
|
| 2458 |
+
e7
|
| 2459 |
+
26
|
| 2460 |
+
fe
|
| 2461 |
+
c2
|
| 2462 |
+
04
|
| 2463 |
+
0d
|
| 2464 |
+
10
|
| 2465 |
+
11
|
| 2466 |
+
e4
|
| 2467 |
+
f4
|
| 2468 |
+
9e
|
| 2469 |
+
01
|
| 2470 |
+
fb
|
| 2471 |
+
e0
|
| 2472 |
+
27
|
| 2473 |
+
14
|
| 2474 |
+
0e
|
| 2475 |
+
fb
|
| 2476 |
+
fa
|
| 2477 |
+
0b
|
| 2478 |
+
02
|
| 2479 |
+
ee
|
| 2480 |
+
f1
|
| 2481 |
+
fc
|
| 2482 |
+
07
|
| 2483 |
+
23
|
| 2484 |
+
00
|
| 2485 |
+
25
|
| 2486 |
+
00
|
| 2487 |
+
f4
|
| 2488 |
+
fc
|
| 2489 |
+
4b
|
| 2490 |
+
1a
|
| 2491 |
+
d5
|
| 2492 |
+
fe
|
| 2493 |
+
fe
|
| 2494 |
+
19
|
| 2495 |
+
c6
|
| 2496 |
+
d7
|
| 2497 |
+
16
|
| 2498 |
+
07
|
| 2499 |
+
1b
|
| 2500 |
+
f6
|
| 2501 |
+
de
|
| 2502 |
+
f2
|
| 2503 |
+
05
|
| 2504 |
+
10
|
| 2505 |
+
ee
|
| 2506 |
+
05
|
| 2507 |
+
02
|
| 2508 |
+
26
|
| 2509 |
+
ef
|
| 2510 |
+
54
|
| 2511 |
+
f7
|
| 2512 |
+
27
|
| 2513 |
+
fa
|
| 2514 |
+
d5
|
| 2515 |
+
1b
|
| 2516 |
+
ea
|
| 2517 |
+
2d
|
| 2518 |
+
01
|
| 2519 |
+
34
|
| 2520 |
+
1d
|
| 2521 |
+
ee
|
| 2522 |
+
fb
|
| 2523 |
+
ec
|
| 2524 |
+
10
|
| 2525 |
+
d8
|
| 2526 |
+
f8
|
| 2527 |
+
d9
|
| 2528 |
+
04
|
| 2529 |
+
f7
|
| 2530 |
+
28
|
| 2531 |
+
f5
|
| 2532 |
+
1d
|
| 2533 |
+
24
|
| 2534 |
+
2f
|
| 2535 |
+
fb
|
| 2536 |
+
e7
|
| 2537 |
+
d7
|
| 2538 |
+
0c
|
| 2539 |
+
0a
|
| 2540 |
+
f6
|
| 2541 |
+
e1
|
| 2542 |
+
fe
|
| 2543 |
+
1d
|
| 2544 |
+
0a
|
| 2545 |
+
11
|
| 2546 |
+
09
|
| 2547 |
+
e1
|
| 2548 |
+
ec
|
| 2549 |
+
f3
|
| 2550 |
+
1b
|
| 2551 |
+
ec
|
| 2552 |
+
04
|
| 2553 |
+
af
|
| 2554 |
+
10
|
| 2555 |
+
13
|
| 2556 |
+
0c
|
| 2557 |
+
e1
|
| 2558 |
+
f3
|
| 2559 |
+
0d
|
| 2560 |
+
28
|
| 2561 |
+
f1
|
| 2562 |
+
e8
|
| 2563 |
+
16
|
| 2564 |
+
35
|
| 2565 |
+
e5
|
| 2566 |
+
f6
|
| 2567 |
+
ec
|
| 2568 |
+
01
|
| 2569 |
+
02
|
| 2570 |
+
0c
|
| 2571 |
+
fa
|
| 2572 |
+
fe
|
| 2573 |
+
0e
|
| 2574 |
+
f2
|
| 2575 |
+
c7
|
| 2576 |
+
f1
|
| 2577 |
+
fc
|
| 2578 |
+
e4
|
| 2579 |
+
ff
|
| 2580 |
+
09
|
| 2581 |
+
c0
|
| 2582 |
+
17
|
| 2583 |
+
e9
|
| 2584 |
+
cb
|
| 2585 |
+
17
|
| 2586 |
+
1d
|
| 2587 |
+
3a
|
| 2588 |
+
e1
|
| 2589 |
+
e8
|
| 2590 |
+
ea
|
| 2591 |
+
19
|
| 2592 |
+
0d
|
| 2593 |
+
10
|
| 2594 |
+
f0
|
| 2595 |
+
12
|
| 2596 |
+
15
|
| 2597 |
+
08
|
| 2598 |
+
e2
|
| 2599 |
+
fa
|
| 2600 |
+
f4
|
| 2601 |
+
1d
|
| 2602 |
+
1a
|
| 2603 |
+
da
|
| 2604 |
+
06
|
| 2605 |
+
f4
|
| 2606 |
+
d1
|
| 2607 |
+
f7
|
| 2608 |
+
19
|
| 2609 |
+
f4
|
| 2610 |
+
01
|
| 2611 |
+
01
|
| 2612 |
+
1e
|
| 2613 |
+
18
|
| 2614 |
+
0c
|
| 2615 |
+
d9
|
| 2616 |
+
13
|
| 2617 |
+
e0
|
| 2618 |
+
03
|
| 2619 |
+
e7
|
| 2620 |
+
cd
|
| 2621 |
+
19
|
| 2622 |
+
e0
|
| 2623 |
+
fe
|
| 2624 |
+
fa
|
| 2625 |
+
e2
|
| 2626 |
+
2c
|
| 2627 |
+
6c
|
| 2628 |
+
da
|
| 2629 |
+
04
|
| 2630 |
+
fa
|
| 2631 |
+
e7
|
| 2632 |
+
00
|
| 2633 |
+
ce
|
| 2634 |
+
fc
|
| 2635 |
+
0c
|
| 2636 |
+
f2
|
| 2637 |
+
d4
|
| 2638 |
+
08
|
| 2639 |
+
f4
|
| 2640 |
+
fe
|
| 2641 |
+
03
|
| 2642 |
+
20
|
| 2643 |
+
fa
|
| 2644 |
+
13
|
| 2645 |
+
fb
|
| 2646 |
+
0f
|
| 2647 |
+
1c
|
| 2648 |
+
21
|
| 2649 |
+
3d
|
| 2650 |
+
f1
|
| 2651 |
+
f1
|
| 2652 |
+
e4
|
| 2653 |
+
e9
|
| 2654 |
+
2e
|
| 2655 |
+
e9
|
| 2656 |
+
eb
|
| 2657 |
+
e4
|
| 2658 |
+
e6
|
| 2659 |
+
d4
|
| 2660 |
+
f2
|
| 2661 |
+
04
|
| 2662 |
+
0e
|
| 2663 |
+
08
|
| 2664 |
+
f4
|
| 2665 |
+
04
|
| 2666 |
+
1b
|
| 2667 |
+
35
|
| 2668 |
+
1c
|
| 2669 |
+
d1
|
| 2670 |
+
1b
|
| 2671 |
+
1b
|
| 2672 |
+
0e
|
| 2673 |
+
13
|
| 2674 |
+
d3
|
| 2675 |
+
f6
|
| 2676 |
+
20
|
| 2677 |
+
05
|
| 2678 |
+
12
|
| 2679 |
+
2e
|
| 2680 |
+
da
|
| 2681 |
+
2c
|
| 2682 |
+
c3
|
| 2683 |
+
0b
|
| 2684 |
+
0c
|
| 2685 |
+
03
|
| 2686 |
+
dd
|
| 2687 |
+
d6
|
| 2688 |
+
dc
|
| 2689 |
+
06
|
| 2690 |
+
fd
|
| 2691 |
+
49
|
| 2692 |
+
f2
|
| 2693 |
+
21
|
| 2694 |
+
01
|
| 2695 |
+
d0
|
| 2696 |
+
2a
|
| 2697 |
+
11
|
| 2698 |
+
c8
|
| 2699 |
+
d9
|
| 2700 |
+
16
|
| 2701 |
+
f5
|
| 2702 |
+
10
|
| 2703 |
+
f7
|
| 2704 |
+
36
|
| 2705 |
+
07
|
| 2706 |
+
10
|
| 2707 |
+
00
|
| 2708 |
+
fa
|
| 2709 |
+
1e
|
| 2710 |
+
e1
|
| 2711 |
+
d8
|
| 2712 |
+
1b
|
| 2713 |
+
1b
|
| 2714 |
+
f6
|
| 2715 |
+
f3
|
| 2716 |
+
fb
|
| 2717 |
+
21
|
| 2718 |
+
d9
|
| 2719 |
+
2d
|
| 2720 |
+
03
|
| 2721 |
+
24
|
| 2722 |
+
e1
|
| 2723 |
+
eb
|
| 2724 |
+
d8
|
| 2725 |
+
16
|
| 2726 |
+
03
|
| 2727 |
+
14
|
| 2728 |
+
f7
|
| 2729 |
+
0c
|
| 2730 |
+
1c
|
| 2731 |
+
bc
|
| 2732 |
+
e6
|
| 2733 |
+
00
|
| 2734 |
+
eb
|
| 2735 |
+
28
|
| 2736 |
+
09
|
| 2737 |
+
e5
|
| 2738 |
+
29
|
| 2739 |
+
02
|
| 2740 |
+
ce
|
| 2741 |
+
02
|
| 2742 |
+
27
|
| 2743 |
+
cf
|
| 2744 |
+
1f
|
| 2745 |
+
11
|
| 2746 |
+
dc
|
| 2747 |
+
d3
|
| 2748 |
+
12
|
| 2749 |
+
d8
|
| 2750 |
+
0c
|
| 2751 |
+
ea
|
| 2752 |
+
cf
|
| 2753 |
+
2d
|
| 2754 |
+
d9
|
| 2755 |
+
03
|
| 2756 |
+
1f
|
| 2757 |
+
1e
|
| 2758 |
+
f7
|
| 2759 |
+
c1
|
| 2760 |
+
1b
|
| 2761 |
+
2c
|
| 2762 |
+
08
|
| 2763 |
+
20
|
| 2764 |
+
22
|
| 2765 |
+
dc
|
| 2766 |
+
bd
|
| 2767 |
+
19
|
| 2768 |
+
e5
|
| 2769 |
+
ff
|
| 2770 |
+
ec
|
| 2771 |
+
cd
|
| 2772 |
+
cf
|
| 2773 |
+
f4
|
| 2774 |
+
f7
|
| 2775 |
+
fd
|
| 2776 |
+
ed
|
| 2777 |
+
fc
|
| 2778 |
+
13
|
| 2779 |
+
04
|
| 2780 |
+
f9
|
| 2781 |
+
f6
|
| 2782 |
+
f1
|
| 2783 |
+
1e
|
| 2784 |
+
0f
|
| 2785 |
+
e2
|
| 2786 |
+
01
|
| 2787 |
+
fe
|
| 2788 |
+
01
|
| 2789 |
+
1d
|
| 2790 |
+
f2
|
| 2791 |
+
0d
|
| 2792 |
+
1d
|
| 2793 |
+
f5
|
| 2794 |
+
0b
|
| 2795 |
+
f8
|
| 2796 |
+
1a
|
| 2797 |
+
01
|
| 2798 |
+
e9
|
| 2799 |
+
19
|
| 2800 |
+
3c
|
| 2801 |
+
2d
|
| 2802 |
+
0a
|
| 2803 |
+
f1
|
| 2804 |
+
17
|
| 2805 |
+
f7
|
| 2806 |
+
f9
|
| 2807 |
+
f4
|
| 2808 |
+
1c
|
| 2809 |
+
0d
|
| 2810 |
+
cf
|
| 2811 |
+
21
|
| 2812 |
+
c7
|
| 2813 |
+
14
|
| 2814 |
+
d1
|
| 2815 |
+
e5
|
| 2816 |
+
fa
|
| 2817 |
+
f8
|
| 2818 |
+
1e
|
| 2819 |
+
16
|
| 2820 |
+
f4
|
| 2821 |
+
f7
|
| 2822 |
+
15
|
| 2823 |
+
14
|
| 2824 |
+
0f
|
| 2825 |
+
a3
|
| 2826 |
+
2e
|
| 2827 |
+
0a
|
| 2828 |
+
0a
|
| 2829 |
+
0c
|
| 2830 |
+
03
|
| 2831 |
+
dd
|
| 2832 |
+
01
|
| 2833 |
+
03
|
| 2834 |
+
1c
|
| 2835 |
+
d0
|
| 2836 |
+
07
|
| 2837 |
+
07
|
| 2838 |
+
08
|
| 2839 |
+
08
|
| 2840 |
+
02
|
| 2841 |
+
1c
|
| 2842 |
+
0b
|
| 2843 |
+
fd
|
| 2844 |
+
e5
|
| 2845 |
+
1e
|
| 2846 |
+
0b
|
| 2847 |
+
13
|
| 2848 |
+
07
|
| 2849 |
+
eb
|
| 2850 |
+
03
|
| 2851 |
+
34
|
| 2852 |
+
de
|
| 2853 |
+
25
|
| 2854 |
+
ea
|
| 2855 |
+
13
|
| 2856 |
+
e1
|
| 2857 |
+
fb
|
| 2858 |
+
27
|
| 2859 |
+
c5
|
| 2860 |
+
23
|
| 2861 |
+
30
|
| 2862 |
+
05
|
| 2863 |
+
f8
|
| 2864 |
+
28
|
| 2865 |
+
e8
|
| 2866 |
+
ff
|
| 2867 |
+
fa
|
| 2868 |
+
fd
|
| 2869 |
+
2a
|
| 2870 |
+
fd
|
| 2871 |
+
16
|
| 2872 |
+
1a
|
| 2873 |
+
fb
|
| 2874 |
+
f3
|
| 2875 |
+
0d
|
| 2876 |
+
d9
|
| 2877 |
+
f4
|
| 2878 |
+
31
|
| 2879 |
+
25
|
| 2880 |
+
31
|
| 2881 |
+
e5
|
| 2882 |
+
d6
|
| 2883 |
+
d2
|
| 2884 |
+
13
|
| 2885 |
+
cc
|
| 2886 |
+
0e
|
| 2887 |
+
ec
|
| 2888 |
+
fa
|
| 2889 |
+
29
|
| 2890 |
+
f4
|
| 2891 |
+
0a
|
| 2892 |
+
ec
|
| 2893 |
+
2c
|
| 2894 |
+
f5
|
| 2895 |
+
fa
|
| 2896 |
+
fa
|
| 2897 |
+
2e
|
| 2898 |
+
04
|
| 2899 |
+
17
|
| 2900 |
+
ed
|
| 2901 |
+
01
|
| 2902 |
+
1a
|
| 2903 |
+
f4
|
| 2904 |
+
22
|
| 2905 |
+
f8
|
| 2906 |
+
05
|
| 2907 |
+
20
|
| 2908 |
+
ea
|
| 2909 |
+
14
|
| 2910 |
+
09
|
| 2911 |
+
08
|
| 2912 |
+
09
|
| 2913 |
+
dd
|
| 2914 |
+
ee
|
| 2915 |
+
2f
|
| 2916 |
+
19
|
| 2917 |
+
c8
|
| 2918 |
+
fd
|
| 2919 |
+
6e
|
| 2920 |
+
10
|
| 2921 |
+
17
|
| 2922 |
+
15
|
| 2923 |
+
fc
|
| 2924 |
+
ed
|
| 2925 |
+
0d
|
| 2926 |
+
d8
|
| 2927 |
+
fb
|
| 2928 |
+
e3
|
| 2929 |
+
fb
|
| 2930 |
+
1b
|
| 2931 |
+
e3
|
| 2932 |
+
fd
|
| 2933 |
+
33
|
| 2934 |
+
35
|
| 2935 |
+
ff
|
| 2936 |
+
21
|
| 2937 |
+
ef
|
| 2938 |
+
11
|
| 2939 |
+
f6
|
| 2940 |
+
20
|
| 2941 |
+
03
|
| 2942 |
+
00
|
| 2943 |
+
04
|
| 2944 |
+
eb
|
| 2945 |
+
15
|
| 2946 |
+
16
|
| 2947 |
+
f9
|
| 2948 |
+
03
|
| 2949 |
+
03
|
| 2950 |
+
09
|
| 2951 |
+
14
|
| 2952 |
+
22
|
| 2953 |
+
04
|
| 2954 |
+
07
|
| 2955 |
+
0d
|
| 2956 |
+
13
|
| 2957 |
+
ea
|
| 2958 |
+
0b
|
| 2959 |
+
ed
|
| 2960 |
+
19
|
| 2961 |
+
2f
|
| 2962 |
+
f0
|
| 2963 |
+
fa
|
| 2964 |
+
12
|
| 2965 |
+
fe
|
| 2966 |
+
0b
|
| 2967 |
+
13
|
| 2968 |
+
fb
|
| 2969 |
+
05
|
| 2970 |
+
ff
|
| 2971 |
+
2a
|
| 2972 |
+
25
|
| 2973 |
+
ed
|
| 2974 |
+
09
|
| 2975 |
+
d5
|
| 2976 |
+
ea
|
| 2977 |
+
ef
|
| 2978 |
+
20
|
| 2979 |
+
e4
|
| 2980 |
+
04
|
| 2981 |
+
18
|
| 2982 |
+
fc
|
| 2983 |
+
05
|
| 2984 |
+
ea
|
| 2985 |
+
ee
|
| 2986 |
+
07
|
| 2987 |
+
f3
|
| 2988 |
+
1d
|
| 2989 |
+
03
|
| 2990 |
+
f4
|
| 2991 |
+
21
|
| 2992 |
+
0d
|
| 2993 |
+
16
|
| 2994 |
+
24
|
| 2995 |
+
10
|
| 2996 |
+
ee
|
| 2997 |
+
19
|
| 2998 |
+
e4
|
| 2999 |
+
f0
|
| 3000 |
+
01
|
| 3001 |
+
10
|
| 3002 |
+
ea
|
| 3003 |
+
fa
|
| 3004 |
+
f2
|
| 3005 |
+
17
|
| 3006 |
+
07
|
| 3007 |
+
0a
|
| 3008 |
+
4e
|
| 3009 |
+
1c
|
| 3010 |
+
ec
|
| 3011 |
+
16
|
| 3012 |
+
03
|
| 3013 |
+
01
|
| 3014 |
+
26
|
| 3015 |
+
eb
|
| 3016 |
+
19
|
| 3017 |
+
d6
|
| 3018 |
+
ff
|
| 3019 |
+
10
|
| 3020 |
+
1c
|
| 3021 |
+
91
|
| 3022 |
+
e4
|
| 3023 |
+
04
|
| 3024 |
+
1e
|
| 3025 |
+
15
|
| 3026 |
+
e9
|
| 3027 |
+
36
|
| 3028 |
+
f5
|
| 3029 |
+
10
|
| 3030 |
+
0f
|
| 3031 |
+
86
|
| 3032 |
+
c6
|
| 3033 |
+
10
|
| 3034 |
+
f7
|
| 3035 |
+
14
|
| 3036 |
+
f2
|
| 3037 |
+
e2
|
| 3038 |
+
21
|
| 3039 |
+
19
|
| 3040 |
+
19
|
| 3041 |
+
fb
|
| 3042 |
+
fb
|
| 3043 |
+
39
|
| 3044 |
+
e1
|
| 3045 |
+
ec
|
| 3046 |
+
c5
|
| 3047 |
+
09
|
| 3048 |
+
e7
|
| 3049 |
+
d8
|
| 3050 |
+
f9
|
| 3051 |
+
e9
|
| 3052 |
+
3b
|
| 3053 |
+
e9
|
| 3054 |
+
e9
|
| 3055 |
+
03
|
| 3056 |
+
01
|
| 3057 |
+
13
|
| 3058 |
+
0d
|
| 3059 |
+
fe
|
| 3060 |
+
04
|
| 3061 |
+
23
|
| 3062 |
+
ec
|
| 3063 |
+
fd
|
| 3064 |
+
f8
|
| 3065 |
+
ff
|
| 3066 |
+
f7
|
| 3067 |
+
02
|
| 3068 |
+
22
|
| 3069 |
+
e4
|
| 3070 |
+
22
|
| 3071 |
+
f4
|
| 3072 |
+
0a
|
circuit/rom/test_features.hex
ADDED
|
@@ -0,0 +1,768 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
51
|
| 2 |
+
3e
|
| 3 |
+
26
|
| 4 |
+
a8
|
| 5 |
+
1c
|
| 6 |
+
cc
|
| 7 |
+
fe
|
| 8 |
+
bd
|
| 9 |
+
e0
|
| 10 |
+
45
|
| 11 |
+
f0
|
| 12 |
+
c5
|
| 13 |
+
e1
|
| 14 |
+
e9
|
| 15 |
+
e0
|
| 16 |
+
20
|
| 17 |
+
45
|
| 18 |
+
f9
|
| 19 |
+
eb
|
| 20 |
+
12
|
| 21 |
+
e0
|
| 22 |
+
2d
|
| 23 |
+
22
|
| 24 |
+
47
|
| 25 |
+
36
|
| 26 |
+
36
|
| 27 |
+
1a
|
| 28 |
+
38
|
| 29 |
+
f6
|
| 30 |
+
02
|
| 31 |
+
f5
|
| 32 |
+
24
|
| 33 |
+
c6
|
| 34 |
+
db
|
| 35 |
+
f7
|
| 36 |
+
48
|
| 37 |
+
0d
|
| 38 |
+
ee
|
| 39 |
+
0d
|
| 40 |
+
df
|
| 41 |
+
bf
|
| 42 |
+
2a
|
| 43 |
+
db
|
| 44 |
+
e7
|
| 45 |
+
cb
|
| 46 |
+
59
|
| 47 |
+
cc
|
| 48 |
+
ec
|
| 49 |
+
da
|
| 50 |
+
e4
|
| 51 |
+
03
|
| 52 |
+
16
|
| 53 |
+
ec
|
| 54 |
+
32
|
| 55 |
+
de
|
| 56 |
+
e1
|
| 57 |
+
c5
|
| 58 |
+
02
|
| 59 |
+
fd
|
| 60 |
+
1c
|
| 61 |
+
fc
|
| 62 |
+
4d
|
| 63 |
+
ce
|
| 64 |
+
3a
|
| 65 |
+
3d
|
| 66 |
+
24
|
| 67 |
+
5d
|
| 68 |
+
16
|
| 69 |
+
0f
|
| 70 |
+
f8
|
| 71 |
+
d4
|
| 72 |
+
36
|
| 73 |
+
f9
|
| 74 |
+
16
|
| 75 |
+
02
|
| 76 |
+
12
|
| 77 |
+
18
|
| 78 |
+
e5
|
| 79 |
+
a3
|
| 80 |
+
e0
|
| 81 |
+
00
|
| 82 |
+
f2
|
| 83 |
+
c8
|
| 84 |
+
e7
|
| 85 |
+
17
|
| 86 |
+
16
|
| 87 |
+
30
|
| 88 |
+
02
|
| 89 |
+
1f
|
| 90 |
+
ec
|
| 91 |
+
d4
|
| 92 |
+
19
|
| 93 |
+
b8
|
| 94 |
+
dd
|
| 95 |
+
38
|
| 96 |
+
14
|
| 97 |
+
97
|
| 98 |
+
14
|
| 99 |
+
21
|
| 100 |
+
01
|
| 101 |
+
1b
|
| 102 |
+
18
|
| 103 |
+
2d
|
| 104 |
+
ed
|
| 105 |
+
f8
|
| 106 |
+
20
|
| 107 |
+
11
|
| 108 |
+
07
|
| 109 |
+
0b
|
| 110 |
+
35
|
| 111 |
+
00
|
| 112 |
+
f3
|
| 113 |
+
c3
|
| 114 |
+
fc
|
| 115 |
+
e7
|
| 116 |
+
14
|
| 117 |
+
1e
|
| 118 |
+
04
|
| 119 |
+
f0
|
| 120 |
+
16
|
| 121 |
+
ff
|
| 122 |
+
0a
|
| 123 |
+
06
|
| 124 |
+
20
|
| 125 |
+
2e
|
| 126 |
+
0e
|
| 127 |
+
1e
|
| 128 |
+
11
|
| 129 |
+
51
|
| 130 |
+
2a
|
| 131 |
+
c4
|
| 132 |
+
d1
|
| 133 |
+
fa
|
| 134 |
+
45
|
| 135 |
+
1b
|
| 136 |
+
18
|
| 137 |
+
30
|
| 138 |
+
01
|
| 139 |
+
b4
|
| 140 |
+
27
|
| 141 |
+
f0
|
| 142 |
+
2b
|
| 143 |
+
e3
|
| 144 |
+
1b
|
| 145 |
+
d7
|
| 146 |
+
28
|
| 147 |
+
44
|
| 148 |
+
3d
|
| 149 |
+
0b
|
| 150 |
+
f7
|
| 151 |
+
e1
|
| 152 |
+
04
|
| 153 |
+
0f
|
| 154 |
+
29
|
| 155 |
+
ec
|
| 156 |
+
43
|
| 157 |
+
98
|
| 158 |
+
ee
|
| 159 |
+
ce
|
| 160 |
+
22
|
| 161 |
+
b0
|
| 162 |
+
0a
|
| 163 |
+
01
|
| 164 |
+
f1
|
| 165 |
+
0c
|
| 166 |
+
e1
|
| 167 |
+
07
|
| 168 |
+
d2
|
| 169 |
+
bd
|
| 170 |
+
39
|
| 171 |
+
36
|
| 172 |
+
02
|
| 173 |
+
bf
|
| 174 |
+
20
|
| 175 |
+
21
|
| 176 |
+
55
|
| 177 |
+
02
|
| 178 |
+
05
|
| 179 |
+
de
|
| 180 |
+
f7
|
| 181 |
+
d9
|
| 182 |
+
bd
|
| 183 |
+
d0
|
| 184 |
+
ea
|
| 185 |
+
ea
|
| 186 |
+
c1
|
| 187 |
+
af
|
| 188 |
+
05
|
| 189 |
+
2b
|
| 190 |
+
e9
|
| 191 |
+
1e
|
| 192 |
+
1e
|
| 193 |
+
4a
|
| 194 |
+
d9
|
| 195 |
+
28
|
| 196 |
+
f2
|
| 197 |
+
cf
|
| 198 |
+
0f
|
| 199 |
+
14
|
| 200 |
+
39
|
| 201 |
+
16
|
| 202 |
+
59
|
| 203 |
+
ea
|
| 204 |
+
d9
|
| 205 |
+
08
|
| 206 |
+
2d
|
| 207 |
+
37
|
| 208 |
+
13
|
| 209 |
+
de
|
| 210 |
+
d5
|
| 211 |
+
eb
|
| 212 |
+
e7
|
| 213 |
+
06
|
| 214 |
+
13
|
| 215 |
+
fa
|
| 216 |
+
9f
|
| 217 |
+
ef
|
| 218 |
+
2d
|
| 219 |
+
b5
|
| 220 |
+
3f
|
| 221 |
+
0d
|
| 222 |
+
eb
|
| 223 |
+
2b
|
| 224 |
+
47
|
| 225 |
+
00
|
| 226 |
+
46
|
| 227 |
+
06
|
| 228 |
+
d3
|
| 229 |
+
e8
|
| 230 |
+
04
|
| 231 |
+
11
|
| 232 |
+
54
|
| 233 |
+
fd
|
| 234 |
+
da
|
| 235 |
+
aa
|
| 236 |
+
d3
|
| 237 |
+
01
|
| 238 |
+
03
|
| 239 |
+
08
|
| 240 |
+
11
|
| 241 |
+
d9
|
| 242 |
+
0c
|
| 243 |
+
e9
|
| 244 |
+
13
|
| 245 |
+
db
|
| 246 |
+
ff
|
| 247 |
+
f1
|
| 248 |
+
3d
|
| 249 |
+
35
|
| 250 |
+
e2
|
| 251 |
+
24
|
| 252 |
+
16
|
| 253 |
+
17
|
| 254 |
+
18
|
| 255 |
+
15
|
| 256 |
+
09
|
| 257 |
+
e3
|
| 258 |
+
18
|
| 259 |
+
c1
|
| 260 |
+
bc
|
| 261 |
+
c2
|
| 262 |
+
12
|
| 263 |
+
fb
|
| 264 |
+
21
|
| 265 |
+
bd
|
| 266 |
+
fb
|
| 267 |
+
1e
|
| 268 |
+
02
|
| 269 |
+
37
|
| 270 |
+
0a
|
| 271 |
+
ad
|
| 272 |
+
01
|
| 273 |
+
c6
|
| 274 |
+
1a
|
| 275 |
+
93
|
| 276 |
+
ff
|
| 277 |
+
fb
|
| 278 |
+
e1
|
| 279 |
+
48
|
| 280 |
+
02
|
| 281 |
+
32
|
| 282 |
+
51
|
| 283 |
+
1f
|
| 284 |
+
29
|
| 285 |
+
11
|
| 286 |
+
31
|
| 287 |
+
0b
|
| 288 |
+
fe
|
| 289 |
+
29
|
| 290 |
+
d5
|
| 291 |
+
e9
|
| 292 |
+
ed
|
| 293 |
+
f3
|
| 294 |
+
fb
|
| 295 |
+
e2
|
| 296 |
+
fe
|
| 297 |
+
55
|
| 298 |
+
0b
|
| 299 |
+
27
|
| 300 |
+
1e
|
| 301 |
+
ff
|
| 302 |
+
04
|
| 303 |
+
38
|
| 304 |
+
1e
|
| 305 |
+
11
|
| 306 |
+
e2
|
| 307 |
+
23
|
| 308 |
+
d8
|
| 309 |
+
13
|
| 310 |
+
34
|
| 311 |
+
9f
|
| 312 |
+
ca
|
| 313 |
+
08
|
| 314 |
+
a7
|
| 315 |
+
fa
|
| 316 |
+
d4
|
| 317 |
+
e0
|
| 318 |
+
fe
|
| 319 |
+
33
|
| 320 |
+
d7
|
| 321 |
+
12
|
| 322 |
+
e2
|
| 323 |
+
2c
|
| 324 |
+
c3
|
| 325 |
+
14
|
| 326 |
+
10
|
| 327 |
+
00
|
| 328 |
+
03
|
| 329 |
+
10
|
| 330 |
+
1e
|
| 331 |
+
b8
|
| 332 |
+
dd
|
| 333 |
+
12
|
| 334 |
+
0b
|
| 335 |
+
e7
|
| 336 |
+
03
|
| 337 |
+
25
|
| 338 |
+
08
|
| 339 |
+
21
|
| 340 |
+
fe
|
| 341 |
+
18
|
| 342 |
+
e2
|
| 343 |
+
ec
|
| 344 |
+
02
|
| 345 |
+
1a
|
| 346 |
+
44
|
| 347 |
+
fc
|
| 348 |
+
2e
|
| 349 |
+
28
|
| 350 |
+
e4
|
| 351 |
+
e8
|
| 352 |
+
f2
|
| 353 |
+
df
|
| 354 |
+
10
|
| 355 |
+
04
|
| 356 |
+
cc
|
| 357 |
+
f3
|
| 358 |
+
dd
|
| 359 |
+
e9
|
| 360 |
+
54
|
| 361 |
+
50
|
| 362 |
+
47
|
| 363 |
+
01
|
| 364 |
+
f9
|
| 365 |
+
b6
|
| 366 |
+
e2
|
| 367 |
+
ef
|
| 368 |
+
4f
|
| 369 |
+
f7
|
| 370 |
+
07
|
| 371 |
+
5a
|
| 372 |
+
48
|
| 373 |
+
0f
|
| 374 |
+
1b
|
| 375 |
+
f7
|
| 376 |
+
1d
|
| 377 |
+
fa
|
| 378 |
+
ce
|
| 379 |
+
ca
|
| 380 |
+
13
|
| 381 |
+
e7
|
| 382 |
+
24
|
| 383 |
+
eb
|
| 384 |
+
f1
|
| 385 |
+
1c
|
| 386 |
+
fd
|
| 387 |
+
f7
|
| 388 |
+
07
|
| 389 |
+
3e
|
| 390 |
+
d9
|
| 391 |
+
e7
|
| 392 |
+
fc
|
| 393 |
+
d7
|
| 394 |
+
98
|
| 395 |
+
f2
|
| 396 |
+
23
|
| 397 |
+
29
|
| 398 |
+
f2
|
| 399 |
+
de
|
| 400 |
+
23
|
| 401 |
+
01
|
| 402 |
+
d3
|
| 403 |
+
e0
|
| 404 |
+
ef
|
| 405 |
+
28
|
| 406 |
+
fa
|
| 407 |
+
06
|
| 408 |
+
fe
|
| 409 |
+
28
|
| 410 |
+
be
|
| 411 |
+
29
|
| 412 |
+
30
|
| 413 |
+
fa
|
| 414 |
+
f4
|
| 415 |
+
f8
|
| 416 |
+
21
|
| 417 |
+
1d
|
| 418 |
+
c8
|
| 419 |
+
ea
|
| 420 |
+
19
|
| 421 |
+
ec
|
| 422 |
+
e6
|
| 423 |
+
fe
|
| 424 |
+
bb
|
| 425 |
+
ec
|
| 426 |
+
e1
|
| 427 |
+
0d
|
| 428 |
+
06
|
| 429 |
+
2b
|
| 430 |
+
e6
|
| 431 |
+
ea
|
| 432 |
+
1d
|
| 433 |
+
eb
|
| 434 |
+
30
|
| 435 |
+
ed
|
| 436 |
+
3c
|
| 437 |
+
24
|
| 438 |
+
fe
|
| 439 |
+
1c
|
| 440 |
+
2c
|
| 441 |
+
1d
|
| 442 |
+
c9
|
| 443 |
+
02
|
| 444 |
+
cf
|
| 445 |
+
fc
|
| 446 |
+
32
|
| 447 |
+
20
|
| 448 |
+
e1
|
| 449 |
+
c6
|
| 450 |
+
14
|
| 451 |
+
d6
|
| 452 |
+
01
|
| 453 |
+
ee
|
| 454 |
+
d7
|
| 455 |
+
e5
|
| 456 |
+
23
|
| 457 |
+
43
|
| 458 |
+
fb
|
| 459 |
+
ec
|
| 460 |
+
05
|
| 461 |
+
03
|
| 462 |
+
d9
|
| 463 |
+
cb
|
| 464 |
+
2e
|
| 465 |
+
2e
|
| 466 |
+
e3
|
| 467 |
+
03
|
| 468 |
+
00
|
| 469 |
+
07
|
| 470 |
+
32
|
| 471 |
+
c9
|
| 472 |
+
c5
|
| 473 |
+
d4
|
| 474 |
+
0d
|
| 475 |
+
11
|
| 476 |
+
e2
|
| 477 |
+
77
|
| 478 |
+
52
|
| 479 |
+
56
|
| 480 |
+
d2
|
| 481 |
+
44
|
| 482 |
+
24
|
| 483 |
+
ef
|
| 484 |
+
e6
|
| 485 |
+
eb
|
| 486 |
+
e6
|
| 487 |
+
bb
|
| 488 |
+
d4
|
| 489 |
+
ed
|
| 490 |
+
fd
|
| 491 |
+
e9
|
| 492 |
+
d0
|
| 493 |
+
ed
|
| 494 |
+
ff
|
| 495 |
+
10
|
| 496 |
+
fe
|
| 497 |
+
32
|
| 498 |
+
f2
|
| 499 |
+
1b
|
| 500 |
+
04
|
| 501 |
+
e0
|
| 502 |
+
e5
|
| 503 |
+
ca
|
| 504 |
+
53
|
| 505 |
+
d8
|
| 506 |
+
94
|
| 507 |
+
1e
|
| 508 |
+
22
|
| 509 |
+
1a
|
| 510 |
+
12
|
| 511 |
+
f2
|
| 512 |
+
16
|
| 513 |
+
c7
|
| 514 |
+
08
|
| 515 |
+
e6
|
| 516 |
+
07
|
| 517 |
+
3f
|
| 518 |
+
09
|
| 519 |
+
e2
|
| 520 |
+
d8
|
| 521 |
+
16
|
| 522 |
+
ed
|
| 523 |
+
08
|
| 524 |
+
f0
|
| 525 |
+
b5
|
| 526 |
+
04
|
| 527 |
+
b0
|
| 528 |
+
e5
|
| 529 |
+
38
|
| 530 |
+
ca
|
| 531 |
+
20
|
| 532 |
+
1b
|
| 533 |
+
0f
|
| 534 |
+
91
|
| 535 |
+
c3
|
| 536 |
+
d7
|
| 537 |
+
0b
|
| 538 |
+
f8
|
| 539 |
+
32
|
| 540 |
+
ee
|
| 541 |
+
2a
|
| 542 |
+
1a
|
| 543 |
+
33
|
| 544 |
+
e6
|
| 545 |
+
b7
|
| 546 |
+
fb
|
| 547 |
+
c7
|
| 548 |
+
2f
|
| 549 |
+
e6
|
| 550 |
+
df
|
| 551 |
+
f9
|
| 552 |
+
45
|
| 553 |
+
54
|
| 554 |
+
cb
|
| 555 |
+
2f
|
| 556 |
+
4a
|
| 557 |
+
a9
|
| 558 |
+
ef
|
| 559 |
+
d7
|
| 560 |
+
ff
|
| 561 |
+
4e
|
| 562 |
+
6e
|
| 563 |
+
0f
|
| 564 |
+
10
|
| 565 |
+
08
|
| 566 |
+
f6
|
| 567 |
+
0d
|
| 568 |
+
ed
|
| 569 |
+
14
|
| 570 |
+
1b
|
| 571 |
+
31
|
| 572 |
+
01
|
| 573 |
+
16
|
| 574 |
+
e7
|
| 575 |
+
f9
|
| 576 |
+
1a
|
| 577 |
+
de
|
| 578 |
+
d1
|
| 579 |
+
08
|
| 580 |
+
df
|
| 581 |
+
b5
|
| 582 |
+
f5
|
| 583 |
+
ee
|
| 584 |
+
5c
|
| 585 |
+
ec
|
| 586 |
+
ca
|
| 587 |
+
1f
|
| 588 |
+
01
|
| 589 |
+
f3
|
| 590 |
+
f5
|
| 591 |
+
cd
|
| 592 |
+
d8
|
| 593 |
+
03
|
| 594 |
+
04
|
| 595 |
+
1f
|
| 596 |
+
f9
|
| 597 |
+
da
|
| 598 |
+
0d
|
| 599 |
+
22
|
| 600 |
+
d1
|
| 601 |
+
15
|
| 602 |
+
ce
|
| 603 |
+
05
|
| 604 |
+
12
|
| 605 |
+
1b
|
| 606 |
+
07
|
| 607 |
+
4a
|
| 608 |
+
1a
|
| 609 |
+
b1
|
| 610 |
+
62
|
| 611 |
+
d9
|
| 612 |
+
1c
|
| 613 |
+
ee
|
| 614 |
+
9f
|
| 615 |
+
36
|
| 616 |
+
09
|
| 617 |
+
dc
|
| 618 |
+
45
|
| 619 |
+
43
|
| 620 |
+
fd
|
| 621 |
+
12
|
| 622 |
+
0f
|
| 623 |
+
20
|
| 624 |
+
32
|
| 625 |
+
ef
|
| 626 |
+
16
|
| 627 |
+
e3
|
| 628 |
+
ee
|
| 629 |
+
06
|
| 630 |
+
03
|
| 631 |
+
18
|
| 632 |
+
e8
|
| 633 |
+
d2
|
| 634 |
+
f0
|
| 635 |
+
22
|
| 636 |
+
3f
|
| 637 |
+
02
|
| 638 |
+
3d
|
| 639 |
+
0a
|
| 640 |
+
15
|
| 641 |
+
ca
|
| 642 |
+
fe
|
| 643 |
+
50
|
| 644 |
+
0e
|
| 645 |
+
05
|
| 646 |
+
e0
|
| 647 |
+
ce
|
| 648 |
+
21
|
| 649 |
+
13
|
| 650 |
+
0b
|
| 651 |
+
c7
|
| 652 |
+
4c
|
| 653 |
+
fd
|
| 654 |
+
f9
|
| 655 |
+
db
|
| 656 |
+
e5
|
| 657 |
+
ef
|
| 658 |
+
e3
|
| 659 |
+
f6
|
| 660 |
+
a5
|
| 661 |
+
04
|
| 662 |
+
2e
|
| 663 |
+
fb
|
| 664 |
+
f3
|
| 665 |
+
d8
|
| 666 |
+
fc
|
| 667 |
+
d5
|
| 668 |
+
00
|
| 669 |
+
ea
|
| 670 |
+
23
|
| 671 |
+
02
|
| 672 |
+
ba
|
| 673 |
+
59
|
| 674 |
+
c0
|
| 675 |
+
06
|
| 676 |
+
ce
|
| 677 |
+
ea
|
| 678 |
+
28
|
| 679 |
+
0c
|
| 680 |
+
e8
|
| 681 |
+
8b
|
| 682 |
+
e2
|
| 683 |
+
16
|
| 684 |
+
b8
|
| 685 |
+
23
|
| 686 |
+
f5
|
| 687 |
+
05
|
| 688 |
+
25
|
| 689 |
+
06
|
| 690 |
+
1f
|
| 691 |
+
0b
|
| 692 |
+
73
|
| 693 |
+
12
|
| 694 |
+
f3
|
| 695 |
+
fc
|
| 696 |
+
41
|
| 697 |
+
fb
|
| 698 |
+
ee
|
| 699 |
+
3c
|
| 700 |
+
e2
|
| 701 |
+
cb
|
| 702 |
+
7f
|
| 703 |
+
39
|
| 704 |
+
24
|
| 705 |
+
0e
|
| 706 |
+
13
|
| 707 |
+
40
|
| 708 |
+
36
|
| 709 |
+
fb
|
| 710 |
+
3a
|
| 711 |
+
ec
|
| 712 |
+
d6
|
| 713 |
+
c7
|
| 714 |
+
00
|
| 715 |
+
ef
|
| 716 |
+
e2
|
| 717 |
+
f1
|
| 718 |
+
10
|
| 719 |
+
2a
|
| 720 |
+
36
|
| 721 |
+
28
|
| 722 |
+
04
|
| 723 |
+
23
|
| 724 |
+
58
|
| 725 |
+
21
|
| 726 |
+
0c
|
| 727 |
+
08
|
| 728 |
+
0f
|
| 729 |
+
04
|
| 730 |
+
49
|
| 731 |
+
cb
|
| 732 |
+
10
|
| 733 |
+
0e
|
| 734 |
+
c3
|
| 735 |
+
c1
|
| 736 |
+
f7
|
| 737 |
+
09
|
| 738 |
+
fd
|
| 739 |
+
29
|
| 740 |
+
36
|
| 741 |
+
0c
|
| 742 |
+
24
|
| 743 |
+
de
|
| 744 |
+
c4
|
| 745 |
+
13
|
| 746 |
+
16
|
| 747 |
+
c7
|
| 748 |
+
52
|
| 749 |
+
4a
|
| 750 |
+
d7
|
| 751 |
+
cc
|
| 752 |
+
9f
|
| 753 |
+
00
|
| 754 |
+
dc
|
| 755 |
+
ba
|
| 756 |
+
0d
|
| 757 |
+
32
|
| 758 |
+
0e
|
| 759 |
+
f0
|
| 760 |
+
78
|
| 761 |
+
23
|
| 762 |
+
22
|
| 763 |
+
4f
|
| 764 |
+
19
|
| 765 |
+
03
|
| 766 |
+
bd
|
| 767 |
+
ee
|
| 768 |
+
18
|