使用C++编写卷积神经网络(二)

上一期介绍了用于储存图像的矩阵类,在写卷积神经网络前,先用C++实现一个三层的神经网络。以手写数字识别为例。嗯,非常经典到老掉牙的例子。

首先先定义一些基本的操作的函数:
查看矩阵信息的函数:

void show(matrix &m) { for (int i = 0; i < m.size(); i++)  cout << m.x[i] << endl; cout << "=============" << endl; }
void show_info(matrix &m)
{
	cout << "cols is " << m.cols << endl;
	cout << "rows is " << m.rows << endl;
	cout << "chans is " << m.chans << endl;
}

用于打乱数据集:

vector<int> get_a_sequence(int length)
{
	vector<int> sequence;
	for (int i = 0; i < length; i++) { sequence.push_back(i); }
	return sequence;
}

void dataset_shuffle(vector<vector<float>> &train_images, vector<vector<int>> &Labels, vector<int> &sequence)
{
	random_shuffle(sequence.begin(), sequence.end());
	vector<vector<float>> new_train_images(60000);
	vector<vector<int>> new_train_labels(60000);
	//new_train_images = train_images;
	//new_train_labels = Labels;
	for (int i = 0; i < train_images.size(); i++)
	{
		new_train_images[i] = train_images[i];
		new_train_labels[i] = Labels[i];
	}
	int index = 0;
	for (int i = 0; i < train_images.size(); i++)
	{
		index = sequence[i];
		train_images[i] = new_train_images[index];
		Labels[i] = new_train_labels[index];
	}
}

获得向量的最大值下标,用于测试函数:

inline int Argmax(float *x, int size)
{
	float max = 0;
	int argmax = 0;
	for (int i = 0; i < size; i++)
	{
		if (max <= x[i])
		{
			max = x[i];
			argmax = i;
		}
	}
	return argmax;
}

测试函数:(因为没有封装,所以写成了三层全连接层的形式)

void test(vector<vector<float>> &test_images, vector<int> &test_labels, vector<matrix> &parameter)
{
	cout << "正在测试中。。。" << endl;

	vector <vector<int>> Labels;
	Labels = Onehot_encoding(test_labels, 10);

	vector<float> Img;
	vector<int> Label;

	matrix W1, W2, B1, B2;
	W1 = parameter[0];
	W2 = parameter[1];
	B1 = parameter[2];
	B2 = parameter[3];

	matrix Hide, Hide_s;
	matrix Output, Output_s;

	int correct_num = 0;
	float accuracy_rate;

	for (int k = 0; k < test_images.size(); k++)
	{
		Img = test_images[k];
		Label = Labels[k];
		matrix img(28, 28, 1); vector_to_matrix(img.x, Img);
		matrix label(10, 1, 1); vector_to_matrix(label.x, Label);
		//数据正向传播
		Hide = M_dot_V(W1, img) + B1;
		Hide_s = sigmoid_f(Hide);

		Output = M_dot_V(W2, Hide_s) + B2;
		Output_s = sigmoid_f(Output);

		int L, index;
		L = Argmax(Output_s.x, 10);
		if (L == test_labels[k])  correct_num++;
	}
	accuracy_rate = 1.0f*correct_num / test_images.size();
	cout << "测试准确率为:" << accuracy_rate << endl;
}

数据集读取:写成.h文件

#pragma once


#include <iostream> // cout
#include <sstream>
#include <fstream>
#include <iomanip> //setw
#include <random>
#include <stdio.h>


namespace mnist
{
std::string data_name() {return std::string("MNIST");}

// from tiny_cnn
template<typename T>
T* reverse_endian(T* p) {
	std::reverse(reinterpret_cast<char*>(p), reinterpret_cast<char*>(p) + sizeof(T));
	return p;
}

// from tiny_cnn (kinda)
bool parse_mnist_labels(const std::string& label_file, std::vector<int> *labels) {
	std::ifstream ifs(label_file.c_str(), std::ios::in | std::ios::binary);

	if (ifs.bad() || ifs.fail()) 
	{
		return false;
	}
	int magic_number, num_items;

	ifs.read((char*) &magic_number, 4);
	ifs.read((char*) &num_items, 4);

	reverse_endian(&magic_number);
	reverse_endian(&num_items);

	for (size_t i = 0; i < num_items; i++) {
		unsigned char label;
		ifs.read((char*) &label, 1);
		labels->push_back((int) label);
	}
	return true;
}

// from tiny_cnn
struct mnist_header {
	int magic_number;
	int num_items;
	int num_rows;
	int num_cols;
};

// from tiny_cnn (kinda)
bool parse_mnist_images(const std::string& image_file, 
	std::vector<std::vector<float>> *images,
	float scale_min = -1.0, float scale_max = 1.0,
	int x_padding = 0, int y_padding = 0) 
{
	std::ifstream ifs(image_file.c_str(), std::ios::in | std::ios::binary);

	if (ifs.bad() || ifs.fail())
	{
			return false;
	}
	mnist_header header;

	// read header
	ifs.read((char*) &header.magic_number, 4);
	ifs.read((char*) &header.num_items, 4);
	ifs.read((char*) &header.num_rows, 4);
	ifs.read((char*) &header.num_cols, 4);

	reverse_endian(&header.magic_number);
	reverse_endian(&header.num_items);
	reverse_endian(&header.num_rows);
	reverse_endian(&header.num_cols);

		
	const int width = header.num_cols + 2 * x_padding;
	const int height = header.num_rows + 2 * y_padding;

	// read each image
	for (size_t i = 0; i < header.num_items; i++) 
	{
		std::vector<float> image;
		std::vector<unsigned char> image_vec(header.num_rows * header.num_cols);

		ifs.read((char*) &image_vec[0], header.num_rows * header.num_cols);
		image.resize(width * height, scale_min);
	
		for (size_t y = 0; y < header.num_rows; y++)
		{
			for (size_t x = 0; x < header.num_cols; x++)
				image[width * (y + y_padding) + x + x_padding] = 
					(image_vec[y * header.num_cols + x] / 255.0f) * (scale_max - scale_min) + scale_min;
		}
		
		images->push_back(image);
	}
	return true;
}

// == load data (MNIST-28x28x1 size, no padding, pixel range -1 to 1)
bool parse_test_data(std::string &data_path, std::vector<std::vector<float>> &test_images, std::vector<int> &test_labels, 
	float min_val=-1.f, float max_val=1.f, int padx=0, int pady=0)
{
	if(!parse_mnist_images(data_path+"/t10k-images.idx3-ubyte", &test_images, min_val, max_val, padx, pady)) 
		if (!parse_mnist_images(data_path + "/t10k-images-idx3-ubyte", &test_images, min_val, max_val, padx, pady))
			return false;
	if(!parse_mnist_labels(data_path+"/t10k-labels.idx1-ubyte", &test_labels)) 
		if (!parse_mnist_labels(data_path + "/t10k-labels-idx1-ubyte", &test_labels)) return false;
	return true;
}
bool parse_train_data(std::string &data_path, std::vector<std::vector<float>> &train_images, std::vector<int> &train_labels, 
	float min_val=-1.f, float max_val=1.f, int padx=0, int pady=0)
{
	if(!parse_mnist_images(data_path+"/train-images.idx3-ubyte", &train_images, min_val, max_val, padx, pady))
		if (!parse_mnist_images(data_path + "/train-images-idx3-ubyte", &train_images, min_val, max_val, padx, pady))
			return false;
	if(!parse_mnist_labels(data_path+"/train-labels.idx1-ubyte", &train_labels))
		if (!parse_mnist_labels(data_path + "/train-labels-idx1-ubyte", &train_labels)) return false;
	return true;
}
}

数据集处理函数:

//========================数据集处理=============================================

//对标签数据做one_hot编码
vector<vector<int>> Onehot_encoding(vector<int> &labels, int type_nums)
{
	vector<vector<int>> labels_encoding;
	for (int i = 0; i < labels.size(); i++)
	{
		vector<int> temp(type_nums, 0);
		temp[labels[i]] = 1;
		labels_encoding.push_back(temp);
	}
	return labels_encoding;
}

//把数据集分成几个大小为batch_size的集合,主要用于样本图像
vector<vector<vector<float>>> split_batch_x(vector<vector<float>> &imgs, int batch_size)
{
	vector<vector<vector<float>>> x;
	int _size = imgs.size() / batch_size;
	for (int i = 0; i < _size; i++)
	{
		vector<vector<float>> batch_x;
		for (int j = 0; j < batch_size; j++)
		{
			batch_x.push_back(imgs[j + i * batch_size]);
		}
		x.push_back(batch_x);
	}
	return x;
}

//把数据集分成几个大小为batch_size的集合,主要用于样本标签
vector<vector<vector<int>>> split_batch_y(vector<vector<int>> &labels, int batch_size)
{
	vector<vector<vector<int>>> y;
	int _size = labels.size() / batch_size;
	for (int i = 0; i < _size; i++)
	{
		vector<vector<int>> batch_y;
		for (int j = 0; j < batch_size; j++)
		{
			batch_y.push_back(labels[j + i * batch_size]);
		}
		y.push_back(batch_y);
	}
	return y;
}

激活函数和它的导数,这里选用了sigmoid:


inline matrix sigmoid_f(matrix &m)
{
	matrix out(m.cols, m.rows, m.chans);
	for (int i = 0; i < out.size(); i++) out.x[i] = 1.0f / (1.0f + exp(-(m.x[i])));
	return out;
}


inline matrix sigmoid_df(matrix &m)
{
	matrix out(m.cols, m.rows, m.chans);
	for (int i = 0; i < out.size(); i++) out.x[i] = m.x[i] * (1.f - m.x[i]);
	return out;

然后再加点矩阵类的一些补充运算

//=======================矩阵类的一些补充运算====================================
//将vector转化为matrix
inline void vector_to_matrix(float *m, vector<int> &v)
{
	for (int i = 0; i < v.size(); i++)  m[i] = v[i];
}
inline void vector_to_matrix(float *m, vector<float> &v)
{
	for (int i = 0; i < v.size(); i++)  m[i] = v[i];
}

//矩阵转置
inline matrix Transposition(matrix &m)
{
	int _w = m.cols;
	int _h = m.rows;
	matrix out(_h, _w, 1);
	for (int i = 0; i < _h; i++)
	{
		for (int j = 0; j < _w; j++)
		{
			out.x[j + i * _w] = m.x[i + j * _h];
		}
	}
	return out;
}

//矩阵*向量,结果是一个向量那种,矩阵和向量都是存成一维的形式,matrix类,你懂的
inline matrix M_dot_V(matrix &A, matrix &B)
{
	int _w = A.cols;
	int _h = A.rows;
	matrix out(_w, 1, 1);
	out.fill(0);
	for (int i = 0; i < _w; i++)
	{
		for (int j = 0; j < _h; j++)
		{
			out.x[i] += A.x[j + i * _h] * B.x[j];
		}
	}
	return out;
}

//向量*向量,结果是一个矩阵那种,矩阵和向量都是存成一维的形式,matrix类,你懂的
inline matrix V_dot_V(matrix &A, matrix &B)
{
	int _w = A.size();
	int _h = B.size();
	matrix out(_w, _h, 1);
	for (int i = 0; i < _w; i++)
	{
		for (int j = 0; j < _h; j++)
		{
			out.x[j + i * _h] = A.x[i] * B.x[j];
		}
	}
	return out;
}

别忘了还要导入一些相关的包哦:

include <vector>
include <iostream>
using namespace std;
using namespace 

最后是主函数(记得把手写数字的数据集下载下来,放在对应目录下):

int main()
{
	string data_path = "data/mnist/";

	int batch_size = 10;
	int num_input = 28 * 28 * 1;
	int num_hide = 30;
	int	num_classes = 10;
	float lr = 3; // 学习率
	int epochs = 1;
	//====================================================================
	//读取数据集
	vector<vector<float>> train_images, train_images_copy;
	vector<int> train_labels;
	vector<vector<float>> test_images;
	vector<int> test_labels;

	cout << "读取数据中" << endl;
	if (!parse_test_data(data_path, test_images, test_labels)) { std::cerr << "error: could not parse data.\n"; return 1; }
	if (!parse_train_data(data_path, train_images, train_labels)) { std::cerr << "error: could not parse data.\n"; return 1; }
	cout << "数据读取完成" << endl;

	train_images_copy = train_images;
	//====================================================================
	vector<vector<int>> Labels;
	Labels = Onehot_encoding(train_labels, 10);

	vector<vector<vector<float>>> x;
	vector<vector<float>> batch_x;
	vector<float> Img;
	vector<vector<vector<int>>> y;
	vector<vector<int>> batch_y;
	vector<int> Label;

	vector<int> sequence;
	sequence = get_a_sequence(train_images.size());  //生成一个序列,用来打乱作为索引,用于打乱数据集
	//========================================================================
	//全连接层
	matrix W1(num_hide, num_input, 1);
	matrix B1(num_hide, 1, 1);
	matrix W2(num_classes, num_hide, 1);
	matrix B2(num_classes, 1, 1);

	W1.fill_random_normal(1.f);
	B1.fill_random_normal(1.f);
	W2.fill_random_normal(1.f);
	B2.fill_random_normal(1.f);

	matrix Hide, Hide_s;    //隐藏层
	matrix Output, Output_s;   //输出层
	matrix delta_1, delta_2;   //隐藏层和输出层误差
	matrix W1_T, W2_T;    //矩阵的转置
	matrix W1_t, W2_t, B1_t, B2_t;   //用来存参数的梯度
	//========================================================================
//开始训练
	for (int epoch = 0; epoch < epochs; epoch++)
	{
		dataset_shuffle(train_images, Labels, sequence);  //随机打乱数据集

		x = split_batch_x(train_images, batch_size);
		y = split_batch_y(Labels, batch_size);
		//=====================================================================
		for (int m = 0; m < x.size(); m++)
		{
			batch_x = x[m];
			batch_y = y[m];

			matrix W1_t_sum(W1.cols, W1.rows, W1.chans); W1_t_sum.fill(0);
			matrix W2_t_sum(W2.cols, W2.rows, W2.chans); W2_t_sum.fill(0);
			matrix B1_t_sum(B1.cols, B1.rows, B1.chans); B1_t_sum.fill(0);
			matrix B2_t_sum(B2.cols, B2.rows, B2.chans); B2_t_sum.fill(0);

			for (int n = 0; n < batch_x.size(); n++)
			{
				Img = batch_x[n];
				Label = batch_y[n];
				matrix img(28, 28, 1); vector_to_matrix(img.x, Img);
				matrix label(10, 1, 1); vector_to_matrix(label.x, Label);

				Hide = M_dot_V(W1, img) + B1;
				Hide_s = sigmoid_f(Hide);

				Output = M_dot_V(W2, Hide_s) + B2;
				Output_s = sigmoid_f(Output);

				//=======================================================================
				//误差反向传播
				delta_1 = (Output_s - label)*sigmoid_df(Output_s);   //输出层误差
				W1_T = Transposition(W1);
				W2_T = Transposition(W2);
				delta_2 = M_dot_V(W2_T, delta_1)*sigmoid_df(Hide_s);   //隐藏层误差

				//=======================================================================
				//计算参数梯度
				B2_t = delta_1;
				B1_t = delta_2;
				W2_t = V_dot_V(delta_1, Hide_s);
				W1_t = V_dot_V(delta_2, img);

				B2_t_sum += B2_t;
				B1_t_sum += B1_t;
				W2_t_sum += W2_t;
				W1_t_sum += W1_t;
			}
			//更新参数===============================================================
			W1 = W1 - W1_t_sum * (lr / batch_size);
			W2 = W2 - W2_t_sum * (lr / batch_size);
			B1 = B1 - B1_t_sum * (lr / batch_size);
			B2 = B2 - B2_t_sum * (lr / batch_size);

			if (m % 100 == 0)  cout << "=====================正在训练第" << epoch << "个epoch,第" << m << "个batch=====================" << endl;
		}
	}
	cout << "训练完成" << endl;

	vector<matrix> parameter;
	parameter.push_back(W1);
	parameter.push_back(W2);
	parameter.push_back(B1);
	parameter.push_back(B2);

	test(train_images_copy, train_labels, parameter);
	test(test_images,test_labels,parameter);

	system("pause");
	return 0;
}

最后是实验结果:
在这里插入图片描述
50个epochs 可以达到93%以上的准确率,然后是100个epochs的结果:
在这里插入图片描述
可以看到准确率可以达到94%以上,不过神经网络差不多只能达到这个结果了,要想有更好的结果,就要使用卷积神经网络了,后面有时间再补充上了。

  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源 神经网络相关资源
### 回答1: 搭建卷积神经网络需要以下步骤: 1. 定义输入数据:卷积神经网络的输入通常是图像数据。 2. 初始化权重:权重是网络的核心部分,需要随机初始化。 3. 卷积层:卷积层通过卷积核对输入数据进行处理,生成卷积层的特征图。 4. 池化层:池化层通过池化操作对卷积层特征图进行下采样。 5. 全连接层:全连接层把池化层的输出压缩为一个向量,并对其进行处理。 6. 输出层:输出层通过softmax函数对全连接层的结果进行分类。 7. 定义损失函数:损失函数用于评估网络的性能,常用的损失函数包括交叉熵损失。 8. 优化器:优化器用于更新网络的参数,常用的优化器包括SGD和Adam。 9. 训练网络:通过不断地训练网络,可以使得网络在训练数据上的性能越来越好。 这些步骤可以使用C语言实现。如果您还不熟悉C语言,建议先学习一些C语言的基础知识,然 ### 回答2: 要用C语言来搭建卷积神经网络,需要遵循一些步骤和原则。 首先,我们需要定义卷积神经网络的结构和层。在C语言中,可以使用结构体来定义一个层和网络的结构。每个层通常包含输入、权重、偏置、激活函数等组成部分。 接下来,我们需要定义函数来执行卷积操作和池化操作。卷积操作需要在输入数据和权重之间进行计算,并使用激活函数对计算结果进行处理。池化操作则是在卷积后对输出进行降采样。这些函数需要按照卷积和池化的步骤来进行编码。 然后,我们需要实现前向传播和反向传播算法来训练卷积神经网络。前向传播算法用于计算预测结果,并将其与真实标签进行比较来计算损失。反向传播算法用于根据损失来更新权重和偏置,以优化网络的性能。 此外,我们还需要实现一些辅助函数,如初始化权重和偏置、导入和导出数据、计算预测精度等。这些辅助函数将帮助我们更好地搭建和测试卷积神经网络。 最后,我们需要使用训练数据来训练网络,并使用测试数据来评估网络的性能。通过多次迭代训练和优化,可以提高网络的准确率和泛化能力。 总之,建立一个使用C语言实现的卷积神经网络需要定义网络结构、编写卷积和池化函数、实现前向和反向传播算法、编写辅助函数,并使用训练和测试数据进行训练和评估。 ### 回答3: 卷积神经网络(Convolutional Neural Network,CNN)是一种经典的神经网络结构,特别适用于图像和语音处理任务。下面我将介绍使用C语言搭建卷积神经网络的基本步骤: 1. 定义网络结构:首先,我们需要定义卷积神经网络的结构,包括网络的层数、每层的神经元数量、卷积核的大小等。可以使用结构体或数组来表示网络结构。 2. 初始化权重:使用随机数或者预训练好的权重来初始化网络中的权重参数。可以使用数组或矩阵来表示网络中的权重。 3. 前向传播:对于给定的输入数据,通过卷积计算、池化等操作依次进行前向传播,得到网络的输出。卷积操作可以使用嵌套循环实现,池化操作可以使用最大值或平均值等方式。 4. 激活函数:将前向传播得到的输出通过激活函数进行非线性变换。常用的激活函数包括ReLU、sigmoid和tanh等。 5. 损失函数:根据网络的输出与真实标签之间的差异计算损失函数,常用的损失函数包括均方误差和交叉熵等。 6. 反向传播:通过计算损失函数对网络中的权重参数求导,然后根据梯度下降算法更新网络中的权重参数。可以使用链式法则计算梯度,通过嵌套循环实现权重的更新。 7. 训练网络:使用训练数据对网络进行训练,通过反复进行前向传播和反向传播来逐渐优化网络的权重参数,使得网络输出与真实标签更加接近。 8. 测试网络:使用测试数据对训练好的网络进行测试,计算网络的准确率或其他性能指标。 总之,通过定义网络结构、初始化权重、前向传播、激活函数、损失函数、反向传播、训练网络和测试网络等步骤,可以用C语言搭建卷积神经网络,并应用于图像和语音处理等任务中。需要注意的是,C语言相比其他高级语言(如Python)的代码实现会复杂一些,但通过良好的设计和代码编写,同样可以实现高效的卷积神经网络

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值