You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

nn.h 14 kB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #pragma once
  2. #include <vector>
  3. #include <memory>
  4. #include <unordered_set>
  5. #include <unordered_map>
  6. #include <algorithm>
  7. #include <pybind11/pybind11.h>
  8. #include <pybind11/numpy.h>
  9. #include <iostream>
  10. #include "../tensor/tensor.h"
  11. #include "../math/arith.h"
  12. namespace py = pybind11;
  13. namespace nn {
  14. class Node {
  15. public:
  16. std::shared_ptr<tensor::Tensor> data;
  17. std::vector<std::shared_ptr<Node>> objects;
  18. std::vector<std::shared_ptr<tensor::Tensor>> gradient;
  19. public:
  20. Node() {}
  21. virtual std::shared_ptr<tensor::Tensor> forward() = 0;
  22. virtual std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) = 0;
  23. std::vector<std::shared_ptr<Node>> get_parents() {
  24. return this->objects;
  25. }
  26. std::vector<float> get_data() {
  27. return this->data->data;
  28. }
  29. std::shared_ptr<tensor::Tensor> get_tensor() {
  30. return this->data;
  31. }
  32. // virtual void update(std::shared_ptr<tensor::Tensor> grad, float lr) = 0;
  33. // virtual void zero_grad() = 0;
  34. virtual ~Node() {}
  35. };
  36. class DataNode: public Node {
  37. public:
  38. DataNode() {}
  39. }; // class DataNode
  40. class Parameter: public DataNode {
  41. public:
  42. // Parameter(const std::vector<std::size_t>& shape) {
  43. // this->data = std::make_shared<tensor::Tensor>(shape, true);
  44. // }
  45. Parameter(py::array_t<float> array) {
  46. py::buffer_info info = array.request();
  47. float* dataPtr = static_cast<float*>(info.ptr);
  48. std::vector<std::size_t> shape = {};
  49. for (auto &it: info.shape) {
  50. shape.push_back(it);
  51. }
  52. auto tensor = std::make_shared<tensor::Tensor>(shape);
  53. std::vector<float> result(dataPtr, dataPtr + info.size);
  54. tensor->data = result;
  55. this->data = tensor;
  56. }
  57. std::shared_ptr<tensor::Tensor> forward() {
  58. return this->data;
  59. };
  60. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) {
  61. return {gradient};
  62. };
  63. void update(std::shared_ptr<tensor::Tensor> grad, double lr) {
  64. for (auto i = 0; i < this->data->size; i++) {
  65. this->data->data[i] -= lr * grad->data[i];
  66. }
  67. }
  68. }; // class Parameter
  69. class Constant: public DataNode {
  70. public:
  71. Constant(std::shared_ptr<tensor::Tensor> data) {
  72. this->data = data;
  73. }
  74. Constant(py::array_t<float> array) {
  75. this->data = tensor::pyarray_to_tensor(array);
  76. }
  77. std::shared_ptr<tensor::Tensor> forward() {
  78. return this->data;
  79. };
  80. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) {
  81. return {gradient};
  82. };
  83. // void update(std::shared_ptr<tensor::Tensor> grad, float lr) {}
  84. }; // class Constant
  85. class FunctionNode: public Node {
  86. public:
  87. FunctionNode(std::shared_ptr<Node> a, std::shared_ptr<Node> b) {
  88. this->objects.emplace_back(a);
  89. this->objects.emplace_back(b);
  90. }
  91. FunctionNode(std::shared_ptr<Node> a) {
  92. this->objects.emplace_back(a);
  93. }
  94. std::shared_ptr<tensor::Tensor> forward() override {
  95. return nullptr;
  96. }
  97. }; //class FunctionNode
  98. class Add: public FunctionNode {
  99. public:
  100. Add(std::shared_ptr<Node> a, std::shared_ptr<Node> b) : FunctionNode(a, b) {
  101. this->data = this->forward();
  102. }
  103. std::shared_ptr<tensor::Tensor> forward() override {
  104. auto a = this->objects[0];
  105. auto b = this->objects[1];
  106. auto outNode = std::make_shared<tensor::Tensor>(a->data->shape);
  107. for (auto i = 0; i < a->data->size; i++) {
  108. outNode->data[i] = a->data->data[i] + b->data->data[i];
  109. }
  110. return outNode;
  111. }
  112. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  113. // assertion needed
  114. return {gradient, gradient};
  115. }
  116. };
  117. class AddBias: public FunctionNode {
  118. public:
  119. AddBias(std::shared_ptr<Node> a, std::shared_ptr<Node> b) : FunctionNode(a, b) {
  120. this->data = this->forward();
  121. }
  122. std::shared_ptr<tensor::Tensor> forward() override {
  123. // features: a Node with shape (batch_size x num_features)
  124. // bias: a Node with shape (1 x num_features)
  125. auto features = this->objects[0];
  126. auto bias = this->objects[1];
  127. auto outNode = std::make_shared<tensor::Tensor>(features->data->shape);
  128. auto batch_size = features->data->shape[0];
  129. auto num_features = features->data->shape[1];
  130. for (size_t i = 0; i < batch_size; ++i) {
  131. for (size_t j = 0; j < num_features; ++j) {
  132. // 计算索引:batch_size行,num_features列的二维张量
  133. size_t idx = i * num_features + j;
  134. // 每个样本的特征向量加上偏置向量
  135. outNode->data[idx] = features->data->data[idx] + bias->data->data[j];
  136. }
  137. }
  138. // for循环写加法总会写吧🤔
  139. // 补全这里的代码
  140. return outNode;
  141. }
  142. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  143. // assertion needed
  144. auto g_bias = std::make_shared<tensor::Tensor>(this->objects[1]->data->shape);
  145. // 从张量形状获取维度信息
  146. auto batch_size = gradient->shape[0];
  147. auto num_features = gradient->shape[1]; // 从shape中获取num_features
  148. // 初始化偏置梯度为零
  149. for (size_t j = 0; j < num_features; ++j)
  150. {
  151. g_bias->data[j] = 0.0f;
  152. }
  153. // 计算偏置的梯度:对每个特征维度,将所有样本的梯度累加
  154. for (size_t i = 0; i < batch_size; ++i) {
  155. for (size_t j = 0; j < num_features; ++j) {
  156. // 累加每个样本对该特征维度的梯度贡献
  157. g_bias->data[j] += gradient->data[i * num_features + j];
  158. }
  159. }
  160. return {gradient, g_bias};
  161. }
  162. std::vector<float> get_data() {
  163. return this->data->data;
  164. }
  165. }; // class AddBias
  166. class Linear: public FunctionNode {
  167. public:
  168. Linear(std::shared_ptr<Node> a, std::shared_ptr<Node> b) : FunctionNode(a, b) {
  169. this->data=this->forward();
  170. // 这段代码就一行,参考下别的类是怎么写的呢?
  171. // 在这里补全
  172. }
  173. std::shared_ptr<tensor::Tensor> forward() override {
  174. // features: (batch_size x input_features)
  175. auto features = this->objects[0];
  176. // weights: (input_features x output_features)
  177. auto weights = this->objects[1];
  178. auto m = features->data->shape[0];
  179. auto k = features->data->shape[1];
  180. auto n = weights->data->shape[1];
  181. // std::cout << m << " " << n << " " << k << std::endl;
  182. // output: (batch_size x output_features)
  183. auto shape = {m, n};
  184. auto outNode = std::make_shared<tensor::Tensor>(shape);
  185. // 实际上你需要补全的是arith::mm函数,快去找找它在哪里
  186. // 其余部分不需要动
  187. arith::mm(features->data->data, weights->data->data, outNode->data, m, k, n);
  188. return outNode;
  189. }
  190. // 辅助函数:矩阵转置
  191. template<typename T>
  192. std::vector<T> transpose(const std::vector<T>& mat, size_t rows, size_t cols) {
  193. std::vector<T> result(rows * cols);
  194. for (size_t i = 0; i < rows; ++i) {
  195. for (size_t j = 0; j < cols; ++j) {
  196. result[j * rows + i] = mat[i * cols + j];
  197. }
  198. }
  199. return result;
  200. }
  201. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  202. auto features = this->objects[0];
  203. auto weights = this->objects[1];
  204. // gradient.shape[0] == features.shape[0]
  205. // gradient.shape[1] == weights.shape[1]
  206. auto grad_features_shape = {gradient->shape[0], weights->data->shape[0]};
  207. auto grad_features = std::make_shared<tensor::Tensor>(grad_features_shape);
  208. auto grad_weights_shape = {features->data->shape[1], gradient->shape[1]};
  209. auto grad_weights = std::make_shared<tensor::Tensor>(grad_weights_shape);
  210. // 计算输入特征的梯度
  211. // grad_features = gradient * weights^T
  212. auto weights_transposed = transpose(weights->data->data, weights->data->shape[0], weights->data->shape[1]);
  213. size_t m = gradient->shape[0];
  214. size_t k = weights->data->shape[1];
  215. size_t n = weights->data->shape[0];
  216. arith::mm(gradient->data, weights_transposed, grad_features->data, m, k, n);
  217. // 计算权重的梯度
  218. // grad_weights = features^T * gradient
  219. auto features_transposed = transpose(features->data->data, features->data->shape[0], features->data->shape[1]);
  220. m = features->data->shape[1];
  221. k = features->data->shape[0];
  222. n = gradient->shape[1];
  223. arith::mm(features_transposed, gradient->data, grad_weights->data, m, k, n);
  224. return {grad_features, grad_weights};
  225. }
  226. }; //class Linear
  227. class ReLU: public FunctionNode {
  228. public:
  229. ReLU(std::shared_ptr<Node> a) : FunctionNode(a) {
  230. // 补全这里
  231. this->data = this->forward();
  232. }
  233. std::shared_ptr<tensor::Tensor> forward() override {
  234. // x: a Node with shape (batch_size x num_features)
  235. auto outNode = std::make_shared<tensor::Tensor>(this->objects[0]->data->shape);
  236. // 补全这里,调用arith::vector_scalar_max
  237. arith::vector_scalar_max(this->objects[0]->data->data, outNode->data, 0.0f);
  238. return outNode;
  239. }
  240. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  241. auto grads = std::make_shared<tensor::Tensor>(this->objects[0]->data->shape);
  242. // 补全这里,一个for循环
  243. for (size_t i = 0; i < grads->size; ++i) {
  244. if (this->objects[0]->data->data[i] > 0) {
  245. grads->data[i] = gradient->data[i];
  246. } else {
  247. grads->data[i] = 0;
  248. }
  249. }
  250. return {grads};
  251. }
  252. }; // class ReLU
  253. class Loss: public FunctionNode {
  254. public:
  255. bool used = false;
  256. public:
  257. Loss(std::shared_ptr<Node> a, std::shared_ptr<Node> b) : FunctionNode(a, b) {}
  258. };
  259. class SquareLoss: public Loss {
  260. public:
  261. SquareLoss(std::shared_ptr<Node> a, std::shared_ptr<Node> b): Loss(a, b) {
  262. // 补全这里的代码
  263. this->data = this->forward();
  264. }
  265. std::shared_ptr<tensor::Tensor> forward() {
  266. // a: a Node with shape (batch_size x dim)
  267. // b: a Node with shape (batch_size x dim)
  268. // 这个简单,就是要注意返回的res需要是一个tensor就行
  269. auto a = this->objects[0]->data;
  270. auto b = this->objects[1]->data;
  271. float sum_squared_diff = 0.0f;
  272. for (size_t i = 0; i < a->size; ++i) {
  273. float diff = a->data[i] - b->data[i];
  274. sum_squared_diff += diff * diff;
  275. }
  276. // 修改下面的代码
  277. float square_loss = sum_squared_diff / a->size;
  278. std::vector<size_t> res_shape = {1};
  279. auto res = std::make_shared<tensor::Tensor>(res_shape);
  280. res->data[0] = square_loss;
  281. return res;
  282. }
  283. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  284. float g = gradient->data[0];
  285. auto a = this->objects[0];
  286. auto b = this->objects[1];
  287. auto grad_a = std::make_shared<tensor::Tensor>(a->data->shape);
  288. auto grad_b = std::make_shared<tensor::Tensor>(b->data->shape);
  289. // 补全下面的代码
  290. size_t n = a->data->size;
  291. for (size_t i = 0; i < n; ++i) {
  292. float diff = a->data->data[i] - b->data->data[i];
  293. grad_a->data[i] = g * (2.0f / n) * diff;
  294. grad_b->data[i] = -g * (2.0f / n) * diff;
  295. }
  296. return {grad_a, grad_b};
  297. }
  298. }; // class SquareLoss
  299. std::shared_ptr<tensor::Tensor> log_softmax(std::shared_ptr<tensor::Tensor> logits);
  300. class SoftmaxLoss: public Loss {
  301. public:
  302. SoftmaxLoss(std::shared_ptr<Node> logits, std::shared_ptr<Node> labels): Loss(logits, labels) {
  303. this->data = this->forward();
  304. }
  305. std::shared_ptr<tensor::Tensor> forward() {
  306. // 我们已经帮你写好log_softmax
  307. auto log_probs = log_softmax(this->objects[0]->data);
  308. // 补全下面的代码,计算softmax loss
  309. auto labels = this->objects[1]->data;
  310. // 样本数量
  311. auto batch_size = log_probs->shape[0];
  312. // 类别数量
  313. auto num_classes = log_probs->shape[1];
  314. // 初始化损失值
  315. float loss = 0.0f;
  316. // 计算 softmax 损失
  317. for (size_t i = 0; i < batch_size; ++i) {
  318. for (size_t j = 0; j < num_classes; ++j) {
  319. // 计算索引
  320. size_t idx = i * num_classes + j;
  321. // 累加损失
  322. loss += labels->data[idx] * log_probs->data[idx];
  323. }
  324. }
  325. // 求平均损失
  326. loss = -loss / batch_size;
  327. std::vector<size_t> res_shape = {1};
  328. auto res = std::make_shared<tensor::Tensor>(res_shape);
  329. res->data[0] = loss;
  330. return res;
  331. }
  332. std::vector<std::shared_ptr<tensor::Tensor>> backward(std::shared_ptr<tensor::Tensor> gradient) override {
  333. auto log_probs = log_softmax(this->objects[0]->data);
  334. std::vector<float> probs(log_probs->data.size());
  335. for (size_t i = 0; i < log_probs->data.size(); ++i) {
  336. probs[i] = std::exp(log_probs->data[i]);
  337. }
  338. auto labels = this->objects[1]->data;
  339. auto batch_size = log_probs->shape[0];
  340. auto num_classes = log_probs->shape[1];
  341. auto grad_logits = std::make_shared<tensor::Tensor>(log_probs->shape);
  342. auto grad_labels = std::make_shared<tensor::Tensor>(labels->shape);
  343. // 补全下面的代码
  344. for (size_t i = 0; i < batch_size; ++i) {
  345. for (size_t j = 0; j < num_classes; ++j) {
  346. size_t idx = i * num_classes + j;
  347. // 根据公式计算梯度
  348. grad_logits->data[idx] = (probs[idx] - labels->data[idx]) / batch_size;
  349. }
  350. }
  351. std::fill(grad_labels->data.begin(), grad_labels->data.end(), 0.0f);
  352. return {grad_logits, grad_labels};
  353. }
  354. }; // class SoftmaxLoss
  355. std::vector<std::shared_ptr<tensor::Tensor>> gradients(std::shared_ptr<Loss> loss, std::vector<std::shared_ptr<Node>> parameters);
  356. }