Skip to content

Commit b324c95

Browse files
committed
add reader_onnx
1 parent a59db83 commit b324c95

File tree

7 files changed

+214
-36
lines changed

7 files changed

+214
-36
lines changed

app/Converters/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
add_executable(Reader_weights reader_weights_sample.cpp)
2-
2+
add_executable(Reader_weights_onnx reader_weights_sample_onnx.cpp)
33
target_link_libraries(Reader_weights PUBLIC perf_lib layers_lib reader_lib)
4-
4+
target_link_libraries(Reader_weights_onnx PUBLIC perf_lib layers_lib reader_lib)
55
add_definitions(-DMODEL_PATH_H5="${CMAKE_SOURCE_DIR}/docs/jsons/model_data_alexnet_1.json")
66
add_definitions(-DMODEL_PATH_GOOGLENET_ONNX="${CMAKE_SOURCE_DIR}/docs/jsons/googlenet_onnx_model.json")

app/Converters/parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def __init__(self, **kwargs):
1717

1818
# Пути к модели и JSON файлу
1919
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
20-
MODEL_PATH = os.path.join(BASE_DIR, 'docs', 'AlexNet-model.h5')
21-
MODEL_DATA_PATH = os.path.join(BASE_DIR, 'docs', 'model_data_alexnet_1.json')
20+
MODEL_PATH = os.path.join(BASE_DIR, 'docs\\models', 'AlexNet-model.h5')
21+
MODEL_DATA_PATH = os.path.join(BASE_DIR, 'docs\\jsons', 'model_data_alexnet_1.json')
2222

2323
# Загрузка модели
2424
model = load_model(MODEL_PATH, custom_objects={'GlorotUniform': CustomGlorotUniform, 'Zeros': CustomZeros})

app/Converters/parser_onnx.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@
77
def onnx_to_json(model_path, output_json_path):
88
# Загрузка модели
99
model = onnx.load(model_path)
10-
11-
# Проверка валидности модели
1210
onnx.checker.check_model(model)
1311

14-
# Создаем словарь для быстрого доступа к инициализаторам по их именам
12+
# Словарь инициализаторов
1513
initializers_dict = {
1614
init.name: {
1715
"data_type": init.data_type,
@@ -21,10 +19,7 @@ def onnx_to_json(model_path, output_json_path):
2119
for init in model.graph.initializer
2220
}
2321

24-
# Создаем список слоев в формате Keras
2522
layer_info = []
26-
27-
# Обрабатываем входные данные как первый слой
2823
input_layer = {
2924
"index": 0,
3025
"name": "input_1",
@@ -34,56 +29,64 @@ def onnx_to_json(model_path, output_json_path):
3429
}
3530
layer_info.append(input_layer)
3631

37-
# Обработка узлов (операций) как слоев
3832
for node in model.graph.node:
39-
# Создаем запись слоя
4033
layer_data = {
4134
"index": len(layer_info),
4235
"name": node.name.replace('/', '_'),
4336
"type": node.op_type,
44-
"weights": [],
45-
"attributes": {} # Сохраняем все атрибуты здесь
37+
"attributes": {}
4638
}
4739

48-
# Обрабатываем все атрибуты узла
40+
# Обработка атрибутов
4941
for attr in node.attribute:
5042
attr_value = helper.get_attribute_value(attr)
51-
52-
# Преобразуем разные типы атрибутов
5343
if isinstance(attr_value, bytes):
5444
attr_value = attr_value.decode('utf-8', errors='ignore')
5545
elif hasattr(attr_value, 'tolist'):
5646
attr_value = attr_value.tolist()
5747
elif str(type(attr_value)).endswith("RepeatedScalarContainer'>"):
5848
attr_value = list(attr_value)
59-
60-
# Сохраняем атрибут
6149
layer_data["attributes"][attr.name] = attr_value
6250

63-
# Специальная обработка для удобства (можно использовать или игнорировать)
6451
if attr.name == "pads":
6552
layer_data["padding"] = "same" if any(p > 0 for p in attr_value) else "valid"
6653
elif attr.name == "kernel_shape":
6754
layer_data["kernel_size"] = attr_value
6855
elif attr.name == "strides":
6956
layer_data["strides"] = attr_value
7057

71-
# Добавляем веса в формате Keras (один список с ядрами и bias)
72-
layer_weights = []
58+
# Собираем все initializers для этого узла
59+
node_init = []
7360
for input_name in node.input:
7461
if input_name in initializers_dict:
75-
init = initializers_dict[input_name]
76-
if len(init["dims"]) > 1: # Ядра свертки/матрицы весов
77-
layer_weights.extend(init["values"])
78-
else: # Bias
79-
layer_weights.append(init["values"])
80-
81-
if layer_weights:
82-
layer_data["weights"] = layer_weights
62+
node_init.append(initializers_dict[input_name])
63+
64+
# Новая логика: разделяем weights/value/bias
65+
if len(node_init) == 1:
66+
init = node_init[0]
67+
if len(init["dims"]) == 0 or (len(init["dims"]) == 1 and init["dims"][0] == 1):
68+
# Скалярное значение или массив из одного элемента
69+
layer_data["value"] = init["values"] if len(init["dims"]) == 0 else init["values"][0]
70+
else:
71+
# Многомерные данные
72+
layer_data["weights"] = init["values"]
73+
elif len(node_init) > 1:
74+
# Для нескольких инициализаторов: weights + bias
75+
weights = []
76+
for init in node_init[:-1]:
77+
if len(init["dims"]) > 0:
78+
weights.extend(init["values"]) if isinstance(init["values"][0], list) else weights.append(
79+
init["values"])
80+
81+
if weights:
82+
layer_data["weights"] = weights
83+
84+
# Последний инициализатор - bias (если одномерный)
85+
if len(node_init[-1]["dims"]) == 1:
86+
layer_data["bias"] = node_init[-1]["values"]
8387

8488
layer_info.append(layer_data)
8589

86-
# Custom JSON encoder
8790
class CustomEncoder(json.JSONEncoder):
8891
def default(self, obj):
8992
if hasattr(obj, 'tolist'):
@@ -92,7 +95,6 @@ def default(self, obj):
9295
return list(obj)
9396
return super().default(obj)
9497

95-
# Сохранение в JSON файл
9698
with open(output_json_path, 'w') as f:
9799
json.dump(layer_info, f, indent=2, cls=CustomEncoder)
98100

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#include <iostream>
2+
3+
#include "Weights_Reader/reader_weights_onnx.hpp"
4+
5+
int main() {
6+
std::string json_file = MODEL_PATH_GOOGLENET_ONNX;
7+
json model_data = read_json_onnx(json_file);
8+
9+
std::cout << "Model contains " << model_data.size()
10+
<< " layers:" << std::endl;
11+
std::cout << "--------------------------------------------------"
12+
<< std::endl;
13+
14+
for (const auto& layer_data : model_data) {
15+
int layer_index = layer_data["index"];
16+
std::string layer_name = layer_data["name"];
17+
std::string layer_type = layer_data["type"];
18+
bool has_weights =
19+
layer_data.contains("weights") && !layer_data["weights"].empty();
20+
bool has_value = layer_data.contains("value");
21+
22+
std::cout << "Layer " << layer_index << ": " << layer_name << " ("
23+
<< layer_type << ")" << std::endl;
24+
25+
// Вывод атрибутов
26+
if (layer_data.contains("attributes") &&
27+
!layer_data["attributes"].empty()) {
28+
std::cout << " Attributes:" << std::endl;
29+
for (const auto& [key, value] : layer_data["attributes"].items()) {
30+
std::cout << " " << key << ": ";
31+
if (value.is_array()) {
32+
std::cout << "[";
33+
for (const auto& v : value) {
34+
if (v.is_number())
35+
std::cout << v.get<float>() << " ";
36+
else if (v.is_string())
37+
std::cout << v.get<std::string>() << " ";
38+
}
39+
std::cout << "]";
40+
} else if (value.is_number()) {
41+
std::cout << value.get<float>();
42+
} else if (value.is_string()) {
43+
std::cout << value.get<std::string>();
44+
}
45+
std::cout << std::endl;
46+
}
47+
}
48+
49+
// Обработка value (скалярных значений)
50+
if (has_value) {
51+
try {
52+
float value = layer_data["value"].get<float>();
53+
std::cout << " Value: " << value << std::endl;
54+
} catch (const std::exception& e) {
55+
std::cerr << " Error processing value: " << e.what() << std::endl;
56+
}
57+
}
58+
59+
// Обработка весов
60+
if (has_weights) {
61+
try {
62+
Tensor tensor = create_tensor_from_json_onnx(layer_data, Type::kFloat);
63+
64+
std::cout << " Weights shape: " << tensor.get_shape() << std::endl;
65+
66+
if (!tensor.get_bias().empty()) {
67+
std::cout << " Bias size: " << tensor.get_bias().size() << std::endl;
68+
}
69+
} catch (const std::exception& e) {
70+
std::cerr << " Error processing weights: " << e.what() << std::endl;
71+
}
72+
} else if (!has_value) {
73+
std::cout << " No weights or value" << std::endl;
74+
}
75+
76+
std::cout << "--------------------------------------------------"
77+
<< std::endl;
78+
}
79+
80+
return 0;
81+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <nlohmann/json.hpp>
2+
#include <string>
3+
#include <vector>
4+
5+
#include "layers/Tensor.hpp"
6+
7+
using json = nlohmann::json;
8+
using namespace itlab_2023;
9+
10+
json read_json_onnx(const std::string& filename);
11+
void extract_values_from_json_onnx(const json& j, std::vector<float>& values);
12+
void parse_json_shape_onnx(const json& j, std::vector<size_t>& shape,
13+
size_t dim);
14+
Tensor create_tensor_from_json_onnx(const json& j, Type type);
15+
16+
void parse_onnx_weights(const json& j, std::vector<float>& weights,
17+
std::vector<float>& bias);

include/layers/Tensor.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ class Tensor {
8383
throw std::invalid_argument("Incorrect vector size given to Tensor");
8484
}
8585
values_ = a;
86-
if (bias.size() != shape_[shape_.dims() - 1]) {
87-
throw std::invalid_argument(
88-
"Bias size does not match the last dimension of the shape");
89-
}
9086
}
9187

9288
Tensor(const Tensor& t) = default;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include "Weights_Reader/reader_weights_onnx.hpp"
2+
3+
#include <fstream>
4+
#include <iostream>
5+
#include <nlohmann/json.hpp>
6+
#include <stdexcept>
7+
#include <vector>
8+
9+
using json = nlohmann::json;
10+
11+
json read_json_onnx(const std::string& filename) {
12+
std::ifstream ifs(filename);
13+
if (!ifs.is_open()) {
14+
throw std::runtime_error("Failed to open JSON file: " + filename);
15+
}
16+
17+
json model_data;
18+
try {
19+
ifs >> model_data;
20+
} catch (const json::parse_error& e) {
21+
throw std::runtime_error("JSON parse error: " + std::string(e.what()));
22+
}
23+
24+
return model_data;
25+
}
26+
27+
void extract_values_from_json_onnx(const json& j, std::vector<float>& values) {
28+
if (j.is_array()) {
29+
for (const auto& item : j) {
30+
extract_values_from_json_onnx(item, values);
31+
}
32+
} else if (j.is_number()) {
33+
values.push_back(j.get<float>());
34+
}
35+
}
36+
37+
void parse_json_shape_onnx(const json& j, std::vector<size_t>& shape,
38+
size_t dim = 0) {
39+
if (!j.is_array()) {
40+
if (dim == 0) shape.push_back(0);
41+
return;
42+
}
43+
44+
if (shape.size() <= dim) {
45+
shape.push_back(j.size());
46+
}
47+
48+
if (!j.empty()) {
49+
parse_json_shape_onnx(j[0], shape, dim + 1);
50+
}
51+
}
52+
53+
Tensor create_tensor_from_json_onnx(const json& layer_data, Type type) {
54+
if (type != Type::kFloat) {
55+
throw std::invalid_argument("Only float type is supported");
56+
}
57+
58+
std::vector<float> weights;
59+
if (layer_data.contains("weights") && !layer_data["weights"].empty()) {
60+
extract_values_from_json_onnx(layer_data["weights"], weights);
61+
}
62+
63+
// Извлекаем bias (если есть)
64+
std::vector<float> bias;
65+
if (layer_data.contains("bias") && !layer_data["bias"].empty()) {
66+
extract_values_from_json_onnx(layer_data["bias"], bias);
67+
}
68+
69+
// Определяем shape
70+
std::vector<size_t> shape;
71+
if (layer_data.contains("weights")) {
72+
parse_json_shape_onnx(layer_data["weights"], shape);
73+
}
74+
75+
std::cout << "Extracted weights size: " << weights.size() << std::endl;
76+
std::cout << "Shape: ";
77+
for (auto dim : shape) std::cout << dim << " ";
78+
std::cout << std::endl;
79+
std::cout << "Extracted bias size: " << bias.size() << std::endl;
80+
81+
return make_tensor<float>(weights, Shape(shape), bias);
82+
}

0 commit comments

Comments
 (0)