package main

import (
	"bufio"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"

	"gorgonia.org/gorgonia"
	"gorgonia.org/tensor"
)

// Константы
const (
	trainMode        = "train"
	testMode         = "test"
	dataPath         = "texts.txt"
	embeddingDim     = 50
	numEpochs        = 10
	learningRate     = 0.01
	numHiddenNeurons = 100
)

// Структура для нейронной сети
type neuralNet struct {
	graph  *gorgonia.ExprGraph
	w1, w2 *gorgonia.Node
}

// Загружаем текстовые данные из файла
func loadTexts(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var texts []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		texts = append(texts, scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return texts, nil
}

// Функция для токенизации текста
func tokenize(text string) []string {
	return strings.Fields(strings.ToLower(text))
}

// Построение словаря для текстов
func buildVocab(texts []string) map[string]int {
	vocab := make(map[string]int)
	for _, text := range texts {
		tokens := tokenize(text)
		for _, token := range tokens {
			if _, exists := vocab[token]; !exists {
				vocab[token] = len(vocab)
			}
		}
	}
	return vocab
}

// Преобразует текст в векторное представление
func textToVector(text string, wordIndex map[string]int) []float64 {
	tokens := tokenize(text)
	vector := make([]float64, len(wordIndex))
	for _, token := range tokens {
		if idx, ok := wordIndex[token]; ok {
			vector[idx] = 1
		}
	}
	return vector
}

// Создание новой нейронной сети
func newNeuralNet(inputSize, hiddenSize, outputSize int) *neuralNet {
	g := gorgonia.NewGraph()

	w1 := gorgonia.NewMatrix(g, tensor.Float64, gorgonia.WithShape(inputSize, hiddenSize), gorgonia.WithName("w1"), gorgonia.WithInit(gorgonia.GlorotN(1.0)))
	w2 := gorgonia.NewMatrix(g, tensor.Float64, gorgonia.WithShape(hiddenSize, outputSize), gorgonia.WithName("w2"), gorgonia.WithInit(gorgonia.GlorotN(1.0)))

	return &neuralNet{
		graph: g,
		w1:    w1,
		w2:    w2,
	}
}

// Прямой проход через сеть
func (nn *neuralNet) forward(x *gorgonia.Node) (*gorgonia.Node, error) {
	l1, err := gorgonia.Mul(x, nn.w1)
	if err != nil {
		return nil, err
	}
	l1Act := gorgonia.Must(gorgonia.Rectify(l1))

	yPred, err := gorgonia.Mul(l1Act, nn.w2)
	if err != nil {
		return nil, err
	}

	return yPred, nil
}

// Обработка ошибок
func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Входная точка программы
func main() {
	if len(os.Args) < 2 {
		log.Fatal("Не указан режим работы: ожидалось train или test")
	}
	mode := os.Args[1]

	texts, err := loadTexts(dataPath)
	check(err)

	vocab := buildVocab(texts)
	wordIndex := make(map[string]int, len(vocab))
	for k, v := range vocab {
		wordIndex[k] = v
	}

	switch mode {
	case trainMode:
		train(texts, wordIndex)
	case testMode:
		test(wordIndex)
	default:
		log.Fatal("Неизвестный режим: ", mode)
	}
}

// Функция для обучения модели
func train(texts []string, wordIndex map[string]int) {
	net := newNeuralNet(len(wordIndex), numHiddenNeurons, len(wordIndex))
	solver := gorgonia.NewRMSPropSolver(gorgonia.WithLearnRate(learningRate))

	totalInputs := len(texts)
	data := make([][][]float64, totalInputs)
	for i, text := range texts {
		xVal := textToVector(text, wordIndex)
		yVal := xVal // Для демонстрации используем текст как целевую переменную
		data[i] = [][]float64{xVal, yVal}
	}

	for epoch := 0; epoch < numEpochs; epoch++ {
		rand.Shuffle(totalInputs, func(i, j int) { data[i], data[j] = data[j], data[i] })

		totalLoss := 0.0
		for _, sample := range data {
			xVal := sample[0]
			yVal := sample[1]

			xTensor := tensor.New(tensor.WithShape(len(wordIndex)), tensor.WithBacking(xVal))
			x := gorgonia.NewVector(net.graph, tensor.Float64, gorgonia.WithShape(len(wordIndex)), gorgonia.WithValue(xTensor))

			yTensor := tensor.New(tensor.WithShape(len(wordIndex)), tensor.WithBacking(yVal))
			y := gorgonia.NewVector(net.graph, tensor.Float64, gorgonia.WithShape(len(wordIndex)), gorgonia.WithValue(yTensor))

			yPred, err := net.forward(x)
			check(err)

			// Вычисляем потерю и градиенты
			losses := gorgonia.Must(gorgonia.Square(gorgonia.Must(gorgonia.Sub(y, yPred))))
			cost := gorgonia.Must(gorgonia.Mean(losses))

			// Получаем градиенты
			grads, err := gorgonia.Grad(cost, net.w1, net.w2)
			check(err)

			// Создаем машину для вычисления
			machine := gorgonia.NewTapeMachine(net.graph, gorgonia.BindDualValues(net.w1, net.w2))
			defer machine.Close()

			// Запуск вычислений в машине
			check(machine.RunAll())

			// Преобразуем Nodes в ValueGrads для оптимизатора
			valGrads := gorgonia.NodesToValueGrads(grads)

			// Обновляем весовые параметры
			check(solver.Step(valGrads))

			totalLoss += cost.Value().Data().(float64)
			machine.Reset()
		}

		fmt.Printf("Epoch %d: Loss %v\n", epoch, totalLoss/float64(len(data)))
	}
}

// Функция для тестирования модели
func test(wordIndex map[string]int) {
	reader := bufio.NewReader(os.Stdin)
	net := newNeuralNet(len(wordIndex), numHiddenNeurons, len(wordIndex))

	for {
		fmt.Print("Введите запрос: ")
		query, _ := reader.ReadString('\n')
		query = strings.TrimSpace(query)

		queryVector := textToVector(query, wordIndex)
		xTensor := tensor.New(tensor.WithShape(len(wordIndex)), tensor.WithBacking(queryVector))
		x := gorgonia.NewVector(net.graph, tensor.Float64, gorgonia.WithShape(len(wordIndex)), gorgonia.WithValue(xTensor))

		yPred, err := net.forward(x)
		check(err)

		// Преобразуйте предсказание yPred в читабельный ответ
		fmt.Printf("Предсказание (вектор): %v\n", yPred.Value().Data())
		fmt.Println("Ответ: пока не обучена использовать предсказание.")
	}
}



2024/10/14 22:03:51 Не указан режим работы: ожидалось train или test


сделай так чтобы надо было самому писать