Linux之网络基础之套接字编程

一、socket套接字编程

  • socket是一套网络编程接口,类似于中间件;上层用户可以通过这些接口简单的完成网络通信传输;而不需要过于关心内部的实现过程。
  • 套接字编程讲的就是使用socket接口实现网络通信。
  • socket编程:
    ① UDP协议:用户数据报协议。特性:无连接、不可靠、面向数据报。常用于对实时性要求高于安全性要求的程序。如视频传输。
    ② TCP协议:传输控制协议。特性:面向连接、可靠传输、面向字节流。常用于对安全可靠性要求高于对性能要求的程序。如文件传输。
    ③ 面向数据报:无连接、不可靠的、无序的,有最大长度限制的数据传输服务。
    ④ 面向字节流:基于连接的、可靠的、有序的,双向的字节流传输服务,不限制上层传输数据大小的传输方式。

1.socket接口的介绍

① 创建套接字
int socket(int domain, int type, int protocol);
domain:地址域—不同的网络地址结构,AF_INET - IPv4地址域。
type:套接字类型 - 流式套接字 / 数据报套接字。(流式套接字:一种有序的,可靠的,双向的,基于连接的字节流传输 SOCK_STREAM;数据报套接字:无连接的,不可靠的,有最大长度限制的传输。 SOCK_DGRAM)
protocol:使用的协议 0—不同套接字类型下的默认协议(流式套接字默认的是tcp/数据报套接字默认的是udp)IPPROTO_TCP----tcp协议 。 IPPRORO_UDP----udp协议。
返回值:返回套接字的操作句柄----文件描述符

② 为套接字绑定地址信息
int bind(int sockfd, struct sockaddr* addr, socklen_t len);
sockfd:创建套接字返回的操作句柄。
addr:要绑定的地址信息结构。
len:地址信息的长度。
返回值:成功返回0,失败返回-1。
用户先定义sockaddr)in的IPV4地址结构,强转之后传入bind之中
bind(sockaddr*)
{
if(sockaddr->sin_family == AF_INET)
{
//这是ipv4地址结构的解析
}
else if(sockaddt->sin_family == AF_INET6)

}

③ 发送数据
int sendto(int sockfd, char* data, int data_len, int fag, struct sockaddr* dest_addr, socklen_t addr_len);
sockfd:套接字操作句柄,发送数据就是将数据拷贝到内核的socket发送缓冲区中
data:要发送的数据的首地址
data_len:要发送的数据的长度
flag:选项参数,默认为0—表示当前操作是阻塞操作 MSG_DONTWAIT—设置为非阻塞。若发送数据的时候,socket发送缓冲区已经满了,则0默认阻塞等待; MSG_DONTWAIT就是立即报错返回了。
dest_addr:目的端地址信息结构–表示数据要发送给谁。每一条数据都要描述源端信息(绑定的地址信息)和对端信息(当前赋予的信息)。

④ 接收数据
int recvfrom(int sockfd, char* buf, int len, int flag, struct sockaddr* src_addr, socklen_t* addr_len);
sockfd:套接字操作句柄
buf:缓冲区的首地址,用于存放接收的数据,从内核socket接收缓冲区中取出数据放入这个buf用户缓冲区中
len:用户想要读取的数据长度,但不能大于buf缓冲区的长度。
flag:0-默认阻塞操作—若缓冲区中没有数据则一直等待。 MSG_DONTWAIT–非阻塞。
src_addr:接收到的数据的发送端地址–表示这个数据是谁发的,从哪来的–回复的时候就是对这个地址进行回复
addr_len:输入输出型参数,用于指定想要获取多长的地址信息;获取地址之后,用于返回地址信息的实际长度
返回值:成功返回实际接收到的数据字节长度,失败返回-1。

⑤ 关闭套接字
int close(int fd);

2.IP地址的三种表示方式以及字节序转换接口

(1.)IP地址的三种表示方式

  • 点分十进制
    点分十进制是IPv4的IP地址标识方法。四个字节表示一个IP地址,每个字节按照十进制表示0~255。
    如192.168.0.1
  • 主机字节序
    主机字节序是指按照处理器的存储数据的字节顺序,一般Intel处理器是小端字节序
    小端字节序:低地址存放在低字节位,高地址存高字节位。如0x12345678====》0x 78 56 34 12
    故Intel处理器的主机字节序一般为小端字节序。
  • 网络字节序
    网络字节序是TCP/IP规定好的存储数据的格式,为大端字节序
    大端字节序:低地址存放高字节位,高地址存放低字节位。如0x12345678====》0x 12 34 56 78

(2)字节序转换接口

接口名含义
uint32_t htonl(uint32_t) ;将4个字节的转换成网络字节序
uint32_t ntohl(uint32_t);将4个字节网咯字节序数据转换为主机字节序
uint16_t htons(uint16_t);将2个字节的主机字节序转换成网络字节序
uint16_t ntohs(uint16_t);将2个字节网络字节序转换成主机字节序
uint32_t inet_addr(const char* ip);将字符串IP地址转换为网络字节序整数IP地址
int inet_pton(int domain, char* src, void* dst);将字符串src的IP地址按照domain地址域网络字节序的IP地址
int inet_ntop(int domain, void* src, char* dst, int len);将网络字节序数据按照domain地址域转换为字符串IP地址

二、UDP网络编程流程的实现

  • 特性:无连接,不可靠,面向数据报。

1.UDP网络通信程序编程流程:

在这里插入图片描述

  • 服务端:
    ① 创建套接字socket。在内核中创建一个socket结构体,通过这个结构体以及返回的文件描述符,使进程与网卡之间建立关联。 服务端socket只能绑定的是服务端主机上的IP地址;客户端也绑定的是自己主机的IP地址。
    ② 为套接字绑定地址信息。在套接字结构体中标记地址信息,让操作系统知道发送数据的时候通过哪些地址发送,以及接受数据的时候,知道应该由哪一个进程来处理。
    ③ 数据接收,数据的发送。发送数据的时候层层封装数据(网络的传输数据都应该包含:源IP地址/目的IP地址/源端口/目的端口/协议)。操作系统对于接收到的数据,判断目的地址信息,去内核中socket链表—查找(找到了,则将这个数据放入了这个socket的接受缓冲区中,没找到,则这个数据直接被丢弃。 )
    ④ 关闭套接字,释放资源。
  • 注意事项:
    ① 客户端不推荐主动绑定地址,而是在发送数据的时候由操作系统选择合适的地址信息进行绑定(尽最大的可能避免出现端口冲突概率。)
    ② 服务端必须主动绑定,因为需要保证地址永远不改变才能被客户端找到。

2.udpsocket类实现套接字编程

//UDPSocket.hpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unisted.h>
#include <string>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

namespace sheena
{
	class UdpSocket
	{
	private:
		void MakeAddr(struct sockaddr_in& addr, const std::string& ip, const uint16_t port)
		{
			addr.sin_family = AF_INET;
			addr.sin_port = htons(port);
			addr.sin_addr.s_addr = inet_addr(ip.c_str());
		}
	public:
			UdpSocket()
				:_sock(-1)
			{}
			~UdpSocket()
			{}
			
			//1.创建套接字
			bool Socket()
			{
				//AF_INET:IPv4地址域;SOCK_DGRAM:用户数据报套接字;IPPROTO_UDP:udp协议
				_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//创建失败返回-1
				if(_sock < 0)
				{
					perror("创建失败!!\n");
					return false;
				}
				return true;
			}
			
			//2.绑定地址信息
			bool Bind(const std::string &ip, const uint16_t port)
			{
				struct sockaddr_in addr;
				MakeAddr(addr, ip, port);
				socklen_t len = sizeof(struct sockaddr_in);
			
				//sockfd:套接字描述符,addr:地址信息(IPv4是struct addr_in结构体)
				int ret = bind(_sock, (struct sockaddr*)& addr, len);
				if(ret < 0)
				{
					perror("绑定地址信息失败!!!\n");
					return false;
				}
				return true;
			}

			//3.接收信息
			bool Recv(std::string& buf, std::string *ip = NULL, uint16_t *port = NULL)
			{
				struct sockaddr_in addr;
				char tmp[1500] = {0};
				socklen_t len = sizeof(struct sockaddr_in);
				//sockfd:套接字描述符,buf:接收信息的缓冲区,len:要接收数据的长度,flag:参数为0为阻塞。src_addr:对端地址信息
				int ret = recvfrom(_sock, tmp, 1500, 0, (struct sockaddr*)& addr, &len);
				if(ret < 0)
				{
					perror("接收信息失败!!!\n");
					return false;
				}

				buf.assign(tmp, ret);
				if(ip != NULL)
				{
					//将网络字节序整数IP地址转换为字符串IP
					*ip = inet_ntoa(addr.sin_addr);
				}
				if(*port != NULL)
				{
					//将网络字节序转换为主机字节序
					*port = ntohs(addr.sin_port);
				}
				return true;
 			}
 			
 			//4.发送信息
 			bool send(const std::string &buf, std::string& dip, uint16_t dport)
 			{
 				struct sockaddr_in addr;
 				MakeAddr(addr, dip, dport);
 				socklen_t len = sizeof(struct sockaddr_in);
				
				//sockfd:套接字描述符,buf:要发送的数据缓冲区,len:要发送的数据长度,
				//flag :参数为0位阻塞发送,dest_addr:要发送地址信息
				int ret - sendto(_sock, &buf[0], buf, size(), 0, (struct sockaddr*)& addr, len);
				if(ret < 0)
				{
					perror("发送信息失败!!\n");
					return false;
				}
				return true;
 			}

			//5.关闭套接字
			bool Close()
			{
				close(_sock);
				return true;
			}
	private:
		int _sock;		
	};
}

3.udp客户端程序

  • 对于客户端来说,并不关心使用什么源端地址将地址发送出去,只要能够发送数据并且能接收数据就可以。
  • 服务端必须主动绑定地址。---- 一旦服务端不主动绑定地址,则会造成操作系统随意选择合适的地址进行绑定,服务端自己都不确定自己用什么地址。如何告诉客户端。因此服务端通常必须主动绑定地址,并且不能随意改动。
#include <stdio.h>
#include <iostream>
#include <string>
#include "UdpSocket.hpp"

#define CHCK_RET(q) if((q) == false) {return -1;}

namespace sheena
{
	//客户端要给服务端发送数据,那么就需要知道服务端的地址信息
	//因此通过程序运行参数传入服务端的地址信息
	int main(int argc, char* argv[])
	{
		if(argc != 3)
		{
			std::cerr << "./udp_client ip port\n";
			return -1;
		}

		//这两个地址信息是服务端地址信息,表示数据由客户端发给谁
		std::string ip_addr = argv[1];//服务端地址信息
		uint1_t port_addr = atoi(9000);
		
		UdpSocket scok;
		CHECK_RET(sock.Socket());
		//CHECK_RET(sock.Bind());因为客户端不知道绑定的是什么地址信息,因为传入的地址信息是服务端的地址信息(对端)
		//所以不绑定地址信息
		//客户端通常并不主动绑定地址,而是在发送数据的时候,操作系统检测有没有
		//绑定,则会自动选择一个合适的地址和端口进行绑定
		while(1)
		{
			std::cout << "client say:" ;
			fflush(stdout);
			std::string buf;
			std::cin >> buf;
			sock.Send(buf, srv_ip, srv_port);

			buf.clear();
			sock.Recv(buf);
			std::cout << "server say: " << buf << endl;
		}
	
		sock.Close();
		std::cout << "Hello world" << std::endl;
		return 0;
	}
}

4.udp服务端程序

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

namespace sheena
{
	int main(int argc, char* argv)
	{
		//通过参数灵活获取IP地址和端口信息
		if(argc != 3)
		{
			printf("./udp_srv is port\n");
			return -1;
		}
	
		//获取本地主机端口号和主机地址
		uint16_t port = atoi(argv[2]);
		char* ip = argv[1];

		//1.创建套接字
		int sockfd = socket(AF_INET, SOCK_DGREAM, IPPROTO_UDP);
		if(sockfd < 0)
		{
			perror("创建套接字失败!!\n");
			return -1;
		}

		//2.绑定地址信息
		struct sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = inet_addr(ip);
		socklen_t len = sizeof(addr);
		int ret = bind(sockfd, (struct sockaddr*)&addr, len);
		if(ret < 0)
		{
			perror("绑定地址信息失败!!!\n");
			return -1;
		}
	
		while(1)
		{
			//3.接收信息
			char buf[1024] = {0};
			struct sockaddr_in cliaddr;
			ret = recvfrom(sockfd, buf, 1023, 0, (struct sockaddr*)&cliaddr, &len);
			if(ret < 0)
			{
				perror("接收信息失败!!\n");
				return -1;
			}
			printf("client say: %s\n", buf);

			//4.发送信息
			printf("server say: ");
			fflush(stdout);
			memset(buf, 0x00, 1024);
			scanf("%s",buf);
			ret = sendto(sockfd, buf, strlen(buf), 0, (struct sockadrr*)& cliaddr, len);
			if(ret < 0)
			{
				perror("发送信息失败!!!\n");
				return -1;
			}
		}

		//5.关闭套接字
		close(sockfd);
		return 0;
	}
}
  • 每个程序绑定的都是自己的网卡地址信息。
  • 客户端发送的对端地址信息一定是服务端绑定的地址信息。
  • 服务端绑定的地址信息,一定是自己主机上的网卡IP地址。

三、TCP网络编程流程的实现

  • 特性:面向连接、可靠传输、面向字节流

1.TCP网络通信程序编程流程

在这里插入图片描述

  • 客户端:创建套接字,描述地址信息,发送连接请求,连接建立成功,收发数据,关闭套接字。
  • 服务端:创建套接字,描述地址信息,开始监听,接收连接请求,新建套接字,获取新建套接字描述符,通过这个描述符与客户端通信,关闭套接字。

2.接口介绍

① 创建套接字:int socket(int domain, int type, int protocol); (AF_INET,SOCK_STREAM—流式套接字,IPPROTO_TCP)
② 绑定地址信息:int bind(int sockfd, struct sockaddr* addr, socklen_t len);
③ 服务端开始监听:int listen(int sockfd, iny backlog);告诉操作系统开始接收连接请求。
backlog:决定同一时间,服务端能接收的客户端连接请求数量。(SYN泛洪攻击:恶意主机不断向服务端主机发送大量的连接请求,若服务端为每一个连接请求建立socket,则会瞬间资源耗尽,服务器崩溃。因此服务端有一个connection pending queue; 存放为连接请求新建的socket节点;backlog参数决定了这个队列的最大节点数量;若这个队列放满了,若还有新连接请求的到来,则将这个后续请求丢弃掉。)但是这个并不能决定服务端能够接收多少客户端请求数量。
④ 获取新建socket的操作句柄:从内核指定socket的pending queue中取出一个socket,返回操作句柄。
int accept(int sockfd, struct sockaddr* addr, socklen_t* len);
sockfd:监听套接字—指定要获取哪个pending queue中的套接字。
addr:获取一个套接字,这个套接字与指定的客户端进行通信,通过addr获取这个客户端的地址信息。
len:输入输出型参数----指定地址信息想要的长度,以及返回实际的地址长度。
返回值:成功则返回新获取的套接字描述符----操作句柄。失败则返回-1。
⑤ 通过重新获取的套接字操作句柄(accept返回的描述符)与指定客户端进行通信
接收数据:ssize_t recv(int sockfd, char* buf, int len, int flag);返回值:成功返回实际读取的数据长度,连接断开返回0,读取失败返回-1。(tcp连接断开也是写端被关闭的一种体现)
发送数据:ssize_t send(int sockfd, char* data, int len, int flag);返回值:成功返回实际发送的数据长度,失败返回-1,若连接断开则触发异常。
⑥ 关闭套接字:释放资源。int close(int fd);
⑦ 客户端向服务端发送连接请求:int connect(int sockfd, int sockaddr* addr, socklen_t lem);
sockfd:客户端套接字—若还未绑定地址,则操作系统会选择合适的源端地址进行绑定。
addr:服务端地址信息—struct sockaddr_in:这个地址信息经过connect之后也会描述到socket中。
len:地址信息长度。

  • 注意:连接若是断开了,recv会返回0,send会触发异常导致进程退出。

3.tcpsocket类实现套接字编程

#ifndef __MY_TCP_H
#define __MY_TCP_H

#include <iostream>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define CHECK_RET(q) if((q) == false){return -1;}
#define MAX_LISTEN 10

namespace sheena
{
	class TcpSocket
	{
	private:
		void MakeAddr(struct sockaddr_in& addr, const std::string& ip, const uint16_t port)
		{
			//添加地址信息
			addr.sin_family = AF_INET;
			addr,sin_port = port;
			addr.sin_adrr.s_addr = inet_addr(ip.c_str());
		}
	public:
		TcpSocket()
			:_sockfd(-1)
		{}

		//1.创建套接字
		bool Socket()
		{
			_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
			if(_sockfd < 0)
			{
				perror("创建套接字失败!!\n");
				return false;
			}
			return true;
		}
		
		//2.绑定地址信息
		bool Bind(const std::string& ip, const uint16_t port)
		{
			struct sockaddr_in addr;
			MakeAddr(add, ip, port);
			socklen_t len = sizeof(struct sockaddr_in);

			int ret = bind(_sockfd, (struct sockaddr*)& addr, len);
			if(ret < 0)
			{
				perror("绑定地址信息!!\n");
				return false;
			}
			return true;
		}

		//3.开始监听(服务器)
		bool  Listen(int backlog = MAX_LISTEN)
		{
			//backlog:决定了同一时间并发连接数,不能写死,采用默认参数方式
			int ret = listen(_sockfd, backlog);
			if(ret < 0)
			{
				perror("监听失败!!\n");
				return false;
			}
			return true;
		}
		//3.发起连接请求(客户端)
		bool Connect(const std::string& srvip, const uint16_t port)
		{
			struct sockaddr_in addr;
			MakeAddr(addr, srvip, port);
			socklen_t len = sizeof(struct sockaddr_in);
			
			int ret = connect(_sockfd, (struct sockaddr*)&addr, len);
			if(ret < 0)
			{
				perror("发起连接请求失败!!!\n");
				return false;
			}
			return true;
		}

		//4.获取新连接(服务器)
		bool Accept(TcpSocket* sock, std::string* ip = NULL, uint16_t *port = NULL)
		{
			struct sockaddr_in addr;
			socklen_t len = sizeof(addr);
		
			//获取新连接的套接字描述符,并且获取这个新连接对应的客户端地址
			int newfd = accept(_sockfd, (struct sockaddr*)& addr, &len);
			if(newfd < 0)
			{
				perror("获取新连接失败!!!\n");
				return false;
			}
			sock->_sockfd = newfd;
			if(ip != NULL)
			{
				*ip = inet_ntoa(addr.sin_addr);
			}
			if(port != NULL)
			{
				*port = ntohs(addr.sin_port);
			}
			return true;
		}

		//5.接收信息
		bool Recv(std::string& buf)
		{
			char tmp[4096] = {0};
			int rlen = recv(_sockfd, tmp, 4096, 0);
			if(rlen < 0)
			{
				//连接失败
				perror("接收信息失败!!\n");
				return false;
			}
			else if(rlen == 0)
			{
				//连接断开
				std::cerr << "连接已断开\n";
				return false;
			}
			buf.assign(tmp, rlen);
			return true;
		}
		
		//6.发送信息
		bool Send(std::string& buf)
		{
			int ret = send(_sockfd, &buf[0], buf,size(), 0);
			if(ret < 0)
			{
				perror("发送信息失败!!\n");
				return false;
			}
			return true;
		}

		//7.关闭套接字
		bool Close()
		{
			close(_sockfd);
			return true;
		}
	private:
		int _sockfd;
	};

	#endif
}

4.tcp客户端程序

#include <stdlib.h>
#include <stdio.h>
#include "TcpSocket.hpp"

namespace sheena
{
	int main(int argc, char* argv[])
	{
		if(argc != 3)
		{
			std::cerr << "./tcp_cli ip port\n";
			return -1;
		}
		
		std::string ip =argv[1];
		uint16_t port = atoi(argv[2]);
	
		TcpSocket cli_sock;
		//1.创建套接字
		CHECK_RET(cli_sock.Socket());
		//不推荐客户端主动绑定地址信息,需要系统自动绑定,所以不需要该步
		//2.绑定地址信息
		//CHECK_RET(cli_sock.Bind());

		while(1)
		{
			//3.发送信息	
			std::cout << "client say: ";
			fflush(stdout);
			std::string buf;
			std::cin >> buf;
			CHECK_RET(cli_sock.Send(buf));

			//4.接收信息
			buf.clear();
			CHECK_RET(cli_sock.Recv(buf));
			std::cout << "server say: " << buf << "\n";
		}
		cli_sock.Close();

		return 0;
	}
}

5.tcp服务端程序

#include <stdlib.h>
#include <stdio.h>
#include "TcpSocket.hpp"

namespace sheena
{
	int main(int argc, char* ardv[])
	{
		if(argc != 3)
		{
			std::cout << "./tcp_srv ip port\n";
			return -1;
		}

		//通过参数获取地址信息
		std::string ip = argv[1];
		uint16_t port = atoi(argv[2]);
	
		//实例化对象,监听套接字
		TcpSocket lst_sock;
		//1.创建套接字
		CHECK_RET(lst_sock.Sock());
		//2.绑定地址信息
		CHECK_RET(lst_sock.Bind(ip, port));
		//3.开始监听
		CHECK_RET(lst_sock.Listen());
		TcpSocket cli_sock;

		//4.获取新连接
		while(1)
		{
			std::string cli_ip;
			uint16_t cli_port;
			if(lst_sock.Accept(&cli_sock, &cli_ip, &cli_port) == false))
			{
				//获取新连接失败后,继续获取下一个连接
				continue;
			}
			//获取新连接成功
			std::cout << "新连接:" << cli_ip << ":" << cli_port << "\n";

			//5.开始通信,接收信息
			std::string buf;
			bool ret = cli_sock.Recv(buf);
			if(ret == false)
			{
				//和当前的客户端通信不能连接
				//继续下一个客户端处理
				cli_sock.Close();
				continue;
			}
			std::cout << "client say: " << buf << "\n";
			std::cout << "server say: ";
			fflush(stdout);
			buf.clear();
			std::cin >> buf;

			//6.发送信息
			ret = cli_sock.Send(buf);
			if(ret ==false)
			{
				cli_sock.Close();
				continue;
			}
		}
		
		lst_sock.Close();
		return 0;
	}
}
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值