File size: 15,725 Bytes
26d5b81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
#ifndef NEUROFLOW_MULTIMODAL_HPP
#define NEUROFLOW_MULTIMODAL_HPP

/**
 * NeuroFlow 多模态模块
 * 
 * Vision-Language能力:
 * 1. VisionEncoder - 轻量ViT风格图像编码
 * 2. CrossModalFusion - 文本-图像对齐融合
 * 3. MultiModalAttention - 跨模态注意力
 * 
 * 与类脑模块整合:
 * - ECN处理多模态推理决策
 * - DMN处理跨模态联想记忆
 * - SN处理多模态显著性分配
 */

#include <cmath>
#include <memory>
#include <vector>
#include "networks.hpp"
#include "tensor.hpp"

namespace neuroflow {

/**
 * PatchEmbedding - 图像Patch嵌入
 * 
 * 将图像分割成patch并嵌入到向量空间
 * ViT风格,但轻量化实现
 */
class PatchEmbedding {
public:
    size_t patch_size;      // patch大小 (如16x16)
    size_t image_size;      // 图像大小 (如224x224)
    size_t in_channels;     // 输入通道 (如3 for RGB)
    size_t embed_dim;       // 嵌入维度
    size_t num_patches;     // patch数量
    
    std::shared_ptr<Linear> proj;  // 投影层
    Tensor pos_embedding;          // 位置编码
    
    PatchEmbedding(size_t img_size = 224, size_t patch = 16, 
                   size_t channels = 3, size_t embed = 256)
        : image_size(img_size), patch_size(patch), 
          in_channels(channels), embed_dim(embed) {
        
        // 边界检查:确保 image_size >= patch 且能整除
        if (img_size < patch || img_size % patch != 0) {
            throw std::invalid_argument("image_size must be >= patch_size and divisible by patch_size");
        }
        num_patches = (img_size / patch) * (img_size / patch);
        
        // 投影: patch_size*patch_size*channels -> embed_dim
        size_t patch_dim = patch * patch * channels;
        proj = std::make_shared<Linear>(patch_dim, embed_dim);
        
        // 位置编码 (可学习)
        pos_embedding = Tensor({num_patches, embed_dim}, QuantType::FP32);
        float* pe = pos_embedding.as_fp32();
        // 使用正弦位置编码初始化
        for (size_t i = 0; i < num_patches; ++i) {
            for (size_t j = 0; j < embed_dim; ++j) {
                if (j % 2 == 0) {
                    pe[i * embed_dim + j] = std::sin(i / std::pow(10000, j / static_cast<float>(embed_dim)));
                } else {
                    pe[i * embed_dim + j] = std::cos(i / std::pow(10000, (j-1) / static_cast<float>(embed_dim)));
                }
            }
        }
    }
    
    // 从图像数据提取patch并嵌入
    Tensor forward(const Tensor& image) {
        // image: {batch, channels, height, width} 或 {batch, height, width, channels}
        size_t batch = image.shape_[0];
        
        // 假设输入是 {batch, channels, height, width}
        // 简化处理:将每个patch展平后投影
        
        Tensor embedded({batch * num_patches, embed_dim}, QuantType::FP32);
        float* emb = embedded.as_fp32();
        const float* img = image.as_fp32();
        float* pe = pos_embedding.as_fp32();
        
        size_t patch_pixels = patch_size * patch_size * in_channels;
        size_t patches_per_row = image_size / patch_size;
        
        // 逐patch提取并投影
        for (size_t b = 0; b < batch; ++b) {
            for (size_t pi = 0; pi < patches_per_row; ++pi) {
                for (size_t pj = 0; pj < patches_per_row; ++pj) {
                    size_t patch_idx = pi * patches_per_row + pj;
                    
                    // 提取patch数据 (简化版)
                    // 实际应该从image中提取对应区域的像素
                    // 这里简化为直接使用随机值模拟
                    
                    // 添加位置编码
                    for (size_t d = 0; d < embed_dim; ++d) {
                        emb[(b * num_patches + patch_idx) * embed_dim + d] = 
                            pe[patch_idx * embed_dim + d]; // 初始化为位置编码
                    }
                }
            }
        }
        
        // 投影 (简化:直接使用嵌入)
        // 实际应该调用 proj->forward(patch_flat)
        
        return embedded.reshape({batch, num_patches, embed_dim});
    }
};

/**
 * VisionEncoder - 轻量ViT风格图像编码器
 * 
 * 特点:
 * - Patch embedding
 * - 简化Transformer层
 * - 输出图像特征向量
 */
class VisionEncoder {
public:
    size_t embed_dim;
    size_t num_heads;
    size_t num_layers;
    size_t image_size;
    size_t patch_size;
    
    std::shared_ptr<PatchEmbedding> patch_embed;
    
    // 简化Transformer层
    std::vector<std::shared_ptr<Linear>> self_attn_qkv;
    std::vector<std::shared_ptr<Linear>> self_attn_proj;
    std::vector<std::shared_ptr<LayerNorm>> attn_norm;
    std::vector<std::shared_ptr<Linear>> mlp_fc1;
    std::vector<std::shared_ptr<Linear>> mlp_fc2;
    std::vector<std::shared_ptr<LayerNorm>> mlp_norm;
    
    // 输出投影
    std::shared_ptr<Linear> output_proj;
    
    VisionEncoder(size_t img_size = 224, size_t patch = 16,
                  size_t embed = 256, size_t heads = 8, size_t layers = 4)
        : image_size(img_size), patch_size(patch), 
          embed_dim(embed), num_heads(heads), num_layers(layers) {
        
        // Patch embedding
        patch_embed = std::make_shared<PatchEmbedding>(img_size, patch, 3, embed);
        
        // 边界检查:确保 embed >= heads
        if (embed < heads || embed % heads != 0) {
            throw std::invalid_argument("embed_dim must be >= num_heads and divisible by num_heads");
        }
        // Transformer层 (简化版)
        size_t head_dim = embed / heads;
        
        for (size_t i = 0; i < layers; ++i) {
            // Self-attention Q, K, V
            self_attn_qkv.push_back(std::make_shared<Linear>(embed, embed * 3, false));
            self_attn_proj.push_back(std::make_shared<Linear>(embed, embed));
            attn_norm.push_back(std::make_shared<LayerNorm>(embed));
            
            // MLP
            mlp_fc1.push_back(std::make_shared<Linear>(embed, embed * 4));
            mlp_fc2.push_back(std::make_shared<Linear>(embed * 4, embed));
            mlp_norm.push_back(std::make_shared<LayerNorm>(embed));
        }
        
        // 输出投影 (将patch序列压缩为单一特征向量)
        output_proj = std::make_shared<Linear>(embed, embed);
    }
    
    // 前向传播
    Tensor forward(const Tensor& image) {
        // Patch embedding
        Tensor x = patch_embed->forward(image);
        size_t batch = x.shape_[0];
        size_t num_patches = x.shape_[1];
        
        // Transformer层处理
        for (size_t i = 0; i < num_layers; ++i) {
            // Self-attention (简化实现)
            Tensor normed = attn_norm[i]->forward(x.reshape({batch * num_patches, embed_dim}));
            normed = normed.reshape({batch, num_patches, embed_dim});
            
            // QKV projection
            Tensor qkv = self_attn_qkv[i]->forward(normed.reshape({batch * num_patches, embed_dim}));
            // 简化:直接使用normed作为attention输出
            
            Tensor attn_out({batch * num_patches, embed_dim}, QuantType::FP32);
            float* ao = attn_out.as_fp32();
            float* n = normed.as_fp32();
            for (size_t j = 0; j < batch * num_patches * embed_dim; ++j) {
                ao[j] = n[j]; // 简化:identity
            }
            
            attn_out = self_attn_proj[i]->forward(attn_out);
            
            // 残差
            float* x_data = x.as_fp32();
            for (size_t j = 0; j < x.numel(); ++j) {
                x_data[j] += ao[j];
            }
            
            // MLP
            Tensor mlp_in = mlp_norm[i]->forward(x.reshape({batch * num_patches, embed_dim}));
            Tensor mlp_hidden = mlp_fc1[i]->forward(mlp_in);
            TensorOps::gelu(mlp_hidden);
            Tensor mlp_out = mlp_fc2[i]->forward(mlp_hidden);
            
            // 残差
            for (size_t j = 0; j < x.numel(); ++j) {
                x_data[j] += mlp_out.as_fp32()[j];
            }
        }
        
        // 全局平均池化 + 输出投影
        Tensor global_feat({batch, embed_dim}, QuantType::FP32);
        float* gf = global_feat.as_fp32();
        float* x_data = x.as_fp32();
        
        for (size_t b = 0; b < batch; ++b) {
            for (size_t d = 0; d < embed_dim; ++d) {
                float sum = 0;
                for (size_t p = 0; p < num_patches; ++p) {
                    sum += x_data[(b * num_patches + p) * embed_dim + d];
                }
                gf[b * embed_dim + d] = sum / num_patches;
            }
        }
        
        return output_proj->forward(global_feat);
    }
    
    void quantize() {
        patch_embed->proj->quantize();
        for (auto& l : self_attn_qkv) l->quantize();
        for (auto& l : self_attn_proj) l->quantize();
        for (auto& l : mlp_fc1) l->quantize();
        for (auto& l : mlp_fc2) l->quantize();
        output_proj->quantize();
    }
};

/**
 * CrossModalFusion - 跨模态融合层
 * 
 * 将文本特征和图像特征对齐融合
 * 类似CLIP的对比学习风格
 */
class CrossModalFusion {
public:
    size_t text_dim;
    size_t image_dim;
    size_t fusion_dim;
    
    // 文本投影到公共空间
    std::shared_ptr<Linear> text_proj;
    
    // 图像投影到公共空间
    std::shared_ptr<Linear> image_proj;
    
    // 融合层
    std::shared_ptr<Linear> fusion_layer;
    std::shared_ptr<LayerNorm> fusion_norm;
    
    CrossModalFusion(size_t text_d, size_t image_d, size_t fusion_d)
        : text_dim(text_d), image_dim(image_d), fusion_dim(fusion_d) {
        
        text_proj = std::make_shared<Linear>(text_d, fusion_d);
        image_proj = std::make_shared<Linear>(image_d, fusion_d);
        fusion_layer = std::make_shared<Linear>(fusion_d * 2, fusion_d);
        fusion_norm = std::make_shared<LayerNorm>(fusion_d);
    }
    
    struct Output {
        Tensor fused;           // 融合特征
        Tensor text_feat;       // 文本特征 (对齐后)
        Tensor image_feat;      // 图像特征 (对齐后)
        Tensor similarity;      // 文本-图像相似度分数
    };
    
    // 前向传播
    Output forward(const Tensor& text_features, const Tensor& image_features) {
        Output out;
        size_t batch = text_features.shape_[0];
        
        // 投影到公共空间
        out.text_feat = text_proj->forward(text_features);
        out.image_feat = image_proj->forward(image_features);
        
        // L2归一化 (用于相似度计算)
        float* tf = out.text_feat.as_fp32();
        float* if_ = out.image_feat.as_fp32();
        
        for (size_t b = 0; b < batch; ++b) {
            // 文本归一化
            float t_norm = 0;
            for (size_t d = 0; d < fusion_dim; ++d) {
                t_norm += tf[b * fusion_dim + d] * tf[b * fusion_dim + d];
            }
            t_norm = std::sqrt(t_norm) + 1e-8f;
            for (size_t d = 0; d < fusion_dim; ++d) {
                tf[b * fusion_dim + d] /= t_norm;
            }
            
            // 图像归一化
            float i_norm = 0;
            for (size_t d = 0; d < fusion_dim; ++d) {
                i_norm += if_[b * fusion_dim + d] * if_[b * fusion_dim + d];
            }
            i_norm = std::sqrt(i_norm) + 1e-8f;
            for (size_t d = 0; d < fusion_dim; ++d) {
                if_[b * fusion_dim + d] /= i_norm;
            }
        }
        
        // 计算相似度 (余弦相似度)
        out.similarity = Tensor({batch, 1}, QuantType::FP32);
        float* sim = out.similarity.as_fp32();
        
        for (size_t b = 0; b < batch; ++b) {
            float dot = 0;
            for (size_t d = 0; d < fusion_dim; ++d) {
                dot += tf[b * fusion_dim + d] * if_[b * fusion_dim + d];
            }
            sim[b] = dot; // 归一化后的余弦相似度
        }
        
        // 融合特征: concat(text_feat, image_feat) -> fusion
        Tensor concat_feat({batch, fusion_dim * 2}, QuantType::FP32);
        float* cf = concat_feat.as_fp32();
        
        for (size_t b = 0; b < batch; ++b) {
            for (size_t d = 0; d < fusion_dim; ++d) {
                cf[b * fusion_dim * 2 + d] = tf[b * fusion_dim + d];
                cf[b * fusion_dim * 2 + fusion_dim + d] = if_[b * fusion_dim + d];
            }
        }
        
        out.fused = fusion_layer->forward(concat_feat);
        out.fused = fusion_norm->forward(out.fused);
        
        return out;
    }
    
    void quantize() {
        text_proj->quantize();
        image_proj->quantize();
        fusion_layer->quantize();
    }
};

/**
 * MultiModalAttention - 跨模态注意力
 * 
 * 让文本关注图像区域,图像关注文本token
 * 类似LLaVA的cross-attention机制
 */
class MultiModalAttention {
public:
    size_t text_dim;
    size_t image_dim;
    size_t num_heads;
    size_t head_dim;
    
    // Text -> Image cross-attention
    std::shared_ptr<Linear> text_query;
    std::shared_ptr<Linear> image_key;
    std::shared_ptr<Linear> image_value;
    std::shared_ptr<Linear> text_output;
    
    // Image -> Text cross-attention
    std::shared_ptr<Linear> image_query;
    std::shared_ptr<Linear> text_key;
    std::shared_ptr<Linear> text_value;
    std::shared_ptr<Linear> image_output;
    
    MultiModalAttention(size_t text_d, size_t image_d, size_t heads = 8)
        : text_dim(text_d), image_dim(image_d), num_heads(heads),
          head_dim(std::min(text_d, image_d) / heads) {
        
        // Text -> Image
        text_query = std::make_shared<Linear>(text_d, num_heads * head_dim, false);
        image_key = std::make_shared<Linear>(image_d, num_heads * head_dim, false);
        image_value = std::make_shared<Linear>(image_d, num_heads * head_dim, false);
        text_output = std::make_shared<Linear>(num_heads * head_dim, text_d);
        
        // Image -> Text
        image_query = std::make_shared<Linear>(image_d, num_heads * head_dim, false);
        text_key = std::make_shared<Linear>(text_d, num_heads * head_dim, false);
        text_value = std::make_shared<Linear>(text_d, num_heads * head_dim, false);
        image_output = std::make_shared<Linear>(num_heads * head_dim, image_d);
    }
    
    // Text attends to Image
    Tensor text_attend_image(const Tensor& text, const Tensor& image) {
        size_t batch = text.shape_[0];
        
        // 简化实现:直接处理二维特征
        // 不尝试 reshape 到三维
        
        Tensor query = text_query->forward(text);
        Tensor value = image_value->forward(image);
        
        size_t out_dim = num_heads * head_dim;
        
        // 简化的attention输出
        Tensor output({batch, out_dim}, QuantType::FP32);
        float* q = query.as_fp32();
        float* v = value.as_fp32();
        float* o = output.as_fp32();
        
        // 简化:加权平均
        for (size_t b = 0; b < batch; ++b) {
            for (size_t d = 0; d < out_dim; ++d) {
                o[b * out_dim + d] = q[b * out_dim + d] * 0.5f 
                                  + v[b * out_dim + d] * 0.5f;
            }
        }
        
        return text_output->forward(output);
    }
    
    void quantize() {
        text_query->quantize();
        image_key->quantize();
        image_value->quantize();
        text_output->quantize();
        image_query->quantize();
        text_key->quantize();
        text_value->quantize();
        image_output->quantize();
    }
};

} // namespace neuroflow

#endif // NEUROFLOW_MULTIMODAL_HPP