
Федеральное агентство связи
Федеральное государственное образовательное бюджетное учреждение высшего образования «Санкт-Петербургский государственный университет телекоммуникаций им. проф. М.А.Бонч-Бруевича»
Факультет «Инфокоммуникационных сетей и систем»
Кафедра «Программной инженерии и вычислительной техники»
Отчет
Лабораторная работа №3
Дисциплина: Проектирование и архитектура программных систем
-
Студент группы
ИКПИ-93
________________
Козлов Н.С
кандидат
технических наук
_________________
Кокарев А.С.
Санкт-Петербург
2023
Оглавление
Постановка задачи
Студент самостоятельно выбирает готовый программный модуль (код) – это может быть любая компьютерная программа или её фрагмент объёмом не менее 100 и не более 500 операторов. Программа может быть сторонняя или разработанная студентами ранее.
В зависимости от субъективной оценки исходного кода, студент выбирает наиболее подходящие метрики для оценки (из представленного списка см. лекции). Количество метрик и их сложность расчёта остаётся в профессиональной компетенции студента и субъективно должны соответствовать достаточной трудоёмкости расчёта для признания преподавателем проработанности теоретической темы студентом. Студент вправе воспользоваться также любыми метриками, которые не вошли в лекционный список. Углублённое изучение выбранных метрик прерогатива студента. Работа, представленная на уровне положительной оценки, автоматически снимает тему метрик с теоретического зачёта.
Программный модуль
Для оценки был выбран модуль программы нейронной сети, написанный на С++. Данный модуль имплементирует структуру нейрона. Код модуля можно найти в листинге 1.
Листинг 1 - Код оцениваемой программы.
С++ |
// Author: Nikita Kozlov // Link: github.com/nyarstot // // This file is part of WaifuGenerator neural network. // // WaifuGenerator is free software: you can redistribute it and/or modify // it under terms of the GNU Generan Public License as published by // the free software foundation, either version 3 of License, or // (at your option) any later version. // // WaifuGenerator is distributed in the hope that it will be usefull, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with WaifuGenerator. If not, see <https://www.gnu.org/licenses/>.
#include "waifupch.h" #include "Neuron.h"
WaifuCPU::Neuron::Neuron(size_t outputAmount, size_t neuronIndex) { for (size_t i{}; i < outputAmount; i++) { m_OutputWeights.push_back(Connector());
m_OutputWeights.back().m_RedWeight = this->randomizeWeight(); m_OutputWeights.back().m_GreenWeight = this->randomizeWeight(); m_OutputWeights.back().m_BlueWeight = this->randomizeWeight(); }
m_NeuronIndex = neuronIndex; }
double _WF_CALL Neuron::randomizeWeight() { return rand() / double(RAND_MAX); }
_WF_CALL PixelRGB _WF_CALL Neuron::activationFunction(PixelRGB value) { double tanhRed = tanh(value[0]); double tanhGreen = tanh(value[1]); double tanhBlue = tanh(value[2]);
return PixelRGB(tanhRed, tanhGreen, tanhBlue); }
_WF_CALL PixelRGB _WF_CALL Neuron::activationFunctionDerivative(PixelRGB value) { double drvtRed = 1 / pow(cosh(value[0]), 2); double drvtGreen = 1 / pow(cosh(value[1]), 2); double drvtBlue = 1 / pow(cosh(value[2]), 2);
return PixelRGB(drvtRed, drvtGreen, drvtBlue); }
_WF_CALL PixelRGB _WF_CALL Neuron::sumDOW(const std::vector<Neuron>& nextLayer) { double sumRed = 0.0f; double sumGreen = 0.0f; double sumBlue = 0.0f;
if (nextLayer.size() == m_OutputWeights.size()) { for (size_t i{}; i < nextLayer.size() - 1; i++) { sumRed += m_OutputWeights[i].m_RedWeight * nextLayer[m_NeuronIndex].m_RedGradient; sumGreen += m_OutputWeights[i].m_GreenWeight * nextLayer[m_NeuronIndex].m_GreenGradient; sumBlue += m_OutputWeights[i].m_BlueWeight * nextLayer[m_NeuronIndex].m_BlueGradient; } }
if (nextLayer.size() != m_OutputWeights.size()) { for (size_t i{}; i < m_OutputWeights.size() - 1; i++) { for (size_t j{}; j < nextLayer.size() - 1; j++) { sumRed += m_OutputWeights[i].m_RedWeight * nextLayer[j].m_RedGradient; sumGreen += m_OutputWeights[i].m_RedWeight * nextLayer[j].m_GreenGradient; sumBlue += m_OutputWeights[i].m_RedWeight * nextLayer[j].m_BlueGradient; } } }
return PixelRGB(sumRed, sumGreen, sumBlue); }
void _WF_CALL Neuron::feedForward(const std::vector<Neuron>& prevLayer) { double sumRed = 0.0f; double sumGreen = 0.0f; double sumBlue = 0.0f;
for (size_t i{}; i < prevLayer.size(); i++) { sumRed = prevLayer[i].getOutputValue()[0] * prevLayer[i].m_OutputWeights[m_NeuronIndex].m_RedWeight; sumGreen = prevLayer[i].getOutputValue()[1] * prevLayer[i].m_OutputWeights[m_NeuronIndex].m_GreenWeight; sumBlue = prevLayer[i].getOutputValue()[2] * prevLayer[i].m_OutputWeights[m_NeuronIndex].m_BlueWeight; }
m_OutputValue = this->activationFunction(PixelRGB(sumRed, sumGreen, sumBlue)); }
void _WF_CALL Neuron::calcOutputGradient(PixelRGB targetValues) { double deltaRed = targetValues[0] - m_OutputValue[0]; double deltaGreen = targetValues[1] - m_OutputValue[1]; double deltaBlue = targetValues[2] - m_OutputValue[2];
PixelRGB drvtRGB = this->activationFunctionDerivative(PixelRGB(deltaRed, deltaGreen, deltaBlue));
m_RedGradient = deltaRed * drvtRGB[0]; m_GreenGradient = deltaGreen * drvtRGB[1]; m_BlueGradient = deltaBlue * drvtRGB[2]; }
void _WF_CALL Neuron::calcHiddenGradient(const std::vector<Neuron>& nextLayer) { PixelRGB dow = sumDOW(nextLayer); PixelRGB outDerivative = this->activationFunctionDerivative(m_OutputValue);
m_RedGradient = dow[0] * outDerivative[0]; m_GreenGradient = dow[1] * outDerivative[1]; m_BlueGradient = dow[2] * outDerivative[2]; }
void _WF_CALL Neuron::updateWeights(std::vector<Neuron>& prevLayer) { for (size_t i{}; i < prevLayer.size(); ++i) { Neuron& l_Neuron = prevLayer[i];
double oldDeltaRedWeight = l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaRedWeight; double oldDeltaGreenWeight = l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaGreenWeight; double oldDeltaBlueWeight = l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaBlueWeight;
double newDeltaRedWeight = C_ETA * l_Neuron.getOutputValue()[0] * m_RedGradient + C_ALPHA * oldDeltaRedWeight; double newDeltaGreenWeight = C_ETA * l_Neuron.getOutputValue()[1] * m_GreenGradient + C_ALPHA * oldDeltaGreenWeight; double newDeltaBlueWeight = C_ETA * l_Neuron.getOutputValue()[2] * m_BlueGradient + C_ALPHA * oldDeltaBlueWeight;
// Set to neuron
l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaRedWeight = newDeltaRedWeight; l_Neuron.m_OutputWeights[m_NeuronIndex].m_RedWeight += newDeltaRedWeight;
l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaGreenWeight = newDeltaGreenWeight; l_Neuron.m_OutputWeights[m_NeuronIndex].m_GreenWeight += newDeltaBlueWeight; l_Neuron.m_OutputWeights[m_NeuronIndex].m_DeltaBlueWeight = newDeltaBlueWeight; l_Neuron.m_OutputWeights[m_NeuronIndex].m_BlueWeight += newDeltaBlueWeight; } } |
В ходе выполнения работы были подсчитано количество уникальных операторов и операндов встречающихся в коде программы. Значения подсчётов представлены в таблицах 1-4.
Таблица 1 – Количество уникальных операторов.
Оператор |
Количество использований |
. |
64 |
, |
14 |
; |
68 |
: |
28 |
[] |
58 |
{} |
23 |
:: |
14 |
-> |
6 |
& |
5 |
() |
60 |
!= |
1 |
+= |
9 |
== |
1 |
= |
43 |
+ |
3 |
++ |
6 |
- |
12 |
< |
10 |
> |
10 |
include |
2 |
double |
23 |
this |
6 |
size_t |
8 |
void |
4 |
Продолжение таблицы 1.
_WF_CALL |
11 |
for |
7 |
return |
4 |
if |
2 |
const |
3 |
pow() |
3 |
cosh() |
3 |
rand() |
1 |
tanh() |
3 |
PixelRGB() |
14 |
randomizeWeight() |
4 |
activationFunction() |
2 |
activationFunctionDerivative() |
3 |
sumDOW() |
2 |
size() |
9 |
feedForward() |
1 |
getOutputValue() |
6 |
calcOutputGradient() |
1 |
calcHiddenGradient() |
1 |
updateWeights() |
1 |
Neuron |
16 |
* |
24 |
Таблица 2 – Общее количество операторов.
Всего операторов |
Количество использований |
46 |
599 |
Таблица 3 – Количество уникальных операндов.
Операнд |
Число использований |
m_OutputWeights |
25 |
outputAmount |
2 |
neuronIndex |
2 |
m_RedWeight |
7 |
m_GreenWeight |
4 |
m_BlueWeight |
4 |
m_NeuronIndex |
16 |
neuronIndex |
2 |
RAND_MAX |
1 |
value |
8 |
tanhRed |
2 |
tanhGreen |
2 |
tanhBlue |
2 |
drvtRed |
2 |
drvtGreen |
2 |
drvtBlue |
2 |
nextLayer |
13 |
sumRed |
7 |
sumGreen |
7 |
sumBlue |
7 |
targetValues |
4 |
m_OutputValue |
5 |
Таблица 4 – Общее количество операндов.
Всего операндов |
Количество использований |
22 |
126 |