遗漏的部分

This commit is contained in:
qing committed 2026-08-02 21:21:03 +08:00
1 parent 84fb370da8
commit 0493383ee8
63 files changed
+28237 -4

No files matched your search

+366
View File
@@ -0,0 +1,366 @@
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <tuple>
#include "ConvLayer.hpp"
class FlattenLayer {
private:
// 输入输出尺寸
int batch_size;
int input_channels;
int input_height;
int input_width;
int output_size;
// 缓存输入形状(用于反向传播)
std::vector<int> input_shape_cache;
std::vector<float> input_cache; // 缓存输入数据(可选)
// 辅助函数
//void flatten_forward(const float* input, float* output);
//void flatten_backward(const float* grad_output, float* grad_input);
public:
// 构造函数
FlattenLayer() : batch_size(0), input_channels(0),
input_height(0), input_width(0), output_size(0) {}
// 设置输入尺寸(自动计算输出尺寸)
void set_input_shape(int channels, int height, int width, int batch = 1) {
input_channels = channels;
input_height = height;
input_width = width;
batch_size = batch;
// 计算输出大小
output_size = channels * height * width;
// 缓存输入形状
input_shape_cache = {channels, height, width, batch};
}
// 设置输入尺寸(从卷积/池化层获取)
template<typename... Args>
void set_input_shape(std::tuple<Args...> shape_tuple) {
set_input_shape(std::get<0>(shape_tuple),
std::get<1>(shape_tuple),
std::get<2>(shape_tuple));
}
// 前向传播
std::vector<float> forward(const std::vector<float>& input, int batch_size = 1, bool training = true) {
// 如果之前没有设置输入尺寸,自动推断
if (input_channels == 0 && input_height == 0 && input_width == 0) {
// 这里假设输入是完整的batch数据,需要外部调用set_input_shape
// 或者根据输入大小推断(但不知道高度和宽度)
std::cerr << "Warning: Input shape not set for FlattenLayer. "
<< "Please call set_input_shape() first." << std::endl;
return input; // 安全返回,但可能不正确
}
// 检查输入大小是否匹配
int expected_input_size = batch_size * input_channels * input_height * input_width;
if (input.size() != static_cast<size_t>(expected_input_size)) {
std::cerr << "Error: Input size mismatch in FlattenLayer. "
<< "Expected: " << expected_input_size
<< ", Got: " << input.size() << std::endl;
return std::vector<float>();
}
// 如果训练模式,缓存输入形状
if (training) {
this->batch_size = batch_size;
input_shape_cache = {input_channels, input_height, input_width, batch_size};
input_cache = input; // 可选:缓存输入数据
}
// 计算输出大小
int output_total_size = batch_size * output_size;
std::vector<float> output(output_total_size, 0.0f);
// 执行展平操作
flatten_forward(input.data(), output.data());
return output;
}
// 反向传播
std::vector<float> backward(const std::vector<float>& grad_output, int batch_size = 1) {
// 检查梯度大小是否匹配
int expected_grad_size = batch_size * output_size;
if (grad_output.size() != static_cast<size_t>(expected_grad_size)) {
std::cerr << "Error: Gradient size mismatch in FlattenLayer. "
<< "Expected: " << expected_grad_size
<< ", Got: " << grad_output.size() << std::endl;
return std::vector<float>();
}
// 恢复输入形状
if (input_shape_cache.size() >= 4) {
input_channels = input_shape_cache[0];
input_height = input_shape_cache[1];
input_width = input_shape_cache[2];
this->batch_size = input_shape_cache[3];
}
// 计算输入梯度大小
int input_total_size = this->batch_size * input_channels * input_height * input_width;
std::vector<float> grad_input(input_total_size, 0.0f);
// 执行反向展平操作
flatten_backward(grad_output.data(), grad_input.data());
return grad_input;
}
// 获取输出尺寸
int get_output_size() const {
return output_size;
}
// 获取输出尺寸(返回元组)
std::tuple<int> get_output_shape() const {
return std::make_tuple(output_size);
}
// 获取输入尺寸
std::tuple<int, int, int> get_input_shape() const {
return std::make_tuple(input_channels, input_height, input_width);
}
// 获取完整输入尺寸(包含批次)
std::tuple<int, int, int, int> get_full_input_shape() const {
return std::make_tuple(input_channels, input_height, input_width, batch_size);
}
// 打印层信息
void print_info() const {
std::cout << "Flatten Layer Info:" << std::endl;
std::cout << " Input Shape: " << input_channels << "x"
<< input_height << "x" << input_width;
if (batch_size > 0) {
std::cout << " (batch: " << batch_size << ")";
}
std::cout << std::endl;
std::cout << " Output Size: " << output_size;
if (batch_size > 0) {
std::cout << " (total: " << batch_size * output_size << ")";
}
std::cout << std::endl;
}
// 重置层状态
void reset() {
input_shape_cache.clear();
input_cache.clear();
batch_size = 0;
input_channels = 0;
input_height = 0;
input_width = 0;
output_size = 0;
}
// 检查是否已初始化
bool is_initialized() const {
return input_channels > 0 && input_height > 0 && input_width > 0;
}
private:
// 展平前向传播实现
void flatten_forward(const float* input, float* output) {
// 简单地将多维数据复制到一维数组
int elements_per_sample = input_channels * input_height * input_width;
for (int b = 0; b < batch_size; b++) {
const float* input_ptr = input + b * elements_per_sample;
float* output_ptr = output + b * output_size;
// 直接内存复制
std::copy(input_ptr, input_ptr + elements_per_sample, output_ptr);
// 或者使用循环(等效)
/*
for (int i = 0; i < elements_per_sample; i++) {
output_ptr[i] = input_ptr[i];
}
*/
}
}
// 展平反向传播实现
void flatten_backward(const float* grad_output, float* grad_input) {
// 反向传播只是将梯度重新整形为输入形状
int elements_per_sample = input_channels * input_height * input_width;
for (int b = 0; b < batch_size; b++) {
const float* grad_output_ptr = grad_output + b * output_size;
float* grad_input_ptr = grad_input + b * elements_per_sample;
// 直接内存复制
std::copy(grad_output_ptr, grad_output_ptr + elements_per_sample, grad_input_ptr);
// 或者使用循环(等效)
/*
for (int i = 0; i < elements_per_sample; i++) {
grad_input_ptr[i] = grad_output_ptr[i];
}
*/
}
}
};
// 动态展平层(自动推断输入形状)
class DynamicFlattenLayer {
private:
int batch_size;
int input_channels;
int input_height;
int input_width;
int output_size;
public:
DynamicFlattenLayer() : batch_size(0), input_channels(0),
input_height(0), input_width(0), output_size(0) {}
// 前向传播(自动推断形状)
std::vector<float> forward(const std::vector<float>& input,
std::tuple<int, int, int> input_shape,
int batch_size = 1,
bool training = true) {
// 从元组获取输入形状
input_channels = std::get<0>(input_shape);
input_height = std::get<1>(input_shape);
input_width = std::get<2>(input_shape);
this->batch_size = batch_size;
// 验证输入大小
int expected_size = batch_size * input_channels * input_height * input_width;
if (input.size() != static_cast<size_t>(expected_size)) {
std::cerr << "Error: Input size mismatch in DynamicFlattenLayer. "
<< "Expected: " << expected_size
<< ", Got: " << input.size()
<< " (shape: " << input_channels << "x"
<< input_height << "x" << input_width
<< ", batch: " << batch_size << ")" << std::endl;
return std::vector<float>();
}
// 计算输出大小
output_size = input_channels * input_height * input_width;
int total_output_size = batch_size * output_size;
std::vector<float> output(total_output_size);
// 执行展平
const float* input_ptr = input.data();
float* output_ptr = output.data();
int elements_per_sample = output_size;
for (int b = 0; b < batch_size; b++) {
std::copy(input_ptr, input_ptr + elements_per_sample, output_ptr);
input_ptr += elements_per_sample;
output_ptr += elements_per_sample;
}
return output;
}
// 反向传播
std::vector<float> backward(const std::vector<float>& grad_output, int batch_size = 1) {
// 检查是否已初始化
if (output_size == 0) {
std::cerr << "Error: DynamicFlattenLayer not initialized. "
<< "Call forward() first." << std::endl;
return std::vector<float>();
}
// 验证梯度大小
int expected_grad_size = batch_size * output_size;
if (grad_output.size() != static_cast<size_t>(expected_grad_size)) {
std::cerr << "Error: Gradient size mismatch in DynamicFlattenLayer. "
<< "Expected: " << expected_grad_size
<< ", Got: " << grad_output.size() << std::endl;
return std::vector<float>();
}
// 恢复输入形状
int total_input_size = batch_size * input_channels * input_height * input_width;
std::vector<float> grad_input(total_input_size);
// 执行反向展平
const float* grad_output_ptr = grad_output.data();
float* grad_input_ptr = grad_input.data();
int elements_per_sample = output_size;
for (int b = 0; b < batch_size; b++) {
std::copy(grad_output_ptr, grad_output_ptr + elements_per_sample, grad_input_ptr);
grad_output_ptr += elements_per_sample;
grad_input_ptr += elements_per_sample;
}
return grad_input;
}
// 获取输出尺寸
int get_output_size() const { return output_size; }
// 获取输入形状
std::tuple<int, int, int> get_input_shape() const {
return std::make_tuple(input_channels, input_height, input_width);
}
};
// 使用示例函数
inline void flatten_layer_example() {
std::cout << "=== Flatten Layer Example ===" << std::endl;
// 创建展平层
FlattenLayer flatten;
// 设置输入形状(例如从池化层获取的输出)
// 假设池化层输出:64通道,7x7特征图
flatten.set_input_shape(64, 7, 7);
// 创建模拟输入数据(batch_size=2)
int batch_size = 2;
std::vector<float> input(2 * 64 * 7 * 7);
for (size_t i = 0; i < input.size(); i++) {
input[i] = static_cast<float>(i) / 100.0f;
}
// 前向传播
std::cout << "Forward pass..." << std::endl;
auto output = flatten.forward(input, batch_size, true);
std::cout << "Input size: " << input.size() << std::endl;
std::cout << "Output size: " << output.size() << std::endl;
std::cout << "Expected output size per sample: " << flatten.get_output_size() << std::endl;
// 打印部分结果
std::cout << "First 10 output values: ";
for (int i = 0; i < std::min(10, static_cast<int>(output.size())); i++) {
std::cout << output[i] << " ";
}
std::cout << std::endl;
// 创建模拟梯度(全为1)
std::vector<float> grad_output(output.size(), 1.0f);
// 反向传播
std::cout << "Backward pass..." << std::endl;
auto grad_input = flatten.backward(grad_output, batch_size);
std::cout << "Gradient input size: " << grad_input.size() << std::endl;
std::cout << "Expected gradient input size: " << 2 * 64 * 7 * 7 << std::endl;
// 验证形状正确性
auto [channels, height, width] = flatten.get_input_shape();
std::cout << "Recovered input shape: " << channels
<< "x" << height << "x" << width << std::endl;
// 打印层信息
flatten.print_info();
}