文章

机器学习

Linux shell 指令相关学习

这是一个手搓的DNN神经网络,就是为了学习神经网络的原理,虽然它失败了,但是我也学习到了一些东西(参数更新的实现要在神经元上实现;神经元真正的存储数据,其它对象想用就读,最好不要再存储一遍),写在这里供后续修改(没有时间了)。

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
# import numpy as np
import enum
import random
import math


def matrix_muti(A: list[list], B: list[list]):
    if not len(A) or not len(B) or not len(A[0]) or not len(B[0]):
        raise "A or B 不能为空"
    if len(A[0]) != len(B):
        e_message = f"Matrix with shape {len(A)},{len(A[0])} can't * Matrix with shape {len(B)},{len(B[0])}"
        print(e_message)
        raise "Matrix_muti Error"
    
    len_A = len(A)
    len_B0 = len(B[0])
    res = [[0 for i in range(len_B0)] for _ in range(len_A)]
    for i in range(len_A):
        for j in range(len_B0):
            for idx in range(len(A)):
                res[i][j] += A[i][idx] * B[idx][j] 
    return res


def T(A: list[list]):
    """
        返回A.T
    """
    res = [[] for _ in range(len(A[0]))]
    for i in range(len(A)):
        for j in range(len(A[0])):
            res[j].append(A[i][j])
    return res


def sigmoid(x):
        # sigmoid 激活函数
        return 1 / (1 + math.exp(-x))
    
def sigmoid_derivative(output):
    # sigmoid 导数
    return output * (1 - output)


class Neuron:

    def __init__(self, is_random_w: bool, dimention: int, W=None) -> None:
        self.W = None   # 权重 列向量
        self.new_W = None # 更新的新权重
        self.tmp = None   # 更新时使用,用于上一层计算
        # self.input = None   # 输入    行向量
        self.output = None  # 输出
        self.this_layer = None  # 指向本层
        self.last_layer = None  # 指向上一层
        self.next_layer = None  # 指向下一层
        
        if is_random_w:
            self.random_w(dimenstion=dimention)

    def random_w(self, dimenstion: int):
        self.W = [[random.randint(0, 5)] for _ in range(dimenstion)]
        self.new_W = [[0] for _ in range(dimenstion)]

    def get_neural_W(self):
        return self.W

    def set_w(self, W):
        self.W = W

    def update_all(self):
        pass

    def update_weight(self, y_std, step):
        if self.this_layer.type == NeuralLayerType.OUTPUT:
            update_func = self.update_whj
        elif self.this_layer.type == NeuralLayerType.MIDDLE:
            update_func = self.update_wih
        else:
            return
        for index in range(len(self.W[0])):
            update_func(y_std, index, step)

    def update_whj(self, yj_std, j, step):
        yj_pre = self.output
        b_j = self.last_layer.neurons[j].output
        self.tmp = (yj_std - yj_pre) * yj_pre * (1 - yj_pre)
        delta = step * self.tmp * b_j
        # self.new_W[j] -= delta
        self.W[j][0] -= delta
    
    def update_wih(self, pre, i, step):
        xi = self.last_layer.neurons[i].output
        eh = 0
        for j in range(len(self.next_layer.neurons)):
            nx_nueron = self.next_layer.neurons[j]
            eh += nx_nueron.tmp * nx_nueron.W[j][0]
        self.tmp = eh * self.output * (1 - self.output)
        delta = step * self.tmp * xi
        # self.new_W[i] -= delta
        self.W[i][0] -= delta


class NeuralLayerType(enum.Enum):
    INPUT = 0
    MIDDLE = 1
    OUTPUT = 2


class NeuralLayer():

    def __init__(self, layer_type: NeuralLayerType, num: int) -> None:
        self.type = layer_type
        self.next_layer = None
        self.last_layer = None
        # self.input = None
        # self.output = None
        self.W = None
        self.neurons = None
        self.neurons_len = num

    def get_layer_W(self):
        """
            从本层的神经元中,获取权重矩阵
        """
        W = [[] for _ in range(len(self.neurons[0].get_neural_W()))]
        for i in range(len(self.neurons)):
            neural_W = self.neurons[i].get_neural_W()
            for j in range(len(neural_W)):
                W[j].append(neural_W[j][0])
        return W
    
    def set_w(self, W):
        """
            将权重赋值给神经元
        """
        for i in range(len(self.neurons)):
            self.neurons[i].set_w(W[i])
    
    def gen_neurals(self):
        # 是否随机分配权重 有多少权重
        self.neurons = [Neuron(is_random_w=True, dimention= len(self.last_layer.neurons) if self.last_layer else 1) 
                        if self.W == None else Neuron(W=self.W[i]) for i in range(self.neurons_len)]
        for i in range(len(self.neurons)):
            self.neurons[i].last_layer = self.last_layer
            self.neurons[i].this_layer = self
            self.neurons[i].next_layer = self.next_layer
            

    # def set_neural_output(self, output):
    #     """
    #         将本层计算的输出矩阵,分发给每个神经元
    #     """
    #     for i in range(len(self.neurals)):
    #         self.neurals[i].output = output[i]

    def cacul(self):
        """
            本层的input已经设置好了,权重W也设置好了,使用这两个计算output并存储
        """
        self.W = self.get_layer_W()       # 从神经元中获取权重
        self.output = matrix_muti(self.input, self.W)   # 矩阵相乘 TODO
        for i in range(len(self.neurons)):
            self.neurons[i].output = self.output[0][i]
        # tmp = self.output
        # self.output = []
        # for i in range(len(tmp)):
        #     self.output.append(tmp[i][0])
        # self.set_neural_output(*self.output) # 把输出更新给神经元,这一步似乎可以没有


class NeuralNetwork():

    def __init__(self, layers_desc: list[tuple[NeuralLayerType, int]], W=None) -> None:
        self.layers = [NeuralLayer(desc[0], desc[1]) for desc in layers_desc]
        for i in range(len(layers_desc)):
            if i == 0:
                self.layers[i].last_layer = None
                self.layers[i].next_layer = self.layers[i+1]
                continue
            if i == len(layers_desc) - 1:
                self.layers[i].last_layer = self.layers[i-1]
                self.layers[i].next_layer = None
                continue
            self.layers[i].last_layer = self.layers[i-1]
            self.layers[i].next_layer = self.layers[i+1]
        if W :
            # 将权重赋给各个层的神经元
            pass
        else:
            # 随机权重
            for i in range(len(self.layers)):
                self.layers[i].gen_neurals()

    def input(self, vector):
        """
            将数据放到输入层
            param vector: 输入列向量
        """
        self.layers[0].input = [vector]
        for i in range(len(self.layers[0].neurons)):
            self.layers[0].neurons[i].output = vector[i]

    def forward(self):
        """
            前向传播,返回输出层结果
        """
        curr_layer = self.layers[0]
        while curr_layer != None:
            if curr_layer.type == NeuralLayerType.OUTPUT:
                curr_layer.cacul()
            elif curr_layer.type != NeuralLayerType.INPUT:
                # 1. 计算本层的输出
                curr_layer.cacul()
                # 2. 传递给下一层
                curr_layer.next_layer.input = curr_layer.output
            else:
                curr_layer.next_layer.input = curr_layer.input
            # 3. 进入下一层
            curr_layer = curr_layer.next_layer

        return self.layers[-1].output

    def back_forward(self, label, predict_label, step, by_layer=True):
        """
        反向传播,更新每层权重
        param step: 学习步长 (learning rate)
        param by_layer: 是否逐层更新
        """
        # 1. 计算输出层的误差
        # output_layer = self.layers[-1]
        # error = [[label[i] - predict_label[i][0]] for i in range(len(label))]  # 误差
        curr_layer = self.layers[-1]

        # 逐层反向传播
        while curr_layer != self.layers[0]:
            index = 0
            for nueron in curr_layer.neurons:
                if curr_layer.type == NeuralLayerType.OUTPUT:
                    y_std = label[index]
                else:
                    y_std = None
                nueron.update_weight(y_std, step)
            curr_layer = curr_layer.last_layer

    def train(self, data_set, label, round, step):
        """
            应当充当整个训练过程的总控程序
            param data_set: 需要训练的数据集, many data
            param round: 训练轮数
            param step: 训练步长
        """
        # 1. round 轮次训练
        for _ in range(round):
            # 2. 针对每个数据进行训练
            for i in range(len(data_set)):
                self.input(data_set[i])
                output = self.forward()
                self.back_forward(label=label[i], predict_label=output, step=step, by_layer=True)


    def predict(self, test_data):
        # 训练好后的预测
        self.input(test_data)
        return self.forward()


if __name__ == "__main__":
    # 测试前向传播效果
    nn = NeuralNetwork([(NeuralLayerType.INPUT, 5), (NeuralLayerType.MIDDLE, 6), (NeuralLayerType.OUTPUT, 1)])
    test_data = [
        [1, 1, 1 ,1 ,1],
        [2, 2, 2, 2, 2],
        [3, 3, 3, 3, 3],
        [4, 4, 4, 4, 4],
        [5, 5, 5, 5, 5],
        [6, 6, 6, 6, 6],
        [7, 7, 7, 7, 7]
    ]
    test_label = [[5, 10, 15, 20, 25, 30, 35]]
    test_label = T(test_label)
    nn.train(data_set=test_data, label=test_label, round=10, step=0.1)

    print(nn.predict([2, 1, 5, 2, 1]))

本文由作者按照 CC BY 4.0 进行授权