Я новичок в языке программирования Julia и все еще изучаю его, пишу код, который я уже написал на Python (или, по крайней мере, опробовал на Python).
Есть статья, в которой объясняется, как сделать очень простую нейронную сеть: https://medium.com/technology-invention-and-more/how-to-build-a-simple-neural-network-in-9-lines-of-python-code-cc8f23647ca1.
Я попробовал код из этой статьи на Python, и он работает нормально. Однако я раньше не использовал линейную алгебру в Python (например, точку). Сейчас пытаюсь перевести этот код на Джулию, но кое-чего не могу понять. Вот мой код Джулии:
using LinearAlgebra
synaptic_weights = [-0.16595599, 0.44064899, -0.99977125]::Vector{Float64}
sigmoid(x) = 1 / (1 + exp(-x))
sigmoid_derivative(x) = x * (1 -x)
function train(training_set_inputs, training_set_outputs, number_of_training_iterations)
global synaptic_weights
for (iteration) in 1:number_of_training_iterations
output = think(training_set_inputs)
error = training_set_outputs .- output
adjustment = dot(transpose(training_set_inputs), error * sigmoid_derivative(output))
synaptic_weights = synaptic_weights .+ adjustment
end
end
think(inputs) = sigmoid(dot(inputs, synaptic_weights))
println("Random starting synaptic weights:")
println(synaptic_weights)
training_set_inputs = [0 0 1 ; 1 1 1 ; 1 0 1 ; 0 1 1]::Matrix{Int64}
training_set_outputs = [0, 1, 1, 0]::Vector{Int64}
train(training_set_inputs, training_set_outputs, 10000)
println("New synaptic weights after training:")
println(synaptic_weights)
println("Considering new situation [1, 0, 0] -> ?:")
println(think([1 0 0]))
Я уже пытался инициализировать векторы (например, synaptic_weights) как:
synaptic_weights = [-0.16595599 ; 0.44064899 ; -0.99977125]
Однако код не работает. Точнее, мне непонятны 3 вещи:
Когда я пытаюсь запустить приведенный выше код Julia, я получаю следующую ошибку:
ERROR: LoadError: DimensionMismatch("first array has length 12 which does not match the length of the second, 3.")
Stacktrace:
[1] dot(::Array{Int64,2}, ::Array{Float64,1}) at C:\Users\julia\AppData\Local\Julia-1.0.3\share\julia\stdlib\v1.0\LinearAlgebra\src\generic.jl:702
[2] think(::Array{Int64,2}) at C:\Users\Viktória\Documents\julia.jl:21
[3] train(::Array{Int64,2}, ::Array{Int64,1}, ::Int64) at C:\Users\Viktória\Documents\julia.jl:11
[4] top-level scope at none:0
in expression starting at C:\Users\Viktória\Documents\julia.jl:28
Эта ошибка возникает, когда функция think(inputs) пытается вычислить скалярное произведение входных данных и synaptic_weights. В этом случае входы представляют собой матрицу 4x3, а синаптические веса - матрицу 3x1 (вектор). Я знаю, что их можно перемножить, и в результате получится матрица (вектор) 4х1. Не означает ли это, что их скалярное произведение можно вычислить?
В любом случае, этот точечный продукт можно вычислить в Python с помощью пакета numpy, поэтому я думаю, что есть определенный способ, которым его также можно вычислить в Julia.
Для скалярного произведения я также попытался создать функцию, которая принимает a и b в качестве аргументов и пытается вычислить их скалярное произведение: сначала вычисляет произведение a и b, а затем возвращает сумму результата. Я не уверен, что это хорошее решение, но код Julia не дал ожидаемого результата, когда я использовал эту функцию, поэтому я удалил его.
Не могли бы вы помочь мне с этим кодом, пожалуйста?






Вот код, адаптированный для Джулии:
sigmoid(x) = 1 / (1 + exp(-x))
sigmoid_derivative(x) = x * (1 -x)
think(synaptic_weights, inputs) = sigmoid.(inputs * synaptic_weights)
function train!(synaptic_weights, training_set_inputs, training_set_outputs,
number_of_training_iterations)
for iteration in 1:number_of_training_iterations
output = think(synaptic_weights, training_set_inputs)
error = training_set_outputs .- output
adjustment = transpose(training_set_inputs) * (error .* sigmoid_derivative.(output))
synaptic_weights .+= adjustment
end
end
synaptic_weights = [-0.16595599, 0.44064899, -0.99977125]
println("Random starting synaptic weights:")
println(synaptic_weights)
training_set_inputs = Float64[0 0 1 ; 1 1 1 ; 1 0 1 ; 0 1 1]
training_set_outputs = Float64[0, 1, 1, 0]
train!(synaptic_weights, training_set_inputs, training_set_outputs, 10000)
println("New synaptic weights after training:")
println(synaptic_weights)
println("Considering new situation [1, 0, 0] -> ?:")
println(think(synaptic_weights, Float64[1 0 0]))
Есть несколько изменений, поэтому, если некоторые из них вам непонятны, спросите, и я расскажу о них подробнее.
Самое главное, что я изменил:
Float64. (например, функции sigmoid и sigmoid_derivative определены таким образом, что они ожидают получить число в качестве аргумента, поэтому, когда мы их вызываем, после их имени добавляется . для запуска трансляции)* вместо dotКод работает примерно в 30 раз быстрее, чем исходная реализация на Python. Я не выжимал максимальную производительность из этого кода (теперь он выполняет много аллокаций, которых можно избежать), так как это потребовало бы немного переписать его логику, и я предполагаю, что вы хотели прямую повторную реализацию.
Использование глобальных переменных замедлит ваш код. Что касается вещания, обратите внимание, что выражение 1 / (1 + exp(-x)) обычно правильно оценивается Джулией, только если x является числом (не вектором). Поэтому, когда вы вызываете sigmoid, вы должны включить трансляцию, добавив . после имени функции. Я добавил еще несколько комментариев в ответ.
Я хотел бы задать еще два вопроса. Почему нельзя использовать глобальные переменные в Джулии? Вы выполняете трансляцию при вызовах
sigmoidиsigmoid_derivativeс., потому что предоставленные для них аргументы являются массивами (и эти трансляции означают выполнение заданных вычислений поэлементно)? В любом случае, я принял ваш ответ и спасибо за вашу четкую помощь!