Возьмите простую RNN в качестве примера, чтобы разобраться в процессе обучения нейронной сети.

Нейронные сети

Эта статья законченаJizhi Academy «Вводный курс PyTorch: глубокое обучение на Torch — обработка естественного языка (NLP)»После серии уроков.

Эта задача состоит в том, чтобы предсказать символы (числа), и позволить нейронной сети найти закон следующих чисел.

012
00112
0001112
000011112
00000111112

Когда нам дан набор данных (например,0000001), пусть нейронная сеть предсказывает, каким должно быть следующее число

1. Создайте архитектуру нейронной сети

Мы строим класс RNN

class simpleRNN(nn.Module):
    def __init():
        ...
    def forword():
        ...
    def initHidden():
        ...

где функцияinitHiddenРоль заключается в инициализации вектора скрытого слоя.

def initHidden(self):
    # 对隐含单元的初始化
    # 注意尺寸是: layer_size, batch_size, hidden_size
    return Variable(torch.zeros(self.num_layers, 1, self.hidden_size))

Используйте функцию инициализации

init используется для построения структуры нейронной сети, входное измерение сети, выходное измерение, размерность и номер скрытого слоя, модель, которую необходимо использовать в процессе, и т. д. — все это определено в в этом.

вnnЭто модуль, который поставляется непосредственно с pytorch и содержит встроенныеEmbedding ,RNN, Linear, logSoftmaxи другие модели, которые можно использовать напрямую.

# 引入pytorch 中的 nn(模型模块)
import torch.nn as nn
def __init__(self, input_size, hidden_size, output_size, num_layers = 1):
        # 定义
        super(SimpleRNN, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        # 一个embedding层
        self.embedding = nn.Embedding(input_size, hidden_size)
        # PyTorch的RNN模型,batch_first标志可以让输入的张量的第一个维度表示batch指标
        self.rnn = nn.RNN(hidden_size, hidden_size, num_layers, batch_first = True)
        # 输出的全链接层
        self.linear = nn.Linear(hidden_size, output_size)
        # 最后的logsoftmax层
        self.softmax = nn.LogSoftmax()

Использовать форвардную функцию как рабочий процесс нейронной сети

Процесс работы также хорошо понятен, то есть ввод шаг за шагом проходит через слой внедрения, слой rnn, линейный слой и слой softmax.

  • embedding (встраивание слоя): используется для встраивания входного слоя в скрытый слой. Процесс примерно состоит в том, чтобы преобразовать входной вектор в горячее кодирование, а затем закодировать его в вектор измерения hidden_size.
  • Слой RNN: после слоя модели RNN.
  • Линейный слой (полный связующий слой): сопоставляет все размеры вектора скрытого слоя с выходными данными один за другим, что можно понимать как общую информацию.
  • softmax: нормализовать данные
 # 运算过程
def forward(self, input, hidden):
        # size of input:[batch_size, num_step, data_dim]
        
        # embedding层:
        # 从输入到隐含层的计算
        output = self.embedding(input, hidden)
        # size of output:[batch_size, num_step, hidden_size]
        
        output, hidden = self.rnn(output, hidden)
        # size of output:[batch_size, num_step, hidden_size]
      
        # 从输出output中取出最后一个时间步的数值,注意output输出包含了所有时间步的结果
        output = output[:,-1,:]
        # size of output:[batch_size, hidden_size]
        
        # 全链接层
        output = self.linear(output)
        # output尺寸为:batch_size, output_size
        
        # softmax层,归一化处理
        output = self.softmax(output)
         # size of output:batch_size, output_size
        return output, hidden

В середине результатов обучения РНН идет спецоперация

output = output[:, -1 ,:]

Выходной размер равен [batch_size, step, hidden_size], этот шаг предназначен для сохранения только последнего количества данных во втором временном шаге измерения. Поскольку характеристикой RNN является память, данные последнего шага содержат информацию обо всех предыдущих шагах. Так что здесь вам нужно взять только последнее число

используйте этот init и forword

initиforwardвсе на питонеclassДве функции, встроенные в .

  • если вы определите__init__, то он будет автоматически запускаться при создании экземпляра классаinitТело функции и параметры экземпляра:initаргументы функции
  • если вы определитеforward, то когда вы выполните этот класс, он будет автоматически выполнятьсяforwardфункция
# 实例化类simpleRNN,此时执行__init__函数
rnn = simpleRNN(input_size = 4, hidden_size = 1, output_size = 3, num_layers = 1)

# 使用类simpleRNN
output, hidden = rnn(input, hidden)

Тогда выполнение форварда эквивалентно тренировочному процессу: ввод -> вывод

2. Вы можете начать обучение

Первый заключается в построении损失函数и优化器

Мощный pytorch поставляется с общими функциями потерь и моделями оптимизатора. Одна команда делает все.

criterion = torch.nn.NLLLoss()
optimizer = torch.optim.Adam(rnn.parameters(), lr = 0.001)

损失函数criterion: используется для записи тренировочных потерь, все веса будут скорректированы в соответствии со значением потерь на каждом шаге. используется здесьNLLLossФункция потерь — это относительно простой расчет потерь, который вычисляет абсолютную разницу между фактическим значением и прогнозируемым значением.

# output是预测值,y是真实值
loss = criterion(output, y)

优化器optimizer: Итеративное выполнение тренировочного процесса. Включая обратное распространение градиента и очистку градиента. Входящие параметры являются параметрами нейронной сетиrnn.parameters()и скорость обученияlr

# 梯度反传,调整权重
optimizer.zero_grad()
# 梯度清空
optimizer.step()

тренировочный процесс

Ход мысли таков:

  1. Подготовьте обучающие данные, проверочные данные и тестовые данные (один набор данных для каждого набора данных представляет собой последовательность чисел)
  2. Циклическая числовая последовательность чисел, текущее число в качестве входных данных, следующее число в качестве метки (т.е. истинный результат)
  3. Каждый цикл проходит через сеть rnn
  4. Рассчитайте потери t_loss для каждой группы и запишите
  5. Оптимизатор оптимизирует параметры
  6. Повторите шаги обучения от 1 до 5 n раз, и n настраивается

Подготовка обучающих данных не входит в рамки этого обсуждения, поэтому обработанные результаты приведены здесь непосредственно следующим образом.

train_set = [[3, 0, 0, 1, 1, 2],
            [3, 0, 1, 2],
            [3, 0, 0, 0, 1, 1, 1, 2],
            [3, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2]
            ...]

начать обучение

# 重复进行50次试验
num_epoch = 50
loss_list = []
for epoch in range(num_epoch):
    train_loss = 0
    # 对train_set中的数据进行随机洗牌,以保证每个epoch得到的训练顺序都不一样。
    np.random.shuffle(train_set)
    # 对train_set中的数据进行循环
    for i, seq in enumerate(train_set):
        loss = 0
        # 对每一个序列的所有字符进行循环
        for t in range(len(seq) - 1):
            #当前字符作为输入
            x = Variable(torch.LongTensor([seq[t]]).unsqueeze(0))
            # x尺寸:batch_size = 1, time_steps = 1, data_dimension = 1
            # 下一个字符作为标签
            y = Variable(torch.LongTensor([seq[t + 1]]))
            # y尺寸:batch_size = 1, data_dimension = 1
            output, hidden = rnn(x, hidden) #RNN输出
            # output尺寸:batch_size, output_size = 3
            # hidden尺寸:layer_size =1, batch_size=1, hidden_size
            loss += criterion(output, y) #计算损失函数
        loss = 1.0 * loss / len(seq) #计算每字符的损失数值
        optimizer.zero_grad() # 梯度清空
        loss.backward() #反向传播
        optimizer.step() #一步梯度下降
        train_loss += loss #累积损失函数值
        # 把结果打印出来
        if i > 0 and i % 500 == 0:
            print('第{}轮, 第{}个,训练Loss:{:.2f}'.format(epoch, i, train_loss.data.numpy()[0] / i))
    loss_list.appand(train_loss)
            

здесьlossЭто потери для каждого цикла обучения (эпохи).На самом деле, как бы ни проводилось обучение, потери здесь будут уменьшаться, потому что нейросеть сделает конечный результат максимально приближенным к реальным данным, поэтому потери обучающего набора нельзя использовать для оценки того, насколько хорошо обучена модель.

В самом процессе обучения мы будем помещать полученную модель в校验集Чтобы подсчитать потери, результат более объективен.

Расчет потерь проверочного набора точно такой же, как и для обучающего набора, за исключением того, чтоtrain_setзаменяетсяvalid_set, и нет необходимости оптимизировать параметры по результатам, что было сделано на шаге обучения.Функция проверочного набора - увидеть эффект обучения модели:

for epoch in range(num_epoch):
    # 训练步骤
    ...
    valid_loss = 0
    for i, seq in enumerate(valid_set):
        # 对每一个valid_set中的字符串做循环
        loss = 0
        outstring = ''
        targets = ''
        hidden = rnn.initHidden() #初始化隐含层神经元
        for t in range(len(seq) - 1):
            # 对每一个字符做循环
            x = Variable(torch.LongTensor([seq[t]]).unsqueeze(0))
            # x尺寸:batch_size = 1, time_steps = 1, data_dimension = 1
            y = Variable(torch.LongTensor([seq[t + 1]]))
            # y尺寸:batch_size = 1, data_dimension = 1
            output, hidden = rnn(x, hidden)
            # output尺寸:batch_size, output_size = 3
            # hidden尺寸:layer_size =1, batch_size=1, hidden_size               
            loss += criterion(output, y) #计算损失函数
        loss = 1.0 * loss / len(seq)
        valid_loss += loss #累积损失函数值
#     # 打印结果
    print('第%d轮, 训练Loss:%f, 校验Loss:%f, 错误率:%f'%(epoch, train_loss.data.numpy() / len(train_set),valid_loss.data.numpy() / len(valid_set),1.0 * errors / len(valid_set)))

Основываясь на выводе потерь проверочного набора, мы можем построить график окончательного изменения потерь.

3. Проверьте эффект предсказания модели

Создайте данные, чтобы проверить, может ли модель угадать следующую цифру текущей цифры. Насколько высока вероятность успеха Первый заключается в построении данных, построении последовательности чисел длиной от 0 до 20 соответственно.

for n in range(20):
    inputs = [0] * n + [1] * n

Затем проверьте каждую последовательность

for n in range(20):
    inputs = [0] * n + [1] * n
    
    outstring = ''
    targets = ''
    diff = 0
    hiddens = []
    hidden = rnn.initHidden()
    for t in range(len(inputs) - 1):
        x = Variable(torch.LongTensor([inputs[t]]).unsqueeze(0))
        # x尺寸:batch_size = 1, time_steps = 1, data_dimension = 1
        y = Variable(torch.LongTensor([inputs[t + 1]]))
        # y尺寸:batch_size = 1, data_dimension = 1
        output, hidden = rnn(x, hidden)
        # output尺寸:batch_size, output_size = 3
        # hidden尺寸:layer_size =1, batch_size=1, hidden_size
        hiddens.append(hidden.data.numpy()[0][0])
        #mm = torch.multinomial(output.view(-1).exp())
        mm = torch.max(output, 1)[1][0]
        outstring += str(mm.data.numpy()[0])
        targets += str(y.data.numpy()[0])
         # 计算模型输出字符串与目标字符串之间差异的字符数量
        diff += 1 - mm.eq(y)
    # 打印出每一个生成的字符串和目标字符串
    print(outstring)
    print(targets)
    print('Diff:{}'.format(diff.data.numpy()[0]))

Конечный результат

[0, 1, 2]
[0, 1, 2]
Diff: 0
[0, 0, 1, 1, 2]
[0, 0, 1, 1, 2]
Diff: 0
[0, 0, 0, 1, 1, 1, 2]
[0, 0, 0, 1, 1, 1, 2]
Diff: 0
...
# 结果不一一列出,大家可以自行尝试

Суммировать

Нейронные сети можно понимать как процесс, позволяющий компьютерам использовать различные математические средства для поиска закономерностей в куче данных. Мы можем понять внутреннюю работу нейронных сетей, анализируя некоторые простые задачи. Столкнувшись со сложными задачами, просто передайте данные модели, и она сделает все возможное, чтобы дать вам хороший результат.

Эта статья законченаJizhi Academy «Вводный курс PyTorch: глубокое обучение на Torch — обработка естественного языка (NLP)»После серии уроков. Также в курсе оlstm, 翻译任务实操Я вернусь снова, когда у меня будет более базовое и богатое знание.