我的世界0.14.3 安卓版 支持安卓14、流量进服 (附修改教程)
此为0.14.3修改版，修改内容如下：1.支持流量进入服务器 2.支持安卓14使用。仅修改两处代码，除此之外，再无任何修改！下载0.14.3(直接下载)修改教程授人以鱼不如授人以渔，简单的给大家讲一下怎么去修改，大家可以兼容更多版本。修改支持安卓14反编译AndroidManifest.xml，修改找到如下代码：<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="22" />将其中的targetSdkVersion值改为24即可，修改后的代码如下<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="24" />修改支持流量进服编辑classes.dex文件，修改路径为com/mojang/minecraftpe/MainActivity下的类。在MainActivity类中，找到isNetworkEnabled函数。定位到这一部分代码： .line 626 .restart local v1 # "info":Landroid/net/NetworkInfo; :cond_1d const/4 v2, 0x0将IPv4参数中的0x0改为 0x1即可 .line 626 .restart local v1 # "info":Landroid/net/NetworkInfo; :cond_1d const/4 v2, 0x1结语怎么说呢，教程完毕，就是这样简单，试着修改一下吧～
// 颜色代码 const BLACK = TextFormat::ESCAPE . "0"; // 黑色 const DARK_BLUE = TextFormat::ESCAPE . "1"; // 深蓝色 const DARK_GREEN = TextFormat::ESCAPE . "2"; // 深绿色 const DARK_AQUA = TextFormat::ESCAPE . "3"; // 深青色 const DARK_RED = TextFormat::ESCAPE . "4"; // 深红色 const DARK_PURPLE = TextFormat::ESCAPE . "5"; // 深紫色 const GOLD = TextFormat::ESCAPE . "6"; // 金色 const GRAY = TextFormat::ESCAPE . "7"; // 灰色 const DARK_GRAY = TextFormat::ESCAPE . "8"; // 深灰色 const BLUE = TextFormat::ESCAPE . "9"; // 蓝色 const GREEN = TextFormat::ESCAPE . "a"; // 绿色 const AQUA = TextFormat::ESCAPE . "b"; // 青色 const RED = TextFormat::ESCAPE . "c"; // 红色 const LIGHT_PURPLE = TextFormat::ESCAPE . "d"; // 浅紫色 const YELLOW = TextFormat::ESCAPE . "e"; // 黄色 const WHITE = TextFormat::ESCAPE . "f"; // 白色 // 格式代码 const OBFUSCATED = TextFormat::ESCAPE . "k"; // 随机字符（混淆） const BOLD = TextFormat::ESCAPE . "l"; // 粗体 const STRIKETHROUGH = TextFormat::ESCAPE . "m"; // 删除线 const UNDERLINE = TextFormat::ESCAPE . "n"; // 下划线 const ITALIC = TextFormat::ESCAPE . "o"; // 斜体 const RESET = TextFormat::ESCAPE . "r"; // 重置所有格式
// 点击音效 const EVENT_SOUND_CLICK = 1000; // 点击失败音效 const EVENT_SOUND_CLICK_FAIL = 1001; // 射击音效 const EVENT_SOUND_SHOOT = 1002; // 门的音效 const EVENT_SOUND_DOOR = 1003; // 嘶嘶声音效 const EVENT_SOUND_FIZZ = 1004; // TNT音效 const EVENT_SOUND_TNT = 1005; // 恶魂音效 const EVENT_SOUND_GHAST = 1007; // 恶魂射击音效 const EVENT_SOUND_GHAST_SHOOT = 1008; // 烈焰人射击音效 const EVENT_SOUND_BLAZE_SHOOT = 1009; // 门碰撞音效 const EVENT_SOUND_DOOR_BUMP = 1010; // 门撞击音效 const EVENT_SOUND_DOOR_CRASH = 1012; // 蝙蝠飞行音效 const EVENT_SOUND_BAT_FLY = 1015; // 僵尸感染音效 const EVENT_SOUND_ZOMBIE_INFECT = 1016; // 僵尸治愈音效 const EVENT_SOUND_ZOMBIE_HEAL = 1017; // 末影人传送音效 const EVENT_SOUND_ENDERMAN_TELEPORT = 1018; // 铁砧破碎音效 const EVENT_SOUND_ANVIL_BREAK = 1020; // 铁砧使用音效 const EVENT_SOUND_ANVIL_USE = 1021; // 铁砧掉落音效 const EVENT_SOUND_ANVIL_FALL = 1022; // 按钮点击音效 const EVENT_SOUND_BUTTON_CLICK = 3500; // 射击粒子效果 const EVENT_PARTICLE_SHOOT = 2000; // 破坏粒子效果(未知,无效果) const EVENT_PARTICLE_DESTROY = 2001; // 溅射粒子效果(玻璃破碎的声音) const EVENT_PARTICLE_SPLASH = 2002; // 末影之眼消失粒子效果 const EVENT_PARTICLE_EYE_DESPAWN = 2003; // 生成粒子效果 const EVENT_PARTICLE_SPAWN = 2004; // 开始下雨 const EVENT_START_RAIN = 3001; // 开始打雷 const EVENT_START_THUNDER = 3002; // 停止下雨 const EVENT_STOP_RAIN = 3003; // 停止打雷 const EVENT_STOP_THUNDER = 3004; // 爆炸音效 const EVENT_SOUND_EXPLODE = 3501; // 施法音效 const EVENT_SOUND_SPELL = 3504; // 溅水音效 const EVENT_SOUND_SPLASH = 3506; // 灰色溅水音效(TODO: 修正名称) const EVENT_SOUND_GRAY_SPLASH = 3507; // 设置数据事件 const EVENT_SET_DATA = 4000; // 玩家睡眠事件 const EVENT_PLAYERS_SLEEPING = 9800; // 添加粒子效果掩码 const EVENT_ADD_PARTICLE_MASK = 0x4000;
1.1.1 正式版发布，新增用户中心。对于未越狱设备，您可以使用ID自行签名安装～首页分类搜索用户中心
在一个文件中若有多个类，可使用注释#pragma mark - 狗狗类 可快速跳转到想要修改的类。 #pragma mark - 狗狗类 @interface dog : NSObject @end @implementation dog @end #pragma mark - 猫猫类 @interface cat : NSObject @end @implementation cat @end #pragma mark - 猪猪类 @interface pig : NSObject @end @implementation pig @end
#import <Foundation/Foundation.h> // Person 类的接口声明 @interface Person : NSObject { @public //成员默认私有，需要加上public变为共有 NSString *_name; int _age; float _height; } @end //类的实现 @implementation Person @end int main(int argc, const char * argv[]) { @autoreleasepool { //新对象 Person *p1 = [Person new]; //指针空间指向 常用 p1->_name = @"张三"; p1->_age = 18; p1->_height = 188.9f; //第二种方式 (*p1)._name = @"李四"; (*p1)._age = 20; (*p1)._height = 180.0f; //打印 NSLog(@"%@",p1->_name); } return 0; } 无参数方法的声明和调用// Person 类的接口声明 @interface Person : NSObject { } //定义(方法)函数 -(void) run; @end //类的实现 @implementation Person //(方法)函数部分 -(void) run { NSLog(@"run run run"); } @end int main(int argc, const char * argv[]) { @autoreleasepool { //新对象 Person *p1 = [Person new]; [p1 run]; } return 0; } 有一个参数方法的声明和调用 // Person 类的接口声明 @interface Person : NSObject //定义(方法)函数 -(void) eat:(NSString *)foodName; @end //(方法)类的实现 @implementation Person -(void) eat:(NSString *)foodName { NSLog(@"主人，喂我吃：%@",foodName); } @end int main(int argc, const char * argv[]) { @autoreleasepool { //新对象 Person *p1 = [Person new]; [p1 eat:@"答辩"]; } return 0; } 多个参数方法的声明和调用 // Person 类的接口声明 @interface Person : NSObject //定义(方法)函数 -(void) eat:(int)day :(NSString *)foodName :(NSString *)foodName2; @end //(方法)类的实现 @implementation Person -(void) eat:(int)day :(NSString *)foodName :(NSString *)foodName2 { NSLog(@"主人，喂我吃%d天的：%@和%@了",day, foodName, foodName2); } @end int main(int argc, const char * argv[]) { @autoreleasepool { //新对象 Person *p1 = [Person new]; [p1 eat:360:@"小零食":@"大便"]; } return 0; }
用于简单的监控服务器当前状态，基于PHP方法实现，数据不保证准确。若想要得到更准确的数据，可尝试使用宝塔API方式获取。在线预览地址：https://15w.net/serverInfo/源代码下载：源代码下载使用方法下载源代码后，放置到网站目录 /serverInfo 下，浏览器访问：域名/serverInfo 即可看到效果。CPU核心修改默认是基于4核心的配置，若服务器CPU核心为其他数量，请修改以下代码index.php 第 137 行，这里的4核心，可改为其他内容 CPU占用 4核心 100% index.php 第 137 行，这里的cpus的数值，可改为其他内容var cpus = 4;宝塔面板报错若使用的是宝塔面板环境，请修改网站根目录中的.user.ini文件open_basedir=/www/wwwroot/zai.ink/:/tmp/追加代码：:/proc/后：open_basedir=/www/wwwroot/zai.ink/:/tmp/:/proc/注意，是追加一个 :/proc/ 代码，请勿复制我的代码。
前言使用套件 Xcode4.6 和 MacOS 10.8.5 理论上可以为iOS4、5、6、7、8、9开发iOS应用程序，我只拿来开发过iOS5和iOS6系统的应用程序，测试完美。注意：当年看的这份教程已经被删除，找不到了，操作起来也很复杂，好在之前制作过系统镜像，可以直接拿来用。我在这里分享一份给大家。下载：MacOS虚拟机（20GB）开始操作下载后解压，我使用的是分卷压缩，防止资源和谐。导入虚拟机下载镜像文件，解压zip，双击文件OS X 10.8.vmx，使用软件VMware Workstation Pro 17打开。运行虚拟机，选择我已复制该虚拟机等待开机。输入开机密码：123456 进入系统。创建项目打开Xcode4.6，简单创建一个项目做测试。具体的Xcode操作自行学习，这里不多概述。。。创建好项目后，点击Run,先在模拟器上跑一跑，可以看到模拟器里成功运行，接着进行下一步！设置无证书打包修改工程设置禁用Xcode自动的签名操作，将工程配置中所有的CodeSigning选项全部设为Don't Code Sign，如图。可能需要先点击“All”让这个选项显示出来。设置自定义脚本在Build Phases中点击右下角的Add Build Phase，然后单击Add Run Script接着输入以下脚本：export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate if [ "${PLATFORM_NAME}" =="iphoneos" ] || [ "${PLATFORM_NAME}" == "ipados"]; then /Applications/Xcode.app/Contents/Developer/iphoneentitlements/gen_entitlements.py"my.company.${PROJECT_NAME}""${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent"; codesign -f -s "iPhone Developer"--entitlements"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent""${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/" fi编译安装到iOS设备使用数据线将iOS设备和电脑连接，会弹出如下窗口，选择连接到虚拟机。接着点击左上角选择设备，选择你的iOS设备，然后点击Run即可进行真机测试。得到IPA文件安装后，用爱思助手导出即可！补充问题1选择设备的时候，请不要登陆AppleID，登录AppleID会导致签名失败。
这里我使用的方法是通过记录5分钟内，访问网站的用户的IP地址，来判断当前在线人数。首先我们需要两个函数，一个是获取客户端IP的函数 /** * 获取客户端IP * @return string */ function getip() { //获取客户端IP if ( isset($_SERVER[ "HTTP_CDN_SRC_IP" ]) ) { //获取网宿CDN真实客户IP return replace_ip( $_SERVER[ "HTTP_CDN_SRC_IP" ] ); } if ( isset($_SERVER[ "HTTP_X_FORWARDED_FOR" ]) ) { //获取网宿、阿里云真实客户IP，参考：https://help.aliyun.com/knowledge_detail/40535.html return replace_ip( $_SERVER[ "HTTP_X_FORWARDED_FOR" ] ); } if ( isset($_SERVER[ "HTTP_CLIENT_IP" ]) ) { return $_SERVER[ "HTTP_CLIENT_IP" ]; } if ( isset($_SERVER[ "HTTP_X_FORWARDED" ]) ) { return $_SERVER[ "HTTP_X_FORWARDED" ]; } if ( isset($_SERVER[ "HTTP_FORWARDED_FOR" ]) ) { return $_SERVER[ "HTTP_FORWARDED_FOR" ]; } if ( isset($_SERVER[ "HTTP_FORWARDED" ]) ) { return $_SERVER[ "HTTP_FORWARDED" ]; } $httpip = $_SERVER[ 'REMOTE_ADDR' ]; if ( !preg_match( "/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/", $httpip ) ) { $httpip = "127.0.0.1"; } return $httpip; }还有一个是拆分代理IP函数 /** * 拆分代理IP * @return string */ function replace_ip($ip) { if (!$ip) { return ""; } $httpip_array = explode(",", $ip); if ($httpip_array[0]) { return $httpip_array[0]; } else { return $ip; } } 接着便是主要代码： /** * * 用户在线数量统计 * * */ // 获取用户 IP 地址 $userIP = getip(); // 获取当前时间戳 $currentTime = $date; // 设置在线时间间隔（5分钟） $timeout = $currentTime - (5 * 60); // 创建或打开文件以保存在线用户数据 $file = fopen("online_users.txt", "c+"); // 获取文件中的数据 $users = unserialize(fread($file, filesize("online_users.txt"))); // 如果用户数据不是数组，则初始化为空数组 if (!is_array($users)) { $users = []; } // 更新当前用户的在线时间 $users[$userIP] = $currentTime; // 删除超时的用户 foreach ($users as $ip => $lastTime) { if ($lastTime < $timeout) { unset($users[$ip]); } } // 重置文件指针，并清空文件内容 ftruncate($file, 0); rewind($file); // 将更新后的用户数据写入文件 fwrite($file, serialize($users)); // 关闭文件 fclose($file); //在线人数 $online_users = count($users);最后这个变量 $online_users 就是在线人数了，放到想要输出的位置，进行输出即可。在线人数 <?php echo $online_users;?> 人
宝塔面板 PHP exec函数 Sudo指令 权限不足解决方法
使用PHP exec函数 执行 sduo的时，提示权限不足，具体报错如下： array(9) { [0]=> string(0) "" [1]=> string(66) "We trust you have received the usual lecture from the local System" [2]=> string(59) "Administrator. It usually boils down to these three things:" [3]=> string(0) "" [4]=> string(38) " #1) Respect the privacy of others." [5]=> string(30) " #2) Think before you type." [6]=> string(52) " #3) With great power comes great responsibility." [7]=> string(0) "" [8]=> string(53) "sudo: no tty present and no askpass program specified" } 解决方法如下：编辑 /etc/sudoers 文件。在此处：## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL追加下方代码：www ALL = NOPASSWD: ALL## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL www ALL = NOPASSWD: ALL这样就可以解决了。
原作者PHP源代码350KB，发现代码里面有很多没用的东西，索性重新写了个“精简版”。代码基于handsome主题修改，其他主题如需使用请自行修改代码适配。精简后的PHP代码仅支持Linux系统，在Centos7.6和7.9上测试通过，其他Linux系统未进行测试，兼容性未知。功能演示文件修改 headnav.php文件路径：usr/themes/handsome/component/headnav.php在此处： <?php if (@Utils::getExpertValue("show_static",true) !== false): ?> 追加内容(此处为追加后的代码)： <?php if (@Utils::getExpertValue("show_static",true) !== false): ?> <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline> 运行状态 CPU占用 2核心 占用内存 磁盘占用 内存缓存 内存缓冲 系统负载 网络状态 IO 实时IO 网络 实时网络 服务器时间 <?php echo $_SERVER['SERVER_SOFTWARE']; ?> WEB服务器 <?php echo $_SERVER['SERVER_PROTOCOL']; ?> 通信协议 <?php echo PHP_VERSION;?> PHP版本 访客信息 持续运行 您的IP 网络地址 浏览器信息 您的设备 <?php echo $_SERVER['REQUEST_METHOD'];?> 请求方法 <?php echo $_SERVER['HTTP_ACCEPT_LANGUAGE'];?> 服务语言 您的设备时间 文件修改 footer.php文件路径：usr/themes/handsome/component/footer.php在此处：<?php $this->options->bottomHtml(); ?> 追加内容(此处为追加后的代码)： <?php $this->options->bottomHtml(); ?> 新建文件 serverInfo.php上述修改完毕之后，在网站的根目录新建 serverInfo.php 文件文件内容如下：<?php /** * 获取当前Unix时间戳 * */ $unixTimestamp = time(); /** * 获取服务器总的运行时长 * */ $serverUptime = getUpTime(); /** * 获取服务器负载 以及CPU使用信息 * */ $serverLoad = GetLoad(); $cpuUsage = GetCPUInfo(); /** * 获取服务器内存信息 * */ $memoryInfo = GetMem(); // 定义要输出的内容 $serverInfo = array( 'serverTime' => date('Y-m-d H:i:s', $unixTimestamp), 'serverUptime' => array( 'days' => $serverUptime['days'], 'hours' => $serverUptime['hours'], 'mins' => $serverUptime['mins'], 'secs' => $serverUptime['secs'] ), 'serverUtcTime' => date('Y/m/d H:i:s', $unixTimestamp), 'diskUsage' => array( 'value' => disk_total_space(__FILE__) - disk_free_space(__FILE__), 'max' => disk_total_space(__FILE__) ) ); $serverStatus = array( 'sysLoad' => array($serverLoad['1m'], $serverLoad['5m'], $serverLoad['15m']), 'cpuUsage' => array( 'user' => $cpuUsage['user'], 'nice' => $cpuUsage['nice'], 'sys' => $cpuUsage['sys'], 'idle' => $cpuUsage['idle'] ), 'memRealUsage' => array( 'value' => $memoryInfo['mRealUsed'], 'max' => $memoryInfo['mTotal'] ), 'memBuffers' => array( 'value' => $memoryInfo['mBuffers'], 'max' => $memoryInfo['mTotal'] ), 'memCached' => array( 'value' => $memoryInfo['mCached'], 'max' => $memoryInfo['mTotal'] ), 'swapUsage' => array( 'value' => $memoryInfo['swapUsed'], 'max' => $memoryInfo['swapTotal'] ), 'swapCached' => array( 'value' => $memoryInfo['swapCached'], 'max' => $memoryInfo['swapTotal'] ) ); $networkStats = array( 'networks' => GetNetwork() ); // 将以上内容合并为一个数组 $output = array( 'serverInfo' => $serverInfo, 'serverStatus' => $serverStatus, 'networkStats' => $networkStats ); // 将数组转换为JSON字符串并输出 echo json_encode($output); /** * 获取系统运行时长 * * @return array */ function getUpTime() { $uptime = (float) @file_get_contents("/proc/uptime"); $days = floor($uptime / 86400); $hours = floor(($uptime % 86400) / 3600); $minutes = floor((($uptime % 86400) % 3600) / 60); $seconds = ($uptime % 3600) % 60; //$time = $days.":".$hours.":".$minutes.":".$seconds; return array( 'days' => $days, 'hours' => $hours, 'mins' => $minutes, 'secs' => $seconds ); } /** * 获取系统负载 * * @return array|false|string[] */ function GetLoad() { if (false === ($str = file_get_contents("/proc/loadavg"))) return []; $loads = explode(' ', $str); if ($loads) { return [ '1m' => $loads[0], '5m' => $loads[1], '15m' => $loads[2], ]; } return []; } function GetCPUInfo() { $load = sys_getloadavg(); $user = $load[0]; $nice = $load[1]; $sys = $load[2]; $idle = 100 - ($user + $nice + $sys); return [ 'user' => $user, 'nice' => $nice, 'sys' => $sys, 'idle' => $idle, ]; } /** * 内存信息 * * @param bool $bFormat 格式化 * * @return array */ function GetMem(bool $bFormat = false) { if (false === ($str = file_get_contents("/proc/meminfo"))) return []; preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $mems); preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers); $mtotal = $mems[1][0] * 1024; $mfree = $mems[2][0] * 1024; $mbuffers = $buffers[1][0] * 1024; $mcached = $mems[3][0] * 1024; $stotal = $mems[4][0] * 1024; $sfree = $mems[5][0] * 1024; $mused = $mtotal - $mfree; $sused = $stotal - $sfree; $mrealused = $mtotal - $mfree - $mcached - $mbuffers; //真实内存使用 $rtn['mTotal'] = !$bFormat ? $mtotal : $this->size_format($mtotal, 1); $rtn['mFree'] = !$bFormat ? $mfree : $this->size_format($mfree, 1); $rtn['mBuffers'] = !$bFormat ? $mbuffers : $this->size_format($mbuffers, 1); $rtn['mCached'] = !$bFormat ? $mcached : $this->size_format($mcached, 1); $rtn['mUsed'] = !$bFormat ? ($mtotal - $mfree) : $this->size_format($mtotal - $mfree, 1); $rtn['mPercent'] = (floatval($mtotal) != 0) ? round($mused / $mtotal * 100, 1) : 0; $rtn['mRealUsed'] = !$bFormat ? $mrealused : $this->size_format($mrealused, 1); $rtn['mRealFree'] = !$bFormat ? ($mtotal - $mrealused) : $this->size_format($mtotal - $mrealused, 1);//真实空闲 $rtn['mRealPercent'] = (floatval($mtotal) != 0) ? round($mrealused / $mtotal * 100, 1) : 0; //真实内存使用率 $rtn['mCachedPercent'] = (floatval($mcached) != 0) ? round($mcached / $mtotal * 100, 1) : 0; //Cached内存使用率 $rtn['swapTotal'] = !$bFormat ? $stotal : $this->size_format($stotal, 1); $rtn['swapFree'] = !$bFormat ? $sfree : $this->size_format($sfree, 1); $rtn['swapUsed'] = !$bFormat ? $sused : $this->size_format($sused, 1); $rtn['swapPercent'] = (floatval($stotal) != 0) ? round($sused / $stotal * 100, 1) : 0; $rtn['swapCached'] = $mbuffers; return $rtn; } /** * 获取网络数据 * * @param bool $bFormat * * @return array */ function GetNetwork(bool $bFormat = false) { $rtn = []; $netstat = file_get_contents('/proc/net/dev'); if (false === $netstat) { return []; } $bufe = preg_split("/\n/", $netstat, -1, PREG_SPLIT_NO_EMPTY); foreach ($bufe as $buf) { if (preg_match('/:/', $buf)) { list($dev_name, $stats_list) = preg_split('/:/', $buf, 2); $dev_name = trim($dev_name); $stats = preg_split('/\s+/', trim($stats_list)); $rtn[$dev_name]['name'] = $dev_name; $rtn[$dev_name]['rx'] = !$bFormat ? $stats[0] : $this->netSize($stats[0]); $rtn[$dev_name]['in_packets'] = $stats[1]; $rtn[$dev_name]['in_errors'] = $stats[2]; $rtn[$dev_name]['in_drop'] = $stats[3]; $rtn[$dev_name]['tx'] = !$bFormat ? $stats[8] : $this->netSize($stats[8]); $rtn[$dev_name]['out_packets'] = $stats[9]; $rtn[$dev_name]['out_errors'] = $stats[10]; $rtn[$dev_name]['out_drop'] = $stats[11]; } } return $rtn; }至此，博客已经成功添加添加服务器状态栏，可以刷新后点击状态栏图标查看。宝塔面板报错若使用的是宝塔面板环境，请修改网站根目录中的.user.ini文件open_basedir=/www/wwwroot/zai.ink/:/tmp/追加代码：:/proc/后：open_basedir=/www/wwwroot/zai.ink/:/tmp/:/proc/
前几天给大家讲了一下ChatGLM2-6B部署教程，今天就再给大家来一个模型微调教程引言随着ChatGPT的发展，不少企业都想训练出来适用于自己领域的大模型，但是训练一个模型成本是非常高的，中小型企业根本无法承受。今天给大家带来ChatGLM2-6B大语言模型微调训练教程，基于清华大学开源的大语言模型（GitHub：ChatGLM2-6B）进行微调，可以用非常少的成本训练出自己行业领域的大模型。软硬件条件系统系统推荐 Ubuntu 22.x ，因为P-Tuning v2不支持Windows多卡。如果是单卡跑的话，使用Windows也是可以的，详细修改教程参照：issues#195硬件微调不需要多高的硬件，但也要满足最低硬件要求：CPU：8核心以上 内存：32G以上 显卡：仅支持英伟达(NVDA)显卡，推荐最近新出卡，能加快微调速度。 显存：显存推荐16G以上，最低8G。 单卡多卡：推荐多卡，单卡也是可以的。数据准备下面给大家几条数据示例：{"content":"你好","summary":"您好，我是人工智能助理iBot机器人。"} {"content":"你叫什么名字？","summary":"我的名字叫做iBot机器人。"} {"content":"你有什么功能？","summary":"我可以解决您在使用网站时遇到的各种问题。"} {"content":"每次签到可以获得多少金币","summary":"您可以通过签到获取金币。每次签到获得的金币数量在5个～100个不等。签到获得的金币支持累加，但有一定的上限，普通用户通过签到最大累计金币数为30个，捐赠用户通过签到最大累计金币数为300个。"} {"content":"软件闪退、黑屏、无法使用的原因是？","summary":"软件闪退、黑屏、无法使用的原因可能包括：软件需要输入ID但用户输入了自己的ID导致闪退；软件与当前iOS版本不兼容；以及软件自身存在问题。"} {"content":"软件提示“输入ID”怎么办？","summary":"当软件打开后需要输入ID时，千万不要输入自己的ID，否则可能导致软件闪退或黑屏。iOS6系统：首先退出软件，回到桌面，在打开软件的一瞬间，迅速按下息屏键，再迅速点亮屏幕，继续使用软件就不会提示了(如果不行的话，多试几次)。非iOS6系统：仅仅对爱思正版软件有效：手机需要链接一次电脑版爱思，它会在你手机上面安装个爱思手机版，这个时候再打开爱思版免ID软件，就不会再提示需要id了。相似的，同步正版和91正版，自然需要下载个同步助手和91助手了。"}上述仅给大家提供几条数据示例，具体微调过程中，还需要根据微调结果增加/减少/调整数据内容和条数。讲这些数据存放到新建文件train.json中拉取项目这一步其实没必要讲的，就是把项目从Github里面克隆出来 或者 直接下载zip文件 都是可以的。项目环境部署可以参考下方文章，但也仅作为参考，因为之前讲的是windows的环境下部署，本次微调使用的系统是ubuntu，虽有不同，但大同小异，下文仅供参考。[post cid="82" /]微调软件依赖运行微调除 ChatGLM2-6B 的依赖之外，还需要安装以下依赖pip install rouge_chinese nltk jieba datasets修改微调代码微调代码文件路径：项目地址/ptuning/train.sh文件部分参数我在这里给大家解读一下：PRE_SEQ_LEN=128 预处理序列的长度，假设你的微调数量很小（约莫有100条）建议调低到64LR=2e-2 学习率，它决定了模型在每次更新权重时所采用的步长。较小的学习率会导致训练过程缓慢，而较大的学习率可能会导致训练过程不稳定。若微调数据量很小（约莫有100条）可以使用较大的学习率例如2e-1学习率较小会导致训练缓慢loss不收敛，较大会导致模型出现遗忘问题、过度拟合。这个参数需要自行研究，找到属于你数据量的最优解。对于：per_device_train_batch_size 1 per_device_eval_batch_size 1 以及 gradient_accumulation_steps 16请前往Github查看或参阅下方引用：一次训练迭代会以 1 的批处理大小进行 16 次累加的前后向传播，等效为 16 的总批处理大小，此时最低只需 6.7G 显存。若想在同等批处理大小下提升训练效率，可在二者乘积不变的情况下，加大 per_device_train_batch_size 的值，但也会带来更多的显存消耗，请根据实际情况酌情调整。修改例子： 源代码： --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 16 \ 修改后： --per_device_train_batch_size 4 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 4 \ 亦或者： --per_device_train_batch_size 8 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 2 \ 还可以： --per_device_train_batch_size 8 \ --per_device_eval_batch_size 2 \ --gradient_accumulation_steps 2 \微调数据放置将微调数据train.json放置到路径：项目地址/ptuning/AdvertiseGen/train.json至于dev.json这个文件，就是训练后你想要什么结果存放到里面，内容示例：{"content":"你好啊","summary":"您好，我是人工智能助理iBot机器人。"} {"content":"你的叫什么？","summary":"我的名字叫做iBot机器人。"} {"content":"你可以做什么？","summary":"我可以解决您在使用网站时遇到的各种问题。"}开始微调：bash train.sh微调后部署这个就不讲了，就是把部署后的模型跑出来，请参阅：ptuning#模型部署我这里的话，直接接入了QQ机器人，就直接演示一下在qq群内的对话吧：群对话：
一直都想研究玩玩这块，迫于财力有限，今天终于能完整的本地复现这些功能。后续考虑购入四张P40 24G显卡放到服务器，并开放api给大家使用。Your browser does not support the video tag.本质上这些大语言模型都是大差不差的，本文就以ChatGLM2-6B为例给大家做演示。简介ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本，相较于第一代，提升流畅性，门槛较低的同时又增加了许多新特性。项目地址： Github - ChatGLM2-6B 环境配置要求系统环境为了快速上手，避免一些问题，本文使用Windows Server 2022纯净系统进行搭建。 推荐使用纯净的系统进行测试。 配置要求以下是我的配置，括号中表示最低配置系统：Windows Server 2022（家用Win系统也可以） CPU：Intel Xeon Platinum 8255C（Intel/AMD 均可，64位，8核心以上最好，不怎么吃CPU） 内存：32G （越大越好，最低16G） 显卡：Nvidia Tesla T4 16G（计算卡一张，内存不低于16g最佳越大越好，最低P4 8G，推荐：P40 24G｜T4 16G｜A10 24G）Python环境安装安装AnacondaAnaconda介绍及安装Anaconda指的是一个开源的Python发行版本，其包含了conda、Python等180多个科学包及其依赖项。因为包含了大量的科学包。Anaconda包括Conda、Python以及一大堆安装好的工具...下载地址：Anaconda Download点击Download选择Windows 64bit版本进行下载。下载完成后，运行安装程序。在安装界面中，选择 All Users 为当前计算机所有用户安装 Anaconda。接下来，选择安装路径，建议使用默认路径。安装过程可能较慢，耐心等待安装完成即可。安装完成后，打开Conda命令行，输入 conda --version 检查 Anaconda 是否安装成功。NVIDIA配置流程驱动安装已经安装驱动的可以跳过此步。避免浪费时间。驱动下载地址：驱动下载 Download根据显卡型号 获取驱动程序，进行下载安装。设置显卡开发者模式这个也没什么好讲的，就按照图中显示配置即可。记录版本号，以便用于下载Cuda这里我的是12.2.138安装 Cuda上一步获取到的版本号：12.2.138 后面的数字不需要管，只需要记住 12.2 这个就可以。打开网站：https://developer.nvidia.com/cuda-toolkit-archive选择对应的版本下载。要选与自己显卡相关的版本cuDNN安装下载地址：https://developer.nvidia.com/rdp/cudnn-download 依旧是需要选择对应的版本进行下载。此处需登陆，没有账号的话注册一个即可，使用邮件地址注册。下载完之后解压缩，我们将目录名称修改为cudnn。将该cudnn目录，复制到目录 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2 目录下(就是你的CUDA安装地址，前面的目录一般都是有了的，只需要以此点进去即可)。配置环境变量，添加2个环境变量路径，根据你自己的目录修改。C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\cudnn\binC:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.2\extras\CUPTI\lib64安装Pytorch地址：https://pytorch.org/打开网站，下滑，选择需要安装的版本。选择适用于您设备的cuda版本，由于我的是12.2，需要需要使用Preview版本。conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch-nightly -c nvidia复制指令，到Anaconda指令窗口执行，请选择适合自己的版本下载，不要复制我的指令。开始跑模型创建模型虚拟环境利用conda创建虚拟环境打开Conda Shell，执行：conda create -n ChatGlm python=3.9创建一个名为ChatGlm的环境，此环境的Python版本为3.9询问是否继续执行，选择 y回车即可。激活模型虚拟环境这里的环境路径C:\ChatGlm是我的路径，请将路径修改成自己的路径。conda activate ChatGlm c: cd C:\ChatGlm下载ChatGLM2-6B这里不多赘述，直接Github：https://github.com/THUDM/ChatGLM2-6B下载后将zip内的文件复制到你的环境路径，我的是C:\ChatGlm。安装模型需要的环境先进入目录，若已经在这个目录下，无需执行这块代码conda activate ChatGlm c: cd C:\ChatGlmpip改为清华源（避免因网络不良导致报错安装环境失败）【非必需】pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple安装模型需要的环境pip install -r requirements.txt安装过程需要从网络下载资源，所需时间较长，若没有报错耐心等待即可。若安装失败，请将源改为pip改为清华源。下载模型原版模型下载[打不开挂科学]：https://huggingface.co/THUDM/chatglm2-6b/tree/main量化模型下载[小显存使用]：https://huggingface.co/THUDM/chatglm2-6b-int4/tree/main因为我的卡是Tesla T4 16G，为了稳定运行，这里我使用Int4量化模型进行测试。模型文件不知道那些有用的话，建议全部下载放到chatglm2-6b文件夹内。下载后的模型存放到项目目录/model/chatglm2-6b下，例如我的就是C:\ChatGlm\model\chatglm2-6b如果你使用的是int4量化模型，则路径为/model/chatglm2-6b-int4运行模型正常模型正常模型,请修改路径为绝对路径：cli_demo.py 第8行：原代码：tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True) model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).cuda()修改后：tokenizer = AutoTokenizer.from_pretrained("model\\chatglm2-6b", trust_remote_code=True) model = AutoModel.from_pretrained("model\\chatglm2-6b", trust_remote_code=True).cuda()量化模型针对量化模型，还需要修改一些代码：cli_demo.py 第8行原代码：tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True) model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).cuda()修改后：tokenizer = AutoTokenizer.from_pretrained("model\\chatglm2-6b-int4", trust_remote_code=True) model = AutoModel.from_pretrained("model\\chatglm2-6b-int4",trust_remote_code=True).cuda()运行程序运行程序有多种方法，这里只使用命令行进行演示python cli_demo.py